/* * Wait for request-line to become inactive. When it doesn't return 0. * Otherwise return != 0. */ extern inline int wait_req_false(void) { int timeout = 2500000; while ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ) && --timeout) delay(1); return (!(GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ)); }
static __inline__ void scsi_clr_ipend(void) { int tmp; tmp = GET_5380_REG(NCR5380_IRCV); scsi_clear_irq(); }
/* * The body of the driver. */ static void scsi_main(struct ncr_softc *sc) { SC_REQ *req, *prev; int itype; int sps; /* * While running in the driver SCSI-interrupts are disabled. */ scsi_idisable(); ENABLE_NCR5380(sc); PID("scsi_main1"); for (;;) { sps = splbio(); if (!connected) { /* * Check if it is fair keep any exclusive access to DMA * claimed. If not, stop queueing new jobs so the discon_q * will be eventually drained and DMA can be given up. */ if (!fair_to_keep_dma()) goto main_exit; /* * Search through the issue-queue for a command * destined for a target that isn't busy. */ prev = NULL; for (req=issue_q; req != NULL; prev = req, req = req->next) { if (!(busy & (1 << req->targ_id))) { /* * Found one, remove it from the issue queue */ if (prev == NULL) issue_q = req->next; else prev->next = req->next; req->next = NULL; break; } } /* * When a request has just ended, we get here before an other * device detects that the bus is free and that it can * reconnect. The problem is that when this happens, we always * baffle the device because our (initiator) id is higher. This * can cause a sort of starvation on slow devices. So we check * for a pending reselection here. * Note that 'connected' will be non-null if the reselection * succeeds. */ if ((GET_5380_REG(NCR5380_IDSTAT) & (SC_S_SEL|SC_S_IO)) == (SC_S_SEL|SC_S_IO)){ if (req != NULL) { req->next = issue_q; issue_q = req; } splx(sps); reselect(sc); scsi_clr_ipend(); goto connected; } /* * The host is not connected and there is no request * pending, exit. */ if (req == NULL) { PID("scsi_main2"); goto main_exit; } /* * Re-enable interrupts before handling the request. */ splx(sps); #ifdef DBG_REQ if (dbg_target_mask & (1 << req->targ_id)) show_request(req, "TARGET"); #endif /* * We found a request. Try to connect to the target. If the * initiator fails arbitration, the command is put back in the * issue queue. */ if (scsi_select(req, 0)) { sps = splbio(); req->next = issue_q; issue_q = req; splx(sps); #ifdef DBG_REQ if (dbg_target_mask & (1 << req->targ_id)) ncr_tprint(req, "Select failed\n"); #endif } } else splx(sps); connected: if (connected) { /* * If the host is currently connected but a 'real-DMA' transfer * is in progress, the 'end-of-DMA' interrupt restarts main. * So quit. */ sps = splbio(); if (connected && (connected->dr_flag & DRIVER_IN_DMA)) { PID("scsi_main3"); goto main_exit; } splx(sps); /* * Let the target guide us through the bus-phases */ while (information_transfer(sc) == -1) ; } } /* NEVER TO REACH HERE */ panic("ncr5380-SCSI: not designed to come here"); main_exit: /* * We enter here with interrupts disabled. We are about to exit main * so interrupts should be re-enabled. Because interrupts are edge * triggered, we could already have missed the interrupt. Therefore * we check the IRQ-line here and re-enter when we really missed a * valid interrupt. */ PID("scsi_main4"); scsi_ienable(); /* * If we're not currently connected, enable reselection * interrupts. */ if (!connected) SET_5380_REG(NCR5380_IDSTAT, SC_HOST_ID); if (scsi_ipending()) { if ((itype = check_intr(sc)) != INTR_SPURIOUS) { scsi_idisable(); splx(sps); if (itype == INTR_RESEL) reselect(sc); #ifdef REAL_DMA else dma_ready(); #else else { if (pdma_ready()) goto connected; panic("Got DMA interrupt without DMA"); } #endif scsi_clr_ipend(); goto connected; }