patch-2.4.15 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: 596
- Date:
Fri Nov 9 13:52:21 2001
- Orig file:
v2.4.14/linux/drivers/scsi/st.c
- Orig date:
Mon Nov 5 15:55:32 2001
diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
@@ -12,7 +12,7 @@
Copyright 1992 - 2001 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Wed Oct 3 22:17:59 2001 by makisara@kai.makisara.local
+ Last modified: Sat Nov 3 19:30:55 2001 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
@@ -21,7 +21,7 @@
error handling will be discarded.
*/
-static char *verstr = "20011003";
+static char *verstr = "20011103";
#include <linux/module.h>
@@ -276,6 +276,17 @@
driver_byte(result) & DRIVER_MASK, host_byte(result));
}
+ if (STp->cln_mode >= EXTENDED_SENSE_START) {
+ if (STp->cln_sense_value)
+ STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] &
+ STp->cln_sense_mask) == STp->cln_sense_value);
+ else
+ STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] &
+ STp->cln_sense_mask) != 0);
+ }
+ if (sense[12] == 0 && sense[13] == 0x17) /* ASC and ASCQ => cleaning requested */
+ STp->cleaning_req = 1;
+
if ((sense[0] & 0x70) == 0x70 &&
scode == RECOVERED_ERROR
#if ST_RECOVERED_WRITE_FATAL
@@ -414,15 +425,6 @@
(STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt);
scsi_release_request((STp->buffer)->last_SRpnt);
- if (STbuffer->writing < STbuffer->buffer_bytes)
-#if 0
- memcpy(STbuffer->b_data,
- STbuffer->b_data + STbuffer->writing,
- STbuffer->buffer_bytes - STbuffer->writing);
-#else
- printk(KERN_WARNING
- "st: write_behind_check: something left in buffer!\n");
-#endif
STbuffer->buffer_bytes -= STbuffer->writing;
STps = &(STp->ps[STp->partition]);
if (STps->drv_block >= 0) {
@@ -636,47 +638,27 @@
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];
+/* See if the drive is ready and gather information about the tape. Return values:
+ < 0 negative error code from errno.h
+ 0 drive ready
+ 1 drive not ready (possibly no tape)
+*/
+#define CHKRES_READY 0
+#define CHKRES_NOT_READY 1
+
+static int check_tape(Scsi_Tape *STp, struct file *filp)
+{
+ int i, retval, new_session = FALSE;
+ unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning;
+ unsigned short st_flags = filp->f_flags;
Scsi_Request *SRpnt;
- Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
- int dev = TAPE_NR(inode->i_rdev);
+ int dev = TAPE_NR(STp->devt);
+ struct inode *inode = filp->f_dentry->d_inode;
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);
- STp->device->access_count++;
- if (!scsi_block_when_processing_errors(STp->device)) {
- retval = (-ENXIO);
- goto err_out;
- }
+ STp->ready = ST_READY;
if (mode != STp->current_mode) {
DEBC(printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n",
@@ -686,54 +668,11 @@
}
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;
+ saved_cleaning = STp->cleaning_req;
+ STp->cleaning_req = 0;
SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout,
MAX_READY_RETRIES, TRUE);
if (!SRpnt) {
@@ -742,7 +681,7 @@
}
if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
- (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
+ (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
/* Flush the queued UNIT ATTENTION sense data */
for (i=0; i < 10; i++) {
@@ -771,6 +710,8 @@
}
new_session = TRUE;
}
+ else
+ STp->cleaning_req |= saved_cleaning;
if ((STp->buffer)->syscall_result != 0) {
if ((STp->device)->scsi_level >= SCSI_2 &&
@@ -788,7 +729,7 @@
STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
STp->partition = STp->new_partition = 0;
STp->door_locked = ST_UNLOCKED;
- return 0;
+ return CHKRES_NOT_READY;
}
if (STp->omit_blklims)
@@ -869,7 +810,8 @@
DEBC(printk(ST_DEB_MSG "st%d: Write protected\n", dev));
- if ((st_flags & O_ACCMODE) == O_WRONLY || (st_flags & O_ACCMODE) == O_RDWR) {
+ if ((st_flags & O_ACCMODE) == O_WRONLY ||
+ (st_flags & O_ACCMODE) == O_RDWR) {
retval = (-EROFS);
goto err_out;
}
@@ -904,6 +846,95 @@
}
}
+ 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, need_dma_buffer;
+ int retval = (-EIO);
+ Scsi_Tape *STp;
+ ST_partstat *STps;
+ int dev = TAPE_NR(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);
+ STp->device->access_count++;
+
+ if (!scsi_block_when_processing_errors(STp->device)) {
+ retval = (-ENXIO);
+ goto err_out;
+ }
+
+ /* 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;
+ }
+
+ 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->recover_count = 0;
+ DEB( STp->nbr_waits = STp->nbr_finished = 0; )
+
+ retval = check_tape(STp, filp);
+ if (retval < 0)
+ goto err_out;
return 0;
err_out:
@@ -1819,7 +1850,7 @@
dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
STp->scsi2_logical);
printk(KERN_INFO
- "st%d: sysv: %d\n", dev, STm->sysv);
+ "st%d: sysv: %d nowait: %d\n", dev, STm->sysv, STp->immediate);
DEB(printk(KERN_INFO
"st%d: debugging: %d\n",
dev, debugging);)
@@ -1856,6 +1887,7 @@
if ((STp->device)->scsi_level >= SCSI_2)
STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
+ STp->immediate = (options & MT_ST_NOWAIT) != 0;
STm->sysv = (options & MT_ST_SYSV) != 0;
DEB( debugging = (options & MT_ST_DEBUGGING) != 0; )
st_log_options(STp, STm, dev);
@@ -1884,6 +1916,8 @@
STp->can_partitions = value;
if ((options & MT_ST_SCSI2LOGICAL) != 0)
STp->scsi2_logical = value;
+ if ((options & MT_ST_NOWAIT) != 0)
+ STp->immediate = value;
if ((options & MT_ST_SYSV) != 0)
STm->sysv = value;
DEB(
@@ -1922,6 +1956,17 @@
printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n",
dev, value);
}
+ } else if (code == MT_ST_SET_CLN) {
+ value = (options & ~MT_ST_OPTIONS) & 0xff;
+ if (value != 0 &&
+ value < EXTENDED_SENSE_START && value >= SCSI_SENSE_BUFFERSIZE)
+ return (-EINVAL);
+ STp->cln_mode = value;
+ STp->cln_sense_mask = (options >> 8) & 0xff;
+ STp->cln_sense_value = (options >> 16) & 0xff;
+ printk(KERN_INFO
+ "st%d: Cleaning request mode %d, mask %02x, value %02x\n",
+ dev, value, STp->cln_sense_mask, STp->cln_sense_value);
} else if (code == MT_ST_DEF_OPTIONS) {
code = (options & ~MT_ST_CLEAR_DEFAULT);
value = (options & MT_ST_CLEAR_DEFAULT);
@@ -2099,6 +2144,78 @@
STp->compression_changed = TRUE;
return 0;
}
+
+
+/* Process the load and unload commands (does unload if the load code is zero) */
+static int do_load_unload(Scsi_Tape *STp, struct file *filp, int load_code)
+{
+ int retval = (-EIO), timeout;
+ DEB(int dev = TAPE_NR(STp->devt);)
+ unsigned char cmd[MAX_COMMAND_SIZE];
+ ST_partstat *STps;
+ Scsi_Request *SRpnt;
+
+ if (STp->ready != ST_READY && !load_code) {
+ if (STp->ready == ST_NO_TAPE)
+ return (-ENOMEDIUM);
+ else
+ return (-EIO);
+ }
+
+ memset(cmd, 0, MAX_COMMAND_SIZE);
+ cmd[0] = START_STOP;
+ if (load_code)
+ cmd[4] |= 1;
+ /*
+ * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A
+ */
+ if (load_code >= 1 + MT_ST_HPLOADER_OFFSET
+ && load_code <= 6 + MT_ST_HPLOADER_OFFSET) {
+ DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n",
+ dev, (cmd[4]) ? "" : "un",
+ load_code - MT_ST_HPLOADER_OFFSET));
+ cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
+ }
+ if (STp->immediate) {
+ cmd[1] = 1; /* Don't wait for completion */
+ timeout = STp->timeout;
+ }
+ else
+ timeout = STp->long_timeout;
+
+ DEBC(
+ if (!load_code)
+ printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev);
+ else
+ printk(ST_DEB_MSG "st%d: Loading tape.\n", dev);
+ );
+
+ SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,
+ timeout, MAX_RETRIES, TRUE);
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
+
+ retval = (STp->buffer)->syscall_result;
+ scsi_release_request(SRpnt);
+
+ if (!retval) { /* SCSI command successful */
+
+ if (!load_code)
+ STp->rew_at_close = 0;
+ else
+ STp->rew_at_close = STp->autorew_dev;
+
+ retval = check_tape(STp, filp);
+ if (retval > 0)
+ retval = 0;
+ }
+ else {
+ STps = &(STp->ps[STp->partition]);
+ STps->drv_file = STps->drv_block = (-1);
+ }
+
+ return retval;
+}
/* Internal ioctl function */
@@ -2106,7 +2223,7 @@
{
int timeout;
long ltmp;
- int i, ioctl_result;
+ int ioctl_result;
int chg_eof = TRUE;
unsigned char cmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt;
@@ -2115,7 +2232,7 @@
int datalen = 0, direction = SCSI_DATA_NONE;
int dev = TAPE_NR(STp->devt);
- if (STp->ready != ST_READY && cmd_in != MTLOAD) {
+ if (STp->ready != ST_READY) {
if (STp->ready == ST_NO_TAPE)
return (-ENOMEDIUM);
else
@@ -2254,42 +2371,11 @@
break;
case MTREW:
cmd[0] = REZERO_UNIT;
-#if ST_NOWAIT
- cmd[1] = 1; /* Don't wait for completion */
- timeout = STp->timeout;
-#endif
- DEBC(printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev));
- fileno = blkno = at_sm = 0;
- break;
- case MTOFFL:
- case MTLOAD:
- case MTUNLOAD:
- cmd[0] = START_STOP;
- if (cmd_in == MTLOAD)
- cmd[4] |= 1;
- /*
- * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A
- */
- if (cmd_in != MTOFFL &&
- arg >= 1 + MT_ST_HPLOADER_OFFSET
- && arg <= 6 + MT_ST_HPLOADER_OFFSET) {
- DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n",
- dev, (cmd[4]) ? "" : "un",
- arg - MT_ST_HPLOADER_OFFSET));
- cmd[3] = arg - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
+ if (STp->immediate) {
+ cmd[1] = 1; /* Don't wait for completion */
+ timeout = STp->timeout;
}
-#if ST_NOWAIT
- cmd[1] = 1; /* Don't wait for completion */
- timeout = STp->timeout;
-#else
- timeout = STp->long_timeout;
-#endif
- DEBC(
- if (cmd_in != MTLOAD)
- printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev);
- else
- printk(ST_DEB_MSG "st%d: Loading tape.\n", dev);
- )
+ DEBC(printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev));
fileno = blkno = at_sm = 0;
break;
case MTNOP:
@@ -2298,10 +2384,10 @@
break;
case MTRETEN:
cmd[0] = START_STOP;
-#if ST_NOWAIT
- cmd[1] = 1; /* Don't wait for completion */
- timeout = STp->timeout;
-#endif
+ if (STp->immediate) {
+ cmd[1] = 1; /* Don't wait for completion */
+ timeout = STp->timeout;
+ }
cmd[4] = 3;
DEBC(printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev));
fileno = blkno = at_sm = 0;
@@ -2331,12 +2417,13 @@
return (-EACCES);
cmd[0] = ERASE;
cmd[1] = 1; /* To the end of tape */
-#if ST_NOWAIT
- cmd[1] |= 2; /* Don't wait for completion */
- timeout = STp->timeout;
-#else
- timeout = STp->long_timeout * 8;
-#endif
+ if (STp->immediate) {
+ cmd[1] |= 2; /* Don't wait for completion */
+ timeout = STp->timeout;
+ }
+ else
+ timeout = STp->long_timeout * 8;
+
DEBC(printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev));
fileno = blkno = at_sm = 0;
break;
@@ -2462,17 +2549,6 @@
else if (chg_eof)
STps->eof = ST_NOEOF;
-
- if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
- STp->rew_at_close = 0;
- else if (cmd_in == MTLOAD) {
- STp->rew_at_close = STp->autorew_dev;
- for (i = 0; i < ST_NBR_PARTITIONS; i++) {
- STp->ps[i].rw = ST_IDLE;
- STp->ps[i].last_block_valid = FALSE;
- }
- STp->partition = 0;
- }
} else { /* SCSI command was not completely successful. Don't return
from this block without releasing the SCSI command block! */
@@ -2692,10 +2768,10 @@
dev, STp->partition, partition));
}
}
-#if ST_NOWAIT
- scmd[1] |= 1; /* Don't wait for completion */
- timeout = STp->timeout;
-#endif
+ if (STp->immediate) {
+ scmd[1] |= 1; /* Don't wait for completion */
+ timeout = STp->timeout;
+ }
SRpnt = st_do_scsi(NULL, STp, scmd, 0, SCSI_DATA_NONE,
timeout, MAX_READY_RETRIES, TRUE);
@@ -3073,6 +3149,16 @@
goto out;
}
+ if (mtc.mt_op == MTUNLOAD || mtc.mt_op == MTOFFL) {
+ retval = do_load_unload(STp, file, 0);
+ goto out;
+ }
+
+ if (mtc.mt_op == MTLOAD) {
+ retval = do_load_unload(STp, file, max(1, mtc.mt_count));
+ goto out;
+ }
+
if (STp->can_partitions && STp->ready == ST_READY &&
(i = update_partition(STp)) < 0) {
retval = i;
@@ -3155,6 +3241,8 @@
(STm->do_buffer_writes && STp->block_size != 0) ||
STp->drv_buffer != 0)
mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
+ if (STp->cleaning_req)
+ mt_status.mt_gstat |= GMT_CLN(0xffffffff);
i = copy_to_user((char *) arg, (char *) &(mt_status),
sizeof(struct mtget));
@@ -3642,6 +3730,7 @@
tpnt->two_fm = ST_TWO_FM;
tpnt->fast_mteom = ST_FAST_MTEOM;
tpnt->scsi2_logical = ST_SCSI2LOGICAL;
+ tpnt->immediate = ST_NOWAIT;
tpnt->write_threshold = st_write_threshold;
tpnt->default_drvbuffer = 0xff; /* No forced buffering */
tpnt->partition = 0;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)