From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:54:45
The first 9 patches of this series fix several issues with suspend/resume
power management operations in scsi and libata. The most significant
changes introduced are in patch 4 and 5, where the manage_start_stop
flag of scsi devices is split into the manage_system_start_stop and
manage_runtime_start_stop flags to allow keeping scsi runtime power
operations for spining up/down ATA devices but have libata do its own
system suspend/resume device power state management using EH.
The remaining patches are code cleanup that do not introduce any
significant functional change.
This series was tested on qemu and on various PCs and servers. I am
CC-ing people who recently reported issues with suspend/resume.
Additional testing would be much appreciated.
Changes from v3:
* Corrected pathc 1 (typo in commit message and WARN_ON() removal)
* Changed path 3 as suggested by Niklas (moved definition of
->slave_alloc)
* Rebased on rc2
* Added review tags
Changes from v2:
* Added patch 4 as simply disabling manage_start_stop from libata was
breaking individual disk runtime suspend/autosuspend. Patch 5 was
reworked accordingly to the changes in patch 4.
* Fixed patch 3: applying the link creation was missing and the link
creation itself was also incorrect, preventing sd probe to execute
correctly. Thanks to Geert for testing and reporting this issue.
* Split the "Fix delayed scsi_rescan_device() execution" patch into
patch 6 (scsi part) and patch 7 (ata part).
* Modified patch 9 to not call sd_shutdown() from sd_remove() for
devices that are not running.
* Added Chia-Lin Tested tag to unchanged patches
Changes from v1:
* Added patch 8 and 9 to fix compilation warnings with W=1
* Addressed John comment in patch 19
* Fixed patch 20 commit message (Sergei)
* Added Hannes Review tag
Damien Le Moal (23):
ata: libata-core: Fix ata_port_request_pm() locking
ata: libata-core: Fix port and device removal
ata: libata-scsi: link ata port and scsi device
scsi: sd: Differentiate system and runtime start/stop management
ata: libata-scsi: Disable scsi device manage_system_start_stop
scsi: Do not attempt to rescan suspended devices
ata: libata-scsi: Fix delayed scsi_rescan_device() execution
ata: libata-core: Do not register PM operations for SAS ports
scsi: sd: Do not issue commands to suspended disks on shutdown
ata: libata-core: Fix compilation warning in ata_dev_config_ncq()
ata: libata-eh: Fix compilation warning in ata_eh_link_report()
scsi: Remove scsi device no_start_on_resume flag
ata: libata-scsi: Cleanup ata_scsi_start_stop_xlat()
ata: libata-core: Synchronize ata_port_detach() with hotplug
ata: libata-core: Detach a port devices on shutdown
ata: libata-core: Remove ata_port_suspend_async()
ata: libata-core: Remove ata_port_resume_async()
ata: libata-core: Do not poweroff runtime suspended ports
ata: libata-core: Do not resume runtime suspended ports
ata: libata-sata: Improve ata_sas_slave_configure()
ata: libata-eh: Improve reset error messages
ata: libata-eh: Reduce "disable device" message verbosity
ata: libata: Cleanup inline DMA helper functions
drivers/ata/libata-core.c | 242 +++++++++++++++++++++++++--------
drivers/ata/libata-eh.c | 76 +++++++++--
drivers/ata/libata-sata.c | 5 +-
drivers/ata/libata-scsi.c | 146 ++++++++++----------
drivers/ata/libata-transport.c | 9 +-
drivers/ata/libata.h | 7 +
drivers/firewire/sbp2.c | 9 +-
drivers/scsi/scsi_scan.c | 18 ++-
drivers/scsi/sd.c | 88 ++++++++----
include/linux/libata.h | 26 ++--
include/scsi/scsi_device.h | 4 +-
include/scsi/scsi_host.h | 2 +-
12 files changed, 444 insertions(+), 188 deletions(-)
--
2.41.0
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:54:47
The function ata_port_request_pm() checks the port flag
ATA_PFLAG_PM_PENDING and calls ata_port_wait_eh() if this flag is set to
ensure that power management operations for a port are not scheduled
simultaneously. However, this flag check is done without holding the
port lock.
Fix this by taking the port lock on entry to the function and checking
the flag under this lock. The lock is released and re-taken if
ata_port_wait_eh() needs to be called. The two WARN_ON() macros checking
that the ATA_PFLAG_PM_PENDING flag was cleared are removed as the first
call is racy and the second one done without holding the port lock.
Fixes: 5ef41082912b ("ata: add ata port system PM callbacks")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-core.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:54:55
Whenever an ATA adapter driver is removed (e.g. rmmod),
ata_port_detach() is called repeatedly for all the adapter ports to
remove (unload) the devices attached to the port and delete the port
device itself. Removing of devices is done using libata EH with the
ATA_PFLAG_UNLOADING port flag set. This causes libata EH to execute
ata_eh_unload() which disables all devices attached to the port.
ata_port_detach() finishes by calling scsi_remove_host() to remove the
scsi host associated with the port. This function will trigger the
removal of all scsi devices attached to the host and in the case of
disks, calls to sd_shutdown() which will flush the device write cache
and stop the device. However, given that the devices were already
disabled by ata_eh_unload(), the synchronize write cache command and
start stop unit commands fail. E.g. running "rmmod ahci" with first
removing sd_mod results in error messages like:
ata13.00: disable device
sd 0:0:0:0: [sda] Synchronizing SCSI cache
sd 0:0:0:0: [sda] Synchronize Cache(10) failed: Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK
sd 0:0:0:0: [sda] Stopping disk
sd 0:0:0:0: [sda] Start/Stop Unit failed: Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK
Fix this by removing all scsi devices of the ata devices connected to
the port before scheduling libata EH to disable the ATA devices.
Also delete the WAR_ON() call checking that the ATA_PFLAG_UNLOADING flag
was cleared as that is done without holding the port lock.
Fixes: 720ba12620ee ("[PATCH] libata-hp: update unload-unplug")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Niklas Cassel <redacted>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-core.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:55:08
There is no direct device ancestry defined between an ata_device and
its scsi device which prevents the power management code from correctly
ordering suspend and resume operations. Create such ancestry with the
ata device as the parent to ensure that the scsi device (child) is
suspended before the ata device and that resume handles the ata device
before the scsi device.
The parent-child (supplier-consumer) relationship is established between
the ata_port (parent) and the scsi device (child) with the function
device_add_link(). The parent used is not the ata_device as the PM
operations are defined per port and the status of all devices connected
through that port is controlled from the port operations.
The device link is established with the new function
ata_scsi_dev_alloc(). This function is used to define the ->slave_alloc
callback of the scsi host template of most drivers.
Fixes: a19a93e4c6a9 ("scsi: core: pm: Rely on the device driver core for async power management")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
---
drivers/ata/libata-scsi.c | 49 +++++++++++++++++++++++++++++++++++----
drivers/ata/libata.h | 1 +
include/linux/libata.h | 2 ++
3 files changed, 47 insertions(+), 5 deletions(-)
@@ -1089,6 +1089,46 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev)return0;}+intata_scsi_dev_alloc(structscsi_device*sdev,structata_port*ap)+{+structdevice_link*link;++ata_scsi_sdev_config(sdev);++/*+*Createalinkfromtheata_portdevicetothescsidevicetoensure+*thatPMdoessuspend/resumeinthecorrectorder:thescsideviceis+*consumer(child)andtheataportthesupplier(parent).+*/+link=device_link_add(&sdev->sdev_gendev,&ap->tdev,+DL_FLAG_STATELESS|+DL_FLAG_PM_RUNTIME|DL_FLAG_RPM_ACTIVE);+if(!link){+ata_port_err(ap,"Failed to create link to scsi device %s\n",+dev_name(&sdev->sdev_gendev));+return-ENODEV;+}++return0;+}++/**+*ata_scsi_slave_alloc-EarlysetupofSCSIdevice+*@sdev:SCSIdevicetoexamine+*+*Thisiscalledfromscsi_alloc_sdev()whenthescsidevice+*associatedwithanATAdeviceisscannedonaport.+*+*LOCKING:+*DefinedbySCSIlayer.Wedon'treallycare.+*/++intata_scsi_slave_alloc(structscsi_device*sdev)+{+returnata_scsi_dev_alloc(sdev,ata_shost_to_port(sdev->host));+}+EXPORT_SYMBOL_GPL(ata_scsi_slave_alloc);+/***ata_scsi_slave_config-SetSCSIdeviceattributes*@sdev:SCSIdevicetoexamine
@@ -1105,14 +1145,11 @@ int ata_scsi_slave_config(struct scsi_device *sdev){structata_port*ap=ata_shost_to_port(sdev->host);structata_device*dev=__ata_scsi_find_dev(ap,sdev);-intrc=0;--ata_scsi_sdev_config(sdev);if(dev)-rc=ata_scsi_dev_config(sdev,dev);+returnata_scsi_dev_config(sdev,dev);-returnrc;+return0;}EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:55:10
The underlying device and driver of a scsi disk may have different
system and runtime power mode control requirements. This is because
runtime power management affects only the scsi disk, while sustem level
power management affects all devices, including the controller for the
scsi disk.
For instance, issuing a START STOP UNIT command when a scsi disk is
runtime suspended and resumed is fine: the command is translated to a
STANDBY IMMEDIATE command to spin down the ATA disk and to a VERIFY
command to wake it up. The scsi disk runtime operations have no effect
on the ata port device used to connect the ATA disk. However, for
system suspend/resume operations, the ATA port used to connect the
device will also be suspended and resumed, with the resum operation
requiring re-validating the device link and the device itseld. In this
case, issuing a VERIFY command to spinup the disk must be done before
starting to revalidate the device, when the ata port is being resumed.
In such case, we must not allow the scsi disk driver to issue START STOP
UNIT commands.
Allow a low level driver to refine the scsi disk start/stop management
by differentiating system and runtime cases with two new scsi device
flags: manage_system_start_stop and manage_runtime_start_stop. These new
flags replace the current manage_start_stop flag. Drivers setting the
manage_start_stop are modifed to set both new flags, thus preserving the
existing start/stop management behavior.
Fixes: 0a8589055936 ("ata,scsi: do not issue START STOP UNIT on resume")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
---
drivers/ata/libata-scsi.c | 3 +-
drivers/firewire/sbp2.c | 9 +++--
drivers/scsi/sd.c | 78 ++++++++++++++++++++++++++++----------
include/scsi/scsi_device.h | 3 +-
4 files changed, 69 insertions(+), 24 deletions(-)
@@ -3809,12 +3849,12 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)}}-if(sdkp->device->manage_start_stop){+if(sd_do_start_stop(sdkp->device,runtime)){if(!sdkp->device->silence_suspend)sd_printk(KERN_NOTICE,sdkp,"Stopping disk\n");/* an error is not worth aborting a system sleep */ret=sd_start_stop_device(sdkp,0);-if(ignore_stop_errors)+if(!runtime)ret=0;}
@@ -3826,23 +3866,23 @@ static int sd_suspend_system(struct device *dev)if(pm_runtime_suspended(dev))return0;-returnsd_suspend_common(dev,true);+returnsd_suspend_common(dev,false);}staticintsd_suspend_runtime(structdevice*dev){-returnsd_suspend_common(dev,false);+returnsd_suspend_common(dev,true);}-staticintsd_resume(structdevice*dev)+staticintsd_resume(structdevice*dev,boolruntime){structscsi_disk*sdkp=dev_get_drvdata(dev);-intret=0;+intret;if(!sdkp)/* E.g.: runtime resume at the start of sd_probe() */return0;-if(!sdkp->device->manage_start_stop)+if(!sd_do_start_stop(sdkp->device,runtime))return0;if(!sdkp->device->no_start_on_resume){
@@ -3860,7 +3900,7 @@ static int sd_resume_system(struct device *dev)if(pm_runtime_suspended(dev))return0;-returnsd_resume(dev);+returnsd_resume(dev,false);}staticintsd_resume_runtime(structdevice*dev)
@@ -3887,7 +3927,7 @@ static int sd_resume_runtime(struct device *dev)"Failed to clear sense data\n");}-returnsd_resume(dev);+returnsd_resume(dev,true);}staticconststructdev_pm_opssd_pm_ops={
@@ -193,7 +193,8 @@ struct scsi_device {unsigneduse_192_bytes_for_3f:1;/* ask for 192 bytes from page 0x3f */unsignedno_start_on_add:1;/* do not issue start on add */unsignedallow_restart:1;/* issue START_UNIT in error handler */-unsignedmanage_start_stop:1;/* Let HLD (sd) manage start/stop */+unsignedmanage_system_start_stop:1;/* Let HLD (sd) manage system start/stop */+unsignedmanage_runtime_start_stop:1;/* Let HLD (sd) manage runtime start/stop */unsignedno_start_on_resume:1;/* Do not issue START_STOP_UNIT on resume */unsignedstart_stop_pwr_cond:1;/* Set power cond. in START_STOP_UNIT */unsignedno_uld_attach:1;/* disable connecting to upper level drivers */
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:55:15
The introduction of a device link to create a consumer/supplier
relationship between the scsi device of an ATA device and the ATA port
of that ATA device fixes the ordering of system suspend and resume
operations. For suspend, the scsi device is suspended first and the ata
port after it. This is fine as this allows the synchronize cache and
START STOP UNIT commands issued by the scsi disk driver to be executed
before the ata port is disabled.
For resume operations, the ata port is resumed first, followed
by the scsi device. This allows having the request queue of the scsi
device to be unfrozen after the ata port resume is scheduled in EH,
thus avoiding to see new requests prematurely issued to the ATA device.
Since libata sets manage_system_start_stop to 1, the scsi disk resume
operation also results in issuing a START STOP UNIT command to the
device being resumed so that the device exits standby power mode.
However, restoring the ATA device to the active power mode must be
synchronized with libata EH processing of the port resume operation to
avoid either 1) seeing the start stop unit command being received too
early when the port is not yet resumed and ready to accept commands, or
after the port resume process issues commands such as IDENTIFY to
revalidate the device. In this last case, the risk is that the device
revalidation fails with timeout errors as the drive is still spun down.
Commit 0a8589055936 ("ata,scsi: do not issue START STOP UNIT on resume")
disabled issuing the START STOP UNIT command to avoid issues with it.
But this is incorrect as transitioning a device to the active power
mode from the standby power mode set on suspend requires a media access
command. The IDENTIFY, READ LOG and SET FEATURES commands executed in
libata EH context triggered by the ata port resume operation may thus
fail.
Fix these synchronization issues is by handling a device power mode
transitions for system suspend and resume directly in libata EH context,
without relying on the scsi disk driver management triggered with the
manage_system_start_stop flag.
To do this, the following libata helper functions are introduced:
1) ata_dev_power_set_standby():
This function issues a STANDBY IMMEDIATE command to transitiom a device
to the standby power mode. For HDDs, this spins down the disks. This
function applies only to ATA and ZAC devices and does nothing otherwise.
This function also does nothing for devices that have the
ATA_FLAG_NO_POWEROFF_SPINDOWN or ATA_FLAG_NO_HIBERNATE_SPINDOWN flag
set.
For suspend, call ata_dev_power_set_standby() in
ata_eh_handle_port_suspend() before the port is disabled and frozen.
ata_eh_unload() is also modified to transition all enabled devices to
the standby power mode when the system is shutdown or devices removed.
2) ata_dev_power_set_active() and
This function applies to ATA or ZAC devices and issues a VERIFY command
for 1 sector at LBA 0 to transition the device to the active power mode.
For HDDs, since this function will complete only once the disk spin up.
Its execution uses the same timeouts as for reset, to give the drive
enough time to complete spinup without triggering a command timeout.
For resume, call ata_dev_power_set_active() in
ata_eh_revalidate_and_attach() after the port has been enabled and
before any other command is issued to the device.
With these changes, the manage_system_start_stop and no_start_on_resume
scsi device flags do not need to be set in ata_scsi_dev_config(). The
flag manage_runtime_start_stop is still set to allow the sd driver to
spinup/spindown a disk through the sd runtime operations.
Fixes: 0a8589055936 ("ata,scsi: do not issue START STOP UNIT on resume")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
---
drivers/ata/libata-core.c | 90 +++++++++++++++++++++++++++++++++++++++
drivers/ata/libata-eh.c | 46 +++++++++++++++++++-
drivers/ata/libata-scsi.c | 16 +++----
drivers/ata/libata.h | 2 +
include/linux/libata.h | 6 ++-
5 files changed, 148 insertions(+), 12 deletions(-)
@@ -1972,6 +1972,96 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,returnrc;}+/**+*ata_dev_power_set_standby-Setadevicepowermodetostandby+*@dev:targetdevice+*+*IssueaSTANDBYIMMEDIATEcommandtosetadevicepowermodetostandby.+*ForanHDDdevice,thisspinsdownthedisks.+*+*LOCKING:+*Kernelthreadcontext(maysleep).+*/+voidata_dev_power_set_standby(structata_device*dev)+{+unsignedlongap_flags=dev->link->ap->flags;+structata_taskfiletf;+unsignedinterr_mask;++/* Issue STANDBY IMMEDIATE command only if supported by the device */+if(dev->class!=ATA_DEV_ATA&&dev->class!=ATA_DEV_ZAC)+return;++/*+*SomeoddclownBIOSesissuespindownonpoweroff(ACPIS4orS5)+*causingsomedrivestospinupanddownagain.Forthese,donothing+*ifwearebeingcalledonshutdown.+*/+if((ap_flags&ATA_FLAG_NO_POWEROFF_SPINDOWN)&&+system_state==SYSTEM_POWER_OFF)+return;++if((ap_flags&ATA_FLAG_NO_HIBERNATE_SPINDOWN)&&+system_entering_hibernation())+return;++ata_tf_init(dev,&tf);+tf.flags|=ATA_TFLAG_DEVICE|ATA_TFLAG_ISADDR;+tf.protocol=ATA_PROT_NODATA;+tf.command=ATA_CMD_STANDBYNOW1;++ata_dev_notice(dev,"Entering standby power mode\n");++err_mask=ata_exec_internal(dev,&tf,NULL,DMA_NONE,NULL,0,0);+if(err_mask)+ata_dev_err(dev,"STANDBY IMMEDIATE failed (err_mask=0x%x)\n",+err_mask);+}++/**+*ata_dev_power_set_active-Setadevicepowermodetoactive+*@dev:targetdevice+*+*IssueaVERIFYcommandtoentertoensurethatthedeviceisinthe+*activepowermode.Foraspun-downHDD(standbyoridlepowermode),+*theVERIFYcommandwillcompleteafterthediskspinsup.+*+*LOCKING:+*Kernelthreadcontext(maysleep).+*/+voidata_dev_power_set_active(structata_device*dev)+{+structata_taskfiletf;+unsignedinterr_mask;++/*+*IssueREADVERIFYSECTORScommandfor1sectoratlba=0only+*ifsupportedbythedevice.+*/+if(dev->class!=ATA_DEV_ATA&&dev->class!=ATA_DEV_ZAC)+return;++ata_tf_init(dev,&tf);+tf.flags|=ATA_TFLAG_DEVICE|ATA_TFLAG_ISADDR;+tf.protocol=ATA_PROT_NODATA;+tf.command=ATA_CMD_VERIFY;+tf.nsect=1;+if(dev->flags&ATA_DFLAG_LBA){+tf.flags|=ATA_TFLAG_LBA;+tf.device|=ATA_LBA;+}else{+/* CHS */+tf.lbal=0x1;/* sect */+}++ata_dev_notice(dev,"Entering active power mode\n");++err_mask=ata_exec_internal(dev,&tf,NULL,DMA_NONE,NULL,0,0);+if(err_mask)+ata_dev_err(dev,"VERIFY failed (err_mask=0x%x)\n",+err_mask);+}+/***ata_read_log_page-readaspecificlogpage*@dev:targetdevice
@@ -498,7 +500,19 @@ static void ata_eh_unload(struct ata_port *ap)structata_device*dev;unsignedlongflags;-/* Restore SControl IPM and SPD for the next driver and+/*+*Unlesswearerestarting,transitionallenableddevicesto+*standbypowermode.+*/+if(system_state!=SYSTEM_RESTART){+ata_for_each_link(link,ap,PMP_FIRST){+ata_for_each_dev(dev,link,ENABLED)+ata_dev_power_set_standby(dev);+}+}++/*+*RestoreSControlIPMandSPDforthenextdriverand*disableattacheddevices.*/ata_for_each_link(link,ap,PMP_FIRST){
@@ -684,6 +698,10 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap)ehc->saved_xfer_mode[devno]=dev->xfer_mode;if(ata_ncq_enabled(dev))ehc->saved_ncq_enabled|=1<<devno;++/* If we are resuming, wake up the device */+if(ap->pflags&ATA_PFLAG_RESUMING)+ehc->i.dev_action[devno]|=ATA_EH_SET_ACTIVE;}}
@@ -3016,6 +3043,15 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,if(ehc->i.flags&ATA_EHI_DID_RESET)readid_flags|=ATA_READID_POSTRESET;+/*+*Whenresuming,beforeexecutinganycommand,makesureto+*transitionthedevicetotheactivepowermode.+*/+if((action&ATA_EH_SET_ACTIVE)&&ata_dev_enabled(dev)){+ata_dev_power_set_active(dev);+ata_eh_done(link,dev,ATA_EH_SET_ACTIVE);+}+if((action&ATA_EH_REVALIDATE)&&ata_dev_enabled(dev)){WARN_ON(dev->class==ATA_DEV_PMP);
@@ -3989,6 +4025,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)unsignedlongflags;intrc=0;structata_device*dev;+structata_link*link;/* are we suspending? */spin_lock_irqsave(ap->lock,flags);
@@ -4001,6 +4038,12 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)WARN_ON(ap->pflags&ATA_PFLAG_SUSPENDED);+/* Set all devices attached to the port in standby mode */+ata_for_each_link(link,ap,HOST_FIRST){+ata_for_each_dev(dev,link,ENABLED)+ata_dev_power_set_standby(dev);+}+/**IfwehaveaZPODDattached,checkitszero*powerreadystatusbeforetheportisfrozen.
@@ -1251,7 +1249,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)tf->lbah=0x0;/* cyl high */}-tf->command=ATA_CMD_VERIFY;/* READ VERIFY */+tf->command=ATA_CMD_VERIFY;/* READ VERIFY */}else{/* Some odd clown BIOSen issue spindown on power off (ACPI S4*orS5)causingsomedrivestospinupanddownagain.
@@ -1261,7 +1259,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)gotoskip;if((qc->ap->flags&ATA_FLAG_NO_HIBERNATE_SPINDOWN)&&-system_entering_hibernation())+system_entering_hibernation())gotoskip;/* Issue ATA STANDBY IMMEDIATE command */
@@ -192,6 +192,7 @@ enum {ATA_PFLAG_UNLOADING=(1<<9),/* driver is being unloaded */ATA_PFLAG_UNLOADED=(1<<10),/* driver is unloaded */+ATA_PFLAG_RESUMING=(1<<16),/* port is being resumed */ATA_PFLAG_SUSPENDED=(1<<17),/* port is suspended (power) */ATA_PFLAG_PM_PENDING=(1<<18),/* PM operation pending */ATA_PFLAG_INIT_GTM_VALID=(1<<19),/* initial gtm data valid */
@@ -318,9 +319,10 @@ enum {ATA_EH_ENABLE_LINK=(1<<3),ATA_EH_PARK=(1<<5),/* unload heads and stop I/O */ATA_EH_GET_SUCCESS_SENSE=(1<<6),/* Get sense data for successful cmd */+ATA_EH_SET_ACTIVE=(1<<7),/* Set a device to active power mode */ATA_EH_PERDEV_MASK=ATA_EH_REVALIDATE|ATA_EH_PARK|-ATA_EH_GET_SUCCESS_SENSE,+ATA_EH_GET_SUCCESS_SENSE|ATA_EH_SET_ACTIVE,ATA_EH_ALL_ACTIONS=ATA_EH_REVALIDATE|ATA_EH_RESET|ATA_EH_ENABLE_LINK,
@@ -357,7 +359,7 @@ enum {/* This should match the actual table size of*ata_eh_cmd_timeout_tableinlibata-eh.c.*/-ATA_EH_CMD_TIMEOUT_TABLE_SIZE=7,+ATA_EH_CMD_TIMEOUT_TABLE_SIZE=8,/* Horkage types. May be set by libata or controller on drives(somehorkagemaybedrive/controllerpairdependent*/
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:55:16
scsi_rescan_device() takes a scsi device lock before executing a device
handler and device driver rescan methods. Waiting for the completion of
any command issued to the device by these methods will thus be done with
the device lock held. As a result, there is a risk of deadlocking within
the power management code if scsi_rescan_device() is called to handle a
device resume with the associated scsi device not yet resumed.
Avoid such situation by checking that the target scsi device is in the
running state, that is, fully capable of executing commands, before
proceeding with the rescan and bailout returning -EWOULDBLOCK otherwise.
With this error return, the caller can retry rescaning the device after
a delay.
The state check is done with the device lock held and is thus safe
against incoming suspend power management operations.
Fixes: 6aa0365a3c85 ("ata: libata-scsi: Avoid deadlock on rescan after device resume")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Niklas Cassel <redacted>
---
drivers/scsi/scsi_scan.c | 18 +++++++++++++++++-
include/scsi/scsi_host.h | 2 +-
2 files changed, 18 insertions(+), 2 deletions(-)
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:55:19
Commit 6aa0365a3c85 ("ata: libata-scsi: Avoid deadlock on rescan after
device resume") modified ata_scsi_dev_rescan() to check the scsi device
"is_suspended" power field to ensure that the scsi device associated
with an ATA device is fully resumed when scsi_rescan_device() is
executed. However, this fix is problematic as:
1) It relies on a PM internal field that should not be used without PM
device locking protection.
2) The check for is_suspended and the call to scsi_rescan_device() are
not atomic and a suspend PM event may be triggered between them,
casuing scsi_rescan_device() to be called on a suspended device and
in that function blocking while holding the scsi device lock. This
would deadlock a following resume operation.
These problems can trigger PM deadlocks on resume, especially with
resume operations triggered quickly after or during suspend operations.
E.g., a simple bash script like:
for (( i=0; i<10; i++ )); do
echo "+2 > /sys/class/rtc/rtc0/wakealarm
echo mem > /sys/power/state
done
that triggers a resume 2 seconds after starting suspending a system can
quickly lead to a PM deadlock preventing the system from correctly
resuming.
Fix this by replacing the check on is_suspended with a check on the
return value given by scsi_rescan_device() as that function will fail if
called against a suspended device. Also make sure rescan tasks already
scheduled are first cancelled before suspending an ata port.
Fixes: 6aa0365a3c85 ("ata: libata-scsi: Avoid deadlock on rescan after device resume")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Niklas Cassel <redacted>
---
drivers/ata/libata-core.c | 16 ++++++++++++++++
drivers/ata/libata-scsi.c | 33 +++++++++++++++------------------
2 files changed, 31 insertions(+), 18 deletions(-)
@@ -4769,37 +4769,34 @@ void ata_scsi_dev_rescan(struct work_struct *work)ata_for_each_dev(dev,link,ENABLED){structscsi_device*sdev=dev->sdev;+/*+*Iftheportwassuspendedbeforethiswasscheduled,+*bailout.+*/+if(ap->pflags&ATA_PFLAG_SUSPENDED)+gotounlock;+if(!sdev)continue;if(scsi_device_get(sdev))continue;-/*-*Iftherescanworkwasscheduledbecauseofaresume-*event,theportisalreadyfullyresumed,butthe-*SCSIdevicemaynotyetbefullyresumed.Insuch-*case,executingscsi_rescan_device()maycausea-*deadlockwiththePMcodeondevice_lock().Prevent-*thisbygivingupandretryingrescanafterashort-*delay.-*/-delay_rescan=sdev->sdev_gendev.power.is_suspended;-if(delay_rescan){-scsi_device_put(sdev);-break;-}-spin_unlock_irqrestore(ap->lock,flags);-scsi_rescan_device(sdev);+ret=scsi_rescan_device(sdev);scsi_device_put(sdev);spin_lock_irqsave(ap->lock,flags);++if(ret)+gotounlock;}}+unlock:spin_unlock_irqrestore(ap->lock,flags);mutex_unlock(&ap->scsi_scan_mutex);-if(delay_rescan)+/* Reschedule with a delay if scsi_rescan_device() returned an error */+if(ret)schedule_delayed_work(&ap->scsi_rescan_task,msecs_to_jiffies(5));}
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:55:36
libsas does its own domain based power management of ports. For such
ports, libata should not use a device type defining power management
operations as executing these operations for suspend/resume in addition
to libsas calls to ata_sas_port_suspend() and ata_sas_port_resume() is
not necessary (and likely dangerous to do, even though problems are not
seen currently).
Introduce the new ata_port_sas_type device_type for ports managed by
libsas. This new device type is used in ata_tport_add() and is defined
without power management operations.
Fixes: 2fcbdcb4c802 ("[SCSI] libata: export ata_port suspend/resume infrastructure for sas")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-core.c | 2 +-
drivers/ata/libata-transport.c | 9 ++++++++-
drivers/ata/libata.h | 2 ++
3 files changed, 11 insertions(+), 2 deletions(-)
@@ -266,6 +266,10 @@ void ata_tport_delete(struct ata_port *ap)put_device(dev);}+staticconststructdevice_typeata_port_sas_type={+.name=ATA_PORT_TYPE_NAME,+};+/** ata_tport_add - initialize a transport ATA port structure**@parent:parentdevice
@@ -283,7 +287,10 @@ int ata_tport_add(struct device *parent,structdevice*dev=&ap->tdev;device_initialize(dev);-dev->type=&ata_port_type;+if(ap->flags&ATA_FLAG_SAS_HOST)+dev->type=&ata_port_sas_type;+else+dev->type=&ata_port_type;dev->parent=parent;ata_host_get(ap->host);
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:55:38
If an error occurs when resuming a host adapter before the devices
attached to the adapter are resumed, the adapter low level driver may
remove the scsi host, resulting in a call to sd_remove() for the
disks of the host. This in turn results in a call to sd_shutdown() which
will issue a synchronize cache command and a start stop unit command to
spindown the disk. sd_shutdown() issues the commands only if the device
is not already suspended but does not check the power state for
system-wide suspend/resume. That is, the commands may be issued with the
device in a suspended state, which causes PM resume to hang, forcing a
reset of the machine to recover.
Fix this by not calling sd_shutdown() in sd_remove() if the device
is not running.
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/scsi/sd.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:55:38
The 24 bytes length allocated to the ncq_desc string in
ata_dev_config_lba() for ata_dev_config_ncq() to use is too short,
causing the following gcc compilation warnings when compiling with W=1:
drivers/ata/libata-core.c: In function ‘ata_dev_configure’:
drivers/ata/libata-core.c:2378:56: warning: ‘%d’ directive output may be truncated writing between 1 and 2 bytes into a region of size between 1 and 11 [-Wformat-truncation=]
2378 | snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth,
| ^~
In function ‘ata_dev_config_ncq’,
inlined from ‘ata_dev_config_lba’ at drivers/ata/libata-core.c:2649:8,
inlined from ‘ata_dev_configure’ at drivers/ata/libata-core.c:2952:9:
drivers/ata/libata-core.c:2378:41: note: directive argument in the range [1, 32]
2378 | snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth,
| ^~~~~~~~~~~~~~~~~~~~~
drivers/ata/libata-core.c:2378:17: note: ‘snprintf’ output between 16 and 31 bytes into a destination of size 24
2378 | snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2379 | ddepth, aa_desc);
| ~~~~~~~~~~~~~~~~
Avoid these warnings and the potential truncation by changing the size
of the ncq_desc string to 32 characters.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
---
drivers/ata/libata-core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:55:49
The 6 bytes length of the tries_buf string in ata_eh_link_report() is
too short and results in a gcc compilation warning with W-!:
drivers/ata/libata-eh.c: In function ‘ata_eh_link_report’:
drivers/ata/libata-eh.c:2371:59: warning: ‘%d’ directive output may be truncated writing between 1 and 11 bytes into a region of size 4 [-Wformat-truncation=]
2371 | snprintf(tries_buf, sizeof(tries_buf), " t%d",
| ^~
drivers/ata/libata-eh.c:2371:56: note: directive argument in the range [-2147483648, 4]
2371 | snprintf(tries_buf, sizeof(tries_buf), " t%d",
| ^~~~~~
drivers/ata/libata-eh.c:2371:17: note: ‘snprintf’ output between 4 and 14 bytes into a destination of size 6
2371 | snprintf(tries_buf, sizeof(tries_buf), " t%d",
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2372 | ap->eh_tries);
| ~~~~~~~~~~~~~
Avoid this warning by increasing the string size to 16B.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
---
drivers/ata/libata-eh.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:55:55
The scsi device flag no_start_on_resume is not set by any scsi low
level driver. Remove it. This reverts the changes introduced by commit
0a8589055936 ("ata,scsi: do not issue START STOP UNIT on resume").
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/scsi/sd.c | 7 ++-----
include/scsi/scsi_device.h | 1 -
2 files changed, 2 insertions(+), 6 deletions(-)
@@ -195,7 +195,6 @@ struct scsi_device {unsignedallow_restart:1;/* issue START_UNIT in error handler */unsignedmanage_system_start_stop:1;/* Let HLD (sd) manage system start/stop */unsignedmanage_runtime_start_stop:1;/* Let HLD (sd) manage runtime start/stop */-unsignedno_start_on_resume:1;/* Do not issue START_STOP_UNIT on resume */unsignedstart_stop_pwr_cond:1;/* Set power cond. in START_STOP_UNIT */unsignedno_uld_attach:1;/* disable connecting to upper level drivers */unsignedselect_no_atn:1;
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:56:03
Now that libata does its own internal device power mode management
through libata EH, the scsi disk driver will not issue START STOP UNIT
commands anymore. We can receive this command only from user passthrough
operations. So there is no need to consider the system state and ATA
port flags for suspend to translate the command.
Since setting up the taskfile for the verify and standby
immediate commands is the same as done in ata_dev_power_set_active()
and ata_dev_power_set_standby(), factor out this code into the helper
function ata_dev_power_init_tf() to simplify ata_scsi_start_stop_xlat()
as well as ata_dev_power_set_active() and ata_dev_power_set_standby().
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-core.c | 55 +++++++++++++++++++++++----------------
drivers/ata/libata-scsi.c | 53 +++++++------------------------------
drivers/ata/libata.h | 2 ++
3 files changed, 44 insertions(+), 66 deletions(-)
@@ -1972,6 +1972,35 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,returnrc;}+boolata_dev_power_init_tf(structata_device*dev,structata_taskfile*tf,+boolset_active)+{+/* Only applies to ATA and ZAC devices */+if(dev->class!=ATA_DEV_ATA&&dev->class!=ATA_DEV_ZAC)+returnfalse;++ata_tf_init(dev,tf);+tf->flags|=ATA_TFLAG_DEVICE|ATA_TFLAG_ISADDR;+tf->protocol=ATA_PROT_NODATA;++if(set_active){+/* VERIFY for 1 sector at lba=0 */+tf->command=ATA_CMD_VERIFY;+tf->nsect=1;+if(dev->flags&ATA_DFLAG_LBA){+tf->flags|=ATA_TFLAG_LBA;+tf->device|=ATA_LBA;+}else{+/* CHS */+tf->lbal=0x1;/* sect */+}+}else{+tf->command=ATA_CMD_STANDBYNOW1;+}++returntrue;+}+/***ata_dev_power_set_standby-Setadevicepowermodetostandby*@dev:targetdevice
@@ -1988,10 +2017,6 @@ void ata_dev_power_set_standby(struct ata_device *dev)structata_taskfiletf;unsignedinterr_mask;-/* Issue STANDBY IMMEDIATE command only if supported by the device */-if(dev->class!=ATA_DEV_ATA&&dev->class!=ATA_DEV_ZAC)-return;-/**SomeoddclownBIOSesissuespindownonpoweroff(ACPIS4orS5)*causingsomedrivestospinupanddownagain.Forthese,donothing
@@ -2005,10 +2030,9 @@ void ata_dev_power_set_standby(struct ata_device *dev)system_entering_hibernation())return;-ata_tf_init(dev,&tf);-tf.flags|=ATA_TFLAG_DEVICE|ATA_TFLAG_ISADDR;-tf.protocol=ATA_PROT_NODATA;-tf.command=ATA_CMD_STANDBYNOW1;+/* Issue STANDBY IMMEDIATE command only if supported by the device */+if(!ata_dev_power_init_tf(dev,&tf,false))+return;ata_dev_notice(dev,"Entering standby power mode\n");
@@ -2038,22 +2062,9 @@ void ata_dev_power_set_active(struct ata_device *dev)*IssueREADVERIFYSECTORScommandfor1sectoratlba=0only*ifsupportedbythedevice.*/-if(dev->class!=ATA_DEV_ATA&&dev->class!=ATA_DEV_ZAC)+if(!ata_dev_power_init_tf(dev,&tf,true))return;-ata_tf_init(dev,&tf);-tf.flags|=ATA_TFLAG_DEVICE|ATA_TFLAG_ISADDR;-tf.protocol=ATA_PROT_NODATA;-tf.command=ATA_CMD_VERIFY;-tf.nsect=1;-if(dev->flags&ATA_DFLAG_LBA){-tf.flags|=ATA_TFLAG_LBA;-tf.device|=ATA_LBA;-}else{-/* CHS */-tf.lbal=0x1;/* sect */-}-ata_dev_notice(dev,"Entering active power mode\n");err_mask=ata_exec_internal(dev,&tf,NULL,DMA_NONE,NULL,0,0);
@@ -1216,54 +1215,24 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)gotoinvalid_fld;}-tf->flags|=ATA_TFLAG_DEVICE|ATA_TFLAG_ISADDR;-tf->protocol=ATA_PROT_NODATA;-if(cdb[1]&0x1){-;/* ignore IMMED bit, violates sat-r05 */-}+/* LOEJ bit set not supported */if(cdb[4]&0x2){fp=4;bp=1;-gotoinvalid_fld;/* LOEJ bit set not supported */+gotoinvalid_fld;}++/* Power conditions not supported */if(((cdb[4]>>4)&0xf)!=0){fp=4;bp=3;-gotoinvalid_fld;/* power conditions not supported */+gotoinvalid_fld;}-if(cdb[4]&0x1){-tf->nsect=1;/* 1 sector, lba=0 */--if(qc->dev->flags&ATA_DFLAG_LBA){-tf->flags|=ATA_TFLAG_LBA;--tf->lbah=0x0;-tf->lbam=0x0;-tf->lbal=0x0;-tf->device|=ATA_LBA;-}else{-/* CHS */-tf->lbal=0x1;/* sect */-tf->lbam=0x0;/* cyl low */-tf->lbah=0x0;/* cyl high */-}--tf->command=ATA_CMD_VERIFY;/* READ VERIFY */-}else{-/* Some odd clown BIOSen issue spindown on power off (ACPI S4-*orS5)causingsomedrivestospinupanddownagain.-*/-if((qc->ap->flags&ATA_FLAG_NO_POWEROFF_SPINDOWN)&&-system_state==SYSTEM_POWER_OFF)-gotoskip;--if((qc->ap->flags&ATA_FLAG_NO_HIBERNATE_SPINDOWN)&&-system_entering_hibernation())-gotoskip;--/* Issue ATA STANDBY IMMEDIATE command */-tf->command=ATA_CMD_STANDBYNOW1;+/* Ignore IMMED bit (cdb[1] & 0x1), violates sat-r05 */+if(!ata_dev_power_init_tf(qc->dev,&qc->tf,cdb[4]&0x1)){+ata_scsi_set_sense(qc->dev,scmd,ABORTED_COMMAND,0,0);+return1;}/*
@@ -1278,12 +1247,8 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)invalid_fld:ata_scsi_set_invalid_field(qc->dev,scmd,fp,bp);return1;-skip:-scmd->result=SAM_STAT_GOOD;-return1;}-/***ata_scsi_flush_xlat-TranslateSCSISYNCHRONIZECACHEcommand*@qc:StoragefortranslatedATAtaskfile
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:56:06
Modify ata_pci_shutdown_one() to schedule EH to unload a port devices
before freezing and thawing the port. This ensures that drives are
cleanly disabled and transitioned to standby power mode when
a PCI adapter is removed or the system is powered off.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-core.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
@@ -6164,10 +6164,24 @@ EXPORT_SYMBOL_GPL(ata_pci_remove_one);voidata_pci_shutdown_one(structpci_dev*pdev){structata_host*host=pci_get_drvdata(pdev);+structata_port*ap;+unsignedlongflags;inti;+/* Tell EH to disable all devices */for(i=0;i<host->n_ports;i++){-structata_port*ap=host->ports[i];+ap=host->ports[i];+spin_lock_irqsave(ap->lock,flags);+ap->pflags|=ATA_PFLAG_UNLOADING;+ata_port_schedule_eh(ap);+spin_unlock_irqrestore(ap->lock,flags);+}++for(i=0;i<host->n_ports;i++){+ap=host->ports[i];++/* Wait for EH to complete before freezing the port */+ata_port_wait_eh(ap);ap->pflags|=ATA_PFLAG_FROZEN;
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:56:07
The call to async_synchronize_cookie() to synchronize a port removal
and hotplug probe is done in ata_host_detach() right before calling
ata_port_detach(). Move this call at the beginning of ata_port_detach()
to ensure that this operation is always synchronized with probe.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-core.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:56:09
Change ata_sas_slave_configure() to return the return value of
ata_scsi_dev_config() to ensure that any error from that function is
propagated to libsas.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: John Garry <john.g.garry@oracle.com>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-sata.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:56:10
When powering off, there is no need to suspend a port that has already
been runtime suspended. Skip the EH PM request in ata_port_pm_poweroff()
in this case.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:56:11
Remove ata_port_resume_async() and replace it with a modified
ata_port_resume() taking an additional bool argument indicating if
ata EH resume operation should be executed synchronously or
asynchronously. With this change, the variable ata_port_resume_ehi is
not longer necessary and its value (ATA_EHI_XXX flags) passed directly
to ata_port_request_pm().
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-core.c | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:56:12
The scsi disk driver does not resume disks that have been runtime
suspended by the user. To be consistent with this behavior, do the same
for ata ports and skip the PM request in ata_port_pm_resume() if the
port was already runtime suspended. With this change, it is no longer
necessary to for the PM state of the port to ACTIVE as the PM core code
will take care of that when handling runtime resume.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-core.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:56:13
Some drives are really slow to spinup on resume, resulting is a very
slow response to COMRESET and to error messages such as:
ata1: COMRESET failed (errno=-16)
ata1: link is slow to respond, please be patient (ready=0)
ata1: SATA link up 6.0 Gbps (SStatus 133 SControl 300)
ata1.00: configured for UDMA/133
Given that the slowness of the response is indicated with the message
"link is slow to respond..." and that resets are retried until the
device is detected as online after up to 1min (ata_eh_reset_timeouts),
there is no point in printing the "COMRESET failed" error message. Let's
not scare the user with non fatal errors and only warn about reset
failures in ata_eh_reset() when all reset retries have been exhausted.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-eh.c | 2 ++
drivers/ata/libata-sata.c | 1 -
2 files changed, 2 insertions(+), 1 deletion(-)
@@ -621,7 +621,6 @@ int sata_link_hardreset(struct ata_link *link, const unsigned int *timing,/* online is set iff link is online && reset succeeded */if(online)*online=false;-ata_link_err(link,"COMRESET failed (errno=%d)\n",rc);}returnrc;}
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:56:14
ata_port_suspend_async() is only called by ata_sas_port_suspend().
Modify ata_port_suspend() with an additional bool argument indicating an
asynchronous or synchronous suspend to allow removing that helper
function. With this change, the variable ata_port_resume_ehi can also be
removed and its value (ATA_EHI_XXX flags passed directly to
ata_port_request_pm().
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-core.c | 46 +++++++++++++++------------------------
1 file changed, 17 insertions(+), 29 deletions(-)
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:56:45
There is no point in warning about a device being disabled when we
expect it to be, that is, on suspend, shutdown or when detaching the
device.
Suppress the message "disable device" for these cases by introducing the
EH static function ata_eh_dev_disable() and by using it in
ata_eh_unload() and ata_eh_detach_dev(). ata_dev_disable() code is
modified to call this new function after printing the "disable device"
message.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-eh.c | 32 +++++++++++++++++++-------------
1 file changed, 19 insertions(+), 13 deletions(-)
@@ -494,6 +494,18 @@ void ata_eh_release(struct ata_port *ap)mutex_unlock(&ap->host->eh_mutex);}+staticvoidata_eh_dev_disable(structata_device*dev)+{+ata_acpi_on_disable(dev);+ata_down_xfermask_limit(dev,ATA_DNXFER_FORCE_PIO0|ATA_DNXFER_QUIET);+dev->class++;++/* From now till the next successful probe, ering is used to+*trackprobefailures.Clearaccumulateddeviceerrorinfo.+*/+ata_ering_clear(&dev->ering);+}+staticvoidata_eh_unload(structata_port*ap){structata_link*link;
@@ -517,8 +529,8 @@ static void ata_eh_unload(struct ata_port *ap)*/ata_for_each_link(link,ap,PMP_FIRST){sata_scr_write(link,SCR_CONTROL,link->saved_scontrol&0xff0);-ata_for_each_dev(dev,link,ALL)-ata_dev_disable(dev);+ata_for_each_dev(dev,link,ENABLED)+ata_eh_dev_disable(dev);}/* freeze and set UNLOADED */
@@ -1211,14 +1223,8 @@ void ata_dev_disable(struct ata_device *dev)return;ata_dev_warn(dev,"disable device\n");-ata_acpi_on_disable(dev);-ata_down_xfermask_limit(dev,ATA_DNXFER_FORCE_PIO0|ATA_DNXFER_QUIET);-dev->class++;-/* From now till the next successful probe, ering is used to-*trackprobefailures.Clearaccumulateddeviceerrorinfo.-*/-ata_ering_clear(&dev->ering);+ata_eh_dev_disable(dev);}EXPORT_SYMBOL_GPL(ata_dev_disable);
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-20 13:56:46
Simplify the inline DMA helper functions ata_using_mwdma(),
ata_using_udma() and ata_dma_enabled() to directly return as a boolean
the result of their test condition.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
include/linux/libata.h | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
On Wed, Sep 20, 2023 at 10:54:17PM +0900, Damien Le Moal wrote:
quoted hunk
The function ata_port_request_pm() checks the port flag
ATA_PFLAG_PM_PENDING and calls ata_port_wait_eh() if this flag is set to
ensure that power management operations for a port are not scheduled
simultaneously. However, this flag check is done without holding the
port lock.
Fix this by taking the port lock on entry to the function and checking
the flag under this lock. The lock is released and re-taken if
ata_port_wait_eh() needs to be called. The two WARN_ON() macros checking
that the ATA_PFLAG_PM_PENDING flag was cleared are removed as the first
call is racy and the second one done without holding the port lock.
Fixes: 5ef41082912b ("ata: add ata port system PM callbacks")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-core.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
On Wed, Sep 20, 2023 at 10:54:19PM +0900, Damien Le Moal wrote:
quoted hunk
There is no direct device ancestry defined between an ata_device and
its scsi device which prevents the power management code from correctly
ordering suspend and resume operations. Create such ancestry with the
ata device as the parent to ensure that the scsi device (child) is
suspended before the ata device and that resume handles the ata device
before the scsi device.
The parent-child (supplier-consumer) relationship is established between
the ata_port (parent) and the scsi device (child) with the function
device_add_link(). The parent used is not the ata_device as the PM
operations are defined per port and the status of all devices connected
through that port is controlled from the port operations.
The device link is established with the new function
ata_scsi_dev_alloc(). This function is used to define the ->slave_alloc
callback of the scsi host template of most drivers.
Fixes: a19a93e4c6a9 ("scsi: core: pm: Rely on the device driver core for async power management")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
---
drivers/ata/libata-scsi.c | 49 +++++++++++++++++++++++++++++++++++----
drivers/ata/libata.h | 1 +
include/linux/libata.h | 2 ++
3 files changed, 47 insertions(+), 5 deletions(-)
@@ -1089,6 +1089,46 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev)return0;}+intata_scsi_dev_alloc(structscsi_device*sdev,structata_port*ap)+{+structdevice_link*link;++ata_scsi_sdev_config(sdev);++/*+*Createalinkfromtheata_portdevicetothescsidevicetoensure+*thatPMdoessuspend/resumeinthecorrectorder:thescsideviceis+*consumer(child)andtheataportthesupplier(parent).+*/+link=device_link_add(&sdev->sdev_gendev,&ap->tdev,+DL_FLAG_STATELESS|+DL_FLAG_PM_RUNTIME|DL_FLAG_RPM_ACTIVE);+if(!link){+ata_port_err(ap,"Failed to create link to scsi device %s\n",+dev_name(&sdev->sdev_gendev));+return-ENODEV;+}++return0;+}++/**+*ata_scsi_slave_alloc-EarlysetupofSCSIdevice+*@sdev:SCSIdevicetoexamine+*+*Thisiscalledfromscsi_alloc_sdev()whenthescsidevice+*associatedwithanATAdeviceisscannedonaport.+*+*LOCKING:+*DefinedbySCSIlayer.Wedon'treallycare.+*/++intata_scsi_slave_alloc(structscsi_device*sdev)+{+returnata_scsi_dev_alloc(sdev,ata_shost_to_port(sdev->host));+}+EXPORT_SYMBOL_GPL(ata_scsi_slave_alloc);+/***ata_scsi_slave_config-SetSCSIdeviceattributes*@sdev:SCSIdevicetoexamine
@@ -1105,14 +1145,11 @@ int ata_scsi_slave_config(struct scsi_device *sdev){structata_port*ap=ata_shost_to_port(sdev->host);structata_device*dev=__ata_scsi_find_dev(ap,sdev);-intrc=0;--ata_scsi_sdev_config(sdev);if(dev)-rc=ata_scsi_dev_config(sdev,dev);+returnata_scsi_dev_config(sdev,dev);-returnrc;+return0;}EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
On Thu, Sep 21, 2023 at 11:21 AM Geert Uytterhoeven
[off-list ref] wrote:
On Wed, Sep 20, 2023 at 3:54 PM Damien Le Moal [off-list ref] wrote:
quoted
The first 9 patches of this series fix several issues with suspend/resume
power management operations in scsi and libata. The most significant
changes introduced are in patch 4 and 5, where the manage_start_stop
flag of scsi devices is split into the manage_system_start_stop and
manage_runtime_start_stop flags to allow keeping scsi runtime power
operations for spining up/down ATA devices but have libata do its own
system suspend/resume device power state management using EH.
The remaining patches are code cleanup that do not introduce any
significant functional change.
This series was tested on qemu and on various PCs and servers. I am
CC-ing people who recently reported issues with suspend/resume.
Additional testing would be much appreciated.
Changes from v3:
* Corrected pathc 1 (typo in commit message and WARN_ON() removal)
* Changed path 3 as suggested by Niklas (moved definition of
->slave_alloc)
* Rebased on rc2
* Added review tags
Thanks for the update!
I gave this a try on Renesas Salvator-XS with R-Car H3 ES2.0 and
a SATA hard drive:
- The drive is spun up during system resume,
- Accessing the drive after the system was resumed is instantaneous.
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
The scsi disk driver does not resume disks that have been runtime
suspended by the user. To be consistent with this behavior, do the same
for ata ports and skip the PM request in ata_port_pm_resume() if the
port was already runtime suspended. With this change, it is no longer
necessary to for the PM state of the port to ACTIVE as the PM core code
^^^^^^
Can't parse this. :-)
will take care of that when handling runtime resume.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
nit: why not static? I could not see it used elsewhere. Indeed, I am not sure why it is not inlined in its only caller, ata_scsi_slave_alloc().
Thanks,
John
quoted hunk
+{+ struct device_link *link;++ ata_scsi_sdev_config(sdev);++ /*+ * Create a link from the ata_port device to the scsi device to ensure+ * that PM does suspend/resume in the correct order: the scsi device is+ * consumer (child) and the ata port the supplier (parent).+ */+ link = device_link_add(&sdev->sdev_gendev, &ap->tdev,+ DL_FLAG_STATELESS |+ DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);+ if (!link) {+ ata_port_err(ap, "Failed to create link to scsi device %s\n",+ dev_name(&sdev->sdev_gendev));+ return -ENODEV;+ }++ return 0;+}++/**+ * ata_scsi_slave_alloc - Early setup of SCSI device+ * @sdev: SCSI device to examine+ *+ * This is called from scsi_alloc_sdev() when the scsi device+ * associated with an ATA device is scanned on a port.+ *+ * LOCKING:+ * Defined by SCSI layer. We don't really care.+ */++int ata_scsi_slave_alloc(struct scsi_device *sdev)+{+ return ata_scsi_dev_alloc(sdev, ata_shost_to_port(sdev->host));+}+EXPORT_SYMBOL_GPL(ata_scsi_slave_alloc);
From: John Garry <john.g.garry@oracle.com> Date: 2023-09-21 17:49:07
On 20/09/2023 14:54, Damien Le Moal wrote:
quoted hunk
libsas does its own domain based power management of ports. For such
ports, libata should not use a device type defining power management
operations as executing these operations for suspend/resume in addition
to libsas calls to ata_sas_port_suspend() and ata_sas_port_resume() is
not necessary (and likely dangerous to do, even though problems are not
seen currently).
Introduce the new ata_port_sas_type device_type for ports managed by
libsas. This new device type is used in ata_tport_add() and is defined
without power management operations.
Fixes: 2fcbdcb4c802 ("[SCSI] libata: export ata_port suspend/resume infrastructure for sas")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
drivers/ata/libata-core.c | 2 +-
drivers/ata/libata-transport.c | 9 ++++++++-
drivers/ata/libata.h | 2 ++
3 files changed, 11 insertions(+), 2 deletions(-)
It seems less than ideal to give different device types the same name.
However, from the definition of device_type.name, it seems to be used for uevent, so I suppose best to keep the same at this stage.
Reviewed-by: John Garry <john.g.garry@oracle.com>
quoted hunk
+};+ /** ata_tport_add - initialize a transport ATA port structure * * @parent: parent device
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-21 19:05:15
On 2023/09/21 0:32, Sergey Shtylyov wrote:
On 9/20/23 4:54 PM, Damien Le Moal wrote:
quoted
The scsi disk driver does not resume disks that have been runtime
suspended by the user. To be consistent with this behavior, do the same
for ata ports and skip the PM request in ata_port_pm_resume() if the
port was already runtime suspended. With this change, it is no longer
necessary to for the PM state of the port to ACTIVE as the PM core code
^^^^^^
Can't parse this. :-)
s/for/force
Will fix that.
quoted
will take care of that when handling runtime resume.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-21 20:10:37
On 2023/09/20 6:54, Damien Le Moal wrote:
The first 9 patches of this series fix several issues with suspend/resume
power management operations in scsi and libata. The most significant
changes introduced are in patch 4 and 5, where the manage_start_stop
flag of scsi devices is split into the manage_system_start_stop and
manage_runtime_start_stop flags to allow keeping scsi runtime power
operations for spining up/down ATA devices but have libata do its own
system suspend/resume device power state management using EH.
The remaining patches are code cleanup that do not introduce any
significant functional change.
Martin,
Could you please review and Ack (if appropriate) the scsi bits of this series ?
I would like to send out the first 9 patches ASAP to address regressions.
Thanks !
This series was tested on qemu and on various PCs and servers. I am
CC-ing people who recently reported issues with suspend/resume.
Additional testing would be much appreciated.
Changes from v3:
* Corrected pathc 1 (typo in commit message and WARN_ON() removal)
* Changed path 3 as suggested by Niklas (moved definition of
->slave_alloc)
* Rebased on rc2
* Added review tags
Changes from v2:
* Added patch 4 as simply disabling manage_start_stop from libata was
breaking individual disk runtime suspend/autosuspend. Patch 5 was
reworked accordingly to the changes in patch 4.
* Fixed patch 3: applying the link creation was missing and the link
creation itself was also incorrect, preventing sd probe to execute
correctly. Thanks to Geert for testing and reporting this issue.
* Split the "Fix delayed scsi_rescan_device() execution" patch into
patch 6 (scsi part) and patch 7 (ata part).
* Modified patch 9 to not call sd_shutdown() from sd_remove() for
devices that are not running.
* Added Chia-Lin Tested tag to unchanged patches
Changes from v1:
* Added patch 8 and 9 to fix compilation warnings with W=1
* Addressed John comment in patch 19
* Fixed patch 20 commit message (Sergei)
* Added Hannes Review tag
Damien Le Moal (23):
ata: libata-core: Fix ata_port_request_pm() locking
ata: libata-core: Fix port and device removal
ata: libata-scsi: link ata port and scsi device
scsi: sd: Differentiate system and runtime start/stop management
ata: libata-scsi: Disable scsi device manage_system_start_stop
scsi: Do not attempt to rescan suspended devices
ata: libata-scsi: Fix delayed scsi_rescan_device() execution
ata: libata-core: Do not register PM operations for SAS ports
scsi: sd: Do not issue commands to suspended disks on shutdown
ata: libata-core: Fix compilation warning in ata_dev_config_ncq()
ata: libata-eh: Fix compilation warning in ata_eh_link_report()
scsi: Remove scsi device no_start_on_resume flag
ata: libata-scsi: Cleanup ata_scsi_start_stop_xlat()
ata: libata-core: Synchronize ata_port_detach() with hotplug
ata: libata-core: Detach a port devices on shutdown
ata: libata-core: Remove ata_port_suspend_async()
ata: libata-core: Remove ata_port_resume_async()
ata: libata-core: Do not poweroff runtime suspended ports
ata: libata-core: Do not resume runtime suspended ports
ata: libata-sata: Improve ata_sas_slave_configure()
ata: libata-eh: Improve reset error messages
ata: libata-eh: Reduce "disable device" message verbosity
ata: libata: Cleanup inline DMA helper functions
drivers/ata/libata-core.c | 242 +++++++++++++++++++++++++--------
drivers/ata/libata-eh.c | 76 +++++++++--
drivers/ata/libata-sata.c | 5 +-
drivers/ata/libata-scsi.c | 146 ++++++++++----------
drivers/ata/libata-transport.c | 9 +-
drivers/ata/libata.h | 7 +
drivers/firewire/sbp2.c | 9 +-
drivers/scsi/scsi_scan.c | 18 ++-
drivers/scsi/sd.c | 88 ++++++++----
include/linux/libata.h | 26 ++--
include/scsi/scsi_device.h | 4 +-
include/scsi/scsi_host.h | 2 +-
12 files changed, 444 insertions(+), 188 deletions(-)
Hi Damien,
On Wed, Sep 20, 2023 at 3:54 PM Damien Le Moal [off-list ref] wrote:
The first 9 patches of this series fix several issues with suspend/resume
power management operations in scsi and libata. The most significant
changes introduced are in patch 4 and 5, where the manage_start_stop
flag of scsi devices is split into the manage_system_start_stop and
manage_runtime_start_stop flags to allow keeping scsi runtime power
operations for spining up/down ATA devices but have libata do its own
system suspend/resume device power state management using EH.
The remaining patches are code cleanup that do not introduce any
significant functional change.
This series was tested on qemu and on various PCs and servers. I am
CC-ing people who recently reported issues with suspend/resume.
Additional testing would be much appreciated.
Changes from v3:
* Corrected pathc 1 (typo in commit message and WARN_ON() removal)
* Changed path 3 as suggested by Niklas (moved definition of
->slave_alloc)
* Rebased on rc2
* Added review tags
Thanks for the update!
I gave this a try on Renesas Salvator-XS with R-Car H3 ES2.0 and
a SATA hard drive:
- The drive is spun up during system resume,
- Accessing the drive after the system was resumed is instantaneous.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-21 20:25:26
On 2023/09/21 2:22, Geert Uytterhoeven wrote:
On Thu, Sep 21, 2023 at 11:21 AM Geert Uytterhoeven
[off-list ref] wrote:
quoted
On Wed, Sep 20, 2023 at 3:54 PM Damien Le Moal [off-list ref] wrote:
quoted
The first 9 patches of this series fix several issues with suspend/resume
power management operations in scsi and libata. The most significant
changes introduced are in patch 4 and 5, where the manage_start_stop
flag of scsi devices is split into the manage_system_start_stop and
manage_runtime_start_stop flags to allow keeping scsi runtime power
operations for spining up/down ATA devices but have libata do its own
system suspend/resume device power state management using EH.
The remaining patches are code cleanup that do not introduce any
significant functional change.
This series was tested on qemu and on various PCs and servers. I am
CC-ing people who recently reported issues with suspend/resume.
Additional testing would be much appreciated.
Changes from v3:
* Corrected pathc 1 (typo in commit message and WARN_ON() removal)
* Changed path 3 as suggested by Niklas (moved definition of
->slave_alloc)
* Rebased on rc2
* Added review tags
Thanks for the update!
I gave this a try on Renesas Salvator-XS with R-Car H3 ES2.0 and
a SATA hard drive:
- The drive is spun up during system resume,
- Accessing the drive after the system was resumed is instantaneous.
nit: why not static? I could not see it used elsewhere. Indeed, I am not
sure why it is not inlined in its only caller, ata_scsi_slave_alloc().
The initial version of this patchset used this function for libsas as well. But
that is now gone, so I can indeed inline this.
Note that with the STATELESS flag added, the linking of ata dev and scsi dev
should work just fine for libsas now, so we could add it. But I am still not
convinced that is necessary... Will have a look as a follow up.
Thanks,
John
quoted
+{+ struct device_link *link;++ ata_scsi_sdev_config(sdev);++ /*+ * Create a link from the ata_port device to the scsi device to ensure+ * that PM does suspend/resume in the correct order: the scsi device is+ * consumer (child) and the ata port the supplier (parent).+ */+ link = device_link_add(&sdev->sdev_gendev, &ap->tdev,+ DL_FLAG_STATELESS |+ DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);+ if (!link) {+ ata_port_err(ap, "Failed to create link to scsi device %s\n",+ dev_name(&sdev->sdev_gendev));+ return -ENODEV;+ }++ return 0;+}++/**+ * ata_scsi_slave_alloc - Early setup of SCSI device+ * @sdev: SCSI device to examine+ *+ * This is called from scsi_alloc_sdev() when the scsi device+ * associated with an ATA device is scanned on a port.+ *+ * LOCKING:+ * Defined by SCSI layer. We don't really care.+ */++int ata_scsi_slave_alloc(struct scsi_device *sdev)+{+ return ata_scsi_dev_alloc(sdev, ata_shost_to_port(sdev->host));+}+EXPORT_SYMBOL_GPL(ata_scsi_slave_alloc);
From: Bart Van Assche <bvanassche@acm.org> Date: 2023-09-21 21:48:50
On 9/20/23 06:54, Damien Le Moal wrote:
If an error occurs when resuming a host adapter before the devices
attached to the adapter are resumed, the adapter low level driver may
remove the scsi host, resulting in a call to sd_remove() for the
disks of the host. This in turn results in a call to sd_shutdown() which
will issue a synchronize cache command and a start stop unit command to
spindown the disk. sd_shutdown() issues the commands only if the device
is not already suspended but does not check the power state for
system-wide suspend/resume. That is, the commands may be issued with the
device in a suspended state, which causes PM resume to hang, forcing a
reset of the machine to recover.
Fix this by not calling sd_shutdown() in sd_remove() if the device
is not running.
Hi Damien,
I'd like to look into an alternative fix (after this patch series went in) but I couldn't identify the call chain in the ATA resume code that results in removal of the SCSI host. Can you please show me the call chain that results in SCSI host removal if resuming fails?
Thanks,
Bart.
From: Bart Van Assche <bvanassche@acm.org> Date: 2023-09-21 21:51:59
On 9/20/23 06:54, Damien Le Moal wrote:
The underlying device and driver of a scsi disk may have different
system and runtime power mode control requirements. This is because
runtime power management affects only the scsi disk, while sustem level
power management affects all devices, including the controller for the
scsi disk.
For instance, issuing a START STOP UNIT command when a scsi disk is
runtime suspended and resumed is fine: the command is translated to a
STANDBY IMMEDIATE command to spin down the ATA disk and to a VERIFY
command to wake it up. The scsi disk runtime operations have no effect
on the ata port device used to connect the ATA disk. However, for
system suspend/resume operations, the ATA port used to connect the
device will also be suspended and resumed, with the resum operation
resum -> resume
requiring re-validating the device link and the device itseld. In this
This function wouldn't be necessary if the sd_suspend_common() callers would pass sdev->manage_system_start_stop / sdev->manage_runtime_start_stop as an additional argument to sd_suspend_common().
quoted hunk
- if (ignore_stop_errors)+ if (!runtime) ret = 0; }
The old code was self-documenting. If the name of the "runtime" argument is retained, a comment above this if-statement that explains why stop errors are ignored during a system suspend would be welcome.
Otherwise this patch looks good to me.
Thanks,
Bart.
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-21 22:26:26
On 2023/09/21 14:36, Bart Van Assche wrote:
On 9/20/23 06:54, Damien Le Moal wrote:
quoted
If an error occurs when resuming a host adapter before the devices
attached to the adapter are resumed, the adapter low level driver may
remove the scsi host, resulting in a call to sd_remove() for the
disks of the host. This in turn results in a call to sd_shutdown() which
will issue a synchronize cache command and a start stop unit command to
spindown the disk. sd_shutdown() issues the commands only if the device
is not already suspended but does not check the power state for
system-wide suspend/resume. That is, the commands may be issued with the
device in a suspended state, which causes PM resume to hang, forcing a
reset of the machine to recover.
Fix this by not calling sd_shutdown() in sd_remove() if the device
is not running.
Hi Damien,
I'd like to look into an alternative fix (after this patch series went
in) but I couldn't identify the call chain in the ATA resume code that
results in removal of the SCSI host. Can you please show me the call
chain that results in SCSI host removal if resuming fails?
See the pm80xx driver for which I recently fixed a resume issue. That is how I
found this problem with device removal: resuming the pm800xx HBA was failing and
the driver then called scsi_remove_host() to drop the ports and that led to
trying to removed sd devices that were still suspended.
From: Damien Le Moal <dlemoal@kernel.org> Date: 2023-09-22 17:00:24
On 2023/09/21 14:45, Bart Van Assche wrote:
On 9/20/23 06:54, Damien Le Moal wrote:
quoted
The underlying device and driver of a scsi disk may have different
system and runtime power mode control requirements. This is because
runtime power management affects only the scsi disk, while sustem level
power management affects all devices, including the controller for the
scsi disk.
For instance, issuing a START STOP UNIT command when a scsi disk is
runtime suspended and resumed is fine: the command is translated to a
STANDBY IMMEDIATE command to spin down the ATA disk and to a VERIFY
command to wake it up. The scsi disk runtime operations have no effect
on the ata port device used to connect the ATA disk. However, for
system suspend/resume operations, the ATA port used to connect the
device will also be suspended and resumed, with the resum operation
resum -> resume
quoted
requiring re-validating the device link and the device itseld. In this
This function wouldn't be necessary if the sd_suspend_common() callers
would pass sdev->manage_system_start_stop /
sdev->manage_runtime_start_stop as an additional argument to
sd_suspend_common().
Sure, but then we need to get the sdkp for the struct device and use
sdkp->device in both sd_suspend_runtime() and sd_suspend_system(). This is in my
opinion not as clean as the little inline helper. But if you insist, I can make
that change.
quoted
- if (ignore_stop_errors)+ if (!runtime) ret = 0; }
The old code was self-documenting. If the name of the "runtime" argument
is retained, a comment above this if-statement that explains why stop
errors are ignored during a system suspend would be welcome.
There is a comment already (unchanged) above the call to sd_start_stop_device(),
one line above the "if".
Otherwise this patch looks good to me.
Thanks,
Bart.