SCSI: fix crashes in sd and sr runtime PM
[pandora-kernel.git] / drivers / scsi / sd.c
index fa3a591..9a4f52d 100644 (file)
@@ -138,6 +138,7 @@ sd_store_cache_type(struct device *dev, struct device_attribute *attr,
        char *buffer_data;
        struct scsi_mode_data data;
        struct scsi_sense_hdr sshdr;
+       static const char temp[] = "temporary ";
        int len;
 
        if (sdp->type != TYPE_DISK)
@@ -146,6 +147,13 @@ sd_store_cache_type(struct device *dev, struct device_attribute *attr,
                 * it's not worth the risk */
                return -EINVAL;
 
+       if (strncmp(buf, temp, sizeof(temp) - 1) == 0) {
+               buf += sizeof(temp) - 1;
+               sdkp->cache_override = 1;
+       } else {
+               sdkp->cache_override = 0;
+       }
+
        for (i = 0; i < ARRAY_SIZE(sd_cache_types); i++) {
                len = strlen(sd_cache_types[i]);
                if (strncmp(sd_cache_types[i], buf, len) == 0 &&
@@ -158,6 +166,13 @@ sd_store_cache_type(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
        rcd = ct & 0x01 ? 1 : 0;
        wce = ct & 0x02 ? 1 : 0;
+
+       if (sdkp->cache_override) {
+               sdkp->WCE = wce;
+               sdkp->RCD = rcd;
+               return count;
+       }
+
        if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT,
                            SD_MAX_RETRIES, &data, NULL))
                return -EINVAL;
@@ -626,10 +641,17 @@ 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)
 {
+       struct scsi_cmnd *SCpnt = rq->special;
+
        if (rq->cmd_flags & REQ_DISCARD) {
                free_page((unsigned long)rq->buffer);
                rq->buffer = NULL;
        }
+       if (SCpnt->cmnd != rq->cmd) {
+               mempool_free(SCpnt->cmnd, sd_cdb_pool);
+               SCpnt->cmnd = NULL;
+               SCpnt->cmd_len = 0;
+       }
 }
 
 /**
@@ -1074,6 +1096,10 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
        SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, "
                                    "cmd=0x%x\n", disk->disk_name, cmd));
 
+       error = scsi_verify_blk_ioctl(bdev, cmd);
+       if (error < 0)
+               return error;
+
        /*
         * If we are in the middle of error recovery, don't let anyone
         * else try and use this device.  Also, if error recovery fails, it
@@ -1096,7 +1122,7 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
                        error = scsi_ioctl(sdp, cmd, p);
                        break;
                default:
-                       error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p);
+                       error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p);
                        if (error != -ENOTTY)
                                break;
                        error = scsi_ioctl(sdp, cmd, p);
@@ -1266,6 +1292,11 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
                           unsigned int cmd, unsigned long arg)
 {
        struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device;
+       int ret;
+
+       ret = scsi_verify_blk_ioctl(bdev, cmd);
+       if (ret < 0)
+               return -ENOIOCTLCMD;
 
        /*
         * If we are in the middle of error recovery, don't let anyone
@@ -1277,8 +1308,6 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
                return -ENODEV;
               
        if (sdev->host->hostt->compat_ioctl) {
-               int ret;
-
                ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
 
                return ret;
@@ -1309,6 +1338,7 @@ static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
 {
        u64 start_lba = blk_rq_pos(scmd->request);
        u64 end_lba = blk_rq_pos(scmd->request) + (scsi_bufflen(scmd) / 512);
+       u64 factor = scmd->device->sector_size / 512;
        u64 bad_lba;
        int info_valid;
        /*
@@ -1330,16 +1360,9 @@ static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
        if (scsi_bufflen(scmd) <= scmd->device->sector_size)
                return 0;
 
-       if (scmd->device->sector_size < 512) {
-               /* only legitimate sector_size here is 256 */
-               start_lba <<= 1;
-               end_lba <<= 1;
-       } else {
-               /* be careful ... don't want any overflows */
-               u64 factor = scmd->device->sector_size / 512;
-               do_div(start_lba, factor);
-               do_div(end_lba, factor);
-       }
+       /* be careful ... don't want any overflows */
+       do_div(start_lba, factor);
+       do_div(end_lba, factor);
 
        /* The bad lba was reported incorrectly, we have no idea where
         * the error is.
@@ -1430,21 +1453,6 @@ static int sd_done(struct scsi_cmnd *SCpnt)
        if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt))
                sd_dif_complete(SCpnt, good_bytes);
 
-       if (scsi_host_dif_capable(sdkp->device->host, sdkp->protection_type)
-           == SD_DIF_TYPE2_PROTECTION && SCpnt->cmnd != SCpnt->request->cmd) {
-
-               /* We have to print a failed command here as the
-                * extended CDB gets freed before scsi_io_completion()
-                * is called.
-                */
-               if (result)
-                       scsi_print_command(SCpnt);
-
-               mempool_free(SCpnt->cmnd, sd_cdb_pool);
-               SCpnt->cmnd = NULL;
-               SCpnt->cmd_len = 0;
-       }
-
        return good_bytes;
 }
 
@@ -1881,8 +1889,7 @@ got_data:
        if (sector_size != 512 &&
            sector_size != 1024 &&
            sector_size != 2048 &&
-           sector_size != 4096 &&
-           sector_size != 256) {
+           sector_size != 4096) {
                sd_printk(KERN_NOTICE, sdkp, "Unsupported sector size %d.\n",
                          sector_size);
                /*
@@ -1931,8 +1938,6 @@ got_data:
                sdkp->capacity <<= 2;
        else if (sector_size == 1024)
                sdkp->capacity <<= 1;
-       else if (sector_size == 256)
-               sdkp->capacity >>= 1;
 
        blk_queue_physical_block_size(sdp->request_queue,
                                      sdkp->physical_block_size);
@@ -2030,6 +2035,10 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
        int old_rcd = sdkp->RCD;
        int old_dpofua = sdkp->DPOFUA;
 
+
+       if (sdkp->cache_override)
+               return;
+
        first_len = 4;
        if (sdp->skip_ms_page_8) {
                if (sdp->type == TYPE_RBC)
@@ -2118,14 +2127,9 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
                        }
                }
 
-               if (modepage == 0x3F) {
-                       sd_printk(KERN_ERR, sdkp, "No Caching mode page "
-                                 "present\n");
-                       goto defaults;
-               } else if ((buffer[offset] & 0x3f) != modepage) {
-                       sd_printk(KERN_ERR, sdkp, "Got wrong page\n");
-                       goto defaults;
-               }
+               sd_printk(KERN_ERR, sdkp, "No Caching mode page found\n");
+               goto defaults;
+
        Page_found:
                if (modepage == 8) {
                        sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0);
@@ -2136,7 +2140,10 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
                }
 
                sdkp->DPOFUA = (data.device_specific & 0x10) != 0;
-               if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) {
+               if (sdp->broken_fua) {
+                       sd_printk(KERN_NOTICE, sdkp, "Disabling FUA\n");
+                       sdkp->DPOFUA = 0;
+               } else if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) {
                        sd_printk(KERN_NOTICE, sdkp,
                                  "Uses READ/WRITE(6), disabling FUA\n");
                        sdkp->DPOFUA = 0;
@@ -2511,6 +2518,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
        sdkp->capacity = 0;
        sdkp->media_present = 1;
        sdkp->write_prot = 0;
+       sdkp->cache_override = 0;
        sdkp->WCE = 0;
        sdkp->RCD = 0;
        sdkp->ATO = 0;
@@ -2759,8 +2767,8 @@ static int sd_suspend(struct device *dev, pm_message_t mesg)
        struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
        int ret = 0;
 
-       if (!sdkp)
-               return 0;       /* this can happen */
+       if (!sdkp)      /* E.g.: runtime suspend following sd_remove() */
+               return 0;
 
        if (sdkp->WCE) {
                sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
@@ -2784,6 +2792,9 @@ static int sd_resume(struct device *dev)
        struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
        int ret = 0;
 
+       if (!sdkp)      /* E.g.: runtime resume at the start of sd_probe() */
+               return 0;
+
        if (!sdkp->device->manage_start_stop)
                goto done;
 
@@ -2818,10 +2829,6 @@ static int __init init_sd(void)
        if (err)
                goto err_out;
 
-       err = scsi_register_driver(&sd_template.gendrv);
-       if (err)
-               goto err_out_class;
-
        sd_cdb_cache = kmem_cache_create("sd_ext_cdb", SD_EXT_CDB_SIZE,
                                         0, 0, NULL);
        if (!sd_cdb_cache) {
@@ -2835,8 +2842,15 @@ static int __init init_sd(void)
                goto err_out_cache;
        }
 
+       err = scsi_register_driver(&sd_template.gendrv);
+       if (err)
+               goto err_out_driver;
+
        return 0;
 
+err_out_driver:
+       mempool_destroy(sd_cdb_pool);
+
 err_out_cache:
        kmem_cache_destroy(sd_cdb_cache);
 
@@ -2859,10 +2873,10 @@ static void __exit exit_sd(void)
 
        SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
 
+       scsi_unregister_driver(&sd_template.gendrv);
        mempool_destroy(sd_cdb_pool);
        kmem_cache_destroy(sd_cdb_cache);
 
-       scsi_unregister_driver(&sd_template.gendrv);
        class_unregister(&sd_disk_class);
 
        for (i = 0; i < SD_MAJORS; i++)