📄 st.c
字号:
name, STp->current_mode, mode)); new_session = 1; 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 = 0; STps->drv_block = 0; STps->drv_file = 0; } new_session = 1; } 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, DMA_FROM_DEVICE, STp->device->timeout, MAX_READY_RETRIES, 1); if (!SRpnt) { retval = (STp->buffer)->syscall_result; goto err_out; } if (!SRpnt->result && !STp->buffer->cmdstat.have_sense) { 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_INFO "%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, DMA_FROM_DEVICE, STp->device->timeout, MAX_READY_RETRIES, 1); 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) { STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7; STp->density = (STp->buffer)->b_data[4]; STp->block_size = (STp->buffer)->b_data[9] * 65536 + (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11]; DEBC(printk(ST_DEB_MSG "%s: Density %x, tape length: %x, drv buffer: %d\n", name, STp->density, (STp->buffer)->b_data[5] * 65536 + (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7], STp->drv_buffer)); } STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; } st_release_request(SRpnt); SRpnt = NULL; STp->inited = 1; if (STp->block_size > 0) (STp->buffer)->buffer_blocks = (STp->buffer)->buffer_size / STp->block_size; else (STp->buffer)->buffer_blocks = 1; (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0; DEBC(printk(ST_DEB_MSG "%s: Block size: %d, buffer size: %d (%d blocks).\n", name, STp->block_size, (STp->buffer)->buffer_size, (STp->buffer)->buffer_blocks)); if (STp->drv_write_prot) { STp->write_prot = 1; DEBC(printk(ST_DEB_MSG "%s: Write protected\n", name)); if (do_wait && ((st_flags & O_ACCMODE) == O_WRONLY || (st_flags & O_ACCMODE) == O_RDWR)) { retval = (-EROFS); goto err_out; } } if (STp->can_partitions && STp->nbr_partitions < 1) { /* This code is reached when the device is opened for the first time after the driver has been initialized with tape in the drive and the partition support has been enabled. */ DEBC(printk(ST_DEB_MSG "%s: Updating partition number in status.\n", name)); if ((STp->partition = find_partition(STp)) < 0) { retval = STp->partition; goto err_out; } STp->new_partition = STp->partition; STp->nbr_partitions = 1; /* This guess will be updated when necessary */ } if (new_session) { /* Change the drive parameters for the new mode */ STp->density_changed = STp->blksize_changed = 0; STp->compression_changed = 0; if (!(STm->defaults_for_writes) && (retval = set_mode_densblk(STp, STm)) < 0) goto err_out; if (STp->default_drvbuffer != 0xff) { if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer)) printk(KERN_WARNING "%s: Can't set default drive buffering to %d.\n", name, STp->default_drvbuffer); } } return CHKRES_READY; err_out: return retval;}/* Open the device. Needs to be called with BKL only because of incrementing the SCSI host module count. */static int st_open(struct inode *inode, struct file *filp){ int i, retval = (-EIO); struct scsi_tape *STp; struct st_partstat *STps; int dev = TAPE_NR(inode); char *name; /* * We really want to do nonseekable_open(inode, filp); here, but some * versions of tar incorrectly call lseek on tapes and bail out if that * fails. So we disallow pread() and pwrite(), but permit lseeks. */ filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); if (!(STp = scsi_tape_get(dev))) return -ENXIO; write_lock(&st_dev_arr_lock); filp->private_data = STp; name = tape_name(STp); if (STp->in_use) { write_unlock(&st_dev_arr_lock); scsi_tape_put(STp); DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); ) return (-EBUSY); } STp->in_use = 1; write_unlock(&st_dev_arr_lock); STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0; if (!scsi_block_when_processing_errors(STp->device)) { retval = (-ENXIO); goto err_out; } /* See that we have at least a one page buffer available */ if (!enlarge_buffer(STp->buffer, PAGE_SIZE, STp->restr_dma)) { printk(KERN_WARNING "%s: Can't allocate one page tape buffer.\n", name); retval = (-EOVERFLOW); goto err_out; } (STp->buffer)->writing = 0; (STp->buffer)->syscall_result = 0; STp->write_prot = ((filp->f_flags & O_ACCMODE) == O_RDONLY); STp->dirty = 0; for (i = 0; i < ST_NBR_PARTITIONS; i++) { STps = &(STp->ps[i]); STps->rw = ST_IDLE; } STp->try_dio_now = STp->try_dio; STp->recover_count = 0; DEB( STp->nbr_waits = STp->nbr_finished = 0; STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = STp->nbr_combinable = 0; ) retval = check_tape(STp, filp); if (retval < 0) goto err_out; if ((filp->f_flags & O_NONBLOCK) == 0 && retval != CHKRES_READY) { if (STp->ready == NO_TAPE) retval = (-ENOMEDIUM); else retval = (-EIO); goto err_out; } return 0; err_out: normalize_buffer(STp->buffer); STp->in_use = 0; scsi_tape_put(STp); return retval;}/* Flush the tape buffer before close */static int st_flush(struct file *filp, fl_owner_t id){ int result = 0, result2; unsigned char cmd[MAX_COMMAND_SIZE]; struct st_request *SRpnt; struct scsi_tape *STp = filp->private_data; struct st_modedef *STm = &(STp->modes[STp->current_mode]); struct st_partstat *STps = &(STp->ps[STp->partition]); char *name = tape_name(STp); if (file_count(filp) > 1) return 0; if (STps->rw == ST_WRITING && !STp->pos_unknown) { result = flush_write_buffer(STp); if (result != 0 && result != (-ENOSPC)) goto out; } if (STp->can_partitions && (result2 = switch_partition(STp)) < 0) { DEBC(printk(ST_DEB_MSG "%s: switch_partition at close failed.\n", name)); if (result == 0) result = result2; goto out; } DEBC( if (STp->nbr_requests) printk(KERN_DEBUG "%s: Number of r/w requests %d, dio used in %d, pages %d (%d).\n", name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable)); if (STps->rw == ST_WRITING && !STp->pos_unknown) { struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; DEBC(printk(ST_DEB_MSG "%s: Async write waits %d, finished %d.\n", name, STp->nbr_waits, STp->nbr_finished); ) memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = WRITE_FILEMARKS; cmd[4] = 1 + STp->two_fm; SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->device->timeout, MAX_WRITE_RETRIES, 1); if (!SRpnt) { result = (STp->buffer)->syscall_result; goto out; } if (STp->buffer->syscall_result == 0 || (cmdstatp->have_sense && !cmdstatp->deferred && (cmdstatp->flags & SENSE_EOM) && (cmdstatp->sense_hdr.sense_key == NO_SENSE || cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) && (!cmdstatp->remainder_valid || cmdstatp->uremainder64 == 0))) { /* Write successful at EOM */ st_release_request(SRpnt); SRpnt = NULL; if (STps->drv_file >= 0) STps->drv_file++; STps->drv_block = 0; if (STp->two_fm) cross_eof(STp, 0); STps->eof = ST_FM; } else { /* Write error */ st_release_request(SRpnt); SRpnt = NULL; printk(KERN_ERR "%s: Error on write filemark.\n", name); if (result == 0) result = (-EIO); } DEBC(printk(ST_DEB_MSG "%s: Buffer flushed, %d EOF(s) written\n", name, cmd[4])); } else if (!STp->rew_at_close) { STps = &(STp->ps[STp->partition]); if (!STm->sysv || STps->rw != ST_READING) { if (STp->can_bsr) result = flush_buffer(STp, 0); else if (STps->eof == ST_FM_HIT) { result = cross_eof(STp, 0); if (result) { if (STps->drv_file >= 0) STps->drv_file++; STps->drv_block = 0; STps->eof = ST_FM; } else STps->eof = ST_NOEOF; } } else if ((STps->eof == ST_NOEOF && !(result = cross_eof(STp, 1))) || STps->eof == ST_FM_HIT) { if (STps->drv_file >= 0) STps->drv_file++; STps->drv_block = 0; STps->eof = ST_FM; } } out: if (STp->rew_at_close) { result2 = st_int_ioctl(STp, MTREW, 1); if (result == 0) result = result2; } return result;}/* Close the device and release it. BKL is not needed: this is the only thread accessing this tape. */static int st_release(struct inode *inode, struct file *filp){ int result = 0; struct scsi_tape *STp = filp->private_data; if (STp->door_locked == ST_LOCKED_AUTO) do_door_lock(STp, 0); normalize_buffer(STp->buffer); write_lock(&st_dev_arr_lock); STp->in_use = 0; write_unlock(&st_dev_arr_lock); scsi_tape_put(STp); return result;}/* The checks common to both reading and writing */static ssize_t rw_checks(struct scsi_tape *STp, struct file *filp, size_t count){ ssize_t retval = 0; /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it * may try and take the device offline, in which case all further * access to the device is prohibited. */ if (!scsi_block_when_processing_errors(STp->device)) { retval = (-ENXIO); goto out; } if (STp->ready != ST_READY) { if (STp->ready == ST_NO_TAPE) retval = (-ENOMEDIUM); else retval = (-EIO); goto out; } if (! STp->modes[STp->current_mode].defined) { retval = (-ENXIO); goto out; } /* * If there was a bus reset, block further access * to this device. */ if (STp->pos_unknown) { retval = (-EIO); goto out; } if (count == 0) goto out; DEB( if (!STp->in_use) { printk(ST_DEB_MSG "%s: Incorrect device.\n", tape_name(STp)); retval = (-EIO); goto out; } ) /* end DEB */ if (STp->can_partitions && (retval = switch_partition(STp)) < 0) goto out; if (STp->block_size == 0 && STp->max_block > 0 && (count < STp->min_block || count > STp->max_block)) { retval = (-EINVAL); goto out; } if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1)) STp->door_locked = ST_LOCKED_AUTO; out: return retval;}static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -