Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / drivers / scsi / st.c
index 5fa0153..7f669b6 100644 (file)
@@ -9,7 +9,7 @@
    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
@@ -17,7 +17,7 @@
    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>
 
@@ -29,17 +29,30 @@ static char *verstr = "20040403";
 #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/blkdev.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
@@ -56,13 +69,6 @@ static char *verstr = "20040403";
 #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"
@@ -71,17 +77,18 @@ static char *verstr = "20040403";
 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");
+MODULE_DESCRIPTION("SCSI tape (st) driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(SCSI_TAPE_MAJOR);
 
 /* Set 'perm' (4th argument) to 0 to disable module_param's definition
  * of sysfs parameters (which module_param doesn't yet support).
@@ -127,7 +134,7 @@ static struct st_dev_parm {
 #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"}; 
 
@@ -141,7 +148,7 @@ static char *st_formats[] = {
 #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
@@ -164,36 +171,33 @@ DEB( static int debugging = DEBUG; )
    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 __user *, ST_buffer *, int);
-static int from_buffer(ST_buffer *, char __user *, 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,
@@ -202,15 +206,20 @@ static struct scsi_driver st_template = {
                .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"
@@ -223,6 +232,46 @@ static int st_int_ioctl(Scsi_Tape *, unsigned int, unsigned long);
        {"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;
@@ -237,7 +286,7 @@ static struct st_reject_data reject_list[] = {
 
 /* 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;
 
@@ -254,78 +303,112 @@ static char * st_incompatible(Scsi_Device* SDp)
 }
 \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(name, 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) {
+
+                       __scsi_print_sense(name, 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++;
@@ -333,9 +416,9 @@ static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt)
 
                 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";
@@ -343,7 +426,7 @@ static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt)
                               STp->recover_count);
                } ) /* end DEB */
 
-               if ((sense[2] & 0xe0) == 0)
+               if (cmdstatp->flags == 0)
                        return 0;
        }
        return (-EIO);
@@ -351,48 +434,51 @@ static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt)
 
 
 /* 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)); );
@@ -402,42 +488,57 @@ static Scsi_Request *
                                (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)
@@ -447,10 +548,12 @@ static void write_behind_check(Scsi_Tape * STp)
         ) /* 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]);
@@ -460,17 +563,37 @@ static void write_behind_check(Scsi_Tape * STp)
                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;
@@ -485,15 +608,15 @@ static int cross_eof(Scsi_Tape * STp, int forward)
         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");
 
@@ -502,27 +625,17 @@ static int cross_eof(Scsi_Tape * STp, int forward)
 
 
 /* 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) {
@@ -543,32 +656,39 @@ static int flush_write_buffer(Scsi_Tape * STp)
                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;
@@ -577,11 +697,11 @@ static int flush_write_buffer(Scsi_Tape * STp)
 
 /* 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;
 
@@ -610,7 +730,7 @@ static int flush_buffer(Scsi_Tape *STp, int seek_next)
        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 {
@@ -632,9 +752,9 @@ static int flush_buffer(Scsi_Tape *STp, int seek_next)
 }
 \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);
 
@@ -642,7 +762,7 @@ static int set_mode_densblk(Scsi_Tape * STp, ST_mode * STm)
            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;
@@ -650,7 +770,7 @@ static int set_mode_densblk(Scsi_Tape * STp, ST_mode * STm)
            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 &&
@@ -665,8 +785,8 @@ static int set_mode_densblk(Scsi_Tape * STp, ST_mode * STm)
 }
 
 
-/* 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);)
@@ -687,10 +807,10 @@ static int do_door_lock(Scsi_Tape * STp, int do_lock)
 
 
 /* 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++) {
@@ -698,7 +818,7 @@ static void reset_state(Scsi_Tape *STp)
                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;
        }
@@ -719,32 +839,33 @@ static void reset_state(Scsi_Tape *STp)
 
 #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;
@@ -757,9 +878,7 @@ static int test_ready(Scsi_Tape *STp, int do_wait)
 
                        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;
                                        }
@@ -768,7 +887,7 @@ static int test_ready(Scsi_Tape *STp, int do_wait)
                                }
                                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;
@@ -784,7 +903,7 @@ static int test_ready(Scsi_Tape *STp, int do_wait)
        }
 
        if (SRpnt != NULL)
-               scsi_release_request(SRpnt);
+               st_release_request(SRpnt);
        return retval;
 }
 
@@ -794,14 +913,14 @@ static int test_ready(Scsi_Tape *STp, int do_wait)
    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);
@@ -811,7 +930,7 @@ static int check_tape(Scsi_Tape *STp, struct file *filp)
        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]);
@@ -836,11 +955,11 @@ static int check_tape(Scsi_Tape *STp, struct file *filp)
                        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;
@@ -867,14 +986,14 @@ static int check_tape(Scsi_Tape *STp, struct file *filp)
                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) |
@@ -894,8 +1013,8 @@ static int check_tape(Scsi_Tape *STp, struct file *filp)
        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;
@@ -926,9 +1045,9 @@ static int check_tape(Scsi_Tape *STp, struct file *filp)
                }
                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 =
@@ -970,8 +1089,8 @@ static int check_tape(Scsi_Tape *STp, struct file *filp)
        }
 
        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;
@@ -996,31 +1115,32 @@ static int check_tape(Scsi_Tape *STp, struct file *filp)
 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;
 
-       nonseekable_open(inode, filp);
+       /*
+        * 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;
@@ -1065,21 +1185,21 @@ static int st_open(struct inode *inode, struct file *filp)
  err_out:
        normalize_buffer(STp->buffer);
        STp->in_use = 0;
-       scsi_device_put(STp->device);
+       scsi_tape_put(STp);
        return retval;
 
 }
 \f
 
 /* Flush the tape buffer before close */
-static int st_flush(struct file *filp)
+static int st_flush(struct file *filp, fl_owner_t id)
 {
        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)
@@ -1105,10 +1225,9 @@ static int st_flush(struct file *filp)
                       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);
                )
 
@@ -1116,36 +1235,36 @@ static int st_flush(struct file *filp)
                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]));
@@ -1155,7 +1274,7 @@ static int st_flush(struct file *filp)
                        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++;
@@ -1165,7 +1284,7 @@ static int st_flush(struct file *filp)
                                        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++;
@@ -1189,7 +1308,7 @@ static int st_flush(struct file *filp)
 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);
@@ -1198,13 +1317,13 @@ static int st_release(struct inode *inode, struct file *filp)
        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)
+static ssize_t rw_checks(struct scsi_tape *STp, struct file *filp, size_t count)
 {
        ssize_t retval = 0;
 
@@ -1271,26 +1390,27 @@ static ssize_t rw_checks(Scsi_Tape *STp, struct file *filp, size_t count)
 }
 
 
-static int setup_buffering(Scsi_Tape *STp, const char __user *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(
@@ -1303,7 +1423,7 @@ static int setup_buffering(Scsi_Tape *STp, const char __user *buf, size_t count,
                     }
                )
        } else
-               STbp->do_dio = FALSE;
+               STbp->do_dio = 0;
        DEB( STp->nbr_requests++; )
 
        if (!STbp->do_dio) {
@@ -1329,14 +1449,15 @@ static int setup_buffering(Scsi_Tape *STp, const char __user *buf, size_t count,
 
 
 /* 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;
        }
 }
 
@@ -1352,11 +1473,11 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
        int async_write;
        unsigned char cmd[MAX_COMMAND_SIZE];
        const char __user *b_point;
-       Scsi_Request *SRpnt = NULL;
-       Scsi_Tape *STp = filp->private_data;
-       ST_mode *STm;
-       ST_partstat *STps;
-       ST_buffer *STbp;
+       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))
@@ -1406,16 +1527,12 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
        }
 
        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) {
@@ -1438,7 +1555,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                goto out;
        }
 
-       retval = setup_buffering(STp, buf, count, FALSE);
+       retval = setup_buffering(STp, buf, count, 0);
        if (retval)
                goto out;
 
@@ -1473,7 +1590,6 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                        }
                }
                count -= do_count;
-               filp->f_pos += do_count;
                b_point += do_count;
 
                async_write = STp->block_size == 0 && !STbp->do_dio &&
@@ -1482,7 +1598,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                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;
@@ -1503,13 +1619,13 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                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);
@@ -1519,15 +1635,13 @@ 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));
-                       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;
@@ -1535,7 +1649,6 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                                        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;
@@ -1552,14 +1665,14 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                                                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;
@@ -1584,10 +1697,9 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                                        }
                                }
                        } else {
-                               filp->f_pos -= do_count;
                                count += do_count;
                                STps->drv_block = (-1);         /* Too cautious? */
-                               retval = (-EIO);
+                               retval = STbp->syscall_result;
                        }
 
                }
@@ -1617,8 +1729,8 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
 
  out:
        if (SRpnt != NULL)
-               scsi_release_request(SRpnt);
-       release_buffering(STp);
+               st_release_request(SRpnt);
+       release_buffering(STp, 0);
        up(&STp->lock);
 
        return retval;
@@ -1630,14 +1742,15 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
 
    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);
 
@@ -1673,9 +1786,9 @@ static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt)
        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;
@@ -1685,32 +1798,31 @@ static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt)
 
        /* 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)
@@ -1724,7 +1836,7 @@ static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt)
                                                }
                                                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);
@@ -1744,7 +1856,7 @@ static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt)
                                                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
@@ -1757,7 +1869,7 @@ static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt)
                                         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
@@ -1778,7 +1890,7 @@ static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt)
                                             "%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));
@@ -1818,11 +1930,11 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
        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))
@@ -1852,7 +1964,7 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
                       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;
@@ -1902,7 +2014,7 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
                                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;
@@ -1913,7 +2025,6 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
                                        goto out;
                                }
                        }
-                       filp->f_pos += transfer;
                        buf += transfer;
                        total += transfer;
                }
@@ -1944,11 +2055,11 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
 
  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);
@@ -1960,7 +2071,7 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
 
 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
@@ -1983,20 +2094,20 @@ static void st_log_options(Scsi_Tape * STp, ST_mode * STm, char *name)
        )
 
 
-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));
@@ -2065,7 +2176,7 @@ static int st_set_options(Scsi_Tape *STp, long options)
                        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);
                        }
                }
@@ -2104,7 +2215,7 @@ static int st_set_options(Scsi_Tape *STp, long options)
                                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);
                                }
                        }
@@ -2137,7 +2248,7 @@ static int st_set_options(Scsi_Tape *STp, long options)
                                        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));
                                        }
                                }
@@ -2171,10 +2282,10 @@ static int st_set_options(Scsi_Tape *STp, long options)
 /* 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;
@@ -2183,12 +2294,12 @@ static int read_mode_page(Scsi_Tape *STp, int page, int omit_block_descs)
        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;
 }
@@ -2196,11 +2307,11 @@ static int read_mode_page(Scsi_Tape *STp, int page, int omit_block_descs)
 
 /* 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;
@@ -2214,12 +2325,12 @@ static int write_mode_page(Scsi_Tape *STp, int page, int slow)
        (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;
 }
@@ -2242,7 +2353,7 @@ static int write_mode_page(Scsi_Tape *STp, int page, int slow)
    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 */
@@ -2253,7 +2364,7 @@ static int st_compression(Scsi_Tape * STp, int state)
                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));
@@ -2282,7 +2393,7 @@ static int st_compression(Scsi_Tape * STp, int state)
                        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);
@@ -2290,19 +2401,19 @@ static int st_compression(Scsi_Tape * STp, int state)
         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)
@@ -2339,13 +2450,13 @@ static int do_load_unload(Scsi_Tape *STp, struct file *filp, int load_code)
                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 */
 
@@ -2368,19 +2479,35 @@ static int do_load_unload(Scsi_Tape *STp, struct file *filp, int load_code)
        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);
@@ -2399,22 +2526,21 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
        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 */
@@ -2422,14 +2548,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                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 */
@@ -2441,8 +2560,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                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);
@@ -2454,13 +2572,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                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);
@@ -2471,8 +2583,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                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;
@@ -2485,13 +2596,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                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;
@@ -2561,7 +2666,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                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:
@@ -2583,7 +2688,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
        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) &&
@@ -2598,7 +2703,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                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)
@@ -2609,7 +2714,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                (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
@@ -2617,7 +2722,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                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);
@@ -2646,14 +2751,14 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
        }
 
        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;
@@ -2688,26 +2793,31 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                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)) {
-                       ioctl_result = 0;       /* EOF written succesfully at EOM */
+                   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 successfully at EOM */
                        if (fileno >= 0)
                                fileno++;
                        STps->drv_file = fileno;
@@ -2717,7 +2827,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                                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 */
@@ -2727,7 +2837,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                        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;
@@ -2740,7 +2850,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                                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 {
@@ -2758,22 +2868,22 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                           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;
        }
 
@@ -2784,12 +2894,12 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
 /* 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)
@@ -2804,8 +2914,8 @@ static int get_location(Scsi_Tape *STp, unsigned int *block, int *partition,
                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;
 
@@ -2835,7 +2945,7 @@ static int get_location(Scsi_Tape *STp, unsigned int *block, int *partition,
                 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;
@@ -2844,15 +2954,15 @@ static int get_location(Scsi_Tape *STp, unsigned int *block, int *partition,
 
 /* 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)
@@ -2871,9 +2981,9 @@ static int set_location(Scsi_Tape *STp, unsigned int block, int partition,
                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",
@@ -2909,8 +3019,8 @@ static int set_location(Scsi_Tape *STp, unsigned int block, int partition,
                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;
 
@@ -2938,7 +3048,7 @@ static int set_location(Scsi_Tape *STp, unsigned int block, int partition,
                result = 0;
        }
 
-       scsi_release_request(SRpnt);
+       st_release_request(SRpnt);
        SRpnt = NULL;
 
        return result;
@@ -2947,7 +3057,7 @@ static int set_location(Scsi_Tape *STp, unsigned int block, int partition,
 
 /* 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;
@@ -2961,9 +3071,9 @@ static int find_partition(Scsi_Tape *STp)
 
 
 /* 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;
@@ -2989,7 +3099,7 @@ static int switch_partition(Scsi_Tape *STp)
 
 /* 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); )
@@ -2997,7 +3107,7 @@ static int nbr_partitions(Scsi_Tape *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",
@@ -3032,14 +3142,14 @@ static int nbr_partitions(Scsi_Tape *STp)
    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;
@@ -3082,7 +3192,7 @@ static int partition_tape(Scsi_Tape *STp, int size)
        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);
@@ -3100,9 +3210,9 @@ static int st_ioctl(struct inode *inode, struct file *file,
        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;
 
@@ -3125,10 +3235,11 @@ static int st_ioctl(struct inode *inode, struct file *file,
         * 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);
 
@@ -3192,6 +3303,20 @@ static int st_ioctl(struct inode *inode, struct file *file,
                                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
@@ -3259,7 +3384,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
                        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 ?-) */
@@ -3308,7 +3433,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
                goto out;
        }
 
-       if ((i = flush_buffer(STp, FALSE)) < 0) {
+       if ((i = flush_buffer(STp, 0)) < 0) {
                retval = i;
                goto out;
        }
@@ -3408,47 +3533,71 @@ static int st_ioctl(struct inode *inode, struct file *file,
                case SCSI_IOCTL_GET_BUS_NUMBER:
                        break;
                default:
-                       i = scsi_cmd_ioctl(file, 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);
+       tb = kzalloc(i, priority);
        if (!tb) {
                printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n");
                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->dma = need_dma;
        tb->buffer_size = got;
 
@@ -3457,12 +3606,13 @@ static ST_buffer *
 
 
 /* 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 */
@@ -3470,12 +3620,12 @@ static int enlarge_buffer(ST_buffer * STbuffer, int new_size, int need_dma)
        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 */
@@ -3491,7 +3641,7 @@ static int enlarge_buffer(ST_buffer * STbuffer, int new_size, int need_dma)
                        }
                        DEB(STbuffer->buffer_size = got);
                        normalize_buffer(STbuffer);
-                       return FALSE;
+                       return 0;
                }
                STbuffer->frp[segs].length = b_size;
                STbuffer->frp_segs += 1;
@@ -3501,12 +3651,12 @@ static int enlarge_buffer(ST_buffer * STbuffer, int new_size, int need_dma)
        }
        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;
 
@@ -3517,12 +3667,13 @@ static void normalize_buffer(ST_buffer * STbuffer)
        }
        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 __user *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;
 
@@ -3553,7 +3704,7 @@ static int append_to_buffer(const char __user *ubp, ST_buffer * st_bp, int do_co
 
 /* 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 __user *ubp, int do_count)
+static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count)
 {
        int i, cnt, res, offset;
 
@@ -3584,7 +3735,7 @@ static int from_buffer(ST_buffer * st_bp, char __user *ubp, int do_count)
 
 
 /* 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;
@@ -3622,7 +3773,7 @@ static void move_buffer_data(ST_buffer * st_bp, int offset)
 
 
 /* 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;
@@ -3686,7 +3837,7 @@ static int __init st_setup(char *str)
                                        break;
                                }
                        }
-                       if (i >= sizeof(parms) / sizeof(struct st_dev_parm))
+                       if (i >= ARRAY_SIZE(parms))
                                 printk(KERN_WARNING "st: invalid parameter in '%s'\n",
                                        stp);
                        stp = strchr(stp, ',');
@@ -3710,6 +3861,9 @@ static struct file_operations st_fops =
        .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,
@@ -3720,30 +3874,29 @@ static int st_probe(struct device *dev)
        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;
        }
 
@@ -3755,7 +3908,7 @@ static int st_probe(struct device *dev)
 
        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);
@@ -3768,17 +3921,16 @@ static int st_probe(struct device *dev)
                        goto out_put_disk;
                }
 
-               tmp_da = kmalloc(tmp_dev_max * sizeof(Scsi_Tape *), GFP_ATOMIC);
+               tmp_da = kzalloc(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 *));
                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;
@@ -3792,13 +3944,13 @@ static int st_probe(struct device *dev)
        if (i >= st_dev_max)
                panic("scsi_devices corrupt (st)");
 
-       tpnt = kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC);
+       tpnt = kzalloc(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));
+       kref_init(&tpnt->kref);
        tpnt->disk = disk;
        sprintf(disk->disk_name, "st%d", i);
        disk->private_data = &tpnt->driver;
@@ -3814,6 +3966,7 @@ static int st_probe(struct device *dev)
                tpnt->tape_type = MT_ISSCSI2;
 
        tpnt->buffer = buffer;
+       tpnt->buffer->last_SRpnt = NULL;
 
        tpnt->inited = 0;
        tpnt->dirty = 0;
@@ -3837,14 +3990,9 @@ static int st_probe(struct device *dev)
        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;
@@ -3860,16 +4008,16 @@ static int st_probe(struct device *dev)
                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++;
@@ -3903,27 +4051,11 @@ static int st_probe(struct device *dev)
                do_create_class_files(tpnt, dev_num, mode);
        }
 
-       for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-               /* Make sure that the minor numbers corresponding to the four
-                  first modes always get the same names */
-               i = mode << (4 - ST_NBR_MODE_BITS);
-               /*  Rewind entry  */
-               devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 0)),
-                             S_IFCHR | S_IRUGO | S_IWUGO,
-                             "%s/mt%s", SDp->devfs_name, st_formats[i]);
-               /*  No-rewind entry  */
-               devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 1)),
-                             S_IFCHR | S_IRUGO | S_IWUGO,
-                             "%s/mt%sn", SDp->devfs_name, st_formats[i]);
-       }
-       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\n", 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;
 
