Skip to content

Commit

Permalink
[SCSI] st: add option to use SILI in variable block reads
Browse files Browse the repository at this point in the history
Add new option MT_ST_SILI to enable setting the SILI bit in reads in variable
block mode. If SILI is set, reading a block shorter than the byte count does
not result in CHECK CONDITION. The length of the block is determined using the
residual count from the HBA. Avoiding the REQUEST SENSE command for every
block speeds up some real applications considerably.

Signed-off-by: Kai Makisara <kai.makisara@kolumbus.fi>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
  • Loading branch information
Kai Makisara authored and James Bottomley committed Apr 7, 2008
1 parent d35055a commit 40f6b36
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 6 deletions.
7 changes: 6 additions & 1 deletion Documentation/scsi/st.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ This file contains brief information about the SCSI tape driver.
The driver is currently maintained by Kai Mäkisara (email
Kai.Makisara@kolumbus.fi)

Last modified: Mon Mar 7 21:14:44 2005 by kai.makisara
Last modified: Thu Feb 21 21:54:16 2008 by kai.makisara


BASICS
Expand Down Expand Up @@ -372,6 +372,11 @@ MTSETDRVBUFFER
MT_ST_SYSV sets the SYSV semantics (mode)
MT_ST_NOWAIT enables immediate mode (i.e., don't wait for
the command to finish) for some commands (e.g., rewind)
MT_ST_SILI enables setting the SILI bit in SCSI commands when
reading in variable block mode to enhance performance when
reading blocks shorter than the byte count; set this only
if you are sure that the drive supports SILI and the HBA
correctly returns transfer residuals
MT_ST_DEBUGGING debugging (global; debugging must be
compiled into the driver)
MT_ST_SETBOOLEANS
Expand Down
40 changes: 36 additions & 4 deletions drivers/scsi/st.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions drivers/scsi/st.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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 */

Expand Down
6 changes: 5 additions & 1 deletion drivers/scsi/st_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions include/linux/mtio.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ struct mtpos {
#define MT_ST_SCSI2LOGICAL 0x800
#define MT_ST_SYSV 0x1000
#define MT_ST_NOWAIT 0x2000
#define MT_ST_SILI 0x4000

/* The mode parameters to be controlled. Parameter chosen with bits 20-28 */
#define MT_ST_CLEAR_DEFAULT 0xfffff
Expand Down

0 comments on commit 40f6b36

Please sign in to comment.