[SCSI] sd: Try READ CAPACITY 16 first for SBC-2 devices
authorMatthew Wilcox <matthew@wil.cx>
Thu, 12 Mar 2009 18:20:30 +0000 (14:20 -0400)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Wed, 18 Mar 2009 01:43:29 +0000 (21:43 -0400)
New features are being added to the READ CAPACITY 16 results, so we
want to issue it in preference to READ CAPACITY 10.  Unfortunately, some
devices misbehave when they see a READ CAPACITY 16, so we restrict this
command to devices which claim conformance to SPC-3 (aka SBC-2), or claim
they have features which are only reported in the READ CAPACITY 16 data.

The READ CAPACITY 16 command is optional, even for SBC-2 devices, so
we fall back to READ CAPACITY 10 if READ CAPACITY 16 fails.

[jejb: don't error if device supports SBC-2 but doesn't support RC16]
Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
Tested-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
drivers/scsi/sd.c

index dcff84a..8eebaa8 100644 (file)
@@ -1329,8 +1329,17 @@ static int read_capacity_16(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 == ILLEGAL_REQUEST &&
+                           (sshdr.asc == 0x20 || sshdr.asc == 0x24) &&
+                           sshdr.ascq == 0x00)
+                               /* Invalid Command Operation Code or
+                                * Invalid Field in CDB, just retry
+                                * silently with RC10 */
+                               return -EINVAL;
+               }
                retries--;
 
        } while (the_result && retries);
@@ -1414,6 +1423,15 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
        return sector_size;
 }
 
+static int sd_try_rc16_first(struct scsi_device *sdp)
+{
+       if (sdp->scsi_level > SCSI_SPC_2)
+               return 1;
+       if (scsi_device_protection(sdp))
+               return 1;
+       return 0;
+}
+
 /*
  * read disk capacity
  */
@@ -1423,11 +1441,14 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
        int sector_size;
        struct scsi_device *sdp = sdkp->device;
 
-       /* Force READ CAPACITY(16) when PROTECT=1 */
-       if (scsi_device_protection(sdp)) {
+       if (sd_try_rc16_first(sdp)) {
                sector_size = read_capacity_16(sdkp, sdp, buffer);
                if (sector_size == -EOVERFLOW)
                        goto got_data;
+               if (sector_size == -ENODEV)
+                       return;
+               if (sector_size < 0)
+                       sector_size = read_capacity_10(sdkp, sdp, buffer);
                if (sector_size < 0)
                        return;
        } else {