forked from mirrors/linux
		
	[SCSI] libata: export ata_port suspend/resume infrastructure for sas
Reuse ata_port_{suspend|resume}_common for sas.  This path is chosen
over adding coordination between ata-tranport and sas-transport because
libsas wants to revalidate the domain at resume-time at the host level.
It can not validate links have resumed properly until libata has had a
chance to perform its revalidation, and any sane placing of an ata_port
in the sas-transport model would delay it's resumption until after the
host.
Export the common portion of port suspend/resume (bypass pm_runtime),
and allow sas to perform these operations asynchronously (similar to the
libsas async-ata probe implmentation).  Async operation is determined by
having an external, rather than stack based, location for storing the
result of the operation.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Jacek Danecki <jacek.danecki@intel.com>
Acked-by: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
			
			
This commit is contained in:
		
							parent
							
								
									ca6d43b051
								
							
						
					
					
						commit
						2fcbdcb4c8
					
				
					 2 changed files with 57 additions and 12 deletions
				
			
		| 
						 | 
				
			
			@ -5252,16 +5252,20 @@ bool ata_link_offline(struct ata_link *link)
 | 
			
		|||
#ifdef CONFIG_PM
 | 
			
		||||
static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 | 
			
		||||
			       unsigned int action, unsigned int ehi_flags,
 | 
			
		||||
			       int wait)
 | 
			
		||||
			       int *async)
 | 
			
		||||
{
 | 
			
		||||
	struct ata_link *link;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	int rc;
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
 | 
			
		||||
	/* Previous resume operation might still be in
 | 
			
		||||
	 * progress.  Wait for PM_PENDING to clear.
 | 
			
		||||
	 */
 | 
			
		||||
	if (ap->pflags & ATA_PFLAG_PM_PENDING) {
 | 
			
		||||
		if (async) {
 | 
			
		||||
			*async = -EAGAIN;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		ata_port_wait_eh(ap);
 | 
			
		||||
		WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -5270,10 +5274,10 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 | 
			
		|||
	spin_lock_irqsave(ap->lock, flags);
 | 
			
		||||
 | 
			
		||||
	ap->pm_mesg = mesg;
 | 
			
		||||
	if (wait) {
 | 
			
		||||
		rc = 0;
 | 
			
		||||
	if (async)
 | 
			
		||||
		ap->pm_result = async;
 | 
			
		||||
	else
 | 
			
		||||
		ap->pm_result = &rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ap->pflags |= ATA_PFLAG_PM_PENDING;
 | 
			
		||||
	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,
 | 
			
		|||
	spin_unlock_irqrestore(ap->lock, flags);
 | 
			
		||||
 | 
			
		||||
	/* wait and check result */
 | 
			
		||||
	if (wait) {
 | 
			
		||||
	if (!async) {
 | 
			
		||||
		ata_port_wait_eh(ap);
 | 
			
		||||
		WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -5294,9 +5298,8 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 | 
			
		|||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
 | 
			
		||||
static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async)
 | 
			
		||||
{
 | 
			
		||||
	struct ata_port *ap = to_ata_port(dev);
 | 
			
		||||
	unsigned int ehi_flags = ATA_EHI_QUIET;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5311,10 +5314,17 @@ static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
 | 
			
		|||
	if (mesg.event == PM_EVENT_SUSPEND)
 | 
			
		||||
		ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
 | 
			
		||||
 | 
			
		||||
	rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, 1);
 | 
			
		||||
	rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
 | 
			
		||||
{
 | 
			
		||||
	struct ata_port *ap = to_ata_port(dev);
 | 
			
		||||
 | 
			
		||||
	return __ata_port_suspend_common(ap, mesg, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ata_port_suspend(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (pm_runtime_suspended(dev))
 | 
			
		||||
| 
						 | 
				
			
			@ -5339,16 +5349,22 @@ static int ata_port_poweroff(struct device *dev)
 | 
			
		|||
	return ata_port_suspend_common(dev, PMSG_HIBERNATE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ata_port_resume_common(struct device *dev)
 | 
			
		||||
static int __ata_port_resume_common(struct ata_port *ap, int *async)
 | 
			
		||||
{
 | 
			
		||||
	struct ata_port *ap = to_ata_port(dev);
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET,
 | 
			
		||||
		ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 1);
 | 
			
		||||
		ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ata_port_resume_common(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct ata_port *ap = to_ata_port(dev);
 | 
			
		||||
 | 
			
		||||
	return __ata_port_resume_common(ap, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ata_port_resume(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
| 
						 | 
				
			
			@ -5381,6 +5397,24 @@ static const struct dev_pm_ops ata_port_pm_ops = {
 | 
			
		|||
	.runtime_idle = ata_port_runtime_idle,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* sas ports don't participate in pm runtime management of ata_ports,
 | 
			
		||||
 * and need to resume ata devices at the domain level, not the per-port
 | 
			
		||||
 * level. sas suspend/resume is async to allow parallel port recovery
 | 
			
		||||
 * since sas has multiple ata_port instances per Scsi_Host.
 | 
			
		||||
 */
 | 
			
		||||
int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
 | 
			
		||||
{
 | 
			
		||||
	return __ata_port_suspend_common(ap, PMSG_SUSPEND, async);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend);
 | 
			
		||||
 | 
			
		||||
int ata_sas_port_async_resume(struct ata_port *ap, int *async)
 | 
			
		||||
{
 | 
			
		||||
	return __ata_port_resume_common(ap, async);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(ata_sas_port_async_resume);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *	ata_host_suspend - suspend host
 | 
			
		||||
 *	@host: host to suspend
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1013,6 +1013,17 @@ extern bool ata_link_offline(struct ata_link *link);
 | 
			
		|||
#ifdef CONFIG_PM
 | 
			
		||||
extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
 | 
			
		||||
extern void ata_host_resume(struct ata_host *host);
 | 
			
		||||
extern int ata_sas_port_async_suspend(struct ata_port *ap, int *async);
 | 
			
		||||
extern int ata_sas_port_async_resume(struct ata_port *ap, int *async);
 | 
			
		||||
#else
 | 
			
		||||
static inline int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
static inline int ata_sas_port_async_resume(struct ata_port *ap, int *async)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
extern int ata_ratelimit(void);
 | 
			
		||||
extern void ata_msleep(struct ata_port *ap, unsigned int msecs);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue