aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas/sas_ata.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_ata.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_ata.c')
-rw-r--r--drivers/scsi/libsas/sas_ata.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 5fdb63ad94b7..92f7e78a096c 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -284,9 +284,10 @@ static int smp_ata_check_ready(struct ata_link *link)
284 struct ata_port *ap = link->ap; 284 struct ata_port *ap = link->ap;
285 struct domain_device *dev = ap->private_data; 285 struct domain_device *dev = ap->private_data;
286 struct domain_device *ex_dev = dev->parent; 286 struct domain_device *ex_dev = dev->parent;
287 struct sas_phy *phy = sas_find_local_phy(dev); 287 struct sas_phy *phy = sas_get_local_phy(dev);
288 288
289 res = sas_get_phy_attached_sas_addr(ex_dev, phy->number, addr); 289 res = sas_get_phy_attached_sas_addr(ex_dev, phy->number, addr);
290 sas_put_local_phy(phy);
290 /* break the wait early if the expander is unreachable, 291 /* break the wait early if the expander is unreachable,
291 * otherwise keep polling 292 * otherwise keep polling
292 */ 293 */
@@ -319,10 +320,10 @@ static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class,
319 unsigned long deadline) 320 unsigned long deadline)
320{ 321{
321 int ret = 0, res; 322 int ret = 0, res;
323 struct sas_phy *phy;
322 struct ata_port *ap = link->ap; 324 struct ata_port *ap = link->ap;
323 int (*check_ready)(struct ata_link *link); 325 int (*check_ready)(struct ata_link *link);
324 struct domain_device *dev = ap->private_data; 326 struct domain_device *dev = ap->private_data;
325 struct sas_phy *phy = sas_find_local_phy(dev);
326 struct sas_internal *i = dev_to_sas_internal(dev); 327 struct sas_internal *i = dev_to_sas_internal(dev);
327 328
328 res = i->dft->lldd_I_T_nexus_reset(dev); 329 res = i->dft->lldd_I_T_nexus_reset(dev);
@@ -330,10 +331,12 @@ static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class,
330 if (res != TMF_RESP_FUNC_COMPLETE) 331 if (res != TMF_RESP_FUNC_COMPLETE)
331 SAS_DPRINTK("%s: Unable to reset ata device?\n", __func__); 332 SAS_DPRINTK("%s: Unable to reset ata device?\n", __func__);
332 333
334 phy = sas_get_local_phy(dev);
333 if (scsi_is_sas_phy_local(phy)) 335 if (scsi_is_sas_phy_local(phy))
334 check_ready = local_ata_check_ready; 336 check_ready = local_ata_check_ready;
335 else 337 else
336 check_ready = smp_ata_check_ready; 338 check_ready = smp_ata_check_ready;
339 sas_put_local_phy(phy);
337 340
338 ret = ata_wait_after_reset(link, deadline, check_ready); 341 ret = ata_wait_after_reset(link, deadline, check_ready);
339 if (ret && ret != -EAGAIN) 342 if (ret && ret != -EAGAIN)