SG: Change sg_set_page() to take length and offset argument
[safe/jmp/linux-2.6] / drivers / scsi / st.c
index 7f669b6..98dfd6e 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 - 2005 Kai Makisara
+   Copyright 1992 - 2007 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 const char *verstr = "20050830";
+static const char *verstr = "20070203";
 
 #include <linux/module.h>
 
@@ -89,6 +89,7 @@ MODULE_AUTHOR("Kai Makisara");
 MODULE_DESCRIPTION("SCSI tape (st) driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV_MAJOR(SCSI_TAPE_MAJOR);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
 
 /* Set 'perm' (4th argument) to 0 to disable module_param's definition
  * of sysfs parameters (which module_param doesn't yet support).
@@ -195,9 +196,9 @@ 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 void do_create_driverfs_files(void);
-static void do_remove_driverfs_files(void);
-static void do_create_class_files(struct scsi_tape *, int, int);
+static int do_create_sysfs_files(void);
+static void do_remove_sysfs_files(void);
+static int do_create_class_files(struct scsi_tape *, int, int);
 
 static struct scsi_driver st_template = {
        .owner                  = THIS_MODULE,
@@ -922,7 +923,7 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
        struct st_modedef *STm;
        struct st_partstat *STps;
        char *name = tape_name(STp);
-       struct inode *inode = filp->f_dentry->d_inode;
+       struct inode *inode = filp->f_path.dentry->d_inode;
        int mode = TAPE_MODE(inode);
 
        STp->ready = ST_READY;
@@ -999,7 +1000,7 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
                        STp->min_block = ((STp->buffer)->b_data[4] << 8) |
                            (STp->buffer)->b_data[5];
                        if ( DEB( debugging || ) !STp->inited)
-                               printk(KERN_WARNING
+                               printk(KERN_INFO
                                        "%s: Block limits %d - %d bytes.\n", name,
                                        STp->min_block, STp->max_block);
                } else {
@@ -1168,6 +1169,7 @@ static int st_open(struct inode *inode, struct file *filp)
                STps = &(STp->ps[i]);
                STps->rw = ST_IDLE;
        }
+       STp->try_dio_now = STp->try_dio;
        STp->recover_count = 0;
        DEB( STp->nbr_waits = STp->nbr_finished = 0;
             STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = STp->nbr_combinable = 0; )
@@ -1177,7 +1179,10 @@ static int st_open(struct inode *inode, struct file *filp)
                goto err_out;
        if ((filp->f_flags & O_NONBLOCK) == 0 &&
            retval != CHKRES_READY) {
-               retval = (-EIO);
+               if (STp->ready == NO_TAPE)
+                       retval = (-ENOMEDIUM);
+               else
+                       retval = (-EIO);
                goto err_out;
        }
        return 0;
@@ -1221,7 +1226,7 @@ static int st_flush(struct file *filp, fl_owner_t id)
        }
 
        DEBC( if (STp->nbr_requests)
-               printk(KERN_WARNING "%s: Number of r/w requests %d, dio used in %d, pages %d (%d).\n",
+               printk(KERN_DEBUG "%s: Number of r/w requests %d, dio used in %d, pages %d (%d).\n",
                       name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable));
 
        if (STps->rw == ST_WRITING && !STp->pos_unknown) {
@@ -1397,9 +1402,9 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
        struct st_buffer *STbp = STp->buffer;
 
        if (is_read)
-               i = STp->try_dio && try_rdio;
+               i = STp->try_dio_now && try_rdio;
        else
-               i = STp->try_dio && try_wdio;
+               i = STp->try_dio_now && try_wdio;
 
        if (i && ((unsigned long)buf & queue_dma_alignment(
                                        STp->device->request_queue)) == 0) {
@@ -1480,7 +1485,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
        struct st_buffer *STbp;
        char *name = tape_name(STp);
 
-       if (down_interruptible(&STp->lock))
+       if (mutex_lock_interruptible(&STp->lock))
                return -ERESTARTSYS;
 
        retval = rw_checks(STp, filp, count);
@@ -1596,7 +1601,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                        STm->do_async_writes && STps->eof < ST_EOM_OK;
 
                if (STp->block_size != 0 && STm->do_buffer_writes &&
-                   !(STp->try_dio && try_wdio) && STps->eof < ST_EOM_OK &&
+                   !(STp->try_dio_now && try_wdio) && STps->eof < ST_EOM_OK &&
                    STbp->buffer_bytes < STbp->buffer_size) {
                        STp->dirty = 1;
                        /* Don't write a buffer that is not full enough. */
@@ -1731,7 +1736,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
        if (SRpnt != NULL)
                st_release_request(SRpnt);
        release_buffering(STp, 0);
-       up(&STp->lock);
+       mutex_unlock(&STp->lock);
 
        return retval;
 }
@@ -1766,7 +1771,7 @@ static long read_tape(struct scsi_tape *STp, long count,
        if (STp->block_size == 0)
                blks = bytes = count;
        else {
-               if (!(STp->try_dio && try_rdio) && STm->do_read_ahead) {
+               if (!(STp->try_dio_now && try_rdio) && STm->do_read_ahead) {
                        blks = (STp->buffer)->buffer_blocks;
                        bytes = blks * STp->block_size;
                } else {
@@ -1937,7 +1942,7 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
        struct st_buffer *STbp = STp->buffer;
        DEB( char *name = tape_name(STp); )
 
-       if (down_interruptible(&STp->lock))
+       if (mutex_lock_interruptible(&STp->lock))
                return -ERESTARTSYS;
 
        retval = rw_checks(STp, filp, count);
@@ -1945,10 +1950,12 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
                goto out;
 
        STm = &(STp->modes[STp->current_mode]);
-       if (!(STm->do_read_ahead) && STp->block_size != 0 &&
-           (count % STp->block_size) != 0) {
-               retval = (-EINVAL);     /* Read must be integral number of blocks */
-               goto out;
+       if (STp->block_size != 0 && (count % STp->block_size) != 0) {
+               if (!STm->do_read_ahead) {
+                       retval = (-EINVAL);     /* Read must be integral number of blocks */
+                       goto out;
+               }
+               STp->try_dio_now = 0;  /* Direct i/o can't handle split blocks */
        }
 
        STps = &(STp->ps[STp->partition]);
@@ -2062,7 +2069,7 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
                release_buffering(STp, 1);
                STbp->buffer_bytes = 0;
        }
-       up(&STp->lock);
+       mutex_unlock(&STp->lock);
 
        return retval;
 }
@@ -2813,15 +2820,18 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
 
                if (cmd_in == MTWEOF &&
                    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++;
+                   (cmdstatp->flags & SENSE_EOM)) {
+                       if (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+                           cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) {
+                               ioctl_result = 0;       /* EOF(s) written successfully at EOM */
+                               STps->eof = ST_NOEOF;
+                       } else {  /* Writing EOF(s) failed */
+                               if (fileno >= 0)
+                                       fileno -= undone;
+                               if (undone < arg)
+                                       STps->eof = ST_NOEOF;
+                       }
                        STps->drv_file = fileno;
-                       STps->eof = ST_NOEOF;
                } else if ((cmd_in == MTFSF) || (cmd_in == MTFSFM)) {
                        if (fileno >= 0)
                                STps->drv_file = fileno - undone;
@@ -3216,7 +3226,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
        char *name = tape_name(STp);
        void __user *p = (void __user *)arg;
 
-       if (down_interruptible(&STp->lock))
+       if (mutex_lock_interruptible(&STp->lock))
                return -ERESTARTSYS;
 
         DEB(
@@ -3527,7 +3537,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
                        retval = (-EFAULT);
                goto out;
        }
-       up(&STp->lock);
+       mutex_unlock(&STp->lock);
        switch (cmd_in) {
                case SCSI_IOCTL_GET_IDLUN:
                case SCSI_IOCTL_GET_BUS_NUMBER:
@@ -3539,7 +3549,8 @@ static int st_ioctl(struct inode *inode, struct file *file,
                            !capable(CAP_SYS_RAWIO))
                                i = -EPERM;
                        else
-                               i = scsi_cmd_ioctl(file, STp->disk, cmd_in, p);
+                               i = scsi_cmd_ioctl(file, STp->disk->queue,
+                                                  STp->disk, cmd_in, p);
                        if (i != -ENOTTY)
                                return i;
                        break;
@@ -3552,7 +3563,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
        return retval;
 
  out:
-       up(&STp->lock);
+       mutex_unlock(&STp->lock);
        return retval;
 }
 
@@ -3786,13 +3797,11 @@ static void buf_to_sg(struct st_buffer *STbp, unsigned int length)
        sg = &(STbp->sg[0]);
        frp = STbp->frp;
        for (i=count=0; count < length; i++) {
-               sg[i].page = frp[i].page;
                if (length - count > frp[i].length)
-                       sg[i].length = frp[i].length;
+                       sg_set_page(&sg[i], frp[i].page, frp[i].length, 0);
                else
-                       sg[i].length = length - count;
+                       sg_set_page(&sg[i], frp[i].page, length - count, 0);
                count += sg[i].length;
-               sg[i].offset = 0;
        }
        STbp->sg_segs = i;
        STbp->frp_sg_current = length;
@@ -3855,7 +3864,7 @@ __setup("st=", st_setup);
 
 #endif
 
-static struct file_operations st_fops =
+static const struct file_operations st_fops =
 {
        .owner =        THIS_MODULE,
        .read =         st_read,
@@ -4018,7 +4027,7 @@ static int st_probe(struct device *dev)
 
        tpnt->density_changed = tpnt->compression_changed =
            tpnt->blksize_changed = 0;
-       init_MUTEX(&tpnt->lock);
+       mutex_init(&tpnt->lock);
 
        st_nr_dev++;
        write_unlock(&st_dev_arr_lock);
@@ -4048,14 +4057,16 @@ static int st_probe(struct device *dev)
                        STm->cdevs[j] = cdev;
 
                }
-               do_create_class_files(tpnt, dev_num, mode);
+               error = do_create_class_files(tpnt, dev_num, mode);
+               if (error)
+                       goto out_free_tape;
        }
 
-       sdev_printk(KERN_WARNING, SDp,
+       sdev_printk(KERN_NOTICE, 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);
+       sdev_printk(KERN_INFO, SDp, "%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);
 
        return 0;
 
@@ -4157,37 +4168,50 @@ static void scsi_tape_release(struct kref *kref)
 
 static int __init init_st(void)
 {
+       int err;
+
        validate_options();
 
-       printk(KERN_INFO
-               "st: Version %s, fixed bufsize %d, s/g segs %d\n",
+       printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n",
                verstr, st_fixed_buffer_size, st_max_sg_segs);
 
        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");
-               return 1;
+               return PTR_ERR(st_sysfs_class);
        }
 
-       if (!register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
-                                   ST_MAX_TAPE_ENTRIES, "st")) {
-               if (scsi_register_driver(&st_template.gendrv) == 0) {
-                       do_create_driverfs_files();
-                       return 0;
-               }
-               unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
-                                        ST_MAX_TAPE_ENTRIES);
+       err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
+                                    ST_MAX_TAPE_ENTRIES, "st");
+       if (err) {
+               printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
+                      SCSI_TAPE_MAJOR);
+               goto err_class;
        }
-       class_destroy(st_sysfs_class);
 
-       printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", SCSI_TAPE_MAJOR);
-       return 1;
+       err = scsi_register_driver(&st_template.gendrv);
+       if (err)
+               goto err_chrdev;
+
+       err = do_create_sysfs_files();
+       if (err)
+               goto err_scsidrv;
+
+       return 0;
+
+err_scsidrv:
+       scsi_unregister_driver(&st_template.gendrv);
+err_chrdev:
+       unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
+                                ST_MAX_TAPE_ENTRIES);
+err_class:
+       class_destroy(st_sysfs_class);
+       return err;
 }
 
 static void __exit exit_st(void)
 {
-       do_remove_driverfs_files();
+       do_remove_sysfs_files();
        scsi_unregister_driver(&st_template.gendrv);
        unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
                                 ST_MAX_TAPE_ENTRIES);
@@ -4225,24 +4249,43 @@ static ssize_t st_version_show(struct device_driver *ddd, char *buf)
 }
 static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL);
 
-static void do_create_driverfs_files(void)
+static int do_create_sysfs_files(void)
 {
-       struct device_driver *driverfs = &st_template.gendrv;
+       struct device_driver *sysfs = &st_template.gendrv;
+       int err;
+
+       err = driver_create_file(sysfs, &driver_attr_try_direct_io);
+       if (err)
+               return err;
+       err = driver_create_file(sysfs, &driver_attr_fixed_buffer_size);
+       if (err)
+               goto err_try_direct_io;
+       err = driver_create_file(sysfs, &driver_attr_max_sg_segs);
+       if (err)
+               goto err_attr_fixed_buf;
+       err = driver_create_file(sysfs, &driver_attr_version);
+       if (err)
+               goto err_attr_max_sg;
+
+       return 0;
 
-       driver_create_file(driverfs, &driver_attr_try_direct_io);
-       driver_create_file(driverfs, &driver_attr_fixed_buffer_size);
-       driver_create_file(driverfs, &driver_attr_max_sg_segs);
-       driver_create_file(driverfs, &driver_attr_version);
+err_attr_max_sg:
+       driver_remove_file(sysfs, &driver_attr_max_sg_segs);
+err_attr_fixed_buf:
+       driver_remove_file(sysfs, &driver_attr_fixed_buffer_size);
+err_try_direct_io:
+       driver_remove_file(sysfs, &driver_attr_try_direct_io);
+       return err;
 }
 
-static void do_remove_driverfs_files(void)
+static void do_remove_sysfs_files(void)
 {
-       struct device_driver *driverfs = &st_template.gendrv;
+       struct device_driver *sysfs = &st_template.gendrv;
 
-       driver_remove_file(driverfs, &driver_attr_version);
-       driver_remove_file(driverfs, &driver_attr_max_sg_segs);
-       driver_remove_file(driverfs, &driver_attr_fixed_buffer_size);
-       driver_remove_file(driverfs, &driver_attr_try_direct_io);
+       driver_remove_file(sysfs, &driver_attr_version);
+       driver_remove_file(sysfs, &driver_attr_max_sg_segs);
+       driver_remove_file(sysfs, &driver_attr_fixed_buffer_size);
+       driver_remove_file(sysfs, &driver_attr_try_direct_io);
 }
 
 
@@ -4293,15 +4336,12 @@ 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(struct scsi_tape *STp, int dev_num, int mode)
+static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
 {
        int i, rew, error;
        char name[10];
        struct class_device *st_class_member;
 
-       if (!st_sysfs_class)
-               return;
-
        for (rew=0; rew < 2; rew++) {
                /* Make sure that the minor numbers corresponding to the four
                   first modes always get the same names */
@@ -4316,18 +4356,24 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
                if (IS_ERR(st_class_member)) {
                        printk(KERN_WARNING "st%d: class_device_create failed\n",
                               dev_num);
+                       error = PTR_ERR(st_class_member);
                        goto out;
                }
                class_set_devdata(st_class_member, &STp->modes[mode]);
 
-               class_device_create_file(st_class_member,
-                                        &class_device_attr_defined);
-               class_device_create_file(st_class_member,
-                                        &class_device_attr_default_blksize);
-               class_device_create_file(st_class_member,
-                                        &class_device_attr_default_density);
-               class_device_create_file(st_class_member,
-                                        &class_device_attr_default_compression);
+               error = class_device_create_file(st_class_member,
+                                              &class_device_attr_defined);
+               if (error) goto out;
+               error = class_device_create_file(st_class_member,
+                                           &class_device_attr_default_blksize);
+               if (error) goto out;
+               error = class_device_create_file(st_class_member,
+                                           &class_device_attr_default_density);
+               if (error) goto out;
+               error = class_device_create_file(st_class_member,
+                                       &class_device_attr_default_compression);
+               if (error) goto out;
+
                if (mode == 0 && rew == 0) {
                        error = sysfs_create_link(&STp->device->sdev_gendev.kobj,
                                                  &st_class_member->kobj,
@@ -4336,11 +4382,15 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
                                printk(KERN_ERR
                                       "st%d: Can't create sysfs link from SCSI device.\n",
                                       dev_num);
+                               goto out;
                        }
                }
        }
- out:
-       return;
+
+       return 0;
+
+out:
+       return error;
 }
 
 /* The following functions may be useful for a larger audience. */
@@ -4394,15 +4444,13 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa
         }
 
        /* Populate the scatter/gather list */
-       sgl[0].page = pages[0]; 
-       sgl[0].offset = uaddr & ~PAGE_MASK;
+       sg_set_page(&sgl[0], pages[0], 0, uaddr & ~PAGE_MASK);
        if (nr_pages > 1) {
                sgl[0].length = PAGE_SIZE - sgl[0].offset;
                count -= sgl[0].length;
                for (i=1; i < nr_pages ; i++) {
-                       sgl[i].offset = 0;
-                       sgl[i].page = pages[i]; 
-                       sgl[i].length = count < PAGE_SIZE ? count : PAGE_SIZE;
+                       sg_set_page(&sgl[i], pages[i],
+                                   count < PAGE_SIZE ? count : PAGE_SIZE, 0);;
                        count -= PAGE_SIZE;
                }
        }
@@ -4431,7 +4479,7 @@ static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_p
        int i;
 
        for (i=0; i < nr_pages; i++) {
-               struct page *page = sgl[i].page;
+               struct page *page = sg_page(&sgl[i]);
 
                if (dirtied)
                        SetPageDirty(page);