scsi: sd: Retry START STOP UNIT commands

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>
This commit is contained in:
Bart Van Assche 2024-09-04 14:03:04 -07:00 committed by Martin K. Petersen
parent 24d7071d96
commit a8598aefae

View 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 */ unsigned char cmd[6] = { START_STOP }; /* START_VALID */
struct scsi_sense_hdr sshdr; 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 = { const struct scsi_exec_args exec_args = {
.sshdr = &sshdr, .sshdr = &sshdr,
.req_flags = BLK_MQ_REQ_PM, .req_flags = BLK_MQ_REQ_PM,
.failures = &failures,
}; };
struct scsi_device *sdp = sdkp->device; struct scsi_device *sdp = sdkp->device;
int res; int res;