aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_transport_sas.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/scsi_transport_sas.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/scsi_transport_sas.c')
-rw-r--r--drivers/scsi/scsi_transport_sas.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index ab3bd0b5ffd9..7d69a25d2004 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -1060,6 +1060,29 @@ int scsi_is_sas_port(const struct device *dev)
1060EXPORT_SYMBOL(scsi_is_sas_port); 1060EXPORT_SYMBOL(scsi_is_sas_port);
1061 1061
1062/** 1062/**
1063 * sas_port_get_phy - try to take a reference on a port member
1064 * @port: port to check
1065 */
1066struct sas_phy *sas_port_get_phy(struct sas_port *port)
1067{
1068 struct sas_phy *phy;
1069
1070 mutex_lock(&port->phy_list_mutex);
1071 if (list_empty(&port->phy_list))
1072 phy = NULL;
1073 else {
1074 struct list_head *ent = port->phy_list.next;
1075
1076 phy = list_entry(ent, typeof(*phy), port_siblings);
1077 get_device(&phy->dev);
1078 }
1079 mutex_unlock(&port->phy_list_mutex);
1080
1081 return phy;
1082}
1083EXPORT_SYMBOL(sas_port_get_phy);
1084
1085/**
1063 * sas_port_add_phy - add another phy to a port to form a wide port 1086 * sas_port_add_phy - add another phy to a port to form a wide port
1064 * @port: port to add the phy to 1087 * @port: port to add the phy to
1065 * @phy: phy to add 1088 * @phy: phy to add