#undef DBG_PIO /* Show the polled-I/O process */
#undef DBG_INF /* Show information transfer process */
#define DBG_NOSTATIC /* No static functions, all in DDB trace*/
-#undef DBG_PID /* Keep track of driver */
+#define DBG_PID 15 /* Keep track of driver */
#undef REAL_DMA /* Use DMA if sensible */
#define fair_to_keep_dma() 1
#define claimed_dma() 1
u_char *pending_5380_data;
u_long pending_5380_count;
-/* #define DEBUG 1 Maybe we try with this off eventually. */
+#define NCR5380_PDMA_DEBUG 1 /* Maybe we try with this off eventually. */
-#if DEBUG
+#if NCR5380_PDMA_DEBUG
int pdma_5380_sends = 0;
int pdma_5380_bytes = 0;
-char *pdma_5380_state="";
+char *pdma_5380_state="", *pdma_5380_prev_state="";
+#define DBG_SET(x) {pdma_5380_prev_state=pdma_5380_state; pdma_5380_state=(x);}
void
pdma_stat()
{
printf("PDMA SCSI: %d xfers completed for %d bytes.\n",
pdma_5380_sends, pdma_5380_bytes);
- printf("pdma_5380_dir = %d.\n",
+ printf("pdma_5380_dir = %d\t",
pdma_5380_dir);
printf("datap = 0x%x, remainder = %d.\n",
pending_5380_data, pending_5380_count);
- printf("pdma_5380_state = %s.\n", pdma_5380_state);
+ printf("state: %s\t", pdma_5380_state);
+ printf("last state: %s\n", pdma_5380_prev_state);
+ scsi_show();
}
#endif
pdma_5380_dir = 0;
-#if DEBUG
- pdma_5380_state = "in pdma_cleanup().";
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("in pdma_cleanup().")
pdma_5380_sends++;
pdma_5380_bytes+=(reqp->xdata_len - pending_5380_count);
#endif
/*
* Back for more punishment.
*/
+#if NCR5380_PDMA_DEBUG
+ pdma_5380_state = "pdma_cleanup() -- going back to run_main().";
+#endif
run_main(cur_softc);
+#if NCR5380_PDMA_DEBUG
+ pdma_5380_state = "pdma_cleanup() -- back from run_main().";
+#endif
}
#endif
extern u_char ncr5380_no_parchk;
if (pdma_5380_dir) {
-#if DEBUG
- pdma_5380_state = "got irq interrupt in xfer.";
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("got irq interrupt in xfer.")
#endif
/*
* If Mr. IRQ isn't set one might wonder how we got
*/
dmstat = GET_5380_REG(NCR5380_DMSTAT);
if (!(dmstat & SC_IRQ_SET)) {
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("irq not set.")
+#endif
return 0;
}
/*
if ( ((dmstat & (0xff & ~SC_ATN_STAT)) == SC_IRQ_SET)
&& ((idstat & (SC_S_BSY|SC_S_REQ))
== (SC_S_BSY | SC_S_REQ)) ) {
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("BSY|REQ.")
+#endif
pdma_cleanup();
return 1;
} else if (PH_IN(reqp->phase) && (dmstat & SC_PAR_ERR)) {
if (!(ncr5380_no_parchk & (1 << reqp->targ_id)))
/* XXX: Should be parity error ???? */
reqp->xs->error = XS_DRIVER_STUFFUP;
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("PARITY.")
+#endif
/* XXX: is this the right reaction? */
pdma_cleanup();
return 1;
* If we're not ready to xfer data, just return.
*/
if ( !(GET_5380_REG(NCR5380_DMSTAT) & SC_DMA_REQ)
- || !pdma_5380_dir)
+ || !pdma_5380_dir) {
return;
+ }
-#if DEBUG
- pdma_5380_state = "got drq interrupt.";
+ /*
+ * I don't think this should be necessary, but it is
+ * for writes--at least to some devices. They don't
+ * let go of PH_DATAOUT until we do pdma_cleanup().
+ */
+ if (pending_5380_count == 0) {
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("forcing pdma_cleanup().")
+#endif
+ pdma_cleanup();
+ return;
+ }
+
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("got drq interrupt.")
#endif
/*
if (setjmp((label_t *) nofault)) {
nofault = (int *) 0;
-#if DEBUG
- pdma_5380_state = "buserr in xfer.";
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("buserr in xfer.")
#endif
count = ( (u_long) mac68k_buserr_addr
- (u_long) ncr_5380_with_drq);
pending_5380_data += count;
pending_5380_count -= count;
-#if DEBUG
- pdma_5380_state = "handled bus error in xfer.";
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("handled bus error in xfer.")
#endif
mac68k_buserr_addr = 0;
return;
if (pdma_5380_dir == 2) { /* Data In */
int resid;
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("Data in.")
+#endif
/*
* Get the dest address aligned.
*/
- resid = count = 4 - (((int) pending_5380_data) & 0x3);
- if (count < 4) {
+ resid = count = min(pending_5380_count,
+ 4 - (((int) pending_5380_data) & 0x3));
+ if (count && (count < 4)) {
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("Data in (aligning dest).")
+#endif
data = (u_int8_t *) pending_5380_data;
drq = (u_int8_t *) ncr_5380_with_drq;
while (count) {
while (pending_5380_count) {
int dcount;
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("Data in (starting read).")
+#endif
dcount = count = min(pending_5380_count, MIN_PHYS);
long_drq = (volatile u_int32_t *) ncr_5380_with_drq;
long_data = (u_int32_t *) pending_5380_data;
pending_5380_data += (dcount - count);
pending_5380_count -= (dcount - count);
-#if DEBUG
- pdma_5380_state = "drq low";
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("drq low")
#endif
return;
}
R4; count -= 4;
}
#undef R4
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("Data in (finishing up).")
+#endif
data = (u_int8_t *) long_data;
drq = (u_int8_t *) long_drq;
while (count) {
} else {
int resid;
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("Data out.")
+#endif
/*
* Get the source address aligned.
*/
- resid = count = 4 - (((int) pending_5380_data) & 0x3);
- if (count < 4) {
+ resid = count = min(pending_5380_count,
+ 4 - (((int) pending_5380_data) & 0x3));
+ if (count && (count < 4)) {
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("Data out (aligning dest).")
+#endif
data = (u_int8_t *) pending_5380_data;
drq = (u_int8_t *) ncr_5380_with_drq;
while (count) {
while (pending_5380_count) {
int dcount;
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("Data out (starting write).")
+#endif
dcount = count = min(pending_5380_count, MIN_PHYS);
long_drq = (volatile u_int32_t *) ncr_5380_with_drq;
long_data = (u_int32_t *) pending_5380_data;
W4; count -= 4;
}
#undef W4
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("Data out (cleaning up).")
+#endif
data = (u_int8_t *) long_data;
drq = (u_int8_t *) long_drq;
while (count) {
*/
nofault = (int *) 0;
-#if DEBUG
- pdma_5380_state = "done in xfer--waiting.";
-#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.";
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("done in xfer.")
#endif
- pdma_cleanup();
- return;
#endif /* if USE_PDMA */
}
panic("ncrscsi: transfer_pdma called when operation already "
"pending.\n");
}
-#if DEBUG
- pdma_5380_state = "in transfer_pdma.";
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("in transfer_pdma.")
#endif
/*
* Don't bother with PDMA if we can't sleep or for small transfers.
*/
if (reqp->dr_flag & DRIVER_NOINT) {
-#if DEBUG
- pdma_5380_state = "pdma, actually using transfer_pio.";
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("pdma, actually using transfer_pio.")
#endif
transfer_pio(phasep, data, count, 0);
return -1;
*/
reqp->dr_flag |= DRIVER_IN_DMA;
- /*
- * Set DMA mode and assert data bus.
- */
- SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) | SC_M_DMA);
- SET_5380_REG(NCR5380_ICOM, GET_5380_REG(NCR5380_ICOM) | SC_ADTB);
-
/*
* Load transfer values for DRQ interrupt handlers.
*/
pending_5380_data = data;
pending_5380_count = len;
-#if DEBUG
- pdma_5380_state = "wait for interrupt.";
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("setting up for interrupt.")
#endif
/*
panic("Unexpected phase in transfer_pdma.\n");
case PH_DATAOUT:
pdma_5380_dir = 1;
+ SET_5380_REG(NCR5380_ICOM, GET_5380_REG(NCR5380_ICOM)|SC_ADTB);
+ SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA);
SET_5380_REG(NCR5380_DMSTAT, 0);
break;
case PH_DATAIN:
pdma_5380_dir = 2;
+ SET_5380_REG(NCR5380_ICOM, 0);
+ SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA);
SET_5380_REG(NCR5380_IRCV, 0);
break;
}
+#if NCR5380_PDMA_DEBUG
+ DBG_SET("wait for interrupt.")
+#endif
+
/*
* Now that we're set up, enable interrupts and drop processor
* priority back down.