scsi: sd: Retry START STOP UNIT commands
authorBart Van Assche <bvanassche@acm.org>
Wed, 4 Sep 2024 21:03:04 +0000 (14:03 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 13 Sep 2024 00:40:32 +0000 (20:40 -0400)
During system resume, sd_start_stop_device() submits a START STOP UNIT
command to the SCSI device that is being resumed. That command is not
retried in case of a unit attention and hence may fail. An example:

[16575.983359] sd 0:0:0:3: [sdd] Starting disk
[16575.983693] sd 0:0:0:3: [sdd] Start/Stop Unit failed: Result: hostbyte=0x00 driverbyte=DRIVER_OK
[16575.983712] sd 0:0:0:3: [sdd] Sense Key : 0x6
[16575.983730] sd 0:0:0:3: [sdd] ASC=0x29 ASCQ=0x0
[16575.983738] sd 0:0:0:3: PM: dpm_run_callback(): scsi_bus_resume+0x0/0xa0 returns -5
[16575.983783] sd 0:0:0:3: PM: failed to resume async: error -5

Make the SCSI core retry the START STOP UNIT command if the device reports
that it has been powered on or that it has been reset.

Cc: Damien Le Moal <dlemoal@kernel.org>
Cc: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Link: https://lore.kernel.org/r/20240904210304.2947789-1-bvanassche@acm.org
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/sd.c

index b0e5654..43a7231 100644 (file)
@@ -4082,9 +4082,38 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start)
 {
        unsigned char cmd[6] = { START_STOP };  /* START_VALID */
        struct scsi_sense_hdr sshdr;
+       struct scsi_failure failure_defs[] = {
+               {
+                       /* Power on, reset, or bus device reset occurred */
+                       .sense = UNIT_ATTENTION,
+                       .asc = 0x29,
+                       .ascq = 0,
+                       .result = SAM_STAT_CHECK_CONDITION,
+               },
+               {
+                       /* Power on occurred */
+                       .sense = UNIT_ATTENTION,
+                       .asc = 0x29,
+                       .ascq = 1,
+                       .result = SAM_STAT_CHECK_CONDITION,
+               },
+               {
+                       /* SCSI bus reset */
+                       .sense = UNIT_ATTENTION,
+                       .asc = 0x29,
+                       .ascq = 2,
+                       .result = SAM_STAT_CHECK_CONDITION,
+               },
+               {}
+       };
+       struct scsi_failures failures = {
+               .total_allowed = 3,
+               .failure_definitions = failure_defs,
+       };
        const struct scsi_exec_args exec_args = {
                .sshdr = &sshdr,
                .req_flags = BLK_MQ_REQ_PM,
+               .failures = &failures,
        };
        struct scsi_device *sdp = sdkp->device;
        int res;