📄 scsi_sii.c
字号:
if (targid == sc->sc_sysid) continue; if (sc->sc_alive[targid] == 0) continue; /* TODO: check for dboff pase end of 128K buffer? */ if (sc->sc_devtyp[targid] & SZ_CDROM) { if (++ncz > szp_ncz) { sc->sc_alive[targid] = 0; continue; } sc->sc_dboff[targid] = dboff; sc->sc_segcnt[targid] = cz_slotsize; dboff += cz_slotsize; } else if (sc->sc_devtyp[targid] & SZ_TAPE) { if (++ntz > szp_ntz) { sc->sc_alive[targid] = 0; continue; } sc->sc_dboff[targid] = dboff; sc->sc_segcnt[targid] = tz_slotsize; dboff += tz_slotsize; } else if (sc->sc_devtyp[targid] & SZ_DISK) { sc->sc_dboff[targid] = dboff; sc->sc_segcnt[targid] = rz_slotsize; dboff += rz_slotsize; } else continue;#ifdef SZDEBUG PRINTD(-1, 0x8, ("sii_probe: cntlr=%d targid=%d ", cntlr, targid)); PRINTD(-1, 0x8, ("devtype=%x req/ack=%d slotsize=%d\n", sc->sc_devtyp[targid], sc->sc_siireqack[targid], sc->sc_segcnt[targid]));#endif SZDEBUG } } } if (sii_firstcall) sii_firstcall = 0;#ifdef SZDEBUG PRINTD(-1, 0x8, ("sii_probe: done probing the SCSI bus\n")); if(sii_debug_probe) { siidebug = save_siidebug; siitarget = save_siitarget; }#endif SZDEBUG return(alive);}/****************************************************************** * * Name: sii_timer * * Abstract: Handle command timeouts on the SII chip. * * Inputs: * unit The ULTRIX logical unit number of the scsi device. * * Outputs: None. * * Return values: None. ******************************************************************/sii_timer(unit)int unit;{ int cntlr, targid, s, retval; register struct sz_softc *sc; register struct sii_regs *siiaddr; int flags; s = spl5(); cntlr = (unit >> 3) & 1; siiaddr = (struct sii_regs *)cvqmsi + cntlr; sc = &sz_softc[cntlr]; targid = unit & 7; /* Ignore timeouts for the tape device */ if(sc->sc_devtyp[targid] & SZ_TAPE) {#ifdef SZDEBUG PRINTD(targid, 0x4, ("sii_timer: SZ_TAPE cmd timeout (bus=%d target=%d cmd=0x%x)\n", cntlr, targid, sc->sc_curcmd[targid]));#endif SZDEBUG flags = SZ_HARDERR | SZ_LOGCMD | SZ_LOGREGS; scsi_logerr(sc, 0, targid, SZ_ET_CMDTIMO, 0, 0, flags); sc->sc_szflags[targid] &= ~SZ_TIMERON; splx(s); return; } /* * The target disconnected and never reselected the SII. * If we can select the target then issue a Bus Device * Reset message to reset that target. This will cause * the SII to go to the bus free state. In the interrupt * routine the SII will then call "sz_start()" to finish * up this command. If we cannot select the target then * we simply reset the SCSI bus. */ if(sc->sc_szflags[targid] & SZ_WAS_DISCON) { /* Wait for scsi bus to be idle */ if (sc->sc_active) { timeout(sii_timer, (caddr_t)sc->sc_unit[targid], 10); splx(s); return; }#ifdef SZDEBUG PRINTD(targid, 0x4, ("sii_timer: DISCON cmd timeout (bus=%d target=%d cmd=0x%x)\n", cntlr, targid, sc->sc_curcmd[targid]));#endif SZDEBUG flags = SZ_HARDERR | SZ_LOGCMD | SZ_LOGREGS; scsi_logerr(sc, 0, targid, SZ_ET_CMDTIMO, 1, 0, flags); /* Try to select the disconnected target */ switch(retval = sii_select_target(sc, targid)) { case SZ_BUSBUSY: /* Target reselected so handle it now. */ if((siiaddr->sii_destat & SII_IDMSK) != targid) timeout(sii_timer, (caddr_t)sc->sc_unit[targid], 10); else timeout(sii_timer, (caddr_t)sc->sc_unit[targid], 30*hz); break; case SZ_SUCCESS: /* Target selected so set flag to reset it. */ sc->sc_szflags[targid] = SZ_RESET_DEV; break; default: /* Target is hung so reset the SCSI bus. */ scsi_logerr(sc, 0, -1, SZ_ET_RSTBUS, 0, 0, SZ_HARDERR); sii_reset(sc); } } /* * The currently active target has hung the SCSI bus. * Reset the SCSI bus and then return. */ else {#ifdef SZDEBUG PRINTD(targid, 0x4, ("sii_timer: ACTIVE cmd timeout (bus=%d target=%d cmd=0x%x)\n", cntlr, targid, sc->sc_curcmd[targid]));#endif SZDEBUG flags = SZ_HARDERR | SZ_LOGCMD | SZ_LOGREGS; scsi_logerr(sc, 0, targid, SZ_ET_CMDTIMO, 2, 0, flags); scsi_logerr(sc, 0, -1, SZ_ET_RSTBUS, 1, 0, SZ_HARDERR); sii_reset(sc); } splx(s);}/****************************************************************** * * Name: sii_scsistart * * Abstract: Start a SCSI operation on the SII chip. * * Inputs: * sc Pointer to sz_softc structure for this controller. * targid Target Id of device (0 - 7). * bp Buffer pointer for I/O request. * * Outputs: None. * * Return values: * SZ_SUCCESS Command completed successfully. * SZ_IP Command in progress waiting for interrupt. * SZ_RET_ERR Command failed (returned bad status). * SZ_RET_ABORT Command aborted. * SZ_BUSBUSY Bus is busy, retry the command later. * SZ_RET_RESET Resetting bus, retry command after bus reset. ******************************************************************/sii_scsistart(sc, targid, bp)register struct sz_softc *sc;int targid;register struct buf *bp;{ int cntlr = sc - &sz_softc[0]; register struct sii_regs *siiaddr = (struct sii_regs *)cvqmsi + cntlr; int retval, phase, timer, tvalue; int flags; /* Initialize variables */ scsi_bus_idle = 0; scsi_completed[targid] = 0; scsi_polled_mode = 0; sii_sent_cmd = 0; /* * If "bp" is "0" we use polled scsi mode, disallow reselect * attempts, and disable interrupts for all DMA transfers. We * poll for DMA completion instead of allowing interrupts. */ siiaddr->sii_csr |= (SII_RSE | SII_IE | SII_SLE); if(bp == (struct buf *)0) { siiaddr->sii_csr &= ~(SII_RSE | SII_IE); scsi_polled_mode = 1; } /* Perform target arbitration and selection */ if((retval = sii_select_target(sc, targid)) != SZ_SUCCESS) return(retval); /* Make sure that the command is in the sz_timetable. */ if (sc->sz_opcode < SZ_TIMETBL_SZ) { /* Set the timeout value for the current scsi command */ sc->sc_szflags[targid] |= SZ_TIMERON; if(sz_timetable[sc->sz_opcode] == 0) { tvalue = 2; timeout(sii_timer, (caddr_t)sc->sc_unit[targid], tvalue*30*hz); } else { tvalue = sz_timetable[sc->sz_opcode]; timeout(sii_timer, (caddr_t)sc->sc_unit[targid], tvalue*30*hz); } }BEGIN_LOOP: /* Loop through all bus phases until command complete */ do { /* Check for a BUS ERROR */ if(siiaddr->sii_cstat & SII_BER) siiaddr->sii_cstat = SII_BER; /* Check for a PARITY ERROR */ if(siiaddr->sii_dstat & SII_IPE) { flags = SZ_HARDERR | SZ_LOGREGS; scsi_logerr(sc, 0, targid, SZ_ET_PARITY, 0, 0, flags);#ifdef SZDEBUG PRINTD(targid, 0x4, ("sii_scsistart: scsi %d parity error\n", cntlr));#endif SZDEBUG goto HANDLE_ERROR; } /* Check for a BUS RESET */ if(siiaddr->sii_cstat & SII_RST_ONBUS) { siiaddr->sii_cstat = SII_RST_ONBUS; scsi_logerr(sc, 0, -1, SZ_ET_BUSRST, 0, 0, SZ_HARDERR);#ifdef SZDEBUG PRINTD(targid, 0x4, ("sii_scsistart: scsi %d bus reset\n", cntlr));#endif SZDEBUG goto HANDLE_ERROR; } /* Check for a STATE CHANGE */ if(siiaddr->sii_cstat & SII_SCH) { siiaddr->sii_cstat = SII_SCH; sii_state_change(sc, &targid); } /* If disconnected and went to BUS FREE STATE then break */ if(scsi_bus_idle) break; /* Check for a PHASE CHANGE */ if(siiaddr->sii_dstat & SII_MIS) { /* Check for a BUS ERROR */ if(siiaddr->sii_cstat & SII_BER) siiaddr->sii_cstat = SII_BER; /* Always clear DID DMA flag on a phase change */ sc->sc_szflags[targid] &= ~SZ_DID_DMA; /* Handle the current bus phase */ if(sii_phase_change(sc, targid) != SZ_SUCCESS) goto HANDLE_ERROR; /* Wait for the next bus phase */ if(!scsi_completed[targid] && !(sc->sc_szflags[targid] & (SZ_WAS_DISCON|SZ_DID_DMA))) { if(!scsi_polled_mode && sii_sent_cmd && !(siiaddr->sii_cstat & (SII_CI|SII_DI)) && (sc->sc_actcmd[targid] != SZ_RQSNS)) return(SZ_IP); } } /* Check for fragmented DMA transfers (>8K) */ if(scsi_polled_mode && !(siiaddr->sii_dstat & SII_MIS) && (siiaddr->sii_dstat & (SII_TBE|SII_IBF)) && !(sc->sc_szflags[targid] & SZ_DID_DMA) && ((sc->sc_fstate == SZ_DATAI_PHA) || (sc->sc_fstate == SZ_DATAO_PHA))) { /* Restart the DMA transfer */ if(!sii_restartdma(sc, targid)) {#ifdef SZDEBUG PRINTD(targid, 0x4, ("sii_scsistart: DMA error in sii_restartdma\n"));#endif SZDEBUG scsi_logerr(sc, 0, targid, SZ_ET_BUSERR, 0x0cd, 0, SZ_HARDERR); goto HANDLE_ERROR; } } /* Sometimes the target stays in the same phase */ if((siiaddr->sii_dstat & (SII_IBF|SII_TBE)) && !(siiaddr->sii_dstat & SII_MIS) && ((sc->sc_fstate != SZ_DATAI_PHA) && (sc->sc_fstate != SZ_DATAO_PHA))) { /* Check for a BUS ERROR */ if(siiaddr->sii_cstat & SII_BER) siiaddr->sii_cstat = SII_BER; /* Handle the current bus phase */ if(sii_phase_change(sc, targid) != SZ_SUCCESS) goto HANDLE_ERROR; } } while(!scsi_bus_idle && !(sc->sc_szflags[targid] & (SZ_WAS_DISCON|SZ_DID_DMA))); /* * Check the status of the current SCSI operation. If the SCSI * operation completed or disconnected then start the next SCSI * operation, otherwise wait for the DMA to complete. * */ if(scsi_bus_idle || (sc->sc_szflags[targid] & SZ_WAS_DISCON)) { /* Handle BUS DEVICE RESET and ABORT processing. */ if(sc->sc_szflags[targid] & (SZ_RESET_DEV|SZ_ABORT_CMD)) {#ifdef SZDEBUG PRINTD(targid, 0x4, ("sii_scsistart: BUS DEVICE RESET and ABORT processing\n"));#endif SZDEBUG if(sc->sc_szflags[targid] & SZ_TIMERON) { untimeout(sii_timer, (caddr_t)sc->sc_unit[targid]); sc->sc_szflags[targid] &= ~SZ_TIMERON; } if (sc->sc_dkn[targid] >= 0) dk_busy &= ~(1 << sc->sc_dkn[targid]); /* For a BUS DEVICE RESET we must wait for device. */ if(sc->sc_szflags[targid] & SZ_RESET_DEV) { scsi_logerr(sc, 0, targid, SZ_ET_RSTTARG, 0, 0, SZ_HARDERR); timeout(sii_restart_target, sc->sc_unit[targid], sz_wait_for_devices*hz); sc->sc_active = 0; sc->sc_fstate = 0; return(SZ_RET_RESET); } /* For an ABORT we simply retry the command. */ else { sc->sc_active = 0; sc->sc_fstate = 0; sc->sc_szflags[targid] = (SZ_NEED_SENSE|SZ_RETRY_CMD); return(SZ_RET_ERR); } } else if(scsi_completed[targid]) {#ifdef SZDEBUG PRINTD(targid, 0x8, ("sii_scsistart: COMMAND COMPLETED successfully\n"));#endif SZDEBUG if(sc->sc_szflags[targid] & SZ_TIMERON) { untimeout(sii_timer, (caddr_t)sc->sc_unit[targid]); sc->sc_szflags[targid] &= ~SZ_TIMERON; } sc->sc_active = 0; if(sc->sc_status[targid] == SZ_GOOD) return(SZ_SUCCESS); else return(SZ_RET_ERR); } else if(sc->sc_szflags[targid] & SZ_WAS_DISCON) {#ifdef SZDEBUG PRINTD(targid, 0x8, ("sii_scsistart: COMMAND IN PROGRESS disconnected\n"));#endif SZDEBUG return(SZ_IP); } else {#ifdef SZDEBUG PRINTD(targid, 0x4, ("sii_scsistart: (targid=%d) went to BUS FREE unexpectedly\n", targid));#endif SZDEBUG sc->sc_active = 0; if(sc->sc_szflags[targid] & SZ_TIMERON) { untimeout(sii_timer, (caddr_t)sc->sc_unit[targid]); sc->sc_szflags[targid] &= ~SZ_TIMERON; } return(SZ_RET_ERR); } } else if(sc->sc_szflags[targid] & SZ_DID_DMA) { /* Poll and busy wait for DMA completion */ if(scsi_polled_mode) {#ifdef SZDEBUG PRINTD(targid, 0x8,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -