aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas/sas_expander.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-12-22 00:33:17 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-29 14:01:06 -0500
commitf41a0c441c3fe43e79ebeb75584dbb5bfa83e5cd (patch)
tree5a53adb90ebf31888184a9bff16ccc1869e2e4b3 /drivers/scsi/libsas/sas_expander.c
parent3a9c5560f677690f65038f399f4f598c79b83186 (diff)
[SCSI] libsas: fix sas_find_local_phy(), take phy references
In the direct-attached case this routine returns the phy on which this device was first discovered. Which is broken if we want to support wide-targets, as this phy reference can become stale even though the port is still active. In the expander-attached case this routine tries to lookup the phy by scanning the attached sas addresses of the parent expander, and BUG_ONs if it can't find it. However since eh and the libsas workqueue run independently we can still be attempting device recovery via eh after libsas has recorded the device as detached. This is even easier to hit now that eh is blocked while device domain rediscovery takes place, and that libata is fed more timed out commands increasing the chances that it will try to recover the ata device. Arrange for dev->phy to always point to a last known good phy, it may be stale after the port is torn down, but it will catch up for wide port reconfigurations, and never be NULL. Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas/sas_expander.c')
-rw-r--r--drivers/scsi/libsas/sas_expander.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 6fb1f3afd1e0..68a80a00f73f 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -723,6 +723,7 @@ static struct domain_device *sas_ex_discover_end_dev(
723 } 723 }
724 } 724 }
725 sas_ex_get_linkrate(parent, child, phy); 725 sas_ex_get_linkrate(parent, child, phy);
726 sas_device_set_phy(child, phy->port);
726 727
727#ifdef CONFIG_SCSI_SAS_ATA 728#ifdef CONFIG_SCSI_SAS_ATA
728 if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) { 729 if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) {
@@ -1810,7 +1811,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
1810{ 1811{
1811 struct expander_device *ex_dev = &parent->ex_dev; 1812 struct expander_device *ex_dev = &parent->ex_dev;
1812 struct ex_phy *phy = &ex_dev->ex_phy[phy_id]; 1813 struct ex_phy *phy = &ex_dev->ex_phy[phy_id];
1813 struct domain_device *child, *n; 1814 struct domain_device *child, *n, *found = NULL;
1814 if (last) { 1815 if (last) {
1815 list_for_each_entry_safe(child, n, 1816 list_for_each_entry_safe(child, n,
1816 &ex_dev->children, siblings) { 1817 &ex_dev->children, siblings) {
@@ -1822,6 +1823,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
1822 sas_unregister_ex_tree(parent->port, child); 1823 sas_unregister_ex_tree(parent->port, child);
1823 else 1824 else
1824 sas_unregister_dev(parent->port, child); 1825 sas_unregister_dev(parent->port, child);
1826 found = child;
1825 break; 1827 break;
1826 } 1828 }
1827 } 1829 }
@@ -1830,6 +1832,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
1830 memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE); 1832 memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
1831 if (phy->port) { 1833 if (phy->port) {
1832 sas_port_delete_phy(phy->port, phy->phy); 1834 sas_port_delete_phy(phy->port, phy->phy);
1835 sas_device_set_phy(found, phy->port);
1833 if (phy->port->num_phys == 0) 1836 if (phy->port->num_phys == 0)
1834 sas_port_delete(phy->port); 1837 sas_port_delete(phy->port);
1835 phy->port = NULL; 1838 phy->port = NULL;