aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas/sas_ata.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2012-06-22 02:41:51 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-08-24 05:10:23 -0400
commit303694eeee5eacad5b84105a15afd9e351e1891b (patch)
treeba8e16274ffbde39b21100ced62b5b11e8c926d6 /drivers/scsi/libsas/sas_ata.c
parent2fcbdcb4c802fe40d6827dbc365dac90cfe8c0a3 (diff)
[SCSI] libsas: suspend / resume support
libsas power management routines to suspend and recover the sas domain based on a model where the lldd is allowed and expected to be "forgetful". sas_suspend_ha - disable event processing allowing the lldd to take down links without concern for causing hotplug events. Regardless of whether the lldd actually posts link down messages libsas notifies the lldd that all domain_devices are gone. sas_prep_resume_ha - on the way back up before the lldd starts link training clean out any spurious events that were generated on the way down, and re-enable event processing sas_resume_ha - after the lldd has started and decided that all phys have posted link-up events this routine is called to let libsas start it's own timeout of any phys that did not resume. After the timeout an lldd can cancel the phy teardown by posting a link-up event. Storage for ex_change_count (u16) and phy_change_count (u8) are changed to int so they can be set to -1 to indicate 'invalidated'. Signed-off-by: Dan Williams <dan.j.williams@intel.com> Reviewed-by: Jacek Danecki <jacek.danecki@intel.com> Tested-by: Maciej Patelczyk <maciej.patelczyk@intel.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas/sas_ata.c')
-rw-r--r--drivers/scsi/libsas/sas_ata.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index a59fcdc8fd63..905ae45133fc 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -700,6 +700,92 @@ void sas_probe_sata(struct asd_sas_port *port)
700 if (ata_dev_disabled(sas_to_ata_dev(dev))) 700 if (ata_dev_disabled(sas_to_ata_dev(dev)))
701 sas_fail_probe(dev, __func__, -ENODEV); 701 sas_fail_probe(dev, __func__, -ENODEV);
702 } 702 }
703
704}
705
706static bool sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
707{
708 struct domain_device *dev, *n;
709 bool retry = false;
710
711 list_for_each_entry_safe(dev, n, &port->dev_list, dev_list_node) {
712 int rc;
713
714 if (!dev_is_sata(dev))
715 continue;
716
717 sas_ata_wait_eh(dev);
718 rc = dev->sata_dev.pm_result;
719 if (rc == -EAGAIN)
720 retry = true;
721 else if (rc) {
722 /* since we don't have a
723 * ->port_{suspend|resume} routine in our
724 * ata_port ops, and no entanglements with
725 * acpi, suspend should just be mechanical trip
726 * through eh, catch cases where these
727 * assumptions are invalidated
728 */
729 WARN_ONCE(1, "failed %s %s error: %d\n", func,
730 dev_name(&dev->rphy->dev), rc);
731 }
732
733 /* if libata failed to power manage the device, tear it down */
734 if (ata_dev_disabled(sas_to_ata_dev(dev)))
735 sas_fail_probe(dev, func, -ENODEV);
736 }
737
738 return retry;
739}
740
741void sas_suspend_sata(struct asd_sas_port *port)
742{
743 struct domain_device *dev;
744
745 retry:
746 mutex_lock(&port->ha->disco_mutex);
747 list_for_each_entry(dev, &port->dev_list, dev_list_node) {
748 struct sata_device *sata;
749
750 if (!dev_is_sata(dev))
751 continue;
752
753 sata = &dev->sata_dev;
754 if (sata->ap->pm_mesg.event == PM_EVENT_SUSPEND)
755 continue;
756
757 sata->pm_result = -EIO;
758 ata_sas_port_async_suspend(sata->ap, &sata->pm_result);
759 }
760 mutex_unlock(&port->ha->disco_mutex);
761
762 if (sas_ata_flush_pm_eh(port, __func__))
763 goto retry;
764}
765
766void sas_resume_sata(struct asd_sas_port *port)
767{
768 struct domain_device *dev;
769
770 retry:
771 mutex_lock(&port->ha->disco_mutex);
772 list_for_each_entry(dev, &port->dev_list, dev_list_node) {
773 struct sata_device *sata;
774
775 if (!dev_is_sata(dev))
776 continue;
777
778 sata = &dev->sata_dev;
779 if (sata->ap->pm_mesg.event == PM_EVENT_ON)
780 continue;
781
782 sata->pm_result = -EIO;
783 ata_sas_port_async_resume(sata->ap, &sata->pm_result);
784 }
785 mutex_unlock(&port->ha->disco_mutex);
786
787 if (sas_ata_flush_pm_eh(port, __func__))
788 goto retry;
703} 789}
704 790
705/** 791/**