Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[cascardo/linux.git] / drivers / scsi / sd.c
index de564b3..8613a13 100644 (file)
@@ -177,24 +177,38 @@ static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
        return container_of(disk->private_data, struct scsi_disk, driver);
 }
 
-static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
+static struct scsi_disk *__scsi_disk_get(struct gendisk *disk)
 {
        struct scsi_disk *sdkp = NULL;
 
+       if (disk->private_data) {
+               sdkp = scsi_disk(disk);
+               if (scsi_device_get(sdkp->device) == 0)
+                       kref_get(&sdkp->kref);
+               else
+                       sdkp = NULL;
+       }
+       return sdkp;
+}
+
+static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
+{
+       struct scsi_disk *sdkp;
+
        down(&sd_ref_sem);
-       if (disk->private_data == NULL)
-               goto out;
-       sdkp = scsi_disk(disk);
-       kref_get(&sdkp->kref);
-       if (scsi_device_get(sdkp->device))
-               goto out_put;
+       sdkp = __scsi_disk_get(disk);
        up(&sd_ref_sem);
        return sdkp;
+}
 
- out_put:
-       kref_put(&sdkp->kref, scsi_disk_release);
-       sdkp = NULL;
- out:
+static struct scsi_disk *scsi_disk_get_from_dev(struct device *dev)
+{
+       struct scsi_disk *sdkp;
+
+       down(&sd_ref_sem);
+       sdkp = dev_get_drvdata(dev);
+       if (sdkp)
+               sdkp = __scsi_disk_get(sdkp->disk);
        up(&sd_ref_sem);
        return sdkp;
 }
@@ -235,6 +249,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                        return 0;
 
                memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd));
+               SCpnt->cmd_len = rq->cmd_len;
                if (rq_data_dir(rq) == WRITE)
                        SCpnt->sc_data_direction = DMA_TO_DEVICE;
                else if (rq->data_len)
@@ -715,16 +730,17 @@ static int sd_sync_cache(struct scsi_device *sdp)
 
 static int sd_issue_flush(struct device *dev, sector_t *error_sector)
 {
+       int ret = 0;
        struct scsi_device *sdp = to_scsi_device(dev);
-       struct scsi_disk *sdkp = dev_get_drvdata(dev);
+       struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
 
        if (!sdkp)
                return -ENODEV;
 
-       if (!sdkp->WCE)
-               return 0;
-
-       return sd_sync_cache(sdp);
+       if (sdkp->WCE)
+               ret = sd_sync_cache(sdp);
+       scsi_disk_put(sdkp);
+       return ret;
 }
 
 static void sd_end_flush(request_queue_t *q, struct request *flush_rq)
@@ -755,21 +771,24 @@ static int sd_prepare_flush(request_queue_t *q, struct request *rq)
        struct scsi_device *sdev = q->queuedata;
        struct scsi_disk *sdkp = dev_get_drvdata(&sdev->sdev_gendev);
 
-       if (sdkp->WCE) {
-               memset(rq->cmd, 0, sizeof(rq->cmd));
-               rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
-               rq->timeout = SD_TIMEOUT;
-               rq->cmd[0] = SYNCHRONIZE_CACHE;
-               return 1;
-       }
+       if (!sdkp || !sdkp->WCE)
+               return 0;
 
-       return 0;
+       memset(rq->cmd, 0, sizeof(rq->cmd));
+       rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
+       rq->timeout = SD_TIMEOUT;
+       rq->cmd[0] = SYNCHRONIZE_CACHE;
+       return 1;
 }
 
 static void sd_rescan(struct device *dev)
 {
-       struct scsi_disk *sdkp = dev_get_drvdata(dev);
-       sd_revalidate_disk(sdkp->disk);
+       struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
+
+       if (sdkp) {
+               sd_revalidate_disk(sdkp->disk);
+               scsi_disk_put(sdkp);
+       }
 }
 
 
@@ -1252,14 +1271,13 @@ got_data:
                 * Jacques Gelinas (Jacques@solucorp.qc.ca)
                 */
                int hard_sector = sector_size;
-               sector_t sz = sdkp->capacity * (hard_sector/256);
+               sector_t sz = (sdkp->capacity/2) * (hard_sector/256);
                request_queue_t *queue = sdp->request_queue;
-               sector_t mb;
+               sector_t mb = sz;
 
                blk_queue_hardsect_size(queue, hard_sector);
                /* avoid 64-bit division on 32-bit platforms */
-               mb = sz >> 1;
-               sector_div(sz, 1250);
+               sector_div(sz, 625);
                mb -= sz - 974;
                sector_div(mb, 1950);
 
@@ -1534,8 +1552,8 @@ static int sd_probe(struct device *dev)
        if (sdp->type != TYPE_DISK && sdp->type != TYPE_MOD && sdp->type != TYPE_RBC)
                goto out;
 
-       SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n", 
-                        sdp->host->host_no, sdp->channel, sdp->id, sdp->lun));
+       SCSI_LOG_HLQUEUE(3, sdev_printk(KERN_INFO, sdp,
+                                       "sd_attach\n"));
 
        error = -ENOMEM;
        sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL);
@@ -1561,6 +1579,7 @@ static int sd_probe(struct device *dev)
        if (error)
                goto out_put;
 
+       get_device(&sdp->sdev_gendev);
        sdkp->device = sdp;
        sdkp->driver = &sd_template;
        sdkp->disk = gd;
@@ -1607,10 +1626,8 @@ static int sd_probe(struct device *dev)
        dev_set_drvdata(dev, sdkp);
        add_disk(gd);
 
-       printk(KERN_NOTICE "Attached scsi %sdisk %s at scsi%d, channel %d, "
-              "id %d, lun %d\n", sdp->removable ? "removable " : "",
-              gd->disk_name, sdp->host->host_no, sdp->channel,
-              sdp->id, sdp->lun);
+       sdev_printk(KERN_NOTICE, sdp, "Attached scsi %sdisk %s\n",
+                   sdp->removable ? "removable " : "", gd->disk_name);
 
        return 0;
 
@@ -1639,7 +1656,9 @@ static int sd_remove(struct device *dev)
 
        del_gendisk(sdkp->disk);
        sd_shutdown(dev);
+
        down(&sd_ref_sem);
+       dev_set_drvdata(dev, NULL);
        kref_put(&sdkp->kref, scsi_disk_release);
        up(&sd_ref_sem);
 
@@ -1665,8 +1684,8 @@ static void scsi_disk_release(struct kref *kref)
        spin_unlock(&sd_index_lock);
 
        disk->private_data = NULL;
-
        put_disk(disk);
+       put_device(&sdkp->device->sdev_gendev);
 
        kfree(sdkp);
 }
@@ -1679,18 +1698,18 @@ static void scsi_disk_release(struct kref *kref)
 static void sd_shutdown(struct device *dev)
 {
        struct scsi_device *sdp = to_scsi_device(dev);
-       struct scsi_disk *sdkp = dev_get_drvdata(dev);
+       struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
 
        if (!sdkp)
                return;         /* this can happen */
 
-       if (!sdkp->WCE)
-               return;
-
-       printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n",
-                       sdkp->disk->disk_name);
-       sd_sync_cache(sdp);
-}      
+       if (sdkp->WCE) {
+               printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n",
+                               sdkp->disk->disk_name);
+               sd_sync_cache(sdp);
+       }
+       scsi_disk_put(sdkp);
+}
 
 /**
  *     init_sd - entry point for this driver (both when built in or when