Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[sfrench/cifs-2.6.git] / drivers / scsi / sd.c
index bce5b13b020b50d149ef9b578d0ced4d964337e3..ccff8f2e2e75bd4b0286f04c96cb41d588205941 100644 (file)
@@ -1672,36 +1672,35 @@ out:
 
 static int sd_sync_cache(struct scsi_disk *sdkp)
 {
-       int retries, res;
+       int res;
        struct scsi_device *sdp = sdkp->device;
        const int timeout = sdp->request_queue->rq_timeout
                * SD_FLUSH_TIMEOUT_MULTIPLIER;
+       /* Leave the rest of the command zero to indicate flush everything. */
+       const unsigned char cmd[16] = { sdp->use_16_for_sync ?
+                               SYNCHRONIZE_CACHE_16 : SYNCHRONIZE_CACHE };
        struct scsi_sense_hdr sshdr;
+       struct scsi_failure failure_defs[] = {
+               {
+                       .allowed = 3,
+                       .result = SCMD_FAILURE_RESULT_ANY,
+               },
+               {}
+       };
+       struct scsi_failures failures = {
+               .failure_definitions = failure_defs,
+       };
        const struct scsi_exec_args exec_args = {
                .req_flags = BLK_MQ_REQ_PM,
                .sshdr = &sshdr,
+               .failures = &failures,
        };
 
        if (!scsi_device_online(sdp))
                return -ENODEV;
 
-       for (retries = 3; retries > 0; --retries) {
-               unsigned char cmd[16] = { 0 };
-
-               if (sdp->use_16_for_sync)
-                       cmd[0] = SYNCHRONIZE_CACHE_16;
-               else
-                       cmd[0] = SYNCHRONIZE_CACHE;
-               /*
-                * Leave the rest of the command zero to indicate
-                * flush everything.
-                */
-               res = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, NULL, 0,
-                                      timeout, sdkp->max_retries, &exec_args);
-               if (res == 0)
-                       break;
-       }
-
+       res = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, NULL, 0, timeout,
+                              sdkp->max_retries, &exec_args);
        if (res) {
                sd_print_result(sdkp, "Synchronize Cache(10) failed", res);
 
@@ -1828,8 +1827,22 @@ static int sd_pr_in_command(struct block_device *bdev, u8 sa,
        struct scsi_device *sdev = sdkp->device;
        struct scsi_sense_hdr sshdr;
        u8 cmd[10] = { PERSISTENT_RESERVE_IN, sa };
+       struct scsi_failure failure_defs[] = {
+               {
+                       .sense = UNIT_ATTENTION,
+                       .asc = SCMD_FAILURE_ASC_ANY,
+                       .ascq = SCMD_FAILURE_ASCQ_ANY,
+                       .allowed = 5,
+                       .result = SAM_STAT_CHECK_CONDITION,
+               },
+               {}
+       };
+       struct scsi_failures failures = {
+               .failure_definitions = failure_defs,
+       };
        const struct scsi_exec_args exec_args = {
                .sshdr = &sshdr,
+               .failures = &failures,
        };
        int result;
 
@@ -1916,8 +1929,22 @@ static int sd_pr_out_command(struct block_device *bdev, u8 sa, u64 key,
        struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
        struct scsi_device *sdev = sdkp->device;
        struct scsi_sense_hdr sshdr;
+       struct scsi_failure failure_defs[] = {
+               {
+                       .sense = UNIT_ATTENTION,
+                       .asc = SCMD_FAILURE_ASC_ANY,
+                       .ascq = SCMD_FAILURE_ASCQ_ANY,
+                       .allowed = 5,
+                       .result = SAM_STAT_CHECK_CONDITION,
+               },
+               {}
+       };
+       struct scsi_failures failures = {
+               .failure_definitions = failure_defs,
+       };
        const struct scsi_exec_args exec_args = {
                .sshdr = &sshdr,
+               .failures = &failures,
        };
        int result;
        u8 cmd[16] = { 0, };
@@ -2262,55 +2289,68 @@ static int sd_done(struct scsi_cmnd *SCpnt)
 static void
 sd_spinup_disk(struct scsi_disk *sdkp)
 {
-       unsigned char cmd[10];
+       static const u8 cmd[10] = { TEST_UNIT_READY };
        unsigned long spintime_expire = 0;
-       int retries, spintime;
+       int spintime, sense_valid = 0;
        unsigned int the_result;
        struct scsi_sense_hdr sshdr;
+       struct scsi_failure failure_defs[] = {
+               /* Do not retry Medium Not Present */
+               {
+                       .sense = UNIT_ATTENTION,
+                       .asc = 0x3A,
+                       .ascq = SCMD_FAILURE_ASCQ_ANY,
+                       .result = SAM_STAT_CHECK_CONDITION,
+               },
+               {
+                       .sense = NOT_READY,
+                       .asc = 0x3A,
+                       .ascq = SCMD_FAILURE_ASCQ_ANY,
+                       .result = SAM_STAT_CHECK_CONDITION,
+               },
+               /* Retry when scsi_status_is_good would return false 3 times */
+               {
+                       .result = SCMD_FAILURE_STAT_ANY,
+                       .allowed = 3,
+               },
+               {}
+       };
+       struct scsi_failures failures = {
+               .failure_definitions = failure_defs,
+       };
        const struct scsi_exec_args exec_args = {
                .sshdr = &sshdr,
+               .failures = &failures,
        };
-       int sense_valid = 0;
 
        spintime = 0;
 
        /* Spin up drives, as required.  Only do this at boot time */
        /* Spinup needs to be done for module loads too. */
        do {
-               retries = 0;
+               bool media_was_present = sdkp->media_present;
 
-               do {
-                       bool media_was_present = sdkp->media_present;
+               scsi_failures_reset_retries(&failures);
 
-                       cmd[0] = TEST_UNIT_READY;
-                       memset((void *) &cmd[1], 0, 9);
-
-                       the_result = scsi_execute_cmd(sdkp->device, cmd,
-                                                     REQ_OP_DRV_IN, NULL, 0,
-                                                     SD_TIMEOUT,
-                                                     sdkp->max_retries,
-                                                     &exec_args);
+               the_result = scsi_execute_cmd(sdkp->device, cmd, REQ_OP_DRV_IN,
+                                             NULL, 0, SD_TIMEOUT,
+                                             sdkp->max_retries, &exec_args);
 
-                       if (the_result > 0) {
-                               /*
-                                * If the drive has indicated to us that it
-                                * doesn't have any media in it, don't bother
-                                * with any more polling.
-                                */
-                               if (media_not_present(sdkp, &sshdr)) {
-                                       if (media_was_present)
-                                               sd_printk(KERN_NOTICE, sdkp,
-                                                         "Media removed, stopped polling\n");
-                                       return;
-                               }
 
-                               sense_valid = scsi_sense_valid(&sshdr);
+               if (the_result > 0) {
+                       /*
+                        * If the drive has indicated to us that it doesn't
+                        * have any media in it, don't bother with any more
+                        * polling.
+                        */
+                       if (media_not_present(sdkp, &sshdr)) {
+                               if (media_was_present)
+                                       sd_printk(KERN_NOTICE, sdkp,
+                                                 "Media removed, stopped polling\n");
+                               return;
                        }
-                       retries++;
-               } while (retries < 3 &&
-                        (!scsi_status_is_good(the_result) ||
-                         (scsi_status_is_check_condition(the_result) &&
-                         sense_valid && sshdr.sense_key == UNIT_ATTENTION)));
+                       sense_valid = scsi_sense_valid(&sshdr);
+               }
 
                if (!scsi_status_is_check_condition(the_result)) {
                        /* no sense, TUR either succeeded or failed
@@ -2345,14 +2385,16 @@ sd_spinup_disk(struct scsi_disk *sdkp)
                         * Issue command to spin up drive when not ready
                         */
                        if (!spintime) {
+                               /* Return immediately and start spin cycle */
+                               const u8 start_cmd[10] = {
+                                       [0] = START_STOP,
+                                       [1] = 1,
+                                       [4] = sdkp->device->start_stop_pwr_cond ?
+                                               0x11 : 1,
+                               };
+
                                sd_printk(KERN_NOTICE, sdkp, "Spinning up disk...");
-                               cmd[0] = START_STOP;
-                               cmd[1] = 1;     /* Return immediately */
-                               memset((void *) &cmd[2], 0, 8);
-                               cmd[4] = 1;     /* Start spin cycle */
-                               if (sdkp->device->start_stop_pwr_cond)
-                                       cmd[4] |= 1 << 4;
-                               scsi_execute_cmd(sdkp->device, cmd,
+                               scsi_execute_cmd(sdkp->device, start_cmd,
                                                 REQ_OP_DRV_IN, NULL, 0,
                                                 SD_TIMEOUT, sdkp->max_retries,
                                                 &exec_args);
@@ -2573,42 +2615,58 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
 static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
                                                unsigned char *buffer)
 {
-       unsigned char cmd[16];
+       static const u8 cmd[10] = { READ_CAPACITY };
        struct scsi_sense_hdr sshdr;
+       struct scsi_failure failure_defs[] = {
+               /* Do not retry Medium Not Present */
+               {
+                       .sense = UNIT_ATTENTION,
+                       .asc = 0x3A,
+                       .result = SAM_STAT_CHECK_CONDITION,
+               },
+               {
+                       .sense = NOT_READY,
+                       .asc = 0x3A,
+                       .result = SAM_STAT_CHECK_CONDITION,
+               },
+                /* Device reset might occur several times so retry a lot */
+               {
+                       .sense = UNIT_ATTENTION,
+                       .asc = 0x29,
+                       .allowed = READ_CAPACITY_RETRIES_ON_RESET,
+                       .result = SAM_STAT_CHECK_CONDITION,
+               },
+               /* Any other error not listed above retry 3 times */
+               {
+                       .result = SCMD_FAILURE_RESULT_ANY,
+                       .allowed = 3,
+               },
+               {}
+       };
+       struct scsi_failures failures = {
+               .failure_definitions = failure_defs,
+       };
        const struct scsi_exec_args exec_args = {
                .sshdr = &sshdr,
+               .failures = &failures,
        };
        int sense_valid = 0;
        int the_result;
-       int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET;
        sector_t lba;
        unsigned sector_size;
 
-       do {
-               cmd[0] = READ_CAPACITY;
-               memset(&cmd[1], 0, 9);
-               memset(buffer, 0, 8);
+       memset(buffer, 0, 8);
 
-               the_result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, buffer,
-                                             8, SD_TIMEOUT, sdkp->max_retries,
-                                             &exec_args);
+       the_result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, buffer,
+                                     8, SD_TIMEOUT, sdkp->max_retries,
+                                     &exec_args);
+
+       if (the_result > 0) {
+               sense_valid = scsi_sense_valid(&sshdr);
 
                if (media_not_present(sdkp, &sshdr))
                        return -ENODEV;
-
-               if (the_result > 0) {
-                       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);
+       }
 
        if (the_result) {
                sd_print_result(sdkp, "Read Capacity(10) failed", the_result);
@@ -3510,6 +3568,24 @@ static bool sd_validate_opt_xfer_size(struct scsi_disk *sdkp,
        return true;
 }
 
+static void sd_read_block_zero(struct scsi_disk *sdkp)
+{
+       unsigned int buf_len = sdkp->device->sector_size;
+       char *buffer, cmd[10] = { };
+
+       buffer = kmalloc(buf_len, GFP_KERNEL);
+       if (!buffer)
+               return;
+
+       cmd[0] = READ_10;
+       put_unaligned_be32(0, &cmd[2]); /* Logical block address 0 */
+       put_unaligned_be16(1, &cmd[7]); /* Transfer 1 logical block */
+
+       scsi_execute_cmd(sdkp->device, cmd, REQ_OP_DRV_IN, buffer, buf_len,
+                        SD_TIMEOUT, sdkp->max_retries, NULL);
+       kfree(buffer);
+}
+
 /**
  *     sd_revalidate_disk - called the first time a new disk is seen,
  *     performs disk spin up, read_capacity, etc.
@@ -3549,7 +3625,13 @@ static int sd_revalidate_disk(struct gendisk *disk)
         */
        if (sdkp->media_present) {
                sd_read_capacity(sdkp, buffer);
-
+               /*
+                * Some USB/UAS devices return generic values for mode pages
+                * until the media has been accessed. Trigger a READ operation
+                * to force the device to populate mode pages.
+                */
+               if (sdp->read_before_ms)
+                       sd_read_block_zero(sdkp);
                /*
                 * set the default to rotational.  All non-rotational devices
                 * support the block characteristics VPD page, which will
@@ -3833,7 +3915,7 @@ static int sd_probe(struct device *dev)
        blk_pm_runtime_init(sdp->request_queue, dev);
        if (sdp->rpm_autosuspend) {
                pm_runtime_set_autosuspend_delay(dev,
-                       sdp->host->hostt->rpm_autosuspend_delay);
+                       sdp->host->rpm_autosuspend_delay);
        }
 
        error = device_add_disk(dev, gd, NULL);