patch-2.4.22 linux-2.4.22/drivers/scsi/st.c
Next file: linux-2.4.22/drivers/scsi/st.h
Previous file: linux-2.4.22/drivers/scsi/sim710_d.h
Back to the patch index
Back to the overall index
- Lines: 433
- Date:
2003-08-25 04:44:42.000000000 -0700
- Orig file:
linux-2.4.21/drivers/scsi/st.c
- Orig date:
2002-11-28 15:53:14.000000000 -0800
diff -urN linux-2.4.21/drivers/scsi/st.c linux-2.4.22/drivers/scsi/st.c
@@ -9,10 +9,10 @@
Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
Michael Schaefer, J"org Weule, and Eric Youngdale.
- Copyright 1992 - 2002 Kai Makisara
- email Kai.Makisara@metla.fi
+ Copyright 1992 - 2003 Kai Makisara
+ email Kai.Makisara@kolumbus.fi
- Last modified: Mon Aug 5 22:54:13 2002 by makisara
+ Last modified: Sun Apr 6 22:44:42 2003 by makisara
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 = "20020805";
+static char *verstr = "20030406";
#include <linux/module.h>
@@ -72,7 +72,6 @@
#include "constants.h"
static int buffer_kbs;
-static int write_threshold_kbs;
static int max_buffers = (-1);
static int max_sg_segs;
static int blocking_open = ST_BLOCKING_OPEN;
@@ -84,8 +83,6 @@
MODULE_PARM(buffer_kbs, "i");
MODULE_PARM_DESC(buffer_kbs, "Default driver buffer size (KB; 32)");
-MODULE_PARM(write_threshold_kbs, "i");
-MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 30)");
MODULE_PARM(max_buffers, "i");
MODULE_PARM_DESC(max_buffers, "Maximum number of buffer allocated at initialisation (4)");
MODULE_PARM(max_sg_segs, "i");
@@ -103,8 +100,8 @@
{
"buffer_kbs", &buffer_kbs
},
- {
- "write_threshold_kbs", &write_threshold_kbs
+ { /* Retained for compatibility */
+ "write_threshold_kbs", NULL
},
{
"max_buffers", &max_buffers
@@ -122,7 +119,6 @@
/* The default definitions have been moved to st_options.h */
#define ST_BUFFER_SIZE (ST_BUFFER_BLOCKS * ST_KILOBYTE)
-#define ST_WRITE_THRESHOLD (ST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
/* The buffer size should fit into the 24 bits for length in the
6-byte SCSI read and write commands. */
@@ -153,7 +149,6 @@
static int st_nbr_buffers;
static ST_buffer **st_buffers = NULL;
static int st_buffer_size = ST_BUFFER_SIZE;
-static int st_write_threshold = ST_WRITE_THRESHOLD;
static int st_max_buffers = ST_MAX_BUFFERS;
static int st_max_sg_segs = ST_MAX_SG;
@@ -167,6 +162,7 @@
static int set_sg_lengths(ST_buffer *, unsigned int);
static int append_to_buffer(const char *, ST_buffer *, int);
static int from_buffer(ST_buffer *, char *, int);
+static void move_buffer_data(ST_buffer *, int);
static int st_init(void);
static int st_attach(Scsi_Device *);
@@ -1196,6 +1192,7 @@
ssize_t total;
ssize_t i, do_count, blks, transfer;
ssize_t retval = 0;
+ int residual, retry_eot = 0, scode;
int write_threshold;
int doing_write = 0;
unsigned char cmd[MAX_COMMAND_SIZE];
@@ -1367,7 +1364,7 @@
write_threshold = 1;
} else
write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
- if (!STm->do_async_writes)
+ if (!STm->do_async_writes || STp->block_size > 0)
write_threshold--;
total = count;
@@ -1381,7 +1378,7 @@
b_point = buf;
while ((STp->block_size == 0 && !STm->do_async_writes && count > 0) ||
(STp->block_size != 0 &&
- (STp->buffer)->buffer_bytes + count > write_threshold)) {
+ (STp->buffer)->buffer_bytes + count > write_threshold && !retry_eot)) {
doing_write = 1;
if (STp->block_size == 0)
do_count = count;
@@ -1398,6 +1395,7 @@
goto out;
}
+ retry_write:
if (STp->block_size == 0)
blks = transfer = do_count;
else {
@@ -1420,46 +1418,66 @@
DEBC(printk(ST_DEB_MSG "st%d: Error on write:\n", dev));
if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
(SRpnt->sr_sense_buffer[2] & 0x40)) {
+ scode = SRpnt->sr_sense_buffer[2] & 0x0f;
if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0)
- transfer = (SRpnt->sr_sense_buffer[3] << 24) |
+ residual = (SRpnt->sr_sense_buffer[3] << 24) |
(SRpnt->sr_sense_buffer[4] << 16) |
(SRpnt->sr_sense_buffer[5] << 8) |
SRpnt->sr_sense_buffer[6];
else if (STp->block_size == 0 &&
- (SRpnt->sr_sense_buffer[2] & 0x0f) ==
- VOLUME_OVERFLOW)
- transfer = do_count;
+ scode == VOLUME_OVERFLOW)
+ residual = do_count;
else
- transfer = 0;
+ residual = 0;
if (STp->block_size != 0)
- transfer *= STp->block_size;
- if (transfer <= do_count) {
- filp->f_pos += do_count - transfer;
- count -= do_count - transfer;
+ residual *= STp->block_size;
+ if (residual <= do_count) {
+ /* Within the data in this write() */
+ filp->f_pos += do_count - residual;
+ count -= do_count - residual;
if (STps->drv_block >= 0) {
if (STp->block_size == 0 &&
- transfer < do_count)
+ residual < do_count)
STps->drv_block++;
else if (STp->block_size != 0)
STps->drv_block +=
- (do_count - transfer) /
+ (transfer - residual) /
STp->block_size;
}
STps->eof = ST_EOM_OK;
retval = (-ENOSPC); /* EOM within current request */
DEBC(printk(ST_DEB_MSG
"st%d: EOM with %d bytes unwritten.\n",
- dev, transfer));
+ dev, count));
} else {
- STps->eof = ST_EOM_ERROR;
- STps->drv_block = (-1); /* Too cautious? */
- retval = (-EIO); /* EOM for old data */
- DEBC(printk(ST_DEB_MSG
- "st%d: EOM with lost data.\n",
- dev));
+ /* EOT in within data buffered earlier */
+ if (!retry_eot && (SRpnt->sr_sense_buffer[0] & 1) == 0 &&
+ (scode == NO_SENSE || scode == RECOVERED_ERROR)) {
+ move_buffer_data(STp->buffer, transfer - residual);
+ retry_eot = TRUE;
+ if (STps->drv_block >= 0) {
+ STps->drv_block += (transfer - residual) /
+ STp->block_size;
+ }
+ STps->eof = ST_EOM_OK;
+ DEBC(printk(ST_DEB_MSG
+ "st%d: Retry write of %d bytes at EOM.\n",
+ dev, do_count));
+ goto retry_write;
+ }
+ else {
+ /* Either error within data buffered by driver or failed retry */
+ STps->eof = ST_EOM_ERROR;
+ STps->drv_block = (-1); /* Too cautious? */
+ retval = (-EIO); /* EOM for old data */
+ DEBC(printk(ST_DEB_MSG
+ "st%d: EOM with lost data.\n",
+ dev));
+ }
}
} else {
STps->drv_block = (-1); /* Too cautious? */
+ retry_eot = FALSE;
retval = (-EIO);
}
@@ -1483,7 +1501,7 @@
(STp->buffer)->buffer_bytes = 0;
STp->dirty = 0;
}
- if (count != 0) {
+ if (count != 0 && !retry_eot) {
STp->dirty = 1;
i = append_to_buffer(b_point, STp->buffer, count);
if (i) {
@@ -1499,26 +1517,14 @@
goto out;
}
- if (STm->do_async_writes &&
- (((STp->buffer)->buffer_bytes >= STp->write_threshold &&
- (STp->buffer)->buffer_bytes >= STp->block_size) ||
- STp->block_size == 0)) {
+ if (STm->do_async_writes && STp->block_size == 0) {
/* Schedule an asynchronous write */
- if (STp->block_size == 0)
- (STp->buffer)->writing = (STp->buffer)->buffer_bytes;
- else
- (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
- STp->block_size) * STp->block_size;
- STp->dirty = !((STp->buffer)->writing ==
- (STp->buffer)->buffer_bytes);
-
- if (STp->block_size == 0)
- blks = (STp->buffer)->writing;
- else
- blks = (STp->buffer)->writing / STp->block_size;
- cmd[2] = blks >> 16;
- cmd[3] = blks >> 8;
- cmd[4] = blks;
+ (STp->buffer)->writing = (STp->buffer)->buffer_bytes;
+ STp->dirty = FALSE;
+ residual = (STp->buffer)->writing;
+ cmd[2] = residual >> 16;
+ cmd[3] = residual >> 8;
+ cmd[4] = residual;
DEB( STp->write_pending = 1; )
SRpnt = st_do_scsi(SRpnt, STp, cmd, (STp->buffer)->writing,
@@ -1532,9 +1538,9 @@
}
STps->at_sm &= (total == 0);
- if (total > 0)
+ if (total > 0 && !retry_eot)
STps->eof = ST_NOEOF;
- retval = total;
+ retval = total - count;
out:
if (SRpnt != NULL)
@@ -1625,9 +1631,14 @@
if (SRpnt->sr_sense_buffer[2] & 0x20) { /* ILI */
if (STp->block_size == 0) {
- if (transfer < 0) {
+ if (transfer <= 0) {
+ if (transfer < 0)
+ printk(KERN_NOTICE
+ "st%d: Failed to read %d byte block with %d byte read.\n",
+ dev, bytes - transfer, bytes);
if (STps->drv_block >= 0)
STps->drv_block += 1;
+ (STp->buffer)->buffer_bytes = 0;
return (-ENOMEM);
}
(STp->buffer)->buffer_bytes = bytes - transfer;
@@ -1694,6 +1705,9 @@
} else /* Some other extended sense code */
retval = (-EIO);
}
+
+ if ((STp->buffer)->buffer_bytes < 0) /* Caused by bogus sense data */
+ (STp->buffer)->buffer_bytes = 0;
}
/* End of extended sense test */
else { /* Non-extended sense */
@@ -2004,16 +2018,7 @@
debugging = value; )
st_log_options(STp, STm, dev);
} else if (code == MT_ST_WRITE_THRESHOLD) {
- value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
- if (value < 1 || value > st_buffer_size) {
- printk(KERN_WARNING
- "st%d: Write threshold %d too small or too large.\n",
- dev, value);
- return (-EIO);
- }
- STp->write_threshold = value;
- printk(KERN_INFO "st%d: Write threshold set to %d bytes.\n",
- dev, value);
+ /* Retained for compatibility */
} else if (code == MT_ST_DEF_BLKSIZE) {
value = (options & ~MT_ST_OPTIONS);
if (value == ~MT_ST_OPTIONS) {
@@ -2155,7 +2160,7 @@
/* Send the mode page in the tape buffer to the drive. Assumes that the mode data
in the buffer is correctly formatted. */
-static int write_mode_page(Scsi_Tape *STp, int page)
+static int write_mode_page(Scsi_Tape *STp, int page, int slow)
{
int pgo;
unsigned char cmd[MAX_COMMAND_SIZE];
@@ -2174,7 +2179,7 @@
(STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR;
SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
- STp->timeout, 0, TRUE);
+ (slow ? STp->long_timeout : STp->timeout), 0, TRUE);
if (SRpnt == NULL)
return (STp->buffer)->syscall_result;
@@ -2241,7 +2246,7 @@
b_data[mpoffs + CP_OFF_C_ALGO] = 0; /* no compression */
}
- retval = write_mode_page(STp, COMPRESSION_PAGE);
+ retval = write_mode_page(STp, COMPRESSION_PAGE, FALSE);
if (retval) {
DEBC(printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev));
return (-EIO);
@@ -3055,7 +3060,7 @@
bp[pgo + PP_OFF_RESERVED] = 0;
bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | PP_MSK_PSUM_MB;
- result = write_mode_page(STp, PART_PAGE);
+ result = write_mode_page(STp, PART_PAGE, TRUE);
if (result) {
printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev);
result = (-EIO);
@@ -3644,6 +3649,50 @@
}
+/* Move data towards start of buffer */
+static void move_buffer_data(ST_buffer * st_bp, int offset)
+{
+ int src_seg, dst_seg, src_offset = 0, dst_offset;
+ int count, total;
+
+ if (offset == 0)
+ return;
+
+ total=st_bp->buffer_bytes - offset;
+ for (src_seg=0; src_seg < st_bp->sg_segs; src_seg++) {
+ src_offset = offset;
+ if (src_offset < st_bp->sg_lengths[src_seg])
+ break;
+ offset -= st_bp->sg_lengths[src_seg];
+ }
+ if (src_seg == st_bp->sg_segs) { /* Should never happen */
+ printk(KERN_WARNING "st: zap_buffer offset overflow.\n");
+ return;
+ }
+
+ st_bp->buffer_bytes = st_bp->read_pointer = total;
+ for (dst_seg=dst_offset=0; total > 0; ) {
+ count = min(st_bp->sg_lengths[dst_seg] - dst_offset,
+ st_bp->sg_lengths[src_seg] - src_offset);
+ memmove(st_bp->sg[dst_seg].address + dst_offset,
+ st_bp->sg[src_seg].address + src_offset, count);
+ printk("st: move (%d,%d) -> (%d,%d) count %d\n",
+ src_seg, src_offset, dst_seg, dst_offset, count);
+ src_offset += count;
+ if (src_offset >= st_bp->sg_lengths[src_seg]) {
+ src_seg++;
+ src_offset = 0;
+ }
+ dst_offset += count;
+ if (dst_offset >= st_bp->sg_lengths[dst_seg]) {
+ dst_seg++;
+ dst_offset = 0;
+ }
+ total -= count;
+ }
+}
+
+
/* Set the scatter/gather list length fields to sum up to the transfer length.
Return the number of segments being used. */
static int set_sg_lengths(ST_buffer *st_bp, unsigned int length)
@@ -3668,15 +3717,6 @@
{
if (buffer_kbs > 0)
st_buffer_size = buffer_kbs * ST_KILOBYTE;
- if (write_threshold_kbs > 0)
- st_write_threshold = write_threshold_kbs * ST_KILOBYTE;
- else if (buffer_kbs > 0)
- st_write_threshold = st_buffer_size - 2048;
- if (st_write_threshold > st_buffer_size) {
- st_write_threshold = st_buffer_size;
- printk(KERN_WARNING "st: write_threshold limited to %d bytes.\n",
- st_write_threshold);
- }
if (max_buffers >= 0)
st_max_buffers = max_buffers;
if (max_sg_segs >= ST_FIRST_SG)
@@ -3695,13 +3735,15 @@
if (ints[0] > 0) {
for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
- *parms[i].val = ints[i + 1];
+ if (parms[i].val)
+ *parms[i].val = ints[i + 1];
} else {
while (stp != NULL) {
for (i = 0; i < ARRAY_SIZE(parms); i++) {
len = strlen(parms[i].name);
if (!strncmp(stp, parms[i].name, len) &&
- (*(stp + len) == ':' || *(stp + len) == '=')) {
+ (*(stp + len) == ':' || *(stp + len) == '=') &&
+ parms[i].val) {
*parms[i].val =
simple_strtoul(stp + len + 1, NULL, 0);
break;
@@ -3863,7 +3905,6 @@
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;
tpnt->new_partition = 0;
@@ -3941,8 +3982,8 @@
return 0;
printk(KERN_INFO
- "st: Version %s, bufsize %d, wrt %d, max init. bufs %d, s/g segs %d\n",
- verstr, st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
+ "st: Version %s, bufsize %d, max init. bufs %d, s/g segs %d\n",
+ verstr, st_buffer_size, st_max_buffers, st_max_sg_segs);
write_lock_irqsave(&st_dev_arr_lock, flags);
if (!st_registered) {
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)