📄 scsi_5380.c
字号:
} /* * Keep the select timer running until 250 MS * timeout expires or the target asserts BSY. */ if (((szaddr->scs_curstat & SCS_BSY) == 0) && ((szaddr->scs_curstat & SCS_BSY) == 0) && ((szaddr->scs_curstat & SCS_BSY) == 0)) { if (++sc->sc_swcount < 5) { timeout(sz_timer3, (caddr_t)unit, 5); /* 50 MS */ splx(s); return; } } /* * Call the sz_start routine, which will call * sz_scsistart() to handle the select timeout * or complete the select, depending on whether * or not the target asserted BSY within 250 MS. */ sz_start(sc, targid); splx(s);}/* * * Name: sz_timer1 -hung bus detection timer * * Abstract: This timeout occurs every 0.2 seconds. It is * strated in the probe routine. If the driver * thinks the bus is idle (sc_active == 0) and * the bus is hung, then sz_timer1 resets the bus * and all software state information. sz_start * is called to get things going again. We declare * the bus hung if BSY is true and SEL is false * for 1 MS. * NOTE: have not tested the case where both * busses hang at the same time. * NOTE: cannot access 5380 registers if bus active. * NOTE: just return if bus reset in progress. * * Inputs: None. * * Outputs: None. * * Return Values: None. * * Side Effects: * IPL raised to 15. * The SCSI bus may be reset. * sz_start() called. * Another .2 second timeout will be queued. * */#ifdef ELDEBUG/* set to cntlr # to cause error */int sz_eldb_rstbus0 = -1;/* set to 0 to cause error, MUST also force an abort in szintr */int sz_eldb_rstbus1 = -1;/* set to 0 to cause error, MUST also force an abort in scsistart */int sz_eldb_rstbus2 = -1;/* set to cntlr # to cause error */int sz_eldb_busrst = -1;/* set to cntrl # to cause a parity error */int sz_eldb_parity = -1;/* Set to ID of target for command abort (on bus 0 only) */int sz_eldb_cmdabrtd0 = -1;int sz_eldb_cmdabrtd3 = -1;#endif ELDEBUGsz_timer1(unused)int unused;{ register struct sz_softc *sc; register struct sz_regs *szaddr; int i, s; int cntlr; int wedged; int flags;#ifdef ELDEBUG int inicmd_tmp;#endif ELDEBUG while (1) { s = spl5(); if (sz_do_timer1 == 0) break; for (cntlr = 0; cntlr < nNSCSI; cntlr++) { sc = &sz_softc[cntlr]; if (sc->sc_cntlr_alive == 0) /* cntlr does not exist */ continue; if (sc->sc_rip) /* bus reset in progress */ continue; if (sc->sc_active) /* bus active, not safe to */ continue; /* access 5380's registers */ /* * We assume bus hung if BSY stuck for 1 MS. */ szaddr = (struct sz_regs *)szmem + cntlr;#ifdef ELDEBUG if (cntlr == sz_eldb_busrst) { /* NOTE: spl5 - no need to mask interrupts */ szaddr->scs_inicmd = SCS_INI_RST; DELAY(25); szaddr->scs_inicmd = 0; sz_eldb_busrst = -1; } if (cntlr == sz_eldb_parity) { /* NOTE: read undriven data bus to cause parity error */ i = szaddr->scs_curdata; sz_eldb_parity = -1; }#endif ELDEBUG wedged = 1; for (i = 0; i < 1000; i++) { if (((szaddr->scs_curstat & SCS_BSY) == 0) && ((szaddr->scs_curstat & SCS_BSY) == 0) && ((szaddr->scs_curstat & SCS_BSY) == 0)) { wedged = 0; break; } DELAY(1); }#ifdef ELDEBUG if (cntlr == sz_eldb_rstbus0) { wedged = 1; sz_eldb_rstbus0 = -1; }#endif ELDEBUG if (wedged == 0) continue; /* * BSY stuck, we assume bus is hung. * Reset the bus and driver state. * Restart I/O operations. */ flags = SZ_HARDERR | SZ_LOGREGS; scsi_logerr(sc, 0, -1, SZ_ET_RSTBUS, 0, 0, flags); if (sz_t1_dorst == 0) { /* TODO: debug */ splx(s); return; /* kill timer, so we don't loop! */ } sz_reset(cntlr); } break; } /* queue another timer and return */ timeout(sz_timer1, 0, 20); /* 0.2 sec */ splx(s); return;}/* * If set to one, move the zeroing of the mode * register to before the spin on phase loop in szintr(). * The idea is to match Martin's note. * Never proved this made any difference one way or * the other. Leave as is because all testing done * with the code this way (sz_i_moveit = 1). */int sz_i_moveit = 1;/* * Controls whether on not we timeout * disconnected disks. * Leave this control on (sz_do_rsto = 1). */int sz_do_rsto = 1;/* * Count the number of Save Data Pointers, * Restore Data Pointers messages, and Implied * Save Data Pointers (disconnect not preceded by * a save data pointer message). * NOTE: this is debug information that came in handy * so many times I decided to keep it around. */extern int sz_sdp[];extern int sz_rdp[];extern int sz_isdp[];/* * These variables control the new code which * uses a phase mismatch interrupt instead of spinning * waiting for the phase to change (in critical cases). * To use the interrupt, set 1 & 3, but not 2. * TODO: this code needs more work. */int sz_no_spin1 = 1;int sz_no_spin2 = 0;int sz_no_spin3 = 1;#ifdef SZ_DSP_DEBUGint sz_nsp_print = 0; /* print, if command didn't do status phase */#endif SZ_DSP_DEBUGint sz_do_reset = 1; /* TODO: debug (cntl reset hung bus) */int wakeup();extern int hz;/* * Controls whether we reset the bus or * just ignore the reselect attempt, * when multiple IDs are detected. * Set to one to reset the bus. * TODO: not usre which is correct. */int sz_i_midrst = 0;/* * DEBUG - normally off * * If set, causes stray interrupt and reselect timeout * messages to console (they always go to the error log). *//* * If set, do an implied save data pointer * if the target disconnects without SDP. */int sz_do_isdp = 1;/* * * Name: szintr -Interrupt service routine * * Abstract: This routine fields interrupts from the SCSI bus * controllers (A & B) and performs the appropriate * actions. General flow is as follows: * * If the bus is active (target selected): * * 1. Find ID and bring target into context. * 2. Check for disconnect (loss of BSY). * 3. Follow phases set by target. * * If the bus is not active (no target selected): * 1. If its not a reselect - log stray interrupt. * 2. If reselect, bring target into context and * follow phases set by target. * * Inputs: * * IPL_device Device IPL is 14 (IPL 16 in critical code path). * cntlr SCSI bus controller number (0 = bus A, 1 = bus B). * * Interrupts A target reselects the initiator. * EOP - DMA count reaches zero (NOT USED). * Bus Parity Error (NOT USED). * Phase Mismatch (instead of EOP). * A target disconnected from the bus. * SCSI bus reset (NOT LATCHED!). * * * Outputs: None. * * Return Values: None. * * * Side Effects: * * Target's context in sz_softc is updated. * DMA transfers may be initiated or continued. * The SCSI bus can be reset (if hung). * Next command started by calling sz_start(). * Error messages may be logged to the console * and/or the error log. * *//* * BSY timing loop count (see SZ_DISCON: in SZ_MESSI:). * Don't change, 500 is a good balance for both * 90 and 60 NS CPUs. * NOTE: to disable BSY timing, set sz_i_btcnt = 1. */int sz_i_btcnt = 500;/*#define SZ_BT_DEBUG*/#ifdef SZ_BT_DEBUGint sz_i_bt[64]; /* 64 units - allows for 8 5380 cntlrs */#endif SZ_BT_DEBUG#ifdef ELDEBUG/* Set ID of target to cause reselect error 0 (on bus 0 only) */int sz_eldb_reselerr0 = -1;/* Set to cntlr # to cause error */int sz_eldb_stryintr0 = -1;int sz_eldb_stryintr1 = -1;/* Set ID of target to cause activity status error (on bus 0 only) */int sz_eldb_actstat = -1;/* Set ID of target to cause DBBR message to be logged (on bus 0 only) */int sz_eldb_dbbr0 = -1;int sz_eldb_dbbr1 = -1;int sz_eldb_dbbr2 = -1;int sz_eldb_dbbr3 = -1;/* Set ID of target to cause REQ failed to set (on bus 0 only) */int sz_eldb_buserra0 = -1;/* Set ID of target to cause REQ failed to clear (on bus 0 only) */int sz_eldb_buserr31 = -1;/* Set ID of target to cause rcv < 5 data bytes (on bus 0 only) */int sz_eldb_buserr12 = -1;/* Set ID of target to cause unknown message (on bus 0 only) */int sz_eldb_buserr73 = -1;int sz_eldb_buserrf3 = -1;/* Set ID of target to cause BSY hung on CMDCPT (on bus 0 only) */int sz_eldb_buserr74 = -1;/* Set ID of target to cause BSY not set on phase change (on bus 0 only) */int sz_eldb_buserr4e = -1;/* Set ID of target to cause REQ not set on phase change (on bus 0 only) */int sz_eldb_buserr4f = -1;#endif ELDEBUGszintr(cntlr)int cntlr;{ int unit, targid; int curstat, save_selstat; int tid, scsi_id, nbits; register struct sz_softc *sc; register struct buf *dp; register struct buf *bp; register struct sz_regs *szaddr = (struct sz_regs *)szmem + cntlr; register struct nb_regs *sziaddr = (struct nb_regs *)nexus; register int reg_cnt; /* MUST be a register for timing */ char *stv; /* virtual address of st page tables */ struct pte *pte, *mpte; /* used for mapping page table entries */ char *bufp; unsigned v; int o, npf; struct proc *rp; u_char *byteptr; int i, s, retval, count; int cmdcnt; int complete; int num_expected, num_received; u_char cmd_type; int exmsg_byte, exmsg_len, exmsg_cnt, exmsg_sdtr, exmsg_data; int ftt; int wedged, force_reset; int flags, subtyp; struct format_params *fp; struct reassign_params *rbp; struct read_defect_params *rdp; struct defect_descriptors *dd; struct mode_sel_sns_params *msp; struct io_uxfer *iox; int datacnt; force_reset = 0; sc = &sz_softc[cntlr];#ifdef ELDEBUG if (cntlr == sz_eldb_stryintr0) { flags = SZ_HARDERR | SZ_LOGREGS; scsi_logerr(sc, 0, -1, SZ_ET_STRYINTR, 0, 0, flags); /* ELDEBUG */ sz_eldb_stryintr0 = -1; } if (cntlr == sz_eldb_stryintr1) { flags = SZ_HARDERR | SZ_LOGREGS | SZ_LOGSELST; scsi_logerr(sc, 0, -1, SZ_ET_STRYINTR, 1, 0, flags); /* ELDEBUG */ sz_eldb_stryintr1 = -1; }#endif ELDEBUG /* * Ingore interrupts if bus reset in progress. * No interrupts should occur during reset wait period. */ if (sc->sc_rip) { i = szaddr->scs_reset; return; } ftt = 1; targid = -1; /* So sz_start() won't be called in abort: below */ /* * The RST bit in the scs_curstat register is not latched! * So, we use the PARCK bit in the mode register to detect * a bus reset. We set PARCK and never clear it, so if it * gets cleared we assume a bus reset did it. * If we detect a bus reset, we abort the current operation, * then force another bus reset. This makes sure we get back * to a known state if the reset was a glitch (not every * device detected the reset). */ if ((szaddr->scs_curstat & SCS_RST) || ((szaddr->scs_mode & SCS_PARCK) == 0)) { scsi_logerr(sc, 0, -1, SZ_ET_BUSRST, 0, 0, SZ_HARDERR); force_reset = 1; } /* * Use SCSI target ID to establish needed context. * If channel active use sc_active. * If not, read SCSI data bus during reselect. */ if (sc->sc_active) { for (targid = 0; targid < NDPS; targid++) if (sc->sc_active & (1 << targid)) break; if (szaddr->scs_status & SCS_PARERR) { flags = SZ_HARDERR | SZ_LOGREGS; scsi_logerr(sc, 0, targid, SZ_ET_PARITY, 0, 0, flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -