📄 scsi_tape.c
字号:
* * Side Effects: * tzcommand() called. * */int tz_rcvdiag(dev) register dev_t dev;{ register struct uba_device *ui; register struct sz_softc *sc; int unit = UNIT(dev); int targid; int i; u_char *byteptr; u_char minrev, actrev; struct scsi_devtab *sdp; ui = szdinfo[unit]; sc = &sz_softc[ui->ui_ctlr]; targid = ui->ui_slave; sdp = (struct scsi_devtab *)sc->sc_devtab[targid]; /* zero the receive data area */ byteptr = (u_char *)&sc->sz_dat[targid]; for (i = 0; i < SZ_RECDIAG_LEN; i++) *byteptr++ = 0; /* * TODO - TZxx: * TZxx tapes may not support the RCV DIAG command. * For now, we just return success. We should do the RCV * DIAG command and look at the results if it succeeds. */ if (sdp->flags & SCSI_NODIAG) { sz_unit_rcvdiag[unit] = 1; return(SZ_SUCCESS); } /* * Try 10 times to receive diagnostic results. * First try after power up (or other unit attention) * will fail. */ for (i = 0; i < 10; i++) { tzcommand(dev, SZ_RECDIAG, 1, 0); if (sc->sc_c_status[targid] == SZ_GOOD) break; } if (i >= 10) { printf("%s unit %d: receive diagnostics command failed.\n", sc->sc_device[targid], unit); if (sz_open_fst) return(SZ_NODEVICE); } if (sc->sz_dat[targid].dat.recdiag.ctlr_selftest != 0) { printf("%s unit %d: controller selftest failed.\n", sc->sc_device[targid], unit); if (sz_open_fst) return(SZ_NODEVICE); } if (sc->sz_dat[targid].dat.recdiag.drv_selftest != 0 ) { printf("%s unit %d: drive selftest failed, code = 0x%x\n", sc->sc_device[targid], unit, sc->sz_dat[targid].dat.recdiag.drv_selftest); if (sz_open_fst) return(SZ_NODEVICE); } if (sc->sc_devtyp[targid] == TZK50) minrev = tz_tzk50_minrev; else if (sc->sc_devtyp[targid] == TZ30) minrev = tz_tz30_minrev; else minrev = 0; if (minrev) { actrev = sc->sz_dat[targid].dat.recdiag.ctlr_fw_rev; if (actrev < minrev) { printf("CAUTION: %s unit %d %s %d, should be %d or later!\n", sc->sc_device[targid], unit, "firmware revision is", actrev, minrev); } } /* * Clear unit_rcvdiag flag, only if everything is ok, * so we don't call tz_rcvdiag() on every open. */ sz_unit_rcvdiag[unit] = 1; return(SZ_SUCCESS);}/* * Name: tzclose -Tape close routine * * Abstract: This routine is called when the tape is closed. * If the tape was opened for writing and actually * written on, then write two file marks and back * space over the second one so the tape ends up * positioned between the two file marks. Rewind * the tape unless it was opened for no rewind. * * Inputs: * * dev ULTRIX major/minor device number. * flag How opened flag (write or read). * * Outputs: * Exclusive use open flag (sc_openf) cleared. * * Return Values: none. * * Side Effects: * tzcommand() called. * *//* TODO: what if - open FNDELAY then close (could rewind tape)? */tzclose(dev, flag) register dev_t dev; register int flag;{ register struct sz_softc *sc; register struct uba_device *ui; int unit = UNIT(dev); int targid; register int sel = SEL(dev); struct scsi_devtab *sdp; struct tape_opt_tab *todp; struct tape_info *ddp; ui = szdinfo[unit]; targid = ui->ui_slave; sc = &sz_softc[ui->ui_ctlr]; sdp = (struct scsi_devtab *)sc->sc_devtab[targid]; /* * get our tape option struct if available */ if( sdp->opt_tab != NULL ){ todp = (struct tape_opt_tab *)sdp->opt_tab; /* * since there is no bp must do it by the dev number */ ddp = &todp->tape_info[((minor(dev)&DENS_MASK)>>3)]; } /* TODO: do we really need to clear this flag 3 times? */ sc->sc_flags[targid] &= ~DEV_EOM; if (sz_unit_online[unit]) { /* only if unit still on-line */ if (flag == FWRITE || ((flag & FWRITE) && (sc->sc_flags[targid] & DEV_WRITTEN))) { /* TODO: may want to retry this one? */ /* TODO: need to check for errors */ /* * check to see if the one_fm flag is set.. * we write one file mark... This is * done for QIC type units.. blankchk * is the logical end of tape detection */ if(sdp->opt_tab){ if( (ddp->tape_flags & ONE_FM) == 0){ tzcommand(dev, SZ_WFM, 2, 0); } else { tzcommand(dev, SZ_WFM, 1, 0); } } else{ tzcommand(dev, SZ_WFM, 2, 0); } /* TODO: need to check for errors */ if(sdp->opt_tab){ if( (ddp->tape_flags & ONE_FM) == 0 ){ tzcommand(dev, SZ_P_BSPACEF, 1, 0); } } else{ tzcommand(dev, SZ_P_BSPACEF, 1, 0); } sc->sc_flags[targid] &= ~DEV_EOM; } /* if we need to rewind... */ if ( (sel & NO_REWIND) == 0 ) { /* no error check, because we don't wait for completion */ tzcommand(dev, SZ_REWIND, 0, 0); /* * must clear out the tpmark_pending flag for fixed * units. */ sc->sc_category_flags[targid] = 0; } /* * to maintain tape position across closes we look at the * at the tape mark pending (fixed block unit) 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;}/* * * Name: tzcommand -Tape command rountine * * Abstract: This routine is called to execute non data transfer * commands (test unit ready, rewind, etc.). It * sets up the command in cszbuf and calls tzstrategy * to queue the command. * * Inputs: * * dev ULTRIX major/minor device number. * com SCSI command type (see scsivar.h). * count Count argument to some commands. * retry If 1, retry command if it fails. * * Outputs: * B_ERROR can be set in bp->b_flags. * * Return Values: None. * * Side Effects: * iowait() on all commands except rewind. * sleep() called. * tzstrategy() called. * */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;}/* * Name: tzstrategy -Tape strategy routine * * Abstract: This routine is called to queue a command for * execution. The routine validates the command * parameters then places it on the I/O queue * of the specified unit. sz_start() is called * if there is not activity. * * Inputs: * * bp Buffer pointer of command to be queued. * * Outputs: * Possible error messages (unit offline). * * Return Values: None. * * bp->b_error: * ENOSPC Reached end of media. * EIO Cancel nbufio commands after end of file. * * Side Effects: * IPL raised to 15 to queue buffer. * */tzstrategy(bp) register struct buf *bp;{ register struct uba_ctlr *um; register struct buf *dp; register int s; int unit = UNIT(bp->b_dev); int targid; int cntlr; register struct sz_softc *sc; struct uba_device *ui; 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 ..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; } s = spl5(); 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);}/* * * Name: tzread -Tape physio read routine * * Abstract: This routine is called to for RAW I/O reads. * Calls physio() with appropriate arguments. * * Inputs: * * dev ULTRIX major/minor device number. * uio Pointer to user I/O (uio) structure. * * Outputs: None. * * Return Values: * Returns value returned by physio(). * * Side Effects: * physio() and tzstrategy() called. * minphys() limits maximum transfer size. * */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)); }/* * * Name: tzwrite -Tape physio write routine * * Abstract: This routine is called to for RAW I/O writes. * Calls physio() with appropriate arguments. * * Inputs: * * dev ULTRIX major/minor device number. * uio Pointer to user I/O (uio) structure. * * Outputs: None. * * Return Values: * Returns value returned by physio(). * * Side Effects:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -