📄 st.c
字号:
* physical tape position may not be what we've been * telling the user; adjust the position accordingly */ if (mtop->mt_count && IN_EOF(un)) { int blkno = un->un_blkno; int fileno = un->un_fileno; int lastop = un->un_lastop; if (stcmd(devp, SCMD_SPACE, Fmk((-1)), SYNC_CMD) == -1) return (EIO); un->un_blkno = blkno; un->un_fileno = fileno; un->un_lastop = lastop; } if (check_density_or_wfm(dev, 1, B_READ, STEPBACK)) { return (EIO); }space_records: tmp = un->un_blkno + mtop->mt_count; if (tmp == un->un_blkno) { un->un_err_resid = 0; un->un_err_fileno = un->un_fileno; un->un_err_blkno = un->un_blkno; break; } else if (un->un_blkno < tmp || (un->un_dp->options & ST_BSR)) { /* * If we're spacing forward, or the device can * backspace records, we can just use the SPACE * command. */ tmp = tmp - un->un_blkno; if (stcmd(devp, SCMD_SPACE, Blk(tmp), SYNC_CMD)) { rval = EIO; } else if (un->un_eof >= ST_EOF_PENDING) { /* * check if we hit BOT/EOT */ if (tmp < 0 && un->un_eof == ST_EOM) { un->un_status = SUN_KEY_BOT; un->un_eof = ST_NO_EOF; } else if (tmp < 0 && un->un_eof == ST_EOF_PENDING) { int residue = un->un_err_resid; /* * we skipped over a filemark * and need to go forward again */ if (stcmd(devp, SCMD_SPACE, Fmk(1), SYNC_CMD)) { rval = EIO; } un->un_err_resid = residue; } if (rval == 0) rval = EIO; } } else { /* * else we rewind, space forward across filemarks to * the desired file, and then space records to the * desired block. */ int t = un->un_fileno; /* save current file */ if (tmp < 0) { /* * Wups - we're backing up over a filemark */ if (un->un_blkno != 0 && (stcmd(devp, SCMD_REWIND, 0, SYNC_CMD) || stcmd(devp, SCMD_SPACE, Fmk(t), SYNC_CMD))) un->un_fileno = -1; un->un_err_resid = -tmp; if (un->un_fileno == 0 && un->un_blkno == 0) { un->un_status = SUN_KEY_BOT; un->un_eof = ST_NO_EOF; } else if (un->un_fileno > 0) { un->un_status = SUN_KEY_EOF; un->un_eof = ST_NO_EOF; } un->un_err_fileno = un->un_fileno; un->un_err_blkno = un->un_blkno; rval = EIO; } else if (stcmd(devp, SCMD_REWIND, 0, SYNC_CMD) || stcmd(devp, SCMD_SPACE, Fmk(t), SYNC_CMD) || stcmd(devp, SCMD_SPACE, Blk(tmp), SYNC_CMD)) { un->un_fileno = -1; rval = EIO; } } break; case MTBSF: /* * backward space of file filemark (1/2" and 8mm) * tape position will end on the beginning of tape side * of the desired file mark */ if ((un->un_dp->options & ST_BSF) == 0) { return (ENOTTY); } /* * If a negative count (which implies a forward space op) * is specified, and we're at logical or physical eot, * bounce the request. */ if (un->un_eof >= ST_EOT && mtop->mt_count < 0) { un->un_err_resid = mtop->mt_count; un->un_status = SUN_KEY_EOT; return (EIO); } /* * physical tape position may not be what we've been * telling the user; adjust the request accordingly */ if (mtop->mt_count && IN_EOF(un)) { un->un_fileno++; un->un_blkno = 0; if (mtop->mt_count < 0) { mtop->mt_count--; } else if (mtop->mt_count == 0) { /* * For all cases here, this means move * to block zero of the current (physical) * file. */ mtop->mt_count = 1; mtop->mt_op = MTNBSF; goto mtnbsf; } else if (mtop->mt_count > 0) { mtop->mt_count++; } } if (check_density_or_wfm(dev, 1, 0, STEPBACK)) { return (EIO); } if (mtop->mt_count <= 0) { mtop->mt_op = MTFSF; mtop->mt_count = -mtop->mt_count; goto fspace; }bspace: { /* * Backspace files (MTNBSF): * * For tapes that can backspace, backspace * count+1 filemarks and then run forward over * a filemark * * For tapes that can't backspace, * calculate desired filenumber * (un->un_fileno - count), rewind, * and then space forward this amount * * Backspace filemarks (MTBSF) * * For tapes that can backspace, backspace count * filemarks * * For tapes that can't backspace, calculate * desired filenumber (un->un_fileno - count), * add 1, rewind, space forward this amount, * and mark state as ST_EOF_PENDING appropriately. */ int skip_cnt, end_at_eof; if (mtop->mt_op == MTBSF) end_at_eof = 1; else end_at_eof = 0; DPRINTF_IOCTL(devp, "bspace: mt_op=%x, count=%x, fileno=%x, blkno=%x\n", mtop->mt_op, mtop->mt_count, un->un_fileno, un->un_blkno); /* * Handle the simple case of BOT * playing a role in these cmds. * We do this by calculating the * ending file number. If the ending * file is < BOT, rewind and set an * error and mark resid appropriately. * If we're backspacing a file (not a * filemark) and the target file is * the first file on the tape, just * rewind. */ tmp = un->un_fileno - mtop->mt_count; if ((end_at_eof && tmp < 0) || (end_at_eof == 0 && tmp <= 0)) { if (stcmd (devp, SCMD_REWIND, 0, SYNC_CMD)) { rval = EIO; } if (tmp < 0) { rval = EIO; un->un_err_resid = -tmp; un->un_status = SUN_KEY_BOT; } break; } if (un->un_dp->options & ST_BSF) { skip_cnt = 1 - end_at_eof; /* * If we are going to end up at the beginning * of the file, we have to space one extra file * first, and then space forward later. */ tmp = -(mtop->mt_count + skip_cnt); DPRINTF_IOCTL(devp, "skip_cnt=%x, tmp=%x\n", skip_cnt, tmp); if (stcmd(devp, SCMD_SPACE, Fmk(tmp), SYNC_CMD)) { rval = EIO; } } else { if (stcmd(devp, SCMD_REWIND, 0, SYNC_CMD)) { rval = EIO; } else { skip_cnt = tmp + end_at_eof; } } /* * If we have to space forward, do so... */ DPRINTF_IOCTL(devp, "space forward skip_cnt=%x, rval=%x\n", skip_cnt, rval); if (rval == 0 && skip_cnt) { if (stcmd(devp, SCMD_SPACE, Fmk(skip_cnt), SYNC_CMD)) { rval = EIO; } else if (end_at_eof) { /* * If we had to space forward, and we're * not a tape that can backspace, mark state * as if we'd just seen a filemark during a * a read. */ if ((un->un_dp->options & ST_BSF) == 0) { un->un_eof = ST_EOF_PENDING; un->un_fileno -= 1; un->un_blkno = INF; } } } if (rval) un->un_fileno = -1; break; } case MTNBSF: /* * backward space file to beginning of file * * If a negative count (which implies a forward space op) * is specified, and we're at logical or physical eot, * bounce the request. */ if (un->un_eof >= ST_EOT && mtop->mt_count < 0) { un->un_err_resid = mtop->mt_count; un->un_status = SUN_KEY_EOT; return (EIO); } /* * physical tape position may not be what we've been * telling the user; adjust the request accordingly */ if (mtop->mt_count && IN_EOF(un)) { un->un_fileno++; un->un_blkno = 0; if (mtop->mt_count < 0) { mtop->mt_count--; } else if (mtop->mt_count == 0) { /* * For all cases here, this means move * to block zero of the current (physical) * file. */ mtop->mt_count = 1; } else if (mtop->mt_count > 0) { mtop->mt_count++; } } if (check_density_or_wfm(dev, 1, 0, STEPBACK)) { return (EIO); }mtnbsf: if (mtop->mt_count <= 0) { mtop->mt_op = MTFSF; mtop->mt_count = -mtop->mt_count; goto fspace; } goto bspace; case MTBSR: /* * backward space into inter-record gap * * If a negative count (which implies a forward space op) * is specified, and we're at logical or physical eot, * bounce the request. */ if (un->un_eof >= ST_EOT && mtop->mt_count < 0) { un->un_err_resid = mtop->mt_count; un->un_status = SUN_KEY_EOT; return (EIO); } if (mtop->mt_count == 0) { return (0); } /* * physical tape position may not be what we've been * telling the user; adjust the position accordingly. * bsr can not skip filemarks and continue to skip records * therefore if we are logically before the filemark but * physically at the EOT side of the filemark, we need to step * back; this allows fsr N where N > number of blocks in file * followed by bsr 1 to position at the beginning of last block */ if (IN_EOF(un)) { int blkno = un->un_blkno; int fileno = un->un_fileno; int lastop = un->un_lastop; if (stcmd(devp, SCMD_SPACE, Fmk((-1)), SYNC_CMD) == -1) return (EIO); un->un_blkno = blkno; un->un_fileno = fileno; un->un_lastop = lastop; } un->un_eof = ST_NO_EOF; if (check_density_or_wfm(dev, 1, 0, STEPBACK)) { return (EIO); } mtop->mt_count = -mtop->mt_count; goto space_records; default: rval = ENOTTY; } DPRINTF_IOCTL(devp, "stioctl: fileno=%x, blkno=%x, un_eof=%x\n", un->un_fileno, un->un_blkno, un->un_eof); if (un->un_fileno < 0) un->un_density_known = 0; return (rval);}static intst_write_fm(dev, wfm)dev_t dev;int wfm;{ register struct scsi_device *devp; register struct scsi_tape *un; int i; if ((devp = stunits[MTUNIT(dev)]) == 0) return (ENXIO); un = UPTR; /* * write one filemark at the time after EOT */ if (un->un_eof >= ST_EOT) { for (i = 0; i < wfm; i++) { if (stcmd(devp, SCMD_WRITE_FILE_MARK, 1, SYNC_CMD)) { return (EIO); } } } else if (stcmd(devp, SCMD_WRITE_FILE_MARK, wfm, SYNC_CMD)) { return (EIO); } return (0);}/* * Command start && done functions */static voidststart(devp)register struct scsi_device *devp;{ register struct buf *bp; register struct scsi_tape *un = UPTR; if (un->un_runq || (bp = un->un_quef) == NULL) { return; } if (!BP_PKT(bp)) { make_st_cmd(devp, bp, strunout); if (!BP_PKT(bp)) { un->un_state = ST_STATE_RESOURCE_WAIT; return; } un->un_state = ST_STATE_OPEN; } un->un_runq = bp; un->un_quef = bp->b_actf; bp->b_actf = 0; if (pkt_transport(BP_PKT(bp)) != TRAN_ACCEPT) { stprintf(devp, "transport rejected"); bp->b_resid = bp->b_bcount; bp->b_flags |= B_ERROR; bp->b_error = EIO; stdone(devp); }}static intstrunout(){ register i, rval, s; register struct scsi_device *devp; register struct scsi_tape *un; rval = 1; s = splr(stpri); for (i = 0; i < ST_MAXUNIT; i++) { devp = stunits[i]; if (devp && devp->sd_present && (un = UPTR) && un->un_attached) { if (un->un_state == ST_STATE_RESOURCE_WAIT) { ststart(devp); if (un->un_state == ST_STATE_RESOURCE_WAIT) { rval = 0; break; } } } } (void) splx(s); return (rval);}static voidstdone(devp)register struct scsi_device *devp;{ register struct buf *bp; register struct scsi_tape *un = UPTR; bp = un->un_runq; un->un_runq = NULL; /* * Start the next one before releasing resources on this one */ if (un->un_quef) { ststart(devp); } if (bp != un->un_sbufp) { scsi_resfree(BP_PKT(bp)); iodone(bp); } else { bp->b_flags |= B_DONE; if (bp->b_flags & B_ASYNC) { int com; scsi_resfree (BP_PKT(bp)); com = (int) bp->b_forw; if (com == SCMD_READ || com == SCMD_WRITE) { bp->b_un.b_addr = (caddr_t) 0; } bp->b_flags &= ~(B_BUSY|B_ASYNC); if (bp->b_flags & B_WANTED) { wakeup((caddr_t) bp); } } else { wakeup((caddr_t) un); } }}/* * Utility functions */static intst_determine_generic(devp)struct scsi_device *devp;{ u_char dens; int bsize; struct scsi_tape *un = UPTR; static char *cart = "0.25 inch cartridge"; char *sizestr, local[8+3]; if (stcmd(devp, SCMD_MODE_SENSE, MSIZE, SYNC_CMD)) return (-1); bsize = (un->un_mspl->high_bl << 16) | (un->un_mspl->mid_bl << 8) | (un->un_mspl->low_bl); if (bsize == 0) { un->un_dp->options |= ST_VARIABLE; un->un_dp->bsize = 10 << 10; } else if (bsize > ST_MAXRECSIZE_FIXED) { /* * record size of this device too big. * try and convert it to variable record length. * */ un->un_dp->options |= ST_VARIABLE; if (st_modeselect(devp)) { stprintf(devp, "Fixed Record Size %d is too large", bsize); stprintf(devp, "Cannot switch to variable record size"); un->un_dp->options &= ~ST_VARIABLE; return (-1); } un->un_mspl->high_bl = un->un_mspl->mid_bl = un->un_mspl->low_bl = 0; } else { un->un_dp->bsize = (u_short) bsize; } switch (dens = un->un_mspl->density) { default: case 0x0: /* * default density, cannot determine any other * information. */ sizestr = "Unknown type- assuming 0.25 inch cartridge"; un->un_dp->type = ST_TYPE_DEFAULT; un->un_dp->options |= (ST_AUTODEN_OVERRIDE|ST_QIC); break; case 0x1: case 0x2: case 0x3: case 0x6:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -