summaryrefslogtreecommitdiff
path: root/drivers/scsi/libsas/sas_ata.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libsas/sas_ata.c')
-rw-r--r--drivers/scsi/libsas/sas_ata.c91
1 files changed, 87 insertions, 4 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index a59fcdc8fd63..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);
@@ -700,6 +697,92 @@ void sas_probe_sata(struct asd_sas_port *port)
if (ata_dev_disabled(sas_to_ata_dev(dev)))
sas_fail_probe(dev, __func__, -ENODEV);
}
+
+}
+
+static bool sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
+{
+ struct domain_device *dev, *n;
+ bool retry = false;
+
+ list_for_each_entry_safe(dev, n, &port->dev_list, dev_list_node) {
+ int rc;
+
+ if (!dev_is_sata(dev))
+ continue;
+
+ sas_ata_wait_eh(dev);
+ rc = dev->sata_dev.pm_result;
+ if (rc == -EAGAIN)
+ retry = true;
+ else if (rc) {
+ /* since we don't have a
+ * ->port_{suspend|resume} routine in our
+ * ata_port ops, and no entanglements with
+ * acpi, suspend should just be mechanical trip
+ * through eh, catch cases where these
+ * assumptions are invalidated
+ */
+ WARN_ONCE(1, "failed %s %s error: %d\n", func,
+ dev_name(&dev->rphy->dev), rc);
+ }
+
+ /* if libata failed to power manage the device, tear it down */
+ if (ata_dev_disabled(sas_to_ata_dev(dev)))
+ sas_fail_probe(dev, func, -ENODEV);
+ }
+
+ return retry;
+}
+
+void sas_suspend_sata(struct asd_sas_port *port)
+{
+ struct domain_device *dev;
+
+ retry:
+ mutex_lock(&port->ha->disco_mutex);
+ list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+ struct sata_device *sata;
+
+ if (!dev_is_sata(dev))
+ continue;
+
+ sata = &dev->sata_dev;
+ if (sata->ap->pm_mesg.event == PM_EVENT_SUSPEND)
+ continue;
+
+ sata->pm_result = -EIO;
+ ata_sas_port_async_suspend(sata->ap, &sata->pm_result);
+ }
+ mutex_unlock(&port->ha->disco_mutex);
+
+ if (sas_ata_flush_pm_eh(port, __func__))
+ goto retry;
+}
+
+void sas_resume_sata(struct asd_sas_port *port)
+{
+ struct domain_device *dev;
+
+ retry:
+ mutex_lock(&port->ha->disco_mutex);
+ list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+ struct sata_device *sata;
+
+ if (!dev_is_sata(dev))
+ continue;
+
+ sata = &dev->sata_dev;
+ if (sata->ap->pm_mesg.event == PM_EVENT_ON)
+ continue;
+
+ sata->pm_result = -EIO;
+ ata_sas_port_async_resume(sata->ap, &sata->pm_result);
+ }
+ mutex_unlock(&port->ha->disco_mutex);
+
+ if (sas_ata_flush_pm_eh(port, __func__))
+ goto retry;
}
/**