Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[SCSI] st: add option to use SILI in variable block reads

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>

authored by

Kai Makisara and committed by
James Bottomley
40f6b36c d35055a0

+51 -6
+6 -1
Documentation/scsi/st.txt
··· 2 2 The driver is currently maintained by Kai Mäkisara (email 3 3 Kai.Makisara@kolumbus.fi) 4 4 5 - Last modified: Mon Mar 7 21:14:44 2005 by kai.makisara 5 + Last modified: Thu Feb 21 21:54:16 2008 by kai.makisara 6 6 7 7 8 8 BASICS ··· 372 372 MT_ST_SYSV sets the SYSV semantics (mode) 373 373 MT_ST_NOWAIT enables immediate mode (i.e., don't wait for 374 374 the command to finish) for some commands (e.g., rewind) 375 + MT_ST_SILI enables setting the SILI bit in SCSI commands when 376 + reading in variable block mode to enhance performance when 377 + reading blocks shorter than the byte count; set this only 378 + if you are sure that the drive supports SILI and the HBA 379 + correctly returns transfer residuals 375 380 MT_ST_DEBUGGING debugging (global; debugging must be 376 381 compiled into the driver) 377 382 MT_ST_SETBOOLEANS
+36 -4
drivers/scsi/st.c
··· 17 17 Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support 18 18 */ 19 19 20 - static const char *verstr = "20080221"; 20 + static const char *verstr = "20080224"; 21 21 22 22 #include <linux/module.h> 23 23 ··· 183 183 184 184 static struct st_buffer *new_tape_buffer(int, int, int); 185 185 static int enlarge_buffer(struct st_buffer *, int, int); 186 + static void clear_buffer(struct st_buffer *); 186 187 static void normalize_buffer(struct st_buffer *); 187 188 static int append_to_buffer(const char __user *, struct st_buffer *, int); 188 189 static int from_buffer(struct st_buffer *, char __user *, int); ··· 443 442 444 443 memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE); 445 444 (STp->buffer)->cmdstat.midlevel_result = SRpnt->result = result; 445 + (STp->buffer)->cmdstat.residual = resid; 446 446 DEB( STp->write_pending = 0; ) 447 447 448 448 if (SRpnt->waiting) ··· 1161 1159 goto err_out; 1162 1160 } 1163 1161 1162 + (STp->buffer)->cleared = 0; 1164 1163 (STp->buffer)->writing = 0; 1165 1164 (STp->buffer)->syscall_result = 0; 1166 1165 ··· 1435 1432 if (STp->block_size) 1436 1433 bufsize = STp->block_size > st_fixed_buffer_size ? 1437 1434 STp->block_size : st_fixed_buffer_size; 1438 - else 1435 + else { 1439 1436 bufsize = count; 1437 + /* Make sure that data from previous user is not leaked even if 1438 + HBA does not return correct residual */ 1439 + if (is_read && STp->sili && !STbp->cleared) 1440 + clear_buffer(STbp); 1441 + } 1442 + 1440 1443 if (bufsize > STbp->buffer_size && 1441 1444 !enlarge_buffer(STbp, bufsize, STp->restr_dma)) { 1442 1445 printk(KERN_WARNING "%s: Can't allocate %d byte tape buffer.\n", ··· 1792 1783 memset(cmd, 0, MAX_COMMAND_SIZE); 1793 1784 cmd[0] = READ_6; 1794 1785 cmd[1] = (STp->block_size != 0); 1786 + if (!cmd[1] && STp->sili) 1787 + cmd[1] |= 2; 1795 1788 cmd[2] = blks >> 16; 1796 1789 cmd[3] = blks >> 8; 1797 1790 cmd[4] = blks; ··· 1922 1911 1923 1912 } 1924 1913 /* End of error handling */ 1925 - else /* Read successful */ 1914 + else { /* Read successful */ 1926 1915 STbp->buffer_bytes = bytes; 1916 + if (STp->sili) /* In fixed block mode residual is always zero here */ 1917 + STbp->buffer_bytes -= STp->buffer->cmdstat.residual; 1918 + } 1927 1919 1928 1920 if (STps->drv_block >= 0) { 1929 1921 if (STp->block_size == 0) ··· 2104 2090 name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, 2105 2091 STp->scsi2_logical); 2106 2092 printk(KERN_INFO 2107 - "%s: sysv: %d nowait: %d\n", name, STm->sysv, STp->immediate); 2093 + "%s: sysv: %d nowait: %d sili: %d\n", name, STm->sysv, STp->immediate, 2094 + STp->sili); 2108 2095 printk(KERN_INFO "%s: debugging: %d\n", 2109 2096 name, debugging); 2110 2097 } ··· 2148 2133 STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; 2149 2134 STp->immediate = (options & MT_ST_NOWAIT) != 0; 2150 2135 STm->sysv = (options & MT_ST_SYSV) != 0; 2136 + STp->sili = (options & MT_ST_SILI) != 0; 2151 2137 DEB( debugging = (options & MT_ST_DEBUGGING) != 0; 2152 2138 st_log_options(STp, STm, name); ) 2153 2139 } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { ··· 2180 2164 STp->immediate = value; 2181 2165 if ((options & MT_ST_SYSV) != 0) 2182 2166 STm->sysv = value; 2167 + if ((options & MT_ST_SILI) != 0) 2168 + STp->sili = value; 2183 2169 DEB( 2184 2170 if ((options & MT_ST_DEBUGGING) != 0) 2185 2171 debugging = value; ··· 3673 3655 STbuffer->frp_segs += 1; 3674 3656 got += b_size; 3675 3657 STbuffer->buffer_size = got; 3658 + if (STbuffer->cleared) 3659 + memset(page_address(STbuffer->frp[segs].page), 0, b_size); 3676 3660 segs++; 3677 3661 } 3678 3662 STbuffer->b_data = page_address(STbuffer->frp[0].page); 3679 3663 3680 3664 return 1; 3665 + } 3666 + 3667 + 3668 + /* Make sure that no data from previous user is in the internal buffer */ 3669 + static void clear_buffer(struct st_buffer * st_bp) 3670 + { 3671 + int i; 3672 + 3673 + for (i=0; i < st_bp->frp_segs; i++) 3674 + memset(page_address(st_bp->frp[i].page), 0, st_bp->frp[i].length); 3675 + st_bp->cleared = 1; 3681 3676 } 3682 3677 3683 3678 ··· 4018 3987 tpnt->two_fm = ST_TWO_FM; 4019 3988 tpnt->fast_mteom = ST_FAST_MTEOM; 4020 3989 tpnt->scsi2_logical = ST_SCSI2LOGICAL; 3990 + tpnt->sili = ST_SILI; 4021 3991 tpnt->immediate = ST_NOWAIT; 4022 3992 tpnt->default_drvbuffer = 0xff; /* No forced buffering */ 4023 3993 tpnt->partition = 0;
+3
drivers/scsi/st.h
··· 12 12 int midlevel_result; 13 13 struct scsi_sense_hdr sense_hdr; 14 14 int have_sense; 15 + int residual; 15 16 u64 uremainder64; 16 17 u8 flags; 17 18 u8 remainder_valid; ··· 35 34 struct st_buffer { 36 35 unsigned char dma; /* DMA-able buffer */ 37 36 unsigned char do_dio; /* direct i/o set up? */ 37 + unsigned char cleared; /* internal buffer cleared after open? */ 38 38 int buffer_size; 39 39 int buffer_blocks; 40 40 int buffer_bytes; ··· 124 122 unsigned char try_dio_now; /* try direct i/o before next close? */ 125 123 unsigned char c_algo; /* compression algorithm */ 126 124 unsigned char pos_unknown; /* after reset position unknown */ 125 + unsigned char sili; /* use SILI when reading in variable b mode */ 127 126 int tape_type; 128 127 int long_timeout; /* timeout for commands known to take long time */ 129 128
+5 -1
drivers/scsi/st_options.h
··· 3 3 4 4 Copyright 1995-2003 Kai Makisara. 5 5 6 - Last modified: Mon Apr 7 22:49:18 2003 by makisara 6 + Last modified: Thu Feb 21 21:47:07 2008 by kai.makisara 7 7 */ 8 8 9 9 #ifndef _ST_OPTIONS_H ··· 93 93 /* If ST_SYSV is non-zero, the tape behaves according to the SYS V semantics. 94 94 The default is BSD semantics. */ 95 95 #define ST_SYSV 0 96 + 97 + /* If ST_SILI is non-zero, the SILI bit is set when reading in variable block 98 + mode and the block size is determined using the residual returned by the HBA. */ 99 + #define ST_SILI 0 96 100 97 101 /* Time to wait for the drive to become ready if blocking open */ 98 102 #define ST_BLOCK_SECONDS 120
+1
include/linux/mtio.h
··· 192 192 #define MT_ST_SCSI2LOGICAL 0x800 193 193 #define MT_ST_SYSV 0x1000 194 194 #define MT_ST_NOWAIT 0x2000 195 + #define MT_ST_SILI 0x4000 195 196 196 197 /* The mode parameters to be controlled. Parameter chosen with bits 20-28 */ 197 198 #define MT_ST_CLEAR_DEFAULT 0xfffff