Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
Michael Schaefer, J"org Weule, and Eric Youngdale.
- Copyright 1992 - 2004 Kai Makisara
+ Copyright 1992 - 2005 Kai Makisara
email Kai.Makisara@kolumbus.fi
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
-static char *verstr = "20040403";
+static const char *verstr = "20050830";
#include <linux/module.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/mtio.h>
+#include <linux/cdrom.h>
#include <linux/ioctl.h>
#include <linux/fcntl.h>
#include <linux/spinlock.h>
#include <linux/moduleparam.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+
#include <asm/uaccess.h>
#include <asm/dma.h>
#include <asm/system.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/sg.h>
+
+
/* The driver prints some debugging information on the console if DEBUG
is defined and non-zero. */
#define DEBUG 0
#define DEBC(a)
#endif
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-
-#include <scsi/scsi_driver.h>
-#include <scsi/scsi_ioctl.h>
-
#define ST_KILOBYTE 1024
#include "st_options.h"
static int buffer_kbs;
static int max_sg_segs;
static int try_direct_io = TRY_DIRECT_IO;
-static int try_rdio = TRUE;
-static int try_wdio = TRUE;
+static int try_rdio = 1;
+static int try_wdio = 1;
static int st_dev_max;
static int st_nr_dev;
-static struct class_simple *st_sysfs_class;
+static struct class *st_sysfs_class;
MODULE_AUTHOR("Kai Makisara");
MODULE_DESCRIPTION("SCSI Tape Driver");
#endif
/* Bit reversed order to get same names for same minors with all
mode counts */
-static char *st_formats[] = {
+static const char *st_formats[] = {
"", "r", "k", "s", "l", "t", "o", "u",
"m", "v", "p", "x", "a", "y", "q", "z"};
#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
#endif
-DEB( static int debugging = DEBUG; )
+static int debugging = DEBUG;
#define MAX_RETRIES 0
#define MAX_WRITE_RETRIES 0
24 bits) */
#define SET_DENS_AND_BLK 0x10001
-static rwlock_t st_dev_arr_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(st_dev_arr_lock);
static int st_fixed_buffer_size = ST_FIXED_BUFFER_SIZE;
static int st_max_sg_segs = ST_MAX_SG;
-static Scsi_Tape **scsi_tapes = NULL;
+static struct scsi_tape **scsi_tapes = NULL;
static int modes_defined;
-static ST_buffer *new_tape_buffer(int, int, int);
-static int enlarge_buffer(ST_buffer *, int, int);
-static void normalize_buffer(ST_buffer *);
-static int append_to_buffer(const char *, ST_buffer *, int);
-static int from_buffer(ST_buffer *, char *, int);
-static void move_buffer_data(ST_buffer *, int);
-static void buf_to_sg(ST_buffer *, unsigned int);
+static struct st_buffer *new_tape_buffer(int, int, int);
+static int enlarge_buffer(struct st_buffer *, int, int);
+static void normalize_buffer(struct st_buffer *);
+static int append_to_buffer(const char __user *, struct st_buffer *, int);
+static int from_buffer(struct st_buffer *, char __user *, int);
+static void move_buffer_data(struct st_buffer *, int);
+static void buf_to_sg(struct st_buffer *, unsigned int);
-static int st_map_user_pages(struct scatterlist *, const unsigned int,
- unsigned long, size_t, int, unsigned long);
static int sgl_map_user_pages(struct scatterlist *, const unsigned int,
unsigned long, size_t, int);
static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int);
static int st_probe(struct device *);
static int st_remove(struct device *);
-static int st_init_command(struct scsi_cmnd *);
static void do_create_driverfs_files(void);
static void do_remove_driverfs_files(void);
-static void do_create_class_files(Scsi_Tape *, int, int);
+static void do_create_class_files(struct scsi_tape *, int, int);
static struct scsi_driver st_template = {
.owner = THIS_MODULE,
.probe = st_probe,
.remove = st_remove,
},
- .init_command = st_init_command,
};
-static int st_compression(Scsi_Tape *, int);
+static int st_compression(struct scsi_tape *, int);
+
+static int find_partition(struct scsi_tape *);
+static int switch_partition(struct scsi_tape *);
-static int find_partition(Scsi_Tape *);
-static int switch_partition(Scsi_Tape *);
+static int st_int_ioctl(struct scsi_tape *, unsigned int, unsigned long);
-static int st_int_ioctl(Scsi_Tape *, unsigned int, unsigned long);
+static void scsi_tape_release(struct kref *);
+
+#define to_scsi_tape(obj) container_of(obj, struct scsi_tape, kref)
+
+static DEFINE_MUTEX(st_ref_mutex);
\f
#include "osst_detect.h"
{"OnStream", "FW-", "", "osst"}
#endif
+static struct scsi_tape *scsi_tape_get(int dev)
+{
+ struct scsi_tape *STp = NULL;
+
+ mutex_lock(&st_ref_mutex);
+ write_lock(&st_dev_arr_lock);
+
+ if (dev < st_dev_max && scsi_tapes != NULL)
+ STp = scsi_tapes[dev];
+ if (!STp) goto out;
+
+ kref_get(&STp->kref);
+
+ if (!STp->device)
+ goto out_put;
+
+ if (scsi_device_get(STp->device))
+ goto out_put;
+
+ goto out;
+
+out_put:
+ kref_put(&STp->kref, scsi_tape_release);
+ STp = NULL;
+out:
+ write_unlock(&st_dev_arr_lock);
+ mutex_unlock(&st_ref_mutex);
+ return STp;
+}
+
+static void scsi_tape_put(struct scsi_tape *STp)
+{
+ struct scsi_device *sdev = STp->device;
+
+ mutex_lock(&st_ref_mutex);
+ kref_put(&STp->kref, scsi_tape_release);
+ scsi_device_put(sdev);
+ mutex_unlock(&st_ref_mutex);
+}
+
struct st_reject_data {
char *vendor;
char *model;
/* If the device signature is on the list of incompatible drives, the
function returns a pointer to the name of the correct driver (if known) */
-static char * st_incompatible(Scsi_Device* SDp)
+static char * st_incompatible(struct scsi_device* SDp)
{
struct st_reject_data *rp;
}
\f
-static inline char *tape_name(Scsi_Tape *tape)
+static inline char *tape_name(struct scsi_tape *tape)
{
return tape->disk->disk_name;
}
+
+static void st_analyze_sense(struct st_request *SRpnt, struct st_cmdstatus *s)
+{
+ const u8 *ucp;
+ const u8 *sense = SRpnt->sense;
+
+ s->have_sense = scsi_normalize_sense(SRpnt->sense,
+ SCSI_SENSE_BUFFERSIZE, &s->sense_hdr);
+ s->flags = 0;
+
+ if (s->have_sense) {
+ s->deferred = 0;
+ s->remainder_valid =
+ scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64);
+ switch (sense[0] & 0x7f) {
+ case 0x71:
+ s->deferred = 1;
+ case 0x70:
+ s->fixed_format = 1;
+ s->flags = sense[2] & 0xe0;
+ break;
+ case 0x73:
+ s->deferred = 1;
+ case 0x72:
+ s->fixed_format = 0;
+ ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
+ s->flags = ucp ? (ucp[3] & 0xe0) : 0;
+ break;
+ }
+ }
+}
+
+
/* Convert the result to success code */
-static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt)
+static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
{
- int result = SRpnt->sr_result;
- unsigned char *sense = SRpnt->sr_sense_buffer, scode;
+ int result = SRpnt->result;
+ u8 scode;
DEB(const char *stp;)
char *name = tape_name(STp);
+ struct st_cmdstatus *cmdstatp;
- if (!result) {
- sense[0] = 0; /* We don't have sense data if this byte is zero */
+ if (!result)
return 0;
- }
- if ((driver_byte(result) & DRIVER_MASK) == DRIVER_SENSE)
- scode = sense[2] & 0x0f;
- else {
- sense[0] = 0;
+ cmdstatp = &STp->buffer->cmdstat;
+ st_analyze_sense(SRpnt, cmdstatp);
+
+ if (cmdstatp->have_sense)
+ scode = STp->buffer->cmdstat.sense_hdr.sense_key;
+ else
scode = 0;
- }
DEB(
if (debugging) {
- printk(ST_DEB_MSG "%s: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
+ printk(ST_DEB_MSG "%s: Error: %x, cmd: %x %x %x %x %x %x\n",
name, result,
- SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],
- SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],
- SRpnt->sr_bufflen);
- if (driver_byte(result) & DRIVER_SENSE)
- print_req_sense("st", SRpnt);
- } else ) /* end DEB */
- if (!(driver_byte(result) & DRIVER_SENSE) ||
- ((sense[0] & 0x70) == 0x70 &&
- scode != NO_SENSE &&
- scode != RECOVERED_ERROR &&
- /* scode != UNIT_ATTENTION && */
- scode != BLANK_CHECK &&
- scode != VOLUME_OVERFLOW &&
- SRpnt->sr_cmnd[0] != MODE_SENSE &&
- SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
- if (driver_byte(result) & DRIVER_SENSE) {
- printk(KERN_WARNING "%s: Error with sense data: ", name);
- print_req_sense("st", SRpnt);
- } else
+ 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("st", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
+ } ) /* end DEB */
+ if (!debugging) { /* Abnormal conditions for tape */
+ if (!cmdstatp->have_sense)
printk(KERN_WARNING
"%s: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
name, result, suggestion(result),
- driver_byte(result) & DRIVER_MASK, host_byte(result));
+ driver_byte(result) & DRIVER_MASK, host_byte(result));
+ else if (cmdstatp->have_sense &&
+ scode != NO_SENSE &&
+ scode != RECOVERED_ERROR &&
+ /* scode != UNIT_ATTENTION && */
+ scode != BLANK_CHECK &&
+ scode != VOLUME_OVERFLOW &&
+ SRpnt->cmd[0] != MODE_SENSE &&
+ SRpnt->cmd[0] != TEST_UNIT_READY) {
+ printk(KERN_WARNING "%s: Error with sense data: ", name);
+ __scsi_print_sense("st", SRpnt->sense,
+ SCSI_SENSE_BUFFERSIZE);
+ }
}
- if (STp->cln_mode >= EXTENDED_SENSE_START) {
+ if (cmdstatp->fixed_format &&
+ STp->cln_mode >= EXTENDED_SENSE_START) { /* Only fixed format sense */
if (STp->cln_sense_value)
- STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] &
+ STp->cleaning_req |= ((SRpnt->sense[STp->cln_mode] &
STp->cln_sense_mask) == STp->cln_sense_value);
else
- STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] &
+ STp->cleaning_req |= ((SRpnt->sense[STp->cln_mode] &
STp->cln_sense_mask) != 0);
}
- if (sense[12] == 0 && sense[13] == 0x17) /* ASC and ASCQ => cleaning requested */
- STp->cleaning_req = 1;
+ 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 ((sense[0] & 0x70) == 0x70 &&
+ if (cmdstatp->have_sense &&
scode == RECOVERED_ERROR
#if ST_RECOVERED_WRITE_FATAL
- && SRpnt->sr_cmnd[0] != WRITE_6
- && SRpnt->sr_cmnd[0] != WRITE_FILEMARKS
+ && SRpnt->cmd[0] != WRITE_6
+ && SRpnt->cmd[0] != WRITE_FILEMARKS
#endif
) {
STp->recover_count++;
DEB(
if (debugging) {
- if (SRpnt->sr_cmnd[0] == READ_6)
+ if (SRpnt->cmd[0] == READ_6)
stp = "read";
- else if (SRpnt->sr_cmnd[0] == WRITE_6)
+ else if (SRpnt->cmd[0] == WRITE_6)
stp = "write";
else
stp = "ioctl";
STp->recover_count);
} ) /* end DEB */
- if ((sense[2] & 0xe0) == 0)
+ if (cmdstatp->flags == 0)
return 0;
}
return (-EIO);
/* Wakeup from interrupt */
-static void st_sleep_done(Scsi_Cmnd * SCpnt)
+static void st_sleep_done(void *data, char *sense, int result, int resid)
{
- int remainder;
- Scsi_Tape *STp = container_of(SCpnt->request->rq_disk->private_data,
- Scsi_Tape, driver);
-
- if ((STp->buffer)->writing &&
- (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
- (SCpnt->sense_buffer[2] & 0x40)) {
- /* EOM at write-behind, has all been written? */
- if ((SCpnt->sense_buffer[0] & 0x80) != 0)
- remainder = (SCpnt->sense_buffer[3] << 24) |
- (SCpnt->sense_buffer[4] << 16) |
- (SCpnt->sense_buffer[5] << 8) |
- SCpnt->sense_buffer[6];
- else
- remainder = 0;
- if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW ||
- remainder > 0)
- (STp->buffer)->midlevel_result = SCpnt->result; /* Error */
- else
- (STp->buffer)->midlevel_result = INT_MAX; /* OK */
- } else
- (STp->buffer)->midlevel_result = SCpnt->result;
- SCpnt->request->rq_status = RQ_SCSI_DONE;
- (STp->buffer)->last_SRpnt = SCpnt->sc_request;
+ struct st_request *SRpnt = data;
+ struct scsi_tape *STp = SRpnt->stp;
+
+ memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE);
+ (STp->buffer)->cmdstat.midlevel_result = SRpnt->result = result;
DEB( STp->write_pending = 0; )
- complete(SCpnt->request->waiting);
+ if (SRpnt->waiting)
+ complete(SRpnt->waiting);
+}
+
+static struct st_request *st_allocate_request(void)
+{
+ return kzalloc(sizeof(struct st_request), GFP_KERNEL);
+}
+
+static void st_release_request(struct st_request *streq)
+{
+ kfree(streq);
}
/* Do the scsi command. Waits until command performed if do_wait is true.
Otherwise write_behind_check() is used to check that the command
has finished. */
-static Scsi_Request *
- st_do_scsi(Scsi_Request * SRpnt, Scsi_Tape * STp, unsigned char *cmd, int bytes,
- int direction, int timeout, int retries, int do_wait)
+static struct st_request *
+st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd,
+ int bytes, int direction, int timeout, int retries, int do_wait)
{
- unsigned char *bp;
+ struct completion *waiting;
+
+ /* 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));
+ if (signal_pending(current))
+ (STp->buffer)->syscall_result = (-EINTR);
+ else
+ (STp->buffer)->syscall_result = (-EBUSY);
+ return NULL;
+ }
if (SRpnt == NULL) {
- SRpnt = scsi_allocate_request(STp->device, GFP_ATOMIC);
+ SRpnt = st_allocate_request();
if (SRpnt == NULL) {
DEBC( printk(KERN_ERR "%s: Can't get SCSI request.\n",
tape_name(STp)); );
(STp->buffer)->syscall_result = (-EBUSY);
return NULL;
}
+ SRpnt->stp = STp;
}
- init_completion(&STp->wait);
- SRpnt->sr_use_sg = STp->buffer->do_dio || (bytes > (STp->buffer)->frp[0].length);
- if (SRpnt->sr_use_sg) {
- if (!STp->buffer->do_dio)
- buf_to_sg(STp->buffer, bytes);
- SRpnt->sr_use_sg = (STp->buffer)->sg_segs;
- bp = (char *) &((STp->buffer)->sg[0]);
- } else
- bp = (STp->buffer)->b_data;
- SRpnt->sr_data_direction = direction;
- SRpnt->sr_cmd_len = 0;
- SRpnt->sr_request->waiting = &(STp->wait);
- SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
- SRpnt->sr_request->rq_disk = STp->disk;
-
- scsi_do_req(SRpnt, (void *) cmd, bp, bytes,
- st_sleep_done, timeout, retries);
-
- if (do_wait) {
- wait_for_completion(SRpnt->sr_request->waiting);
- SRpnt->sr_request->waiting = NULL;
+ /* If async IO, set last_SRpnt. This ptr tells write_behind_check
+ which IO is outstanding. It's nulled out when the IO completes. */
+ if (!do_wait)
+ (STp->buffer)->last_SRpnt = SRpnt;
+
+ waiting = &STp->wait;
+ init_completion(waiting);
+ SRpnt->waiting = waiting;
+
+ if (!STp->buffer->do_dio)
+ buf_to_sg(STp->buffer, bytes);
+
+ memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd));
+ STp->buffer->cmdstat.have_sense = 0;
+ STp->buffer->syscall_result = 0;
+
+ if (scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), direction,
+ &((STp->buffer)->sg[0]), bytes, (STp->buffer)->sg_segs,
+ timeout, retries, SRpnt, st_sleep_done, GFP_KERNEL)) {
+ /* could not allocate the buffer or request was too large */
+ (STp->buffer)->syscall_result = (-EBUSY);
+ (STp->buffer)->last_SRpnt = NULL;
+ }
+ else if (do_wait) {
+ wait_for_completion(waiting);
+ SRpnt->waiting = NULL;
(STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);
}
+
return SRpnt;
}
-/* Handle the write-behind checking (downs the semaphore) */
-static void write_behind_check(Scsi_Tape * STp)
+/* Handle the write-behind checking (waits for completion). Returns -ENOSPC if
+ write has been correct but EOM early warning reached, -EIO if write ended in
+ error or zero if write successful. Asynchronous writes are used only in
+ variable block mode. */
+static int write_behind_check(struct scsi_tape * STp)
{
- ST_buffer *STbuffer;
- ST_partstat *STps;
+ int retval = 0;
+ struct st_buffer *STbuffer;
+ struct st_partstat *STps;
+ struct st_cmdstatus *cmdstatp;
+ struct st_request *SRpnt;
STbuffer = STp->buffer;
+ if (!STbuffer->writing)
+ return 0;
DEB(
if (STp->write_pending)
) /* end DEB */
wait_for_completion(&(STp->wait));
- (STp->buffer)->last_SRpnt->sr_request->waiting = NULL;
+ SRpnt = STbuffer->last_SRpnt;
+ STbuffer->last_SRpnt = NULL;
+ SRpnt->waiting = NULL;
- (STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt);
- scsi_release_request((STp->buffer)->last_SRpnt);
+ (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);
+ st_release_request(SRpnt);
STbuffer->buffer_bytes -= STbuffer->writing;
STps = &(STp->ps[STp->partition]);
else
STps->drv_block += STbuffer->writing / STp->block_size;
}
+
+ cmdstatp = &STbuffer->cmdstat;
+ if (STbuffer->syscall_result) {
+ retval = -EIO;
+ if (cmdstatp->have_sense && !cmdstatp->deferred &&
+ (cmdstatp->flags & SENSE_EOM) &&
+ (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+ cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR)) {
+ /* EOM at write-behind, has all data been written? */
+ if (!cmdstatp->remainder_valid ||
+ cmdstatp->uremainder64 == 0)
+ retval = -ENOSPC;
+ }
+ if (retval == -EIO)
+ STps->drv_block = -1;
+ }
STbuffer->writing = 0;
- return;
+ 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 */
+
+ return retval;
}
/* Step over EOF if it has been inadvertently crossed (ioctl not used because
it messes up the block number). */
-static int cross_eof(Scsi_Tape * STp, int forward)
+static int cross_eof(struct scsi_tape * STp, int forward)
{
- Scsi_Request *SRpnt;
+ struct st_request *SRpnt;
unsigned char cmd[MAX_COMMAND_SIZE];
cmd[0] = SPACE;
DEBC(printk(ST_DEB_MSG "%s: Stepping over filemark %s.\n",
tape_name(STp), forward ? "forward" : "backward"));
- SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,
- STp->device->timeout, MAX_RETRIES, TRUE);
+ SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
+ STp->device->timeout, MAX_RETRIES, 1);
if (!SRpnt)
return (STp->buffer)->syscall_result;
- scsi_release_request(SRpnt);
+ st_release_request(SRpnt);
SRpnt = NULL;
- if ((STp->buffer)->midlevel_result != 0)
+ if ((STp->buffer)->cmdstat.midlevel_result != 0)
printk(KERN_ERR "%s: Stepping over filemark %s failed.\n",
tape_name(STp), forward ? "forward" : "backward");
/* Flush the write buffer (never need to write if variable blocksize). */
-static int flush_write_buffer(Scsi_Tape * STp)
+static int flush_write_buffer(struct scsi_tape * STp)
{
int offset, transfer, blks;
int result;
unsigned char cmd[MAX_COMMAND_SIZE];
- Scsi_Request *SRpnt;
- ST_partstat *STps;
+ struct st_request *SRpnt;
+ struct st_partstat *STps;
- if ((STp->buffer)->writing) {
- write_behind_check(STp);
- if ((STp->buffer)->syscall_result) {
- DEBC(printk(ST_DEB_MSG
- "%s: Async write error (flush) %x.\n",
- tape_name(STp), (STp->buffer)->midlevel_result))
- if ((STp->buffer)->midlevel_result == INT_MAX)
- return (-ENOSPC);
- return (-EIO);
- }
- }
- if (STp->block_size == 0)
- return 0;
+ result = write_behind_check(STp);
+ if (result)
+ return result;
result = 0;
if (STp->dirty == 1) {
cmd[3] = blks >> 8;
cmd[4] = blks;
- SRpnt = st_do_scsi(NULL, STp, cmd, transfer, SCSI_DATA_WRITE,
- STp->device->timeout, MAX_WRITE_RETRIES, TRUE);
+ SRpnt = st_do_scsi(NULL, STp, cmd, transfer, DMA_TO_DEVICE,
+ STp->device->timeout, MAX_WRITE_RETRIES, 1);
if (!SRpnt)
return (STp->buffer)->syscall_result;
STps = &(STp->ps[STp->partition]);
if ((STp->buffer)->syscall_result != 0) {
- if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
- (SRpnt->sr_sense_buffer[2] & 0x40) &&
- (SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) {
+ struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
+
+ if (cmdstatp->have_sense && !cmdstatp->deferred &&
+ (cmdstatp->flags & SENSE_EOM) &&
+ (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+ cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
+ (!cmdstatp->remainder_valid ||
+ cmdstatp->uremainder64 == 0)) { /* All written at EOM early warning */
STp->dirty = 0;
(STp->buffer)->buffer_bytes = 0;
+ if (STps->drv_block >= 0)
+ STps->drv_block += blks;
result = (-ENOSPC);
} else {
printk(KERN_ERR "%s: Error on flush.\n",
tape_name(STp));
+ STps->drv_block = (-1);
result = (-EIO);
}
- STps->drv_block = (-1);
} else {
if (STps->drv_block >= 0)
STps->drv_block += blks;
STp->dirty = 0;
(STp->buffer)->buffer_bytes = 0;
}
- scsi_release_request(SRpnt);
+ st_release_request(SRpnt);
SRpnt = NULL;
}
return result;
/* Flush the tape buffer. The tape will be positioned correctly unless
seek_next is true. */
-static int flush_buffer(Scsi_Tape *STp, int seek_next)
+static int flush_buffer(struct scsi_tape *STp, int seek_next)
{
int backspace, result;
- ST_buffer *STbuffer;
- ST_partstat *STps;
+ struct st_buffer *STbuffer;
+ struct st_partstat *STps;
STbuffer = STp->buffer;
result = 0;
if (!seek_next) {
if (STps->eof == ST_FM_HIT) {
- result = cross_eof(STp, FALSE); /* Back over the EOF hit */
+ result = cross_eof(STp, 0); /* Back over the EOF hit */
if (!result)
STps->eof = ST_NOEOF;
else {
}
\f
/* Set the mode parameters */
-static int set_mode_densblk(Scsi_Tape * STp, ST_mode * STm)
+static int set_mode_densblk(struct scsi_tape * STp, struct st_modedef * STm)
{
- int set_it = FALSE;
+ int set_it = 0;
unsigned long arg;
char *name = tape_name(STp);
STm->default_density >= 0 &&
STm->default_density != STp->density) {
arg = STm->default_density;
- set_it = TRUE;
+ set_it = 1;
} else
arg = STp->density;
arg <<= MT_ST_DENSITY_SHIFT;
STm->default_blksize >= 0 &&
STm->default_blksize != STp->block_size) {
arg |= STm->default_blksize;
- set_it = TRUE;
+ set_it = 1;
} else
arg |= STp->block_size;
if (set_it &&
}
-/* Lock or unlock the drive door. Don't use when Scsi_Request allocated. */
-static int do_door_lock(Scsi_Tape * STp, int do_lock)
+/* 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);)
/* Set the internal state after reset */
-static void reset_state(Scsi_Tape *STp)
+static void reset_state(struct scsi_tape *STp)
{
int i;
- ST_partstat *STps;
+ struct st_partstat *STps;
STp->pos_unknown = 0;
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
STps->rw = ST_IDLE;
STps->eof = ST_NOEOF;
STps->at_sm = 0;
- STps->last_block_valid = FALSE;
+ STps->last_block_valid = 0;
STps->drv_block = -1;
STps->drv_file = -1;
}
#define MAX_ATTENTIONS 10
-static int test_ready(Scsi_Tape *STp, int do_wait)
+static int test_ready(struct scsi_tape *STp, int do_wait)
{
int attentions, waits, max_wait, scode;
- int retval = CHKRES_READY, new_session = FALSE;
+ int retval = CHKRES_READY, new_session = 0;
unsigned char cmd[MAX_COMMAND_SIZE];
- Scsi_Request *SRpnt = NULL;
+ struct st_request *SRpnt = NULL;
+ struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
max_wait = do_wait ? ST_BLOCK_SECONDS : 0;
for (attentions=waits=0; ; ) {
memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = TEST_UNIT_READY;
- SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
- STp->long_timeout, MAX_READY_RETRIES, TRUE);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
+ STp->long_timeout, MAX_READY_RETRIES, 1);
if (!SRpnt) {
retval = (STp->buffer)->syscall_result;
break;
}
- if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) {
+ if (cmdstatp->have_sense) {
- scode = (SRpnt->sr_sense_buffer[2] & 0x0f);
+ scode = cmdstatp->sense_hdr.sense_key;
if (scode == UNIT_ATTENTION) { /* New media? */
- new_session = TRUE;
+ new_session = 1;
if (attentions < MAX_ATTENTIONS) {
attentions++;
continue;
if (scode == NOT_READY) {
if (waits < max_wait) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ);
- if (signal_pending(current)) {
+ if (msleep_interruptible(1000)) {
retval = (-EINTR);
break;
}
}
else {
if ((STp->device)->scsi_level >= SCSI_2 &&
- SRpnt->sr_sense_buffer[12] == 0x3a) /* Check ASC */
+ cmdstatp->sense_hdr.asc == 0x3a) /* Check ASC */
retval = CHKRES_NO_TAPE;
else
retval = CHKRES_NOT_READY;
}
if (SRpnt != NULL)
- scsi_release_request(SRpnt);
+ st_release_request(SRpnt);
return retval;
}
0 drive ready
1 drive not ready (possibly no tape)
*/
-static int check_tape(Scsi_Tape *STp, struct file *filp)
+static int check_tape(struct scsi_tape *STp, struct file *filp)
{
- int i, retval, new_session = FALSE, do_wait;
+ int i, retval, new_session = 0, do_wait;
unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning;
unsigned short st_flags = filp->f_flags;
- Scsi_Request *SRpnt = NULL;
- ST_mode *STm;
- ST_partstat *STps;
+ struct st_request *SRpnt = NULL;
+ struct st_modedef *STm;
+ struct st_partstat *STps;
char *name = tape_name(STp);
struct inode *inode = filp->f_dentry->d_inode;
int mode = TAPE_MODE(inode);
if (mode != STp->current_mode) {
DEBC(printk(ST_DEB_MSG "%s: Mode change from %d to %d.\n",
name, STp->current_mode, mode));
- new_session = TRUE;
+ new_session = 1;
STp->current_mode = mode;
}
STm = &(STp->modes[STp->current_mode]);
STps->rw = ST_IDLE;
STps->eof = ST_NOEOF;
STps->at_sm = 0;
- STps->last_block_valid = FALSE;
+ STps->last_block_valid = 0;
STps->drv_block = 0;
STps->drv_file = 0;
}
- new_session = TRUE;
+ new_session = 1;
}
else {
STp->cleaning_req |= saved_cleaning;
memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = READ_BLOCK_LIMITS;
- SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, SCSI_DATA_READ, STp->device->timeout,
- MAX_READY_RETRIES, TRUE);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, DMA_FROM_DEVICE,
+ STp->device->timeout, MAX_READY_RETRIES, 1);
if (!SRpnt) {
retval = (STp->buffer)->syscall_result;
goto err_out;
}
- if (!SRpnt->sr_result && !SRpnt->sr_sense_buffer[0]) {
+ if (!SRpnt->result && !STp->buffer->cmdstat.have_sense) {
STp->max_block = ((STp->buffer)->b_data[1] << 16) |
((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
STp->min_block = ((STp->buffer)->b_data[4] << 8) |
cmd[0] = MODE_SENSE;
cmd[4] = 12;
- SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, SCSI_DATA_READ, STp->device->timeout,
- MAX_READY_RETRIES, TRUE);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, DMA_FROM_DEVICE,
+ STp->device->timeout, MAX_READY_RETRIES, 1);
if (!SRpnt) {
retval = (STp->buffer)->syscall_result;
goto err_out;
}
STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
}
- scsi_release_request(SRpnt);
+ st_release_request(SRpnt);
SRpnt = NULL;
- STp->inited = TRUE;
+ STp->inited = 1;
if (STp->block_size > 0)
(STp->buffer)->buffer_blocks =
}
if (new_session) { /* Change the drive parameters for the new mode */
- STp->density_changed = STp->blksize_changed = FALSE;
- STp->compression_changed = FALSE;
+ STp->density_changed = STp->blksize_changed = 0;
+ STp->compression_changed = 0;
if (!(STm->defaults_for_writes) &&
(retval = set_mode_densblk(STp, STm)) < 0)
goto err_out;
static int st_open(struct inode *inode, struct file *filp)
{
int i, retval = (-EIO);
- Scsi_Tape *STp;
- ST_partstat *STps;
+ 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
+ * versions of tar incorrectly call lseek on tapes and bail out if that
+ * fails. So we disallow pread() and pwrite(), but permit lseeks.
+ */
+ filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
+
+ if (!(STp = scsi_tape_get(dev)))
+ return -ENXIO;
+
write_lock(&st_dev_arr_lock);
- if (dev >= st_dev_max || scsi_tapes == NULL ||
- ((STp = scsi_tapes[dev]) == NULL)) {
- write_unlock(&st_dev_arr_lock);
- return (-ENXIO);
- }
filp->private_data = STp;
name = tape_name(STp);
if (STp->in_use) {
write_unlock(&st_dev_arr_lock);
+ scsi_tape_put(STp);
DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); )
return (-EBUSY);
}
- if(scsi_device_get(STp->device)) {
- write_unlock(&st_dev_arr_lock);
- return (-ENXIO);
- }
STp->in_use = 1;
write_unlock(&st_dev_arr_lock);
STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0;
err_out:
normalize_buffer(STp->buffer);
STp->in_use = 0;
- scsi_device_put(STp->device);
+ scsi_tape_put(STp);
return retval;
}
{
int result = 0, result2;
unsigned char cmd[MAX_COMMAND_SIZE];
- Scsi_Request *SRpnt;
- Scsi_Tape *STp = filp->private_data;
- ST_mode *STm = &(STp->modes[STp->current_mode]);
- ST_partstat *STps = &(STp->ps[STp->partition]);
+ struct st_request *SRpnt;
+ 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)
name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable));
if (STps->rw == ST_WRITING && !STp->pos_unknown) {
+ struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
- DEBC(printk(ST_DEB_MSG "%s: File length %ld bytes.\n",
- name, (long) (filp->f_pos));
- printk(ST_DEB_MSG "%s: Async write waits %d, finished %d.\n",
+ DEBC(printk(ST_DEB_MSG "%s: Async write waits %d, finished %d.\n",
name, STp->nbr_waits, STp->nbr_finished);
)
cmd[0] = WRITE_FILEMARKS;
cmd[4] = 1 + STp->two_fm;
- SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,
- STp->device->timeout, MAX_WRITE_RETRIES, TRUE);
+ SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
+ STp->device->timeout, MAX_WRITE_RETRIES, 1);
if (!SRpnt) {
result = (STp->buffer)->syscall_result;
goto out;
}
- if ((STp->buffer)->syscall_result != 0 &&
- ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
- (SRpnt->sr_sense_buffer[2] & 0x4f) != 0x40 ||
- ((SRpnt->sr_sense_buffer[0] & 0x80) != 0 &&
- (SRpnt->sr_sense_buffer[3] | SRpnt->sr_sense_buffer[4] |
- SRpnt->sr_sense_buffer[5] |
- SRpnt->sr_sense_buffer[6]) != 0))) {
- /* Filter out successful write at EOM */
- scsi_release_request(SRpnt);
- SRpnt = NULL;
- printk(KERN_ERR "%s: Error on write filemark.\n", name);
- if (result == 0)
- result = (-EIO);
- } else {
- scsi_release_request(SRpnt);
+ if (STp->buffer->syscall_result == 0 ||
+ (cmdstatp->have_sense && !cmdstatp->deferred &&
+ (cmdstatp->flags & SENSE_EOM) &&
+ (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+ cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
+ (!cmdstatp->remainder_valid || cmdstatp->uremainder64 == 0))) {
+ /* Write successful at EOM */
+ st_release_request(SRpnt);
SRpnt = NULL;
if (STps->drv_file >= 0)
STps->drv_file++;
STps->drv_block = 0;
if (STp->two_fm)
- cross_eof(STp, FALSE);
+ cross_eof(STp, 0);
STps->eof = ST_FM;
}
+ else { /* Write error */
+ st_release_request(SRpnt);
+ SRpnt = NULL;
+ printk(KERN_ERR "%s: Error on write filemark.\n", name);
+ if (result == 0)
+ result = (-EIO);
+ }
DEBC(printk(ST_DEB_MSG "%s: Buffer flushed, %d EOF(s) written\n",
name, cmd[4]));
if (STp->can_bsr)
result = flush_buffer(STp, 0);
else if (STps->eof == ST_FM_HIT) {
- result = cross_eof(STp, FALSE);
+ result = cross_eof(STp, 0);
if (result) {
if (STps->drv_file >= 0)
STps->drv_file++;
STps->eof = ST_NOEOF;
}
} else if ((STps->eof == ST_NOEOF &&
- !(result = cross_eof(STp, TRUE))) ||
+ !(result = cross_eof(STp, 1))) ||
STps->eof == ST_FM_HIT) {
if (STps->drv_file >= 0)
STps->drv_file++;
static int st_release(struct inode *inode, struct file *filp)
{
int result = 0;
- Scsi_Tape *STp = filp->private_data;
+ struct scsi_tape *STp = filp->private_data;
if (STp->door_locked == ST_LOCKED_AUTO)
do_door_lock(STp, 0);
write_lock(&st_dev_arr_lock);
STp->in_use = 0;
write_unlock(&st_dev_arr_lock);
- scsi_device_put(STp->device);
+ scsi_tape_put(STp);
return result;
}
\f
/* The checks common to both reading and writing */
-static ssize_t rw_checks(Scsi_Tape *STp, struct file *filp, size_t count, loff_t *ppos)
+static ssize_t rw_checks(struct scsi_tape *STp, struct file *filp, size_t count)
{
ssize_t retval = 0;
goto out;
}
- if (ppos != &filp->f_pos) {
- /* "A request was outside the capabilities of the device." */
- retval = (-ENXIO);
- goto out;
- }
-
if (STp->ready != ST_READY) {
if (STp->ready == ST_NO_TAPE)
retval = (-ENOMEDIUM);
}
-static int setup_buffering(Scsi_Tape *STp, const char *buf, size_t count, int is_read)
+static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
+ size_t count, int is_read)
{
int i, bufsize, retval = 0;
- ST_buffer *STbp = STp->buffer;
+ struct st_buffer *STbp = STp->buffer;
if (is_read)
i = STp->try_dio && try_rdio;
else
i = STp->try_dio && try_wdio;
+
if (i && ((unsigned long)buf & queue_dma_alignment(
STp->device->request_queue)) == 0) {
- i = st_map_user_pages(&(STbp->sg[0]), STbp->use_sg,
- (unsigned long)buf, count, (is_read ? READ : WRITE),
- STp->max_pfn);
+ i = sgl_map_user_pages(&(STbp->sg[0]), STbp->use_sg,
+ (unsigned long)buf, count, (is_read ? READ : WRITE));
if (i > 0) {
STbp->do_dio = i;
STbp->buffer_bytes = 0; /* can be used as transfer counter */
}
else
- STbp->do_dio = FALSE; /* fall back to buffering with any error */
+ STbp->do_dio = 0; /* fall back to buffering with any error */
STbp->sg_segs = STbp->do_dio;
STbp->frp_sg_current = 0;
DEB(
}
)
} else
- STbp->do_dio = FALSE;
+ STbp->do_dio = 0;
DEB( STp->nbr_requests++; )
if (!STbp->do_dio) {
/* Can be called more than once after each setup_buffer() */
-static void release_buffering(Scsi_Tape *STp)
+static void release_buffering(struct scsi_tape *STp, int is_read)
{
- ST_buffer *STbp;
+ struct st_buffer *STbp;
STbp = STp->buffer;
if (STbp->do_dio) {
- sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, FALSE);
+ sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, is_read);
STbp->do_dio = 0;
+ STbp->sg_segs = 0;
}
}
/* Write command */
static ssize_t
- st_write(struct file *filp, const char *buf, size_t count, loff_t * ppos)
+st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
{
ssize_t total;
ssize_t i, do_count, blks, transfer;
int undone, retry_eot = 0, scode;
int async_write;
unsigned char cmd[MAX_COMMAND_SIZE];
- const char *b_point;
- Scsi_Request *SRpnt = NULL;
- Scsi_Tape *STp = filp->private_data;
- ST_mode *STm;
- ST_partstat *STps;
- ST_buffer *STbp;
+ const char __user *b_point;
+ struct st_request *SRpnt = NULL;
+ struct scsi_tape *STp = filp->private_data;
+ struct st_modedef *STm;
+ struct st_partstat *STps;
+ struct st_buffer *STbp;
char *name = tape_name(STp);
if (down_interruptible(&STp->lock))
return -ERESTARTSYS;
- retval = rw_checks(STp, filp, count, ppos);
+ retval = rw_checks(STp, filp, count);
if (retval || count == 0)
goto out;
}
STbp = STp->buffer;
- if (STbp->writing) {
- write_behind_check(STp);
- if (STbp->syscall_result) {
- DEBC(printk(ST_DEB_MSG "%s: Async write error (write) %x.\n",
- name, STbp->midlevel_result));
- if (STbp->midlevel_result == INT_MAX)
- STps->eof = ST_EOM_OK;
- else
- STps->eof = ST_EOM_ERROR;
- }
+ i = write_behind_check(STp);
+ if (i) {
+ if (i == -ENOSPC)
+ STps->eof = ST_EOM_OK;
+ else
+ STps->eof = ST_EOM_ERROR;
}
if (STps->eof == ST_EOM_OK) {
goto out;
}
- retval = setup_buffering(STp, buf, count, FALSE);
+ retval = setup_buffering(STp, buf, count, 0);
if (retval)
goto out;
}
}
count -= do_count;
- filp->f_pos += do_count;
b_point += do_count;
async_write = STp->block_size == 0 && !STbp->do_dio &&
if (STp->block_size != 0 && STm->do_buffer_writes &&
!(STp->try_dio && try_wdio) && STps->eof < ST_EOM_OK &&
STbp->buffer_bytes < STbp->buffer_size) {
- STp->dirty = TRUE;
+ STp->dirty = 1;
/* Don't write a buffer that is not full enough. */
if (!async_write && count == 0)
break;
cmd[3] = blks >> 8;
cmd[4] = blks;
- SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, DMA_TO_DEVICE,
STp->device->timeout, MAX_WRITE_RETRIES, !async_write);
if (!SRpnt) {
retval = STbp->syscall_result;
goto out;
}
- if (async_write) {
+ if (async_write && !STbp->syscall_result) {
STbp->writing = transfer;
STp->dirty = !(STbp->writing ==
STbp->buffer_bytes);
}
if (STbp->syscall_result != 0) {
+ struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
+
DEBC(printk(ST_DEB_MSG "%s: Error on write:\n", name));
- if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
- (SRpnt->sr_sense_buffer[2] & 0x40)) {
- scode = SRpnt->sr_sense_buffer[2] & 0x0f;
- if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0)
- undone = (SRpnt->sr_sense_buffer[3] << 24) |
- (SRpnt->sr_sense_buffer[4] << 16) |
- (SRpnt->sr_sense_buffer[5] << 8) |
- SRpnt->sr_sense_buffer[6];
+ if (cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) {
+ scode = cmdstatp->sense_hdr.sense_key;
+ if (cmdstatp->remainder_valid)
+ undone = (int)cmdstatp->uremainder64;
else if (STp->block_size == 0 &&
scode == VOLUME_OVERFLOW)
undone = transfer;
undone = 0;
if (STp->block_size != 0)
undone *= STp->block_size;
- filp->f_pos -= undone;
if (undone <= do_count) {
/* Only data from this write is not written */
count += undone;
retval = (-ENOSPC); /* EOM within current request */
DEBC(printk(ST_DEB_MSG
"%s: EOM with %d bytes unwritten.\n",
- name, count));
+ name, (int)count));
} else {
/* EOT within data buffered earlier (possible only
in fixed block mode without direct i/o) */
- if (!retry_eot && (SRpnt->sr_sense_buffer[0] & 1) == 0 &&
+ if (!retry_eot && !cmdstatp->deferred &&
(scode == NO_SENSE || scode == RECOVERED_ERROR)) {
move_buffer_data(STp->buffer, transfer - undone);
- retry_eot = TRUE;
+ retry_eot = 1;
if (STps->drv_block >= 0) {
STps->drv_block += (transfer - undone) /
STp->block_size;
}
}
} else {
- filp->f_pos -= do_count;
count += do_count;
STps->drv_block = (-1); /* Too cautious? */
- retval = (-EIO);
+ retval = STbp->syscall_result;
}
}
out:
if (SRpnt != NULL)
- scsi_release_request(SRpnt);
- release_buffering(STp);
+ st_release_request(SRpnt);
+ release_buffering(STp, 0);
up(&STp->lock);
return retval;
Does release user buffer mapping if it is set.
*/
-static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt)
+static long read_tape(struct scsi_tape *STp, long count,
+ struct st_request ** aSRpnt)
{
int transfer, blks, bytes;
unsigned char cmd[MAX_COMMAND_SIZE];
- Scsi_Request *SRpnt;
- ST_mode *STm;
- ST_partstat *STps;
- ST_buffer *STbp;
+ struct st_request *SRpnt;
+ struct st_modedef *STm;
+ struct st_partstat *STps;
+ struct st_buffer *STbp;
int retval = 0;
char *name = tape_name(STp);
cmd[4] = blks;
SRpnt = *aSRpnt;
- SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, SCSI_DATA_READ,
- STp->device->timeout, MAX_RETRIES, TRUE);
- release_buffering(STp);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, DMA_FROM_DEVICE,
+ STp->device->timeout, MAX_RETRIES, 1);
+ release_buffering(STp, 1);
*aSRpnt = SRpnt;
if (!SRpnt)
return STbp->syscall_result;
/* Something to check */
if (STbp->syscall_result) {
+ 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->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1],
- SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3],
- SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5],
- SRpnt->sr_sense_buffer[6], SRpnt->sr_sense_buffer[7]));
- if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) { /* extended sense */
+ 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 ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
- SRpnt->sr_sense_buffer[2] &= 0xcf; /* No need for EOM in this case */
+ if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
+ cmdstatp->flags &= 0xcf; /* No need for EOM in this case */
- if ((SRpnt->sr_sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
+ if (cmdstatp->flags != 0) { /* EOF, EOM, or ILI */
/* Compute the residual count */
- if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0)
- transfer = (SRpnt->sr_sense_buffer[3] << 24) |
- (SRpnt->sr_sense_buffer[4] << 16) |
- (SRpnt->sr_sense_buffer[5] << 8) |
- SRpnt->sr_sense_buffer[6];
+ if (cmdstatp->remainder_valid)
+ transfer = (int)cmdstatp->uremainder64;
else
transfer = 0;
if (STp->block_size == 0 &&
- (SRpnt->sr_sense_buffer[2] & 0x0f) == MEDIUM_ERROR)
+ cmdstatp->sense_hdr.sense_key == MEDIUM_ERROR)
transfer = bytes;
- if (SRpnt->sr_sense_buffer[2] & 0x20) { /* ILI */
+ if (cmdstatp->flags & SENSE_ILI) { /* ILI */
if (STp->block_size == 0) {
if (transfer <= 0) {
if (transfer < 0)
}
STbp->buffer_bytes = bytes - transfer;
} else {
- scsi_release_request(SRpnt);
+ 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);
if (st_int_ioctl(STp, MTBSR, 1))
return (-EIO);
}
- } else if (SRpnt->sr_sense_buffer[2] & 0x80) { /* FM overrides EOM */
+ } else if (cmdstatp->flags & SENSE_FMK) { /* FM overrides EOM */
if (STps->eof != ST_FM_HIT)
STps->eof = ST_FM_HIT;
else
DEBC(printk(ST_DEB_MSG
"%s: EOF detected (%d bytes read).\n",
name, STbp->buffer_bytes));
- } else if (SRpnt->sr_sense_buffer[2] & 0x40) {
+ } else if (cmdstatp->flags & SENSE_EOM) {
if (STps->eof == ST_FM)
STps->eof = ST_EOD_1;
else
"%s: Tape error while reading.\n", name));
STps->drv_block = (-1);
if (STps->eof == ST_FM &&
- (SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) {
+ cmdstatp->sense_hdr.sense_key == BLANK_CHECK) {
DEBC(printk(ST_DEB_MSG
"%s: Zero returned for first BLANK CHECK after EOF.\n",
name));
/* Read command */
static ssize_t
- st_read(struct file *filp, char *buf, size_t count, loff_t * ppos)
+st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
{
ssize_t total;
ssize_t retval = 0;
ssize_t i, transfer;
int special, do_dio = 0;
- Scsi_Request *SRpnt = NULL;
- Scsi_Tape *STp = filp->private_data;
- ST_mode *STm;
- ST_partstat *STps;
- ST_buffer *STbp = STp->buffer;
+ struct st_request *SRpnt = NULL;
+ struct scsi_tape *STp = filp->private_data;
+ struct st_modedef *STm;
+ struct st_partstat *STps;
+ struct st_buffer *STbp = STp->buffer;
DEB( char *name = tape_name(STp); )
if (down_interruptible(&STp->lock))
return -ERESTARTSYS;
- retval = rw_checks(STp, filp, count, ppos);
+ retval = rw_checks(STp, filp, count);
if (retval || count == 0)
goto out;
STps->eof, STbp->buffer_bytes);
) /* end DEB */
- retval = setup_buffering(STp, buf, count, TRUE);
+ retval = setup_buffering(STp, buf, count, 1);
if (retval)
goto out;
do_dio = STbp->do_dio;
printk(ST_DEB_MSG
"%s: EOF up (%d). Left %d, needed %d.\n", name,
STps->eof, STbp->buffer_bytes,
- count - total);
+ (int)(count - total));
) /* end DEB */
transfer = STbp->buffer_bytes < count - total ?
STbp->buffer_bytes : count - total;
goto out;
}
}
- filp->f_pos += transfer;
buf += transfer;
total += transfer;
}
out:
if (SRpnt != NULL) {
- scsi_release_request(SRpnt);
+ st_release_request(SRpnt);
SRpnt = NULL;
}
if (do_dio) {
- release_buffering(STp);
+ release_buffering(STp, 1);
STbp->buffer_bytes = 0;
}
up(&STp->lock);
DEB(
/* Set the driver options */
-static void st_log_options(Scsi_Tape * STp, ST_mode * STm, char *name)
+static void st_log_options(struct scsi_tape * STp, struct st_modedef * STm, char *name)
{
if (debugging) {
printk(KERN_INFO
)
-static int st_set_options(Scsi_Tape *STp, long options)
+static int st_set_options(struct scsi_tape *STp, long options)
{
int value;
long code;
- ST_mode *STm;
+ struct st_modedef *STm;
char *name = tape_name(STp);
struct cdev *cd0, *cd1;
STm = &(STp->modes[STp->current_mode]);
if (!STm->defined) {
cd0 = STm->cdevs[0]; cd1 = STm->cdevs[1];
- memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
+ memcpy(STm, &(STp->modes[0]), sizeof(struct st_modedef));
STm->cdevs[0] = cd0; STm->cdevs[1] = cd1;
- modes_defined = TRUE;
+ modes_defined = 1;
DEBC(printk(ST_DEB_MSG
"%s: Initialized mode %d definition from mode 0\n",
name, STp->current_mode));
DEBC( printk(KERN_INFO "%s: Default block size set to %d bytes.\n",
name, STm->default_blksize));
if (STp->ready == ST_READY) {
- STp->blksize_changed = FALSE;
+ STp->blksize_changed = 0;
set_mode_densblk(STp, STm);
}
}
DEBC( printk(KERN_INFO "%s: Density default set to %x\n",
name, STm->default_density));
if (STp->ready == ST_READY) {
- STp->density_changed = FALSE;
+ STp->density_changed = 0;
set_mode_densblk(STp, STm);
}
}
DEBC( printk(KERN_INFO "%s: Compression default set to %x\n",
name, (value & 1)));
if (STp->ready == ST_READY) {
- STp->compression_changed = FALSE;
+ STp->compression_changed = 0;
st_compression(STp, (STm->default_compression == ST_YES));
}
}
/* Read a mode page into the tape buffer. The block descriptors are included
if incl_block_descs is true. The page control is ored to the page number
parameter, if necessary. */
-static int read_mode_page(Scsi_Tape *STp, int page, int omit_block_descs)
+static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs)
{
unsigned char cmd[MAX_COMMAND_SIZE];
- Scsi_Request *SRpnt = NULL;
+ struct st_request *SRpnt = NULL;
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SENSE;
cmd[2] = page;
cmd[4] = 255;
- SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ,
- STp->device->timeout, 0, TRUE);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE,
+ STp->device->timeout, 0, 1);
if (SRpnt == NULL)
return (STp->buffer)->syscall_result;
- scsi_release_request(SRpnt);
+ st_release_request(SRpnt);
return (STp->buffer)->syscall_result;
}
/* Send the mode page in the tape buffer to the drive. Assumes that the mode data
in the buffer is correctly formatted. The long timeout is used if slow is non-zero. */
-static int write_mode_page(Scsi_Tape *STp, int page, int slow)
+static int write_mode_page(struct scsi_tape *STp, int page, int slow)
{
int pgo;
unsigned char cmd[MAX_COMMAND_SIZE];
- Scsi_Request *SRpnt = NULL;
+ struct st_request *SRpnt = NULL;
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SELECT;
(STp->buffer)->b_data[MH_OFF_DEV_SPECIFIC] &= ~MH_BIT_WP;
(STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR;
- SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
- (slow ? STp->long_timeout : STp->device->timeout), 0, TRUE);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE,
+ (slow ? STp->long_timeout : STp->device->timeout), 0, 1);
if (SRpnt == NULL)
return (STp->buffer)->syscall_result;
- scsi_release_request(SRpnt);
+ st_release_request(SRpnt);
return (STp->buffer)->syscall_result;
}
work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>).
Including block descriptors should not cause any harm to other drives. */
-static int st_compression(Scsi_Tape * STp, int state)
+static int st_compression(struct scsi_tape * STp, int state)
{
int retval;
int mpoffs; /* Offset to mode page start */
return (-EIO);
/* Read the current page contents */
- retval = read_mode_page(STp, COMPRESSION_PAGE, FALSE);
+ retval = read_mode_page(STp, COMPRESSION_PAGE, 0);
if (retval) {
DEBC(printk(ST_DEB_MSG "%s: Compression mode page not supported.\n",
name));
b_data[mpoffs + CP_OFF_C_ALGO] = 0; /* no compression */
}
- retval = write_mode_page(STp, COMPRESSION_PAGE, FALSE);
+ retval = write_mode_page(STp, COMPRESSION_PAGE, 0);
if (retval) {
DEBC(printk(ST_DEB_MSG "%s: Compression change failed.\n", name));
return (-EIO);
DEBC(printk(ST_DEB_MSG "%s: Compression state changed to %d.\n",
name, state));
- STp->compression_changed = TRUE;
+ STp->compression_changed = 1;
return 0;
}
/* Process the load and unload commands (does unload if the load code is zero) */
-static int do_load_unload(Scsi_Tape *STp, struct file *filp, int load_code)
+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];
- ST_partstat *STps;
- Scsi_Request *SRpnt;
+ struct st_partstat *STps;
+ struct st_request *SRpnt;
if (STp->ready != ST_READY && !load_code) {
if (STp->ready == ST_NO_TAPE)
printk(ST_DEB_MSG "%s: Loading tape.\n", name);
);
- SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,
- timeout, MAX_RETRIES, TRUE);
+ SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
+ timeout, MAX_RETRIES, 1);
if (!SRpnt)
return (STp->buffer)->syscall_result;
retval = (STp->buffer)->syscall_result;
- scsi_release_request(SRpnt);
+ st_release_request(SRpnt);
if (!retval) { /* SCSI command successful */
return retval;
}
\f
+#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)
+{
+ s32 sc;
+
+ sc = cmd[2] & 0x80 ? 0xff000000 : 0;
+ sc |= (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+ if (direction)
+ sc = -sc;
+ printk(ST_DEB_MSG "%s: Spacing tape %s over %d %s.\n", name,
+ direction ? "backward" : "forward", sc, units);
+}
+#endif
+
/* Internal ioctl function */
-static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
+static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned long arg)
{
int timeout;
long ltmp;
int ioctl_result;
- int chg_eof = TRUE;
+ int chg_eof = 1;
unsigned char cmd[MAX_COMMAND_SIZE];
- Scsi_Request *SRpnt;
- ST_partstat *STps;
+ struct st_request *SRpnt;
+ struct st_partstat *STps;
int fileno, blkno, at_sm, undone;
- int datalen = 0, direction = SCSI_DATA_NONE;
+ int datalen = 0, direction = DMA_NONE;
char *name = tape_name(STp);
WARN_ON(STp->buffer->do_dio != 0);
memset(cmd, 0, MAX_COMMAND_SIZE);
switch (cmd_in) {
case MTFSFM:
- chg_eof = FALSE; /* Changed from the FSF after this */
+ chg_eof = 0; /* Changed from the FSF after this */
case MTFSF:
cmd[0] = SPACE;
cmd[1] = 0x01; /* Space FileMarks */
cmd[2] = (arg >> 16);
cmd[3] = (arg >> 8);
cmd[4] = arg;
- DEBC(printk(ST_DEB_MSG "%s: Spacing tape forward over %d filemarks.\n",
- name, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]));
+ DEBC(deb_space_print(name, ST_DEB_FORWARD, "filemarks", cmd);)
if (fileno >= 0)
fileno += arg;
blkno = 0;
at_sm &= (arg == 0);
break;
case MTBSFM:
- chg_eof = FALSE; /* Changed from the FSF after this */
+ chg_eof = 0; /* Changed from the FSF after this */
case MTBSF:
cmd[0] = SPACE;
cmd[1] = 0x01; /* Space FileMarks */
cmd[2] = (ltmp >> 16);
cmd[3] = (ltmp >> 8);
cmd[4] = ltmp;
- DEBC(
- if (cmd[2] & 0x80)
- ltmp = 0xff000000;
- ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
- printk(ST_DEB_MSG
- "%s: Spacing tape backward over %ld filemarks.\n",
- name, (-ltmp));
- )
+ DEBC(deb_space_print(name, ST_DEB_BACKWARD, "filemarks", cmd);)
if (fileno >= 0)
fileno -= arg;
blkno = (-1); /* We can't know the block number */
cmd[2] = (arg >> 16);
cmd[3] = (arg >> 8);
cmd[4] = arg;
- DEBC(printk(ST_DEB_MSG "%s: Spacing tape forward %d blocks.\n", name,
- cmd[2] * 65536 + cmd[3] * 256 + cmd[4]));
+ DEBC(deb_space_print(name, ST_DEB_FORWARD, "blocks", cmd);)
if (blkno >= 0)
blkno += arg;
at_sm &= (arg == 0);
cmd[2] = (ltmp >> 16);
cmd[3] = (ltmp >> 8);
cmd[4] = ltmp;
- DEBC(
- if (cmd[2] & 0x80)
- ltmp = 0xff000000;
- ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
- printk(ST_DEB_MSG
- "%s: Spacing tape backward %ld blocks.\n", name, (-ltmp));
- )
+ DEBC(deb_space_print(name, ST_DEB_BACKWARD, "blocks", cmd);)
if (blkno >= 0)
blkno -= arg;
at_sm &= (arg == 0);
cmd[2] = (arg >> 16);
cmd[3] = (arg >> 8);
cmd[4] = arg;
- DEBC(printk(ST_DEB_MSG "%s: Spacing tape forward %d setmarks.\n", name,
- cmd[2] * 65536 + cmd[3] * 256 + cmd[4]));
+ DEBC(deb_space_print(name, ST_DEB_FORWARD, "setmarks", cmd);)
if (arg != 0) {
blkno = fileno = (-1);
at_sm = 1;
cmd[2] = (ltmp >> 16);
cmd[3] = (ltmp >> 8);
cmd[4] = ltmp;
- DEBC(
- if (cmd[2] & 0x80)
- ltmp = 0xff000000;
- ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
- printk(ST_DEB_MSG "%s: Spacing tape backward %ld setmarks.\n",
- name, (-ltmp));
- )
+ DEBC(deb_space_print(name, ST_DEB_BACKWARD, "setmarks", cmd);)
if (arg != 0) {
blkno = fileno = (-1);
at_sm = 1;
cmd[1] = 3;
DEBC(printk(ST_DEB_MSG "%s: Spacing to end of recorded medium.\n",
name));
- blkno = 0;
+ blkno = -1;
at_sm = 0;
break;
case MTERASE:
case MTSETDENSITY: /* Set tape density */
case MTSETDRVBUFFER: /* Set drive buffering */
case SET_DENS_AND_BLK: /* Set density and block size */
- chg_eof = FALSE;
+ chg_eof = 0;
if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
return (-EIO); /* Not allowed if data in buffer */
if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
if ((STp->use_pf & USE_PF))
cmd[1] = MODE_SELECT_PAGE_FORMAT;
cmd[4] = datalen = 12;
- direction = SCSI_DATA_WRITE;
+ direction = DMA_TO_DEVICE;
memset((STp->buffer)->b_data, 0, 12);
if (cmd_in == MTSETDRVBUFFER)
(STp->buffer)->b_data[3] = 8; /* block descriptor length */
if (cmd_in == MTSETDENSITY) {
(STp->buffer)->b_data[4] = arg;
- STp->density_changed = TRUE; /* At least we tried ;-) */
+ STp->density_changed = 1; /* At least we tried ;-) */
} else if (cmd_in == SET_DENS_AND_BLK)
(STp->buffer)->b_data[4] = arg >> 24;
else
if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
ltmp = arg & MT_ST_BLKSIZE_MASK;
if (cmd_in == MTSETBLK)
- STp->blksize_changed = TRUE; /* At least we tried ;-) */
+ STp->blksize_changed = 1; /* At least we tried ;-) */
} else
ltmp = STp->block_size;
(STp->buffer)->b_data[9] = (ltmp >> 16);
}
SRpnt = st_do_scsi(NULL, STp, cmd, datalen, direction,
- timeout, MAX_RETRIES, TRUE);
+ timeout, MAX_RETRIES, 1);
if (!SRpnt)
return (STp->buffer)->syscall_result;
ioctl_result = (STp->buffer)->syscall_result;
if (!ioctl_result) { /* SCSI command successful */
- scsi_release_request(SRpnt);
+ st_release_request(SRpnt);
SRpnt = NULL;
STps->drv_block = blkno;
STps->drv_file = fileno;
else if (chg_eof)
STps->eof = ST_NOEOF;
+ if (cmd_in == MTWEOF)
+ STps->rw = ST_IDLE;
} else { /* SCSI command was not completely successful. Don't return
from this block without releasing the SCSI command block! */
+ struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
- if (SRpnt->sr_sense_buffer[2] & 0x40) {
+ if (cmdstatp->flags & SENSE_EOM) {
if (cmd_in != MTBSF && cmd_in != MTBSFM &&
cmd_in != MTBSR && cmd_in != MTBSS)
STps->eof = ST_EOM_OK;
STps->drv_block = 0;
}
- undone = ((SRpnt->sr_sense_buffer[3] << 24) +
- (SRpnt->sr_sense_buffer[4] << 16) +
- (SRpnt->sr_sense_buffer[5] << 8) +
- SRpnt->sr_sense_buffer[6]);
+ if (cmdstatp->remainder_valid)
+ undone = (int)cmdstatp->uremainder64;
+ else
+ undone = 0;
if (cmd_in == MTWEOF &&
- (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
- (SRpnt->sr_sense_buffer[2] & 0x4f) == 0x40 &&
- ((SRpnt->sr_sense_buffer[0] & 0x80) == 0 || undone == 0)) {
+ cmdstatp->have_sense &&
+ (cmdstatp->flags & SENSE_EOM) &&
+ (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+ cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
+ undone == 0) {
ioctl_result = 0; /* EOF written succesfully at EOM */
if (fileno >= 0)
fileno++;
STps->drv_file = fileno - undone;
else
STps->drv_file = fileno;
- STps->drv_block = 0;
+ STps->drv_block = -1;
STps->eof = ST_NOEOF;
} else if ((cmd_in == MTBSF) || (cmd_in == MTBSFM)) {
if (arg > 0 && undone < 0) /* Some drives get this wrong */
STps->drv_block = 0;
STps->eof = ST_NOEOF;
} else if (cmd_in == MTFSR) {
- if (SRpnt->sr_sense_buffer[2] & 0x80) { /* Hit filemark */
+ if (cmdstatp->flags & SENSE_FMK) { /* Hit filemark */
if (STps->drv_file >= 0)
STps->drv_file++;
STps->drv_block = 0;
STps->eof = ST_NOEOF;
}
} else if (cmd_in == MTBSR) {
- if (SRpnt->sr_sense_buffer[2] & 0x80) { /* Hit filemark */
+ if (cmdstatp->flags & SENSE_FMK) { /* Hit filemark */
STps->drv_file--;
STps->drv_block = (-1);
} else {
cmd_in == MTSETDENSITY ||
cmd_in == MTSETDRVBUFFER ||
cmd_in == SET_DENS_AND_BLK) {
- if ((SRpnt->sr_sense_buffer[2] & 0x0f) == ILLEGAL_REQUEST &&
+ if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST &&
!(STp->use_pf & PF_TESTED)) {
/* Try the other possible state of Page Format if not
already tried */
STp->use_pf = !STp->use_pf | PF_TESTED;
- scsi_release_request(SRpnt);
+ st_release_request(SRpnt);
SRpnt = NULL;
return st_int_ioctl(STp, cmd_in, arg);
}
} else if (chg_eof)
STps->eof = ST_NOEOF;
- if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
+ if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
STps->eof = ST_EOD;
- scsi_release_request(SRpnt);
+ st_release_request(SRpnt);
SRpnt = NULL;
}
/* Get the tape position. If bt == 2, arg points into a kernel space mt_loc
structure. */
-static int get_location(Scsi_Tape *STp, unsigned int *block, int *partition,
+static int get_location(struct scsi_tape *STp, unsigned int *block, int *partition,
int logical)
{
int result;
unsigned char scmd[MAX_COMMAND_SIZE];
- Scsi_Request *SRpnt;
+ struct st_request *SRpnt;
DEB( char *name = tape_name(STp); )
if (STp->ready != ST_READY)
if (!logical && !STp->scsi2_logical)
scmd[1] = 1;
}
- SRpnt = st_do_scsi(NULL, STp, scmd, 20, SCSI_DATA_READ, STp->device->timeout,
- MAX_READY_RETRIES, TRUE);
+ SRpnt = st_do_scsi(NULL, STp, scmd, 20, DMA_FROM_DEVICE,
+ STp->device->timeout, MAX_READY_RETRIES, 1);
if (!SRpnt)
return (STp->buffer)->syscall_result;
DEBC(printk(ST_DEB_MSG "%s: Got tape pos. blk %d part %d.\n", name,
*block, *partition));
}
- scsi_release_request(SRpnt);
+ st_release_request(SRpnt);
SRpnt = NULL;
return result;
/* Set the tape block and partition. Negative partition means that only the
block should be set in vendor specific way. */
-static int set_location(Scsi_Tape *STp, unsigned int block, int partition,
+static int set_location(struct scsi_tape *STp, unsigned int block, int partition,
int logical)
{
- ST_partstat *STps;
+ struct st_partstat *STps;
int result, p;
unsigned int blk;
int timeout;
unsigned char scmd[MAX_COMMAND_SIZE];
- Scsi_Request *SRpnt;
+ struct st_request *SRpnt;
DEB( char *name = tape_name(STp); )
if (STp->ready != ST_READY)
return (-EINVAL);
if (partition != STp->partition) {
if (get_location(STp, &blk, &p, 1))
- STps->last_block_valid = FALSE;
+ STps->last_block_valid = 0;
else {
- STps->last_block_valid = TRUE;
+ STps->last_block_valid = 1;
STps->last_block_visited = blk;
DEBC(printk(ST_DEB_MSG
"%s: Visited block %d for partition %d saved.\n",
timeout = STp->device->timeout;
}
- SRpnt = st_do_scsi(NULL, STp, scmd, 0, SCSI_DATA_NONE,
- timeout, MAX_READY_RETRIES, TRUE);
+ SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE,
+ timeout, MAX_READY_RETRIES, 1);
if (!SRpnt)
return (STp->buffer)->syscall_result;
result = 0;
}
- scsi_release_request(SRpnt);
+ st_release_request(SRpnt);
SRpnt = NULL;
return result;
/* Find the current partition number for the drive status. Called from open and
returns either partition number of negative error code. */
-static int find_partition(Scsi_Tape *STp)
+static int find_partition(struct scsi_tape *STp)
{
int i, partition;
unsigned int block;
/* Change the partition if necessary */
-static int switch_partition(Scsi_Tape *STp)
+static int switch_partition(struct scsi_tape *STp)
{
- ST_partstat *STps;
+ struct st_partstat *STps;
if (STp->partition == STp->new_partition)
return 0;
/* Get the number of partitions on the tape. As a side effect reads the
mode page into the tape buffer. */
-static int nbr_partitions(Scsi_Tape *STp)
+static int nbr_partitions(struct scsi_tape *STp)
{
int result;
DEB( char *name = tape_name(STp); )
if (STp->ready != ST_READY)
return (-EIO);
- result = read_mode_page(STp, PART_PAGE, TRUE);
+ result = read_mode_page(STp, PART_PAGE, 1);
if (result) {
DEBC(printk(ST_DEB_MSG "%s: Can't read medium partition page.\n",
is acceptable also to some other old drives and enforced if the first partition
size field is used for the first additional partition size.
*/
-static int partition_tape(Scsi_Tape *STp, int size)
+static int partition_tape(struct scsi_tape *STp, int size)
{
char *name = tape_name(STp);
int result;
int pgo, psd_cnt, psdo;
unsigned char *bp;
- result = read_mode_page(STp, PART_PAGE, FALSE);
+ result = read_mode_page(STp, PART_PAGE, 0);
if (result) {
DEBC(printk(ST_DEB_MSG "%s: Can't read partition mode page.\n", name));
return result;
bp[pgo + PP_OFF_RESERVED] = 0;
bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | PP_MSK_PSUM_MB;
- result = write_mode_page(STp, PART_PAGE, TRUE);
+ result = write_mode_page(STp, PART_PAGE, 1);
if (result) {
printk(KERN_INFO "%s: Partitioning of tape failed.\n", name);
result = (-EIO);
int i, cmd_nr, cmd_type, bt;
int retval = 0;
unsigned int blk;
- Scsi_Tape *STp = file->private_data;
- ST_mode *STm;
- ST_partstat *STps;
+ 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;
* may try and take the device offline, in which case all further
* access to the device is prohibited.
*/
- if (!scsi_block_when_processing_errors(STp->device)) {
- retval = (-ENXIO);
+ retval = scsi_nonblockable_ioctl(STp->device, cmd_in, p, file);
+ if (!scsi_block_when_processing_errors(STp->device) || retval != -ENODEV)
goto out;
- }
+ retval = 0;
+
cmd_type = _IOC_TYPE(cmd_in);
cmd_nr = _IOC_NR(cmd_in);
retval = i;
goto out;
}
+ if (STps->rw == ST_WRITING &&
+ (mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
+ mtc.mt_op == MTSEEK ||
+ mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)) {
+ i = st_int_ioctl(STp, MTWEOF, 1);
+ if (i < 0) {
+ retval = i;
+ goto out;
+ }
+ if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)
+ mtc.mt_count++;
+ STps->rw = ST_IDLE;
+ }
+
} else {
/*
* If there was a bus reset, block further access
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
STp->ps[i].rw = ST_IDLE;
STp->ps[i].at_sm = 0;
- STp->ps[i].last_block_valid = FALSE;
+ STp->ps[i].last_block_valid = 0;
}
STp->partition = STp->new_partition = 0;
STp->nbr_partitions = 1; /* Bad guess ?-) */
goto out;
}
- if ((i = flush_buffer(STp, FALSE)) < 0) {
+ if ((i = flush_buffer(STp, 0)) < 0) {
retval = i;
goto out;
}
case SCSI_IOCTL_GET_BUS_NUMBER:
break;
default:
- i = scsi_cmd_ioctl(STp->disk, cmd_in, p);
+ 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(file, STp->disk, cmd_in, p);
if (i != -ENOTTY)
return i;
break;
}
- return scsi_ioctl(STp->device, cmd_in, p);
+ 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;
+ }
+ return retval;
out:
up(&STp->lock);
return retval;
}
+
+#ifdef CONFIG_COMPAT
+static long st_compat_ioctl(struct file *file, unsigned int cmd, 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);
+
+ }
+ return ret;
+}
+#endif
+
\f
/* Try to allocate a new tape buffer. Calling function must not hold
dev_arr_lock. */
-static ST_buffer *
+static struct st_buffer *
new_tape_buffer(int from_initialization, int need_dma, int max_sg)
{
- int i, priority, got = 0, segs = 0;
- ST_buffer *tb;
+ int i, got = 0;
+ gfp_t priority;
+ struct st_buffer *tb;
if (from_initialization)
priority = GFP_ATOMIC;
else
priority = GFP_KERNEL;
- i = sizeof(ST_buffer) + (max_sg - 1) * sizeof(struct scatterlist) +
+ i = sizeof(struct st_buffer) + (max_sg - 1) * sizeof(struct scatterlist) +
max_sg * sizeof(struct st_buf_fragment);
tb = kmalloc(i, priority);
if (!tb) {
return NULL;
}
memset(tb, 0, i);
- tb->frp_segs = tb->orig_frp_segs = segs;
+ tb->frp_segs = tb->orig_frp_segs = 0;
tb->use_sg = max_sg;
- if (segs > 0)
- tb->b_data = page_address(tb->sg[0].page);
tb->frp = (struct st_buf_fragment *)(&(tb->sg[0]) + max_sg);
- tb->in_use = TRUE;
+ tb->in_use = 1;
tb->dma = need_dma;
tb->buffer_size = got;
/* Try to allocate enough space in the tape buffer */
-static int enlarge_buffer(ST_buffer * STbuffer, int new_size, int need_dma)
+static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dma)
{
- int segs, nbr, max_segs, b_size, priority, order, got;
+ int segs, nbr, max_segs, b_size, order, got;
+ gfp_t priority;
if (new_size <= STbuffer->buffer_size)
- return TRUE;
+ return 1;
if (STbuffer->buffer_size <= PAGE_SIZE)
normalize_buffer(STbuffer); /* Avoid extra segment */
max_segs = STbuffer->use_sg;
nbr = max_segs - STbuffer->frp_segs;
if (nbr <= 0)
- return FALSE;
+ return 0;
priority = GFP_KERNEL | __GFP_NOWARN;
if (need_dma)
priority |= GFP_DMA;
- for (b_size = PAGE_SIZE, order=0;
+ for (b_size = PAGE_SIZE, order=0; order <= 6 &&
b_size < new_size - STbuffer->buffer_size;
order++, b_size *= 2)
; /* empty */
}
DEB(STbuffer->buffer_size = got);
normalize_buffer(STbuffer);
- return FALSE;
+ return 0;
}
STbuffer->frp[segs].length = b_size;
STbuffer->frp_segs += 1;
}
STbuffer->b_data = page_address(STbuffer->frp[0].page);
- return TRUE;
+ return 1;
}
/* Release the extra buffer */
-static void normalize_buffer(ST_buffer * STbuffer)
+static void normalize_buffer(struct st_buffer * STbuffer)
{
int i, order;
}
STbuffer->frp_segs = STbuffer->orig_frp_segs;
STbuffer->frp_sg_current = 0;
+ STbuffer->sg_segs = 0;
}
/* Move data from the user buffer to the tape buffer. Returns zero (success) or
negative error code. */
-static int append_to_buffer(const char *ubp, ST_buffer * st_bp, int do_count)
+static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count)
{
int i, cnt, res, offset;
/* Move data from the tape buffer to the user buffer. Returns zero (success) or
negative error code. */
-static int from_buffer(ST_buffer * st_bp, char *ubp, int do_count)
+static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count)
{
int i, cnt, res, offset;
/* Move data towards start of buffer */
-static void move_buffer_data(ST_buffer * st_bp, int offset)
+static void move_buffer_data(struct st_buffer * st_bp, int offset)
{
int src_seg, dst_seg, src_offset = 0, dst_offset;
int count, total;
/* Fill the s/g list up to the length required for this transfer */
-static void buf_to_sg(ST_buffer *STbp, unsigned int length)
+static void buf_to_sg(struct st_buffer *STbp, unsigned int length)
{
int i;
unsigned int count;
.read = st_read,
.write = st_write,
.ioctl = st_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = st_compat_ioctl,
+#endif
.open = st_open,
.flush = st_flush,
.release = st_release,
struct scsi_device *SDp = to_scsi_device(dev);
struct gendisk *disk = NULL;
struct cdev *cdev = NULL;
- Scsi_Tape *tpnt = NULL;
- ST_mode *STm;
- ST_partstat *STps;
- ST_buffer *buffer;
+ struct scsi_tape *tpnt = NULL;
+ struct st_modedef *STm;
+ struct st_partstat *STps;
+ struct st_buffer *buffer;
int i, j, mode, dev_num, error;
char *stp;
- u64 bounce_limit;
if (SDp->type != TYPE_TAPE)
return -ENODEV;
if ((stp = st_incompatible(SDp))) {
- printk(KERN_INFO
- "st: Found incompatible tape at scsi%d, channel %d, id %d, lun %d\n",
- SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+ sdev_printk(KERN_INFO, SDp, "Found incompatible tape\n");
printk(KERN_INFO "st: The suggested driver is %s.\n", stp);
return -ENODEV;
}
- i = SDp->host->sg_tablesize;
+ i = min(SDp->request_queue->max_hw_segments,
+ SDp->request_queue->max_phys_segments);
if (st_max_sg_segs < i)
i = st_max_sg_segs;
- buffer = new_tape_buffer(TRUE, (SDp->host)->unchecked_isa_dma, i);
+ buffer = new_tape_buffer(1, (SDp->host)->unchecked_isa_dma, i);
if (buffer == NULL) {
- printk(KERN_ERR "st: Can't allocate new tape buffer. Device not attached.\n");
+ printk(KERN_ERR
+ "st: Can't allocate new tape buffer. Device not attached.\n");
goto out;
}
write_lock(&st_dev_arr_lock);
if (st_nr_dev >= st_dev_max) {
- Scsi_Tape **tmp_da;
+ struct scsi_tape **tmp_da;
int tmp_dev_max;
tmp_dev_max = max(st_nr_dev * 2, 8);
goto out_put_disk;
}
- tmp_da = kmalloc(tmp_dev_max * sizeof(Scsi_Tape *), GFP_ATOMIC);
+ tmp_da = kmalloc(tmp_dev_max * sizeof(struct scsi_tape *), GFP_ATOMIC);
if (tmp_da == NULL) {
write_unlock(&st_dev_arr_lock);
printk(KERN_ERR "st: Can't extend device array.\n");
goto out_put_disk;
}
- memset(tmp_da, 0, tmp_dev_max * sizeof(Scsi_Tape *));
+ memset(tmp_da, 0, tmp_dev_max * sizeof(struct scsi_tape *));
if (scsi_tapes != NULL) {
memcpy(tmp_da, scsi_tapes,
- st_dev_max * sizeof(Scsi_Tape *));
+ st_dev_max * sizeof(struct scsi_tape *));
kfree(scsi_tapes);
}
scsi_tapes = tmp_da;
if (i >= st_dev_max)
panic("scsi_devices corrupt (st)");
- tpnt = kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC);
+ tpnt = kmalloc(sizeof(struct scsi_tape), GFP_ATOMIC);
if (tpnt == NULL) {
write_unlock(&st_dev_arr_lock);
printk(KERN_ERR "st: Can't allocate device descriptor.\n");
goto out_put_disk;
}
- memset(tpnt, 0, sizeof(Scsi_Tape));
+ memset(tpnt, 0, sizeof(struct scsi_tape));
+ kref_init(&tpnt->kref);
tpnt->disk = disk;
sprintf(disk->disk_name, "st%d", i);
disk->private_data = &tpnt->driver;
tpnt->tape_type = MT_ISSCSI2;
tpnt->buffer = buffer;
+ tpnt->buffer->last_SRpnt = NULL;
tpnt->inited = 0;
tpnt->dirty = 0;
tpnt->long_timeout = ST_LONG_TIMEOUT;
tpnt->try_dio = try_direct_io && !SDp->host->unchecked_isa_dma;
- bounce_limit = scsi_calculate_bounce_limit(SDp->host) >> PAGE_SHIFT;
- if (bounce_limit > ULONG_MAX)
- bounce_limit = ULONG_MAX;
- tpnt->max_pfn = bounce_limit;
-
for (i = 0; i < ST_NBR_MODES; i++) {
STm = &(tpnt->modes[i]);
- STm->defined = FALSE;
+ STm->defined = 0;
STm->sysv = ST_SYSV;
STm->defaults_for_writes = 0;
STm->do_async_writes = ST_ASYNC_WRITES;
STps->rw = ST_IDLE;
STps->eof = ST_NOEOF;
STps->at_sm = 0;
- STps->last_block_valid = FALSE;
+ STps->last_block_valid = 0;
STps->drv_block = (-1);
STps->drv_file = (-1);
}
tpnt->current_mode = 0;
- tpnt->modes[0].defined = TRUE;
+ tpnt->modes[0].defined = 1;
tpnt->density_changed = tpnt->compression_changed =
- tpnt->blksize_changed = FALSE;
+ tpnt->blksize_changed = 0;
init_MUTEX(&tpnt->lock);
st_nr_dev++;
}
disk->number = devfs_register_tape(SDp->devfs_name);
- printk(KERN_WARNING
- "Attached scsi tape %s at scsi%d, channel %d, id %d, lun %d\n",
- tape_name(tpnt), SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
- printk(KERN_WARNING "%s: try direct i/o: %s (alignment %d B), max page reachable by HBA %lu\n",
+ sdev_printk(KERN_WARNING, SDp,
+ "Attached scsi tape %s", tape_name(tpnt));
+ printk(KERN_WARNING "%s: try direct i/o: %s (alignment %d B)\n",
tape_name(tpnt), tpnt->try_dio ? "yes" : "no",
- queue_dma_alignment(SDp->request_queue) + 1, tpnt->max_pfn);
+ queue_dma_alignment(SDp->request_queue) + 1);
return 0;
if (STm->cdevs[j]) {
if (cdev == STm->cdevs[j])
cdev = NULL;
- class_simple_device_remove(MKDEV(SCSI_TAPE_MAJOR,
- TAPE_MINOR(i, mode, j)));
+ class_device_destroy(st_sysfs_class,
+ MKDEV(SCSI_TAPE_MAJOR,
+ TAPE_MINOR(i, mode, j)));
cdev_del(STm->cdevs[j]);
}
}
write_unlock(&st_dev_arr_lock);
out_put_disk:
put_disk(disk);
- if (tpnt)
- kfree(tpnt);
+ kfree(tpnt);
out_buffer_free:
kfree(buffer);
out:
static int st_remove(struct device *dev)
{
- Scsi_Device *SDp = to_scsi_device(dev);
- Scsi_Tape *tpnt;
+ struct scsi_device *SDp = to_scsi_device(dev);
+ struct scsi_tape *tpnt;
int i, j, mode;
write_lock(&st_dev_arr_lock);
for (i = 0; i < st_dev_max; i++) {
tpnt = scsi_tapes[i];
if (tpnt != NULL && tpnt->device == SDp) {
- scsi_tapes[i] = 0;
+ scsi_tapes[i] = NULL;
st_nr_dev--;
write_unlock(&st_dev_arr_lock);
devfs_unregister_tape(tpnt->disk->number);
devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[j]);
devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[j]);
for (j=0; j < 2; j++) {
- class_simple_device_remove(MKDEV(SCSI_TAPE_MAJOR,
- TAPE_MINOR(i, mode, j)));
+ class_device_destroy(st_sysfs_class,
+ MKDEV(SCSI_TAPE_MAJOR,
+ TAPE_MINOR(i, mode, j)));
cdev_del(tpnt->modes[mode].cdevs[j]);
tpnt->modes[mode].cdevs[j] = NULL;
}
}
- tpnt->device = NULL;
- if (tpnt->buffer) {
- tpnt->buffer->orig_frp_segs = 0;
- normalize_buffer(tpnt->buffer);
- kfree(tpnt->buffer);
- }
- put_disk(tpnt->disk);
- kfree(tpnt);
+ mutex_lock(&st_ref_mutex);
+ kref_put(&tpnt->kref, scsi_tape_release);
+ mutex_unlock(&st_ref_mutex);
return 0;
}
}
return 0;
}
-static void st_intr(struct scsi_cmnd *SCpnt)
-{
- scsi_io_completion(SCpnt, (SCpnt->result ? 0: SCpnt->bufflen), 1);
-}
-
-/*
- * st_init_command: only called via the scsi_cmd_ioctl (block SG_IO)
- * interface for REQ_BLOCK_PC commands.
- */
-static int st_init_command(struct scsi_cmnd *SCpnt)
+/**
+ * scsi_tape_release - Called to free the Scsi_Tape structure
+ * @kref: pointer to embedded kref
+ *
+ * st_ref_mutex must be held entering this routine. Because it is
+ * called on last put, you should always use the scsi_tape_get()
+ * scsi_tape_put() helpers which manipulate the semaphore directly
+ * and never do a direct kref_put().
+ **/
+static void scsi_tape_release(struct kref *kref)
{
- struct request *rq;
-
- if (!(SCpnt->request->flags & REQ_BLOCK_PC))
- return 0;
+ struct scsi_tape *tpnt = to_scsi_tape(kref);
+ struct gendisk *disk = tpnt->disk;
- rq = SCpnt->request;
- if (sizeof(rq->cmd) > sizeof(SCpnt->cmnd))
- return 0;
-
- memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd));
+ tpnt->device = NULL;
- if (rq_data_dir(rq) == WRITE)
- SCpnt->sc_data_direction = DMA_TO_DEVICE;
- else if (rq->data_len)
- SCpnt->sc_data_direction = DMA_FROM_DEVICE;
- else
- SCpnt->sc_data_direction = DMA_NONE;
+ if (tpnt->buffer) {
+ tpnt->buffer->orig_frp_segs = 0;
+ normalize_buffer(tpnt->buffer);
+ kfree(tpnt->buffer);
+ }
- SCpnt->timeout_per_command = rq->timeout;
- SCpnt->transfersize = rq->data_len;
- SCpnt->done = st_intr;
- return 1;
+ disk->private_data = NULL;
+ put_disk(disk);
+ kfree(tpnt);
+ return;
}
static int __init init_st(void)
"st: Version %s, fixed bufsize %d, s/g segs %d\n",
verstr, st_fixed_buffer_size, st_max_sg_segs);
- st_sysfs_class = class_simple_create(THIS_MODULE, "scsi_tape");
+ st_sysfs_class = class_create(THIS_MODULE, "scsi_tape");
if (IS_ERR(st_sysfs_class)) {
st_sysfs_class = NULL;
printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n");
do_create_driverfs_files();
return 0;
}
- if (st_sysfs_class)
- class_simple_destroy(st_sysfs_class);
unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
-
ST_MAX_TAPE_ENTRIES);
}
+ class_destroy(st_sysfs_class);
printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", SCSI_TAPE_MAJOR);
return 1;
static void __exit exit_st(void)
{
- if (st_sysfs_class)
- class_simple_destroy(st_sysfs_class);
- st_sysfs_class = NULL;
do_remove_driverfs_files();
scsi_unregister_driver(&st_template.gendrv);
unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
ST_MAX_TAPE_ENTRIES);
+ class_destroy(st_sysfs_class);
kfree(scsi_tapes);
printk(KERN_INFO "st: Unloaded.\n");
}
/* The sysfs simple class interface */
static ssize_t st_defined_show(struct class_device *class_dev, char *buf)
{
- ST_mode *STm = (ST_mode *)class_get_devdata(class_dev);
+ struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev);
ssize_t l = 0;
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->defined);
static ssize_t st_defblk_show(struct class_device *class_dev, char *buf)
{
- ST_mode *STm = (ST_mode *)class_get_devdata(class_dev);
+ struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev);
ssize_t l = 0;
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_blksize);
static ssize_t st_defdensity_show(struct class_device *class_dev, char *buf)
{
- ST_mode *STm = (ST_mode *)class_get_devdata(class_dev);
+ struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev);
ssize_t l = 0;
char *fmt;
static ssize_t st_defcompression_show(struct class_device *class_dev, char *buf)
{
- ST_mode *STm = (ST_mode *)class_get_devdata(class_dev);
+ struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev);
ssize_t l = 0;
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_compression - 1);
CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL);
-static void do_create_class_files(Scsi_Tape *STp, int dev_num, int mode)
+static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
{
int i, rew, error;
char name[10];
snprintf(name, 10, "%s%s%s", rew ? "n" : "",
STp->disk->disk_name, st_formats[i]);
st_class_member =
- class_simple_device_add(st_sysfs_class,
- MKDEV(SCSI_TAPE_MAJOR,
- TAPE_MINOR(dev_num, mode, rew)),
- &STp->device->sdev_gendev, "%s", name);
+ class_device_create(st_sysfs_class, NULL,
+ MKDEV(SCSI_TAPE_MAJOR,
+ TAPE_MINOR(dev_num, mode, rew)),
+ &STp->device->sdev_gendev, "%s", name);
if (IS_ERR(st_class_member)) {
- printk(KERN_WARNING "st%d: class_simple_device_add failed\n",
+ printk(KERN_WARNING "st%d: class_device_create failed\n",
dev_num);
goto out;
}
return;
}
-
-/* Pin down user pages and put them into a scatter gather list. Returns <= 0 if
- - mapping of all pages not successful
- - any page is above max_pfn
- (i.e., either completely successful or fails)
-*/
-static int st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages,
- unsigned long uaddr, size_t count, int rw,
- unsigned long max_pfn)
-{
- int i, nr_pages;
-
- nr_pages = sgl_map_user_pages(sgl, max_pages, uaddr, count, rw);
- if (nr_pages <= 0)
- return nr_pages;
-
- for (i=0; i < nr_pages; i++) {
- if (page_to_pfn(sgl[i].page) > max_pfn)
- goto out_unmap;
- }
- return nr_pages;
-
- out_unmap:
- sgl_unmap_user_pages(sgl, nr_pages, FALSE);
- return 0;
-}
-
-
/* The following functions may be useful for a larger audience. */
static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages,
unsigned long uaddr, size_t count, int rw)
{
+ 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;
- unsigned int nr_pages;
struct page **pages;
- nr_pages = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT;
-
/* User attempted Overflow! */
if ((uaddr + count) < uaddr)
return -EINVAL;
if (res > 0) {
for (j=0; j < res; j++)
page_cache_release(pages[j]);
+ res = 0;
}
kfree(pages);
return res;
int i;
for (i=0; i < nr_pages; i++) {
- if (dirtied && !PageReserved(sgl[i].page))
- SetPageDirty(sgl[i].page);
+ struct page *page = sgl[i].page;
+
+ if (dirtied)
+ SetPageDirty(page);
/* FIXME: cache flush missing for rw==READ
* FIXME: call the correct reference counting function
*/
- page_cache_release(sgl[i].page);
+ page_cache_release(page);
}
return 0;