📄 scsi_5380.c
字号:
i = szaddr->scs_reset; szaddr->scs_mode = SCS_PARCK; goto abort; } unit = sc->sc_unit[targid]; dp = &szutab[unit]; bp = dp->b_actf; if ((dp->b_active == 0) || (bp == 0)) { scsi_logerr(sc, 0, targid, SZ_ET_ACTSTAT, 0, 0, SZ_HARDERR); i = szaddr->scs_reset; if (force_reset) goto abort; else return; } /* * TODO: * Debug code. Can't remember ever hitting this one. */ if ((sc->sc_selstat[targid] != SZ_SELECT) && (sc->sc_selstat[targid] != SZ_RESELECT)) { flags = SZ_HARDERR | SZ_LOGSELST; scsi_logerr(sc, 0, targid, SZ_ET_ACTSTAT, 1, 0, flags); i = szaddr->scs_reset; goto abort; }#ifdef ELDEBUG if ((cntlr == 0) && (targid == sz_eldb_actstat)) { flags = SZ_HARDERR | SZ_LOGSELST; scsi_logerr(sc, 0, targid, SZ_ET_ACTSTAT, 1, 0, flags);/* ELDEBUG */ sz_eldb_actstat = -1; }#endif ELDEBUG save_selstat = sc->sc_selstat[targid]; /* if only DMA set, was phase mismatch intr */ if (sz_no_spin1) { if (sz_no_spin3) szaddr->scs_mode &= ~SCS_DMA; else if ((szaddr->scs_mode & (SCS_DMA|SCS_INTEOP)) == SCS_DMA) szaddr->scs_mode &= ~SCS_DMA; } } if (force_reset) /* bus reset detected, but we were not active */ goto abort; /* * If BSYERR set, target has disconnected. Say we are no * longer active. Start disconnect timer if target is a * disk. Call sz_start() to start next I/O, if possible. * Could also be a busy target (see below). */ if((szaddr->scs_status & SCS_BSYERR) == SCS_BSYERR) { szaddr->scs_mode = SCS_PARCK; /* clears MONBSY */ i = szaddr->scs_reset; if (sc->sc_szflags[targid] & SZ_BUSYTARG) { /* * Not a disconnect. Target returned a busy status and * cannot accept a command right now. So we queue a * timeout to resend the command later. */ sc->sc_selstat[targid] = SZ_IDLE; sc->sc_fstate = 0;/* szaddr->scs_mode = SCS_PARCK; */ szaddr->scs_tarcmd = 0; /* make sure phases match for 5380 */ szaddr->scs_outdata = 0; sc->sc_active = 0; /* channel no longer active */ if (sc->sc_dkn[targid] >= 0) dk_busy &= ~(1 << sc->sc_dkn[targid]); /* TODO: time should be device specific! */ timeout(sz_timer4, (caddr_t)unit, 50); /* 0.5 sec */ } else {sz_i_discon:#ifdef SZDEBUG printd2("szintr: disconnect\n");#endif SZDEBUG#ifdef DCT_STATS sc->sc_dcstart[targid] = sziaddr->nb_diagtime;#endif DCT_STATS sc->sc_selstat[targid] = SZ_DISCONN;/* szaddr->scs_mode = SCS_PARCK; */ szaddr->scs_tarcmd = 0; /* make sure phases match for 5380 */ szaddr->scs_outdata = 0; sc->sc_active = 0; /* channel no longer active */ if (sz_do_rsto) { /* * TODO: needs more work. * Ok for RZ22, RZ23, and RZ55. Who knows for RZxx? * Use longer timeout for floppy disk. * Do this at all? Use command timeout instead? * No timeout on format, reassign, vfy_data, and rdd commands. * Only timeout read, write, read capacity commands. */ if ((sc->sc_devtyp[targid] & SZ_DISK) && !sc->sc_rzspecial[targid]) { switch (sc->sc_curcmd[targid]) { case SZ_READ: case SZ_WRITE: case SZ_READ_10: case SZ_WRITE_10: case SZ_RDCAP: /* TODO: what about non-DEC floppy? */ if ((sc->sc_devtyp[targid] == RX23) || (sc->sc_devtyp[targid] == RX33)) { timeout(sz_timer2, (caddr_t)unit, hz*30); } else timeout(sz_timer2, (caddr_t)unit, hz*10); sc->sc_szflags[targid] |= SZ_TIMERON; break; default: break; } } } } /* * Select enable should already be on, BUT... */ szaddr->scs_selena = sc->sc_sysid; sc->sc_scs_selena = sc->sc_sysid; DELAY(10); /* * The bus can be busy again by the time we get here * because of the delay between the time BSYERR set * and we service the loss of BSY interrupt. * If SEL is true, then a device (can even be the one * that just disconnected) has grabbed the bus. So, * we don't call sz_start() to start the next I/O, since * the bus would be busy and arbitration would fail. * As soon as the IPL drops we will get a reselect interrupt. */ if (szaddr->scs_status & SCS_INTREQ) { if (szaddr->scs_curstat & SCS_SEL) return; } sz_start(sc, -1); /* Start next I/O (if one is ready) */ return; } /* * If we are not active, check for reselect. */ if(sc->sc_active == 0) { /* NOTE: make sure BSY false for bus settle delay (400 ns) */ /* * There is critical timing in the reselect code path. * Do not remove the spl6(). Even the clock must not * be allowed to interrupt this code. The result could * be multiple targets selected on the SCSI bus (very bad). */ s = spl6(); curstat = (szaddr->scs_curstat & SCS_BSY); curstat |= (szaddr->scs_curstat & SCS_BSY); curstat |= szaddr->scs_curstat; if ((curstat & (SCS_BSY|SCS_SEL|SCS_IO)) == (SCS_SEL|SCS_IO)) { i = szaddr->scs_mode; szaddr->scs_mode |= SCS_PARCK; /* be sure parity checking on */#ifdef SZDEBUG printd2("szintr: reselect\n");#endif SZDEBUG /* * Read bus ID bits from current data register. * Make sure only two ID bits on the bus * and one of them is the initiator's. * Don't respond to the reselect if there is a parity error. * Only log the parity error if ID bits on the data bus. * No IDs on the bus means its not being driven, i.e., * the target droped the reselect after the 5380 set INTREQ. */ scsi_id = szaddr->scs_curdata; szaddr->scs_mode = i; /* restore mode regsiter */ if (szaddr->scs_status & SCS_PARERR) { if (scsi_id != 0) { flags = SZ_HARDERR | SZ_LOGREGS | SZ_LOGBUS; scsi_logerr(sc, 0, -1, SZ_ET_PARITY, 1, scsi_id, flags); } i = szaddr->scs_reset; splx(s); return; } nbits = 0; for (tid = 0; tid < NDPS; tid++) if (scsi_id & (1 << tid)) nbits++;#ifdef ELDEBUG for (tid = 0; tid < NDPS; tid++) { if ((1 << tid) == sc->sc_sysid) continue; /* skip initiator */ if (scsi_id & (1 << tid)) break; } if ((cntlr == 0) && (tid == sz_eldb_reselerr0)) { nbits = 3; sz_eldb_reselerr0 = -1; }#endif ELDEBUG if ((nbits != 2) || ((scsi_id & sc->sc_sysid) == 0)) { flags = SZ_HARDERR | SZ_LOGBUS | SZ_LOGREGS; scsi_logerr(sc, 0, -1, SZ_ET_RESELERR, 0, scsi_id, flags); i = szaddr->scs_reset; splx(s); /* TODO: which way is correct? */ if (sz_i_midrst) { force_reset = 1; goto abort; } else return; } /* * Must assert BSY within 200 Usec after we detect * reselect, so we set BSY as soon as we can. */ szaddr->scs_inicmd = SCS_INI_BSY; for (tid = 0; tid < NDPS; tid++) { if ((1 << tid) == sc->sc_sysid) continue; /* skip initiator */ if (scsi_id & (1 << tid)) break; } sc->sc_active = (scsi_id & ~sc->sc_sysid); splx(s); /* end of critical timing sequence */ targid = tid; save_selstat = sc->sc_selstat[targid]; if (sc->sc_selstat[targid] != SZ_DISCONN) { flags = SZ_HARDERR | SZ_LOGSELST; scsi_logerr(sc, 0, targid, SZ_ET_RESELERR, 1, 0, flags); i = szaddr->scs_reset; szaddr->scs_inicmd = 0; /* clear BSY */ sc->sc_selstat[targid] = save_selstat; /* TODO: return or abort? */ /* TODO: this error is very bad news! what to do? */ return; } SZWAIT_WHILE(((szaddr->scs_curstat & SCS_SEL) == SCS_SEL),10000,retval); if(retval >= 10000) { flags = SZ_HARDERR; scsi_logerr(sc, 0, targid, SZ_ET_RESELERR, 2, 0, flags); /* TODO: temp read reset reg so don't loose interrupts */ i = szaddr->scs_reset; szaddr->scs_inicmd = 0; /* clear BSY */ sc->sc_active = 0; sc->sc_selstat[targid] = save_selstat; goto abort; } szaddr->scs_inicmd = 0; /* clear BSY */ /* NOTE: we are looking for BSY from the target */ DELAY(1); if (((szaddr->scs_curstat & SCS_BSY) == 0) && ((szaddr->scs_curstat & SCS_BSY) == 0) && ((szaddr->scs_curstat & SCS_BSY) == 0)) { flags = SZ_HARDERR; scsi_logerr(sc, 0, targid, SZ_ET_RESELERR, 3, 0, flags); i = szaddr->scs_reset; sc->sc_active = 0; sc->sc_selstat[targid] = save_selstat; return; } DELAY(200); if (((szaddr->scs_curstat & SCS_BSY) == 0) && ((szaddr->scs_curstat & SCS_BSY) == 0) && ((szaddr->scs_curstat & SCS_BSY) == 0)) { flags = SZ_HARDERR; scsi_logerr(sc, 0, targid, SZ_ET_RESELERR, 4, 0, flags); i = szaddr->scs_reset; sc->sc_active = 0; sc->sc_selstat[targid] = save_selstat; return; } /* NOTE: must turn scs_selena back on for any subsequent error */ sc->sc_selstat[targid] = SZ_RESELECT; unit = sc->sc_unit[targid]; dp = &szutab[unit]; bp = dp->b_actf; if ((dp->b_active == 0) || (bp == 0)) { flags = SZ_HARDERR; scsi_logerr(sc, 0, targid, SZ_ET_RESELERR, 5, 0, flags); i = szaddr->scs_reset; sc->sc_active = 0; szaddr->scs_selena = sc->sc_sysid; sc->sc_scs_selena = sc->sc_sysid; sc->sc_selstat[targid] = save_selstat; return; }#ifdef DCT_STATS sc->sc_dcend[targid] = sziaddr->nb_diagtime; /* diagtime counter wraps after 16 bits */ if (sc->sc_dcend[targid] < sc->sc_dcstart[targid]) sc->sc_dcend[targid] += 65536; sc->sc_dcdiff[targid] = sc->sc_dcend[targid]-sc->sc_dcstart[targid]; if (sc->sc_dcdiff[targid] > sc->sc_dclongest[targid]) sc->sc_dclongest[targid] = sc->sc_dcdiff[targid];#endif DCT_STATS } else { splx(s); /* cuz we set spl6() in above if statement */ /* * We get here when an interrupt occurs and we * are not active and the bus is free. We * assume this is a reselect timeout interrupt. * If no disconnected targets, then its a stray interrupt. * We reset the controller and ignore the interrupt. * We depend on the disconnect timeout (sz_timer2) * to kick the target and get it going again. * First, check for parity error. */ if (szaddr->scs_status & SCS_PARERR) { flags = SZ_HARDERR | SZ_LOGREGS; scsi_logerr(sc, 0, -1, SZ_ET_PARITY, 2, 0, flags); i = szaddr->scs_reset; return; } count = 0; for (i = 0; i < NDPS; i++) count += sc->sc_selstat[i]; if (count == 0) { flags = SZ_HARDERR | SZ_LOGREGS; scsi_logerr(sc, 0, -1, SZ_ET_STRYINTR, 0, 0, flags); } else { flags = SZ_HARDERR | SZ_LOGREGS | SZ_LOGSELST; scsi_logerr(sc, 0, -1, SZ_ET_STRYINTR, 1, 0, flags); } i = szaddr->scs_reset; return; } } /* * THIS CANNOT HAPPEN, unless the hardware * goes insane (like the first SCSI/SCSI controller). */ if (sc->sc_active == 0) { scsi_logerr(sc, 0, -1, SZ_ET_ACTSTAT, 2, 0, SZ_HARDERR); if (szaddr->scs_status & SCS_INTREQ) i = szaddr->scs_reset; return; }#ifdef ELDEBUG if ((cntlr == 0) && (targid != -1) && (targid == sz_eldb_cmdabrtd0)) { sz_eldb_cmdabrtd0 = -1; goto abort; }#endif ELDEBUG /* * The target controls the bus phase. We wait for REQ and BSY * to be asserted on the bus before determining which phase * is active. Once REQ and BSY are asserted, the appropiate action * is taken. */ /* TODO: moved from phase spin loop! */ if (sz_i_moveit) { szaddr->scs_mode = SCS_PARCK; /* * Turn off the SCS_INI_ENOUT driver */ inicmd_tmp &= ~SCS_INI_ENOUT; szaddr->scs_inicmd = inicmd_tmp; } /* TODO: end of moved code! */ exmsg_byte = 0; exmsg_sdtr = 0; complete = 0; do { if (sz_no_spin2) { if ((ftt == 0) && (szaddr->scs_status & SCS_MATCH)) { szaddr->scs_mode |= SCS_DMA; return; } ftt = 0; } for (retval = 0; retval < 100000; retval++) { if (((szaddr->scs_curstat & SCS_BSY) == 0) && ((szaddr->scs_curstat & SCS_BSY) == 0) && ((szaddr->scs_curstat & SCS_BSY) == 0)) { retval = 1000000; break; } if (szaddr->scs_curstat & SCS_REQ) break; DELAY(100); }#ifdef SPIN_STATS if ((retval > sc->sc_i_spin1[targid]) && (retval < 100000)) { sc->sc_i_spin1[targid] = retval; sc->sc_i_spcmd[targid] = sc->sc_curcmd[targid]; sc->sc_i_phase[targid] = ((szaddr->scs_curstat & SCS_PHA_MSK) >> 2); }#endif SPIN_STATS#ifdef ELDEBUG if ((cntlr == 0) && (targid == sz_eldb_buserr4e)) { retval = 1000000; sz_eldb_buserr4e = -1; } if ((cntlr == 0) && (targid == sz_eldb_buserr4f)) { retval = 100000; sz_eldb_buserr4f = -1; }#endif ELDEBUG if (retval >= 100000) { if (retval == 1000000) subtyp = 0x4e; /* BSY dropped */ else subtyp = 0x4f; /* REQ failed to set */ flags = SZ_HARDERR | SZ_LOGREGS; scsi_logerr(sc, 0, targid, SZ_ET_BUSERR, subtyp, 0, flags); /* TODO: temp read reset reg so don't loose interrupts */ /* TODO: caution, in a loop! */ i = szaddr->scs_reset; sc->sc_active = 0; szaddr->scs_selena = sc->sc_sysid; sc->sc_scs_selena = sc->sc_sysid; /* * This code is in a loop. How we handle this error * depends on whether or not its the fi
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -