📄 st.c
字号:
/* * 1/2" reel */ sizestr = "0.50 inch reel"; un->un_dp->type = ST_TYPE_REEL; un->un_dp->options |= ST_REEL; un->un_dp->densities[0] = 0x1; un->un_dp->densities[1] = 0x2; un->un_dp->densities[2] = 0x6; un->un_dp->densities[3] = 0x3; break; case 0x4: case 0x5: case 0x7: case 0x0b: /* * Quarter inch. */ sizestr = cart; un->un_dp->type = ST_TYPE_DEFAULT; un->un_dp->options |= ST_QIC; un->un_dp->densities[1] = 0x4; un->un_dp->densities[2] = 0x5; un->un_dp->densities[3] = 0x7; un->un_dp->densities[0] = 0x0b; break; case 0x0f: case 0x10: case 0x11: case 0x12: /* * QIC-120, QIC-150, QIC-320, QIC-600 */ sizestr = cart; un->un_dp->type = ST_TYPE_DEFAULT; un->un_dp->options |= ST_QIC; un->un_dp->densities[0] = 0x0f; un->un_dp->densities[1] = 0x10; un->un_dp->densities[2] = 0x11; un->un_dp->densities[3] = 0x12; break; case 0x09: case 0x0a: case 0x0c: case 0x0d: /* * 1/2" cartridge tapes. Include HI-TC. */ sizestr = cart; sizestr[2] = '5'; sizestr[3] = '0'; un->un_dp->type = ST_TYPE_HIC; un->un_dp->densities[0] = 0x09; un->un_dp->densities[1] = 0x0a; un->un_dp->densities[2] = 0x0c; un->un_dp->densities[3] = 0x0d; break; case 0x13: case 0x14: /* * Helical Scan (Exabyte) devices */ if (dens == 0x13) sizestr = "3.81mm helical scan cartridge"; else sizestr = "8mm helical scan cartridge"; un->un_dp->type = ST_TYPE_EXABYTE; un->un_dp->options |= ST_AUTODEN_OVERRIDE; break; } /* * Assume LONG ERASE and NO BUFFERED MODE */ un->un_dp->options |= (ST_LONG_ERASE|ST_NOBUF); /* * set up large read and write retry counts */ un->un_dp->max_rretries = un->un_dp->max_wretries = 1000; /* * make up name */ local[0] = '<'; bcopy(devp->sd_inq->inq_vid, &local[1], 8); local[9] = '>'; local[10] = 0; /* * If this is a 0.50 inch reel tape, and * it is *not* variable mode, try and * set it to variable record length * mode. */ if ((un->un_dp->options & (ST_VARIABLE|ST_REEL)) == ST_REEL) { un->un_dp->options |= ST_VARIABLE; if (st_modeselect(devp)) { un->un_dp->options &= ~ST_VARIABLE; } else { un->un_dp->bsize = 10 << 10; un->un_mspl->high_bl = un->un_mspl->mid_bl = un->un_mspl->low_bl = 0; } } /* * Write to console about type of device found */ stprintf(devp, "Generic Drive, Vendor=%s\n\t%s", local, sizestr); if (un->un_dp->options & ST_VARIABLE) { printf("\tVariable record length I/O\n"); } else { printf("\tFixed record length (%d byte blocks) I/O\n", un->un_dp->bsize); } return (0);}static intst_determine_density(devp, rw)struct scsi_device *devp;int rw;{ struct scsi_tape *un = UPTR; /* * If we're past BOT, density is determined already. */ if (un->un_fileno > 0) { /* * XXX: put in a bitch message about attempting to * XXX: change density past BOT. */ return (0); } /* * If we're going to be writing, we set the density */ if (rw == B_WRITE) { /* un_curdens is used as an index into densities table */ un->un_curdens = MT_DENSITY(un->un_dev); if (st_set_density(devp)) { return (-1); } return (0); } /* * If density is known already, * we don't have to get it again.(?) */ if (un->un_density_known) return (0); if (st_get_density(devp)) { return (-1); } return (0);}/* * Try to determine density. We do this by attempting to read the * first record off the tape, cycling through the available density * codes as we go. */static intst_get_density(devp)struct scsi_device *devp;{ register struct scsi_tape *un = UPTR; int succes = 0, rval = -1, i; u_int size; u_char dens, olddens; if (un->un_dp->options & ST_AUTODEN_OVERRIDE) { un->un_density_known = 1; return (0); } /* * This will only work on variable record length tapes * if and only if all variable record length tapes autodensity * select. */ size = (unsigned) un->un_dp->bsize; un->un_tmpbuf = (caddr_t) kmem_alloc(size); /* * Start at the specified density */ dens = olddens = un->un_curdens = MT_DENSITY(un->un_dev); for (i = 0; i < NDENSITIES; i++, ((un->un_curdens == NDENSITIES-1) ? un->un_curdens = 0 : un->un_curdens += 1)) { /* * If we've done this density before, * don't bother to do it again. */ dens = un->un_dp->densities[un->un_curdens]; if (i > 0 && dens == olddens) continue; olddens = dens; DPRINTF(devp, "trying density 0x%x", dens); if (st_set_density(devp)) continue; succes = (stcmd(devp, SCMD_READ, (int) size, SYNC_CMD) == 0); if (stcmd(devp, SCMD_REWIND, 0, SYNC_CMD)) { break; } if (succes) { stinit(un); rval = 0; un->un_density_known = 1; break; } } (void) kmem_free(un->un_tmpbuf, size); un->un_tmpbuf = 0; return (rval);}static intst_set_density(devp)struct scsi_device *devp;{ struct scsi_tape *un = UPTR; if ((un->un_dp->options & ST_AUTODEN_OVERRIDE) == 0) { un->un_mspl->density = un->un_dp->densities[un->un_curdens]; if (st_modeselect(devp)) { return (-1); } } un->un_density_known = 1; return (0);}static intst_loadtape(devp)struct scsi_device *devp;{ /* * 'LOAD' the tape to BOT */ if (stcmd(devp, SCMD_LOAD, 1, SYNC_CMD)) { /* * Don't bounce the loadtape function here- some devices * don't support the load command. For them, if the load * tape command fails with an ILLEGAL REQUEST sense key, * try a rewind instead. */ if (UPTR->un_status == KEY_ILLEGAL_REQUEST) { if (stcmd(devp, SCMD_REWIND, 0, SYNC_CMD)) { return (-1); } } else return (-1); } /* * run a MODE SENSE to get the write protect status, then run * a MODESELECT operation in order to set any modes that might * be appropriate for this device (like VARIABLE, etc..) */ if (stcmd(devp, SCMD_MODE_SENSE, MSIZE, SYNC_CMD) || st_modeselect(devp)) return (-1); stinit(UPTR); UPTR->un_density_known = 0; return (0);}/* * Note: QIC devices aren't so smart. If you try to append * after EOM, the write can fail because the device doesn't know * it's at EOM. In that case, issue a read. The read should fail * because there's no data, but the device knows it's at EOM, * so a subsequent write should succeed. To further confuse matters, * the target returns the same error if the tape is positioned * such that a write would overwrite existing data. That's why * we have to do the append test. A read in the middle of * recorded data would succeed, thus indicating we're attempting * something illegal. */static voidst_test_append(bp)struct buf *bp;{ struct scsi_device *devp = stunits[MTUNIT(bp->b_dev)]; struct scsi_tape *un = UPTR; int status; DPRINTF(devp, "testing append to file %d", un->un_fileno); un->un_laststate = un->un_state; un->un_state = ST_STATE_APPEND_TESTING; un->un_test_append = 0; /* * first, map in the buffer, because we're doing a double write -- * first into the kernel, then onto the tape. */ bp_mapin(bp); /* * get a copy of the data.... */ un->un_tmpbuf = (caddr_t) kmem_alloc((unsigned) bp->b_bcount); bcopy(bp->b_un.b_addr, un->un_tmpbuf, (u_int) bp->b_bcount); /* * attempt the write.. */ if (stcmd(devp, SCMD_WRITE, (int) bp->b_bcount, SYNC_CMD) == 0) {success: DPRINTF(devp, "append write succeeded"); bp->b_resid = un->un_sbufp->b_resid; /* * Note: iodone will do a bp_mapout() */ iodone(bp); un->un_laststate = un->un_state; un->un_state = ST_STATE_OPEN; (void) kmem_free (un->un_tmpbuf, (unsigned)bp->b_bcount); un->un_tmpbuf = 0; return; } /* * The append failed. Do a short read. If that fails, we are at EOM * so we can retry the write command. If that succeeds, than we're * all screwed up (the controller reported a real error). * * XXX: should the dummy read be > SECSIZE? should it be the device's * XXX: block size? * */ status = un->un_status; un->un_status = 0; (void) stcmd(devp, SCMD_READ, SECSIZE, SYNC_CMD); if (un->un_status == KEY_BLANK_CHECK) { DPRINTF(devp, "append at EOM"); /* * Okay- the read failed. We should actually have confused * the controller enough to allow writing. In any case, the * i/o is on its own from here on out. */ un->un_laststate = un->un_state; un->un_state = ST_STATE_OPEN; bcopy(bp->b_un.b_addr, un->un_tmpbuf, (u_int) bp->b_bcount); if (stcmd(devp, SCMD_WRITE, (int) bp->b_bcount, SYNC_CMD) == 0) goto success; } DPRINTF(devp, "append write failed- not at EOM"); bp->b_resid = bp->b_bcount; bp->b_flags |= B_ERROR; bp->b_error = EIO; /* * backspace one record to get back to where we were */ if (stcmd(devp, SCMD_SPACE, Blk(-1), SYNC_CMD)) un->un_fileno = -1; un->un_err_resid = bp->b_resid; un->un_status = status; /* * Note: iodone will do a bp_mapout() */ iodone(bp); un->un_laststate = un->un_state; un->un_state = ST_STATE_OPEN_PENDING_IO; (void) kmem_free (un->un_tmpbuf, (unsigned)bp->b_bcount); un->un_tmpbuf = 0;}/* * Special command handler *//* * common stcmd code. The fourth parameter states * whether the caller wishes to await the results */static intstcmd(devp, com, count, wait)register struct scsi_device *devp;int com, count, wait;{ struct scsi_tape *un = UPTR; register struct buf *bp; register s, error;#ifdef ST_DEBUG if (st_debug & ST_DEBUG_CMDS) st_debug_cmds(devp, com, count, wait);#endif bp = un->un_sbufp; s = splr(stpri); while (bp->b_flags & B_BUSY) { bp->b_flags |= B_WANTED; if (un->un_state == ST_STATE_OPENING) { if (sleep((caddr_t) bp, (PZERO+1)|PCATCH)) { bp->b_flags &= ~B_WANTED; (void) splx(s); return (EINTR); } } else { (void) sleep((caddr_t) bp, PRIBIO); } } if (!wait) bp->b_flags = B_BUSY|B_ASYNC; else bp->b_flags = B_BUSY; (void) splx(s); if (com == SCMD_READ || com == SCMD_WRITE) { bp->b_un.b_addr = un->un_tmpbuf; if (com == SCMD_READ) bp->b_flags |= B_READ; } bp->b_error = 0; bp->b_dev = un->un_dev; bp->b_bcount = count; bp->b_resid = 0; bp->b_forw = (struct buf *) com; make_st_cmd(devp, bp, SLEEP_FUNC); ststrategy(bp); if (!wait) { return (0); } s = splr(stpri); while ((bp->b_flags & B_DONE) == 0) { if (un->un_state == ST_STATE_OPENING) { if (sleep((caddr_t) un, (PZERO+1)|PCATCH)) { if (bp->b_flags & B_DONE) break; bp->b_flags |= B_ASYNC; (void) splx(s); return (EINTR); } } else (void) sleep((caddr_t) un, PRIBIO); } error = geterror(bp); scsi_resfree(BP_PKT(bp)); (void) splx(s); if (com == SCMD_READ || com == SCMD_WRITE) { bp->b_un.b_addr = (caddr_t) 0; } bp->b_flags &= ~B_BUSY; if (bp->b_flags & B_WANTED) { wakeup((caddr_t) bp); } return (error);}/* * We assume someone else has set the density code */static intst_modeselect(devp)struct scsi_device *devp;{ register struct scsi_tape *un = UPTR; un->un_mspl->reserved1 = un->un_mspl->reserved2 = 0; un->un_mspl->wp = 0; if (un->un_dp->options & ST_NOBUF) un->un_mspl->bufm = 0; else un->un_mspl->bufm = 1; un->un_mspl->bd_len = 8; un->un_mspl->high_nb = un->un_mspl->mid_nb = un->un_mspl->low_nb = 0; if ((un->un_dp->options & ST_VARIABLE) == 0) { un->un_mspl->high_bl = 0; un->un_mspl->mid_bl = (un->un_dp->bsize>>8) & 0xff; un->un_mspl->low_bl = (un->un_dp->bsize) & 0xff; } else { un->un_mspl->high_bl = un->un_mspl->mid_bl = un->un_mspl->low_bl = 0; } if (stcmd(devp, SCMD_MODE_SELECT, MSIZE, SYNC_CMD) || stcmd(devp, SCMD_MODE_SENSE, MSIZE, SYNC_CMD)) { if (un->un_state >= ST_STATE_OPEN) { stprintf(devp, "unable to set tape mode"); un->un_fileno = -1; return (ENXIO); } return (-1); } return (0);}static voidstinit(un)struct scsi_tape *un;{ un->un_blkno = 0; un->un_fileno = 0; un->un_lastop = ST_OP_NIL; un->un_eof = ST_NO_EOF; if (st_error_level != STERR_ALL) { if (DEBUGGING) st_error_level = STERR_ALL; else st_error_level = STERR_RETRYABLE; }}static voidmake_st_cmd(devp, bp, func)register struct scsi_device *devp;register struct buf *bp;int (*func)();{ register struct scsi_pkt *pkt; register struct scsi_tape *un = UPTR; register count, com, flags, tval = st_io_time; char fixbit = (un->un_dp->options & ST_VARIABLE) ? 0: 1; flags = (scsi_options & SCSI_OPTIONS_DR) ? 0: FLAG_NODISCON; if (un->un_dp->options & ST_NOPARITY) flags |= FLAG_NOPARITY; /* * fixbit is for setting the Fixed Mode and Suppress Incorrect * Length Indicator bits on read/write commands, for setting * the Long bit on erase commands, and for setting the Code * Field bits on space commands. *//* * XXX why do we set lastop here? */ if (bp != un->un_sbufp) { /* regular raw I/O */ pkt = scsi_resalloc(ROUTE, C
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -