]> Pileus Git - ~andy/linux/blobdiff - drivers/scsi/sd.c
Merge branch 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[~andy/linux] / drivers / scsi / sd.c
index de6c60320f6ffb70f1b9d00a1677f1f36caabba0..8802e48bc063408710792451e95cab70ce4b1a0e 100644 (file)
@@ -97,6 +97,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
 #endif
 
 static int  sd_revalidate_disk(struct gendisk *);
+static void sd_unlock_native_capacity(struct gendisk *disk);
 static int  sd_probe(struct device *);
 static int  sd_remove(struct device *);
 static void sd_shutdown(struct device *);
@@ -1101,6 +1102,7 @@ static const struct block_device_operations sd_fops = {
 #endif
        .media_changed          = sd_media_changed,
        .revalidate_disk        = sd_revalidate_disk,
+       .unlock_native_capacity = sd_unlock_native_capacity,
 };
 
 static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
@@ -1434,6 +1436,8 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
 #error RC16_LEN must not be more than SD_BUF_SIZE
 #endif
 
+#define READ_CAPACITY_RETRIES_ON_RESET 10
+
 static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
                                                unsigned char *buffer)
 {
@@ -1441,7 +1445,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
        struct scsi_sense_hdr sshdr;
        int sense_valid = 0;
        int the_result;
-       int retries = 3;
+       int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET;
        unsigned int alignment;
        unsigned long long lba;
        unsigned sector_size;
@@ -1470,6 +1474,13 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
                                 * Invalid Field in CDB, just retry
                                 * silently with RC10 */
                                return -EINVAL;
+                       if (sense_valid &&
+                           sshdr.sense_key == UNIT_ATTENTION &&
+                           sshdr.asc == 0x29 && sshdr.ascq == 0x00)
+                               /* Device reset might occur several times,
+                                * give it one more chance */
+                               if (--reset_retries > 0)
+                                       continue;
                }
                retries--;
 
@@ -1528,7 +1539,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
        struct scsi_sense_hdr sshdr;
        int sense_valid = 0;
        int the_result;
-       int retries = 3;
+       int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET;
        sector_t lba;
        unsigned sector_size;
 
@@ -1544,8 +1555,16 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
                if (media_not_present(sdkp, &sshdr))
                        return -ENODEV;
 
-               if (the_result)
+               if (the_result) {
                        sense_valid = scsi_sense_valid(&sshdr);
+                       if (sense_valid &&
+                           sshdr.sense_key == UNIT_ATTENTION &&
+                           sshdr.asc == 0x29 && sshdr.ascq == 0x00)
+                               /* Device reset might occur several times,
+                                * give it one more chance */
+                               if (--reset_retries > 0)
+                                       continue;
+               }
                retries--;
 
        } while (the_result && retries);
@@ -1574,6 +1593,8 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
 
 static int sd_try_rc16_first(struct scsi_device *sdp)
 {
+       if (sdp->host->max_cmd_len < 16)
+               return 0;
        if (sdp->scsi_level > SCSI_SPC_2)
                return 1;
        if (scsi_device_protection(sdp))
@@ -2101,6 +2122,26 @@ static int sd_revalidate_disk(struct gendisk *disk)
        return 0;
 }
 
+/**
+ *     sd_unlock_native_capacity - unlock native capacity
+ *     @disk: struct gendisk to set capacity for
+ *
+ *     Block layer calls this function if it detects that partitions
+ *     on @disk reach beyond the end of the device.  If the SCSI host
+ *     implements ->unlock_native_capacity() method, it's invoked to
+ *     give it a chance to adjust the device capacity.
+ *
+ *     CONTEXT:
+ *     Defined by block layer.  Might sleep.
+ */
+static void sd_unlock_native_capacity(struct gendisk *disk)
+{
+       struct scsi_device *sdev = scsi_disk(disk)->device;
+
+       if (sdev->host->hostt->unlock_native_capacity)
+               sdev->host->hostt->unlock_native_capacity(sdev);
+}
+
 /**
  *     sd_format_disk_name - format disk name
  *     @prefix: name prefix - ie. "sd" for SCSI disks