Much improved pdma transfers.
Still not nearly as fast as FWB's drivers under the MacOS. Uses the "blind" transfer method instead of polled pdma.
This commit is contained in:
parent
21f7aa38f6
commit
e23598f24f
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: mac68k5380.c,v 1.9 1995/09/16 18:22:33 briggs Exp $ */
|
/* $NetBSD: mac68k5380.c,v 1.10 1995/09/23 01:11:42 briggs Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1995 Allen Briggs
|
* Copyright (c) 1995 Allen Briggs
|
||||||
@ -37,6 +37,7 @@
|
|||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
#include <sys/device.h>
|
#include <sys/device.h>
|
||||||
|
#include <sys/dkstat.h>
|
||||||
#include <sys/syslog.h>
|
#include <sys/syslog.h>
|
||||||
#include <sys/buf.h>
|
#include <sys/buf.h>
|
||||||
#include <scsi/scsi_all.h>
|
#include <scsi/scsi_all.h>
|
||||||
@ -71,6 +72,7 @@
|
|||||||
#define claimed_dma() 1
|
#define claimed_dma() 1
|
||||||
#define reconsider_dma()
|
#define reconsider_dma()
|
||||||
#define USE_PDMA 1 /* Use special pdma-transfer function */
|
#define USE_PDMA 1 /* Use special pdma-transfer function */
|
||||||
|
#define MIN_PHYS 0x2000 /* pdma space w/ /DSACK is only 0x2000 */
|
||||||
|
|
||||||
#define ENABLE_NCR5380(sc) cur_softc = sc;
|
#define ENABLE_NCR5380(sc) cur_softc = sc;
|
||||||
|
|
||||||
@ -174,6 +176,7 @@ u_char *pending_5380_data;
|
|||||||
u_long pending_5380_count;
|
u_long pending_5380_count;
|
||||||
|
|
||||||
/* #define DEBUG 1 Maybe we try with this off eventually. */
|
/* #define DEBUG 1 Maybe we try with this off eventually. */
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
int pdma_5380_sends = 0;
|
int pdma_5380_sends = 0;
|
||||||
int pdma_5380_bytes = 0;
|
int pdma_5380_bytes = 0;
|
||||||
@ -183,7 +186,7 @@ char *pdma_5380_state="";
|
|||||||
void
|
void
|
||||||
pdma_stat()
|
pdma_stat()
|
||||||
{
|
{
|
||||||
printf("PDMA SCSI: %d xfers completed for %d bytes, pending = %d.\n",
|
printf("PDMA SCSI: %d xfers completed for %d bytes.\n",
|
||||||
pdma_5380_sends, pdma_5380_bytes);
|
pdma_5380_sends, pdma_5380_bytes);
|
||||||
printf("pdma_5380_dir = %d.\n",
|
printf("pdma_5380_dir = %d.\n",
|
||||||
pdma_5380_dir);
|
pdma_5380_dir);
|
||||||
@ -221,6 +224,11 @@ pdma_cleanup(void)
|
|||||||
*/
|
*/
|
||||||
SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA);
|
SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear any pending interrupts.
|
||||||
|
*/
|
||||||
|
scsi_clr_ipend();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tell interrupt functions that DMA has ended.
|
* Tell interrupt functions that DMA has ended.
|
||||||
*/
|
*/
|
||||||
@ -286,81 +294,217 @@ ncr5380_irq_intr(p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_PDMA
|
|
||||||
/*
|
/*
|
||||||
* Macroed for readability.
|
* This is the meat of the PDMA transfer.
|
||||||
|
* When we get here, we shove data as fast as the mac can take it.
|
||||||
|
* We depend on several things:
|
||||||
|
* * All macs after the Mac Plus that have a 5380 chip should have a general
|
||||||
|
* logic IC that handshakes data for blind transfers.
|
||||||
|
* * If the SCSI controller finishes sending/receiving data before we do,
|
||||||
|
* the same general logic IC will generate a /BERR for us in short order.
|
||||||
|
* * The fault address for said /BERR minus the base address for the
|
||||||
|
* transfer will be the amount of data that was actually written.
|
||||||
|
*
|
||||||
|
* We use the nofault flag and the setjmp/longjmp in locore.s so we can
|
||||||
|
* detect and handle the bus error for early termination of a command.
|
||||||
|
* This is usually caused by a disconnecting target.
|
||||||
*/
|
*/
|
||||||
#define DONE ( (GET_5380_REG(NCR5380_DMSTAT) & SC_ACK_STAT) \
|
|
||||||
|| (GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ) )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ncr5380_drq_intr(p)
|
ncr5380_drq_intr(p)
|
||||||
void *p;
|
void *p;
|
||||||
{
|
{
|
||||||
struct ncr_softc *sc = p;
|
|
||||||
#if USE_PDMA
|
#if USE_PDMA
|
||||||
|
extern int *nofault, mac68k_buserr_addr;
|
||||||
|
struct ncr_softc *sc = p;
|
||||||
|
label_t faultbuf;
|
||||||
|
register int count;
|
||||||
|
volatile u_int32_t *long_drq;
|
||||||
|
u_int32_t *long_data;
|
||||||
|
volatile u_int8_t *drq;
|
||||||
|
u_int8_t *data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we're not ready to xfer data, just return.
|
||||||
|
*/
|
||||||
|
if ( !(GET_5380_REG(NCR5380_DMSTAT) & SC_DMA_REQ)
|
||||||
|
|| !pdma_5380_dir)
|
||||||
|
return;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
pdma_5380_state = "got drq interrupt.";
|
pdma_5380_state = "got drq interrupt.";
|
||||||
#endif
|
#endif
|
||||||
if (pdma_5380_dir == 2) { /* Data In */
|
|
||||||
/*
|
/*
|
||||||
* Can we "unroll" this any? I don't think so--in fact, I
|
* Setup for a possible bus error caused by SCSI controller
|
||||||
* question the safety of using long word transfers. The
|
* switching out of DATA-IN/OUT before we're done with the
|
||||||
* device could theoretically disconnect at any time.
|
* current transfer.
|
||||||
* The long word xfer is controlled by the Mac's circuitry,
|
*/
|
||||||
* and we can't know how much it transferred if the device
|
nofault = (int *) &faultbuf;
|
||||||
* decides to disconnect on us.
|
|
||||||
* If it does disconnect in the middle of a long xfer, it
|
if (setjmp((label_t *) nofault)) {
|
||||||
* should get a bus error--we might be able to derive from
|
nofault = (int *) 0;
|
||||||
* that bus error where the transaction stopped, but I
|
|
||||||
* don't want to think about that...
|
|
||||||
*/
|
|
||||||
while (GET_5380_REG(NCR5380_DMSTAT) & SC_DMA_REQ)
|
|
||||||
if (pending_5380_count) {
|
|
||||||
*pending_5380_data++ = *ncr_5380_with_drq;
|
|
||||||
pending_5380_count --;
|
|
||||||
} else {
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
pdma_5380_state = "done in xfer in.";
|
pdma_5380_state = "buserr in xfer.";
|
||||||
|
#endif
|
||||||
|
count = ( (u_long) mac68k_buserr_addr
|
||||||
|
- (u_long) ncr_5380_with_drq);
|
||||||
|
if ((count < 0) || (count > pending_5380_count)) {
|
||||||
|
printf("pdma in: count = %d (0x%x) (pending "
|
||||||
|
"count %d)\n", count, count,
|
||||||
|
pending_5380_count);
|
||||||
|
panic("something is wrong");
|
||||||
|
}
|
||||||
|
|
||||||
|
pending_5380_data += count;
|
||||||
|
pending_5380_count -= count;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
pdma_5380_state = "handled bus error in xfer.";
|
||||||
|
#endif
|
||||||
|
mac68k_buserr_addr = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdma_5380_dir == 2) { /* Data In */
|
||||||
|
int resid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the dest address aligned.
|
||||||
|
*/
|
||||||
|
resid = count = 4 - (((int) pending_5380_data) & 0x3);
|
||||||
|
if (count < 4) {
|
||||||
|
data = (u_int8_t *) pending_5380_data;
|
||||||
|
drq = (u_int8_t *) ncr_5380_with_drq;
|
||||||
|
while (count) {
|
||||||
|
#define R1 *data++ = *drq++
|
||||||
|
R1; count--;
|
||||||
|
#undef R1
|
||||||
|
}
|
||||||
|
pending_5380_data += resid;
|
||||||
|
pending_5380_count -= resid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get ready to start the transfer.
|
||||||
|
*/
|
||||||
|
count = pending_5380_count;
|
||||||
|
long_drq = (volatile u_int32_t *) ncr_5380_with_drq;
|
||||||
|
long_data = (u_int32_t *) pending_5380_data;
|
||||||
|
|
||||||
|
#define R4 *long_data++ = *long_drq++
|
||||||
|
while ( count >= 512 ) {
|
||||||
|
if (!(GET_5380_REG(NCR5380_DMSTAT) & SC_DMA_REQ)) {
|
||||||
|
nofault = (int *) 0;
|
||||||
|
|
||||||
|
pending_5380_data += (pending_5380_count-count);
|
||||||
|
pending_5380_count = count;
|
||||||
|
#if DEBUG
|
||||||
|
pdma_5380_state = "drq low";
|
||||||
#endif
|
#endif
|
||||||
SET_5380_REG(NCR5380_MODE,
|
|
||||||
GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#if DEBUG
|
R4; R4; R4; R4; R4; R4; R4; R4;
|
||||||
pdma_5380_state = "handled drq interrupt.";
|
R4; R4; R4; R4; R4; R4; R4; R4; /* 64 */
|
||||||
#endif
|
R4; R4; R4; R4; R4; R4; R4; R4;
|
||||||
return;
|
R4; R4; R4; R4; R4; R4; R4; R4; /* 128 */
|
||||||
} else if (pdma_5380_dir == 1) {
|
R4; R4; R4; R4; R4; R4; R4; R4;
|
||||||
/*
|
R4; R4; R4; R4; R4; R4; R4; R4;
|
||||||
* See comment on pdma_xfer_in(), above.
|
R4; R4; R4; R4; R4; R4; R4; R4;
|
||||||
*/
|
R4; R4; R4; R4; R4; R4; R4; R4; /* 256 */
|
||||||
while (GET_5380_REG(NCR5380_DMSTAT) & SC_DMA_REQ)
|
R4; R4; R4; R4; R4; R4; R4; R4;
|
||||||
if (pending_5380_count) {
|
R4; R4; R4; R4; R4; R4; R4; R4;
|
||||||
*ncr_5380_with_drq = *pending_5380_data++;
|
R4; R4; R4; R4; R4; R4; R4; R4;
|
||||||
pending_5380_count --;
|
R4; R4; R4; R4; R4; R4; R4; R4;
|
||||||
} else {
|
R4; R4; R4; R4; R4; R4; R4; R4;
|
||||||
#if DEBUG
|
R4; R4; R4; R4; R4; R4; R4; R4;
|
||||||
pdma_5380_state = "done in xfer out--waiting.";
|
R4; R4; R4; R4; R4; R4; R4; R4;
|
||||||
#endif
|
R4; R4; R4; R4; R4; R4; R4; R4; /* 512 */
|
||||||
while (!DONE);
|
count -= 512;
|
||||||
#if DEBUG
|
}
|
||||||
pdma_5380_state = "really done in xfer out.";
|
while (count >= 4) {
|
||||||
#endif
|
R4; count -= 4;
|
||||||
pdma_cleanup();
|
}
|
||||||
return;
|
#undef R4
|
||||||
|
data = (u_int8_t *) long_data;
|
||||||
|
drq = (u_int8_t *) long_drq;
|
||||||
|
while (count) {
|
||||||
|
#define R1 *data++ = *drq++
|
||||||
|
R1; count--;
|
||||||
|
#undef R1
|
||||||
}
|
}
|
||||||
#if DEBUG
|
|
||||||
} else {
|
} else {
|
||||||
pdma_5380_state = "drq when out of phase.";
|
int resid;
|
||||||
return;
|
|
||||||
#endif
|
/*
|
||||||
|
* Get the source address aligned.
|
||||||
|
*/
|
||||||
|
resid = count = 4 - (((int) pending_5380_data) & 0x3);
|
||||||
|
if (count < 4) {
|
||||||
|
data = (u_int8_t *) pending_5380_data;
|
||||||
|
drq = (u_int8_t *) ncr_5380_with_drq;
|
||||||
|
while (count) {
|
||||||
|
#define W1 *drq++ = *data++
|
||||||
|
W1; count--;
|
||||||
|
#undef W1
|
||||||
|
}
|
||||||
|
pending_5380_data += resid;
|
||||||
|
pending_5380_count -= resid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get ready to start the transfer.
|
||||||
|
*/
|
||||||
|
count = pending_5380_count;
|
||||||
|
long_drq = (volatile u_int32_t *) ncr_5380_with_drq;
|
||||||
|
long_data = (u_int32_t *) pending_5380_data;
|
||||||
|
|
||||||
|
#define W4 *long_drq++ = *long_data++
|
||||||
|
while ( count >= 64 ) {
|
||||||
|
W4; W4; W4; W4; W4; W4; W4; W4;
|
||||||
|
W4; W4; W4; W4; W4; W4; W4; W4;
|
||||||
|
count -= 64;
|
||||||
|
}
|
||||||
|
while (count >= 4) {
|
||||||
|
W4; count -= 4;
|
||||||
|
}
|
||||||
|
#undef W4
|
||||||
|
data = (u_int8_t *) long_data;
|
||||||
|
drq = (u_int8_t *) long_drq;
|
||||||
|
while (count) {
|
||||||
|
#define W1 *drq++ = *data++
|
||||||
|
W1; count--;
|
||||||
|
}
|
||||||
|
#undef W1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OK. No bus error occurred above. Clear the nofault flag
|
||||||
|
* so we no longer short-circuit bus errors.
|
||||||
|
*/
|
||||||
|
nofault = (int *) 0;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
pdma_5380_state = "handled drq interrupt.";
|
pdma_5380_state = "done in xfer--waiting.";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is this necessary?
|
||||||
|
*/
|
||||||
|
while (!( (GET_5380_REG(NCR5380_DMSTAT) & SC_ACK_STAT)
|
||||||
|
|| (GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ) ));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update pointers for pdma_cleanup().
|
||||||
|
*/
|
||||||
|
pending_5380_data += pending_5380_count;
|
||||||
|
pending_5380_count = 0;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
pdma_5380_state = "done in xfer.";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pdma_cleanup();
|
||||||
|
return;
|
||||||
#endif /* if USE_PDMA */
|
#endif /* if USE_PDMA */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,30 +530,30 @@ transfer_pdma(phasep, data, count)
|
|||||||
pdma_5380_state = "in transfer_pdma.";
|
pdma_5380_state = "in transfer_pdma.";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
scsi_idisable();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't bother with PDMA if we can't sleep.
|
* Don't bother with PDMA if we can't sleep or for small transfers.
|
||||||
*/
|
*/
|
||||||
if (reqp->dr_flag & DRIVER_NOINT) {
|
if (reqp->dr_flag & DRIVER_NOINT) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
pdma_5380_state = "using transfer_pio.";
|
pdma_5380_state = "pdma, actually using transfer_pio.";
|
||||||
#endif
|
#endif
|
||||||
transfer_pio(phasep, data, count, 0);
|
transfer_pio(phasep, data, count, 0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Match phases with target.
|
|
||||||
*/
|
|
||||||
SET_5380_REG(NCR5380_TCOM, *phasep);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We are probably already at spl2(), so this is likely a no-op.
|
* We are probably already at spl2(), so this is likely a no-op.
|
||||||
* Paranoia.
|
* Paranoia.
|
||||||
*/
|
*/
|
||||||
s = splbio();
|
s = splbio();
|
||||||
|
|
||||||
|
scsi_idisable();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Match phases with target.
|
||||||
|
*/
|
||||||
|
SET_5380_REG(NCR5380_TCOM, *phasep);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear pending interrupts.
|
* Clear pending interrupts.
|
||||||
*/
|
*/
|
||||||
@ -418,14 +562,12 @@ transfer_pdma(phasep, data, count)
|
|||||||
/*
|
/*
|
||||||
* Wait until target asserts BSY.
|
* Wait until target asserts BSY.
|
||||||
*/
|
*/
|
||||||
while ( ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) == 0) &&
|
while ( ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) == 0)
|
||||||
((GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) == 0) &&
|
&& (--scsi_timeout) );
|
||||||
((GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) == 0) &&
|
|
||||||
(--scsi_timeout) );
|
|
||||||
if (!scsi_timeout) {
|
if (!scsi_timeout) {
|
||||||
#if DIAGNOSTIC
|
#if DIAGNOSTIC
|
||||||
printf("scsi timeout: waiting for BSY in %s.\n",
|
printf("scsi timeout: waiting for BSY in %s.\n",
|
||||||
(pdma_5380_dir == 1) ? "pdma_out" : "pdma_in");
|
(*phasep == PH_DATAOUT) ? "pdma_out" : "pdma_in");
|
||||||
#endif
|
#endif
|
||||||
goto scsi_timeout_error;
|
goto scsi_timeout_error;
|
||||||
}
|
}
|
||||||
@ -460,19 +602,12 @@ transfer_pdma(phasep, data, count)
|
|||||||
panic("Unexpected phase in transfer_pdma.\n");
|
panic("Unexpected phase in transfer_pdma.\n");
|
||||||
case PH_DATAOUT:
|
case PH_DATAOUT:
|
||||||
pdma_5380_dir = 1;
|
pdma_5380_dir = 1;
|
||||||
|
SET_5380_REG(NCR5380_DMSTAT, 0);
|
||||||
break;
|
break;
|
||||||
case PH_DATAIN:
|
case PH_DATAIN:
|
||||||
pdma_5380_dir = 2;
|
pdma_5380_dir = 2;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initiate the DMA transaction--sending or receiving.
|
|
||||||
*/
|
|
||||||
if (pdma_5380_dir == 1) {
|
|
||||||
SET_5380_REG(NCR5380_DMSTAT, 0);
|
|
||||||
} else {
|
|
||||||
SET_5380_REG(NCR5380_IRCV, 0);
|
SET_5380_REG(NCR5380_IRCV, 0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user