From ca6d43b051b5a061b33c43303b6b4c93b46a34b5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Jun 2012 23:41:41 -0700 Subject: [SCSI] libata: reset once Hotplug testing with libsas currently encounters a 55 second wait for link recovery to give up. In the case where the user trusts the response time of their devices permit the recovery attempts to be limited to one. Signed-off-by: Dan Williams Acked-by: Jeff Garzik Acked-by: Tejun Heo Signed-off-by: James Bottomley --- include/linux/libata.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux/libata.h') diff --git a/include/linux/libata.h b/include/linux/libata.h index 64f90e17e51d..31a2853e9530 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -184,6 +184,7 @@ enum { ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */ ATA_LFLAG_SW_ACTIVITY = (1 << 7), /* keep activity stats */ ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */ + ATA_LFLAG_RST_ONCE = (1 << 9), /* limit recovery to one reset */ /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ -- cgit v1.2.3 From 2fcbdcb4c802fe40d6827dbc365dac90cfe8c0a3 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Jun 2012 23:41:46 -0700 Subject: [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 Reviewed-by: Jacek Danecki Acked-by: Jeff Garzik Signed-off-by: James Bottomley --- drivers/ata/libata-core.c | 58 +++++++++++++++++++++++++++++++++++++---------- include/linux/libata.h | 11 +++++++++ 2 files changed, 57 insertions(+), 12 deletions(-) (limited to 'include/linux/libata.h') 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) #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 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); #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); -- cgit v1.2.3 From 8d8e7d13146eb6be8b98dbd58ac30421a4f8edf3 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 9 Jul 2012 21:06:08 -0700 Subject: [SCSI] libsas, ipr: cleanup ata_host flags initialization via ata_host_init libsas and ipr pass flags to ata_host_init that are meant for the port. ata_host flags: ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host only */ ATA_HOST_STARTED = (1 << 1), /* Host started */ ATA_HOST_PARALLEL_SCAN = (1 << 2), /* Ports on this host can be scanned in parallel */ ATA_HOST_IGNORE_ATA = (1 << 3), /* Ignore ATA devices on this host. */ flags passed by libsas: ATA_FLAG_SATA = (1 << 1), ATA_FLAG_PIO_DMA = (1 << 7), /* PIO cmds via DMA */ ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */ The only one that aliases is ATA_HOST_STARTED which is a 'don't care' in the libsas and ipr cases since ata_hosts from these sources are not registered with libata. Reported-by: Hannes Reinecke Signed-off-by: Dan Williams Acked-by: Brian King Acked-by: Jeff Garzik Signed-off-by: James Bottomley --- drivers/ata/libata-core.c | 10 ++-------- drivers/scsi/ipr.c | 3 +-- drivers/scsi/libsas/sas_ata.c | 5 +---- include/linux/libata.h | 3 +-- 4 files changed, 5 insertions(+), 16 deletions(-) (limited to 'include/linux/libata.h') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 09657c372d3b..2d479b67d0b4 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5960,24 +5960,18 @@ int ata_host_start(struct ata_host *host) } /** - * ata_sas_host_init - Initialize a host struct + * ata_sas_host_init - Initialize a host struct for sas (ipr, libsas) * @host: host to initialize * @dev: device host is attached to - * @flags: host flags * @ops: port_ops * - * LOCKING: - * PCI/etc. bus probe sem. - * */ -/* KILLME - the only user left is ipr */ void ata_host_init(struct ata_host *host, struct device *dev, - unsigned long flags, struct ata_port_operations *ops) + struct ata_port_operations *ops) { spin_lock_init(&host->lock); mutex_init(&host->eh_mutex); host->dev = dev; - host->flags = flags; host->ops = ops; } diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 467dc38246f9..dacc784ad2d6 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -8775,8 +8775,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata; memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg)); - ata_host_init(&ioa_cfg->ata_host, &pdev->dev, - sata_port_info.flags, &ipr_sata_ops); + ata_host_init(&ioa_cfg->ata_host, &pdev->dev, &ipr_sata_ops); ioa_cfg->ipr_chip = ipr_get_chip_info(dev_id); diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 905ae45133fc..bdb81cda8401 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -580,10 +580,7 @@ int sas_ata_init(struct domain_device *found_dev) struct ata_port *ap; int rc; - ata_host_init(&found_dev->sata_dev.ata_host, - ha->dev, - sata_port_info.flags, - &sas_sata_ops); + ata_host_init(&found_dev->sata_dev.ata_host, ha->dev, &sas_sata_ops); ap = ata_sas_port_alloc(&found_dev->sata_dev.ata_host, &sata_port_info, shost); diff --git a/include/linux/libata.h b/include/linux/libata.h index cc834e1136b2..a22707186421 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -987,8 +987,7 @@ extern int ata_host_activate(struct ata_host *host, int irq, irq_handler_t irq_handler, unsigned long irq_flags, struct scsi_host_template *sht); extern void ata_host_detach(struct ata_host *host); -extern void ata_host_init(struct ata_host *, struct device *, - unsigned long, struct ata_port_operations *); +extern void ata_host_init(struct ata_host *, struct device *, struct ata_port_operations *); extern int ata_scsi_detect(struct scsi_host_template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct Scsi_Host *h, struct scsi_cmnd *cmd); -- cgit v1.2.3