Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / scsi / st.c
index 265d1ee..56cb490 100644 (file)
@@ -17,7 +17,7 @@
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
  */
 
-static char *verstr = "20050312";
+static const char *verstr = "20050830";
 
 #include <linux/module.h>
 
@@ -29,14 +29,15 @@ static char *verstr = "20050312";
 #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>
@@ -49,7 +50,7 @@ static char *verstr = "20050312";
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_ioctl.h>
-#include <scsi/scsi_request.h>
+#include <scsi/sg.h>
 
 
 /* The driver prints some debugging information on the console if DEBUG
@@ -82,11 +83,12 @@ 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).
@@ -132,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"}; 
 
@@ -186,15 +188,12 @@ 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);
@@ -207,7 +206,6 @@ static struct scsi_driver st_template = {
                .probe          = st_probe,
                .remove         = st_remove,
        },
-       .init_command           = st_init_command,
 };
 
 static int st_compression(struct scsi_tape *, int);
@@ -217,6 +215,12 @@ static int switch_partition(struct scsi_tape *);
 
 static int st_int_ioctl(struct 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"
 #ifndef SIGS_FROM_OSST
@@ -228,6 +232,46 @@ static int st_int_ioctl(struct 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;
@@ -265,12 +309,13 @@ static inline char *tape_name(struct scsi_tape *tape)
 }
 
 
-static void st_analyze_sense(struct scsi_request *SRpnt, struct st_cmdstatus *s)
+static void st_analyze_sense(struct st_request *SRpnt, struct st_cmdstatus *s)
 {
        const u8 *ucp;
-       const u8 *sense = SRpnt->sr_sense_buffer;
+       const u8 *sense = SRpnt->sense;
 
-       s->have_sense = scsi_request_normalize_sense(SRpnt, &s->sense_hdr);
+       s->have_sense = scsi_normalize_sense(SRpnt->sense,
+                               SCSI_SENSE_BUFFERSIZE, &s->sense_hdr);
        s->flags = 0;
 
        if (s->have_sense) {
@@ -297,9 +342,9 @@ static void st_analyze_sense(struct scsi_request *SRpnt, struct st_cmdstatus *s)
 
 
 /* Convert the result to success code */
-static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt)
+static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
 {
-       int result = SRpnt->sr_result;
+       int result = SRpnt->result;
        u8 scode;
        DEB(const char *stp;)
        char *name = tape_name(STp);
@@ -309,7 +354,7 @@ static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt)
                return 0;
 
        cmdstatp = &STp->buffer->cmdstat;
-       st_analyze_sense(STp->buffer->last_SRpnt, cmdstatp);
+       st_analyze_sense(SRpnt, cmdstatp);
 
        if (cmdstatp->have_sense)
                scode = STp->buffer->cmdstat.sense_hdr.sense_key;
@@ -318,13 +363,12 @@ static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt)
 
         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);
+                      SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
+                      SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
                if (cmdstatp->have_sense)
-                       scsi_print_req_sense("st", SRpnt);
+                        __scsi_print_sense("st", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
        } ) /* end DEB */
        if (!debugging) { /* Abnormal conditions for tape */
                if (!cmdstatp->have_sense)
@@ -338,20 +382,21 @@ static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt)
                         /* scode != UNIT_ATTENTION && */
                         scode != BLANK_CHECK &&
                         scode != VOLUME_OVERFLOW &&
-                        SRpnt->sr_cmnd[0] != MODE_SENSE &&
-                        SRpnt->sr_cmnd[0] != TEST_UNIT_READY) {
+                        SRpnt->cmd[0] != MODE_SENSE &&
+                        SRpnt->cmd[0] != TEST_UNIT_READY) {
                                printk(KERN_WARNING "%s: Error with sense data: ", name);
-                               scsi_print_req_sense("st", SRpnt);
+                               __scsi_print_sense("st", SRpnt->sense,
+                                                  SCSI_SENSE_BUFFERSIZE);
                }
        }
 
        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 (cmdstatp->have_sense &&
@@ -363,8 +408,8 @@ static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt)
        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++;
@@ -372,9 +417,9 @@ static int st_chk_result(struct scsi_tape *STp, struct 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";
@@ -390,30 +435,51 @@ static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt)
 
 
 /* Wakeup from interrupt */
-static void st_sleep_done(struct scsi_cmnd * SCpnt)
+static void st_sleep_done(void *data, char *sense, int result, int resid)
 {
-       struct scsi_tape *STp = container_of(SCpnt->request->rq_disk->private_data,
-                                            struct scsi_tape, driver);
+       struct st_request *SRpnt = data;
+       struct scsi_tape *STp = SRpnt->stp;
 
-       (STp->buffer)->cmdstat.midlevel_result = SCpnt->result;
-       SCpnt->request->rq_status = RQ_SCSI_DONE;
-       (STp->buffer)->last_SRpnt = SCpnt->sc_request;
+       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 struct scsi_request *
-st_do_scsi(struct scsi_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd,
+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)); );
@@ -423,32 +489,38 @@ st_do_scsi(struct scsi_request * SRpnt, struct scsi_tape * STp, unsigned char *c
                                (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;
-       STp->buffer->cmdstat.have_sense = 0;
+       /* 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;
 
-       scsi_do_req(SRpnt, (void *) cmd, bp, bytes,
-                   st_sleep_done, timeout, retries);
+       waiting = &STp->wait;
+       init_completion(waiting);
+       SRpnt->waiting = waiting;
 
-       if (do_wait) {
-               wait_for_completion(SRpnt->sr_request->waiting);
-               SRpnt->sr_request->waiting = NULL;
+       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;
 }
 
@@ -463,6 +535,7 @@ static int write_behind_check(struct scsi_tape * STp)
        struct st_buffer *STbuffer;
        struct st_partstat *STps;
        struct st_cmdstatus *cmdstatp;
+       struct st_request *SRpnt;
 
        STbuffer = STp->buffer;
        if (!STbuffer->writing)
@@ -476,10 +549,12 @@ static int write_behind_check(struct 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]);
@@ -519,7 +594,7 @@ static int write_behind_check(struct scsi_tape * STp)
    it messes up the block number). */
 static int cross_eof(struct scsi_tape * STp, int forward)
 {
-       struct scsi_request *SRpnt;
+       struct st_request *SRpnt;
        unsigned char cmd[MAX_COMMAND_SIZE];
 
        cmd[0] = SPACE;
@@ -539,7 +614,7 @@ static int cross_eof(struct scsi_tape * STp, int forward)
        if (!SRpnt)
                return (STp->buffer)->syscall_result;
 
-       scsi_release_request(SRpnt);
+       st_release_request(SRpnt);
        SRpnt = NULL;
 
        if ((STp->buffer)->cmdstat.midlevel_result != 0)
@@ -556,7 +631,7 @@ static int flush_write_buffer(struct scsi_tape * STp)
        int offset, transfer, blks;
        int result;
        unsigned char cmd[MAX_COMMAND_SIZE];
-       struct scsi_request *SRpnt;
+       struct st_request *SRpnt;
        struct st_partstat *STps;
 
        result = write_behind_check(STp);
@@ -614,7 +689,7 @@ static int flush_write_buffer(struct scsi_tape * STp)
                        STp->dirty = 0;
                        (STp->buffer)->buffer_bytes = 0;
                }
-               scsi_release_request(SRpnt);
+               st_release_request(SRpnt);
                SRpnt = NULL;
        }
        return result;
@@ -711,7 +786,7 @@ static int set_mode_densblk(struct scsi_tape * STp, struct st_modedef * STm)
 }
 
 
-/* Lock or unlock the drive door. Don't use when scsi_request allocated. */
+/* 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;
@@ -770,7 +845,7 @@ static int test_ready(struct scsi_tape *STp, int do_wait)
        int attentions, waits, max_wait, scode;
        int retval = CHKRES_READY, new_session = 0;
        unsigned char cmd[MAX_COMMAND_SIZE];
-       struct scsi_request *SRpnt = NULL;
+       struct st_request *SRpnt = NULL;
        struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
 
        max_wait = do_wait ? ST_BLOCK_SECONDS : 0;
@@ -829,7 +904,7 @@ static int test_ready(struct scsi_tape *STp, int do_wait)
        }
 
        if (SRpnt != NULL)
-               scsi_release_request(SRpnt);
+               st_release_request(SRpnt);
        return retval;
 }
 
@@ -844,7 +919,7 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
        int i, retval, new_session = 0, do_wait;
        unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning;
        unsigned short st_flags = filp->f_flags;
-       struct scsi_request *SRpnt = NULL;
+       struct st_request *SRpnt = NULL;
        struct st_modedef *STm;
        struct st_partstat *STps;
        char *name = tape_name(STp);
@@ -919,7 +994,7 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
                        goto err_out;
                }
 
-               if (!SRpnt->sr_result && !STp->buffer->cmdstat.have_sense) {
+               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) |
@@ -971,7 +1046,7 @@ static int check_tape(struct 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 = 1;
 
@@ -1053,25 +1128,20 @@ static int st_open(struct inode *inode, struct file *filp)
         */
        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;
@@ -1116,7 +1186,7 @@ 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;
 
 }
@@ -1127,7 +1197,7 @@ static int st_flush(struct file *filp)
 {
        int result = 0, result2;
        unsigned char cmd[MAX_COMMAND_SIZE];
-       struct scsi_request *SRpnt;
+       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]);
@@ -1180,7 +1250,7 @@ static int st_flush(struct file *filp)
                      cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
                     (!cmdstatp->remainder_valid || cmdstatp->uremainder64 == 0))) {
                        /* Write successful at EOM */
-                       scsi_release_request(SRpnt);
+                       st_release_request(SRpnt);
                        SRpnt = NULL;
                        if (STps->drv_file >= 0)
                                STps->drv_file++;
@@ -1190,7 +1260,7 @@ static int st_flush(struct file *filp)
                        STps->eof = ST_FM;
                }
                else { /* Write error */
-                       scsi_release_request(SRpnt);
+                       st_release_request(SRpnt);
                        SRpnt = NULL;
                        printk(KERN_ERR "%s: Error on write filemark.\n", name);
                        if (result == 0)
@@ -1248,7 +1318,7 @@ 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;
 }
@@ -1331,11 +1401,11 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
                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 */
@@ -1380,14 +1450,15 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
 
 
 /* Can be called more than once after each setup_buffer() */
-static void release_buffering(struct scsi_tape *STp)
+static void release_buffering(struct scsi_tape *STp, int is_read)
 {
        struct st_buffer *STbp;
 
        STbp = STp->buffer;
        if (STbp->do_dio) {
-               sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, 0);
+               sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, is_read);
                STbp->do_dio = 0;
+               STbp->sg_segs = 0;
        }
 }
 
@@ -1403,7 +1474,7 @@ 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;
-       struct scsi_request *SRpnt = NULL;
+       struct st_request *SRpnt = NULL;
        struct scsi_tape *STp = filp->private_data;
        struct st_modedef *STm;
        struct st_partstat *STps;
@@ -1555,7 +1626,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                        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);
@@ -1629,7 +1700,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                        } else {
                                count += do_count;
                                STps->drv_block = (-1);         /* Too cautious? */
-                               retval = (-EIO);
+                               retval = STbp->syscall_result;
                        }
 
                }
@@ -1659,8 +1730,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;
@@ -1673,11 +1744,11 @@ 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(struct scsi_tape *STp, long count,
-                     struct scsi_request ** aSRpnt)
+                     struct st_request ** aSRpnt)
 {
        int transfer, blks, bytes;
        unsigned char cmd[MAX_COMMAND_SIZE];
-       struct scsi_request *SRpnt;
+       struct st_request *SRpnt;
        struct st_modedef *STm;
        struct st_partstat *STps;
        struct st_buffer *STbp;
@@ -1718,7 +1789,7 @@ static long read_tape(struct scsi_tape *STp, long count,
        SRpnt = *aSRpnt;
        SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, DMA_FROM_DEVICE,
                           STp->device->timeout, MAX_RETRIES, 1);
-       release_buffering(STp);
+       release_buffering(STp, 1);
        *aSRpnt = SRpnt;
        if (!SRpnt)
                return STbp->syscall_result;
@@ -1733,10 +1804,10 @@ static long read_tape(struct scsi_tape *STp, long count,
                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]));
+                            SRpnt->sense[0], SRpnt->sense[1],
+                            SRpnt->sense[2], SRpnt->sense[3],
+                            SRpnt->sense[4], SRpnt->sense[5],
+                            SRpnt->sense[6], SRpnt->sense[7]));
                if (cmdstatp->have_sense) {
 
                        if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
@@ -1766,7 +1837,7 @@ static long read_tape(struct scsi_tape *STp, long count,
                                                }
                                                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);
@@ -1860,7 +1931,7 @@ 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;
-       struct scsi_request *SRpnt = NULL;
+       struct st_request *SRpnt = NULL;
        struct scsi_tape *STp = filp->private_data;
        struct st_modedef *STm;
        struct st_partstat *STps;
@@ -1985,11 +2056,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);
@@ -2215,7 +2286,7 @@ static int st_set_options(struct scsi_tape *STp, long options)
 static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs)
 {
        unsigned char cmd[MAX_COMMAND_SIZE];
-       struct scsi_request *SRpnt = NULL;
+       struct st_request *SRpnt = NULL;
 
        memset(cmd, 0, MAX_COMMAND_SIZE);
        cmd[0] = MODE_SENSE;
@@ -2229,7 +2300,7 @@ static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs)
        if (SRpnt == NULL)
                return (STp->buffer)->syscall_result;
 
-       scsi_release_request(SRpnt);
+       st_release_request(SRpnt);
 
        return (STp->buffer)->syscall_result;
 }
@@ -2241,7 +2312,7 @@ static int write_mode_page(struct scsi_tape *STp, int page, int slow)
 {
        int pgo;
        unsigned char cmd[MAX_COMMAND_SIZE];
-       struct scsi_request *SRpnt = NULL;
+       struct st_request *SRpnt = NULL;
 
        memset(cmd, 0, MAX_COMMAND_SIZE);
        cmd[0] = MODE_SELECT;
@@ -2260,7 +2331,7 @@ static int write_mode_page(struct scsi_tape *STp, int page, int slow)
        if (SRpnt == NULL)
                return (STp->buffer)->syscall_result;
 
-       scsi_release_request(SRpnt);
+       st_release_request(SRpnt);
 
        return (STp->buffer)->syscall_result;
 }
@@ -2343,7 +2414,7 @@ static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_cod
        DEB( char *name = tape_name(STp); )
        unsigned char cmd[MAX_COMMAND_SIZE];
        struct st_partstat *STps;
-       struct scsi_request *SRpnt;
+       struct st_request *SRpnt;
 
        if (STp->ready != ST_READY && !load_code) {
                if (STp->ready == ST_NO_TAPE)
@@ -2386,7 +2457,7 @@ static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_cod
                return (STp->buffer)->syscall_result;
 
        retval = (STp->buffer)->syscall_result;
-       scsi_release_request(SRpnt);
+       st_release_request(SRpnt);
 
        if (!retval) {  /* SCSI command successful */
 
@@ -2434,7 +2505,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
        int ioctl_result;
        int chg_eof = 1;
        unsigned char cmd[MAX_COMMAND_SIZE];
-       struct scsi_request *SRpnt;
+       struct st_request *SRpnt;
        struct st_partstat *STps;
        int fileno, blkno, at_sm, undone;
        int datalen = 0, direction = DMA_NONE;
@@ -2688,7 +2759,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
        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;
@@ -2803,7 +2874,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
                                /* 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);
                        }
@@ -2813,7 +2884,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
                if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
                        STps->eof = ST_EOD;
 
-               scsi_release_request(SRpnt);
+               st_release_request(SRpnt);
                SRpnt = NULL;
        }
 
@@ -2829,7 +2900,7 @@ static int get_location(struct scsi_tape *STp, unsigned int *block, int *partiti
 {
        int result;
        unsigned char scmd[MAX_COMMAND_SIZE];
-       struct scsi_request *SRpnt;
+       struct st_request *SRpnt;
        DEB( char *name = tape_name(STp); )
 
        if (STp->ready != ST_READY)
@@ -2875,7 +2946,7 @@ static int get_location(struct scsi_tape *STp, unsigned int *block, int *partiti
                 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;
@@ -2892,7 +2963,7 @@ static int set_location(struct scsi_tape *STp, unsigned int block, int partition
        unsigned int blk;
        int timeout;
        unsigned char scmd[MAX_COMMAND_SIZE];
-       struct scsi_request *SRpnt;
+       struct st_request *SRpnt;
        DEB( char *name = tape_name(STp); )
 
        if (STp->ready != ST_READY)
@@ -2978,7 +3049,7 @@ static int set_location(struct scsi_tape *STp, unsigned int block, int partition
                result = 0;
        }
 
-       scsi_release_request(SRpnt);
+       st_release_request(SRpnt);
        SRpnt = NULL;
 
        return result;
@@ -3463,7 +3534,10 @@ static int st_ioctl(struct inode *inode, struct file *file,
                case SCSI_IOCTL_GET_BUS_NUMBER:
                        break;
                default:
-                       if (!capable(CAP_SYS_ADMIN))
+                       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);
@@ -3471,10 +3545,12 @@ static int st_ioctl(struct inode *inode, struct file *file,
                                return i;
                        break;
        }
-       if (!capable(CAP_SYS_ADMIN) &&
-           (cmd_in == SCSI_IOCTL_START_UNIT || cmd_in == SCSI_IOCTL_STOP_UNIT))
-               return -EPERM;
-       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);
@@ -3503,7 +3579,8 @@ static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a
 static struct st_buffer *
  new_tape_buffer(int from_initialization, int need_dma, int max_sg)
 {
-       int i, priority, got = 0, segs = 0;
+       int i, got = 0;
+       gfp_t priority;
        struct st_buffer *tb;
 
        if (from_initialization)
@@ -3513,16 +3590,13 @@ static struct st_buffer *
 
        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 = 1;
@@ -3536,7 +3610,8 @@ static struct st_buffer *
 /* Try to allocate enough space in the tape buffer */
 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 1;
@@ -3552,7 +3627,7 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm
        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 */
@@ -3594,6 +3669,7 @@ static void normalize_buffer(struct st_buffer * STbuffer)
        }
        STbuffer->frp_segs = STbuffer->orig_frp_segs;
        STbuffer->frp_sg_current = 0;
+       STbuffer->sg_segs = 0;
 }
 
 
@@ -3806,19 +3882,17 @@ static int st_probe(struct device *dev)
        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(1, (SDp->host)->unchecked_isa_dma, i);
@@ -3849,14 +3923,13 @@ static int st_probe(struct device *dev)
                        goto out_put_disk;
                }
 
-               tmp_da = kmalloc(tmp_dev_max * sizeof(struct 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(struct scsi_tape *));
                if (scsi_tapes != NULL) {
                        memcpy(tmp_da, scsi_tapes,
                               st_dev_max * sizeof(struct scsi_tape *));
@@ -3873,13 +3946,13 @@ static int st_probe(struct device *dev)
        if (i >= st_dev_max)
                panic("scsi_devices corrupt (st)");
 
-       tpnt = kmalloc(sizeof(struct 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(struct scsi_tape));
+       kref_init(&tpnt->kref);
        tpnt->disk = disk;
        sprintf(disk->disk_name, "st%d", i);
        disk->private_data = &tpnt->driver;
@@ -3895,6 +3968,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;
@@ -3918,11 +3992,6 @@ 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 = 0;
@@ -3984,27 +4053,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;
 
@@ -4017,8 +4070,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]);
                        }
                }
@@ -4031,8 +4085,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:
@@ -4053,29 +4106,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;
                }
        }
@@ -4084,39 +4129,32 @@ static int st_remove(struct device *dev)
        return 0;
 }
 
-static void st_intr(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)
 {
-       scsi_io_completion(SCpnt, (SCpnt->result ? 0: SCpnt->bufflen), 1);
-}
+       struct scsi_tape *tpnt = to_scsi_tape(kref);
+       struct gendisk *disk = tpnt->disk;
 
-/*
- * 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)
-{
-       struct request *rq;
+       tpnt->device = NULL;
 
-       if (!(SCpnt->request->flags & REQ_BLOCK_PC))
-               return 0;
-
-       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)
@@ -4127,7 +4165,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");
@@ -4140,12 +4178,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;
@@ -4153,13 +4189,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");
 }
@@ -4277,12 +4311,12 @@ static void do_create_class_files(struct 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;
                }
@@ -4311,44 +4345,16 @@ static void do_create_class_files(struct 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, 0);
-       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;
@@ -4413,6 +4419,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;
@@ -4426,12 +4433,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;