summaryrefslogtreecommitdiff
path: root/drivers/scsi/st.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/st.c')
-rw-r--r--drivers/scsi/st.c1632
1 files changed, 1057 insertions, 575 deletions
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 2a32036a9404..168f25e4aaa3 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -1,6 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
- file Documentation/scsi/st.txt for more information.
+ file Documentation/scsi/st.rst for more information.
History:
Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
@@ -9,7 +10,7 @@
Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
Michael Schaefer, J"org Weule, and Eric Youngdale.
- Copyright 1992 - 2010 Kai Makisara
+ Copyright 1992 - 2016 Kai Makisara
email Kai.Makisara@kolumbus.fi
Some small formal changes - aeb, 950809
@@ -17,19 +18,21 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
-static const char *verstr = "20101219";
+static const char *verstr = "20160209";
#include <linux/module.h>
+#include <linux/compat.h>
#include <linux/fs.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/mtio.h>
+#include <linux/major.h>
#include <linux/cdrom.h>
#include <linux/ioctl.h>
#include <linux/fcntl.h>
@@ -41,8 +44,9 @@ static const char *verstr = "20101219";
#include <linux/delay.h>
#include <linux/mutex.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/dma.h>
+#include <linux/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_dbg.h>
@@ -56,13 +60,14 @@ static const char *verstr = "20101219";
/* The driver prints some debugging information on the console if DEBUG
is defined and non-zero. */
-#define DEBUG 0
+#define DEBUG 1
+#define NO_DEBUG 0
+#define ST_DEB_MSG KERN_NOTICE
#if DEBUG
/* The message level for the debug messages is currently set to KERN_NOTICE
so that people can easily see the messages. Later when the debugging messages
in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
-#define ST_DEB_MSG KERN_NOTICE
#define DEB(a) a
#define DEBC(a) if (debugging) { a ; }
#else
@@ -80,9 +85,11 @@ static int max_sg_segs;
static int try_direct_io = TRY_DIRECT_IO;
static int try_rdio = 1;
static int try_wdio = 1;
+static int debug_flag;
-static struct class st_sysfs_class;
-static struct device_attribute st_dev_attrs[];
+static const struct class st_sysfs_class;
+static const struct attribute_group *st_dev_groups[];
+static const struct attribute_group *st_drv_groups[];
MODULE_AUTHOR("Kai Makisara");
MODULE_DESCRIPTION("SCSI tape (st) driver");
@@ -100,6 +107,9 @@ module_param_named(max_sg_segs, max_sg_segs, int, 0);
MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (256)");
module_param_named(try_direct_io, try_direct_io, int, 0);
MODULE_PARM_DESC(try_direct_io, "Try direct I/O between user buffer and tape drive (1)");
+module_param_named(debug_flag, debug_flag, int, 0);
+MODULE_PARM_DESC(debug_flag, "Enable DEBUG, same as setting debugging=1");
+
/* Extra parameters for testing */
module_param_named(try_rdio, try_rdio, int, 0);
@@ -124,6 +134,9 @@ static struct st_dev_parm {
},
{
"try_direct_io", &try_direct_io
+ },
+ {
+ "debug_flag", &debug_flag
}
};
#endif
@@ -150,9 +163,11 @@ static const char *st_formats[] = {
static int debugging = DEBUG;
+/* Setting these non-zero may risk recognizing resets */
#define MAX_RETRIES 0
#define MAX_WRITE_RETRIES 0
#define MAX_READY_RETRIES 0
+
#define NO_TAPE NOT_READY
#define ST_TIMEOUT (900 * HZ)
@@ -160,7 +175,7 @@ static int debugging = DEBUG;
/* Remove mode bits and auto-rewind bit (7) */
#define TAPE_NR(x) ( ((iminor(x) & ~255) >> (ST_NBR_MODE_BITS + 1)) | \
- (iminor(x) & ~(-1 << ST_MODE_SHIFT)) )
+ (iminor(x) & ((1 << ST_MODE_SHIFT)-1)))
#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
/* Construct the minor number from the device (d), mode (m), and non-rewind (n) data */
@@ -176,7 +191,7 @@ static int st_max_sg_segs = ST_MAX_SG;
static int modes_defined;
-static int enlarge_buffer(struct st_buffer *, int, int);
+static int enlarge_buffer(struct st_buffer *, 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);
@@ -190,15 +205,12 @@ static int sgl_unmap_user_pages(struct st_buffer *, const unsigned int, int);
static int st_probe(struct device *);
static int st_remove(struct device *);
-static int do_create_sysfs_files(void);
-static void do_remove_sysfs_files(void);
-
static struct scsi_driver st_template = {
- .owner = THIS_MODULE,
.gendrv = {
.name = "st",
.probe = st_probe,
.remove = st_remove,
+ .groups = st_drv_groups,
},
};
@@ -220,7 +232,6 @@ static DEFINE_IDR(st_index_idr);
-#include "osst_detect.h"
#ifndef SIGS_FROM_OSST
#define SIGS_FROM_OSST \
{"OnStream", "SC-", "", "osst"}, \
@@ -300,11 +311,14 @@ static char * st_incompatible(struct scsi_device* SDp)
}
-static inline char *tape_name(struct scsi_tape *tape)
-{
- return tape->disk->disk_name;
-}
-
+#define st_printk(prefix, t, fmt, a...) \
+ sdev_prefix_printk(prefix, (t)->device, (t)->name, fmt, ##a)
+#ifdef DEBUG
+#define DEBC_printk(t, fmt, a...) \
+ if (debugging) { st_printk(ST_DEB_MSG, t, fmt, ##a ); }
+#else
+#define DEBC_printk(t, fmt, a...)
+#endif
static void st_analyze_sense(struct st_request *SRpnt, struct st_cmdstatus *s)
{
@@ -322,12 +336,14 @@ static void st_analyze_sense(struct st_request *SRpnt, struct st_cmdstatus *s)
switch (sense[0] & 0x7f) {
case 0x71:
s->deferred = 1;
+ fallthrough;
case 0x70:
s->fixed_format = 1;
s->flags = sense[2] & 0xe0;
break;
case 0x73:
s->deferred = 1;
+ fallthrough;
case 0x72:
s->fixed_format = 0;
ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
@@ -343,10 +359,18 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
{
int result = SRpnt->result;
u8 scode;
+ unsigned int ctr;
DEB(const char *stp;)
- char *name = tape_name(STp);
+ char *name = STp->name;
struct st_cmdstatus *cmdstatp;
+ ctr = scsi_get_ua_por_ctr(STp->device);
+ if (ctr != STp->por_ctr) {
+ STp->por_ctr = ctr;
+ STp->pos_unknown = 1; /* ASC => power on / reset */
+ st_printk(KERN_WARNING, STp, "Power on/reset recognized.");
+ }
+
if (!result)
return 0;
@@ -358,21 +382,21 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
else
scode = 0;
- DEB(
- if (debugging) {
- printk(ST_DEB_MSG "%s: Error: %x, cmd: %x %x %x %x %x %x\n",
- name, result,
- SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
- SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
+ DEB(
+ if (debugging) {
+ st_printk(ST_DEB_MSG, STp,
+ "Error: %x, cmd: %x %x %x %x %x %x\n", result,
+ SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
+ SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
if (cmdstatp->have_sense)
- __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
+ __scsi_print_sense(STp->device, name,
+ SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
} ) /* end DEB */
if (!debugging) { /* Abnormal conditions for tape */
if (!cmdstatp->have_sense)
- printk(KERN_WARNING
- "%s: Error %x (driver bt 0x%x, host bt 0x%x).\n",
- name, result, driver_byte(result),
- host_byte(result));
+ st_printk(KERN_WARNING, STp,
+ "Error %x (driver bt 0, host bt 0x%x).\n",
+ result, host_byte(result));
else if (cmdstatp->have_sense &&
scode != NO_SENSE &&
scode != RECOVERED_ERROR &&
@@ -382,7 +406,8 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
SRpnt->cmd[0] != MODE_SENSE &&
SRpnt->cmd[0] != TEST_UNIT_READY) {
- __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
+ __scsi_print_sense(STp->device, name,
+ SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
}
}
@@ -398,8 +423,11 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
if (cmdstatp->have_sense &&
cmdstatp->sense_hdr.asc == 0 && cmdstatp->sense_hdr.ascq == 0x17)
STp->cleaning_req = 1; /* ASC and ASCQ => cleaning requested */
-
- STp->pos_unknown |= STp->device->was_reset;
+ if (cmdstatp->have_sense && scode == UNIT_ATTENTION &&
+ cmdstatp->sense_hdr.asc == 0x29 && !STp->pos_unknown) {
+ STp->pos_unknown = 1; /* ASC => power on / reset */
+ st_printk(KERN_WARNING, STp, "Power on/reset recognized.");
+ }
if (cmdstatp->have_sense &&
scode == RECOVERED_ERROR
@@ -411,7 +439,7 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
STp->recover_count++;
STp->recover_reg++;
- DEB(
+ DEB(
if (debugging) {
if (SRpnt->cmd[0] == READ_6)
stp = "read";
@@ -419,8 +447,9 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
stp = "write";
else
stp = "ioctl";
- printk(ST_DEB_MSG "%s: Recovered %s error (%d).\n", name, stp,
- STp->recover_count);
+ st_printk(ST_DEB_MSG, STp,
+ "Recovered %s error (%d).\n",
+ stp, STp->recover_count);
} ) /* end DEB */
if (cmdstatp->flags == 0)
@@ -437,8 +466,8 @@ static struct st_request *st_allocate_request(struct scsi_tape *stp)
if (streq)
streq->stp = stp;
else {
- DEBC(printk(KERN_ERR "%s: Can't get SCSI request.\n",
- tape_name(stp)););
+ st_printk(KERN_ERR, stp,
+ "Can't get SCSI request.\n");
if (signal_pending(current))
stp->buffer->syscall_result = -EINTR;
else
@@ -453,21 +482,70 @@ static void st_release_request(struct st_request *streq)
kfree(streq);
}
-static void st_scsi_execute_end(struct request *req, int uptodate)
+static void st_do_stats(struct scsi_tape *STp, struct request *req)
+{
+ struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req);
+ ktime_t now;
+
+ now = ktime_get();
+ if (scmd->cmnd[0] == WRITE_6) {
+ now = ktime_sub(now, STp->stats->write_time);
+ atomic64_add(ktime_to_ns(now), &STp->stats->tot_write_time);
+ atomic64_add(ktime_to_ns(now), &STp->stats->tot_io_time);
+ atomic64_inc(&STp->stats->write_cnt);
+ if (scmd->result) {
+ atomic64_add(atomic_read(&STp->stats->last_write_size)
+ - STp->buffer->cmdstat.residual,
+ &STp->stats->write_byte_cnt);
+ if (STp->buffer->cmdstat.residual > 0)
+ atomic64_inc(&STp->stats->resid_cnt);
+ } else
+ atomic64_add(atomic_read(&STp->stats->last_write_size),
+ &STp->stats->write_byte_cnt);
+ } else if (scmd->cmnd[0] == READ_6) {
+ now = ktime_sub(now, STp->stats->read_time);
+ atomic64_add(ktime_to_ns(now), &STp->stats->tot_read_time);
+ atomic64_add(ktime_to_ns(now), &STp->stats->tot_io_time);
+ atomic64_inc(&STp->stats->read_cnt);
+ if (scmd->result) {
+ atomic64_add(atomic_read(&STp->stats->last_read_size)
+ - STp->buffer->cmdstat.residual,
+ &STp->stats->read_byte_cnt);
+ if (STp->buffer->cmdstat.residual > 0)
+ atomic64_inc(&STp->stats->resid_cnt);
+ } else
+ atomic64_add(atomic_read(&STp->stats->last_read_size),
+ &STp->stats->read_byte_cnt);
+ } else {
+ now = ktime_sub(now, STp->stats->other_time);
+ atomic64_add(ktime_to_ns(now), &STp->stats->tot_io_time);
+ atomic64_inc(&STp->stats->other_cnt);
+ }
+ atomic64_dec(&STp->stats->in_flight);
+}
+
+static enum rq_end_io_ret st_scsi_execute_end(struct request *req,
+ blk_status_t status)
{
+ struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req);
struct st_request *SRpnt = req->end_io_data;
struct scsi_tape *STp = SRpnt->stp;
struct bio *tmp;
- STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors;
- STp->buffer->cmdstat.residual = req->resid_len;
+ STp->buffer->cmdstat.midlevel_result = SRpnt->result = scmd->result;
+ STp->buffer->cmdstat.residual = scmd->resid_len;
+
+ st_do_stats(STp, req);
tmp = SRpnt->bio;
+ if (scmd->sense_len)
+ memcpy(SRpnt->sense, scmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
if (SRpnt->waiting)
complete(SRpnt->waiting);
blk_rq_unmap_user(tmp);
- __blk_put_request(req->q, req);
+ blk_mq_free_request(req);
+ return RQ_END_IO_NONE;
}
static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
@@ -477,15 +555,16 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
struct request *req;
struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
int err = 0;
- int write = (data_direction == DMA_TO_DEVICE);
-
- req = blk_get_request(SRpnt->stp->device->request_queue, write,
- GFP_KERNEL);
- if (!req)
- return DRIVER_ERROR << 24;
+ struct scsi_tape *STp = SRpnt->stp;
+ struct scsi_cmnd *scmd;
- req->cmd_type = REQ_TYPE_BLOCK_PC;
- req->cmd_flags |= REQ_QUIET;
+ req = scsi_alloc_request(SRpnt->stp->device->request_queue,
+ data_direction == DMA_TO_DEVICE ?
+ REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+ scmd = blk_mq_rq_to_pdu(req);
+ req->rq_flags |= RQF_QUIET;
mdata->null_mapped = 1;
@@ -493,22 +572,31 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen,
GFP_KERNEL);
if (err) {
- blk_put_request(req);
- return DRIVER_ERROR << 24;
+ blk_mq_free_request(req);
+ return err;
}
}
+ atomic64_inc(&STp->stats->in_flight);
+ if (cmd[0] == WRITE_6) {
+ atomic_set(&STp->stats->last_write_size, bufflen);
+ STp->stats->write_time = ktime_get();
+ } else if (cmd[0] == READ_6) {
+ atomic_set(&STp->stats->last_read_size, bufflen);
+ STp->stats->read_time = ktime_get();
+ } else {
+ STp->stats->other_time = ktime_get();
+ }
+
SRpnt->bio = req->bio;
- req->cmd_len = COMMAND_SIZE(cmd[0]);
- memset(req->cmd, 0, BLK_MAX_CDB);
- memcpy(req->cmd, cmd, req->cmd_len);
- req->sense = SRpnt->sense;
- req->sense_len = 0;
+ scmd->cmd_len = COMMAND_SIZE(cmd[0]);
+ memcpy(scmd->cmnd, cmd, scmd->cmd_len);
req->timeout = timeout;
- req->retries = retries;
+ scmd->allowed = retries;
+ req->end_io = st_scsi_execute_end;
req->end_io_data = SRpnt;
- blk_execute_rq_nowait(req->q, NULL, req, 1, st_scsi_execute_end);
+ blk_execute_rq_nowait(req, true);
return 0;
}
@@ -525,8 +613,8 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd
/* if async, make sure there's no command outstanding */
if (!do_wait && ((STp->buffer)->last_SRpnt)) {
- printk(KERN_ERR "%s: Async command already active.\n",
- tape_name(STp));
+ st_printk(KERN_ERR, STp,
+ "Async command already active.\n");
if (signal_pending(current))
(STp->buffer)->syscall_result = (-EINTR);
else
@@ -597,12 +685,12 @@ static int write_behind_check(struct scsi_tape * STp)
if (!STbuffer->writing)
return 0;
- DEB(
+ DEB(
if (STp->write_pending)
STp->nbr_waits++;
else
STp->nbr_finished++;
- ) /* end DEB */
+ ) /* end DEB */
wait_for_completion(&(STp->wait));
SRpnt = STbuffer->last_SRpnt;
@@ -639,8 +727,9 @@ static int write_behind_check(struct scsi_tape * STp)
STbuffer->writing = 0;
DEB(if (debugging && retval)
- printk(ST_DEB_MSG "%s: Async write error %x, return value %d.\n",
- tape_name(STp), STbuffer->cmdstat.midlevel_result, retval);) /* end DEB */
+ st_printk(ST_DEB_MSG, STp,
+ "Async write error %x, return value %d.\n",
+ STbuffer->cmdstat.midlevel_result, retval);) /* end DEB */
return retval;
}
@@ -662,8 +751,8 @@ static int cross_eof(struct scsi_tape * STp, int forward)
cmd[2] = cmd[3] = cmd[4] = 0xff; /* -1 filemarks */
cmd[5] = 0;
- DEBC(printk(ST_DEB_MSG "%s: Stepping over filemark %s.\n",
- tape_name(STp), forward ? "forward" : "backward"));
+ DEBC_printk(STp, "Stepping over filemark %s.\n",
+ forward ? "forward" : "backward");
SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
STp->device->request_queue->rq_timeout,
@@ -675,8 +764,9 @@ static int cross_eof(struct scsi_tape * STp, int forward)
SRpnt = NULL;
if ((STp->buffer)->cmdstat.midlevel_result != 0)
- printk(KERN_ERR "%s: Stepping over filemark %s failed.\n",
- tape_name(STp), forward ? "forward" : "backward");
+ st_printk(KERN_ERR, STp,
+ "Stepping over filemark %s failed.\n",
+ forward ? "forward" : "backward");
return (STp->buffer)->syscall_result;
}
@@ -699,8 +789,7 @@ static int st_flush_write_buffer(struct scsi_tape * STp)
if (STp->dirty == 1) {
transfer = STp->buffer->buffer_bytes;
- DEBC(printk(ST_DEB_MSG "%s: Flushing %d bytes.\n",
- tape_name(STp), transfer));
+ DEBC_printk(STp, "Flushing %d bytes.\n", transfer);
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = WRITE_6;
@@ -732,8 +821,7 @@ static int st_flush_write_buffer(struct scsi_tape * STp)
STps->drv_block += blks;
result = (-ENOSPC);
} else {
- printk(KERN_ERR "%s: Error on flush.\n",
- tape_name(STp));
+ st_printk(KERN_ERR, STp, "Error on flush.\n");
STps->drv_block = (-1);
result = (-EIO);
}
@@ -755,10 +843,10 @@ static int st_flush_write_buffer(struct scsi_tape * STp)
static int flush_buffer(struct scsi_tape *STp, int seek_next)
{
int backspace, result;
- struct st_buffer *STbuffer;
struct st_partstat *STps;
- STbuffer = STp->buffer;
+ if (STp->ready != ST_READY)
+ return 0;
/*
* If there was a bus reset, block further access
@@ -767,8 +855,6 @@ static int flush_buffer(struct scsi_tape *STp, int seek_next)
if (STp->pos_unknown)
return (-EIO);
- if (STp->ready != ST_READY)
- return 0;
STps = &(STp->ps[STp->partition]);
if (STps->rw == ST_WRITING) /* Writing */
return st_flush_write_buffer(STp);
@@ -811,7 +897,6 @@ static int set_mode_densblk(struct scsi_tape * STp, struct st_modedef * STm)
{
int set_it = 0;
unsigned long arg;
- char *name = tape_name(STp);
if (!STp->density_changed &&
STm->default_density >= 0 &&
@@ -830,9 +915,10 @@ static int set_mode_densblk(struct scsi_tape * STp, struct st_modedef * STm)
arg |= STp->block_size;
if (set_it &&
st_int_ioctl(STp, SET_DENS_AND_BLK, arg)) {
- printk(KERN_WARNING
- "%s: Can't set default block size to %d bytes and density %x.\n",
- name, STm->default_blksize, STm->default_density);
+ st_printk(KERN_WARNING, STp,
+ "Can't set default block size to %d bytes "
+ "and density %x.\n",
+ STm->default_blksize, STm->default_density);
if (modes_defined)
return (-EINVAL);
}
@@ -843,20 +929,16 @@ static int set_mode_densblk(struct scsi_tape * STp, struct st_modedef * STm)
/* Lock or unlock the drive door. Don't use when st_request allocated. */
static int do_door_lock(struct scsi_tape * STp, int do_lock)
{
- int retval, cmd;
- DEB(char *name = tape_name(STp);)
+ int retval;
+ DEBC_printk(STp, "%socking drive door.\n", do_lock ? "L" : "Unl");
- cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
- DEBC(printk(ST_DEB_MSG "%s: %socking drive door.\n", name,
- do_lock ? "L" : "Unl"));
- retval = scsi_ioctl(STp->device, cmd, NULL);
- if (!retval) {
+ retval = scsi_set_medium_removal(STp->device,
+ do_lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
+ if (!retval)
STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
- }
- else {
+ else
STp->door_locked = ST_LOCK_FAILS;
- }
return retval;
}
@@ -881,7 +963,6 @@ static void reset_state(struct scsi_tape *STp)
STp->partition = find_partition(STp);
if (STp->partition < 0)
STp->partition = 0;
- STp->new_partition = STp->partition;
}
}
@@ -898,6 +979,7 @@ static int test_ready(struct scsi_tape *STp, int do_wait)
{
int attentions, waits, max_wait, scode;
int retval = CHKRES_READY, new_session = 0;
+ unsigned int ctr;
unsigned char cmd[MAX_COMMAND_SIZE];
struct st_request *SRpnt = NULL;
struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
@@ -920,7 +1002,10 @@ static int test_ready(struct scsi_tape *STp, int do_wait)
scode = cmdstatp->sense_hdr.sense_key;
if (scode == UNIT_ATTENTION) { /* New media? */
- new_session = 1;
+ if (cmdstatp->sense_hdr.asc == 0x28) { /* New media */
+ new_session = 1;
+ DEBC_printk(STp, "New tape session.");
+ }
if (attentions < MAX_ATTENTIONS) {
attentions++;
continue;
@@ -951,11 +1036,23 @@ static int test_ready(struct scsi_tape *STp, int do_wait)
}
}
+ ctr = scsi_get_ua_new_media_ctr(STp->device);
+ if (ctr != STp->new_media_ctr) {
+ STp->new_media_ctr = ctr;
+ new_session = 1;
+ DEBC_printk(STp, "New tape session.");
+ }
+
retval = (STp->buffer)->syscall_result;
if (!retval)
retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY;
break;
}
+ if (STp->first_tur) {
+ /* Don't set pos_unknown right after device recognition */
+ STp->pos_unknown = 0;
+ STp->first_tur = 0;
+ }
if (SRpnt != NULL)
st_release_request(SRpnt);
@@ -976,15 +1073,14 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
struct st_request *SRpnt = NULL;
struct st_modedef *STm;
struct st_partstat *STps;
- char *name = tape_name(STp);
struct inode *inode = file_inode(filp);
int mode = TAPE_MODE(inode);
STp->ready = ST_READY;
if (mode != STp->current_mode) {
- DEBC(printk(ST_DEB_MSG "%s: Mode change from %d to %d.\n",
- name, STp->current_mode, mode));
+ DEBC_printk(STp, "Mode change from %d to %d.\n",
+ STp->current_mode, mode);
new_session = 1;
STp->current_mode = mode;
}
@@ -1055,13 +1151,12 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
STp->min_block = ((STp->buffer)->b_data[4] << 8) |
(STp->buffer)->b_data[5];
if ( DEB( debugging || ) !STp->inited)
- printk(KERN_INFO
- "%s: Block limits %d - %d bytes.\n", name,
- STp->min_block, STp->max_block);
+ st_printk(KERN_INFO, STp,
+ "Block limits %d - %d bytes.\n",
+ STp->min_block, STp->max_block);
} else {
STp->min_block = STp->max_block = (-1);
- DEBC(printk(ST_DEB_MSG "%s: Can't read block limits.\n",
- name));
+ DEBC_printk(STp, "Can't read block limits.\n");
}
}
@@ -1078,56 +1173,58 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
}
if ((STp->buffer)->syscall_result != 0) {
- DEBC(printk(ST_DEB_MSG "%s: No Mode Sense.\n", name));
+ DEBC_printk(STp, "No Mode Sense.\n");
STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */
(STp->buffer)->syscall_result = 0; /* Prevent error propagation */
STp->drv_write_prot = 0;
} else {
- DEBC(printk(ST_DEB_MSG
- "%s: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n",
- name,
- (STp->buffer)->b_data[0], (STp->buffer)->b_data[1],
- (STp->buffer)->b_data[2], (STp->buffer)->b_data[3]));
+ DEBC_printk(STp,"Mode sense. Length %d, "
+ "medium %x, WBS %x, BLL %d\n",
+ (STp->buffer)->b_data[0],
+ (STp->buffer)->b_data[1],
+ (STp->buffer)->b_data[2],
+ (STp->buffer)->b_data[3]);
if ((STp->buffer)->b_data[3] >= 8) {
STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7;
STp->density = (STp->buffer)->b_data[4];
STp->block_size = (STp->buffer)->b_data[9] * 65536 +
(STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11];
- DEBC(printk(ST_DEB_MSG
- "%s: Density %x, tape length: %x, drv buffer: %d\n",
- name, STp->density, (STp->buffer)->b_data[5] * 65536 +
- (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7],
- STp->drv_buffer));
+ DEBC_printk(STp, "Density %x, tape length: %x, "
+ "drv buffer: %d\n",
+ STp->density,
+ (STp->buffer)->b_data[5] * 65536 +
+ (STp->buffer)->b_data[6] * 256 +
+ (STp->buffer)->b_data[7],
+ STp->drv_buffer);
}
STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
if (!STp->drv_buffer && STp->immediate_filemark) {
- printk(KERN_WARNING
- "%s: non-buffered tape: disabling writing immediate filemarks\n",
- name);
+ st_printk(KERN_WARNING, STp,
+ "non-buffered tape: disabling "
+ "writing immediate filemarks\n");
STp->immediate_filemark = 0;
}
}
st_release_request(SRpnt);
SRpnt = NULL;
- STp->inited = 1;
+ STp->inited = 1;
if (STp->block_size > 0)
(STp->buffer)->buffer_blocks =
- (STp->buffer)->buffer_size / STp->block_size;
+ (STp->buffer)->buffer_size / STp->block_size;
else
(STp->buffer)->buffer_blocks = 1;
(STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
- DEBC(printk(ST_DEB_MSG
- "%s: Block size: %d, buffer size: %d (%d blocks).\n", name,
- STp->block_size, (STp->buffer)->buffer_size,
- (STp->buffer)->buffer_blocks));
+ DEBC_printk(STp, "Block size: %d, buffer size: %d (%d blocks).\n",
+ STp->block_size, (STp->buffer)->buffer_size,
+ (STp->buffer)->buffer_blocks);
if (STp->drv_write_prot) {
STp->write_prot = 1;
- DEBC(printk(ST_DEB_MSG "%s: Write protected\n", name));
+ DEBC_printk(STp, "Write protected\n");
if (do_wait &&
((st_flags & O_ACCMODE) == O_WRONLY ||
@@ -1141,8 +1238,7 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
/* This code is reached when the device is opened for the first time
after the driver has been initialized with tape in the drive and the
partition support has been enabled. */
- DEBC(printk(ST_DEB_MSG
- "%s: Updating partition number in status.\n", name));
+ DEBC_printk(STp, "Updating partition number in status.\n");
if ((STp->partition = find_partition(STp)) < 0) {
retval = STp->partition;
goto err_out;
@@ -1160,9 +1256,10 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
if (STp->default_drvbuffer != 0xff) {
if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer))
- printk(KERN_WARNING
- "%s: Can't set default drive buffering to %d.\n",
- name, STp->default_drvbuffer);
+ st_printk(KERN_WARNING, STp,
+ "Can't set default drive "
+ "buffering to %d.\n",
+ STp->default_drvbuffer);
}
}
@@ -1182,7 +1279,6 @@ static int st_open(struct inode *inode, struct file *filp)
struct scsi_tape *STp;
struct st_partstat *STps;
int dev = TAPE_NR(inode);
- char *name;
/*
* We really want to do nonseekable_open(inode, filp); here, but some
@@ -1196,13 +1292,12 @@ static int st_open(struct inode *inode, struct file *filp)
}
filp->private_data = STp;
- name = tape_name(STp);
spin_lock(&st_use_lock);
if (STp->in_use) {
spin_unlock(&st_use_lock);
+ DEBC_printk(STp, "Device already in use.\n");
scsi_tape_put(STp);
- DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); )
return (-EBUSY);
}
@@ -1221,9 +1316,9 @@ static int st_open(struct inode *inode, struct file *filp)
}
/* See that we have at least a one page buffer available */
- if (!enlarge_buffer(STp->buffer, PAGE_SIZE, STp->restr_dma)) {
- printk(KERN_WARNING "%s: Can't allocate one page tape buffer.\n",
- name);
+ if (!enlarge_buffer(STp->buffer, PAGE_SIZE)) {
+ st_printk(KERN_WARNING, STp,
+ "Can't allocate one page tape buffer.\n");
retval = (-EOVERFLOW);
goto err_out;
}
@@ -1262,9 +1357,9 @@ static int st_open(struct inode *inode, struct file *filp)
spin_lock(&st_use_lock);
STp->in_use = 0;
spin_unlock(&st_use_lock);
- scsi_tape_put(STp);
if (resumed)
scsi_autopm_put_device(STp->device);
+ scsi_tape_put(STp);
return retval;
}
@@ -1279,7 +1374,6 @@ static int st_flush(struct file *filp, fl_owner_t id)
struct scsi_tape *STp = filp->private_data;
struct st_modedef *STm = &(STp->modes[STp->current_mode]);
struct st_partstat *STps = &(STp->ps[STp->partition]);
- char *name = tape_name(STp);
if (file_count(filp) > 1)
return 0;
@@ -1292,24 +1386,25 @@ static int st_flush(struct file *filp, fl_owner_t id)
if (STp->can_partitions &&
(result2 = switch_partition(STp)) < 0) {
- DEBC(printk(ST_DEB_MSG
- "%s: switch_partition at close failed.\n", name));
+ DEBC_printk(STp, "switch_partition at close failed.\n");
if (result == 0)
result = result2;
goto out;
}
DEBC( if (STp->nbr_requests)
- printk(KERN_DEBUG "%s: Number of r/w requests %d, dio used in %d, pages %d.\n",
- name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages));
+ st_printk(KERN_DEBUG, STp,
+ "Number of r/w requests %d, dio used in %d, "
+ "pages %d.\n", STp->nbr_requests, STp->nbr_dio,
+ STp->nbr_pages));
if (STps->rw == ST_WRITING && !STp->pos_unknown) {
struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
- DEBC(printk(ST_DEB_MSG "%s: Async write waits %d, finished %d.\n",
- name, STp->nbr_waits, STp->nbr_finished);
- )
-
+#if DEBUG
+ DEBC_printk(STp, "Async write waits %d, finished %d.\n",
+ STp->nbr_waits, STp->nbr_finished);
+#endif
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = WRITE_FILEMARKS;
if (STp->immediate_filemark)
@@ -1343,13 +1438,13 @@ static int st_flush(struct file *filp, fl_owner_t id)
else { /* Write error */
st_release_request(SRpnt);
SRpnt = NULL;
- printk(KERN_ERR "%s: Error on write filemark.\n", name);
+ st_printk(KERN_ERR, STp,
+ "Error on write filemark.\n");
if (result == 0)
result = (-EIO);
}
- DEBC(printk(ST_DEB_MSG "%s: Buffer flushed, %d EOF(s) written\n",
- name, cmd[4]));
+ DEBC_printk(STp, "Buffer flushed, %d EOF(s) written\n", cmd[4]);
} else if (!STp->rew_at_close) {
STps = &(STp->ps[STp->partition]);
if (!STm->sysv || STps->rw != ST_READING) {
@@ -1389,7 +1484,6 @@ static int st_flush(struct file *filp, fl_owner_t id)
accessing this tape. */
static int st_release(struct inode *inode, struct file *filp)
{
- int result = 0;
struct scsi_tape *STp = filp->private_data;
if (STp->door_locked == ST_LOCKED_AUTO)
@@ -1402,9 +1496,9 @@ static int st_release(struct inode *inode, struct file *filp)
scsi_autopm_put_device(STp->device);
scsi_tape_put(STp);
- return result;
+ return 0;
}
-
+
/* The checks common to both reading and writing */
static ssize_t rw_checks(struct scsi_tape *STp, struct file *filp, size_t count)
{
@@ -1447,9 +1541,10 @@ static ssize_t rw_checks(struct scsi_tape *STp, struct file *filp, size_t count)
if (count == 0)
goto out;
- DEB(
+ DEB(
if (!STp->in_use) {
- printk(ST_DEB_MSG "%s: Incorrect device.\n", tape_name(STp));
+ st_printk(ST_DEB_MSG, STp,
+ "Incorrect device.\n");
retval = (-EIO);
goto out;
} ) /* end DEB */
@@ -1518,9 +1613,10 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
}
if (bufsize > STbp->buffer_size &&
- !enlarge_buffer(STbp, bufsize, STp->restr_dma)) {
- printk(KERN_WARNING "%s: Can't allocate %d byte tape buffer.\n",
- tape_name(STp), bufsize);
+ !enlarge_buffer(STbp, bufsize)) {
+ st_printk(KERN_WARNING, STp,
+ "Can't allocate %d byte tape buffer.\n",
+ bufsize);
retval = (-EOVERFLOW);
goto out;
}
@@ -1563,7 +1659,6 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
struct st_modedef *STm;
struct st_partstat *STps;
struct st_buffer *STbp;
- char *name = tape_name(STp);
if (mutex_lock_interruptible(&STp->lock))
return -ERESTARTSYS;
@@ -1574,8 +1669,8 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
/* Write must be integral number of blocks */
if (STp->block_size != 0 && (count % STp->block_size) != 0) {
- printk(KERN_WARNING "%s: Write not multiple of tape block size.\n",
- name);
+ st_printk(KERN_WARNING, STp,
+ "Write not multiple of tape block size.\n");
retval = (-EINVAL);
goto out;
}
@@ -1601,8 +1696,8 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
if (STm->default_compression != ST_DONT_TOUCH &&
!(STp->compression_changed)) {
if (st_compression(STp, (STm->default_compression == ST_YES))) {
- printk(KERN_WARNING "%s: Can't set default compression.\n",
- name);
+ st_printk(KERN_WARNING, STp,
+ "Can't set default compression.\n");
if (modes_defined) {
retval = (-EINVAL);
goto out;
@@ -1723,7 +1818,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
if (STbp->syscall_result != 0) {
struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
- DEBC(printk(ST_DEB_MSG "%s: Error on write:\n", name));
+ DEBC_printk(STp, "Error on write:\n");
if (cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) {
scode = cmdstatp->sense_hdr.sense_key;
if (cmdstatp->remainder_valid)
@@ -1750,9 +1845,9 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
if (STp->block_size == 0 ||
undone > 0 || count == 0)
retval = (-ENOSPC); /* EOM within current request */
- DEBC(printk(ST_DEB_MSG
- "%s: EOM with %d bytes unwritten.\n",
- name, (int)count));
+ DEBC_printk(STp, "EOM with %d "
+ "bytes unwritten.\n",
+ (int)count);
} else {
/* EOT within data buffered earlier (possible only
in fixed block mode without direct i/o) */
@@ -1765,9 +1860,10 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
STp->block_size;
}
STps->eof = ST_EOM_OK;
- DEBC(printk(ST_DEB_MSG
- "%s: Retry write of %d bytes at EOM.\n",
- name, STp->buffer->buffer_bytes));
+ DEBC_printk(STp, "Retry "
+ "write of %d "
+ "bytes at EOM.\n",
+ STp->buffer->buffer_bytes);
goto retry_write;
}
else {
@@ -1778,9 +1874,8 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
STps->eof = ST_EOM_ERROR;
STps->drv_block = (-1); /* Too cautious? */
retval = (-EIO); /* EOM for old data */
- DEBC(printk(ST_DEB_MSG
- "%s: EOM with lost data.\n",
- name));
+ DEBC_printk(STp, "EOM with "
+ "lost data.\n");
}
}
} else {
@@ -1839,7 +1934,6 @@ static long read_tape(struct scsi_tape *STp, long count,
struct st_partstat *STps;
struct st_buffer *STbp;
int retval = 0;
- char *name = tape_name(STp);
if (count == 0)
return 0;
@@ -1891,12 +1985,12 @@ static long read_tape(struct scsi_tape *STp, long count,
struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
retval = 1;
- DEBC(printk(ST_DEB_MSG "%s: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
- name,
- SRpnt->sense[0], SRpnt->sense[1],
- SRpnt->sense[2], SRpnt->sense[3],
- SRpnt->sense[4], SRpnt->sense[5],
- SRpnt->sense[6], SRpnt->sense[7]));
+ DEBC_printk(STp,
+ "Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
+ SRpnt->sense[0], SRpnt->sense[1],
+ SRpnt->sense[2], SRpnt->sense[3],
+ SRpnt->sense[4], SRpnt->sense[5],
+ SRpnt->sense[6], SRpnt->sense[7]);
if (cmdstatp->have_sense) {
if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
@@ -1908,28 +2002,35 @@ static long read_tape(struct scsi_tape *STp, long count,
transfer = (int)cmdstatp->uremainder64;
else
transfer = 0;
- if (STp->block_size == 0 &&
- cmdstatp->sense_hdr.sense_key == MEDIUM_ERROR)
- transfer = bytes;
+ if (cmdstatp->sense_hdr.sense_key == MEDIUM_ERROR) {
+ if (STp->block_size == 0)
+ transfer = bytes;
+ /* Some drives set ILI with MEDIUM ERROR */
+ cmdstatp->flags &= ~SENSE_ILI;
+ }
if (cmdstatp->flags & SENSE_ILI) { /* ILI */
- if (STp->block_size == 0) {
- if (transfer <= 0) {
- if (transfer < 0)
- printk(KERN_NOTICE
- "%s: Failed to read %d byte block with %d byte transfer.\n",
- name, bytes - transfer, bytes);
- if (STps->drv_block >= 0)
- STps->drv_block += 1;
- STbp->buffer_bytes = 0;
- return (-ENOMEM);
- }
+ if (STp->block_size == 0 &&
+ transfer < 0) {
+ st_printk(KERN_NOTICE, STp,
+ "Failed to read %d "
+ "byte block with %d "
+ "byte transfer.\n",
+ bytes - transfer,
+ bytes);
+ if (STps->drv_block >= 0)
+ STps->drv_block += 1;
+ STbp->buffer_bytes = 0;
+ return (-ENOMEM);
+ } else if (STp->block_size == 0) {
STbp->buffer_bytes = bytes - transfer;
} else {
st_release_request(SRpnt);
SRpnt = *aSRpnt = NULL;
if (transfer == blks) { /* We did not get anything, error */
- printk(KERN_NOTICE "%s: Incorrect block size.\n", name);
+ st_printk(KERN_NOTICE, STp,
+ "Incorrect "
+ "block size.\n");
if (STps->drv_block >= 0)
STps->drv_block += blks - transfer + 1;
st_int_ioctl(STp, MTBSR, 1);
@@ -1938,9 +2039,11 @@ static long read_tape(struct scsi_tape *STp, long count,
/* We have some data, deliver it */
STbp->buffer_bytes = (blks - transfer) *
STp->block_size;
- DEBC(printk(ST_DEB_MSG
- "%s: ILI but enough data received %ld %d.\n",
- name, count, STbp->buffer_bytes));
+ DEBC_printk(STp, "ILI but "
+ "enough data "
+ "received %ld "
+ "%d.\n", count,
+ STbp->buffer_bytes);
if (STps->drv_block >= 0)
STps->drv_block += 1;
if (st_int_ioctl(STp, MTBSR, 1))
@@ -1956,9 +2059,9 @@ static long read_tape(struct scsi_tape *STp, long count,
else
STbp->buffer_bytes =
bytes - transfer * STp->block_size;
- DEBC(printk(ST_DEB_MSG
- "%s: EOF detected (%d bytes read).\n",
- name, STbp->buffer_bytes));
+ DEBC_printk(STp, "EOF detected (%d "
+ "bytes read).\n",
+ STbp->buffer_bytes);
} else if (cmdstatp->flags & SENSE_EOM) {
if (STps->eof == ST_FM)
STps->eof = ST_EOD_1;
@@ -1970,20 +2073,20 @@ static long read_tape(struct scsi_tape *STp, long count,
STbp->buffer_bytes =
bytes - transfer * STp->block_size;
- DEBC(printk(ST_DEB_MSG "%s: EOM detected (%d bytes read).\n",
- name, STbp->buffer_bytes));
+ DEBC_printk(STp, "EOM detected (%d "
+ "bytes read).\n",
+ STbp->buffer_bytes);
}
}
- /* end of EOF, EOM, ILI test */
+ /* end of EOF, EOM, ILI test */
else { /* nonzero sense key */
- DEBC(printk(ST_DEB_MSG
- "%s: Tape error while reading.\n", name));
+ DEBC_printk(STp, "Tape error while reading.\n");
STps->drv_block = (-1);
if (STps->eof == ST_FM &&
cmdstatp->sense_hdr.sense_key == BLANK_CHECK) {
- DEBC(printk(ST_DEB_MSG
- "%s: Zero returned for first BLANK CHECK after EOF.\n",
- name));
+ DEBC_printk(STp, "Zero returned for "
+ "first BLANK CHECK "
+ "after EOF.\n");
STps->eof = ST_EOD_2; /* First BLANK_CHECK after FM */
} else /* Some other extended sense code */
retval = (-EIO);
@@ -1992,13 +2095,13 @@ static long read_tape(struct scsi_tape *STp, long count,
if (STbp->buffer_bytes < 0) /* Caused by bogus sense data */
STbp->buffer_bytes = 0;
}
- /* End of extended sense test */
+ /* End of extended sense test */
else { /* Non-extended sense */
retval = STbp->syscall_result;
}
}
- /* End of error handling */
+ /* End of error handling */
else { /* Read successful */
STbp->buffer_bytes = bytes;
if (STp->sili) /* In fixed block mode residual is always zero here */
@@ -2028,7 +2131,6 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
struct st_modedef *STm;
struct st_partstat *STps;
struct st_buffer *STbp = STp->buffer;
- DEB( char *name = tape_name(STp); )
if (mutex_lock_interruptible(&STp->lock))
return -ERESTARTSYS;
@@ -2053,11 +2155,12 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
goto out;
STps->rw = ST_READING;
}
- DEB(
+ DEB(
if (debugging && STps->eof != ST_NOEOF)
- printk(ST_DEB_MSG "%s: EOF/EOM flag up (%d). Bytes %d\n", name,
- STps->eof, STbp->buffer_bytes);
- ) /* end DEB */
+ st_printk(ST_DEB_MSG, STp,
+ "EOF/EOM flag up (%d). Bytes %d\n",
+ STps->eof, STbp->buffer_bytes);
+ ) /* end DEB */
retval = setup_buffering(STp, buf, count, 1);
if (retval)
@@ -2104,13 +2207,13 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
/* Move the data from driver buffer to user buffer */
if (STbp->buffer_bytes > 0) {
- DEB(
+ DEB(
if (debugging && STps->eof != ST_NOEOF)
- printk(ST_DEB_MSG
- "%s: EOF up (%d). Left %d, needed %d.\n", name,
- STps->eof, STbp->buffer_bytes,
- (int)(count - total));
- ) /* end DEB */
+ st_printk(ST_DEB_MSG, STp,
+ "EOF up (%d). Left %d, needed %d.\n",
+ STps->eof, STbp->buffer_bytes,
+ (int)(count - total));
+ ) /* end DEB */
transfer = STbp->buffer_bytes < count - total ?
STbp->buffer_bytes : count - total;
if (!do_dio) {
@@ -2166,26 +2269,30 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
DEB(
/* Set the driver options */
-static void st_log_options(struct scsi_tape * STp, struct st_modedef * STm, char *name)
+static void st_log_options(struct scsi_tape * STp, struct st_modedef * STm)
{
if (debugging) {
- printk(KERN_INFO
- "%s: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
- name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
- STm->do_read_ahead);
- printk(KERN_INFO
- "%s: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
- name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
- printk(KERN_INFO
- "%s: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
- name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
- STp->scsi2_logical);
- printk(KERN_INFO
- "%s: sysv: %d nowait: %d sili: %d nowait_filemark: %d\n",
- name, STm->sysv, STp->immediate, STp->sili,
- STp->immediate_filemark);
- printk(KERN_INFO "%s: debugging: %d\n",
- name, debugging);
+ st_printk(KERN_INFO, STp,
+ "Mode %d options: buffer writes: %d, "
+ "async writes: %d, read ahead: %d\n",
+ STp->current_mode, STm->do_buffer_writes,
+ STm->do_async_writes, STm->do_read_ahead);
+ st_printk(KERN_INFO, STp,
+ " can bsr: %d, two FMs: %d, "
+ "fast mteom: %d, auto lock: %d,\n",
+ STp->can_bsr, STp->two_fm, STp->fast_mteom,
+ STp->do_auto_lock);
+ st_printk(KERN_INFO, STp,
+ " defs for wr: %d, no block limits: %d, "
+ "partitions: %d, s2 log: %d\n",
+ STm->defaults_for_writes, STp->omit_blklims,
+ STp->can_partitions, STp->scsi2_logical);
+ st_printk(KERN_INFO, STp,
+ " sysv: %d nowait: %d sili: %d "
+ "nowait_filemark: %d\n",
+ STm->sysv, STp->immediate, STp->sili,
+ STp->immediate_filemark);
+ st_printk(KERN_INFO, STp, " debugging: %d\n", debugging);
}
}
)
@@ -2196,18 +2303,23 @@ static int st_set_options(struct scsi_tape *STp, long options)
int value;
long code;
struct st_modedef *STm;
- char *name = tape_name(STp);
struct cdev *cd0, *cd1;
+ struct device *d0, *d1;
STm = &(STp->modes[STp->current_mode]);
if (!STm->defined) {
- cd0 = STm->cdevs[0]; cd1 = STm->cdevs[1];
+ cd0 = STm->cdevs[0];
+ cd1 = STm->cdevs[1];
+ d0 = STm->devs[0];
+ d1 = STm->devs[1];
memcpy(STm, &(STp->modes[0]), sizeof(struct st_modedef));
- STm->cdevs[0] = cd0; STm->cdevs[1] = cd1;
+ STm->cdevs[0] = cd0;
+ STm->cdevs[1] = cd1;
+ STm->devs[0] = d0;
+ STm->devs[1] = d1;
modes_defined = 1;
- DEBC(printk(ST_DEB_MSG
- "%s: Initialized mode %d definition from mode 0\n",
- name, STp->current_mode));
+ DEBC_printk(STp, "Initialized mode %d definition from mode 0\n",
+ STp->current_mode);
}
code = options & MT_ST_OPTIONS;
@@ -2229,7 +2341,7 @@ static int st_set_options(struct scsi_tape *STp, long options)
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); )
+ st_log_options(STp, STm); )
} else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
value = (code == MT_ST_SETBOOLEANS);
if ((options & MT_ST_BUFFER_WRITES) != 0)
@@ -2263,21 +2375,21 @@ static int st_set_options(struct scsi_tape *STp, long options)
STm->sysv = value;
if ((options & MT_ST_SILI) != 0)
STp->sili = value;
- DEB(
+ DEB(
if ((options & MT_ST_DEBUGGING) != 0)
debugging = value;
- st_log_options(STp, STm, name); )
+ st_log_options(STp, STm); )
} else if (code == MT_ST_WRITE_THRESHOLD) {
/* Retained for compatibility */
} else if (code == MT_ST_DEF_BLKSIZE) {
value = (options & ~MT_ST_OPTIONS);
if (value == ~MT_ST_OPTIONS) {
STm->default_blksize = (-1);
- DEBC( printk(KERN_INFO "%s: Default block size disabled.\n", name));
+ DEBC_printk(STp, "Default block size disabled.\n");
} else {
STm->default_blksize = value;
- DEBC( printk(KERN_INFO "%s: Default block size set to %d bytes.\n",
- name, STm->default_blksize));
+ DEBC_printk(STp,"Default block size set to "
+ "%d bytes.\n", STm->default_blksize);
if (STp->ready == ST_READY) {
STp->blksize_changed = 0;
set_mode_densblk(STp, STm);
@@ -2287,13 +2399,13 @@ static int st_set_options(struct scsi_tape *STp, long options)
value = (options & ~MT_ST_OPTIONS);
if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
- DEBC( printk(KERN_INFO "%s: Long timeout set to %d seconds.\n", name,
- (value & ~MT_ST_SET_LONG_TIMEOUT)));
+ DEBC_printk(STp, "Long timeout set to %d seconds.\n",
+ (value & ~MT_ST_SET_LONG_TIMEOUT));
} else {
blk_queue_rq_timeout(STp->device->request_queue,
value * HZ);
- DEBC( printk(KERN_INFO "%s: Normal timeout set to %d seconds.\n",
- name, value) );
+ DEBC_printk(STp, "Normal timeout set to %d seconds.\n",
+ value);
}
} else if (code == MT_ST_SET_CLN) {
value = (options & ~MT_ST_OPTIONS) & 0xff;
@@ -2304,21 +2416,21 @@ static int st_set_options(struct scsi_tape *STp, long options)
STp->cln_mode = value;
STp->cln_sense_mask = (options >> 8) & 0xff;
STp->cln_sense_value = (options >> 16) & 0xff;
- printk(KERN_INFO
- "%s: Cleaning request mode %d, mask %02x, value %02x\n",
- name, value, STp->cln_sense_mask, STp->cln_sense_value);
+ st_printk(KERN_INFO, STp,
+ "Cleaning request mode %d, mask %02x, value %02x\n",
+ value, STp->cln_sense_mask, STp->cln_sense_value);
} else if (code == MT_ST_DEF_OPTIONS) {
code = (options & ~MT_ST_CLEAR_DEFAULT);
value = (options & MT_ST_CLEAR_DEFAULT);
if (code == MT_ST_DEF_DENSITY) {
if (value == MT_ST_CLEAR_DEFAULT) {
STm->default_density = (-1);
- DEBC( printk(KERN_INFO "%s: Density default disabled.\n",
- name));
+ DEBC_printk(STp,
+ "Density default disabled.\n");
} else {
STm->default_density = value & 0xff;
- DEBC( printk(KERN_INFO "%s: Density default set to %x\n",
- name, STm->default_density));
+ DEBC_printk(STp, "Density default set to %x\n",
+ STm->default_density);
if (STp->ready == ST_READY) {
STp->density_changed = 0;
set_mode_densblk(STp, STm);
@@ -2327,31 +2439,33 @@ static int st_set_options(struct scsi_tape *STp, long options)
} else if (code == MT_ST_DEF_DRVBUFFER) {
if (value == MT_ST_CLEAR_DEFAULT) {
STp->default_drvbuffer = 0xff;
- DEBC( printk(KERN_INFO
- "%s: Drive buffer default disabled.\n", name));
+ DEBC_printk(STp,
+ "Drive buffer default disabled.\n");
} else {
STp->default_drvbuffer = value & 7;
- DEBC( printk(KERN_INFO
- "%s: Drive buffer default set to %x\n",
- name, STp->default_drvbuffer));
+ DEBC_printk(STp,
+ "Drive buffer default set to %x\n",
+ STp->default_drvbuffer);
if (STp->ready == ST_READY)
st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer);
}
} else if (code == MT_ST_DEF_COMPRESSION) {
if (value == MT_ST_CLEAR_DEFAULT) {
STm->default_compression = ST_DONT_TOUCH;
- DEBC( printk(KERN_INFO
- "%s: Compression default disabled.\n", name));
+ DEBC_printk(STp,
+ "Compression default disabled.\n");
} else {
if ((value & 0xff00) != 0) {
STp->c_algo = (value & 0xff00) >> 8;
- DEBC( printk(KERN_INFO "%s: Compression algorithm set to 0x%x.\n",
- name, STp->c_algo));
+ DEBC_printk(STp, "Compression "
+ "algorithm set to 0x%x.\n",
+ STp->c_algo);
}
if ((value & 0xff) != 0xff) {
STm->default_compression = (value & 1 ? ST_YES : ST_NO);
- DEBC( printk(KERN_INFO "%s: Compression default set to %x\n",
- name, (value & 1)));
+ DEBC_printk(STp, "Compression default "
+ "set to %x\n",
+ (value & 1));
if (STp->ready == ST_READY) {
STp->compression_changed = 0;
st_compression(STp, (STm->default_compression == ST_YES));
@@ -2466,7 +2580,6 @@ static int st_compression(struct scsi_tape * STp, int state)
int retval;
int mpoffs; /* Offset to mode page start */
unsigned char *b_data = (STp->buffer)->b_data;
- DEB( char *name = tape_name(STp); )
if (STp->ready != ST_READY)
return (-EIO);
@@ -2474,18 +2587,17 @@ static int st_compression(struct scsi_tape * STp, int state)
/* Read the current page contents */
retval = read_mode_page(STp, COMPRESSION_PAGE, 0);
if (retval) {
- DEBC(printk(ST_DEB_MSG "%s: Compression mode page not supported.\n",
- name));
+ DEBC_printk(STp, "Compression mode page not supported.\n");
return (-EIO);
}
mpoffs = MODE_HEADER_LENGTH + b_data[MH_OFF_BDESCS_LENGTH];
- DEBC(printk(ST_DEB_MSG "%s: Compression state is %d.\n", name,
- (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0)));
+ DEBC_printk(STp, "Compression state is %d.\n",
+ (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0));
/* Check if compression can be changed */
if ((b_data[mpoffs + CP_OFF_DCE_DCC] & DCC_MASK) == 0) {
- DEBC(printk(ST_DEB_MSG "%s: Compression not supported.\n", name));
+ DEBC_printk(STp, "Compression not supported.\n");
return (-EIO);
}
@@ -2503,11 +2615,10 @@ static int st_compression(struct scsi_tape * STp, int state)
retval = write_mode_page(STp, COMPRESSION_PAGE, 0);
if (retval) {
- DEBC(printk(ST_DEB_MSG "%s: Compression change failed.\n", name));
+ DEBC_printk(STp, "Compression change failed.\n");
return (-EIO);
}
- DEBC(printk(ST_DEB_MSG "%s: Compression state changed to %d.\n",
- name, state));
+ DEBC_printk(STp, "Compression state changed to %d.\n", state);
STp->compression_changed = 1;
return 0;
@@ -2518,7 +2629,6 @@ static int st_compression(struct scsi_tape * STp, int state)
static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_code)
{
int retval = (-EIO), timeout;
- DEB( char *name = tape_name(STp); )
unsigned char cmd[MAX_COMMAND_SIZE];
struct st_partstat *STps;
struct st_request *SRpnt;
@@ -2539,9 +2649,9 @@ static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_cod
*/
if (load_code >= 1 + MT_ST_HPLOADER_OFFSET
&& load_code <= 6 + MT_ST_HPLOADER_OFFSET) {
- DEBC(printk(ST_DEB_MSG "%s: Enhanced %sload slot %2d.\n",
- name, (cmd[4]) ? "" : "un",
- load_code - MT_ST_HPLOADER_OFFSET));
+ DEBC_printk(STp, " Enhanced %sload slot %2d.\n",
+ (cmd[4]) ? "" : "un",
+ load_code - MT_ST_HPLOADER_OFFSET);
cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
}
if (STp->immediate) {
@@ -2553,9 +2663,9 @@ static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_cod
DEBC(
if (!load_code)
- printk(ST_DEB_MSG "%s: Unloading tape.\n", name);
+ st_printk(ST_DEB_MSG, STp, "Unloading tape.\n");
else
- printk(ST_DEB_MSG "%s: Loading tape.\n", name);
+ st_printk(ST_DEB_MSG, STp, "Loading tape.\n");
);
SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
@@ -2590,17 +2700,23 @@ static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_cod
#if DEBUG
#define ST_DEB_FORWARD 0
#define ST_DEB_BACKWARD 1
-static void deb_space_print(char *name, int direction, char *units, unsigned char *cmd)
+static void deb_space_print(struct scsi_tape *STp, int direction, char *units, unsigned char *cmd)
{
s32 sc;
- sc = cmd[2] & 0x80 ? 0xff000000 : 0;
- sc |= (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+ if (!debugging)
+ return;
+
+ sc = sign_extend32(get_unaligned_be24(&cmd[2]), 23);
if (direction)
sc = -sc;
- printk(ST_DEB_MSG "%s: Spacing tape %s over %d %s.\n", name,
- direction ? "backward" : "forward", sc, units);
+ st_printk(ST_DEB_MSG, STp, "Spacing tape %s over %d %s.\n",
+ direction ? "backward" : "forward", sc, units);
}
+#else
+#define ST_DEB_FORWARD 0
+#define ST_DEB_BACKWARD 1
+static void deb_space_print(struct scsi_tape *STp, int direction, char *units, unsigned char *cmd) {}
#endif
@@ -2616,7 +2732,6 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
struct st_partstat *STps;
int fileno, blkno, at_sm, undone;
int datalen = 0, direction = DMA_NONE;
- char *name = tape_name(STp);
WARN_ON(STp->buffer->do_dio != 0);
if (STp->ready != ST_READY) {
@@ -2635,13 +2750,14 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
switch (cmd_in) {
case MTFSFM:
chg_eof = 0; /* Changed from the FSF after this */
+ fallthrough;
case MTFSF:
cmd[0] = SPACE;
cmd[1] = 0x01; /* Space FileMarks */
cmd[2] = (arg >> 16);
cmd[3] = (arg >> 8);
cmd[4] = arg;
- DEBC(deb_space_print(name, ST_DEB_FORWARD, "filemarks", cmd);)
+ deb_space_print(STp, ST_DEB_FORWARD, "filemarks", cmd);
if (fileno >= 0)
fileno += arg;
blkno = 0;
@@ -2649,6 +2765,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
break;
case MTBSFM:
chg_eof = 0; /* Changed from the FSF after this */
+ fallthrough;
case MTBSF:
cmd[0] = SPACE;
cmd[1] = 0x01; /* Space FileMarks */
@@ -2656,7 +2773,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
cmd[2] = (ltmp >> 16);
cmd[3] = (ltmp >> 8);
cmd[4] = ltmp;
- DEBC(deb_space_print(name, ST_DEB_BACKWARD, "filemarks", cmd);)
+ deb_space_print(STp, ST_DEB_BACKWARD, "filemarks", cmd);
if (fileno >= 0)
fileno -= arg;
blkno = (-1); /* We can't know the block number */
@@ -2668,7 +2785,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
cmd[2] = (arg >> 16);
cmd[3] = (arg >> 8);
cmd[4] = arg;
- DEBC(deb_space_print(name, ST_DEB_FORWARD, "blocks", cmd);)
+ deb_space_print(STp, ST_DEB_FORWARD, "blocks", cmd);
if (blkno >= 0)
blkno += arg;
at_sm &= (arg == 0);
@@ -2680,7 +2797,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
cmd[2] = (ltmp >> 16);
cmd[3] = (ltmp >> 8);
cmd[4] = ltmp;
- DEBC(deb_space_print(name, ST_DEB_BACKWARD, "blocks", cmd);)
+ deb_space_print(STp, ST_DEB_BACKWARD, "blocks", cmd);
if (blkno >= 0)
blkno -= arg;
at_sm &= (arg == 0);
@@ -2691,7 +2808,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
cmd[2] = (arg >> 16);
cmd[3] = (arg >> 8);
cmd[4] = arg;
- DEBC(deb_space_print(name, ST_DEB_FORWARD, "setmarks", cmd);)
+ deb_space_print(STp, ST_DEB_FORWARD, "setmarks", cmd);
if (arg != 0) {
blkno = fileno = (-1);
at_sm = 1;
@@ -2704,7 +2821,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
cmd[2] = (ltmp >> 16);
cmd[3] = (ltmp >> 8);
cmd[4] = ltmp;
- DEBC(deb_space_print(name, ST_DEB_BACKWARD, "setmarks", cmd);)
+ deb_space_print(STp, ST_DEB_BACKWARD, "setmarks", cmd);
if (arg != 0) {
blkno = fileno = (-1);
at_sm = 1;
@@ -2725,13 +2842,19 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
cmd[3] = (arg >> 8);
cmd[4] = arg;
timeout = STp->device->request_queue->rq_timeout;
- DEBC(
- if (cmd_in != MTWSM)
- printk(ST_DEB_MSG "%s: Writing %d filemarks.\n", name,
- cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
- else
- printk(ST_DEB_MSG "%s: Writing %d setmarks.\n", name,
- cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+ DEBC(
+ if (cmd_in != MTWSM)
+ st_printk(ST_DEB_MSG, STp,
+ "Writing %d filemarks.\n",
+ cmd[2] * 65536 +
+ cmd[3] * 256 +
+ cmd[4]);
+ else
+ st_printk(ST_DEB_MSG, STp,
+ "Writing %d setmarks.\n",
+ cmd[2] * 65536 +
+ cmd[3] * 256 +
+ cmd[4]);
)
if (fileno >= 0)
fileno += arg;
@@ -2744,13 +2867,12 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
cmd[1] = 1; /* Don't wait for completion */
timeout = STp->device->request_queue->rq_timeout;
}
- DEBC(printk(ST_DEB_MSG "%s: Rewinding tape.\n", name));
+ DEBC_printk(STp, "Rewinding tape.\n");
fileno = blkno = at_sm = 0;
break;
case MTNOP:
- DEBC(printk(ST_DEB_MSG "%s: No op on tape.\n", name));
+ DEBC_printk(STp, "No op on tape.\n");
return 0; /* Should do something ? */
- break;
case MTRETEN:
cmd[0] = START_STOP;
if (STp->immediate) {
@@ -2758,7 +2880,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
timeout = STp->device->request_queue->rq_timeout;
}
cmd[4] = 3;
- DEBC(printk(ST_DEB_MSG "%s: Retensioning tape.\n", name));
+ DEBC_printk(STp, "Retensioning tape.\n");
fileno = blkno = at_sm = 0;
break;
case MTEOM:
@@ -2776,8 +2898,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
fileno = (-1);
cmd[0] = SPACE;
cmd[1] = 3;
- DEBC(printk(ST_DEB_MSG "%s: Spacing to end of recorded medium.\n",
- name));
+ DEBC_printk(STp, "Spacing to end of recorded medium.\n");
blkno = -1;
at_sm = 0;
break;
@@ -2793,8 +2914,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
else
timeout = STp->long_timeout * 8;
- DEBC(printk(ST_DEB_MSG "%s: Erasing tape.\n", name));
- fileno = blkno = at_sm = 0;
+ DEBC_printk(STp, "Erasing tape.\n");
break;
case MTSETBLK: /* Set block length */
case MTSETDENSITY: /* Set tape density */
@@ -2808,7 +2928,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
STp->max_block > 0 &&
((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
(arg & MT_ST_BLKSIZE_MASK) > STp->max_block)) {
- printk(KERN_WARNING "%s: Illegal block size.\n", name);
+ st_printk(KERN_WARNING, STp, "Illegal block size.\n");
return (-EINVAL);
}
cmd[0] = MODE_SELECT;
@@ -2827,35 +2947,38 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
if (cmd_in == MTSETDENSITY) {
(STp->buffer)->b_data[4] = arg;
STp->density_changed = 1; /* At least we tried ;-) */
+ STp->changed_density = arg;
} else if (cmd_in == SET_DENS_AND_BLK)
(STp->buffer)->b_data[4] = arg >> 24;
else
(STp->buffer)->b_data[4] = STp->density;
if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
ltmp = arg & MT_ST_BLKSIZE_MASK;
- if (cmd_in == MTSETBLK)
+ if (cmd_in == MTSETBLK) {
STp->blksize_changed = 1; /* At least we tried ;-) */
+ STp->changed_blksize = arg;
+ }
} else
ltmp = STp->block_size;
(STp->buffer)->b_data[9] = (ltmp >> 16);
(STp->buffer)->b_data[10] = (ltmp >> 8);
(STp->buffer)->b_data[11] = ltmp;
timeout = STp->device->request_queue->rq_timeout;
- DEBC(
+ DEBC(
if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK)
- printk(ST_DEB_MSG
- "%s: Setting block size to %d bytes.\n", name,
- (STp->buffer)->b_data[9] * 65536 +
- (STp->buffer)->b_data[10] * 256 +
- (STp->buffer)->b_data[11]);
+ st_printk(ST_DEB_MSG, STp,
+ "Setting block size to %d bytes.\n",
+ (STp->buffer)->b_data[9] * 65536 +
+ (STp->buffer)->b_data[10] * 256 +
+ (STp->buffer)->b_data[11]);
if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK)
- printk(ST_DEB_MSG
- "%s: Setting density code to %x.\n", name,
- (STp->buffer)->b_data[4]);
+ st_printk(ST_DEB_MSG, STp,
+ "Setting density code to %x.\n",
+ (STp->buffer)->b_data[4]);
if (cmd_in == MTSETDRVBUFFER)
- printk(ST_DEB_MSG
- "%s: Setting drive buffer code to %d.\n", name,
- ((STp->buffer)->b_data[2] >> 4) & 7);
+ st_printk(ST_DEB_MSG, STp,
+ "Setting drive buffer code to %d.\n",
+ ((STp->buffer)->b_data[2] >> 4) & 7);
)
break;
default:
@@ -2981,7 +3104,9 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
cmd_in == MTSETDRVBUFFER ||
cmd_in == SET_DENS_AND_BLK) {
if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST &&
- !(STp->use_pf & PF_TESTED)) {
+ cmdstatp->sense_hdr.asc == 0x24 &&
+ (STp->device)->scsi_level <= SCSI_2 &&
+ !(STp->use_pf & PF_TESTED)) {
/* Try the other possible state of Page Format if not
already tried */
STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED;
@@ -3012,7 +3137,6 @@ static int get_location(struct scsi_tape *STp, unsigned int *block, int *partiti
int result;
unsigned char scmd[MAX_COMMAND_SIZE];
struct st_request *SRpnt;
- DEB( char *name = tape_name(STp); )
if (STp->ready != ST_READY)
return (-EIO);
@@ -3036,7 +3160,7 @@ static int get_location(struct scsi_tape *STp, unsigned int *block, int *partiti
(STp->device->scsi_level >= SCSI_2 &&
((STp->buffer)->b_data[0] & 4) != 0)) {
*block = *partition = 0;
- DEBC(printk(ST_DEB_MSG "%s: Can't read tape position.\n", name));
+ DEBC_printk(STp, " Can't read tape position.\n");
result = (-EIO);
} else {
result = 0;
@@ -3055,8 +3179,8 @@ static int get_location(struct scsi_tape *STp, unsigned int *block, int *partiti
(STp->buffer)->b_data[1] == 0) /* BOP of partition 0 */
STp->ps[0].drv_block = STp->ps[0].drv_file = 0;
}
- DEBC(printk(ST_DEB_MSG "%s: Got tape pos. blk %d part %d.\n", name,
- *block, *partition));
+ DEBC_printk(STp, "Got tape pos. blk %d part %d.\n",
+ *block, *partition);
}
st_release_request(SRpnt);
SRpnt = NULL;
@@ -3076,15 +3200,14 @@ static int set_location(struct scsi_tape *STp, unsigned int block, int partition
int timeout;
unsigned char scmd[MAX_COMMAND_SIZE];
struct st_request *SRpnt;
- DEB( char *name = tape_name(STp); )
if (STp->ready != ST_READY)
return (-EIO);
timeout = STp->long_timeout;
STps = &(STp->ps[STp->partition]);
- DEBC(printk(ST_DEB_MSG "%s: Setting block to %d and partition to %d.\n",
- name, block, partition));
+ DEBC_printk(STp, "Setting block to %d and partition to %d.\n",
+ block, partition);
DEB(if (partition < 0)
return (-EIO); )
@@ -3098,9 +3221,9 @@ static int set_location(struct scsi_tape *STp, unsigned int block, int partition
else {
STps->last_block_valid = 1;
STps->last_block_visited = blk;
- DEBC(printk(ST_DEB_MSG
- "%s: Visited block %d for partition %d saved.\n",
- name, blk, STp->partition));
+ DEBC_printk(STp, "Visited block %d for "
+ "partition %d saved.\n",
+ blk, STp->partition);
}
}
@@ -3122,9 +3245,9 @@ static int set_location(struct scsi_tape *STp, unsigned int block, int partition
if (STp->partition != partition) {
scmd[1] |= 2;
scmd[8] = partition;
- DEBC(printk(ST_DEB_MSG
- "%s: Trying to change partition from %d to %d\n",
- name, STp->partition, partition));
+ DEBC_printk(STp, "Trying to change partition "
+ "from %d to %d\n", STp->partition,
+ partition);
}
}
if (STp->immediate) {
@@ -3208,14 +3331,16 @@ static int switch_partition(struct scsi_tape *STp)
#define PP_OFF_RESERVED 7
#define PP_BIT_IDP 0x20
+#define PP_BIT_FDP 0x80
#define PP_MSK_PSUM_MB 0x10
+#define PP_MSK_PSUM_UNITS 0x18
+#define PP_MSK_POFM 0x04
/* Get the number of partitions on the tape. As a side effect reads the
mode page into the tape buffer. */
static int nbr_partitions(struct scsi_tape *STp)
{
int result;
- DEB( char *name = tape_name(STp); )
if (STp->ready != ST_READY)
return (-EIO);
@@ -3223,19 +3348,41 @@ static int nbr_partitions(struct scsi_tape *STp)
result = read_mode_page(STp, PART_PAGE, 1);
if (result) {
- DEBC(printk(ST_DEB_MSG "%s: Can't read medium partition page.\n",
- name));
+ DEBC_printk(STp, "Can't read medium partition page.\n");
result = (-EIO);
} else {
result = (STp->buffer)->b_data[MODE_HEADER_LENGTH +
PP_OFF_NBR_ADD_PARTS] + 1;
- DEBC(printk(ST_DEB_MSG "%s: Number of partitions %d.\n", name, result));
+ DEBC_printk(STp, "Number of partitions %d.\n", result);
}
return result;
}
+static int format_medium(struct scsi_tape *STp, int format)
+{
+ int result = 0;
+ int timeout = STp->long_timeout;
+ unsigned char scmd[MAX_COMMAND_SIZE];
+ struct st_request *SRpnt;
+
+ memset(scmd, 0, MAX_COMMAND_SIZE);
+ scmd[0] = FORMAT_UNIT;
+ scmd[2] = format;
+ if (STp->immediate) {
+ scmd[1] |= 1; /* Don't wait for completion */
+ timeout = STp->device->request_queue->rq_timeout;
+ }
+ DEBC_printk(STp, "Sending FORMAT MEDIUM\n");
+ SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE,
+ timeout, MAX_RETRIES, 1);
+ if (!SRpnt)
+ result = STp->buffer->syscall_result;
+ return result;
+}
+
+
/* Partition the tape into two partitions if size > 0 or one partition if
size == 0.
@@ -3254,86 +3401,208 @@ static int nbr_partitions(struct scsi_tape *STp)
and 10 when 1 partition is defined (information from Eric Lee Green). This is
is acceptable also to some other old drives and enforced if the first partition
size field is used for the first additional partition size.
+
+ For drives that advertize SCSI-3 or newer, use the SSC-3 methods.
*/
static int partition_tape(struct scsi_tape *STp, int size)
{
- char *name = tape_name(STp);
int result;
+ int target_partition;
+ bool scsi3 = STp->device->scsi_level >= SCSI_3, needs_format = false;
int pgo, psd_cnt, psdo;
+ int psum = PP_MSK_PSUM_MB, units = 0;
unsigned char *bp;
result = read_mode_page(STp, PART_PAGE, 0);
if (result) {
- DEBC(printk(ST_DEB_MSG "%s: Can't read partition mode page.\n", name));
+ DEBC_printk(STp, "Can't read partition mode page.\n");
return result;
}
+ target_partition = 1;
+ if (size < 0) {
+ target_partition = 0;
+ size = -size;
+ }
+
/* The mode page is in the buffer. Let's modify it and write it. */
bp = (STp->buffer)->b_data;
pgo = MODE_HEADER_LENGTH + bp[MH_OFF_BDESCS_LENGTH];
- DEBC(printk(ST_DEB_MSG "%s: Partition page length is %d bytes.\n",
- name, bp[pgo + MP_OFF_PAGE_LENGTH] + 2));
+ DEBC_printk(STp, "Partition page length is %d bytes.\n",
+ bp[pgo + MP_OFF_PAGE_LENGTH] + 2);
psd_cnt = (bp[pgo + MP_OFF_PAGE_LENGTH] + 2 - PART_PAGE_FIXED_LENGTH) / 2;
+
+ if (scsi3) {
+ needs_format = (bp[pgo + PP_OFF_FLAGS] & PP_MSK_POFM) != 0;
+ if (needs_format && size == 0) {
+ /* No need to write the mode page when clearing
+ * partitioning
+ */
+ DEBC_printk(STp, "Formatting tape with one partition.\n");
+ result = format_medium(STp, 0);
+ goto out;
+ }
+ if (needs_format) /* Leave the old value for HP DATs claiming SCSI_3 */
+ psd_cnt = 2;
+ if ((bp[pgo + PP_OFF_FLAGS] & PP_MSK_PSUM_UNITS) == PP_MSK_PSUM_UNITS) {
+ /* Use units scaling for large partitions if the device
+ * suggests it and no precision lost. Required for IBM
+ * TS1140/50 drives that don't support MB units.
+ */
+ if (size >= 1000 && (size % 1000) == 0) {
+ size /= 1000;
+ psum = PP_MSK_PSUM_UNITS;
+ units = 9; /* GB */
+ }
+ }
+ /* Try it anyway if too large to specify in MB */
+ if (psum == PP_MSK_PSUM_MB && size >= 65534) {
+ size /= 1000;
+ psum = PP_MSK_PSUM_UNITS;
+ units = 9; /* GB */
+ }
+ }
+
+ if (size >= 65535 || /* Does not fit into two bytes */
+ (target_partition == 0 && psd_cnt < 2)) {
+ result = -EINVAL;
+ goto out;
+ }
+
psdo = pgo + PART_PAGE_FIXED_LENGTH;
- if (psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS]) {
- bp[psdo] = bp[psdo + 1] = 0xff; /* Rest of the tape */
+ /* The second condition is for HP DDS which use only one partition size
+ * descriptor
+ */
+ if (target_partition > 0 &&
+ (psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS] ||
+ bp[pgo + PP_OFF_MAX_ADD_PARTS] != 1)) {
+ bp[psdo] = bp[psdo + 1] = 0xff; /* Rest to partition 0 */
psdo += 2;
}
memset(bp + psdo, 0, bp[pgo + PP_OFF_NBR_ADD_PARTS] * 2);
- DEBC(printk("%s: psd_cnt %d, max.parts %d, nbr_parts %d\n", name,
+ DEBC_printk(STp, "psd_cnt %d, max.parts %d, nbr_parts %d\n",
psd_cnt, bp[pgo + PP_OFF_MAX_ADD_PARTS],
- bp[pgo + PP_OFF_NBR_ADD_PARTS]));
+ bp[pgo + PP_OFF_NBR_ADD_PARTS]);
- if (size <= 0) {
+ if (size == 0) {
bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0;
if (psd_cnt <= bp[pgo + PP_OFF_MAX_ADD_PARTS])
bp[pgo + MP_OFF_PAGE_LENGTH] = 6;
- DEBC(printk(ST_DEB_MSG "%s: Formatting tape with one partition.\n",
- name));
+ DEBC_printk(STp, "Formatting tape with one partition.\n");
} else {
bp[psdo] = (size >> 8) & 0xff;
bp[psdo + 1] = size & 0xff;
+ if (target_partition == 0)
+ bp[psdo + 2] = bp[psdo + 3] = 0xff;
bp[pgo + 3] = 1;
if (bp[pgo + MP_OFF_PAGE_LENGTH] < 8)
bp[pgo + MP_OFF_PAGE_LENGTH] = 8;
- DEBC(printk(ST_DEB_MSG
- "%s: Formatting tape with two partitions (1 = %d MB).\n",
- name, size));
+ DEBC_printk(STp,
+ "Formatting tape with two partitions (%i = %d MB).\n",
+ target_partition, units > 0 ? size * 1000 : size);
}
bp[pgo + PP_OFF_PART_UNITS] = 0;
bp[pgo + PP_OFF_RESERVED] = 0;
- bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | PP_MSK_PSUM_MB;
+ if (size != 1 || units != 0) {
+ bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | psum |
+ (bp[pgo + PP_OFF_FLAGS] & 0x07);
+ bp[pgo + PP_OFF_PART_UNITS] = units;
+ } else
+ bp[pgo + PP_OFF_FLAGS] = PP_BIT_FDP |
+ (bp[pgo + PP_OFF_FLAGS] & 0x1f);
+ bp[pgo + MP_OFF_PAGE_LENGTH] = 6 + psd_cnt * 2;
result = write_mode_page(STp, PART_PAGE, 1);
+
+ if (!result && needs_format)
+ result = format_medium(STp, 1);
+
if (result) {
- printk(KERN_INFO "%s: Partitioning of tape failed.\n", name);
+ st_printk(KERN_INFO, STp, "Partitioning of tape failed.\n");
result = (-EIO);
}
+out:
return result;
}
-
+/*
+ * Handles any extra state needed for ioctls which are not st-specific.
+ * Called with the scsi_tape lock held, released before return
+ */
+static long st_common_ioctl(struct scsi_tape *STp, struct st_modedef *STm,
+ struct file *file, unsigned int cmd_in,
+ unsigned long arg)
+{
+ int i, retval = 0;
+
+ if (!STm->defined) {
+ retval = -ENXIO;
+ goto out;
+ }
+
+ switch (cmd_in) {
+ case SCSI_IOCTL_GET_IDLUN:
+ case SCSI_IOCTL_GET_BUS_NUMBER:
+ case SCSI_IOCTL_GET_PCI:
+ break;
+ case SG_IO:
+ case SCSI_IOCTL_SEND_COMMAND:
+ case CDROM_SEND_PACKET:
+ if (!capable(CAP_SYS_RAWIO)) {
+ retval = -EPERM;
+ goto out;
+ }
+ fallthrough;
+ default:
+ if ((i = flush_buffer(STp, 0)) < 0) {
+ retval = i;
+ goto out;
+ } else { /* flush_buffer succeeds */
+ if (STp->can_partitions) {
+ i = switch_partition(STp);
+ if (i < 0) {
+ retval = i;
+ goto out;
+ }
+ }
+ }
+ }
+ mutex_unlock(&STp->lock);
+
+ retval = scsi_ioctl(STp->device, file->f_mode & FMODE_WRITE,
+ cmd_in, (void __user *)arg);
+ if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) {
+ /* unload */
+ STp->rew_at_close = 0;
+ STp->ready = ST_NO_TAPE;
+ }
+
+ return retval;
+out:
+ mutex_unlock(&STp->lock);
+ return retval;
+}
/* The ioctl command */
static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
{
+ void __user *p = (void __user *)arg;
int i, cmd_nr, cmd_type, bt;
int retval = 0;
unsigned int blk;
+ bool cmd_mtiocget;
struct scsi_tape *STp = file->private_data;
struct st_modedef *STm;
struct st_partstat *STps;
- char *name = tape_name(STp);
- void __user *p = (void __user *)arg;
if (mutex_lock_interruptible(&STp->lock))
return -ERESTARTSYS;
- DEB(
+ DEB(
if (debugging && !STp->in_use) {
- printk(ST_DEB_MSG "%s: Incorrect device.\n", name);
+ st_printk(ST_DEB_MSG, STp, "Incorrect device.\n");
retval = (-EIO);
goto out;
} ) /* end DEB */
@@ -3347,11 +3616,19 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
* may try and take the device offline, in which case all further
* access to the device is prohibited.
*/
- retval = scsi_nonblockable_ioctl(STp->device, cmd_in, p,
- file->f_flags & O_NDELAY);
- if (!scsi_block_when_processing_errors(STp->device) || retval != -ENODEV)
+ retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in,
+ file->f_flags & O_NDELAY);
+ if (retval)
goto out;
- retval = 0;
+
+ switch (cmd_in) {
+ case MTIOCPOS:
+ case MTIOCGET:
+ case MTIOCTOP:
+ break;
+ default:
+ return st_common_ioctl(STp, STm, file, cmd_in, arg);
+ }
cmd_type = _IOC_TYPE(cmd_in);
cmd_nr = _IOC_NR(cmd_in);
@@ -3371,8 +3648,8 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
}
if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
- printk(KERN_WARNING
- "%s: MTSETDRVBUFFER only allowed for root.\n", name);
+ st_printk(KERN_WARNING, STp,
+ "MTSETDRVBUFFER only allowed for root.\n");
retval = (-EPERM);
goto out;
}
@@ -3438,6 +3715,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
*/
if (mtc.mt_op != MTREW &&
mtc.mt_op != MTOFFL &&
+ mtc.mt_op != MTLOAD &&
mtc.mt_op != MTRETEN &&
mtc.mt_op != MTERASE &&
mtc.mt_op != MTSEEK &&
@@ -3445,9 +3723,23 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
retval = (-EIO);
goto out;
}
- reset_state(STp);
- /* remove this when the midlevel properly clears was_reset */
- STp->device->was_reset = 0;
+ reset_state(STp); /* Clears pos_unknown */
+
+ /* Fix the device settings after reset, ignore errors */
+ if (mtc.mt_op == MTREW || mtc.mt_op == MTSEEK ||
+ mtc.mt_op == MTEOM) {
+ if (STp->can_partitions) {
+ /* STp->new_partition contains the
+ * latest partition set
+ */
+ STp->partition = 0;
+ switch_partition(STp);
+ }
+ if (STp->density_changed)
+ st_int_ioctl(STp, MTSETDENSITY, STp->changed_density);
+ if (STp->blksize_changed)
+ st_int_ioctl(STp, MTSETBLK, STp->changed_blksize);
+ }
}
if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
@@ -3489,8 +3781,13 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
retval = (-EINVAL);
goto out;
}
- if ((i = st_int_ioctl(STp, MTREW, 0)) < 0 ||
- (i = partition_tape(STp, mtc.mt_count)) < 0) {
+ i = do_load_unload(STp, file, 1);
+ if (i < 0) {
+ retval = i;
+ goto out;
+ }
+ i = partition_tape(STp, mtc.mt_count);
+ if (i < 0) {
retval = i;
goto out;
}
@@ -3500,7 +3797,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
STp->ps[i].last_block_valid = 0;
}
STp->partition = STp->new_partition = 0;
- STp->nbr_partitions = 1; /* Bad guess ?-) */
+ STp->nbr_partitions = mtc.mt_count != 0 ? 2 : 1;
STps->drv_block = STps->drv_file = 0;
retval = 0;
goto out;
@@ -3546,17 +3843,28 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
goto out;
}
+ cmd_mtiocget = cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET);
+
if ((i = flush_buffer(STp, 0)) < 0) {
- retval = i;
- goto out;
- }
- if (STp->can_partitions &&
- (i = switch_partition(STp)) < 0) {
- retval = i;
- goto out;
+ if (cmd_mtiocget && STp->pos_unknown) {
+ /* flush fails -> modify status accordingly */
+ reset_state(STp);
+ STp->pos_unknown = 1;
+ } else { /* return error */
+ retval = i;
+ goto out;
+ }
+ } else { /* flush_buffer succeeds */
+ if (STp->can_partitions) {
+ i = switch_partition(STp);
+ if (i < 0) {
+ retval = i;
+ goto out;
+ }
+ }
}
- if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
+ if (cmd_mtiocget) {
struct mtget mt_status;
if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
@@ -3570,7 +3878,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
mt_status.mt_blkno = STps->drv_block;
mt_status.mt_fileno = STps->drv_file;
- if (STp->block_size != 0) {
+ if (STp->block_size != 0 && mt_status.mt_blkno >= 0) {
if (STps->rw == ST_WRITING)
mt_status.mt_blkno +=
(STp->buffer)->buffer_bytes / STp->block_size;
@@ -3614,14 +3922,11 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
if (STp->cleaning_req)
mt_status.mt_gstat |= GMT_CLN(0xffffffff);
- i = copy_to_user(p, &mt_status, sizeof(struct mtget));
- if (i) {
- retval = (-EFAULT);
+ retval = put_user_mtget(p, &mt_status);
+ if (retval)
goto out;
- }
STp->recover_reg = 0; /* Clear after read */
- retval = 0;
goto out;
} /* End of MTIOCGET */
if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
@@ -3635,53 +3940,27 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
goto out;
}
mt_pos.mt_blkno = blk;
- i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
- if (i)
- retval = (-EFAULT);
- goto out;
- }
- mutex_unlock(&STp->lock);
- switch (cmd_in) {
- case SCSI_IOCTL_GET_IDLUN:
- case SCSI_IOCTL_GET_BUS_NUMBER:
- break;
- default:
- if ((cmd_in == SG_IO ||
- cmd_in == SCSI_IOCTL_SEND_COMMAND ||
- cmd_in == CDROM_SEND_PACKET) &&
- !capable(CAP_SYS_RAWIO))
- i = -EPERM;
- else
- i = scsi_cmd_ioctl(STp->disk->queue, STp->disk,
- file->f_mode, cmd_in, p);
- if (i != -ENOTTY)
- return i;
- break;
- }
- retval = scsi_ioctl(STp->device, cmd_in, p);
- if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { /* unload */
- STp->rew_at_close = 0;
- STp->ready = ST_NO_TAPE;
+ retval = put_user_mtpos(p, &mt_pos);
}
- return retval;
-
out:
mutex_unlock(&STp->lock);
return retval;
}
#ifdef CONFIG_COMPAT
-static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
{
- struct scsi_tape *STp = file->private_data;
- struct scsi_device *sdev = STp->device;
- int ret = -ENOIOCTLCMD;
- if (sdev->host->hostt->compat_ioctl) {
-
- ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
-
+ /* argument conversion is handled using put_user_mtpos/put_user_mtget */
+ switch (cmd_in) {
+ case MTIOCPOS32:
+ cmd_in = MTIOCPOS;
+ break;
+ case MTIOCGET32:
+ cmd_in = MTIOCGET;
+ break;
}
- return ret;
+
+ return st_ioctl(file, cmd_in, arg);
}
#endif
@@ -3689,22 +3968,21 @@ static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a
/* Try to allocate a new tape buffer. Calling function must not hold
dev_arr_lock. */
-static struct st_buffer *new_tape_buffer(int need_dma, int max_sg)
+static struct st_buffer *new_tape_buffer(int max_sg)
{
struct st_buffer *tb;
- tb = kzalloc(sizeof(struct st_buffer), GFP_ATOMIC);
+ tb = kzalloc(sizeof(struct st_buffer), GFP_KERNEL);
if (!tb) {
printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n");
return NULL;
}
tb->frp_segs = 0;
tb->use_sg = max_sg;
- tb->dma = need_dma;
tb->buffer_size = 0;
- tb->reserved_pages = kzalloc(max_sg * sizeof(struct page *),
- GFP_ATOMIC);
+ tb->reserved_pages = kcalloc(max_sg, sizeof(struct page *),
+ GFP_KERNEL);
if (!tb->reserved_pages) {
kfree(tb);
return NULL;
@@ -3717,9 +3995,9 @@ static struct st_buffer *new_tape_buffer(int need_dma, int max_sg)
/* Try to allocate enough space in the tape buffer */
#define ST_MAX_ORDER 6
-static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dma)
+static int enlarge_buffer(struct st_buffer * STbuffer, int new_size)
{
- int segs, nbr, max_segs, b_size, order, got;
+ int segs, max_segs, b_size, order, got;
gfp_t priority;
if (new_size <= STbuffer->buffer_size)
@@ -3729,13 +4007,8 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm
normalize_buffer(STbuffer); /* Avoid extra segment */
max_segs = STbuffer->use_sg;
- nbr = max_segs - STbuffer->frp_segs;
- if (nbr <= 0)
- return 0;
priority = GFP_KERNEL | __GFP_NOWARN;
- if (need_dma)
- priority |= GFP_DMA;
if (STbuffer->cleared)
priority |= __GFP_ZERO;
@@ -3755,7 +4028,7 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm
if (order == ST_MAX_ORDER)
return 0;
normalize_buffer(STbuffer);
- return enlarge_buffer(STbuffer, new_size, need_dma);
+ return enlarge_buffer(STbuffer, new_size);
}
for (segs = STbuffer->frp_segs, got = STbuffer->buffer_size;
@@ -3928,7 +4201,7 @@ static void validate_options(void)
*/
static int __init st_setup(char *str)
{
- int i, len, ints[5];
+ int i, len, ints[ARRAY_SIZE(parms) + 1];
char *stp;
stp = get_options(str, ARRAY_SIZE(ints), ints);
@@ -4005,6 +4278,7 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
}
cdev->owner = THIS_MODULE;
cdev->ops = &st_fops;
+ STm->cdevs[rew] = cdev;
error = cdev_add(cdev, cdev_devno, 1);
if (error) {
@@ -4013,11 +4287,10 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
pr_err("st%d: Device not attached.\n", dev_num);
goto out_free;
}
- STm->cdevs[rew] = cdev;
i = mode << (4 - ST_NBR_MODE_BITS);
snprintf(name, 10, "%s%s%s", rew ? "n" : "",
- tape->disk->disk_name, st_formats[i]);
+ tape->name, st_formats[i]);
dev = device_create(&st_sysfs_class, &tape->device->sdev_gendev,
cdev_devno, &tape->modes[mode], "%s", name);
@@ -4032,8 +4305,9 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
return 0;
out_free:
cdev_del(STm->cdevs[rew]);
- STm->cdevs[rew] = NULL;
out:
+ STm->cdevs[rew] = NULL;
+ STm->devs[rew] = NULL;
return error;
}
@@ -4071,52 +4345,41 @@ static void remove_cdevs(struct scsi_tape *tape)
static int st_probe(struct device *dev)
{
struct scsi_device *SDp = to_scsi_device(dev);
- struct gendisk *disk = NULL;
struct scsi_tape *tpnt = NULL;
struct st_modedef *STm;
struct st_partstat *STps;
struct st_buffer *buffer;
int i, error;
- char *stp;
if (SDp->type != TYPE_TAPE)
return -ENODEV;
- if ((stp = st_incompatible(SDp))) {
- sdev_printk(KERN_INFO, SDp, "Found incompatible tape\n");
- printk(KERN_INFO "st: The suggested driver is %s.\n", stp);
+ if (st_incompatible(SDp)) {
+ sdev_printk(KERN_INFO, SDp,
+ "OnStream tapes are no longer supported;\n");
+ sdev_printk(KERN_INFO, SDp,
+ "please mail to linux-scsi@vger.kernel.org.\n");
return -ENODEV;
}
+ scsi_autopm_get_device(SDp);
i = queue_max_segments(SDp->request_queue);
if (st_max_sg_segs < i)
i = st_max_sg_segs;
- buffer = new_tape_buffer((SDp->host)->unchecked_isa_dma, i);
+ buffer = new_tape_buffer(i);
if (buffer == NULL) {
- printk(KERN_ERR
- "st: Can't allocate new tape buffer. Device not attached.\n");
+ sdev_printk(KERN_ERR, SDp,
+ "st: Can't allocate new tape buffer. "
+ "Device not attached.\n");
goto out;
}
- disk = alloc_disk(1);
- if (!disk) {
- printk(KERN_ERR "st: out of memory. Device not attached.\n");
- goto out_buffer_free;
- }
-
- tpnt = kzalloc(sizeof(struct scsi_tape), GFP_ATOMIC);
+ tpnt = kzalloc(sizeof(struct scsi_tape), GFP_KERNEL);
if (tpnt == NULL) {
- printk(KERN_ERR "st: Can't allocate device descriptor.\n");
- goto out_put_disk;
+ sdev_printk(KERN_ERR, SDp,
+ "st: Can't allocate device descriptor.\n");
+ goto out_buffer_free;
}
kref_init(&tpnt->kref);
- tpnt->disk = disk;
- disk->private_data = &tpnt->driver;
- disk->queue = SDp->request_queue;
- /* SCSI tape doesn't register this gendisk via add_disk(). Manually
- * take queue reference that release_disk() expects. */
- if (!blk_get_queue(disk->queue))
- goto out_put_disk;
- tpnt->driver = &st_template;
tpnt->device = SDp;
if (SDp->scsi_level <= 2)
@@ -4131,7 +4394,6 @@ static int st_probe(struct device *dev)
tpnt->dirty = 0;
tpnt->in_use = 0;
tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
- tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
tpnt->use_pf = (SDp->scsi_level >= SCSI_2);
tpnt->density = 0;
tpnt->do_auto_lock = ST_AUTO_LOCK;
@@ -4149,7 +4411,8 @@ static int st_probe(struct device *dev)
tpnt->nbr_partitions = 0;
blk_queue_rq_timeout(tpnt->device->request_queue, ST_TIMEOUT);
tpnt->long_timeout = ST_LONG_TIMEOUT;
- tpnt->try_dio = try_direct_io && !SDp->host->unchecked_isa_dma;
+ tpnt->try_dio = try_direct_io;
+ tpnt->first_tur = 1;
for (i = 0; i < ST_NBR_MODES; i++) {
STm = &(tpnt->modes[i]);
@@ -4189,10 +4452,19 @@ static int st_probe(struct device *dev)
idr_preload_end();
if (error < 0) {
pr_warn("st: idr allocation failed: %d\n", error);
- goto out_put_queue;
+ goto out_free_tape;
}
tpnt->index = error;
- sprintf(disk->disk_name, "st%d", tpnt->index);
+ sprintf(tpnt->name, "st%d", tpnt->index);
+ tpnt->stats = kzalloc(sizeof(struct scsi_tape_stats), GFP_KERNEL);
+ if (tpnt->stats == NULL) {
+ sdev_printk(KERN_ERR, SDp,
+ "st: Can't allocate statistics.\n");
+ goto out_idr_remove;
+ }
+
+ tpnt->new_media_ctr = scsi_get_ua_new_media_ctr(SDp);
+ tpnt->por_ctr = scsi_get_ua_por_ctr(SDp);
dev_set_drvdata(dev, tpnt);
@@ -4203,26 +4475,26 @@ static int st_probe(struct device *dev)
scsi_autopm_put_device(SDp);
sdev_printk(KERN_NOTICE, SDp,
- "Attached scsi tape %s\n", tape_name(tpnt));
+ "Attached scsi tape %s\n", tpnt->name);
sdev_printk(KERN_INFO, SDp, "%s: try direct i/o: %s (alignment %d B)\n",
- tape_name(tpnt), tpnt->try_dio ? "yes" : "no",
+ tpnt->name, tpnt->try_dio ? "yes" : "no",
queue_dma_alignment(SDp->request_queue) + 1);
return 0;
out_remove_devs:
remove_cdevs(tpnt);
+ kfree(tpnt->stats);
+out_idr_remove:
spin_lock(&st_index_lock);
idr_remove(&st_index_idr, tpnt->index);
spin_unlock(&st_index_lock);
-out_put_queue:
- blk_put_queue(disk->queue);
-out_put_disk:
- put_disk(disk);
+out_free_tape:
kfree(tpnt);
out_buffer_free:
kfree(buffer);
out:
+ scsi_autopm_put_device(SDp);
return -ENODEV;
};
@@ -4256,7 +4528,6 @@ static int st_remove(struct device *dev)
static void scsi_tape_release(struct kref *kref)
{
struct scsi_tape *tpnt = to_scsi_tape(kref);
- struct gendisk *disk = tpnt->disk;
tpnt->device = NULL;
@@ -4266,15 +4537,14 @@ static void scsi_tape_release(struct kref *kref)
kfree(tpnt->buffer);
}
- disk->private_data = NULL;
- put_disk(disk);
+ kfree(tpnt->stats);
kfree(tpnt);
return;
}
-static struct class st_sysfs_class = {
+static const struct class st_sysfs_class = {
.name = "scsi_tape",
- .dev_attrs = st_dev_attrs,
+ .dev_groups = st_dev_groups,
};
static int __init init_st(void)
@@ -4286,6 +4556,12 @@ static int __init init_st(void)
printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n",
verstr, st_fixed_buffer_size, st_max_sg_segs);
+ debugging = (debug_flag > 0) ? debug_flag : NO_DEBUG;
+ if (debugging) {
+ printk(KERN_INFO "st: Debugging enabled debug_flag = %d\n",
+ debugging);
+ }
+
err = class_register(&st_sysfs_class);
if (err) {
pr_err("Unable register sysfs class for SCSI tapes\n");
@@ -4304,14 +4580,8 @@ static int __init init_st(void)
if (err)
goto err_chrdev;
- err = do_create_sysfs_files();
- if (err)
- goto err_scsidrv;
-
return 0;
-err_scsidrv:
- scsi_unregister_driver(&st_template.gendrv);
err_chrdev:
unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
ST_MAX_TAPE_ENTRIES);
@@ -4322,11 +4592,11 @@ err_class:
static void __exit exit_st(void)
{
- do_remove_sysfs_files();
scsi_unregister_driver(&st_template.gendrv);
unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
ST_MAX_TAPE_ENTRIES);
class_unregister(&st_sysfs_class);
+ idr_destroy(&st_index_idr);
printk(KERN_INFO "st: Unloaded.\n");
}
@@ -4335,68 +4605,68 @@ module_exit(exit_st);
/* The sysfs driver interface. Read-only at the moment */
-static ssize_t st_try_direct_io_show(struct device_driver *ddp, char *buf)
+static ssize_t try_direct_io_show(struct device_driver *ddp, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", try_direct_io);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", try_direct_io);
}
-static DRIVER_ATTR(try_direct_io, S_IRUGO, st_try_direct_io_show, NULL);
+static DRIVER_ATTR_RO(try_direct_io);
-static ssize_t st_fixed_buffer_size_show(struct device_driver *ddp, char *buf)
+static ssize_t fixed_buffer_size_show(struct device_driver *ddp, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", st_fixed_buffer_size);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", st_fixed_buffer_size);
}
-static DRIVER_ATTR(fixed_buffer_size, S_IRUGO, st_fixed_buffer_size_show, NULL);
+static DRIVER_ATTR_RO(fixed_buffer_size);
-static ssize_t st_max_sg_segs_show(struct device_driver *ddp, char *buf)
+static ssize_t max_sg_segs_show(struct device_driver *ddp, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", st_max_sg_segs);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", st_max_sg_segs);
}
-static DRIVER_ATTR(max_sg_segs, S_IRUGO, st_max_sg_segs_show, NULL);
+static DRIVER_ATTR_RO(max_sg_segs);
-static ssize_t st_version_show(struct device_driver *ddd, char *buf)
+static ssize_t version_show(struct device_driver *ddd, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "[%s]\n", verstr);
+ return scnprintf(buf, PAGE_SIZE, "[%s]\n", verstr);
}
-static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL);
+static DRIVER_ATTR_RO(version);
-static int do_create_sysfs_files(void)
+#if DEBUG
+static ssize_t debug_flag_store(struct device_driver *ddp,
+ const char *buf, size_t count)
{
- struct device_driver *sysfs = &st_template.gendrv;
- int err;
-
- err = driver_create_file(sysfs, &driver_attr_try_direct_io);
- if (err)
- return err;
- err = driver_create_file(sysfs, &driver_attr_fixed_buffer_size);
- if (err)
- goto err_try_direct_io;
- err = driver_create_file(sysfs, &driver_attr_max_sg_segs);
- if (err)
- goto err_attr_fixed_buf;
- err = driver_create_file(sysfs, &driver_attr_version);
- if (err)
- goto err_attr_max_sg;
-
- return 0;
-
-err_attr_max_sg:
- driver_remove_file(sysfs, &driver_attr_max_sg_segs);
-err_attr_fixed_buf:
- driver_remove_file(sysfs, &driver_attr_fixed_buffer_size);
-err_try_direct_io:
- driver_remove_file(sysfs, &driver_attr_try_direct_io);
- return err;
+/* We only care what the first byte of the data is the rest is unused.
+ * if it's a '1' we turn on debug and if it's a '0' we disable it. All
+ * other values have -EINVAL returned if they are passed in.
+ */
+ if (count > 0) {
+ if (buf[0] == '0') {
+ debugging = NO_DEBUG;
+ return count;
+ } else if (buf[0] == '1') {
+ debugging = 1;
+ return count;
+ }
+ }
+ return -EINVAL;
}
-static void do_remove_sysfs_files(void)
+static ssize_t debug_flag_show(struct device_driver *ddp, char *buf)
{
- struct device_driver *sysfs = &st_template.gendrv;
-
- driver_remove_file(sysfs, &driver_attr_version);
- driver_remove_file(sysfs, &driver_attr_max_sg_segs);
- driver_remove_file(sysfs, &driver_attr_fixed_buffer_size);
- driver_remove_file(sysfs, &driver_attr_try_direct_io);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", debugging);
}
+static DRIVER_ATTR_RW(debug_flag);
+#endif
+
+static struct attribute *st_drv_attrs[] = {
+ &driver_attr_try_direct_io.attr,
+ &driver_attr_fixed_buffer_size.attr,
+ &driver_attr_max_sg_segs.attr,
+ &driver_attr_version.attr,
+#if DEBUG
+ &driver_attr_debug_flag.attr,
+#endif
+ NULL,
+};
+ATTRIBUTE_GROUPS(st_drv);
/* The sysfs simple class interface */
static ssize_t
@@ -4408,6 +4678,7 @@ defined_show(struct device *dev, struct device_attribute *attr, char *buf)
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->defined);
return l;
}
+static DEVICE_ATTR_RO(defined);
static ssize_t
default_blksize_show(struct device *dev, struct device_attribute *attr,
@@ -4419,7 +4690,7 @@ default_blksize_show(struct device *dev, struct device_attribute *attr,
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_blksize);
return l;
}
-
+static DEVICE_ATTR_RO(default_blksize);
static ssize_t
default_density_show(struct device *dev, struct device_attribute *attr,
@@ -4433,6 +4704,7 @@ default_density_show(struct device *dev, struct device_attribute *attr,
l = snprintf(buf, PAGE_SIZE, fmt, STm->default_density);
return l;
}
+static DEVICE_ATTR_RO(default_density);
static ssize_t
default_compression_show(struct device *dev, struct device_attribute *attr,
@@ -4444,6 +4716,7 @@ default_compression_show(struct device *dev, struct device_attribute *attr,
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_compression - 1);
return l;
}
+static DEVICE_ATTR_RO(default_compression);
static ssize_t
options_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -4472,14 +4745,241 @@ options_show(struct device *dev, struct device_attribute *attr, char *buf)
l = snprintf(buf, PAGE_SIZE, "0x%08x\n", options);
return l;
}
+static DEVICE_ATTR_RO(options);
+
+/**
+ * position_lost_in_reset_show - Value 1 indicates that reads, writes, etc.
+ * are blocked because a device reset has occurred and no operation positioning
+ * the tape has been issued.
+ * @dev: struct device
+ * @attr: attribute structure
+ * @buf: buffer to return formatted data in
+ */
+static ssize_t position_lost_in_reset_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct st_modedef *STm = dev_get_drvdata(dev);
+ struct scsi_tape *STp = STm->tape;
-static struct device_attribute st_dev_attrs[] = {
- __ATTR_RO(defined),
- __ATTR_RO(default_blksize),
- __ATTR_RO(default_density),
- __ATTR_RO(default_compression),
- __ATTR_RO(options),
- __ATTR_NULL,
+ return sprintf(buf, "%d", STp->pos_unknown);
+}
+static DEVICE_ATTR_RO(position_lost_in_reset);
+
+/* Support for tape stats */
+
+/**
+ * read_cnt_show - return read count - count of reads made from tape drive
+ * @dev: struct device
+ * @attr: attribute structure
+ * @buf: buffer to return formatted data in
+ */
+static ssize_t read_cnt_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct st_modedef *STm = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lld",
+ (long long)atomic64_read(&STm->tape->stats->read_cnt));
+}
+static DEVICE_ATTR_RO(read_cnt);
+
+/**
+ * read_byte_cnt_show - return read byte count - tape drives
+ * may use blocks less than 512 bytes this gives the raw byte count of
+ * of data read from the tape drive.
+ * @dev: struct device
+ * @attr: attribute structure
+ * @buf: buffer to return formatted data in
+ */
+static ssize_t read_byte_cnt_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct st_modedef *STm = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lld",
+ (long long)atomic64_read(&STm->tape->stats->read_byte_cnt));
+}
+static DEVICE_ATTR_RO(read_byte_cnt);
+
+/**
+ * read_ns_show - return read ns - overall time spent waiting on reads in ns.
+ * @dev: struct device
+ * @attr: attribute structure
+ * @buf: buffer to return formatted data in
+ */
+static ssize_t read_ns_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct st_modedef *STm = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lld",
+ (long long)atomic64_read(&STm->tape->stats->tot_read_time));
+}
+static DEVICE_ATTR_RO(read_ns);
+
+/**
+ * write_cnt_show - write count - number of user calls
+ * to write(2) that have written data to tape.
+ * @dev: struct device
+ * @attr: attribute structure
+ * @buf: buffer to return formatted data in
+ */
+static ssize_t write_cnt_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct st_modedef *STm = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lld",
+ (long long)atomic64_read(&STm->tape->stats->write_cnt));
+}
+static DEVICE_ATTR_RO(write_cnt);
+
+/**
+ * write_byte_cnt_show - write byte count - raw count of
+ * bytes written to tape.
+ * @dev: struct device
+ * @attr: attribute structure
+ * @buf: buffer to return formatted data in
+ */
+static ssize_t write_byte_cnt_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct st_modedef *STm = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lld",
+ (long long)atomic64_read(&STm->tape->stats->write_byte_cnt));
+}
+static DEVICE_ATTR_RO(write_byte_cnt);
+
+/**
+ * write_ns_show - write ns - number of nanoseconds waiting on write
+ * requests to complete.
+ * @dev: struct device
+ * @attr: attribute structure
+ * @buf: buffer to return formatted data in
+ */
+static ssize_t write_ns_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct st_modedef *STm = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lld",
+ (long long)atomic64_read(&STm->tape->stats->tot_write_time));
+}
+static DEVICE_ATTR_RO(write_ns);
+
+/**
+ * in_flight_show - number of I/Os currently in flight -
+ * in most cases this will be either 0 or 1. It may be higher if someone
+ * has also issued other SCSI commands such as via an ioctl.
+ * @dev: struct device
+ * @attr: attribute structure
+ * @buf: buffer to return formatted data in
+ */
+static ssize_t in_flight_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct st_modedef *STm = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lld",
+ (long long)atomic64_read(&STm->tape->stats->in_flight));
+}
+static DEVICE_ATTR_RO(in_flight);
+
+/**
+ * io_ns_show - io wait ns - this is the number of ns spent
+ * waiting on all I/O to complete. This includes tape movement commands
+ * such as rewinding, seeking to end of file or tape, it also includes
+ * read and write. To determine the time spent on tape movement
+ * subtract the read and write ns from this value.
+ * @dev: struct device
+ * @attr: attribute structure
+ * @buf: buffer to return formatted data in
+ */
+static ssize_t io_ns_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct st_modedef *STm = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lld",
+ (long long)atomic64_read(&STm->tape->stats->tot_io_time));
+}
+static DEVICE_ATTR_RO(io_ns);
+
+/**
+ * other_cnt_show - other io count - this is the number of
+ * I/O requests other than read and write requests.
+ * Typically these are tape movement requests but will include driver
+ * tape movement. This includes only requests issued by the st driver.
+ * @dev: struct device
+ * @attr: attribute structure
+ * @buf: buffer to return formatted data in
+ */
+static ssize_t other_cnt_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct st_modedef *STm = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lld",
+ (long long)atomic64_read(&STm->tape->stats->other_cnt));
+}
+static DEVICE_ATTR_RO(other_cnt);
+
+/**
+ * resid_cnt_show - A count of the number of times we get a residual
+ * count - this should indicate someone issuing reads larger than the
+ * block size on tape.
+ * @dev: struct device
+ * @attr: attribute structure
+ * @buf: buffer to return formatted data in
+ */
+static ssize_t resid_cnt_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct st_modedef *STm = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lld",
+ (long long)atomic64_read(&STm->tape->stats->resid_cnt));
+}
+static DEVICE_ATTR_RO(resid_cnt);
+
+static struct attribute *st_dev_attrs[] = {
+ &dev_attr_defined.attr,
+ &dev_attr_default_blksize.attr,
+ &dev_attr_default_density.attr,
+ &dev_attr_default_compression.attr,
+ &dev_attr_options.attr,
+ &dev_attr_position_lost_in_reset.attr,
+ NULL,
+};
+
+static struct attribute *st_stats_attrs[] = {
+ &dev_attr_read_cnt.attr,
+ &dev_attr_read_byte_cnt.attr,
+ &dev_attr_read_ns.attr,
+ &dev_attr_write_cnt.attr,
+ &dev_attr_write_byte_cnt.attr,
+ &dev_attr_write_ns.attr,
+ &dev_attr_in_flight.attr,
+ &dev_attr_io_ns.attr,
+ &dev_attr_other_cnt.attr,
+ &dev_attr_resid_cnt.attr,
+ NULL,
+};
+
+static struct attribute_group stats_group = {
+ .name = "stats",
+ .attrs = st_stats_attrs,
+};
+
+static struct attribute_group st_group = {
+ .attrs = st_dev_attrs,
+};
+
+static const struct attribute_group *st_dev_groups[] = {
+ &st_group,
+ &stats_group,
+ NULL,
};
/* The following functions may be useful for a larger audience. */
@@ -4490,7 +4990,7 @@ static int sgl_map_user_pages(struct st_buffer *STbp,
unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
unsigned long start = uaddr >> PAGE_SHIFT;
const int nr_pages = end - start;
- int res, i, j;
+ int res, i;
struct page **pages;
struct rq_map_data *mdata = &STbp->map_data;
@@ -4506,22 +5006,14 @@ static int sgl_map_user_pages(struct st_buffer *STbp,
if (count == 0)
return 0;
- if ((pages = kmalloc(max_pages * sizeof(*pages), GFP_KERNEL)) == NULL)
+ pages = kmalloc_array(max_pages, sizeof(*pages), GFP_KERNEL);
+ if (pages == NULL)
return -ENOMEM;
/* Try to fault in all of the necessary pages */
- down_read(&current->mm->mmap_sem);
/* rw==READ means read from drive, write into memory area */
- res = get_user_pages(
- current,
- current->mm,
- uaddr,
- nr_pages,
- rw == READ,
- 0, /* don't force */
- pages,
- NULL);
- up_read(&current->mm->mmap_sem);
+ res = pin_user_pages_fast(uaddr, nr_pages, rw == READ ? FOLL_WRITE : 0,
+ pages);
/* Errors and no page mapped should return here */
if (res < nr_pages)
@@ -4540,8 +5032,7 @@ static int sgl_map_user_pages(struct st_buffer *STbp,
return nr_pages;
out_unmap:
if (res > 0) {
- for (j=0; j < res; j++)
- page_cache_release(pages[j]);
+ unpin_user_pages(pages, res);
res = 0;
}
kfree(pages);
@@ -4553,18 +5044,9 @@ static int sgl_map_user_pages(struct st_buffer *STbp,
static int sgl_unmap_user_pages(struct st_buffer *STbp,
const unsigned int nr_pages, int dirtied)
{
- int i;
+ /* FIXME: cache flush missing for rw==READ */
+ unpin_user_pages_dirty_lock(STbp->mapped_pages, nr_pages, dirtied);
- for (i=0; i < nr_pages; i++) {
- struct page *page = STbp->mapped_pages[i];
-
- if (dirtied)
- SetPageDirty(page);
- /* FIXME: cache flush missing for rw==READ
- * FIXME: call the correct reference counting function
- */
- page_cache_release(page);
- }
kfree(STbp->mapped_pages);
STbp->mapped_pages = NULL;