diff options
Diffstat (limited to 'drivers/scsi/st.c')
-rw-r--r-- | drivers/scsi/st.c | 89 |
1 files changed, 82 insertions, 7 deletions
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 0a52d9d2da2c..df83bea2c620 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c | |||
@@ -17,7 +17,7 @@ | |||
17 | Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support | 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 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | 23 | ||
@@ -183,6 +183,7 @@ static int modes_defined; | |||
183 | 183 | ||
184 | static struct st_buffer *new_tape_buffer(int, int, int); | 184 | static struct st_buffer *new_tape_buffer(int, int, int); |
185 | static int enlarge_buffer(struct st_buffer *, int, int); | 185 | static int enlarge_buffer(struct st_buffer *, int, int); |
186 | static void clear_buffer(struct st_buffer *); | ||
186 | static void normalize_buffer(struct st_buffer *); | 187 | static void normalize_buffer(struct st_buffer *); |
187 | static int append_to_buffer(const char __user *, struct st_buffer *, int); | 188 | static int append_to_buffer(const char __user *, struct st_buffer *, int); |
188 | static int from_buffer(struct st_buffer *, char __user *, int); | 189 | 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) | |||
442 | 443 | ||
443 | memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE); | 444 | memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE); |
444 | (STp->buffer)->cmdstat.midlevel_result = SRpnt->result = result; | 445 | (STp->buffer)->cmdstat.midlevel_result = SRpnt->result = result; |
446 | (STp->buffer)->cmdstat.residual = resid; | ||
445 | DEB( STp->write_pending = 0; ) | 447 | DEB( STp->write_pending = 0; ) |
446 | 448 | ||
447 | if (SRpnt->waiting) | 449 | if (SRpnt->waiting) |
@@ -626,7 +628,7 @@ static int cross_eof(struct scsi_tape * STp, int forward) | |||
626 | 628 | ||
627 | 629 | ||
628 | /* Flush the write buffer (never need to write if variable blocksize). */ | 630 | /* Flush the write buffer (never need to write if variable blocksize). */ |
629 | static int flush_write_buffer(struct scsi_tape * STp) | 631 | static int st_flush_write_buffer(struct scsi_tape * STp) |
630 | { | 632 | { |
631 | int offset, transfer, blks; | 633 | int offset, transfer, blks; |
632 | int result; | 634 | int result; |
@@ -717,7 +719,7 @@ static int flush_buffer(struct scsi_tape *STp, int seek_next) | |||
717 | return 0; | 719 | return 0; |
718 | STps = &(STp->ps[STp->partition]); | 720 | STps = &(STp->ps[STp->partition]); |
719 | if (STps->rw == ST_WRITING) /* Writing */ | 721 | if (STps->rw == ST_WRITING) /* Writing */ |
720 | return flush_write_buffer(STp); | 722 | return st_flush_write_buffer(STp); |
721 | 723 | ||
722 | if (STp->block_size == 0) | 724 | if (STp->block_size == 0) |
723 | return 0; | 725 | return 0; |
@@ -1159,6 +1161,7 @@ static int st_open(struct inode *inode, struct file *filp) | |||
1159 | goto err_out; | 1161 | goto err_out; |
1160 | } | 1162 | } |
1161 | 1163 | ||
1164 | (STp->buffer)->cleared = 0; | ||
1162 | (STp->buffer)->writing = 0; | 1165 | (STp->buffer)->writing = 0; |
1163 | (STp->buffer)->syscall_result = 0; | 1166 | (STp->buffer)->syscall_result = 0; |
1164 | 1167 | ||
@@ -1211,7 +1214,7 @@ static int st_flush(struct file *filp, fl_owner_t id) | |||
1211 | return 0; | 1214 | return 0; |
1212 | 1215 | ||
1213 | if (STps->rw == ST_WRITING && !STp->pos_unknown) { | 1216 | if (STps->rw == ST_WRITING && !STp->pos_unknown) { |
1214 | result = flush_write_buffer(STp); | 1217 | result = st_flush_write_buffer(STp); |
1215 | if (result != 0 && result != (-ENOSPC)) | 1218 | if (result != 0 && result != (-ENOSPC)) |
1216 | goto out; | 1219 | goto out; |
1217 | } | 1220 | } |
@@ -1432,8 +1435,14 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf, | |||
1432 | if (STp->block_size) | 1435 | if (STp->block_size) |
1433 | bufsize = STp->block_size > st_fixed_buffer_size ? | 1436 | bufsize = STp->block_size > st_fixed_buffer_size ? |
1434 | STp->block_size : st_fixed_buffer_size; | 1437 | STp->block_size : st_fixed_buffer_size; |
1435 | else | 1438 | else { |
1436 | bufsize = count; | 1439 | bufsize = count; |
1440 | /* Make sure that data from previous user is not leaked even if | ||
1441 | HBA does not return correct residual */ | ||
1442 | if (is_read && STp->sili && !STbp->cleared) | ||
1443 | clear_buffer(STbp); | ||
1444 | } | ||
1445 | |||
1437 | if (bufsize > STbp->buffer_size && | 1446 | if (bufsize > STbp->buffer_size && |
1438 | !enlarge_buffer(STbp, bufsize, STp->restr_dma)) { | 1447 | !enlarge_buffer(STbp, bufsize, STp->restr_dma)) { |
1439 | printk(KERN_WARNING "%s: Can't allocate %d byte tape buffer.\n", | 1448 | 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, | |||
1783 | memset(cmd, 0, MAX_COMMAND_SIZE); | 1792 | memset(cmd, 0, MAX_COMMAND_SIZE); |
1784 | cmd[0] = READ_6; | 1793 | cmd[0] = READ_6; |
1785 | cmd[1] = (STp->block_size != 0); | 1794 | cmd[1] = (STp->block_size != 0); |
1795 | if (!cmd[1] && STp->sili) | ||
1796 | cmd[1] |= 2; | ||
1786 | cmd[2] = blks >> 16; | 1797 | cmd[2] = blks >> 16; |
1787 | cmd[3] = blks >> 8; | 1798 | cmd[3] = blks >> 8; |
1788 | cmd[4] = blks; | 1799 | cmd[4] = blks; |
@@ -1911,8 +1922,11 @@ static long read_tape(struct scsi_tape *STp, long count, | |||
1911 | 1922 | ||
1912 | } | 1923 | } |
1913 | /* End of error handling */ | 1924 | /* End of error handling */ |
1914 | else /* Read successful */ | 1925 | else { /* Read successful */ |
1915 | STbp->buffer_bytes = bytes; | 1926 | STbp->buffer_bytes = bytes; |
1927 | if (STp->sili) /* In fixed block mode residual is always zero here */ | ||
1928 | STbp->buffer_bytes -= STp->buffer->cmdstat.residual; | ||
1929 | } | ||
1916 | 1930 | ||
1917 | if (STps->drv_block >= 0) { | 1931 | if (STps->drv_block >= 0) { |
1918 | if (STp->block_size == 0) | 1932 | if (STp->block_size == 0) |
@@ -2090,7 +2104,8 @@ static void st_log_options(struct scsi_tape * STp, struct st_modedef * STm, char | |||
2090 | name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, | 2104 | name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, |
2091 | STp->scsi2_logical); | 2105 | STp->scsi2_logical); |
2092 | printk(KERN_INFO | 2106 | printk(KERN_INFO |
2093 | "%s: sysv: %d nowait: %d\n", name, STm->sysv, STp->immediate); | 2107 | "%s: sysv: %d nowait: %d sili: %d\n", name, STm->sysv, STp->immediate, |
2108 | STp->sili); | ||
2094 | printk(KERN_INFO "%s: debugging: %d\n", | 2109 | printk(KERN_INFO "%s: debugging: %d\n", |
2095 | name, debugging); | 2110 | name, debugging); |
2096 | } | 2111 | } |
@@ -2133,6 +2148,7 @@ static int st_set_options(struct scsi_tape *STp, long options) | |||
2133 | STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; | 2148 | STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; |
2134 | STp->immediate = (options & MT_ST_NOWAIT) != 0; | 2149 | STp->immediate = (options & MT_ST_NOWAIT) != 0; |
2135 | STm->sysv = (options & MT_ST_SYSV) != 0; | 2150 | STm->sysv = (options & MT_ST_SYSV) != 0; |
2151 | STp->sili = (options & MT_ST_SILI) != 0; | ||
2136 | DEB( debugging = (options & MT_ST_DEBUGGING) != 0; | 2152 | DEB( debugging = (options & MT_ST_DEBUGGING) != 0; |
2137 | st_log_options(STp, STm, name); ) | 2153 | st_log_options(STp, STm, name); ) |
2138 | } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { | 2154 | } 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) | |||
2164 | STp->immediate = value; | 2180 | STp->immediate = value; |
2165 | if ((options & MT_ST_SYSV) != 0) | 2181 | if ((options & MT_ST_SYSV) != 0) |
2166 | STm->sysv = value; | 2182 | STm->sysv = value; |
2183 | if ((options & MT_ST_SILI) != 0) | ||
2184 | STp->sili = value; | ||
2167 | DEB( | 2185 | DEB( |
2168 | if ((options & MT_ST_DEBUGGING) != 0) | 2186 | if ((options & MT_ST_DEBUGGING) != 0) |
2169 | debugging = value; | 2187 | debugging = value; |
@@ -3655,6 +3673,8 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm | |||
3655 | STbuffer->frp_segs += 1; | 3673 | STbuffer->frp_segs += 1; |
3656 | got += b_size; | 3674 | got += b_size; |
3657 | STbuffer->buffer_size = got; | 3675 | STbuffer->buffer_size = got; |
3676 | if (STbuffer->cleared) | ||
3677 | memset(page_address(STbuffer->frp[segs].page), 0, b_size); | ||
3658 | segs++; | 3678 | segs++; |
3659 | } | 3679 | } |
3660 | STbuffer->b_data = page_address(STbuffer->frp[0].page); | 3680 | 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 | |||
3663 | } | 3683 | } |
3664 | 3684 | ||
3665 | 3685 | ||
3686 | /* Make sure that no data from previous user is in the internal buffer */ | ||
3687 | static void clear_buffer(struct st_buffer * st_bp) | ||
3688 | { | ||
3689 | int i; | ||
3690 | |||
3691 | for (i=0; i < st_bp->frp_segs; i++) | ||
3692 | memset(page_address(st_bp->frp[i].page), 0, st_bp->frp[i].length); | ||
3693 | st_bp->cleared = 1; | ||
3694 | } | ||
3695 | |||
3696 | |||
3666 | /* Release the extra buffer */ | 3697 | /* Release the extra buffer */ |
3667 | static void normalize_buffer(struct st_buffer * STbuffer) | 3698 | static void normalize_buffer(struct st_buffer * STbuffer) |
3668 | { | 3699 | { |
@@ -3987,6 +4018,7 @@ static int st_probe(struct device *dev) | |||
3987 | tpnt->two_fm = ST_TWO_FM; | 4018 | tpnt->two_fm = ST_TWO_FM; |
3988 | tpnt->fast_mteom = ST_FAST_MTEOM; | 4019 | tpnt->fast_mteom = ST_FAST_MTEOM; |
3989 | tpnt->scsi2_logical = ST_SCSI2LOGICAL; | 4020 | tpnt->scsi2_logical = ST_SCSI2LOGICAL; |
4021 | tpnt->sili = ST_SILI; | ||
3990 | tpnt->immediate = ST_NOWAIT; | 4022 | tpnt->immediate = ST_NOWAIT; |
3991 | tpnt->default_drvbuffer = 0xff; /* No forced buffering */ | 4023 | tpnt->default_drvbuffer = 0xff; /* No forced buffering */ |
3992 | tpnt->partition = 0; | 4024 | tpnt->partition = 0; |
@@ -4333,6 +4365,46 @@ static ssize_t st_defcompression_show(struct class_device *class_dev, char *buf) | |||
4333 | 4365 | ||
4334 | CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL); | 4366 | CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL); |
4335 | 4367 | ||
4368 | static ssize_t st_options_show(struct class_device *class_dev, char *buf) | ||
4369 | { | ||
4370 | struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev); | ||
4371 | struct scsi_tape *STp; | ||
4372 | int i, j, options; | ||
4373 | ssize_t l = 0; | ||
4374 | |||
4375 | for (i=0; i < st_dev_max; i++) { | ||
4376 | for (j=0; j < ST_NBR_MODES; j++) | ||
4377 | if (&scsi_tapes[i]->modes[j] == STm) | ||
4378 | break; | ||
4379 | if (j < ST_NBR_MODES) | ||
4380 | break; | ||
4381 | } | ||
4382 | if (i == st_dev_max) | ||
4383 | return 0; /* should never happen */ | ||
4384 | |||
4385 | STp = scsi_tapes[i]; | ||
4386 | |||
4387 | options = STm->do_buffer_writes ? MT_ST_BUFFER_WRITES : 0; | ||
4388 | options |= STm->do_async_writes ? MT_ST_ASYNC_WRITES : 0; | ||
4389 | options |= STm->do_read_ahead ? MT_ST_READ_AHEAD : 0; | ||
4390 | DEB( options |= debugging ? MT_ST_DEBUGGING : 0 ); | ||
4391 | options |= STp->two_fm ? MT_ST_TWO_FM : 0; | ||
4392 | options |= STp->fast_mteom ? MT_ST_FAST_MTEOM : 0; | ||
4393 | options |= STm->defaults_for_writes ? MT_ST_DEF_WRITES : 0; | ||
4394 | options |= STp->can_bsr ? MT_ST_CAN_BSR : 0; | ||
4395 | options |= STp->omit_blklims ? MT_ST_NO_BLKLIMS : 0; | ||
4396 | options |= STp->can_partitions ? MT_ST_CAN_PARTITIONS : 0; | ||
4397 | options |= STp->scsi2_logical ? MT_ST_SCSI2LOGICAL : 0; | ||
4398 | options |= STm->sysv ? MT_ST_SYSV : 0; | ||
4399 | options |= STp->immediate ? MT_ST_NOWAIT : 0; | ||
4400 | options |= STp->sili ? MT_ST_SILI : 0; | ||
4401 | |||
4402 | l = snprintf(buf, PAGE_SIZE, "0x%08x\n", options); | ||
4403 | return l; | ||
4404 | } | ||
4405 | |||
4406 | CLASS_DEVICE_ATTR(options, S_IRUGO, st_options_show, NULL); | ||
4407 | |||
4336 | static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) | 4408 | static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) |
4337 | { | 4409 | { |
4338 | int i, rew, error; | 4410 | int i, rew, error; |
@@ -4370,6 +4442,9 @@ static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) | |||
4370 | error = class_device_create_file(st_class_member, | 4442 | error = class_device_create_file(st_class_member, |
4371 | &class_device_attr_default_compression); | 4443 | &class_device_attr_default_compression); |
4372 | if (error) goto out; | 4444 | if (error) goto out; |
4445 | error = class_device_create_file(st_class_member, | ||
4446 | &class_device_attr_options); | ||
4447 | if (error) goto out; | ||
4373 | 4448 | ||
4374 | if (mode == 0 && rew == 0) { | 4449 | if (mode == 0 && rew == 0) { |
4375 | error = sysfs_create_link(&STp->device->sdev_gendev.kobj, | 4450 | error = sysfs_create_link(&STp->device->sdev_gendev.kobj, |