diff options
-rw-r--r-- | sys/arch/mac68k/dev/mac68k5380.c | 152 |
1 files changed, 97 insertions, 55 deletions
diff --git a/sys/arch/mac68k/dev/mac68k5380.c b/sys/arch/mac68k/dev/mac68k5380.c index 72bb0f51380..5c4fdca77d4 100644 --- a/sys/arch/mac68k/dev/mac68k5380.c +++ b/sys/arch/mac68k/dev/mac68k5380.c @@ -66,7 +66,7 @@ #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 @@ -175,24 +175,27 @@ int pdma_5380_dir = 0; 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 @@ -206,8 +209,8 @@ pdma_cleanup(void) 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 @@ -241,7 +244,13 @@ pdma_cleanup(void) /* * 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 @@ -254,8 +263,8 @@ pdma_ready() 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 @@ -263,6 +272,9 @@ extern u_char ncr5380_no_parchk; */ dmstat = GET_5380_REG(NCR5380_DMSTAT); if (!(dmstat & SC_IRQ_SET)) { +#if NCR5380_PDMA_DEBUG + DBG_SET("irq not set.") +#endif return 0; } /* @@ -276,12 +288,18 @@ extern u_char ncr5380_no_parchk; 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; @@ -354,11 +372,25 @@ extern int *nofault, mac68k_buserr_addr; * 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 /* @@ -370,8 +402,8 @@ extern int *nofault, mac68k_buserr_addr; 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); @@ -386,8 +418,8 @@ extern int *nofault, mac68k_buserr_addr; 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; @@ -396,11 +428,18 @@ extern int *nofault, mac68k_buserr_addr; 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) { @@ -418,6 +457,9 @@ extern int *nofault, mac68k_buserr_addr; 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; @@ -429,8 +471,8 @@ extern int *nofault, mac68k_buserr_addr; 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; } @@ -456,6 +498,9 @@ extern int *nofault, mac68k_buserr_addr; 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) { @@ -469,11 +514,18 @@ extern int *nofault, mac68k_buserr_addr; } 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) { @@ -491,6 +543,9 @@ extern int *nofault, mac68k_buserr_addr; 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; @@ -505,6 +560,9 @@ extern int *nofault, mac68k_buserr_addr; 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) { @@ -523,28 +581,10 @@ extern int *nofault, mac68k_buserr_addr; */ 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 */ } @@ -566,16 +606,16 @@ transfer_pdma(phasep, data, count) 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; @@ -618,19 +658,13 @@ transfer_pdma(phasep, data, count) 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 /* @@ -642,14 +676,22 @@ transfer_pdma(phasep, data, count) 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. |