aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ata/libata-core.c58
-rw-r--r--include/linux/libata.h11
2 files changed, 57 insertions, 12 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 70964aabcb89..09657c372d3b 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5252,16 +5252,20 @@ bool ata_link_offline(struct ata_link *link)
5252#ifdef CONFIG_PM 5252#ifdef CONFIG_PM
5253static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg, 5253static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
5254 unsigned int action, unsigned int ehi_flags, 5254 unsigned int action, unsigned int ehi_flags,
5255 int wait) 5255 int *async)
5256{ 5256{
5257 struct ata_link *link; 5257 struct ata_link *link;
5258 unsigned long flags; 5258 unsigned long flags;
5259 int rc; 5259 int rc = 0;
5260 5260
5261 /* Previous resume operation might still be in 5261 /* Previous resume operation might still be in
5262 * progress. Wait for PM_PENDING to clear. 5262 * progress. Wait for PM_PENDING to clear.
5263 */ 5263 */
5264 if (ap->pflags & ATA_PFLAG_PM_PENDING) { 5264 if (ap->pflags & ATA_PFLAG_PM_PENDING) {
5265 if (async) {
5266 *async = -EAGAIN;
5267 return 0;
5268 }
5265 ata_port_wait_eh(ap); 5269 ata_port_wait_eh(ap);
5266 WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING); 5270 WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
5267 } 5271 }
@@ -5270,10 +5274,10 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
5270 spin_lock_irqsave(ap->lock, flags); 5274 spin_lock_irqsave(ap->lock, flags);
5271 5275
5272 ap->pm_mesg = mesg; 5276 ap->pm_mesg = mesg;
5273 if (wait) { 5277 if (async)
5274 rc = 0; 5278 ap->pm_result = async;
5279 else
5275 ap->pm_result = &rc; 5280 ap->pm_result = &rc;
5276 }
5277 5281
5278 ap->pflags |= ATA_PFLAG_PM_PENDING; 5282 ap->pflags |= ATA_PFLAG_PM_PENDING;
5279 ata_for_each_link(link, ap, HOST_FIRST) { 5283 ata_for_each_link(link, ap, HOST_FIRST) {
@@ -5286,7 +5290,7 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
5286 spin_unlock_irqrestore(ap->lock, flags); 5290 spin_unlock_irqrestore(ap->lock, flags);
5287 5291
5288 /* wait and check result */ 5292 /* wait and check result */
5289 if (wait) { 5293 if (!async) {
5290 ata_port_wait_eh(ap); 5294 ata_port_wait_eh(ap);
5291 WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING); 5295 WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
5292 } 5296 }
@@ -5294,9 +5298,8 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
5294 return rc; 5298 return rc;
5295} 5299}
5296 5300
5297static int ata_port_suspend_common(struct device *dev, pm_message_t mesg) 5301static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async)
5298{ 5302{
5299 struct ata_port *ap = to_ata_port(dev);
5300 unsigned int ehi_flags = ATA_EHI_QUIET; 5303 unsigned int ehi_flags = ATA_EHI_QUIET;
5301 int rc; 5304 int rc;
5302 5305
@@ -5311,10 +5314,17 @@ static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
5311 if (mesg.event == PM_EVENT_SUSPEND) 5314 if (mesg.event == PM_EVENT_SUSPEND)
5312 ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY; 5315 ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
5313 5316
5314 rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, 1); 5317 rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
5315 return rc; 5318 return rc;
5316} 5319}
5317 5320
5321static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
5322{
5323 struct ata_port *ap = to_ata_port(dev);
5324
5325 return __ata_port_suspend_common(ap, mesg, NULL);
5326}
5327
5318static int ata_port_suspend(struct device *dev) 5328static int ata_port_suspend(struct device *dev)
5319{ 5329{
5320 if (pm_runtime_suspended(dev)) 5330 if (pm_runtime_suspended(dev))
@@ -5339,16 +5349,22 @@ static int ata_port_poweroff(struct device *dev)
5339 return ata_port_suspend_common(dev, PMSG_HIBERNATE); 5349 return ata_port_suspend_common(dev, PMSG_HIBERNATE);
5340} 5350}
5341 5351
5342static int ata_port_resume_common(struct device *dev) 5352static int __ata_port_resume_common(struct ata_port *ap, int *async)
5343{ 5353{
5344 struct ata_port *ap = to_ata_port(dev);
5345 int rc; 5354 int rc;
5346 5355
5347 rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET, 5356 rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET,
5348 ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 1); 5357 ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
5349 return rc; 5358 return rc;
5350} 5359}
5351 5360
5361static int ata_port_resume_common(struct device *dev)
5362{
5363 struct ata_port *ap = to_ata_port(dev);
5364
5365 return __ata_port_resume_common(ap, NULL);
5366}
5367
5352static int ata_port_resume(struct device *dev) 5368static int ata_port_resume(struct device *dev)
5353{ 5369{
5354 int rc; 5370 int rc;
@@ -5381,6 +5397,24 @@ static const struct dev_pm_ops ata_port_pm_ops = {
5381 .runtime_idle = ata_port_runtime_idle, 5397 .runtime_idle = ata_port_runtime_idle,
5382}; 5398};
5383 5399
5400/* sas ports don't participate in pm runtime management of ata_ports,
5401 * and need to resume ata devices at the domain level, not the per-port
5402 * level. sas suspend/resume is async to allow parallel port recovery
5403 * since sas has multiple ata_port instances per Scsi_Host.
5404 */
5405int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
5406{
5407 return __ata_port_suspend_common(ap, PMSG_SUSPEND, async);
5408}
5409EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend);
5410
5411int ata_sas_port_async_resume(struct ata_port *ap, int *async)
5412{
5413 return __ata_port_resume_common(ap, async);
5414}
5415EXPORT_SYMBOL_GPL(ata_sas_port_async_resume);
5416
5417
5384/** 5418/**
5385 * ata_host_suspend - suspend host 5419 * ata_host_suspend - suspend host
5386 * @host: host to suspend 5420 * @host: host to suspend
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 31a2853e9530..cc834e1136b2 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -1013,6 +1013,17 @@ extern bool ata_link_offline(struct ata_link *link);
1013#ifdef CONFIG_PM 1013#ifdef CONFIG_PM
1014extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg); 1014extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
1015extern void ata_host_resume(struct ata_host *host); 1015extern void ata_host_resume(struct ata_host *host);
1016extern int ata_sas_port_async_suspend(struct ata_port *ap, int *async);
1017extern int ata_sas_port_async_resume(struct ata_port *ap, int *async);
1018#else
1019static inline int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
1020{
1021 return 0;
1022}
1023static inline int ata_sas_port_async_resume(struct ata_port *ap, int *async)
1024{
1025 return 0;
1026}
1016#endif 1027#endif
1017extern int ata_ratelimit(void); 1028extern int ata_ratelimit(void);
1018extern void ata_msleep(struct ata_port *ap, unsigned int msecs); 1029extern void ata_msleep(struct ata_port *ap, unsigned int msecs);