📄 tz.c
字号:
* end of record. * Fixed length blocks, an error. */ if (sp->endOfMedia) { bp->b_error = ENOSPC; bp->b_resid = resid; break; } if (sc->sc_blklen && sp->badBlockLen) { tprintf(sc->sc_ctty, "tz%d: Incorrect Block Length, expected %d got %d\n", unit, sc->sc_blklen, resid); break; } if (resid < 0) { /* * Variable length records but * attempted to read less than a * full record. */ tprintf(sc->sc_ctty, "tz%d: Partial Read of Variable Length Tape Block, expected %d read %d\n", unit, bp->b_bcount - resid, bp->b_bcount); bp->b_resid = 0; break; } if (sp->fileMark) sc->sc_flags |= TZF_SEENEOF; /* * Attempting to read more than a record is * OK. Just record how much was actually read. */ bp->b_flags &= ~B_ERROR; bp->b_error = 0; bp->b_resid = resid; break; case SCSI_CLASS7_UNIT_ATTN: if (!(sc->sc_flags & TZF_OPEN)) break; default: prerr: printf("tz%d: ", unit); scsiPrintSense((ScsiClass7Sense *) sc->sc_sense.sense, sizeof(sc->sc_sense.sense) - resid); } } } else if (error || (status & SCSI_STATUS_CHECKCOND)) {#ifdef DEBUG if (!cold && tzdebug) printf("tz%d: error %d scsi status 0x%x\n", unit, error, status);#endif /* save error info */ sc->sc_sense.status = status; bp->b_flags |= B_ERROR; bp->b_error = error; bp->b_resid = resid; if (status & SCSI_STATUS_CHECKCOND) { /* * Start a REQUEST_SENSE command. * Since we are called at interrupt time, we can't * wait for the command to finish; that's why we use * the sc_flags field. */ sc->sc_flags |= TZF_SENSEINPROGRESS; sc->sc_cdb.len = sizeof(ScsiGroup0Cmd); scsiGroup0Cmd(SCSI_REQUEST_SENSE, sc->sc_sd->sd_slave, 0, sizeof(sc->sc_sense.sense), (ScsiGroup0Cmd *)sc->sc_cdb.cdb); sc->sc_errbuf.b_flags = B_BUSY | B_PHYS | B_READ; sc->sc_errbuf.b_bcount = sizeof(sc->sc_sense.sense); sc->sc_errbuf.b_un.b_addr = (caddr_t)sc->sc_sense.sense; sc->sc_errbuf.b_actf = bp; sc->sc_errbuf.b_actb = bp->b_actb; *bp->b_actb = &sc->sc_errbuf; bp->b_actb = &sc->sc_errbuf.b_actf; tzstart(unit); return; } } else { sc->sc_sense.status = status; bp->b_resid = resid; } if (dp = bp->b_actf) dp->b_actb = bp->b_actb; else sc->sc_tab.b_actb = bp->b_actb; *bp->b_actb = dp; biodone(bp); if (sc->sc_tab.b_actf) tzstart(unit); else { sc->sc_tab.b_active = 0; if (sc->sc_flags & TZF_WAIT) { sc->sc_flags &= ~TZF_WAIT; wakeup(&sc->sc_flags); } }}/* ARGSUSED */tzopen(dev, flags, type, p) dev_t dev; int flags, type; struct proc *p;{ register int unit = tzunit(dev); register struct tz_softc *sc = &tz_softc[unit]; int error; if (unit >= NTZ || sc->sc_sd == NULL) return (ENXIO); if (!(sc->sc_flags & TZF_ALIVE)) { /* check again, tape may have been turned off at boot time */ if (!tzprobe(sc->sc_sd)) return (ENXIO); } if (sc->sc_flags & TZF_OPEN) return (EBUSY); /* clear UNIT_ATTENTION */ error = tzcommand(dev, SCSI_TEST_UNIT_READY, 0, 0, 0); while (error) { ScsiClass7Sense *sp = (ScsiClass7Sense *)sc->sc_sense.sense; /* return error if last error was not UNIT_ATTENTION */ if (!(sc->sc_sense.status & SCSI_STATUS_CHECKCOND) || sp->error7 != 0x70 || sp->key != SCSI_CLASS7_UNIT_ATTN) return (error); /* * Try it again just to be sure and * try to negotiate synchonous transfers. */ error = tzcommand(dev, SCSI_TEST_UNIT_READY, 0, 0, 0); } /* get the current mode settings */ error = tzcommand(dev, SCSI_MODE_SENSE, 0, sc->sc_modelen, (caddr_t)&sc->sc_mode); if (error) return (error); /* check for write protected tape */ if ((flags & FWRITE) && sc->sc_mode.writeprot) { uprintf("tz%d: write protected\n", unit); return (EACCES); } /* set record length */ switch (sc->sc_tapeid) { case MT_ISAR: case MT_ISHPDAT: case MT_ISVIPER1: sc->sc_blklen = 512; break; case MT_ISEXABYTE:#if 0 if (minor(dev) & TZ_FIXEDBLK) sc->sc_blklen = 1024; else sc->sc_blklen = st_exblklen;#endif break; case MT_ISPYTHON: case MT_ISMFOUR: case MT_ISTK50: sc->sc_blklen = 0; break; default: sc->sc_blklen = (sc->sc_mode.block_size2 << 16) | (sc->sc_mode.block_size1 << 8) | sc->sc_mode.block_size0; } /* save total number of blocks on tape */ sc->sc_numblks = (sc->sc_mode.blocks_2 << 16) | (sc->sc_mode.blocks_1 << 8) | sc->sc_mode.blocks_0; /* setup for mode select */ sc->sc_mode.len = 0; sc->sc_mode.media = 0; sc->sc_mode.bufferedMode = 1; sc->sc_mode.blocks_0 = 0; sc->sc_mode.blocks_1 = 0; sc->sc_mode.blocks_2 = 0; sc->sc_mode.block_size0 = sc->sc_blklen >> 16; sc->sc_mode.block_size1 = sc->sc_blklen >> 8; sc->sc_mode.block_size2 = sc->sc_blklen; /* check for tape density changes */ switch (sc->sc_tapeid) { case MT_ISAR: if (minor(dev) & TZ_HIDENSITY) sc->sc_mode.density = 0x5; else { if (flags & FWRITE) { uprintf("Can only write QIC-24\n"); return (EIO); } sc->sc_mode.density = 0x4; } break; case MT_ISMT02: /* * The tape density is set automatically when the tape * is loaded. We only need to change it if we are writing. */ if (flags & FWRITE) { if (minor(dev) & TZ_HIDENSITY) sc->sc_mode.density = 0; else sc->sc_mode.density = 0x4; } break; case MT_ISEXABYTE:#if 0 if (minor(dev) & TZ_HIDENSITY) uprintf("EXB-8200 density support only\n"); sc->sc_mode.vupb = (u_char)st_exvup; sc->sc_mode.rsvd5 = 0; sc->sc_mode.p5 = 0; sc->sc_mode.motionthres = (u_char)st_exmotthr; sc->sc_mode.reconthres = (u_char)st_exreconthr; sc->sc_mode.gapthres = (u_char)st_exgapthr;#endif break; case MT_ISHPDAT: case MT_ISVIPER1: case MT_ISPYTHON: case MT_ISTK50: if (minor(dev) & TZ_HIDENSITY) uprintf("tz%d: Only one density supported\n", unit); break; case MT_ISMFOUR: break; /* XXX could do density select? */ } /* set the current mode settings */ error = tzcommand(dev, SCSI_MODE_SELECT, 0, sc->sc_modelen, (caddr_t)&sc->sc_mode); if (error) return (error); sc->sc_ctty = tprintf_open(p); sc->sc_flags = TZF_ALIVE | TZF_OPEN; return (0);}tzclose(dev, flag) dev_t dev; int flag;{ register struct tz_softc *sc = &tz_softc[tzunit(dev)]; int error = 0; if (!(sc->sc_flags & TZF_OPEN)) return (0); if (flag == FWRITE || ((flag & FWRITE) && (sc->sc_flags & TZF_WRITTEN))) { error = tzcommand(dev, SCSI_WRITE_EOF, 0, 1, 0);#if 0 /* * Cartridge tapes don't do double EOFs on EOT. */ switch (sc->sc_tapeid) { case MT_ISAR: case MT_ISMT02: break; default: error = tzcommand(dev, SCSI_WRITE_EOF, 0, 1, 0); if (minor(dev) & TZ_NOREWIND) (void) tzcommand(dev, SCSI_SPACE, 0, -1, 0); }#endif } if ((minor(dev) & TZ_NOREWIND) == 0) (void) tzcommand(dev, SCSI_REWIND, 0, 0, 0); sc->sc_flags &= ~(TZF_OPEN | TZF_WRITTEN); tprintf_close(sc->sc_ctty); return (error);}tzioctl(dev, cmd, data, flag) dev_t dev; int cmd; caddr_t data; int flag;{ register struct tz_softc *sc = &tz_softc[tzunit(dev)]; register struct buf *bp = &sc->sc_buf; struct mtop *mtop; struct mtget *mtget; int code, count; static tzops[] = { SCSI_WRITE_EOF, SCSI_SPACE, SCSI_SPACE, SCSI_SPACE, SCSI_SPACE, SCSI_REWIND, SCSI_REWIND, SCSI_TEST_UNIT_READY }; switch (cmd) { case MTIOCTOP: /* tape operation */ mtop = (struct mtop *)data; if ((unsigned)mtop->mt_op < MTREW && mtop->mt_count <= 0) return (EINVAL); switch (mtop->mt_op) { case MTWEOF: code = 0; count = mtop->mt_count; break; case MTFSF: code = 1; count = mtop->mt_count; break; case MTBSF: code = 1; count = -mtop->mt_count; break; case MTFSR: code = 0; count = mtop->mt_count; break; case MTBSR: code = 0; count = -mtop->mt_count; break; case MTREW: case MTOFFL: case MTNOP: code = 0; count = 0; break; default: return (EINVAL); } return (tzcommand(dev, tzops[mtop->mt_op], code, count, 0)); case MTIOCGET: mtget = (struct mtget *)data; mtget->mt_dsreg = 0; mtget->mt_erreg = sc->sc_sense.status; mtget->mt_resid = 0; mtget->mt_type = 0; break; default: return (EINVAL); } return (0);}voidtzstrategy(bp) register struct buf *bp;{ register int unit = tzunit(bp->b_dev); register struct tz_softc *sc = &tz_softc[unit]; register struct buf *dp; register int s; if (sc->sc_flags & TZF_SEENEOF) { bp->b_resid = bp->b_bcount; biodone(bp); return; } bp->b_actf = NULL; dp = &sc->sc_tab; s = splbio(); bp->b_actb = dp->b_actb; *dp->b_actb = bp; dp->b_actb = &bp->b_actf; if (dp->b_active == 0) { dp->b_active = 1; tzstart(unit); } splx(s);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -