]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/scsi/sd.c
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[karo-tx-linux.git] / drivers / scsi / sd.c
index 8fa3d0b73ad9bf42164f9e4fbd633fb056018736..80f39b8b02239ad325143fb3e5e38c9753729ab4 100644 (file)
@@ -142,7 +142,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;
-       const char *temp = "temporary ";
+       static const char temp[] = "temporary ";
        int len;
 
        if (sdp->type != TYPE_DISK)
@@ -442,8 +442,10 @@ sd_store_write_same_blocks(struct device *dev, struct device_attribute *attr,
 
        if (max == 0)
                sdp->no_write_same = 1;
-       else if (max <= SD_MAX_WS16_BLOCKS)
+       else if (max <= SD_MAX_WS16_BLOCKS) {
+               sdp->no_write_same = 0;
                sdkp->max_ws_blocks = max;
+       }
 
        sd_config_write_same(sdkp);
 
@@ -503,6 +505,16 @@ static struct scsi_driver sd_template = {
        .eh_action              = sd_eh_action,
 };
 
+/*
+ * Dummy kobj_map->probe function.
+ * The default ->probe function will call modprobe, which is
+ * pointless as this module is already loaded.
+ */
+static struct kobject *sd_default_probe(dev_t devt, int *partno, void *data)
+{
+       return NULL;
+}
+
 /*
  * Device no to disk mapping:
  * 
@@ -740,7 +752,6 @@ static void sd_config_write_same(struct scsi_disk *sdkp)
 {
        struct request_queue *q = sdkp->disk->queue;
        unsigned int logical_block_size = sdkp->device->sector_size;
-       unsigned int blocks = 0;
 
        if (sdkp->device->no_write_same) {
                sdkp->max_ws_blocks = 0;
@@ -752,18 +763,20 @@ static void sd_config_write_same(struct scsi_disk *sdkp)
         * blocks per I/O unless the device explicitly advertises a
         * bigger limit.
         */
-       if (sdkp->max_ws_blocks == 0)
-               sdkp->max_ws_blocks = SD_MAX_WS10_BLOCKS;
-
-       if (sdkp->ws16 || sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS)
-               blocks = min_not_zero(sdkp->max_ws_blocks,
-                                     (u32)SD_MAX_WS16_BLOCKS);
-       else
-               blocks = min_not_zero(sdkp->max_ws_blocks,
-                                     (u32)SD_MAX_WS10_BLOCKS);
+       if (sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS)
+               sdkp->max_ws_blocks = min_not_zero(sdkp->max_ws_blocks,
+                                                  (u32)SD_MAX_WS16_BLOCKS);
+       else if (sdkp->ws16 || sdkp->ws10 || sdkp->device->no_report_opcodes)
+               sdkp->max_ws_blocks = min_not_zero(sdkp->max_ws_blocks,
+                                                  (u32)SD_MAX_WS10_BLOCKS);
+       else {
+               sdkp->device->no_write_same = 1;
+               sdkp->max_ws_blocks = 0;
+       }
 
 out:
-       blk_queue_max_write_same_sectors(q, blocks * (logical_block_size >> 9));
+       blk_queue_max_write_same_sectors(q, sdkp->max_ws_blocks *
+                                        (logical_block_size >> 9));
 }
 
 /**
@@ -2635,9 +2648,24 @@ static void sd_read_block_provisioning(struct scsi_disk *sdkp)
 
 static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)
 {
-       if (scsi_report_opcode(sdkp->device, buffer, SD_BUF_SIZE,
-                              WRITE_SAME_16))
+       struct scsi_device *sdev = sdkp->device;
+
+       if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, INQUIRY) < 0) {
+               sdev->no_report_opcodes = 1;
+
+               /* Disable WRITE SAME if REPORT SUPPORTED OPERATION
+                * CODES is unsupported and the device has an ATA
+                * Information VPD page (SAT).
+                */
+               if (!scsi_get_vpd_page(sdev, 0x89, buffer, SD_BUF_SIZE))
+                       sdev->no_write_same = 1;
+       }
+
+       if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME_16) == 1)
                sdkp->ws16 = 1;
+
+       if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME) == 1)
+               sdkp->ws10 = 1;
 }
 
 static int sd_try_extended_inquiry(struct scsi_device *sdp)
@@ -2970,8 +2998,10 @@ static int sd_probe(struct device *dev)
 static int sd_remove(struct device *dev)
 {
        struct scsi_disk *sdkp;
+       dev_t devt;
 
        sdkp = dev_get_drvdata(dev);
+       devt = disk_devt(sdkp->disk);
        scsi_autopm_get_device(sdkp->device);
 
        async_synchronize_full_domain(&scsi_sd_probe_domain);
@@ -2981,6 +3011,9 @@ static int sd_remove(struct device *dev)
        del_gendisk(sdkp->disk);
        sd_shutdown(dev);
 
+       blk_register_region(devt, SD_MINORS, NULL,
+                           sd_default_probe, NULL, NULL);
+
        mutex_lock(&sd_ref_mutex);
        dev_set_drvdata(dev, NULL);
        put_device(&sdkp->dev);
@@ -3124,9 +3157,13 @@ static int __init init_sd(void)
 
        SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
 
-       for (i = 0; i < SD_MAJORS; i++)
-               if (register_blkdev(sd_major(i), "sd") == 0)
-                       majors++;
+       for (i = 0; i < SD_MAJORS; i++) {
+               if (register_blkdev(sd_major(i), "sd") != 0)
+                       continue;
+               majors++;
+               blk_register_region(sd_major(i), SD_MINORS, NULL,
+                                   sd_default_probe, NULL, NULL);
+       }
 
        if (!majors)
                return -ENODEV;
@@ -3185,8 +3222,10 @@ static void __exit exit_sd(void)
 
        class_unregister(&sd_disk_class);
 
-       for (i = 0; i < SD_MAJORS; i++)
+       for (i = 0; i < SD_MAJORS; i++) {
+               blk_unregister_region(sd_major(i), SD_MINORS);
                unregister_blkdev(sd_major(i), "sd");
+       }
 }
 
 module_init(init_sd);