patch-2.3.99-pre6 linux/drivers/scsi/st.c
Next file: linux/drivers/scsi/st.h
Previous file: linux/drivers/scsi/sd.c
Back to the patch index
Back to the overall index
- Lines: 760
- Date:
Mon Apr 24 13:54:22 2000
- Orig file:
v2.3.99-pre5/linux/drivers/scsi/st.c
- Orig date:
Mon Mar 27 08:08:27 2000
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
@@ -12,7 +12,7 @@
Copyright 1992 - 2000 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Sun Mar 19 22:06:54 2000 by makisara@kai.makisara.local
+ Last modified: Sun Apr 23 23:41:32 2000 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
@@ -791,15 +791,6 @@
(STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7],
STp->drv_buffer));
}
-
- if (STp->block_size > (STp->buffer)->buffer_size &&
- !enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
- printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n",
- dev, STp->block_size);
- scsi_release_request(SRpnt);
- retval = (-EIO);
- goto err_out;
- }
STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
}
scsi_release_request(SRpnt);
@@ -1032,7 +1023,8 @@
{
struct inode *inode = filp->f_dentry->d_inode;
ssize_t total;
- ssize_t i, do_count, blks, retval, transfer;
+ ssize_t i, do_count, blks, transfer;
+ ssize_t retval = 0;
int write_threshold;
int doing_write = 0;
static unsigned char cmd[MAX_COMMAND_SIZE];
@@ -1047,6 +1039,9 @@
STp = scsi_tapes[dev];
read_unlock(&st_dev_arr_lock);
+ if (down_interruptible(&STp->lock))
+ return -ERESTARTSYS;
+
/*
* 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
@@ -1054,59 +1049,86 @@
* access to the device is prohibited.
*/
if (!scsi_block_when_processing_errors(STp->device)) {
- return -ENXIO;
+ retval = (-ENXIO);
+ goto out;
}
if (ppos != &filp->f_pos) {
/* "A request was outside the capabilities of the device." */
- return -ENXIO;
+ retval = (-ENXIO);
+ goto out;
}
if (STp->ready != ST_READY) {
if (STp->ready == ST_NO_TAPE)
- return (-ENOMEDIUM);
+ retval = (-ENOMEDIUM);
else
- return (-EIO);
+ retval = (-EIO);
+ goto out;
}
STm = &(STp->modes[STp->current_mode]);
- if (!STm->defined)
- return (-ENXIO);
+ if (!STm->defined) {
+ retval = (-ENXIO);
+ goto out;
+ }
if (count == 0)
- return 0;
+ goto out;
/*
* If there was a bus reset, block further access
* to this device.
*/
- if (STp->device->was_reset)
- return (-EIO);
+ if (STp->device->was_reset) {
+ retval = (-EIO);
+ goto out;
+ }
DEB(
if (!STp->in_use) {
printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
- return (-EIO);
+ retval = (-EIO);
+ goto out;
} ) /* end DEB */
/* Write must be integral number of blocks */
if (STp->block_size != 0 && (count % STp->block_size) != 0) {
printk(KERN_WARNING "st%d: Write not multiple of tape block size.\n",
dev);
- return (-EIO);
+ retval = (-EINVAL);
+ goto out;
}
if (STp->can_partitions &&
(retval = update_partition(STp)) < 0)
- return retval;
+ goto out;
STps = &(STp->ps[STp->partition]);
- if (STp->write_prot)
- return (-EACCES);
+ if (STp->write_prot) {
+ retval = (-EACCES);
+ goto out;
+ }
- if (STp->block_size == 0 &&
- count > (STp->buffer)->buffer_size &&
- !enlarge_buffer(STp->buffer, count, STp->restr_dma))
- return (-EOVERFLOW);
+ if (STp->block_size == 0) {
+ if (STp->max_block > 0 &&
+ (count < STp->min_block || count > STp->max_block)) {
+ retval = (-EINVAL);
+ goto out;
+ }
+ if (count > (STp->buffer)->buffer_size &&
+ !enlarge_buffer(STp->buffer, count, STp->restr_dma)) {
+ retval = (-EOVERFLOW);
+ goto out;
+ }
+ }
+ if ((STp->buffer)->buffer_blocks < 1) {
+ /* Fixed block mode with too small buffer */
+ if (!enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
+ retval = (-EOVERFLOW);
+ goto out;
+ }
+ (STp->buffer)->buffer_blocks = 1;
+ }
if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
!st_int_ioctl(STp, MTLOCK, 0))
@@ -1115,19 +1137,21 @@
if (STps->rw == ST_READING) {
retval = flush_buffer(STp, 0);
if (retval)
- return retval;
+ goto out;
STps->rw = ST_WRITING;
} else if (STps->rw != ST_WRITING &&
STps->drv_file == 0 && STps->drv_block == 0) {
if ((retval = set_mode_densblk(STp, STm)) < 0)
- return retval;
+ goto out;
if (STm->default_compression != ST_DONT_TOUCH &&
!(STp->compression_changed)) {
if (st_compression(STp, (STm->default_compression == ST_YES))) {
printk(KERN_WARNING "st%d: Can't set default compression.\n",
dev);
- if (modes_defined)
- return (-EINVAL);
+ if (modes_defined) {
+ retval = (-EINVAL);
+ goto out;
+ }
}
}
}
@@ -1144,22 +1168,30 @@
}
}
- if (STps->eof == ST_EOM_OK)
- return (-ENOSPC);
- else if (STps->eof == ST_EOM_ERROR)
- return (-EIO);
+ if (STps->eof == ST_EOM_OK) {
+ retval = (-ENOSPC);
+ goto out;
+ }
+ else if (STps->eof == ST_EOM_ERROR) {
+ retval = (-EIO);
+ goto out;
+ }
/* Check the buffer readability in cases where copy_user might catch
the problems after some tape movement. */
if (STp->block_size != 0 &&
(copy_from_user(&i, buf, 1) != 0 ||
- copy_from_user(&i, buf + count - 1, 1) != 0))
- return (-EFAULT);
+ copy_from_user(&i, buf + count - 1, 1) != 0)) {
+ retval = (-EFAULT);
+ goto out;
+ }
if (!STm->do_buffer_writes) {
#if 0
- if (STp->block_size != 0 && (count % STp->block_size) != 0)
- return (-EIO); /* Write must be integral number of blocks */
+ if (STp->block_size != 0 && (count % STp->block_size) != 0) {
+ retval = (-EINVAL); /* Write must be integral number of blocks */
+ goto out;
+ }
#endif
write_threshold = 1;
} else
@@ -1191,11 +1223,8 @@
i = append_to_buffer(b_point, STp->buffer, do_count);
if (i) {
- if (SRpnt != NULL) {
- scsi_release_request(SRpnt);
- SRpnt = NULL;
- }
- return i;
+ retval = i;
+ goto out;
}
if (STp->block_size == 0)
@@ -1211,8 +1240,10 @@
SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
STp->timeout, MAX_WRITE_RETRIES, TRUE);
- if (!SRpnt)
- return (STp->buffer)->syscall_result;
+ if (!SRpnt) {
+ retval = (STp->buffer)->syscall_result;
+ goto out;
+ }
if ((STp->buffer)->syscall_result != 0) {
DEBC(printk(ST_DEB_MSG "st%d: Error on write:\n", dev));
@@ -1267,9 +1298,8 @@
(STp->buffer)->buffer_bytes = 0;
STp->dirty = 0;
if (count < total)
- return total - count;
- else
- return retval;
+ retval = total - count;
+ goto out;
}
filp->f_pos += do_count;
b_point += do_count;
@@ -1287,20 +1317,16 @@
STp->dirty = 1;
i = append_to_buffer(b_point, STp->buffer, count);
if (i) {
- if (SRpnt != NULL) {
- scsi_release_request(SRpnt);
- SRpnt = NULL;
- }
- return i;
+ retval = i;
+ goto out;
}
filp->f_pos += count;
count = 0;
}
if (doing_write && (STp->buffer)->syscall_result != 0) {
- scsi_release_request(SRpnt);
- SRpnt = NULL;
- return (STp->buffer)->syscall_result;
+ retval = (STp->buffer)->syscall_result;
+ goto out;
}
if (STm->do_async_writes &&
@@ -1328,18 +1354,24 @@
SRpnt = st_do_scsi(SRpnt, STp, cmd, (STp->buffer)->writing,
SCSI_DATA_WRITE, STp->timeout,
MAX_WRITE_RETRIES, FALSE);
- if (SRpnt == NULL)
- return (STp->buffer)->syscall_result;
+ if (SRpnt == NULL) {
+ retval = (STp->buffer)->syscall_result;
+ goto out;
+ }
+ SRpnt = NULL; /* Prevent releasing this request! */
- } else if (SRpnt != NULL) {
- scsi_release_request(SRpnt);
- SRpnt = NULL;
}
STps->at_sm &= (total == 0);
if (total > 0)
STps->eof = ST_NOEOF;
+ retval = total;
+
+ out:
+ if (SRpnt != NULL)
+ scsi_release_request(SRpnt);
+ up(&STp->lock);
- return (total);
+ return retval;
}
/* Read data from the tape. Returns zero in the normal case, one if the
@@ -1516,6 +1548,7 @@
{
struct inode *inode = filp->f_dentry->d_inode;
ssize_t total;
+ ssize_t retval = 0;
ssize_t i, transfer;
int special;
Scsi_Request *SRpnt = NULL;
@@ -1528,6 +1561,9 @@
STp = scsi_tapes[dev];
read_unlock(&st_dev_arr_lock);
+ if (down_interruptible(&STp->lock))
+ return -ERESTARTSYS;
+
/*
* 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
@@ -1535,41 +1571,65 @@
* access to the device is prohibited.
*/
if (!scsi_block_when_processing_errors(STp->device)) {
- return -ENXIO;
+ retval = (-ENXIO);
+ goto out;
}
if (ppos != &filp->f_pos) {
/* "A request was outside the capabilities of the device." */
- return -ENXIO;
+ retval = (-ENXIO);
+ goto out;
}
if (STp->ready != ST_READY) {
if (STp->ready == ST_NO_TAPE)
- return (-ENOMEDIUM);
+ retval = (-ENOMEDIUM);
else
- return (-EIO);
+ retval = (-EIO);
+ goto out;
}
STm = &(STp->modes[STp->current_mode]);
- if (!STm->defined)
- return (-ENXIO);
+ if (!STm->defined) {
+ retval = (-ENXIO);
+ goto out;
+ }
DEB(
if (!STp->in_use) {
printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
- return (-EIO);
+ retval = (-EIO);
+ goto out;
} ) /* end DEB */
if (STp->can_partitions &&
- (total = update_partition(STp)) < 0)
- return total;
+ (retval = update_partition(STp)) < 0)
+ goto out;
- if (STp->block_size == 0 &&
- count > (STp->buffer)->buffer_size &&
- !enlarge_buffer(STp->buffer, count, STp->restr_dma))
- return (-EOVERFLOW);
+ if (STp->block_size == 0) {
+ if (STp->max_block > 0 &&
+ (count < STp->min_block || count > STp->max_block)) {
+ retval = (-EINVAL);
+ goto out;
+ }
+ if (count > (STp->buffer)->buffer_size &&
+ !enlarge_buffer(STp->buffer, count, STp->restr_dma)) {
+ retval = (-EOVERFLOW);
+ goto out;
+ }
+ }
+ if ((STp->buffer)->buffer_blocks < 1) {
+ /* Fixed block mode with too small buffer */
+ if (!enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
+ retval = (-EOVERFLOW);
+ goto out;
+ }
+ (STp->buffer)->buffer_blocks = 1;
+ }
if (!(STm->do_read_ahead) && STp->block_size != 0 &&
- (count % STp->block_size) != 0)
- return (-EIO); /* Read must be integral number of blocks */
+ (count % STp->block_size) != 0) {
+ retval = (-EINVAL); /* Read must be integral number of blocks */
+ goto out;
+ }
if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
!st_int_ioctl(STp, MTLOCK, 0))
@@ -1577,9 +1637,9 @@
STps = &(STp->ps[STp->partition]);
if (STps->rw == ST_WRITING) {
- transfer = flush_buffer(STp, 0);
- if (transfer)
- return transfer;
+ retval = flush_buffer(STp, 0);
+ if (retval)
+ goto out;
STps->rw = ST_READING;
}
DEB(
@@ -1592,9 +1652,11 @@
STps->eof >= ST_EOD_1) {
if (STps->eof < ST_EOD) {
STps->eof += 1;
- return 0;
+ retval = 0;
+ goto out;
}
- return (-EIO); /* EOM or Blank Check */
+ retval = (-EIO); /* EOM or Blank Check */
+ goto out;
}
/* Check the buffer writability before any tape movement. Don't alter
@@ -1602,8 +1664,10 @@
if (copy_from_user(&i, buf, 1) != 0 ||
copy_to_user(buf, &i, 1) != 0 ||
copy_from_user(&i, buf + count - 1, 1) != 0 ||
- copy_to_user(buf + count - 1, &i, 1) != 0)
- return (-EFAULT);
+ copy_to_user(buf + count - 1, &i, 1) != 0) {
+ retval = (-EFAULT);
+ goto out;
+ }
STps->rw = ST_READING;
@@ -1615,10 +1679,8 @@
if ((STp->buffer)->buffer_bytes == 0) {
special = read_tape(STp, count - total, &SRpnt);
if (special < 0) { /* No need to continue read */
- if (SRpnt != NULL) {
- scsi_release_request(SRpnt);
- }
- return special;
+ retval = special;
+ goto out;
}
}
@@ -1635,11 +1697,8 @@
(STp->buffer)->buffer_bytes : count - total;
i = from_buffer(STp->buffer, buf, transfer);
if (i) {
- if (SRpnt != NULL) {
- scsi_release_request(SRpnt);
- SRpnt = NULL;
- }
- return i;
+ retval = i;
+ goto out;
}
filp->f_pos += transfer;
buf += transfer;
@@ -1652,11 +1711,6 @@
} /* for (total = 0, special = 0;
total < count && !special; ) */
- if (SRpnt != NULL) {
- scsi_release_request(SRpnt);
- SRpnt = NULL;
- }
-
/* Change the eof state if no data from tape or buffer */
if (total == 0) {
if (STps->eof == ST_FM_HIT) {
@@ -1673,8 +1727,16 @@
STps->eof = ST_EOD;
} else if (STps->eof == ST_FM)
STps->eof = ST_NOEOF;
+ retval = total;
+
+ out:
+ if (SRpnt != NULL) {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
+ }
+ up(&STp->lock);
- return total;
+ return retval;
}
@@ -2236,9 +2298,9 @@
return (-EIO); /* Not allowed if data in buffer */
if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
(arg & MT_ST_BLKSIZE_MASK) != 0 &&
+ STp->max_block > 0 &&
((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
- (arg & MT_ST_BLKSIZE_MASK) > STp->max_block ||
- (arg & MT_ST_BLKSIZE_MASK) > st_buffer_size)) {
+ (arg & MT_ST_BLKSIZE_MASK) > STp->max_block)) {
printk(KERN_WARNING "st%d: Illegal block size.\n", dev);
return (-EINVAL);
}
@@ -2745,6 +2807,7 @@
unsigned int cmd_in, unsigned long arg)
{
int i, cmd_nr, cmd_type, bt;
+ int retval = 0;
unsigned int blk;
Scsi_Tape *STp;
ST_mode *STm;
@@ -2755,10 +2818,14 @@
STp = scsi_tapes[dev];
read_unlock(&st_dev_arr_lock);
+ if (down_interruptible(&STp->lock))
+ return -ERESTARTSYS;
+
DEB(
if (debugging && !STp->in_use) {
printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
- return (-EIO);
+ retval = (-EIO);
+ goto out;
} ) /* end DEB */
STm = &(STp->modes[STp->current_mode]);
@@ -2771,7 +2838,8 @@
* access to the device is prohibited.
*/
if (!scsi_block_when_processing_errors(STp->device)) {
- return -ENXIO;
+ retval = (-ENXIO);
+ goto out;
}
cmd_type = _IOC_TYPE(cmd_in);
cmd_nr = _IOC_NR(cmd_in);
@@ -2779,21 +2847,29 @@
if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
struct mtop mtc;
- if (_IOC_SIZE(cmd_in) != sizeof(mtc))
- return (-EINVAL);
+ if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
+ retval = (-EINVAL);
+ goto out;
+ }
i = copy_from_user((char *) &mtc, (char *) arg, sizeof(struct mtop));
- if (i)
- return (-EFAULT);
+ if (i) {
+ retval = (-EFAULT);
+ goto out;
+ }
if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
printk(KERN_WARNING
"st%d: MTSETDRVBUFFER only allowed for root.\n", dev);
- return (-EPERM);
+ retval = (-EPERM);
+ goto out;
}
if (!STm->defined &&
- (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0))
- return (-ENXIO);
+ (mtc.mt_op != MTSETDRVBUFFER &&
+ (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
+ retval = (-ENXIO);
+ goto out;
+ }
if (!(STp->device)->was_reset) {
@@ -2822,8 +2898,10 @@
mtc.mt_op == MTCOMPRESSION;
}
i = flush_buffer(STp, i);
- if (i < 0)
- return i;
+ if (i < 0) {
+ retval = i;
+ goto out;
+ }
} else {
/*
* If there was a bus reset, block further access
@@ -2835,8 +2913,10 @@
mtc.mt_op != MTRETEN &&
mtc.mt_op != MTERASE &&
mtc.mt_op != MTSEEK &&
- mtc.mt_op != MTEOM)
- return (-EIO);
+ mtc.mt_op != MTEOM) {
+ retval = (-EIO);
+ goto out;
+ }
STp->device->was_reset = 0;
if (STp->door_locked != ST_UNLOCKED &&
STp->door_locked != ST_LOCK_FAILS) {
@@ -2858,8 +2938,10 @@
st_int_ioctl(STp, MTUNLOCK, 0); /* Ignore result! */
if (mtc.mt_op == MTSETDRVBUFFER &&
- (mtc.mt_count & MT_ST_OPTIONS) != 0)
- return st_set_options(STp, mtc.mt_count);
+ (mtc.mt_count & MT_ST_OPTIONS) != 0) {
+ retval = st_set_options(STp, mtc.mt_count);
+ goto out;
+ }
if (mtc.mt_op == MTSETPART) {
if (!STp->can_partitions ||
@@ -2871,7 +2953,8 @@
if (mtc.mt_count >= STp->nbr_partitions)
return (-EINVAL);
STp->new_partition = mtc.mt_count;
- return 0;
+ retval = 0;
+ goto out;
}
if (mtc.mt_op == MTMKPART) {
@@ -2888,39 +2971,52 @@
STp->partition = STp->new_partition = 0;
STp->nbr_partitions = 1; /* Bad guess ?-) */
STps->drv_block = STps->drv_file = 0;
- return 0;
+ retval = 0;
+ goto out;
}
if (mtc.mt_op == MTSEEK) {
i = set_location(STp, mtc.mt_count, STp->new_partition, 0);
if (!STp->can_partitions)
STp->ps[0].rw = ST_IDLE;
- return i;
+ retval = i;
+ goto out;
}
if (STp->can_partitions && STp->ready == ST_READY &&
- (i = update_partition(STp)) < 0)
- return i;
+ (i = update_partition(STp)) < 0) {
+ retval = i;
+ goto out;
+ }
if (mtc.mt_op == MTCOMPRESSION)
- return st_compression(STp, (mtc.mt_count & 1));
+ retval = st_compression(STp, (mtc.mt_count & 1));
else
- return st_int_ioctl(STp, mtc.mt_op, mtc.mt_count);
+ retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count);
+ goto out;
+ }
+ if (!STm->defined) {
+ retval = (-ENXIO);
+ goto out;
}
- if (!STm->defined)
- return (-ENXIO);
- if ((i = flush_buffer(STp, FALSE)) < 0)
- return i;
+ if ((i = flush_buffer(STp, FALSE)) < 0) {
+ retval = i;
+ goto out;
+ }
if (STp->can_partitions &&
- (i = update_partition(STp)) < 0)
- return i;
+ (i = update_partition(STp)) < 0) {
+ retval = i;
+ goto out;
+ }
if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
struct mtget mt_status;
- if (_IOC_SIZE(cmd_in) != sizeof(struct mtget))
- return (-EINVAL);
+ if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
+ retval = (-EINVAL);
+ goto out;
+ }
mt_status.mt_type = STp->tape_type;
mt_status.mt_dsreg =
@@ -2972,25 +3068,37 @@
i = copy_to_user((char *) arg, (char *) &(mt_status),
sizeof(struct mtget));
- if (i)
- return (-EFAULT);
+ if (i) {
+ retval = (-EFAULT);
+ goto out;
+ }
STp->recover_reg = 0; /* Clear after read */
- return 0;
+ retval = 0;
+ goto out;
} /* End of MTIOCGET */
if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
struct mtpos mt_pos;
- if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos))
- return (-EINVAL);
- if ((i = get_location(STp, &blk, &bt, 0)) < 0)
- return i;
+ if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
+ retval = (-EINVAL);
+ goto out;
+ }
+ if ((i = get_location(STp, &blk, &bt, 0)) < 0) {
+ retval = i;
+ goto out;
+ }
mt_pos.mt_blkno = blk;
i = copy_to_user((char *) arg, (char *) (&mt_pos), sizeof(struct mtpos));
if (i)
- return (-EFAULT);
- return 0;
+ retval = (-EFAULT);
+ goto out;
}
+ up(&STp->lock);
return scsi_ioctl(STp->device, cmd_in, (void *) arg);
+
+ out:
+ up(&STp->lock);
+ return retval;
}
@@ -3469,6 +3577,7 @@
tpnt->density_changed = tpnt->compression_changed =
tpnt->blksize_changed = FALSE;
+ init_MUTEX(&tpnt->lock);
st_template.nr_dev++;
write_unlock_irqrestore(&st_dev_arr_lock, flags);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)