Merge git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm
[cascardo/linux.git] / drivers / scsi / sd.c
index 0994ab6..2714bec 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/blkdev.h>
 #include <linux/blkpg.h>
 #include <linux/delay.h>
+#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/string_helpers.h>
 #include <linux/async.h>
@@ -118,8 +119,8 @@ static DEFINE_IDA(sd_index_ida);
  * object after last put) */
 static DEFINE_MUTEX(sd_ref_mutex);
 
-struct kmem_cache *sd_cdb_cache;
-mempool_t *sd_cdb_pool;
+static struct kmem_cache *sd_cdb_cache;
+static mempool_t *sd_cdb_pool;
 
 static const char *sd_cache_types[] = {
        "write through", "none", "write back",
@@ -146,7 +147,7 @@ sd_store_cache_type(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        for (i = 0; i < ARRAY_SIZE(sd_cache_types); i++) {
-               const int len = strlen(sd_cache_types[i]);
+               len = strlen(sd_cache_types[i]);
                if (strncmp(sd_cache_types[i], buf, len) == 0 &&
                    buf[len] == '\n') {
                        ct = i;
@@ -433,7 +434,6 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq)
                nr_sectors >>= 3;
        }
 
-       rq->cmd_type = REQ_TYPE_BLOCK_PC;
        rq->timeout = SD_TIMEOUT;
 
        memset(rq->cmd, 0, rq->cmd_len);
@@ -468,13 +468,15 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq)
        blk_add_request_payload(rq, page, len);
        ret = scsi_setup_blk_pc_cmnd(sdp, rq);
        rq->buffer = page_address(page);
+       if (ret != BLKPREP_OK) {
+               __free_page(page);
+               rq->buffer = NULL;
+       }
        return ret;
 }
 
 static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq)
 {
-       /* for now, we use REQ_TYPE_BLOCK_PC. */
-       rq->cmd_type = REQ_TYPE_BLOCK_PC;
        rq->timeout = SD_TIMEOUT;
        rq->retries = SD_MAX_RETRIES;
        rq->cmd[0] = SYNCHRONIZE_CACHE;
@@ -485,8 +487,10 @@ static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq)
 
 static void sd_unprep_fn(struct request_queue *q, struct request *rq)
 {
-       if (rq->cmd_flags & REQ_DISCARD)
-               __free_page(virt_to_page(rq->buffer));
+       if (rq->cmd_flags & REQ_DISCARD) {
+               free_page((unsigned long)rq->buffer);
+               rq->buffer = NULL;
+       }
 }
 
 /**
@@ -776,6 +780,8 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
  *     or from within the kernel (e.g. as a result of a mount(1) ).
  *     In the latter case @inode and @filp carry an abridged amount
  *     of information as noted above.
+ *
+ *     Locking: called with bdev->bd_mutex held.
  **/
 static int sd_open(struct block_device *bdev, fmode_t mode)
 {
@@ -790,6 +796,10 @@ static int sd_open(struct block_device *bdev, fmode_t mode)
 
        sdev = sdkp->device;
 
+       retval = scsi_autopm_get_device(sdev);
+       if (retval)
+               goto error_autopm;
+
        /*
         * If the device is in error recovery, wait until it is done.
         * If the device is offline, then disallow any access to it.
@@ -826,7 +836,7 @@ static int sd_open(struct block_device *bdev, fmode_t mode)
        if (!scsi_device_online(sdev))
                goto error_out;
 
-       if (!sdkp->openers++ && sdev->removable) {
+       if ((atomic_inc_return(&sdkp->openers) == 1) && sdev->removable) {
                if (scsi_block_when_processing_errors(sdev))
                        scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT);
        }
@@ -834,6 +844,8 @@ static int sd_open(struct block_device *bdev, fmode_t mode)
        return 0;
 
 error_out:
+       scsi_autopm_put_device(sdev);
+error_autopm:
        scsi_disk_put(sdkp);
        return retval;  
 }
@@ -848,6 +860,8 @@ error_out:
  *
  *     Note: may block (uninterruptible) if error recovery is underway
  *     on this disk.
+ *
+ *     Locking: called with bdev->bd_mutex held.
  **/
 static int sd_release(struct gendisk *disk, fmode_t mode)
 {
@@ -856,7 +870,7 @@ static int sd_release(struct gendisk *disk, fmode_t mode)
 
        SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_release\n"));
 
-       if (!--sdkp->openers && sdev->removable) {
+       if (atomic_dec_return(&sdkp->openers) && sdev->removable) {
                if (scsi_block_when_processing_errors(sdev))
                        scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
        }
@@ -865,6 +879,8 @@ static int sd_release(struct gendisk *disk, fmode_t mode)
         * XXX and what if there are packets in flight and this close()
         * XXX is followed by a "rmmod sd_mod"?
         */
+
+       scsi_autopm_put_device(sdev);
        scsi_disk_put(sdkp);
        return 0;
 }
@@ -927,7 +943,7 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
        error = scsi_nonblockable_ioctl(sdp, cmd, p,
                                        (mode & FMODE_NDELAY) != 0);
        if (!scsi_block_when_processing_errors(sdp) || !error)
-               return error;
+               goto out;
 
        /*
         * Send SCSI addressing ioctls directly to mid level, send other
@@ -937,13 +953,17 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
        switch (cmd) {
                case SCSI_IOCTL_GET_IDLUN:
                case SCSI_IOCTL_GET_BUS_NUMBER:
-                       return scsi_ioctl(sdp, cmd, p);
+                       error = scsi_ioctl(sdp, cmd, p);
+                       break;
                default:
                        error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p);
                        if (error != -ENOTTY)
-                               return error;
+                               break;
+                       error = scsi_ioctl(sdp, cmd, p);
+                       break;
        }
-       return scsi_ioctl(sdp, cmd, p);
+out:
+       return error;
 }
 
 static void set_media_not_present(struct scsi_disk *sdkp)
@@ -1117,7 +1137,7 @@ static const struct block_device_operations sd_fops = {
        .owner                  = THIS_MODULE,
        .open                   = sd_open,
        .release                = sd_release,
-       .locked_ioctl           = sd_ioctl,
+       .ioctl                  = sd_ioctl,
        .getgeo                 = sd_getgeo,
 #ifdef CONFIG_COMPAT
        .compat_ioctl           = sd_compat_ioctl,
@@ -1185,6 +1205,12 @@ static int sd_done(struct scsi_cmnd *SCpnt)
        int sense_valid = 0;
        int sense_deferred = 0;
 
+       if (SCpnt->request->cmd_flags & REQ_DISCARD) {
+               if (!result)
+                       scsi_set_resid(SCpnt, 0);
+               return good_bytes;
+       }
+
        if (result) {
                sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr);
                if (sense_valid)
@@ -1397,7 +1423,7 @@ sd_spinup_disk(struct scsi_disk *sdkp)
 /*
  * Determine whether disk supports Data Integrity Field.
  */
-void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer)
+static void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer)
 {
        struct scsi_device *sdp = sdkp->device;
        u8 type;
@@ -1943,7 +1969,7 @@ defaults:
  * The ATO bit indicates whether the DIF application tag is available
  * for use by the operating system.
  */
-void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
+static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
 {
        int res, offset;
        struct scsi_device *sdp = sdkp->device;
@@ -2255,7 +2281,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
        if (sdp->removable)
                gd->flags |= GENHD_FL_REMOVABLE;
 
-       dev_set_drvdata(dev, sdkp);
        add_disk(gd);
        sd_dif_config_host(sdkp);
 
@@ -2263,6 +2288,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
 
        sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
                  sdp->removable ? "removable " : "");
+       scsi_autopm_put_device(sdp);
        put_device(&sdkp->dev);
 }
 
@@ -2289,7 +2315,7 @@ static int sd_probe(struct device *dev)
        struct scsi_device *sdp = to_scsi_device(dev);
        struct scsi_disk *sdkp;
        struct gendisk *gd;
-       u32 index;
+       int index;
        int error;
 
        error = -ENODEV;
@@ -2328,7 +2354,7 @@ static int sd_probe(struct device *dev)
        sdkp->driver = &sd_template;
        sdkp->disk = gd;
        sdkp->index = index;
-       sdkp->openers = 0;
+       atomic_set(&sdkp->openers, 0);
        sdkp->previous_state = 1;
 
        if (!sdp->request_queue->rq_timeout) {
@@ -2340,14 +2366,15 @@ static int sd_probe(struct device *dev)
        }
 
        device_initialize(&sdkp->dev);
-       sdkp->dev.parent = &sdp->sdev_gendev;
+       sdkp->dev.parent = dev;
        sdkp->dev.class = &sd_disk_class;
-       dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev));
+       dev_set_name(&sdkp->dev, dev_name(dev));
 
        if (device_add(&sdkp->dev))
                goto out_free_index;
 
-       get_device(&sdp->sdev_gendev);
+       get_device(dev);
+       dev_set_drvdata(dev, sdkp);
 
        get_device(&sdkp->dev); /* prevent release before async_schedule */
        async_schedule(sd_probe_async, sdkp);
@@ -2381,8 +2408,10 @@ static int sd_remove(struct device *dev)
 {
        struct scsi_disk *sdkp;
 
-       async_synchronize_full();
        sdkp = dev_get_drvdata(dev);
+       scsi_autopm_get_device(sdkp->device);
+
+       async_synchronize_full();
        blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn);
        blk_queue_unprep_rq(sdkp->device->request_queue, NULL);
        device_del(&sdkp->dev);