@@ -3936,8 +4068,9 @@ out_free_tape:
                        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]);
                        }
                }
@@ -3950,8 +4083,7 @@ out_free_tape:
        write_unlock(&st_dev_arr_lock);
 out_put_disk:
        put_disk(disk);
-       if (tpnt)
-               kfree(tpnt);
+       kfree(tpnt);
 out_buffer_free:
        kfree(buffer);
 out:
@@ -3961,8 +4093,8 @@ 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);
@@ -3972,29 +4104,21 @@ static int st_remove(struct device *dev)
                        scsi_tapes[i] = NULL;
                        st_nr_dev--;
                        write_unlock(&st_dev_arr_lock);
-                       devfs_unregister_tape(tpnt->disk->number);
                        sysfs_remove_link(&tpnt->device->sdev_gendev.kobj,
                                          "tape");
                        for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-                               j = mode << (4 - ST_NBR_MODE_BITS);
-                               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;
                }
        }
@@ -4003,39 +4127,32 @@ static int st_remove(struct device *dev)
        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;
+       struct scsi_tape *tpnt = to_scsi_tape(kref);
+       struct gendisk *disk = tpnt->disk;
 
-       if (!(SCpnt->request->flags & REQ_BLOCK_PC))
-               return 0;
+       tpnt->device = NULL;
 
-       rq = SCpnt->request;
-       if (sizeof(rq->cmd) > sizeof(SCpnt->cmnd))
-               return 0;
-
-       memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd));
-
-       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)
@@ -4046,7 +4163,7 @@ 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");
@@ -4059,12 +4176,10 @@ static int __init init_st(void)
                        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;
@@ -4072,13 +4187,11 @@ static int __init init_st(void)
 
 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");
 }
@@ -4136,7 +4249,7 @@ static void do_remove_driverfs_files(void)
 /* 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);
@@ -4147,7 +4260,7 @@ CLASS_DEVICE_ATTR(defined, S_IRUGO, st_defined_show, NULL);
 
 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);
@@ -4158,7 +4271,7 @@ CLASS_DEVICE_ATTR(default_blksize, S_IRUGO, st_defblk_show, NULL);
 
 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;
 
@@ -4171,7 +4284,7 @@ CLASS_DEVICE_ATTR(default_density, S_IRUGO, st_defdensity_show, NULL);
 
 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);
@@ -4180,7 +4293,7 @@ static ssize_t st_defcompression_show(struct class_device *class_dev, char *buf)
 
 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];
@@ -4196,12 +4309,12 @@ static void do_create_class_files(Scsi_Tape *STp, int dev_num, int mode)
                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;
                }
@@ -4230,44 +4343,16 @@ static void do_create_class_files(Scsi_Tape *STp, int dev_num, int mode)
        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;
@@ -4332,6 +4417,7 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa
        if (res > 0) {
                for (j=0; j < res; j++)
                        page_cache_release(pages[j]);
+               res = 0;
        }
        kfree(pages);
        return res;
@@ -4345,12 +4431,14 @@ static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_p
        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;