diff options
Diffstat (limited to 'drivers/scsi/st.c')
-rw-r--r-- | drivers/scsi/st.c | 54 |
1 files changed, 38 insertions, 16 deletions
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 338aa8c42968..ebbd50ec0cda 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -46,7 +46,7 @@ static const char *verstr = "20160209"; #include <linux/uaccess.h> #include <asm/dma.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <scsi/scsi.h> #include <scsi/scsi_dbg.h> @@ -87,7 +87,7 @@ static int try_rdio = 1; static int try_wdio = 1; static int debug_flag; -static struct class st_sysfs_class; +static const struct class st_sysfs_class; static const struct attribute_group *st_dev_groups[]; static const struct attribute_group *st_drv_groups[]; @@ -206,7 +206,6 @@ static int st_remove(struct device *); static struct scsi_driver st_template = { .gendrv = { .name = "st", - .owner = THIS_MODULE, .probe = st_probe, .remove = st_remove, .groups = st_drv_groups, @@ -835,6 +834,9 @@ static int flush_buffer(struct scsi_tape *STp, int seek_next) int backspace, result; struct st_partstat *STps; + if (STp->ready != ST_READY) + return 0; + /* * If there was a bus reset, block further access * to this device. @@ -842,8 +844,6 @@ static int flush_buffer(struct scsi_tape *STp, int seek_next) 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 st_flush_write_buffer(STp); @@ -991,7 +991,10 @@ static int test_ready(struct scsi_tape *STp, int do_wait) scode = cmdstatp->sense_hdr.sense_key; if (scode == UNIT_ATTENTION) { /* New media? */ - new_session = 1; + if (cmdstatp->sense_hdr.asc == 0x28) { /* New media */ + new_session = 1; + DEBC_printk(STp, "New tape session."); + } if (attentions < MAX_ATTENTIONS) { attentions++; continue; @@ -1027,6 +1030,11 @@ static int test_ready(struct scsi_tape *STp, int do_wait) retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY; break; } + if (STp->first_tur) { + /* Don't set pos_unknown right after device recognition */ + STp->pos_unknown = 0; + STp->first_tur = 0; + } if (SRpnt != NULL) st_release_request(SRpnt); @@ -3506,6 +3514,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) int i, cmd_nr, cmd_type, bt; int retval = 0; unsigned int blk; + bool cmd_mtiocget; struct scsi_tape *STp = file->private_data; struct st_modedef *STm; struct st_partstat *STps; @@ -3619,6 +3628,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) */ if (mtc.mt_op != MTREW && mtc.mt_op != MTOFFL && + mtc.mt_op != MTLOAD && mtc.mt_op != MTRETEN && mtc.mt_op != MTERASE && mtc.mt_op != MTSEEK && @@ -3732,17 +3742,28 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) goto out; } + cmd_mtiocget = cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET); + if ((i = flush_buffer(STp, 0)) < 0) { - retval = i; - goto out; - } - if (STp->can_partitions && - (i = switch_partition(STp)) < 0) { - retval = i; - goto out; + if (cmd_mtiocget && STp->pos_unknown) { + /* flush fails -> modify status accordingly */ + reset_state(STp); + STp->pos_unknown = 1; + } else { /* return error */ + retval = i; + goto out; + } + } else { /* flush_buffer succeeds */ + if (STp->can_partitions) { + i = switch_partition(STp); + if (i < 0) { + retval = i; + goto out; + } + } } - if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) { + if (cmd_mtiocget) { struct mtget mt_status; if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) { @@ -3756,7 +3777,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK); mt_status.mt_blkno = STps->drv_block; mt_status.mt_fileno = STps->drv_file; - if (STp->block_size != 0) { + if (STp->block_size != 0 && mt_status.mt_blkno >= 0) { if (STps->rw == ST_WRITING) mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size; @@ -4312,6 +4333,7 @@ static int st_probe(struct device *dev) blk_queue_rq_timeout(tpnt->device->request_queue, ST_TIMEOUT); tpnt->long_timeout = ST_LONG_TIMEOUT; tpnt->try_dio = try_direct_io; + tpnt->first_tur = 1; for (i = 0; i < ST_NBR_MODES; i++) { STm = &(tpnt->modes[i]); @@ -4438,7 +4460,7 @@ static void scsi_tape_release(struct kref *kref) return; } -static struct class st_sysfs_class = { +static const struct class st_sysfs_class = { .name = "scsi_tape", .dev_groups = st_dev_groups, }; |