linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / scsi / sd.c
index 98bd3aa..9d98723 100644 (file)
@@ -32,6 +32,7 @@
  *     than the level indicated above to trigger output.       
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -46,6 +47,7 @@
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/blkpg.h>
+#include <linux/kref.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
  */
 #define SD_MAJORS      16
 
-MODULE_AUTHOR("Eric Youngdale");
-MODULE_DESCRIPTION("SCSI disk (sd) driver");
-MODULE_LICENSE("GPL");
-
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK0_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK1_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK2_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK3_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK4_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK5_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK6_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK7_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK8_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK9_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK10_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK11_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK12_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR);
-MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR);
-
 /*
  * This is limited by the naming scheme enforced in sd_probe,
  * add another character to it if you really need more disks.
@@ -113,10 +94,12 @@ MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR);
  */
 #define SD_BUF_SIZE            512
 
+static void scsi_disk_release(struct kref *kref);
+
 struct scsi_disk {
        struct scsi_driver *driver;     /* always &sd_template */
        struct scsi_device *device;
-       struct class_device cdev;
+       struct kref     kref;
        struct gendisk  *disk;
        unsigned int    openers;        /* protected by BKL for now, yuck */
        sector_t        capacity;       /* size in 512-byte sectors */
@@ -127,7 +110,6 @@ struct scsi_disk {
        unsigned        RCD : 1;        /* state of disk RCD bit, unused */
        unsigned        DPOFUA : 1;     /* state of disk DPOFUA bit */
 };
-#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev)
 
 static DEFINE_IDR(sd_index_idr);
 static DEFINE_SPINLOCK(sd_index_lock);
@@ -149,118 +131,6 @@ static int sd_issue_flush(struct device *, sector_t *);
 static void sd_prepare_flush(request_queue_t *, struct request *);
 static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
                             unsigned char *buffer);
-static void scsi_disk_release(struct class_device *cdev);
-
-static const char *sd_cache_types[] = {
-       "write through", "none", "write back",
-       "write back, no read (daft)"
-};
-
-static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf,
-                                  size_t count)
-{
-       int i, ct = -1, rcd, wce, sp;
-       struct scsi_disk *sdkp = to_scsi_disk(cdev);
-       struct scsi_device *sdp = sdkp->device;
-       char buffer[64];
-       char *buffer_data;
-       struct scsi_mode_data data;
-       struct scsi_sense_hdr sshdr;
-       int len;
-
-       if (sdp->type != TYPE_DISK)
-               /* no cache control on RBC devices; theoretically they
-                * can do it, but there's probably so many exceptions
-                * it's not worth the risk */
-               return -EINVAL;
-
-       for (i = 0; i < ARRAY_SIZE(sd_cache_types); i++) {
-               const int len = strlen(sd_cache_types[i]);
-               if (strncmp(sd_cache_types[i], buf, len) == 0 &&
-                   buf[len] == '\n') {
-                       ct = i;
-                       break;
-               }
-       }
-       if (ct < 0)
-               return -EINVAL;
-       rcd = ct & 0x01 ? 1 : 0;
-       wce = ct & 0x02 ? 1 : 0;
-       if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT,
-                           SD_MAX_RETRIES, &data, NULL))
-               return -EINVAL;
-       len = min_t(size_t, sizeof(buffer), data.length - data.header_length -
-                 data.block_descriptor_length);
-       buffer_data = buffer + data.header_length +
-               data.block_descriptor_length;
-       buffer_data[2] &= ~0x05;
-       buffer_data[2] |= wce << 2 | rcd;
-       sp = buffer_data[0] & 0x80 ? 1 : 0;
-
-       if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT,
-                            SD_MAX_RETRIES, &data, &sshdr)) {
-               if (scsi_sense_valid(&sshdr))
-                       scsi_print_sense_hdr(sdkp->disk->disk_name, &sshdr);
-               return -EINVAL;
-       }
-       sd_revalidate_disk(sdkp->disk);
-       return count;
-}
-
-static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf,
-                                     size_t count)
-{
-       struct scsi_disk *sdkp = to_scsi_disk(cdev);
-       struct scsi_device *sdp = sdkp->device;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EACCES;
-
-       if (sdp->type != TYPE_DISK)
-               return -EINVAL;
-
-       sdp->allow_restart = simple_strtoul(buf, NULL, 10);
-
-       return count;
-}
-
-static ssize_t sd_show_cache_type(struct class_device *cdev, char *buf)
-{
-       struct scsi_disk *sdkp = to_scsi_disk(cdev);
-       int ct = sdkp->RCD + 2*sdkp->WCE;
-
-       return snprintf(buf, 40, "%s\n", sd_cache_types[ct]);
-}
-
-static ssize_t sd_show_fua(struct class_device *cdev, char *buf)
-{
-       struct scsi_disk *sdkp = to_scsi_disk(cdev);
-
-       return snprintf(buf, 20, "%u\n", sdkp->DPOFUA);
-}
-
-static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf)
-{
-       struct scsi_disk *sdkp = to_scsi_disk(cdev);
-
-       return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart);
-}
-
-static struct class_device_attribute sd_disk_attrs[] = {
-       __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type,
-              sd_store_cache_type),
-       __ATTR(FUA, S_IRUGO, sd_show_fua, NULL),
-       __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart,
-              sd_store_allow_restart),
-       __ATTR_NULL,
-};
-
-static struct class sd_disk_class = {
-       .name           = "scsi_disk",
-       .owner          = THIS_MODULE,
-       .release        = scsi_disk_release,
-       .class_dev_attrs = sd_disk_attrs,
-};
 
 static struct scsi_driver sd_template = {
        .owner                  = THIS_MODULE,
@@ -304,6 +174,8 @@ static int sd_major(int major_idx)
        }
 }
 
+#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kref)
+
 static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
 {
        return container_of(disk->private_data, struct scsi_disk, driver);
@@ -316,7 +188,7 @@ static struct scsi_disk *__scsi_disk_get(struct gendisk *disk)
        if (disk->private_data) {
                sdkp = scsi_disk(disk);
                if (scsi_device_get(sdkp->device) == 0)
-                       class_device_get(&sdkp->cdev);
+                       kref_get(&sdkp->kref);
                else
                        sdkp = NULL;
        }
@@ -350,7 +222,7 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
        struct scsi_device *sdev = sdkp->device;
 
        mutex_lock(&sd_ref_mutex);
-       class_device_put(&sdkp->cdev);
+       kref_put(&sdkp->kref, scsi_disk_release);
        scsi_device_put(sdev);
        mutex_unlock(&sd_ref_mutex);
 }
@@ -502,7 +374,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                SCpnt->cmnd[4] = (unsigned char) this_count;
                SCpnt->cmnd[5] = 0;
        }
-       SCpnt->request_bufflen = this_count * sdp->sector_size;
+       SCpnt->request_bufflen = SCpnt->bufflen =
+                       this_count * sdp->sector_size;
 
        /*
         * We shouldn't disconnect in the middle of a sector, so with a dumb
@@ -915,10 +788,11 @@ static struct block_device_operations sd_fops = {
 static void sd_rw_intr(struct scsi_cmnd * SCpnt)
 {
        int result = SCpnt->result;
-       unsigned int xfer_size = SCpnt->request_bufflen;
-       unsigned int good_bytes = result ? 0 : xfer_size;
-       u64 start_lba = SCpnt->request->sector;
-       u64 bad_lba;
+       int this_count = SCpnt->bufflen;
+       int good_bytes = (result == 0 ? this_count : 0);
+       sector_t block_sectors = 1;
+       u64 first_err_block;
+       sector_t error_sector;
        struct scsi_sense_hdr sshdr;
        int sense_valid = 0;
        int sense_deferred = 0;
@@ -929,6 +803,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
                if (sense_valid)
                        sense_deferred = scsi_sense_is_deferred(&sshdr);
        }
+
 #ifdef CONFIG_SCSI_LOGGING
        SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", 
                                SCpnt->request->rq_disk->disk_name, result));
@@ -938,72 +813,89 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
                                sshdr.sense_key, sshdr.asc, sshdr.ascq));
        }
 #endif
-       if (driver_byte(result) != DRIVER_SENSE &&
-           (!sense_valid || sense_deferred))
-               goto out;
+       /*
+          Handle MEDIUM ERRORs that indicate partial success.  Since this is a
+          relatively rare error condition, no care is taken to avoid
+          unnecessary additional work such as memcpy's that could be avoided.
+        */
+       if (driver_byte(result) != 0 &&
+                sense_valid && !sense_deferred) {
+               switch (sshdr.sense_key) {
+               case MEDIUM_ERROR:
+                       if (!blk_fs_request(SCpnt->request))
+                               break;
+                       info_valid = scsi_get_sense_info_fld(
+                               SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+                               &first_err_block);
+                       /*
+                        * May want to warn and skip if following cast results
+                        * in actual truncation (if sector_t < 64 bits)
+                        */
+                       error_sector = (sector_t)first_err_block;
+                       if (SCpnt->request->bio != NULL)
+                               block_sectors = bio_sectors(SCpnt->request->bio);
+                       switch (SCpnt->device->sector_size) {
+                       case 1024:
+                               error_sector <<= 1;
+                               if (block_sectors < 2)
+                                       block_sectors = 2;
+                               break;
+                       case 2048:
+                               error_sector <<= 2;
+                               if (block_sectors < 4)
+                                       block_sectors = 4;
+                               break;
+                       case 4096:
+                               error_sector <<=3;
+                               if (block_sectors < 8)
+                                       block_sectors = 8;
+                               break;
+                       case 256:
+                               error_sector >>= 1;
+                               break;
+                       default:
+                               break;
+                       }
 
-       switch (sshdr.sense_key) {
-       case HARDWARE_ERROR:
-       case MEDIUM_ERROR:
-               if (!blk_fs_request(SCpnt->request))
-                       goto out;
-               info_valid = scsi_get_sense_info_fld(SCpnt->sense_buffer,
-                                                    SCSI_SENSE_BUFFERSIZE,
-                                                    &bad_lba);
-               if (!info_valid)
-                       goto out;
-               if (xfer_size <= SCpnt->device->sector_size)
-                       goto out;
-               switch (SCpnt->device->sector_size) {
-               case 256:
-                       start_lba <<= 1;
+                       error_sector &= ~(block_sectors - 1);
+                       good_bytes = (error_sector - SCpnt->request->sector) << 9;
+                       if (good_bytes < 0 || good_bytes >= this_count)
+                               good_bytes = 0;
                        break;
-               case 512:
-                       break;
-               case 1024:
-                       start_lba >>= 1;
-                       break;
-               case 2048:
-                       start_lba >>= 2;
+
+               case RECOVERED_ERROR: /* an error occurred, but it recovered */
+               case NO_SENSE: /* LLDD got sense data */
+                       /*
+                        * Inform the user, but make sure that it's not treated
+                        * as a hard error.
+                        */
+                       scsi_print_sense("sd", SCpnt);
+                       SCpnt->result = 0;
+                       memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+                       good_bytes = this_count;
                        break;
-               case 4096:
-                       start_lba >>= 3;
+
+               case ILLEGAL_REQUEST:
+                       if (SCpnt->device->use_10_for_rw &&
+                           (SCpnt->cmnd[0] == READ_10 ||
+                            SCpnt->cmnd[0] == WRITE_10))
+                               SCpnt->device->use_10_for_rw = 0;
+                       if (SCpnt->device->use_10_for_ms &&
+                           (SCpnt->cmnd[0] == MODE_SENSE_10 ||
+                            SCpnt->cmnd[0] == MODE_SELECT_10))
+                               SCpnt->device->use_10_for_ms = 0;
                        break;
+
                default:
-                       /* Print something here with limiting frequency. */
-                       goto out;
                        break;
                }
-               /* This computation should always be done in terms of
-                * the resolution of the device's medium.
-                */
-               good_bytes = (bad_lba - start_lba)*SCpnt->device->sector_size;
-               break;
-       case RECOVERED_ERROR:
-       case NO_SENSE:
-               /* Inform the user, but make sure that it's not treated
-                * as a hard error.
-                */
-               scsi_print_sense("sd", SCpnt);
-               SCpnt->result = 0;
-               memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
-               good_bytes = xfer_size;
-               break;
-       case ILLEGAL_REQUEST:
-               if (SCpnt->device->use_10_for_rw &&
-                   (SCpnt->cmnd[0] == READ_10 ||
-                    SCpnt->cmnd[0] == WRITE_10))
-                       SCpnt->device->use_10_for_rw = 0;
-               if (SCpnt->device->use_10_for_ms &&
-                   (SCpnt->cmnd[0] == MODE_SENSE_10 ||
-                    SCpnt->cmnd[0] == MODE_SELECT_10))
-                       SCpnt->device->use_10_for_ms = 0;
-               break;
-       default:
-               break;
        }
- out:
-       scsi_io_completion(SCpnt, good_bytes);
+       /*
+        * This calls the generic completion function, now that we know
+        * how many actual sectors finished, and how many sectors we need
+        * to say have failed.
+        */
+       scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
 }
 
 static int media_not_present(struct scsi_disk *sdkp,
@@ -1441,12 +1333,6 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
        if (!scsi_status_is_good(res))
                goto bad_sense;
 
-       if (!data.header_length) {
-               modepage = 6;
-               printk(KERN_ERR "%s: missing header in MODE_SENSE response\n",
-                      diskname);
-       }
-
        /* that went OK, now ask for the proper length */
        len = data.length;
 
@@ -1468,6 +1354,10 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
        res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr);
 
        if (scsi_status_is_good(res)) {
+               const char *types[] = {
+                       "write through", "none", "write back",
+                       "write back, no read (daft)"
+               };
                int ct = 0;
                int offset = data.header_length + data.block_descriptor_length;
 
@@ -1500,7 +1390,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
                ct =  sdkp->RCD + 2*sdkp->WCE;
 
                printk(KERN_NOTICE "SCSI device %s: drive cache: %s%s\n",
-                      diskname, sd_cache_types[ct],
+                      diskname, types[ct],
                       sdkp->DPOFUA ? " w/ FUA" : "");
 
                return;
@@ -1627,10 +1517,13 @@ static int sd_probe(struct device *dev)
                                        "sd_attach\n"));
 
        error = -ENOMEM;
-       sdkp = kzalloc(sizeof(*sdkp), GFP_KERNEL);
+       sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL);
        if (!sdkp)
                goto out;
 
+       memset (sdkp, 0, sizeof(*sdkp));
+       kref_init(&sdkp->kref);
+
        gd = alloc_disk(16);
        if (!gd)
                goto out_free;
@@ -1647,16 +1540,7 @@ static int sd_probe(struct device *dev)
        if (error)
                goto out_put;
 
-       class_device_initialize(&sdkp->cdev);
-       sdkp->cdev.dev = &sdp->sdev_gendev;
-       sdkp->cdev.class = &sd_disk_class;
-       strncpy(sdkp->cdev.class_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE);
-
-       if (class_device_add(&sdkp->cdev))
-               goto out_put;
-
        get_device(&sdp->sdev_gendev);
-
        sdkp->device = sdp;
        sdkp->driver = &sd_template;
        sdkp->disk = gd;
@@ -1688,6 +1572,8 @@ static int sd_probe(struct device *dev)
                        'a' + m1, 'a' + m2, 'a' + m3);
        }
 
+       strcpy(gd->devfs_name, sdp->devfs_name);
+
        gd->private_data = &sdkp->driver;
        gd->queue = sdkp->device->request_queue;
 
@@ -1706,11 +1592,11 @@ static int sd_probe(struct device *dev)
 
        return 0;
 
- out_put:
+out_put:
        put_disk(gd);
- out_free:
+out_free:
        kfree(sdkp);
- out:
+out:
        return error;
 }
 
@@ -1729,13 +1615,12 @@ static int sd_remove(struct device *dev)
 {
        struct scsi_disk *sdkp = dev_get_drvdata(dev);
 
-       class_device_del(&sdkp->cdev);
        del_gendisk(sdkp->disk);
        sd_shutdown(dev);
 
        mutex_lock(&sd_ref_mutex);
        dev_set_drvdata(dev, NULL);
-       class_device_put(&sdkp->cdev);
+       kref_put(&sdkp->kref, scsi_disk_release);
        mutex_unlock(&sd_ref_mutex);
 
        return 0;
@@ -1743,16 +1628,16 @@ static int sd_remove(struct device *dev)
 
 /**
  *     scsi_disk_release - Called to free the scsi_disk structure
- *     @cdev: pointer to embedded class device
+ *     @kref: pointer to embedded kref
  *
  *     sd_ref_mutex must be held entering this routine.  Because it is
  *     called on last put, you should always use the scsi_disk_get()
  *     scsi_disk_put() helpers which manipulate the semaphore directly
- *     and never do a direct class_device_put().
+ *     and never do a direct kref_put().
  **/
-static void scsi_disk_release(struct class_device *cdev)
+static void scsi_disk_release(struct kref *kref)
 {
-       struct scsi_disk *sdkp = to_scsi_disk(cdev);
+       struct scsi_disk *sdkp = to_scsi_disk(kref);
        struct gendisk *disk = sdkp->disk;
        
        spin_lock(&sd_index_lock);
@@ -1806,8 +1691,6 @@ static int __init init_sd(void)
        if (!majors)
                return -ENODEV;
 
-       class_register(&sd_disk_class);
-
        return scsi_register_driver(&sd_template.gendrv);
 }
 
@@ -1825,9 +1708,11 @@ static void __exit exit_sd(void)
        scsi_unregister_driver(&sd_template.gendrv);
        for (i = 0; i < SD_MAJORS; i++)
                unregister_blkdev(sd_major(i), "sd");
-
-       class_unregister(&sd_disk_class);
 }
 
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Youngdale");
+MODULE_DESCRIPTION("SCSI disk (sd) driver");
+
 module_init(init_sd);
 module_exit(exit_sd);