Skip to content

Commit 0a85890

Browse files
committed
ata,scsi: do not issue START STOP UNIT on resume
During system resume, ata_port_pm_resume() triggers ata EH to 1) Resume the controller 2) Reset and rescan the ports 3) Revalidate devices This EH execution is started asynchronously from ata_port_pm_resume(), which means that when sd_resume() is executed, none or only part of the above processing may have been executed. However, sd_resume() issues a START STOP UNIT to wake up the drive from sleep mode. This command is translated to ATA with ata_scsi_start_stop_xlat() and issued to the device. However, depending on the state of execution of the EH process and revalidation triggerred by ata_port_pm_resume(), two things may happen: 1) The START STOP UNIT fails if it is received before the controller has been reenabled at the beginning of the EH execution. This is visible with error messages like: ata10.00: device reported invalid CHS sector 0 sd 9:0:0:0: [sdc] Start/Stop Unit failed: Result: hostbyte=DID_OK driverbyte=DRIVER_OK sd 9:0:0:0: [sdc] Sense Key : Illegal Request [current] sd 9:0:0:0: [sdc] Add. Sense: Unaligned write command sd 9:0:0:0: PM: dpm_run_callback(): scsi_bus_resume+0x0/0x90 returns -5 sd 9:0:0:0: PM: failed to resume async: error -5 2) The START STOP UNIT command is received while the EH process is on-going, which mean that it is stopped and must wait for its completion, at which point the command is rather useless as the drive is already fully spun up already. This case results also in a significant delay in sd_resume() which is observable by users as the entire system resume completion is delayed. Given that ATA devices will be woken up by libata activity on resume, sd_resume() has no need to issue a START STOP UNIT command, which solves the above mentioned problems. Do not issue this command by introducing the new scsi_device flag no_start_on_resume and setting this flag to 1 in ata_scsi_dev_config(). sd_resume() is modified to issue a START STOP UNIT command only if this flag is not set. Reported-by: Paul Ausbeck <paula@soe.ucsc.edu> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=215880 Fixes: a19a93e ("scsi: core: pm: Rely on the device driver core for async power management") Signed-off-by: Damien Le Moal <dlemoal@kernel.org> Tested-by: Tanner Watkins <dalzot@gmail.com> Tested-by: Paul Ausbeck <paula@soe.ucsc.edu> Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Bart Van Assche <bvanassche@acm.org>
1 parent 5d0c230 commit 0a85890

File tree

3 files changed

+14
-3
lines changed

3 files changed

+14
-3
lines changed

drivers/ata/libata-scsi.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,7 +1100,14 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev)
11001100
}
11011101
} else {
11021102
sdev->sector_size = ata_id_logical_sector_size(dev->id);
1103+
/*
1104+
* Stop the drive on suspend but do not issue START STOP UNIT
1105+
* on resume as this is not necessary and may fail: the device
1106+
* will be woken up by ata_port_pm_resume() with a port reset
1107+
* and device revalidation.
1108+
*/
11031109
sdev->manage_start_stop = 1;
1110+
sdev->no_start_on_resume = 1;
11041111
}
11051112

11061113
/*

drivers/scsi/sd.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3876,16 +3876,19 @@ static int sd_suspend_runtime(struct device *dev)
38763876
static int sd_resume(struct device *dev)
38773877
{
38783878
struct scsi_disk *sdkp = dev_get_drvdata(dev);
3879-
int ret;
3879+
int ret = 0;
38803880

38813881
if (!sdkp) /* E.g.: runtime resume at the start of sd_probe() */
38823882
return 0;
38833883

38843884
if (!sdkp->device->manage_start_stop)
38853885
return 0;
38863886

3887-
sd_printk(KERN_NOTICE, sdkp, "Starting disk\n");
3888-
ret = sd_start_stop_device(sdkp, 1);
3887+
if (!sdkp->device->no_start_on_resume) {
3888+
sd_printk(KERN_NOTICE, sdkp, "Starting disk\n");
3889+
ret = sd_start_stop_device(sdkp, 1);
3890+
}
3891+
38893892
if (!ret)
38903893
opal_unlock_from_suspend(sdkp->opal_dev);
38913894
return ret;

include/scsi/scsi_device.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ struct scsi_device {
194194
unsigned no_start_on_add:1; /* do not issue start on add */
195195
unsigned allow_restart:1; /* issue START_UNIT in error handler */
196196
unsigned manage_start_stop:1; /* Let HLD (sd) manage start/stop */
197+
unsigned no_start_on_resume:1; /* Do not issue START_STOP_UNIT on resume */
197198
unsigned start_stop_pwr_cond:1; /* Set power cond. in START_STOP_UNIT */
198199
unsigned no_uld_attach:1; /* disable connecting to upper level drivers */
199200
unsigned select_no_atn:1;

0 commit comments

Comments
 (0)