📄 scsi_tape.c
字号:
* units */ sc->sc_category_flags[targid] = 0; } /* * to maintain tape position across closes we * look at the tape mark pending flag (fixed block units) * if so we back space across it. */ if( sc->sc_category_flags[targid] & TPMARK_PENDING){ tzcommand(dev, SZ_P_BSPACEF, 1, 0); sc->sc_category_flags[targid] &= ~TPMARK_PENDING; sc->sc_category_flags[targid] &= ~DEV_TPMARK; } } sc->sc_openf[targid] = 0;}tzcommand(dev, com, count, retry) register dev_t dev; register int com; register int count; register int retry;{ int unit = UNIT(dev); register struct buf *bp = &cszbuf[unit]; 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_comand = com; bp->b_bcount = count; bp->b_blkno = 0; bp->b_retry = retry; tzstrategy(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;}tzstrategy(bp) register struct buf *bp;{ struct uba_device *ui; register struct uba_ctlr *um; register struct sz_softc *sc; register struct buf *dp; register int s; int unit = UNIT(bp->b_dev); int targid; int cntlr; ui = szdinfo[unit]; targid = ui->ui_slave; cntlr = ui->ui_ctlr; sc = &sz_softc[cntlr]; if ((sc->sc_flags[targid]&DEV_EOM) && !((sc->sc_flags[targid]&DEV_CSE) || (dis_eot_sz[unit] & DISEOT))) { bp->b_resid = bp->b_bcount; bp->b_error = ENOSPC; bp->b_flags |= B_ERROR; biodone(bp); return; } if ((bp->b_flags&B_READ) && (bp->b_flags&B_RAWASYNC) && ((sc->sc_category_flags[targid]&DEV_TPMARK) || (sc->sc_flags[targid]&DEV_HARDERR))) { bp->b_error = EIO; bp->b_flags |= B_ERROR; biodone(bp); return; } /* * Fixed block tapes.... If the tape mark pending * flag is set then set DEV_TPMARK and clear pending * for nbuf ..and reads (sync). */ if ((bp->b_flags&B_READ) && !(bp->b_flags&B_RAWASYNC) && (sc->sc_category_flags[targid] & TPMARK_PENDING)) { sc->sc_category_flags[targid] |= DEV_TPMARK; sc->sc_category_flags[targid] &= ~TPMARK_PENDING; bp->b_resid = bp->b_bcount; biodone(bp); return; } bp->av_forw = NULL; /* * If SZ_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_szflags[targid] & SZ_NODEVICE) { DEV_UGH(sc->sc_device[targid],unit,"offline"); bp->b_resid = bp->b_bcount; bp->b_error = ENOSPC; bp->b_flags |= B_ERROR; biodone(bp); return; }#ifdef vax s = spl5();#endif vax#ifdef mips s = splbio();#endif mips dp = &szutab[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) && (sc->sc_active == 0)) { sc->sc_xstate[targid] = SZ_NEXT; sc->sc_xevent[targid] = SZ_BEGIN; sz_start(sc, targid); } splx(s);}tzread(dev, uio) register dev_t dev; register struct uio *uio;{ int unit = UNIT(dev); return (physio(tzstrategy, &rszbuf[unit], dev, B_READ, minphys, uio));}tzwrite(dev, uio) register dev_t dev; register struct uio *uio;{ int unit = UNIT(dev); return (physio(tzstrategy, &rszbuf[unit], dev, B_WRITE, minphys, uio));}tzioctl(dev, cmd, data, flag) dev_t dev; register int cmd; caddr_t data; int flag;{ register struct uba_device *ui; register struct sz_softc *sc; register struct uba_ctlr *um; int unit = UNIT(dev); int cntlr; int targid; register int callcount; register int fcount; struct mtop *mtop; struct mtget *mtget; struct devget *devget; struct sz_modsns_dt *msdp; struct scsi_devtab *sdp; struct tape_opt_tab *todp; /* we depend of the values and order of the MT codes here * static stops[] = { SZ_WFM,SZ_P_FSPACEF,SZ_P_BSPACEF,SZ_P_FSPACER, * SZ_P_BSPACER,SZ_REWIND,SZ_P_UNLOAD,SZ_P_CACHE, * SZ_P_NOCACHE,SZ_RQSNS }; */#define SZ_SZNOP SZ_INQ /* we depend on the values and order of the MT codes here */ static stops[] = { SZ_WFM,SZ_P_FSPACEF,SZ_P_BSPACEF,SZ_P_FSPACER, /* MTWEOF MTFSF MTBSF MTFSR */ SZ_P_BSPACER,SZ_REWIND,SZ_P_UNLOAD,SZ_SZNOP, /* MTBSR MTREW MTOFFL MTNOP */ SZ_P_CACHE,SZ_P_NOCACHE,SZ_RQSNS,SZ_RQSNS, /* MTCACHE MTNOCACHE MTCSE MTCLX */ SZ_RQSNS,SZ_SZNOP,SZ_SZNOP,SZ_SZNOP,SZ_SZNOP,SZ_SZNOP, /* MTCLS MTENAEOT MTDISEOT MTFLUSH MTGTON MTGTOFF */ SZ_P_RETENSION}; /* MTRETEN */ ui = szdinfo[unit]; cntlr = ui->ui_ctlr; um = szminfo[cntlr]; targid = ui->ui_slave; sc = &sz_softc[cntlr]; sdp = (struct scsi_devtab *)sc->sc_devtab[targid]; /* * get our tape option struct if available */ if( sdp->opt_tab){ todp = (struct tape_opt_tab *)sdp->opt_tab; } PRINTD(targid, 0x2, ("tzioctl: switch cmd %x\n", cmd ) ); switch (cmd) { case MTIOCTOP: /* tape operation */ /* * If SZ_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_szflags[targid] & SZ_NODEVICE) { DEV_UGH(sc->sc_device[targid],unit,"offline"); return(ENXIO); } mtop = (struct mtop *)data; PRINTD(targid, 0x2, ("tzioctl: switch MTIOCTOP data %x\n", mtop->mt_op)); switch (mtop->mt_op) { case MTWEOF: callcount = 1; if( sc->sc_category_flags[targid] & TPMARK_PENDING){ fcount = mtop->mt_count - 1; sc->sc_category_flags[targid] &= ~TPMARK_PENDING; } else { fcount = mtop->mt_count; } break; case MTFSF: callcount = 1; if( sc->sc_category_flags[targid] & TPMARK_PENDING){ fcount = mtop->mt_count - 1; if (fcount < 0 ){ fcount = 0; } if( fcount == 0){ sc->sc_category_flags[targid] &= ~TPMARK_PENDING; sc->sc_category_flags[targid] |= DEV_TPMARK; } else { sc->sc_category_flags[targid] &= ~TPMARK_PENDING; } } else { fcount = mtop->mt_count; } break; case MTBSF: callcount = 1; if( sc->sc_category_flags[targid] & TPMARK_PENDING){ fcount = mtop->mt_count + 1; sc->sc_category_flags[targid] &= ~TPMARK_PENDING; } else { fcount = mtop->mt_count; } break; case MTFSR: callcount = 1; if( sc->sc_category_flags[targid] & TPMARK_PENDING){ fcount = mtop->mt_count - 1; if (fcount < 0 ){ fcount = 0; } if( fcount == 0){ sc->sc_category_flags[targid] &= ~TPMARK_PENDING; sc->sc_category_flags[targid] |= DEV_TPMARK; } else { sc->sc_category_flags[targid] &= ~TPMARK_PENDING; } } else { fcount = mtop->mt_count; } break; case MTBSR: callcount = 1; if( sc->sc_category_flags[targid] & TPMARK_PENDING){ fcount = mtop->mt_count + 1; sc->sc_category_flags[targid] &= ~TPMARK_PENDING; } else { fcount = mtop->mt_count; } break; case MTOFFL: sc->sc_flags[targid] |= DEV_OFFLINE; sc->sc_category_flags[targid] &= ~TPMARK_PENDING; case MTREW: sc->sc_flags[targid] &= ~DEV_EOM; sc->sc_category_flags[targid] &= ~TPMARK_PENDING; callcount = 1; fcount = 1; break; case MTNOP: return(0); case MTCACHE: case MTNOCACHE: return(ENXIO); case MTFLUSH: return (ENXIO); case MTCSE: /* * Clear Serious Exception, used by tape utilities * to clean up after Nbuf I/O and end of media. */ sc->sc_category_flags[targid] &= ~DEV_TPMARK; sc->sc_flags[targid] |= DEV_CSE; return(0); case MTCLX: case MTCLS: return(0); case MTENAEOT: dis_eot_sz[unit] = 0; return(0); case MTDISEOT: dis_eot_sz[unit] = DISEOT; sc->sc_flags[targid] &= ~DEV_EOM; return(0); case MTRETEN: /* RETENSION command... */ sc->sc_flags[targid] &= ~DEV_EOM; sc->sc_category_flags[targid] &= ~TPMARK_PENDING; callcount = 1; fcount = 1; break; default: return (ENXIO); } if (callcount <= 0 || fcount <= 0) return (EINVAL); while (--callcount >= 0) { tzcommand(dev, stops[mtop->mt_op], fcount, 0); if (sc->sc_c_status[targid] != SZ_GOOD) { if ((sc->sc_c_snskey[targid] != SZ_NOSENSE) && (sc->sc_c_snskey[targid] != SZ_RECOVERR)) return(EIO); if (sc->sc_category_flags[targid] & DEV_TPMARK) return(EIO); } } return(0); /* TODO: these are bogus values, fix and test if possible! */ case MTIOCGET: /* tape status */ mtget = (struct mtget *)data; mtget->mt_dsreg = sc->sc_flags[targid]; /* send cur flags */ mtget->mt_erreg = 0; /* TODO: not correct value? */ mtget->mt_resid = sc->sc_resid[targid]; mtget->mt_type = MT_ISST; break; case DEVIOCGET: /* device status */ devget = (struct devget *)data; bzero(devget,sizeof(struct devget)); devget->category = DEV_TAPE;#ifdef vax devget->bus = DEV_NB; bcopy(DEV_VS_SCSI, devget->interface, strlen(DEV_VS_SCSI));#endif vax#ifdef mips devget->bus = DEV_SCSI; bcopy(DEV_SCSI_GEN, devget->interface, strlen(DEV_SCSI_GEN));#endif mips bcopy(sc->sc_device[targid], devget->device, DEV_SIZE); devget->adpt_num = um->um_adpt; devget->nexus_num = 0; devget->bus_num = 0; devget->ctlr_num = cntlr; devget->rctlr_num = 0; devget->slave_num = targid; bcopy("tz", devget->dev_name, 3); devget->unit_num = unit; devget->soft_count = sc->sc_softcnt[targid]; devget->hard_count = sc->sc_hardcnt[targid]; devget->stat = sc->sc_flags[targid]; /* * we only want the lower 4 bits at this time * the rest is density which gwts filled in later */ devget->category_stat = (sc->sc_category_flags[targid] & 0X0F); /* * Do a mode sense to check for write locked drive. * First one can fail due to unit attention. */ tzcommand(dev, SZ_MODSNS, -1, 0); if (sc->sc_c_status[targid] != SZ_GOOD) tzcommand(dev, SZ_MODSNS, -1, 0); if (sc->sc_c_status[targid] == SZ_GOOD) { msdp = (struct sz_modsns_dt *)&sc->sz_dat[targid]; if (msdp->wp) { /* Tape is write locked. */ devget->stat |= DEV_WRTLCK; } /* * Setup the tape density. */ if (msdp->density <= density_entrys) { devget->category_stat |= density_table[msdp->density]; } /* * Setup default density codes. */ if (msdp->density == SCSI_DENS_DEFAULT) { switch (sdp->devtype) { case TZ05: devget->category_stat |= DEV_1600BPI; break; case TZ07: devget->category_stat |= DEV_6250BPI; break; case TZ30: case TZK50: devget->category_stat |= DEV_6666BPI; break; case TZK10: devget->category_stat |= DEV_16000_BPI; break; case TLZ04: devget->category_stat |= DEV_61000_BPI; break; case TZK08: devget->category_stat |= DEV_54000_BPI; break; default: if (sdp->opt_tab) { if (todp->opt_flags & SCSI_QIC) { devget->category_stat |= DEV_10000_BPI; } else if (todp->opt_flags & SCSI_9TRK) { devget->category_stat |= DEV_6250BPI; } } break; } /* End 'switch (sdp->devtype)' */ } /* End 'if (msdp->density == SCSI_DENS_DEFAULT)' */ } /* End 'if (sc->sc_c_status[targid] == SZ_GOOD)' */ break; default: return (ENXIO); break; } return (0);}/* * * Name: tzcomplete -Tape completion routine * * Abstract: This routine is called from the scsi state machine * to perform the completion work for the current data * transfer. * * Inputs: * * bp Buffer pointer of command to be completed. * * Outputs: * Only printing debug messages. * * Return Values: Nothing formal, b_resid is updated. * * Side Effects: * biodone() is called to free up the current bp. * The buffer queue is changed to free up the front entry. * */int tzcomplete( bp ) struct buf *bp;{ struct uba_device *ui; struct sz_softc *sc; register struct buf *dp; int unit; int targid; unit = UNIT(bp->b_dev); ui = szdinfo[unit]; sc = &sz_softc[ui->ui_ctlr]; targid = ui->ui_slave; dp = &szutab[unit]; PRINTD( targid, 0x01, ("tzcomplete called unit %d\n", UNIT(bp->b_dev)) ); /* * Remove the completed request from the queue * and release the buffer. */ /* TODO: are we absolutely sure dp is valid? */ dp->b_actf = bp->av_forw; bp->b_resid = sc->sc_resid[targid]; PRINTD(targid, 0x5, ("tzcomplete: resid = %d\n", bp->b_resid)); biodone(bp); sc->sc_flags[targid] |= DEV_DONE; sc->sc_xevent[targid] = SZ_BEGIN; sz_retries[sc->sc_unit[targid]] = 0; /* * The comand has ended */ dp->b_active = 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -