📄 st.c
字号:
if (!SRpnt) return (STp->buffer)->syscall_result; scsi_release_request(SRpnt); SRpnt = NULL; if ((STp->buffer)->midlevel_result != 0) printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n", TAPE_NR(STp->devt), 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 "st%d: Async write error (flush) %x.\n", TAPE_NR(STp->devt), (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 "st%d: Flushing %d bytes.\n", TAPE_NR(STp->devt), 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->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 "st%d: Error on flush.\n", TAPE_NR(STp->devt)); 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->device->was_reset) 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; int dev = TAPE_NR(STp->devt); 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 "st%d: Can't set default block size to %d bytes and density %x.\n", dev, STm->default_blksize, STm->default_density); if (modes_defined) return (-EINVAL); } return 0;}/* 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){ unsigned short st_flags; int i, need_dma_buffer, new_session = FALSE; int retval; unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt; Scsi_Tape *STp; ST_mode *STm; ST_partstat *STps; int dev = TAPE_NR(inode->i_rdev); int mode = TAPE_MODE(inode->i_rdev); unsigned long flags; write_lock_irqsave(&st_dev_arr_lock, flags); STp = scsi_tapes[dev]; if (dev >= st_template.dev_max || STp == NULL) { write_unlock_irqrestore(&st_dev_arr_lock, flags); return (-ENXIO); } if (STp->in_use) { write_unlock_irqrestore(&st_dev_arr_lock, flags); DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); ) return (-EBUSY); } STp->in_use = 1; write_unlock_irqrestore(&st_dev_arr_lock, flags); STp->rew_at_close = STp->autorew_dev = (MINOR(inode->i_rdev) & 0x80) == 0; if (STp->device->host->hostt->module) __MOD_INC_USE_COUNT(STp->device->host->hostt->module); if (!scsi_block_when_processing_errors(STp->device)) { retval = (-ENXIO); goto err_out; } if (mode != STp->current_mode) { DEBC(printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n", dev, STp->current_mode, mode)); new_session = TRUE; STp->current_mode = mode; } STm = &(STp->modes[STp->current_mode]); /* Allocate a buffer for this user */ need_dma_buffer = STp->restr_dma; write_lock_irqsave(&st_dev_arr_lock, flags); for (i = 0; i < st_nbr_buffers; i++) if (!st_buffers[i]->in_use && (!need_dma_buffer || st_buffers[i]->dma)) { STp->buffer = st_buffers[i]; (STp->buffer)->in_use = 1; break; } write_unlock_irqrestore(&st_dev_arr_lock, flags); if (i >= st_nbr_buffers) { STp->buffer = new_tape_buffer(FALSE, need_dma_buffer, TRUE); if (STp->buffer == NULL) { printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev); retval = (-EBUSY); goto err_out; } } (STp->buffer)->writing = 0; (STp->buffer)->syscall_result = 0; (STp->buffer)->use_sg = STp->device->host->sg_tablesize; /* Compute the usable buffer size for this SCSI adapter */ if (!(STp->buffer)->use_sg) (STp->buffer)->buffer_size = (STp->buffer)->sg[0].length; else { for (i = 0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg && i < (STp->buffer)->sg_segs; i++) (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length; } st_flags = filp->f_flags; STp->write_prot = ((st_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->ready = ST_READY; STp->recover_count = 0; DEB( STp->nbr_waits = STp->nbr_finished = 0; ) memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); cmd[0] = TEST_UNIT_READY; SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout, MAX_READY_RETRIES, TRUE); if (!SRpnt) { retval = (STp->buffer)->syscall_result; goto err_out; } if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ /* Flush the queued UNIT ATTENTION sense data */ for (i=0; i < 10; i++) { 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->sr_sense_buffer[0] & 0x70) != 0x70 || (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION) break; } (STp->device)->was_reset = 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; } if ((STp->buffer)->syscall_result != 0) { if ((STp->device)->scsi_level >= SCSI_2 && (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY && SRpnt->sr_sense_buffer[12] == 0x3a) { /* Check ASC */ STp->ready = ST_NO_TAPE; } else STp->ready = ST_NOT_READY; scsi_release_request(SRpnt); SRpnt = NULL; 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 0; } 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->timeout, MAX_READY_RETRIES, TRUE); 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 "st%d: Block limits %d - %d bytes.\n", dev, STp->min_block, STp->max_block); } else { STp->min_block = STp->max_block = (-1); DEBC(printk(ST_DEB_MSG "st%d: Can't read block limits.\n", dev)); } } 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->timeout, MAX_READY_RETRIES, TRUE); if ((STp->buffer)->syscall_result != 0) { DEBC(printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev)); 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 "st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", dev, (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 "st%d: Density %x, tape length: %x, drv buffer: %d\n", dev, 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; } scsi_release_request(SRpnt); SRpnt = NULL; STp->inited = TRUE; 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 "st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev, 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 "st%d: Write protected\n", dev)); if ((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 "st%d: Updating partition number in status.\n", dev)); 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 = FALSE; STp->compression_changed = FALSE; 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 "st%d: Can't set default drive buffering to %d.\n", dev, STp->default_drvbuffer); } } return 0; err_out: if (STp->buffer != NULL) { (STp->buffer)->in_use = 0; STp->buffer = NULL; } STp->in_use = 0; if (STp->device->host->hostt->module)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -