Merge branch 'master' into for_paulus
[linux-drm-fsl-dcu.git] / drivers / scsi / st.c
index 756ceb93ddc801f5249ca5f20f67f0ccea78f88d..3d2e02381e92257618050314a2e358957e204221 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>
 
@@ -195,9 +195,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 int 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_class_files(struct scsi_tape *, int, int);
 
 static struct scsi_driver st_template = {
        .owner                  = THIS_MODULE,
@@ -368,7 +368,7 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
                       SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
                       SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
                if (cmdstatp->have_sense)
-                        __scsi_print_sense("st", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
+                        __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
        } ) /* end DEB */
        if (!debugging) { /* Abnormal conditions for tape */
                if (!cmdstatp->have_sense)
@@ -384,9 +384,8 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
                         scode != VOLUME_OVERFLOW &&
                         SRpnt->cmd[0] != MODE_SENSE &&
                         SRpnt->cmd[0] != TEST_UNIT_READY) {
-                               printk(KERN_WARNING "%s: Error with sense data: ", name);
-                               __scsi_print_sense("st", SRpnt->sense,
-                                                  SCSI_SENSE_BUFFERSIZE);
+
+                       __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
                }
        }
 
@@ -923,7 +922,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;
@@ -1000,7 +999,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 {
@@ -1169,6 +1168,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; )
@@ -1178,7 +1178,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;
@@ -1222,7 +1225,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) {
@@ -1398,9 +1401,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) {
@@ -1597,7 +1600,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. */
@@ -1767,7 +1770,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 {
@@ -1946,10 +1949,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]);
@@ -2814,15 +2819,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;
@@ -3856,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,
@@ -4049,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;
 
@@ -4158,32 +4168,45 @@ 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_driverfs_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)
@@ -4226,14 +4249,33 @@ 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_driverfs_files(void)
 {
        struct device_driver *driverfs = &st_template.gendrv;
+       int err;
+
+       err = driver_create_file(driverfs, &driver_attr_try_direct_io);
+       if (err)
+               return err;
+       err = driver_create_file(driverfs, &driver_attr_fixed_buffer_size);
+       if (err)
+               goto err_try_direct_io;
+       err = driver_create_file(driverfs, &driver_attr_max_sg_segs);
+       if (err)
+               goto err_attr_fixed_buf;
+       err = driver_create_file(driverfs, &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(driverfs, &driver_attr_max_sg_segs);
+err_attr_fixed_buf:
+       driver_remove_file(driverfs, &driver_attr_fixed_buffer_size);
+err_try_direct_io:
+       driver_remove_file(driverfs, &driver_attr_try_direct_io);
+       return err;
 }
 
 static void do_remove_driverfs_files(void)
@@ -4294,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 */
@@ -4317,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,
@@ -4337,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. */