📄 st.c
字号:
STps->drv_block++; else STps->drv_block += STbuffer->writing / STp->block_size; } STbuffer->writing = 0; return;}/* Step over EOF if it has been inadvertently crossed (ioctl not used because it messes up the block number). */static int cross_eof(Scsi_Tape * STp, int forward){ Scsi_Request *SRpnt; unsigned char cmd[MAX_COMMAND_SIZE]; cmd[0] = SPACE; cmd[1] = 0x01; /* Space FileMarks */ if (forward) { cmd[2] = cmd[3] = 0; cmd[4] = 1; } else cmd[2] = cmd[3] = cmd[4] = 0xff; /* -1 filemarks */ cmd[5] = 0; DEBC(printk(ST_DEB_MSG "%s: Stepping over filemark %s.\n", tape_name(STp), forward ? "forward" : "backward")); SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->device->timeout, MAX_RETRIES, TRUE); if (!SRpnt) return (STp->buffer)->syscall_result; scsi_release_request(SRpnt); SRpnt = NULL; if ((STp->buffer)->midlevel_result != 0) printk(KERN_ERR "%s: Stepping over filemark %s failed.\n", tape_name(STp), forward ? "forward" : "backward"); return (STp->buffer)->syscall_result;}/* Flush the write buffer (never need to write if variable blocksize). */static int flush_write_buffer(Scsi_Tape * STp){ int offset, transfer, blks; int result; unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt; ST_partstat *STps; if ((STp->buffer)->writing) { write_behind_check(STp); if ((STp->buffer)->syscall_result) { DEBC(printk(ST_DEB_MSG "%s: Async write error (flush) %x.\n", tape_name(STp), (STp->buffer)->midlevel_result)) if ((STp->buffer)->midlevel_result == INT_MAX) return (-ENOSPC); return (-EIO); } } if (STp->block_size == 0) return 0; result = 0; if (STp->dirty == 1) { offset = (STp->buffer)->buffer_bytes; transfer = ((offset + STp->block_size - 1) / STp->block_size) * STp->block_size; DEBC(printk(ST_DEB_MSG "%s: Flushing %d bytes.\n", tape_name(STp), transfer)); memset((STp->buffer)->b_data + offset, 0, transfer - offset); memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = WRITE_6; cmd[1] = 1; blks = transfer / STp->block_size; cmd[2] = blks >> 16; cmd[3] = blks >> 8; cmd[4] = blks; SRpnt = st_do_scsi(NULL, STp, cmd, transfer, SCSI_DATA_WRITE, STp->device->timeout, MAX_WRITE_RETRIES, TRUE); if (!SRpnt) return (STp->buffer)->syscall_result; STps = &(STp->ps[STp->partition]); if ((STp->buffer)->syscall_result != 0) { if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && (SRpnt->sr_sense_buffer[2] & 0x40) && (SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) { STp->dirty = 0; (STp->buffer)->buffer_bytes = 0; result = (-ENOSPC); } else { printk(KERN_ERR "%s: Error on flush.\n", tape_name(STp)); result = (-EIO); } STps->drv_block = (-1); } else { if (STps->drv_block >= 0) STps->drv_block += blks; STp->dirty = 0; (STp->buffer)->buffer_bytes = 0; } scsi_release_request(SRpnt); SRpnt = NULL; } return result;}/* Flush the tape buffer. The tape will be positioned correctly unless seek_next is true. */static int flush_buffer(Scsi_Tape *STp, int seek_next){ int backspace, result; ST_buffer *STbuffer; ST_partstat *STps; STbuffer = STp->buffer; /* * If there was a bus reset, block further access * to this device. */ if (STp->pos_unknown) return (-EIO); if (STp->ready != ST_READY) return 0; STps = &(STp->ps[STp->partition]); if (STps->rw == ST_WRITING) /* Writing */ return flush_write_buffer(STp); if (STp->block_size == 0) return 0; backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size - ((STp->buffer)->read_pointer + STp->block_size - 1) / STp->block_size; (STp->buffer)->buffer_bytes = 0; (STp->buffer)->read_pointer = 0; result = 0; if (!seek_next) { if (STps->eof == ST_FM_HIT) { result = cross_eof(STp, FALSE); /* Back over the EOF hit */ if (!result) STps->eof = ST_NOEOF; else { if (STps->drv_file >= 0) STps->drv_file++; STps->drv_block = 0; } } if (!result && backspace > 0) result = st_int_ioctl(STp, MTBSR, backspace); } else if (STps->eof == ST_FM_HIT) { if (STps->drv_file >= 0) STps->drv_file++; STps->drv_block = 0; STps->eof = ST_NOEOF; } return result;}/* Set the mode parameters */static int set_mode_densblk(Scsi_Tape * STp, ST_mode * STm){ int set_it = FALSE; unsigned long arg; char *name = tape_name(STp); if (!STp->density_changed && STm->default_density >= 0 && STm->default_density != STp->density) { arg = STm->default_density; set_it = TRUE; } else arg = STp->density; arg <<= MT_ST_DENSITY_SHIFT; if (!STp->blksize_changed && STm->default_blksize >= 0 && STm->default_blksize != STp->block_size) { arg |= STm->default_blksize; set_it = TRUE; } else arg |= STp->block_size; if (set_it && st_int_ioctl(STp, SET_DENS_AND_BLK, arg)) { printk(KERN_WARNING "%s: Can't set default block size to %d bytes and density %x.\n", name, STm->default_blksize, STm->default_density); if (modes_defined) return (-EINVAL); } return 0;}/* Lock or unlock the drive door. Don't use when Scsi_Request allocated. */static int do_door_lock(Scsi_Tape * STp, int do_lock){ int retval, cmd; DEB(char *name = tape_name(STp);) cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK; DEBC(printk(ST_DEB_MSG "%s: %socking drive door.\n", name, do_lock ? "L" : "Unl")); retval = scsi_ioctl(STp->device, cmd, NULL); if (!retval) { STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED; } else { STp->door_locked = ST_LOCK_FAILS; } return retval;}/* Set the internal state after reset */static void reset_state(Scsi_Tape *STp){ int i; ST_partstat *STps; STp->pos_unknown = 0; for (i = 0; i < ST_NBR_PARTITIONS; i++) { STps = &(STp->ps[i]); STps->rw = ST_IDLE; STps->eof = ST_NOEOF; STps->at_sm = 0; STps->last_block_valid = FALSE; STps->drv_block = -1; STps->drv_file = -1; } if (STp->can_partitions) { STp->partition = find_partition(STp); if (STp->partition < 0) STp->partition = 0; STp->new_partition = STp->partition; }}/* Test if the drive is ready. Returns either one of the codes below or a negative system error code. */#define CHKRES_READY 0#define CHKRES_NEW_SESSION 1#define CHKRES_NOT_READY 2#define CHKRES_NO_TAPE 3#define MAX_ATTENTIONS 10static int test_ready(Scsi_Tape *STp, int do_wait){ int attentions, waits, max_wait, scode; int retval = CHKRES_READY, new_session = FALSE; unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt = NULL; max_wait = do_wait ? ST_BLOCK_SECONDS : 0; for (attentions=waits=0; ; ) { memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); cmd[0] = TEST_UNIT_READY; SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout, MAX_READY_RETRIES, TRUE); if (!SRpnt) { retval = (STp->buffer)->syscall_result; break; } if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) { scode = (SRpnt->sr_sense_buffer[2] & 0x0f); if (scode == UNIT_ATTENTION) { /* New media? */ new_session = TRUE; if (attentions < MAX_ATTENTIONS) { attentions++; continue; } else { retval = (-EIO); break; } } if (scode == NOT_READY) { if (waits < max_wait) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); if (signal_pending(current)) { retval = (-EINTR); break; } waits++; continue; } else { if ((STp->device)->scsi_level >= SCSI_2 && SRpnt->sr_sense_buffer[12] == 0x3a) /* Check ASC */ retval = CHKRES_NO_TAPE; else retval = CHKRES_NOT_READY; break; } } } retval = (STp->buffer)->syscall_result; if (!retval) retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY; break; } if (SRpnt != NULL) scsi_release_request(SRpnt); return retval;}/* See if the drive is ready and gather information about the tape. Return values: < 0 negative error code from errno.h 0 drive ready 1 drive not ready (possibly no tape)*/static int check_tape(Scsi_Tape *STp, struct file *filp){ int i, retval, new_session = FALSE, do_wait; unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning; unsigned short st_flags = filp->f_flags; Scsi_Request *SRpnt = NULL; ST_mode *STm; ST_partstat *STps; char *name = tape_name(STp); struct inode *inode = filp->f_dentry->d_inode; int mode = TAPE_MODE(inode); STp->ready = ST_READY; if (mode != STp->current_mode) { DEBC(printk(ST_DEB_MSG "%s: Mode change from %d to %d.\n", name, STp->current_mode, mode)); new_session = TRUE; STp->current_mode = mode; } STm = &(STp->modes[STp->current_mode]); saved_cleaning = STp->cleaning_req; STp->cleaning_req = 0; do_wait = ((filp->f_flags & O_NONBLOCK) == 0); retval = test_ready(STp, do_wait); if (retval < 0) goto err_out; if (retval == CHKRES_NEW_SESSION) { STp->pos_unknown = 0; STp->partition = STp->new_partition = 0; if (STp->can_partitions) STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ for (i = 0; i < ST_NBR_PARTITIONS; i++) { STps = &(STp->ps[i]); STps->rw = ST_IDLE; STps->eof = ST_NOEOF; STps->at_sm = 0; STps->last_block_valid = FALSE; STps->drv_block = 0; STps->drv_file = 0; } new_session = TRUE; } else { STp->cleaning_req |= saved_cleaning; if (retval == CHKRES_NOT_READY || retval == CHKRES_NO_TAPE) { if (retval == CHKRES_NO_TAPE) STp->ready = ST_NO_TAPE; else STp->ready = ST_NOT_READY; STp->density = 0; /* Clear the erroneous "residue" */ STp->write_prot = 0; STp->block_size = 0; STp->ps[0].drv_file = STp->ps[0].drv_block = (-1); STp->partition = STp->new_partition = 0; STp->door_locked = ST_UNLOCKED; return CHKRES_NOT_READY; } } if (STp->omit_blklims) STp->min_block = STp->max_block = (-1); else { memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); cmd[0] = READ_BLOCK_LIMITS; SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, SCSI_DATA_READ, STp->device->timeout, MAX_READY_RETRIES, TRUE); if (!SRpnt) { retval = (STp->buffer)->syscall_result; goto err_out; } if (!SRpnt->sr_result && !SRpnt->sr_sense_buffer[0]) { STp->max_block = ((STp->buffer)->b_data[1] << 16) | ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3]; STp->min_block = ((STp->buffer)->b_data[4] << 8) | (STp->buffer)->b_data[5]; if ( DEB( debugging || ) !STp->inited) printk(KERN_WARNING "%s: Block limits %d - %d bytes.\n", name, STp->min_block, STp->max_block); } else { STp->min_block = STp->max_block = (-1); DEBC(printk(ST_DEB_MSG "%s: Can't read block limits.\n", name)); } } memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); cmd[0] = MODE_SENSE; cmd[4] = 12; SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, SCSI_DATA_READ, STp->device->timeout, MAX_READY_RETRIES, TRUE); if (!SRpnt) { retval = (STp->buffer)->syscall_result; goto err_out; } if ((STp->buffer)->syscall_result != 0) { DEBC(printk(ST_DEB_MSG "%s: No Mode Sense.\n", name)); STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */ (STp->buffer)->syscall_result = 0; /* Prevent error propagation */ STp->drv_write_prot = 0; } else { DEBC(printk(ST_DEB_MSG "%s: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", name, (STp->buffer)->b_data[0], (STp->buffer)->b_data[1], (STp->buffer)->b_data[2], (STp->buffer)->b_data[3])); if ((STp->buffer)->b_data[3] >= 8) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -