Commit 83391bef authored by Kai Mäkisara's avatar Kai Mäkisara Committed by Linus Torvalds

[PATCH] SCSI tape door lock and reset fixes

- switch to using scsi_ioctl() for drive door locking and unlocking
  instead of private code
- use a driver internal flag to save the reset status until tape is
  positioned into known location
- set driver state properly for all partitions after reset
- change put_device() to driver_unregister() in st_detach()
- C99 initializer changes (from Art Haas)
parent e50e1b0f
...@@ -12,13 +12,13 @@ ...@@ -12,13 +12,13 @@
Copyright 1992 - 2002 Kai Makisara Copyright 1992 - 2002 Kai Makisara
email Kai.Makisara@metla.fi email Kai.Makisara@metla.fi
Last modified: Sun Sep 29 22:29:16 2002 by makisara Last modified: Tue Oct 15 22:01:04 2002 by makisara
Some small formal changes - aeb, 950809 Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/ */
static char *verstr = "20020929"; static char *verstr = "20021015";
#include <linux/module.h> #include <linux/module.h>
...@@ -291,6 +291,8 @@ static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt) ...@@ -291,6 +291,8 @@ static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt)
if (sense[12] == 0 && sense[13] == 0x17) /* ASC and ASCQ => cleaning requested */ if (sense[12] == 0 && sense[13] == 0x17) /* ASC and ASCQ => cleaning requested */
STp->cleaning_req = 1; STp->cleaning_req = 1;
STp->pos_unknown |= STp->device->was_reset;
if ((sense[0] & 0x70) == 0x70 && if ((sense[0] & 0x70) == 0x70 &&
scode == RECOVERED_ERROR scode == RECOVERED_ERROR
#if ST_RECOVERED_WRITE_FATAL #if ST_RECOVERED_WRITE_FATAL
...@@ -566,7 +568,7 @@ static int flush_buffer(Scsi_Tape *STp, int seek_next) ...@@ -566,7 +568,7 @@ static int flush_buffer(Scsi_Tape *STp, int seek_next)
* If there was a bus reset, block further access * If there was a bus reset, block further access
* to this device. * to this device.
*/ */
if (STp->device->was_reset) if (STp->pos_unknown)
return (-EIO); return (-EIO);
if (STp->ready != ST_READY) if (STp->ready != ST_READY)
...@@ -640,6 +642,52 @@ static int set_mode_densblk(Scsi_Tape * STp, ST_mode * STm) ...@@ -640,6 +642,52 @@ static int set_mode_densblk(Scsi_Tape * STp, ST_mode * STm)
} }
return 0; 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(int dev = TAPE_NR(STp->devt);)
cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
DEBC(printk(ST_DEB_MSG "st%d: %socking drive door.\n", dev,
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 /* Test if the drive is ready. Returns either one of the codes below or a negative system
error code. */ error code. */
...@@ -757,7 +805,7 @@ static int check_tape(Scsi_Tape *STp, struct file *filp) ...@@ -757,7 +805,7 @@ static int check_tape(Scsi_Tape *STp, struct file *filp)
goto err_out; goto err_out;
if (retval == CHKRES_NEW_SESSION) { if (retval == CHKRES_NEW_SESSION) {
(STp->device)->was_reset = 0; STp->pos_unknown = 0;
STp->partition = STp->new_partition = 0; STp->partition = STp->new_partition = 0;
if (STp->can_partitions) if (STp->can_partitions)
STp->nbr_partitions = 1; /* This guess will be updated later STp->nbr_partitions = 1; /* This guess will be updated later
...@@ -1021,7 +1069,7 @@ static int st_flush(struct file *filp) ...@@ -1021,7 +1069,7 @@ static int st_flush(struct file *filp)
STm = &(STp->modes[STp->current_mode]); STm = &(STp->modes[STp->current_mode]);
STps = &(STp->ps[STp->partition]); STps = &(STp->ps[STp->partition]);
if (STps->rw == ST_WRITING && !(STp->device)->was_reset) { if (STps->rw == ST_WRITING && !STp->pos_unknown) {
result = flush_write_buffer(STp); result = flush_write_buffer(STp);
if (result != 0 && result != (-ENOSPC)) if (result != 0 && result != (-ENOSPC))
goto out; goto out;
...@@ -1040,7 +1088,7 @@ static int st_flush(struct file *filp) ...@@ -1040,7 +1088,7 @@ static int st_flush(struct file *filp)
printk(KERN_WARNING "st%d: Number of r/w requests %d, dio used in %d, pages %d (%d).\n", printk(KERN_WARNING "st%d: Number of r/w requests %d, dio used in %d, pages %d (%d).\n",
dev, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable)); dev, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable));
if (STps->rw == ST_WRITING && !(STp->device)->was_reset) { if (STps->rw == ST_WRITING && !STp->pos_unknown) {
DEBC(printk(ST_DEB_MSG "st%d: File length %ld bytes.\n", DEBC(printk(ST_DEB_MSG "st%d: File length %ld bytes.\n",
dev, (long) (filp->f_pos)); dev, (long) (filp->f_pos));
...@@ -1136,7 +1184,7 @@ static int st_release(struct inode *inode, struct file *filp) ...@@ -1136,7 +1184,7 @@ static int st_release(struct inode *inode, struct file *filp)
read_unlock(&st_dev_arr_lock); read_unlock(&st_dev_arr_lock);
if (STp->door_locked == ST_LOCKED_AUTO) if (STp->door_locked == ST_LOCKED_AUTO)
st_int_ioctl(STp, MTUNLOCK, 0); do_door_lock(STp, 0);
normalize_buffer(STp->buffer); normalize_buffer(STp->buffer);
write_lock(&st_dev_arr_lock); write_lock(&st_dev_arr_lock);
...@@ -1189,7 +1237,7 @@ static ssize_t rw_checks(Scsi_Tape *STp, struct file *filp, size_t count, loff_t ...@@ -1189,7 +1237,7 @@ static ssize_t rw_checks(Scsi_Tape *STp, struct file *filp, size_t count, loff_t
* If there was a bus reset, block further access * If there was a bus reset, block further access
* to this device. * to this device.
*/ */
if (STp->device->was_reset) { if (STp->pos_unknown) {
retval = (-EIO); retval = (-EIO);
goto out; goto out;
} }
...@@ -1216,7 +1264,7 @@ static ssize_t rw_checks(Scsi_Tape *STp, struct file *filp, size_t count, loff_t ...@@ -1216,7 +1264,7 @@ static ssize_t rw_checks(Scsi_Tape *STp, struct file *filp, size_t count, loff_t
} }
if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
!st_int_ioctl(STp, MTLOCK, 0)) !do_door_lock(STp, 1))
STp->door_locked = ST_LOCKED_AUTO; STp->door_locked = ST_LOCKED_AUTO;
out: out:
...@@ -2502,18 +2550,6 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg) ...@@ -2502,18 +2550,6 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
DEBC(printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev)); DEBC(printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev));
fileno = blkno = at_sm = 0; fileno = blkno = at_sm = 0;
break; break;
case MTLOCK:
chg_eof = FALSE;
cmd[0] = ALLOW_MEDIUM_REMOVAL;
cmd[4] = SCSI_REMOVAL_PREVENT;
DEBC(printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev));
break;
case MTUNLOCK:
chg_eof = FALSE;
cmd[0] = ALLOW_MEDIUM_REMOVAL;
cmd[4] = SCSI_REMOVAL_ALLOW;
DEBC(printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev));
break;
case MTSETBLK: /* Set block length */ case MTSETBLK: /* Set block length */
case MTSETDENSITY: /* Set tape density */ case MTSETDENSITY: /* Set tape density */
case MTSETDRVBUFFER: /* Set drive buffering */ case MTSETDRVBUFFER: /* Set drive buffering */
...@@ -2594,11 +2630,6 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg) ...@@ -2594,11 +2630,6 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
STps->drv_file = fileno; STps->drv_file = fileno;
STps->at_sm = at_sm; STps->at_sm = at_sm;
if (cmd_in == MTLOCK)
STp->door_locked = ST_LOCKED_EXPLICIT;
else if (cmd_in == MTUNLOCK)
STp->door_locked = ST_UNLOCKED;
if (cmd_in == MTBSFM) if (cmd_in == MTBSFM)
ioctl_result = st_int_ioctl(STp, MTFSF, 1); ioctl_result = st_int_ioctl(STp, MTFSF, 1);
else if (cmd_in == MTFSFM) else if (cmd_in == MTFSFM)
...@@ -2713,9 +2744,6 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg) ...@@ -2713,9 +2744,6 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
STps->eof = ST_EOD; STps->eof = ST_EOD;
if (cmd_in == MTLOCK)
STp->door_locked = ST_LOCK_FAILS;
scsi_release_request(SRpnt); scsi_release_request(SRpnt);
SRpnt = NULL; SRpnt = NULL;
} }
...@@ -3104,7 +3132,7 @@ static int st_ioctl(struct inode *inode, struct file *file, ...@@ -3104,7 +3132,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
goto out; goto out;
} }
if (!(STp->device)->was_reset) { if (!STp->pos_unknown) {
if (STps->eof == ST_FM_HIT) { if (STps->eof == ST_FM_HIT) {
if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
...@@ -3152,16 +3180,9 @@ static int st_ioctl(struct inode *inode, struct file *file, ...@@ -3152,16 +3180,9 @@ static int st_ioctl(struct inode *inode, struct file *file,
retval = (-EIO); retval = (-EIO);
goto out; goto out;
} }
reset_state(STp);
/* remove this when the midlevel properly clears was_reset */
STp->device->was_reset = 0; STp->device->was_reset = 0;
if (STp->door_locked != ST_UNLOCKED &&
STp->door_locked != ST_LOCK_FAILS) {
if (st_int_ioctl(STp, MTLOCK, 0)) {
printk(KERN_NOTICE
"st%d: Could not relock door after bus reset.\n",
dev);
STp->door_locked = ST_UNLOCKED;
}
}
} }
if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
...@@ -3170,7 +3191,7 @@ static int st_ioctl(struct inode *inode, struct file *file, ...@@ -3170,7 +3191,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */ STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */
if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED) if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
st_int_ioctl(STp, MTUNLOCK, 0); /* Ignore result! */ do_door_lock(STp, 0); /* Ignore result! */
if (mtc.mt_op == MTSETDRVBUFFER && if (mtc.mt_op == MTSETDRVBUFFER &&
(mtc.mt_count & MT_ST_OPTIONS) != 0) { (mtc.mt_count & MT_ST_OPTIONS) != 0) {
...@@ -3238,6 +3259,11 @@ static int st_ioctl(struct inode *inode, struct file *file, ...@@ -3238,6 +3259,11 @@ static int st_ioctl(struct inode *inode, struct file *file,
goto out; goto out;
} }
if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
goto out;
}
if (STp->can_partitions && STp->ready == ST_READY && if (STp->can_partitions && STp->ready == ST_READY &&
(i = switch_partition(STp)) < 0) { (i = switch_partition(STp)) < 0) {
retval = i; retval = i;
...@@ -3642,13 +3668,13 @@ static DEVICE_ATTR(type,S_IRUGO,st_device_type_read,NULL); ...@@ -3642,13 +3668,13 @@ static DEVICE_ATTR(type,S_IRUGO,st_device_type_read,NULL);
static struct file_operations st_fops = static struct file_operations st_fops =
{ {
owner: THIS_MODULE, .owner = THIS_MODULE,
read: st_read, .read = st_read,
write: st_write, .write = st_write,
ioctl: st_ioctl, .ioctl = st_ioctl,
open: st_open, .open = st_open,
flush: st_flush, .flush = st_flush,
release: st_release, .release = st_release,
}; };
static int st_attach(Scsi_Device * SDp) static int st_attach(Scsi_Device * SDp)
...@@ -3909,12 +3935,12 @@ static void st_detach(Scsi_Device * SDp) ...@@ -3909,12 +3935,12 @@ static void st_detach(Scsi_Device * SDp)
&dev_attr_type); &dev_attr_type);
device_remove_file(&tpnt->driverfs_dev_r[mode], device_remove_file(&tpnt->driverfs_dev_r[mode],
&dev_attr_kdev); &dev_attr_kdev);
put_device(&tpnt->driverfs_dev_r[mode]); device_unregister(&tpnt->driverfs_dev_r[mode]);
device_remove_file(&tpnt->driverfs_dev_n[mode], device_remove_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_type); &dev_attr_type);
device_remove_file(&tpnt->driverfs_dev_n[mode], device_remove_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_kdev); &dev_attr_kdev);
put_device(&tpnt->driverfs_dev_n[mode]); device_unregister(&tpnt->driverfs_dev_n[mode]);
} }
if (tpnt->buffer) { if (tpnt->buffer) {
tpnt->buffer->orig_frp_segs = 0; tpnt->buffer->orig_frp_segs = 0;
......
...@@ -94,6 +94,7 @@ typedef struct { ...@@ -94,6 +94,7 @@ typedef struct {
unsigned char use_pf; /* Set Page Format bit in all mode selects? */ unsigned char use_pf; /* Set Page Format bit in all mode selects? */
unsigned char try_dio; /* try direct i/o? */ unsigned char try_dio; /* try direct i/o? */
unsigned char c_algo; /* compression algorithm */ unsigned char c_algo; /* compression algorithm */
unsigned char pos_unknown; /* after reset position unknown */
int tape_type; int tape_type;
int write_threshold; int write_threshold;
int timeout; /* timeout for normal commands */ int timeout; /* timeout for normal commands */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment