USB: option: add Ericsson F3507g and Dell 5530
[safe/jmp/linux-2.6] / drivers / scsi / st.c
index a4361a8..5c28d08 100644 (file)
@@ -17,7 +17,7 @@
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
  */
 
-static const char *verstr = "20080224";
+static const char *verstr = "20080504";
 
 #include <linux/module.h>
 
@@ -38,6 +38,7 @@ static const char *verstr = "20080224";
 #include <linux/cdev.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/dma.h>
@@ -628,9 +629,9 @@ static int cross_eof(struct scsi_tape * STp, int forward)
 
 
 /* Flush the write buffer (never need to write if variable blocksize). */
-static int flush_write_buffer(struct scsi_tape * STp)
+static int st_flush_write_buffer(struct scsi_tape * STp)
 {
-       int offset, transfer, blks;
+       int transfer, blks;
        int result;
        unsigned char cmd[MAX_COMMAND_SIZE];
        struct st_request *SRpnt;
@@ -643,14 +644,10 @@ static int flush_write_buffer(struct scsi_tape * STp)
        result = 0;
        if (STp->dirty == 1) {
 
-               offset = (STp->buffer)->buffer_bytes;
-               transfer = ((offset + STp->block_size - 1) /
-                           STp->block_size) * STp->block_size;
+               transfer = STp->buffer->buffer_bytes;
                 DEBC(printk(ST_DEB_MSG "%s: Flushing %d bytes.\n",
                                tape_name(STp), transfer));
 
-               memset((STp->buffer)->b_data + offset, 0, transfer - offset);
-
                memset(cmd, 0, MAX_COMMAND_SIZE);
                cmd[0] = WRITE_6;
                cmd[1] = 1;
@@ -719,7 +716,7 @@ static int flush_buffer(struct scsi_tape *STp, int seek_next)
                return 0;
        STps = &(STp->ps[STp->partition]);
        if (STps->rw == ST_WRITING)     /* Writing */
-               return flush_write_buffer(STp);
+               return st_flush_write_buffer(STp);
 
        if (STp->block_size == 0)
                return 0;
@@ -1113,7 +1110,7 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
 }
 
 
-\f/* Open the device. Needs to be called with BKL only because of incrementing the SCSI host
+\f/* Open the device. Needs to take the BKL only because of incrementing the SCSI host
    module count. */
 static int st_open(struct inode *inode, struct file *filp)
 {
@@ -1123,6 +1120,7 @@ static int st_open(struct inode *inode, struct file *filp)
        int dev = TAPE_NR(inode);
        char *name;
 
+       lock_kernel();
        /*
         * 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
@@ -1130,8 +1128,10 @@ static int st_open(struct inode *inode, struct file *filp)
         */
        filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
 
-       if (!(STp = scsi_tape_get(dev)))
+       if (!(STp = scsi_tape_get(dev))) {
+               unlock_kernel();
                return -ENXIO;
+       }
 
        write_lock(&st_dev_arr_lock);
        filp->private_data = STp;
@@ -1140,6 +1140,7 @@ static int st_open(struct inode *inode, struct file *filp)
        if (STp->in_use) {
                write_unlock(&st_dev_arr_lock);
                scsi_tape_put(STp);
+               unlock_kernel();
                DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); )
                return (-EBUSY);
        }
@@ -1188,12 +1189,14 @@ static int st_open(struct inode *inode, struct file *filp)
                        retval = (-EIO);
                goto err_out;
        }
+       unlock_kernel();
        return 0;
 
  err_out:
        normalize_buffer(STp->buffer);
        STp->in_use = 0;
        scsi_tape_put(STp);
+       unlock_kernel();
        return retval;
 
 }
@@ -1214,7 +1217,7 @@ static int st_flush(struct file *filp, fl_owner_t id)
                return 0;
 
        if (STps->rw == ST_WRITING && !STp->pos_unknown) {
-               result = flush_write_buffer(STp);
+               result = st_flush_write_buffer(STp);
                if (result != 0 && result != (-ENOSPC))
                        goto out;
        }
@@ -1663,6 +1666,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                                if (undone <= do_count) {
                                        /* Only data from this write is not written */
                                        count += undone;
+                                       b_point -= undone;
                                        do_count -= undone;
                                        if (STp->block_size)
                                                blks = (transfer - undone) / STp->block_size;
@@ -4108,9 +4112,9 @@ out_free_tape:
                        if (STm->cdevs[j]) {
                                if (cdev == STm->cdevs[j])
                                        cdev = NULL;
-                               class_device_destroy(st_sysfs_class,
-                                                    MKDEV(SCSI_TAPE_MAJOR,
-                                                          TAPE_MINOR(i, mode, j)));
+                                       device_destroy(st_sysfs_class,
+                                                      MKDEV(SCSI_TAPE_MAJOR,
+                                                            TAPE_MINOR(i, mode, j)));
                                cdev_del(STm->cdevs[j]);
                        }
                }
@@ -4148,9 +4152,9 @@ static int st_remove(struct device *dev)
                                          "tape");
                        for (mode = 0; mode < ST_NBR_MODES; ++mode) {
                                for (j=0; j < 2; j++) {
-                                       class_device_destroy(st_sysfs_class,
-                                                            MKDEV(SCSI_TAPE_MAJOR,
-                                                                  TAPE_MINOR(i, mode, j)));
+                                       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;
                                }
@@ -4319,31 +4323,34 @@ static void do_remove_sysfs_files(void)
 
 
 /* The sysfs simple class interface */
-static ssize_t st_defined_show(struct class_device *class_dev, char *buf)
+static ssize_t
+st_defined_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev);
+       struct st_modedef *STm = dev_get_drvdata(dev);
        ssize_t l = 0;
 
        l = snprintf(buf, PAGE_SIZE, "%d\n", STm->defined);
        return l;
 }
 
-CLASS_DEVICE_ATTR(defined, S_IRUGO, st_defined_show, NULL);
+DEVICE_ATTR(defined, S_IRUGO, st_defined_show, NULL);
 
-static ssize_t st_defblk_show(struct class_device *class_dev, char *buf)
+static ssize_t
+st_defblk_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev);
+       struct st_modedef *STm = dev_get_drvdata(dev);
        ssize_t l = 0;
 
        l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_blksize);
        return l;
 }
 
-CLASS_DEVICE_ATTR(default_blksize, S_IRUGO, st_defblk_show, NULL);
+DEVICE_ATTR(default_blksize, S_IRUGO, st_defblk_show, NULL);
 
-static ssize_t st_defdensity_show(struct class_device *class_dev, char *buf)
+static ssize_t
+st_defdensity_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev);
+       struct st_modedef *STm = dev_get_drvdata(dev);
        ssize_t l = 0;
        char *fmt;
 
@@ -4352,24 +4359,67 @@ static ssize_t st_defdensity_show(struct class_device *class_dev, char *buf)
        return l;
 }
 
-CLASS_DEVICE_ATTR(default_density, S_IRUGO, st_defdensity_show, NULL);
+DEVICE_ATTR(default_density, S_IRUGO, st_defdensity_show, NULL);
 
-static ssize_t st_defcompression_show(struct class_device *class_dev, char *buf)
+static ssize_t
+st_defcompression_show(struct device *dev, struct device_attribute *attr,
+                      char *buf)
 {
-       struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev);
+       struct st_modedef *STm = dev_get_drvdata(dev);
        ssize_t l = 0;
 
        l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_compression - 1);
        return l;
 }
 
-CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL);
+DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL);
+
+static ssize_t
+st_options_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct st_modedef *STm = dev_get_drvdata(dev);
+       struct scsi_tape *STp;
+       int i, j, options;
+       ssize_t l = 0;
+
+       for (i=0; i < st_dev_max; i++) {
+               for (j=0; j < ST_NBR_MODES; j++)
+                       if (&scsi_tapes[i]->modes[j] == STm)
+                               break;
+               if (j < ST_NBR_MODES)
+                       break;
+       }
+       if (i == st_dev_max)
+               return 0;  /* should never happen */
+
+       STp = scsi_tapes[i];
+
+       options = STm->do_buffer_writes ? MT_ST_BUFFER_WRITES : 0;
+       options |= STm->do_async_writes ? MT_ST_ASYNC_WRITES : 0;
+       options |= STm->do_read_ahead ? MT_ST_READ_AHEAD : 0;
+       DEB( options |= debugging ? MT_ST_DEBUGGING : 0 );
+       options |= STp->two_fm ? MT_ST_TWO_FM : 0;
+       options |= STp->fast_mteom ? MT_ST_FAST_MTEOM : 0;
+       options |= STm->defaults_for_writes ? MT_ST_DEF_WRITES : 0;
+       options |= STp->can_bsr ? MT_ST_CAN_BSR : 0;
+       options |= STp->omit_blklims ? MT_ST_NO_BLKLIMS : 0;
+       options |= STp->can_partitions ? MT_ST_CAN_PARTITIONS : 0;
+       options |= STp->scsi2_logical ? MT_ST_SCSI2LOGICAL : 0;
+       options |= STm->sysv ? MT_ST_SYSV : 0;
+       options |= STp->immediate ? MT_ST_NOWAIT : 0;
+       options |= STp->sili ? MT_ST_SILI : 0;
+
+       l = snprintf(buf, PAGE_SIZE, "0x%08x\n", options);
+       return l;
+}
+
+DEVICE_ATTR(options, S_IRUGO, st_options_show, NULL);
 
 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;
+       struct device *st_class_member;
 
        for (rew=0; rew < 2; rew++) {
                /* Make sure that the minor numbers corresponding to the four
@@ -4378,29 +4428,31 @@ static int 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_device_create(st_sysfs_class, NULL,
-                                           MKDEV(SCSI_TAPE_MAJOR,
-                                                 TAPE_MINOR(dev_num, mode, rew)),
-                                           &STp->device->sdev_gendev, "%s", name);
+                       device_create(st_sysfs_class, &STp->device->sdev_gendev,
+                                     MKDEV(SCSI_TAPE_MAJOR,
+                                           TAPE_MINOR(dev_num, mode, rew)),
+                                     &STp->modes[mode], "%s", name);
                if (IS_ERR(st_class_member)) {
-                       printk(KERN_WARNING "st%d: class_device_create failed\n",
+                       printk(KERN_WARNING "st%d: device_create failed\n",
                               dev_num);
                        error = PTR_ERR(st_class_member);
                        goto out;
                }
-               class_set_devdata(st_class_member, &STp->modes[mode]);
 
-               error = class_device_create_file(st_class_member,
-                                              &class_device_attr_defined);
+               error = device_create_file(st_class_member,
+                                          &dev_attr_defined);
+               if (error) goto out;
+               error = device_create_file(st_class_member,
+                                          &dev_attr_default_blksize);
                if (error) goto out;
-               error = class_device_create_file(st_class_member,
-                                           &class_device_attr_default_blksize);
+               error = device_create_file(st_class_member,
+                                          &dev_attr_default_density);
                if (error) goto out;
-               error = class_device_create_file(st_class_member,
-                                           &class_device_attr_default_density);
+               error = device_create_file(st_class_member,
+                                          &dev_attr_default_compression);
                if (error) goto out;
-               error = class_device_create_file(st_class_member,
-                                       &class_device_attr_default_compression);
+               error = device_create_file(st_class_member,
+                                          &dev_attr_options);
                if (error) goto out;
 
                if (mode == 0 && rew == 0) {