summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/st.c40
-rw-r--r--drivers/scsi/st.h3
-rw-r--r--drivers/scsi/st_options.h6
3 files changed, 44 insertions, 5 deletions
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 0a52d9d2da2c..a4361a8c6ac6 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -17,7 +17,7 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
-static const char *verstr = "20080221";
+static const char *verstr = "20080224";
#include <linux/module.h>
@@ -183,6 +183,7 @@ static int modes_defined;
static struct st_buffer *new_tape_buffer(int, int, int);
static int enlarge_buffer(struct st_buffer *, int, int);
+static void clear_buffer(struct st_buffer *);
static void normalize_buffer(struct st_buffer *);
static int append_to_buffer(const char __user *, struct st_buffer *, int);
static int from_buffer(struct st_buffer *, char __user *, int);
@@ -442,6 +443,7 @@ static void st_sleep_done(void *data, char *sense, int result, int resid)
memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE);
(STp->buffer)->cmdstat.midlevel_result = SRpnt->result = result;
+ (STp->buffer)->cmdstat.residual = resid;
DEB( STp->write_pending = 0; )
if (SRpnt->waiting)
@@ -1159,6 +1161,7 @@ static int st_open(struct inode *inode, struct file *filp)
goto err_out;
}
+ (STp->buffer)->cleared = 0;
(STp->buffer)->writing = 0;
(STp->buffer)->syscall_result = 0;
@@ -1432,8 +1435,14 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
if (STp->block_size)
bufsize = STp->block_size > st_fixed_buffer_size ?
STp->block_size : st_fixed_buffer_size;
- else
+ else {
bufsize = count;
+ /* Make sure that data from previous user is not leaked even if
+ HBA does not return correct residual */
+ if (is_read && STp->sili && !STbp->cleared)
+ clear_buffer(STbp);
+ }
+
if (bufsize > STbp->buffer_size &&
!enlarge_buffer(STbp, bufsize, STp->restr_dma)) {
printk(KERN_WARNING "%s: Can't allocate %d byte tape buffer.\n",
@@ -1783,6 +1792,8 @@ static long read_tape(struct scsi_tape *STp, long count,
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = READ_6;
cmd[1] = (STp->block_size != 0);
+ if (!cmd[1] && STp->sili)
+ cmd[1] |= 2;
cmd[2] = blks >> 16;
cmd[3] = blks >> 8;
cmd[4] = blks;
@@ -1911,8 +1922,11 @@ static long read_tape(struct scsi_tape *STp, long count,
}
/* End of error handling */
- else /* Read successful */
+ else { /* Read successful */
STbp->buffer_bytes = bytes;
+ if (STp->sili) /* In fixed block mode residual is always zero here */
+ STbp->buffer_bytes -= STp->buffer->cmdstat.residual;
+ }
if (STps->drv_block >= 0) {
if (STp->block_size == 0)
@@ -2090,7 +2104,8 @@ static void st_log_options(struct scsi_tape * STp, struct st_modedef * STm, char
name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
STp->scsi2_logical);
printk(KERN_INFO
- "%s: sysv: %d nowait: %d\n", name, STm->sysv, STp->immediate);
+ "%s: sysv: %d nowait: %d sili: %d\n", name, STm->sysv, STp->immediate,
+ STp->sili);
printk(KERN_INFO "%s: debugging: %d\n",
name, debugging);
}
@@ -2133,6 +2148,7 @@ static int st_set_options(struct scsi_tape *STp, long options)
STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
STp->immediate = (options & MT_ST_NOWAIT) != 0;
STm->sysv = (options & MT_ST_SYSV) != 0;
+ STp->sili = (options & MT_ST_SILI) != 0;
DEB( debugging = (options & MT_ST_DEBUGGING) != 0;
st_log_options(STp, STm, name); )
} else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
@@ -2164,6 +2180,8 @@ static int st_set_options(struct scsi_tape *STp, long options)
STp->immediate = value;
if ((options & MT_ST_SYSV) != 0)
STm->sysv = value;
+ if ((options & MT_ST_SILI) != 0)
+ STp->sili = value;
DEB(
if ((options & MT_ST_DEBUGGING) != 0)
debugging = value;
@@ -3655,6 +3673,8 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm
STbuffer->frp_segs += 1;
got += b_size;
STbuffer->buffer_size = got;
+ if (STbuffer->cleared)
+ memset(page_address(STbuffer->frp[segs].page), 0, b_size);
segs++;
}
STbuffer->b_data = page_address(STbuffer->frp[0].page);
@@ -3663,6 +3683,17 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm
}
+/* Make sure that no data from previous user is in the internal buffer */
+static void clear_buffer(struct st_buffer * st_bp)
+{
+ int i;
+
+ for (i=0; i < st_bp->frp_segs; i++)
+ memset(page_address(st_bp->frp[i].page), 0, st_bp->frp[i].length);
+ st_bp->cleared = 1;
+}
+
+
/* Release the extra buffer */
static void normalize_buffer(struct st_buffer * STbuffer)
{
@@ -3987,6 +4018,7 @@ static int st_probe(struct device *dev)
tpnt->two_fm = ST_TWO_FM;
tpnt->fast_mteom = ST_FAST_MTEOM;
tpnt->scsi2_logical = ST_SCSI2LOGICAL;
+ tpnt->sili = ST_SILI;
tpnt->immediate = ST_NOWAIT;
tpnt->default_drvbuffer = 0xff; /* No forced buffering */
tpnt->partition = 0;
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 5931726fcf93..b92712f95931 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -12,6 +12,7 @@ struct st_cmdstatus {
int midlevel_result;
struct scsi_sense_hdr sense_hdr;
int have_sense;
+ int residual;
u64 uremainder64;
u8 flags;
u8 remainder_valid;
@@ -34,6 +35,7 @@ struct st_request {
struct st_buffer {
unsigned char dma; /* DMA-able buffer */
unsigned char do_dio; /* direct i/o set up? */
+ unsigned char cleared; /* internal buffer cleared after open? */
int buffer_size;
int buffer_blocks;
int buffer_bytes;
@@ -122,6 +124,7 @@ struct scsi_tape {
unsigned char try_dio_now; /* try direct i/o before next close? */
unsigned char c_algo; /* compression algorithm */
unsigned char pos_unknown; /* after reset position unknown */
+ unsigned char sili; /* use SILI when reading in variable b mode */
int tape_type;
int long_timeout; /* timeout for commands known to take long time */
diff --git a/drivers/scsi/st_options.h b/drivers/scsi/st_options.h
index b6b5c9c37677..d2f947935554 100644
--- a/drivers/scsi/st_options.h
+++ b/drivers/scsi/st_options.h
@@ -3,7 +3,7 @@
Copyright 1995-2003 Kai Makisara.
- Last modified: Mon Apr 7 22:49:18 2003 by makisara
+ Last modified: Thu Feb 21 21:47:07 2008 by kai.makisara
*/
#ifndef _ST_OPTIONS_H
@@ -94,6 +94,10 @@
The default is BSD semantics. */
#define ST_SYSV 0
+/* If ST_SILI is non-zero, the SILI bit is set when reading in variable block
+ mode and the block size is determined using the residual returned by the HBA. */
+#define ST_SILI 0
+
/* Time to wait for the drive to become ready if blocking open */
#define ST_BLOCK_SECONDS 120