📄 stc.c
字号:
* not a cartridge is present. */ /* Clear all flags so driver does not lock up after hard error */ sc->sc_flags = 0; sc->sc_category_flags = 0; sc->sc_stflags &= ~ST_NODEVICE; sc->sc_sns.errclass = 0; /* this allows the mechanism that sends the commands to the * drive to be able to tell that these commands are coming * from the open routine and need to be handled in a special * way. */ st_from_open++; do { sc->sc_sns.snskey = 0; if (unit_attn) { sc->sc_stflags |= st_rcvdiag(dev); } if (!(sc->sc_stflags & ST_NODEVICE)) { stcommand(dev, ST_TUR, 1); if(sc->sc_stflags & ST_NEED_SENSE) { stcommand(dev, ST_RQSNS, 1); switch(retval = sterror(sc)) { case ST_SUCCESS: break; case ST_RETRY: timeout(wakeup, (caddr_t)sc, hz/2); sleep((caddr_t)sc, PZERO + 1); retry++; if (!(sc->sc_flags & DEV_EOM)) { sc->sc_flags = 0; } break; case ST_FATAL: if (!(sc->sc_flags & DEV_EOM)) { sc->sc_flags = 0; } if(flag & FNDELAY) { sc->sc_stflags |= ST_NODEVICE; } else { return(ENXIO); } break; } } else { retval = ST_SUCCESS; } } else { retval = ST_SUCCESS; } } while ((retry < 10) && (retval == ST_RETRY)); if (retry >= 10) { if (!(flag & FNDELAY)) { DEV_UGH(sc->sc_device, unit, "offline"); return(EIO); } } /* * If ST_NODEVICE is not set, the device exists, * and we want to do a ST_MODSEL command */ if (!(sc->sc_stflags & ST_NODEVICE)) { stcommand(dev, ST_MODSEL, 1); } sc->sc_openf = 1; sc->sc_blkno = (daddr_t)0; sc->sc_nxrec = INF; st_from_open = 0; sc->sc_rate = ST_TIMERRATE; if ((sc->sc_timer & ST_TIMERON) == 0) { sc->sc_timer = ST_TIMERON; timeout(st_timer, 0, (sc->sc_rate * hz)); /* schedule timer starting */ }#ifdef STDEBUG ST_TRACK('O');#endif STDEBUG return (0);}/* */int st_rcvdiag(dev) register dev_t dev;{ register struct st_softc *sc = &st_softc[0]; int unit = UNIT(dev); int i; u_char *byteptr; byteptr = (u_char *)&sc->st_dat; /* zero the receive data area */ for (i = 0; i < ST_RECDIAG_LEN; i++) { *byteptr++ = 0; } /* * Issue this command twice, as the first one * after powerup always fails. */ stcommand(dev, ST_RECDIAG, 1); stcommand(dev, ST_RECDIAG, 1); if (sc->st_dat.dat.recdiag.ctlr_selftest != 0) { printf("st0: controller failed selftest\n"); return(ST_NODEVICE); } if (sc->st_dat.dat.recdiag.drv_selftest != 0 ) { printf("st0: drive failed selftest, code = 0x%x\n", sc->st_dat.dat.recdiag.drv_selftest); return(ST_NODEVICE); }#ifdef STDEBUG printd("st_rcvdiag: Rev. %d\n", sc->st_dat.dat.recdiag.ctlr_fw_rev);#endif STDEBUG if (sc->st_dat.dat.recdiag.ctlr_fw_rev < 32 ) { printf("st0: controller firmware rev %d not supported\n", sc->st_dat.dat.recdiag.ctlr_fw_rev); return(ST_NODEVICE); } /* clear unit_attn so that we won't call st_rcvdiag() on each open */ unit_attn = 0; return(ST_SUCCESS);}/* *//* * This timer is started in stopen(), and "goes off" every 30 seconds. * Whenever the timer "goes off" sc->sc_ticks is incremented and the * timeout value is looked up in st_timetable[] and checked against the * number sc->sc_ticks. If the number of ticks in st_timetable[] has * been exceeded, we assume either the TZK50 controller or the TK50 * drive has failed to respond and we attempt to reset the controller * and drive and return all outstanding requests with an error. */st_timer(unused)int unused;{ register struct uba_ctlr *um = stdinfo[0]->ui_mi; register struct st_softc *sc = &st_softc[0]; register struct buf *dp; register struct buf *bp; register struct nb1_regs *staddr = (struct nb1_regs *)qmem; register struct nb_regs *stiaddr = (struct nb_regs *)nexus; struct vsbuf *vs; struct vsdev *vd; int i, s, zs, z; dp = &stutab[0]; bp = dp->b_actf; vs = &vsbuf; vd = &vstapedev;#ifdef STDEBUG printd("tick..");#endif STDEBUG s = spl5(); /* * if the drive is not open, return. */ if (sc->sc_openf == 0) {#ifdef STDEBUG printd("\n");#endif STDEBUG sc->sc_timer = 0; sc->sc_ticks = 0; splx(s); return; } if (dp->b_actf == dp) { sc->sc_timer = ST_TIMERON;#ifdef STDEBUG printd(" No work\n");#endif STDEBUG } else { sc->sc_ticks++; if (sc->sc_ticks > (char)st_timetable[sc->sc_curcmd]) { sc->sc_ticks = 0;#ifdef STDEBUG printd("st_timer: sc->sc_curcmd = 0x%x\n", sc->sc_curcmd); if (sc->sc_selstat == ST_DISCONN) { printd("st0: waiting for reselect...\n"); } else { printd("st0: timeout -- What to do now?\n"); st_dump_softc(sc); }#endif STDEBUG /* call st_start with ST_RESET to reset the bus */ sc->sc_stflags |= ST_ENCR_ERR; sc->sc_xstate = ST_ERR; sc->sc_xevent = ST_RESET; /* * If the tape doesn't own the RAM buffer, call vs_bufctl * to have it allocated */ if (vs->vs_active != vd) { vd->vsd_action = VS_ALLOC; vd->vsd_funcptr = st_start; vs_bufctl(vd);#ifdef STDEBUG ST_TRACK('*');#endif STDEBUG return; } else { st_start(sc); /* * Make sure that the tape isn't hanging the system * by keeping the RAM buffer */ if (vs->vs_active == vd) { vd->vsd_action = VS_DEALLOC; vs_bufctl(vd); } } }#ifdef STDEBUG else { printd(" work\n"); }#endif STDEBUG } /* queue another watch dog timer */ sc->sc_timer = ST_TIMERON; timeout(st_timer, 0, (sc->sc_rate * hz)); splx(s); return;}/* */stclose(dev, flag) register dev_t dev; register int flag;{ register struct st_softc *sc = &st_softc[0]; register int unit = 0; register int sel = SEL(dev);#ifdef STDEBUG ST_TRACK('c');#endif STDEBUG sc->sc_flags &= ~DEV_EOM; if (flag == FWRITE || ((flag & FWRITE) && (sc->sc_flags & DEV_WRITTEN))) { stcommand(dev, ST_WFM, 2); sc->sc_flags &= ~DEV_EOM; stcommand(dev, ST_P_BSPACEF, 1); sc->sc_flags &= ~DEV_EOM; } /* if we need to rewind... */ if ((sel == MTLR) || (sel == MTHR)) { stcommand(dev, ST_REWIND, 0); } sc->sc_openf = 0;#ifdef STDEBUG ST_TRACK('C');#endif STDEBUG}/* */stcommand(dev, com, count) register dev_t dev; register int com; register int count;{ register struct buf *bp = &cstbuf[UNIT(dev)];#ifdef STDEBUG ST_TRACK('m');#endif STDEBUG while (bp->b_flags & B_BUSY) { if(bp->b_bcount == 0 && (bp->b_flags & B_DONE)) break; bp->b_flags |= B_WANTED; sleep((caddr_t)bp, PRIBIO); } /* Load the buffer. The b_count field gets used to hold the command * count. The b_resid field gets used to hold the command mnermonic. * These two fields are "known" to be "save" to use for this purpose. * (Most other drivers also use these fields in this way.) */ bp->b_flags = B_BUSY|B_READ; bp->b_dev = dev; bp->b_command = com; bp->b_bcount = count; bp->b_blkno = 0; ststrategy(bp); /* * In the case of rewind from close, don't wait. * This is the only case where count can be 0. */ if (count == 0) return; iowait(bp); if (bp->b_flags&B_WANTED) wakeup((caddr_t)bp); bp->b_flags &= B_ERROR;#ifdef STDEBUG ST_TRACK('M');#endif STDEBUG}/* */ststrategy(bp) register struct buf *bp;{ register struct uba_ctlr *um; register struct st_softc *sc = &st_softc[0]; register struct buf *dp; register struct vsdev *vd; register int s; int unit = 0;#ifdef STDEBUG ST_TRACK('t');#endif STDEBUG vd = &vstapedev; if ((sc->sc_flags & DEV_EOM) && !((sc->sc_flags & DEV_CSE) || (dis_eot_st[unit] & DISEOT))) { bp->b_resid = bp->b_bcount; bp->b_error = ENOSPC; bp->b_flags |= B_ERROR; biodone(bp); return; }#ifdef TM_NO_FIX sc->sc_category_flags &= ~DEV_TPMARK;#else if ((bp->b_flags&B_READ) && (bp->b_flags&B_RAWASYNC) && ((sc->sc_category_flags&DEV_TPMARK) || (sc->sc_flags&DEV_HARDERR))) { bp->b_error = EIO; bp->b_flags |= B_ERROR; biodone(bp); return; }#endif TM_NO_FIX bp->av_forw = NULL; /* * If ST_NODEVICE is set, the device was opened * with FNDELAY, but the device didn't respond. * We'll try again to see if the device is here, * if it is not, return an error */ if (sc->sc_stflags & ST_NODEVICE) { DEV_UGH(sc->sc_device,unit,"offline"); bp->b_resid = bp->b_bcount; bp->b_error = ENOSPC; bp->b_flags |= B_ERROR; biodone(bp); return; } um = stdinfo[unit]->ui_mi; s = spl5(); dp = &stutab[unit]; if (dp->b_actf == NULL) dp->b_actf = bp; else dp->b_actl->av_forw = bp; dp->b_actl = bp; if (dp->b_active == 0) { dp->b_active = 1; sc->sc_xstate = ST_NEXT; sc->sc_xevent = ST_BEGIN; /* * Call the routine that allocates the VAXSTAR 16K buffer * that the disk controller and tape controller share. * When the buffer is allocated to us (the tape driver) * st_start will be called from the allocation routine */ vd->vsd_action = VS_ALLOC; vd->vsd_funcptr = st_start; vs_bufctl(vd); } splx(s);#ifdef STDEBUG ST_TRACK('T');#endif STDEBUG}/* *//* * Interrupts come through here */stintr(){ register struct uba_ctlr *um = stdinfo[0]->ui_mi; register struct st_softc *sc = &st_softc[0]; register struct buf *dp; register struct buf *bp; register struct nb1_regs *staddr = (struct nb1_regs *)qmem; register struct nb_regs *stiaddr = (struct nb_regs *)nexus; register struct vsbuf *vs; register struct vsdev *vd; 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 sel_dly = 0; int arb_tries; int cmdcnt; int complete; int num_expected; vs = &vsbuf; vd = &vstapedev; dp = &stutab[0]; bp = dp->b_actf;#ifdef STDEBUG ST_TRACK('i');#endif STDEBUG /* * Check to make sure the tape owns the 16k hardware * buffer before touching any device registers. If * the tape doesn't have the buffer, request it. */ if(vs->vs_status != VS_ST) { sc->sc_stflags &= ~ST_RETD_KEEP; vd->vsd_action = VS_ALLOC; vd->vsd_funcptr = stintr; vs_bufctl(vd);#ifdef STDEBUG ST_TRACK('A');#endif STDEBUG return; }#ifdef STDEBUG printd6('T'); if (stdebug > 6) { printd("stintr:\n"); stdumpregs(); }#endif STDEBUG /* * If a disconnect, give the buffer back. We don't * need to save any pointers because we only have * one drive, and will take up where we left off * when a reselect occurs. */ if((staddr->scs_status & SCS_BSYERR) == SCS_BSYERR) {#ifdef STDEBUG printd2("stintr: disconnecting...\n");#endif STDEBUG sc->sc_selstat = ST_DISCONN; staddr->scs_mode = 0; i = staddr->scs_reset; if(sc->sc_stflags & ST_RETD_KEEP) { sc->sc_stflags &= ~ST_RETD_KEEP; vd->vsd_action = VS_DEALLOC; vs_bufctl(vd);#ifdef STDEBUG ST_TRACK('B');#endif STDEBUG } else { return(VS_DEALLOC); } return; } /* * If ST_DISCONN, check for reselect. */ if(sc->sc_selstat == ST_DISCONN) { if(((staddr->scs_curstat & (SCS_BSY|SCS_SEL|SCS_IO)) == (SCS_SEL|SCS_IO))) { sc->sc_selstat = ST_RESELECT;#ifdef STDEBUG ST_TRACK('G'); printd2("stintr: reselecting...\n");#endif STDEBUG inicmd_tmp = SCS_INI_BSY; staddr->scs_inicmd = inicmd_tmp; STWAIT_WHILE(((staddr->scs_curstat & SCS_SEL) == SCS_SEL),10000,retval); if(retval >= 10000) { mprintf("st0: device failed to reselect\n"); goto abort; } inicmd_tmp &= ~SCS_INI_BSY; staddr->scs_inicmd = inicmd_tmp; sc->sc_selstat = ST_SELECT; } } /* * The target controls the bus phase. We wait for REQ and BSY * to be asserted on the bus before determining which phase
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -