📄 st.c
字号:
msd.blks1 = 0; msd.blks0 = 0; msd.rsvd4 = 0; msd.blklen2 = (sc->sc_blklen >> 16) & 0xff; msd.blklen1 = (sc->sc_blklen >> 8) & 0xff; msd.blklen0 = sc->sc_blklen & 0xff; /* * Do we have any density problems? */ switch (sc->sc_tapeid) { case MT_ISAR: if (minor(dev) & STDEV_HIDENSITY) msd.density = 0x5; else { if (flag & FWRITE) { uprintf("Can only write QIC-24\n"); return(EIO); } msd.density = 0x4; } break; case MT_ISEXABYTE: if (minor(dev) & STDEV_HIDENSITY) uprintf("EXB-8200 density support only\n"); msd.vupb = (u_char)st_exvup; msd.rsvd5 = 0; msd.p5 = 0; msd.motionthres = (u_char)st_exmotthr; msd.reconthres = (u_char)st_exreconthr; msd.gapthres = (u_char)st_exgapthr; break; case MT_ISHPDAT: case MT_ISVIPER1: case MT_ISPYTHON: if (minor(dev) & STDEV_HIDENSITY) uprintf("Only one density supported\n"); break; case MT_ISMFOUR: break; /* XXX could do density select? */ default: uprintf("Unsupported drive\n"); return(EIO); } modlen = sc->sc_datalen[CMD_MODE_SELECT]; modsel.cdb[4] = modlen; /* mode select */ count = 0;retryselect: stat = scsi_immed_command(ctlr, slave, unit, &modsel, (u_char *)&msd, modlen, B_WRITE); /* * First command after power cycle, bus reset or tape change * will error. Try command again */ if (stat == STS_CHECKCOND) { sc->sc_filepos = 0; stxsense(ctlr, slave, unit, sc); stat = scsi_immed_command(ctlr, slave, unit, &modsel, (u_char *)&msd, modlen, B_WRITE);#ifdef DEBUG if (stat && (st_debug & ST_OPEN)) printf("stopen: stat on mode select 0x%x second try\n", stat);#endif if (stat == STS_CHECKCOND) { stxsense(ctlr, slave, unit, sc); prtkey(UNIT(dev), sc); } if (stat) return(EIO); } if (stat == -1 || stat == STS_BUSY) { /* * XXX it might just be that the bus is busy because * another tape is doing a command. This would change * with connect/disconnect, ie. the other drive would * not hold onto the bus. * * Sleep on lbolt for up to 20 minutes (max time to FSF * an exabyte to EOT: 16:xx minutes) */ if (++count > 60*20) { uprintf("SCSI bus timeout\n"); return(EBUSY); } if (error = tsleep((caddr_t)&lbolt, PZERO | PCATCH, "st_scsiwait", 0)) return (error); goto retryselect; } /* drive ready ? */ stat = scsi_test_unit_rdy(ctlr, slave, unit); if (stat == STS_CHECKCOND) { stxsense(ctlr, slave, unit, sc); switch (sc->sc_tapeid) { case MT_ISEXABYTE: if ((xsense->sc_xsense.key & XSK_NOTRDY) && xsense->exb_xsense.tnp) uprintf("no cartridge\n"); else if (xsense->sc_xsense.key & XSK_NOTRDY) uprintf("cartridge not loaded\n"); else if (xsense->sc_xsense.key & XSK_UNTATTEN) { uprintf("new cart/power interrupt\n"); stat = 0; } else if ((xsense->sc_xsense.key & XSK_UNTATTEN) && xsense->exb_xsense.tnp) uprintf("cartridge unloading\n"); else prtkey(UNIT(dev), sc); break; case MT_ISMFOUR: case MT_ISAR: if (xsense->sc_xsense.key & XSK_UNTATTEN) stat = scsi_test_unit_rdy(ctlr, slave, unit); if (stat == STS_CHECKCOND) { stxsense(ctlr, slave, unit, sc); if (xsense->sc_xsense.key) prtkey(UNIT(dev), sc); } else { sc->sc_filepos = 0; /* new tape */ stat = 0; } break; case MT_ISHPDAT: case MT_ISVIPER1: case MT_ISPYTHON: if (xsense->sc_xsense.key & XSK_UNTATTEN) stat = scsi_test_unit_rdy(ctlr, slave, unit); if (stat == STS_CHECKCOND) { stxsense(ctlr, slave, unit, sc); if (xsense->sc_xsense.key) prtkey(UNIT(dev), sc); } break; default: uprintf("st%d: not ready\n", UNIT(dev)); prtkey(UNIT(dev), sc); break; } } if (stat) return(EIO); /* mode sense */ modlen = sc->sc_datalen[CMD_MODE_SENSE]; modsense.cdb[4] = modlen; stat = scsi_immed_command(ctlr, slave, unit, &modsense, (u_char *)&mode, modlen, B_READ);#ifdef DEBUG if (st_debug & ST_OPENSTAT) prtmodstat(&mode);#endif if (stat == STS_CHECKCOND) { stxsense(ctlr, slave, unit, sc);#ifdef DEBUG if (st_debug & ST_OPEN) dumpxsense(xsense);#endif } if (stat) return(EIO); if ((flag & FWRITE) && mode.md.wp) { uprintf("st:%d write protected\n", UNIT(dev)); return(EACCES); } /* save total number of blocks on tape */ sc->sc_numblks = mode.md.numblk2 << 16 | mode.md.numblk1 << 8 | mode.md.numblk0; if (xsense->sc_xsense.eom && !(sc->sc_flags & STF_LEOT)) sc->sc_filepos = 0;#ifdef DEBUG if (st_debug & ST_FMKS) printf("st%d: open filepos = %d\n", UNIT(dev), sc->sc_filepos);#endif sc->sc_flags |= (STF_OPEN); if (flag & FWRITE) sc->sc_flags |= STF_WMODE; sc->sc_flags &= ~STF_MOVED;#ifdef TTI /* make stats available, also lit up TTi display */ sc->sc_tticntdwn = 100;#endif stxsense(ctlr, slave, unit, sc); return(0);}/*ARGSUSED*/stclose(dev, flag) dev_t dev; int flag;{ register struct st_softc *sc = &st_softc[UNIT(dev)]; register int hit = 0; if ((sc->sc_flags & (STF_WMODE|STF_WRTTN)) == (STF_WMODE|STF_WRTTN)) { /* * Cartridge tapes don't do double EOFs on EOT. * We assume that variable-block devices use double EOF. */ stcommand(dev, MTWEOF, 1); if (sc->sc_blklen == 0) { stcommand(dev, MTWEOF, 1); stcommand(dev, MTBSR, 1); } hit++; } if ((minor(dev) & STDEV_NOREWIND) == 0) { stcommand(dev, MTREW, 1); hit++; }#ifdef NOTDEF /* wait until more stable before trying [XXX Needed ?] */ if (!hit && (sc->sc_flags & SFT_WMODE)) /* force out any any bufferd write data */ stcommand(dev, MTFSR, 0); #endif /* make stats available */ stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave, sc->sc_punit, sc); sc->sc_flags &= ~(STF_OPEN|STF_WMODE|STF_WRTTN); tprintf_close(sc->sc_ctty); return(0); /* XXX */}ststrategy(bp) register struct buf *bp;{ struct buf *dp; int unit, s; unit = UNIT(bp->b_dev); dp = &sttab[unit]; bp->b_actf = NULL; 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; stustart(unit); } splx(s);}stustart(unit) int unit;{ if (scsireq(&st_softc[unit].sc_dq)) ststart(unit);}ststart(unit) int unit;{ struct hp_device *hp = st_softc[unit].sc_hd; if (scsiustart(hp->hp_ctlr)) stgo(unit);}stgo(unit) int unit;{ register struct st_softc *sc = &st_softc[unit]; register struct scsi_fmt_cdb *cmd; register struct buf *bp = sttab[unit].b_actf; struct hp_device *hp = sc->sc_hd; int pad, stat; long nblks; if (sc->sc_flags & STF_CMD) { cmd = &stcmd[unit]; pad = 0; } else { cmd = bp->b_flags & B_READ ? &st_read_cmd : &st_write_cmd; if (sc->sc_blklen) cmd->cdb[1] |= 0x01; /* fixed mode */ else cmd->cdb[1] &= 0xfe; if (bp->b_flags & B_READ) sc->sc_flags &= ~STF_WRTTN; else sc->sc_flags |= STF_WRTTN; if (sc->sc_blklen) { /* fixed mode */ nblks = bp->b_bcount / sc->sc_blklen; if (bp->b_bcount % sc->sc_blklen) { tprintf(sc->sc_ctty, "st%d: I/O not block aligned %d/%ld\n", unit, sc->sc_blklen, bp->b_bcount); cmd->cdb[1] &= 0xfe; /* force error */ } } else /* variable len */ nblks = bp->b_bcount; *(u_char *)(&cmd->cdb[2]) = (u_char) (nblks >> 16); *(u_char *)(&cmd->cdb[3]) = (u_char) (nblks >> 8); *(u_char *)(&cmd->cdb[4]) = (u_char) nblks; /* * Always Zero. We are either writing in variable * length mode we are writing in fixed block mode, * or we are going to do odd length IO and are not * going to use DMA. */ pad = 0; }#ifdef DEBUG if (st_debug & ST_GO) printf("stgo: cmd len %d [0]0x%x [1]0x%x [2]0x%x [3]0x%x [4]0x%x [5]0x%x\n", cmd->len, cmd->cdb[0], cmd->cdb[1], cmd->cdb[2], cmd->cdb[3], cmd->cdb[4], cmd->cdb[5]);#endif sc->sc_flags |= STF_MOVED; if (bp->b_bcount & 1) {#ifdef DEBUG if (st_debug & ST_ODDIO) printf("stgo%d: odd count %d using manual transfer\n", unit, bp->b_bcount);#endif stat = scsi_tt_oddio(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp->b_un.b_addr, bp->b_bcount, bp->b_flags, 1); if (stat == 0) { bp->b_resid = 0; stfinish(unit, sc, bp); } } else stat = scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad); if (stat) { bp->b_error = EIO; bp->b_flags |= B_ERROR; stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave, sc->sc_punit, sc); sterror(unit, sc, stat); stfinish(unit, sc, bp); }}stfinish(unit, sc, bp) int unit; struct st_softc *sc; struct buf *bp;{ register struct buf *dp; sttab[unit].b_errcnt = 0; if (dp = bp->b_actf) dp->b_actb = bp->b_actb; else sttab[unit].b_actb = bp->b_actb; *bp->b_actb = dp; iodone(bp); scsifree(&sc->sc_dq); if (sttab[unit].b_actf) stustart(unit); else sttab[unit].b_active = 0;}stread(dev, uio) dev_t dev; struct uio *uio;{ int unit = UNIT(dev); return(physio(ststrategy, &stbuf[unit], dev, B_READ, minphys, uio));}stwrite(dev, uio) dev_t dev; struct uio *uio;{ int unit = UNIT(dev); return(physio(ststrategy, &stbuf[unit], dev, B_WRITE, minphys, uio));}/*ARGSUSED*/stdump(dev) dev_t dev;{ return(ENXIO);}/*ARGSUSED*/stioctl(dev, cmd, data, flag) dev_t dev; int cmd; caddr_t data; int flag;{ register struct st_softc *sc = &st_softc[UNIT(dev)]; register int cnt; register struct mtget *mtget; register struct st_xsense *xp = &st_xsense[UNIT(dev)]; register struct mtop *op; long resid; switch (cmd) { /* tape operation */ case MTIOCTOP: op = (struct mtop *)data; switch (op->mt_op) { case MTBSR: case MTFSR: if (sc->sc_tapeid == MT_ISAR) return(ENXIO); case MTWEOF: case MTFSF: case MTBSF: cnt = (int)op->mt_count; break; case MTREW: case MTOFFL: cnt = 1; break; case MTNOP: return(0); default: return(EINVAL); } if (cnt <= 0) return(EINVAL); stcommand(dev, (u_int)op->mt_op, cnt); break; /* drive status */ case MTIOCGET: mtget = (struct mtget *)data; stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave, sc->sc_punit, sc); mtget->mt_type = sc->sc_tapeid; mtget->mt_dsreg = 0; mtget->mt_erreg = ((xp->sc_xsense.valid << 15) | (xp->sc_xsense.filemark << 14) | (xp->sc_xsense.eom << 13) | (xp->sc_xsense.ili << 12) | (xp->sc_xsense.key << 8)); if (sc->sc_tapeid == MT_ISEXABYTE) { mtget->mt_dsreg = sc->sc_flags; resid = (xp->exb_xsense.tplft2 << 16 | xp->exb_xsense.tplft1 << 8 | xp->exb_xsense.tplft0); mtget->mt_resid = resid / 1000; mtget->mt_erreg |= (((xp->exb_xsense.rwerrcnt2 << 16 | xp->exb_xsense.rwerrcnt1 << 8 | xp->exb_xsense.rwerrcnt0) * 100) / (sc->sc_numblks - resid)) & 0xff; } else if (xp->sc_xsense.valid) { resid = ((xp->sc_xsense.info1 << 24) | (xp->sc_xsense.info2 << 16) | (xp->sc_xsense.info3 << 8) | (xp->sc_xsense.info4)); if (sc->sc_blklen) /* if fixed mode */ resid *= sc->sc_blklen; mtget->mt_resid = resid; } else mtget->mt_resid = 0; break; default: return(ENXIO); } return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -