aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas
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
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')
-rw-r--r--drivers/scsi/libsas/sas_ata.c7
-rw-r--r--drivers/scsi/libsas/sas_discover.c24
-rw-r--r--drivers/scsi/libsas/sas_expander.c5
-rw-r--r--drivers/scsi/libsas/sas_internal.h1
-rw-r--r--drivers/scsi/libsas/sas_port.c7
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c38
6 files changed, 55 insertions, 27 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)
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index c56cc6400819..789b50861bb9 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -147,6 +147,7 @@ static int sas_get_port_device(struct asd_sas_port *port)
147 memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE); 147 memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE);
148 memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE); 148 memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE);
149 port->disc.max_level = 0; 149 port->disc.max_level = 0;
150 sas_device_set_phy(dev, port->port);
150 151
151 dev->rphy = rphy; 152 dev->rphy = rphy;
152 153
@@ -234,6 +235,9 @@ void sas_free_device(struct kref *kref)
234 if (dev->parent) 235 if (dev->parent)
235 sas_put_device(dev->parent); 236 sas_put_device(dev->parent);
236 237
238 sas_port_put_phy(dev->phy);
239 dev->phy = NULL;
240
237 /* remove the phys and ports, everything else should be gone */ 241 /* remove the phys and ports, everything else should be gone */
238 if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) 242 if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV)
239 kfree(dev->ex_dev.ex_phy); 243 kfree(dev->ex_dev.ex_phy);
@@ -308,6 +312,26 @@ void sas_unregister_domain_devices(struct asd_sas_port *port)
308 312
309} 313}
310 314
315void sas_device_set_phy(struct domain_device *dev, struct sas_port *port)
316{
317 struct sas_ha_struct *ha;
318 struct sas_phy *new_phy;
319
320 if (!dev)
321 return;
322
323 ha = dev->port->ha;
324 new_phy = sas_port_get_phy(port);
325
326 /* pin and record last seen phy */
327 spin_lock_irq(&ha->phy_port_lock);
328 if (new_phy) {
329 sas_port_put_phy(dev->phy);
330 dev->phy = new_phy;
331 }
332 spin_unlock_irq(&ha->phy_port_lock);
333}
334
311/* ---------- Discovery and Revalidation ---------- */ 335/* ---------- Discovery and Revalidation ---------- */
312 336
313/** 337/**
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;
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index a9a3bb94c1bc..c8febc71c40d 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -87,6 +87,7 @@ int sas_smp_phy_control(struct domain_device *dev, int phy_id,
87 enum phy_func phy_func, struct sas_phy_linkrates *); 87 enum phy_func phy_func, struct sas_phy_linkrates *);
88int sas_smp_get_phy_events(struct sas_phy *phy); 88int sas_smp_get_phy_events(struct sas_phy *phy);
89 89
90void sas_device_set_phy(struct domain_device *dev, struct sas_port *port);
90struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); 91struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
91struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id); 92struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
92int sas_get_phy_attached_sas_addr(struct domain_device *dev, int phy_id, 93int sas_get_phy_attached_sas_addr(struct domain_device *dev, int phy_id,
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index 2980bde4e34a..31adcd1b4191 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -108,9 +108,6 @@ static void sas_form_port(struct asd_sas_phy *phy)
108 port->num_phys++; 108 port->num_phys++;
109 port->phy_mask |= (1U << phy->id); 109 port->phy_mask |= (1U << phy->id);
110 110
111 if (!port->phy)
112 port->phy = phy->phy;
113
114 if (*(u64 *)port->attached_sas_addr == 0) { 111 if (*(u64 *)port->attached_sas_addr == 0) {
115 port->class = phy->class; 112 port->class = phy->class;
116 memcpy(port->attached_sas_addr, phy->attached_sas_addr, 113 memcpy(port->attached_sas_addr, phy->attached_sas_addr,
@@ -175,8 +172,10 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone)
175 sas_unregister_domain_devices(port); 172 sas_unregister_domain_devices(port);
176 sas_port_delete(port->port); 173 sas_port_delete(port->port);
177 port->port = NULL; 174 port->port = NULL;
178 } else 175 } else {
179 sas_port_delete_phy(port->port, phy->phy); 176 sas_port_delete_phy(port->port, phy->phy);
177 sas_device_set_phy(dev, port->port);
178 }
180 179
181 if (si->dft->lldd_port_deformed) 180 if (si->dft->lldd_port_deformed)
182 si->dft->lldd_port_deformed(phy); 181 si->dft->lldd_port_deformed(phy);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 5cc44fddfe95..94ef76316c31 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -439,30 +439,26 @@ static int sas_recover_I_T(struct domain_device *dev)
439 return res; 439 return res;
440} 440}
441 441
442/* Find the sas_phy that's attached to this device */ 442/* take a reference on the last known good phy for this device */
443struct sas_phy *sas_find_local_phy(struct domain_device *dev) 443struct sas_phy *sas_get_local_phy(struct domain_device *dev)
444{ 444{
445 struct domain_device *pdev = dev->parent; 445 struct sas_ha_struct *ha = dev->port->ha;
446 struct ex_phy *exphy = NULL; 446 struct sas_phy *phy;
447 int i; 447 unsigned long flags;
448 448
449 /* Directly attached device */ 449 /* a published domain device always has a valid phy, it may be
450 if (!pdev) 450 * stale, but it is never NULL
451 return dev->port->phy; 451 */
452 BUG_ON(!dev->phy);
452 453
453 /* Otherwise look in the expander */ 454 spin_lock_irqsave(&ha->phy_port_lock, flags);
454 for (i = 0; i < pdev->ex_dev.num_phys; i++) 455 phy = dev->phy;
455 if (!memcmp(dev->sas_addr, 456 get_device(&phy->dev);
456 pdev->ex_dev.ex_phy[i].attached_sas_addr, 457 spin_unlock_irqrestore(&ha->phy_port_lock, flags);
457 SAS_ADDR_SIZE)) {
458 exphy = &pdev->ex_dev.ex_phy[i];
459 break;
460 }
461 458
462 BUG_ON(!exphy); 459 return phy;
463 return exphy->phy;
464} 460}
465EXPORT_SYMBOL_GPL(sas_find_local_phy); 461EXPORT_SYMBOL_GPL(sas_get_local_phy);
466 462
467/* Attempt to send a LUN reset message to a device */ 463/* Attempt to send a LUN reset message to a device */
468int sas_eh_device_reset_handler(struct scsi_cmnd *cmd) 464int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
@@ -489,7 +485,7 @@ int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
489int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd) 485int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
490{ 486{
491 struct domain_device *dev = cmd_to_domain_dev(cmd); 487 struct domain_device *dev = cmd_to_domain_dev(cmd);
492 struct sas_phy *phy = sas_find_local_phy(dev); 488 struct sas_phy *phy = sas_get_local_phy(dev);
493 int res; 489 int res;
494 490
495 res = sas_phy_reset(phy, 1); 491 res = sas_phy_reset(phy, 1);
@@ -497,6 +493,8 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
497 SAS_DPRINTK("Bus reset of %s failed 0x%x\n", 493 SAS_DPRINTK("Bus reset of %s failed 0x%x\n",
498 kobject_name(&phy->dev.kobj), 494 kobject_name(&phy->dev.kobj),
499 res); 495 res);
496 sas_put_local_phy(phy);
497
500 if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) 498 if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE)
501 return SUCCESS; 499 return SUCCESS;
502 500