aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/scsi/aic94xx/aic94xx_tmf.c9
-rw-r--r--drivers/scsi/isci/task.c9
-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
-rw-r--r--drivers/scsi/mvsas/mv_sas.c3
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c19
-rw-r--r--drivers/scsi/scsi_transport_sas.c23
-rw-r--r--include/scsi/libsas.h9
-rw-r--r--include/scsi/scsi_transport_sas.h6
13 files changed, 116 insertions, 44 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
index 0add73bdf2a4..50b914ffab94 100644
--- a/drivers/scsi/aic94xx/aic94xx_tmf.c
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -181,7 +181,7 @@ static int asd_clear_nexus_I_T(struct domain_device *dev,
181int asd_I_T_nexus_reset(struct domain_device *dev) 181int asd_I_T_nexus_reset(struct domain_device *dev)
182{ 182{
183 int res, tmp_res, i; 183 int res, tmp_res, i;
184 struct sas_phy *phy = sas_find_local_phy(dev); 184 struct sas_phy *phy = sas_get_local_phy(dev);
185 /* Standard mandates link reset for ATA (type 0) and 185 /* Standard mandates link reset for ATA (type 0) and
186 * hard reset for SSP (type 1) */ 186 * hard reset for SSP (type 1) */
187 int reset_type = (dev->dev_type == SATA_DEV || 187 int reset_type = (dev->dev_type == SATA_DEV ||
@@ -201,7 +201,7 @@ int asd_I_T_nexus_reset(struct domain_device *dev)
201 for (i = 0 ; i < 3; i++) { 201 for (i = 0 ; i < 3; i++) {
202 tmp_res = asd_clear_nexus_I_T(dev, NEXUS_PHASE_RESUME); 202 tmp_res = asd_clear_nexus_I_T(dev, NEXUS_PHASE_RESUME);
203 if (tmp_res == TC_RESUME) 203 if (tmp_res == TC_RESUME)
204 return res; 204 goto out;
205 msleep(500); 205 msleep(500);
206 } 206 }
207 207
@@ -211,7 +211,10 @@ int asd_I_T_nexus_reset(struct domain_device *dev)
211 dev_printk(KERN_ERR, &phy->dev, 211 dev_printk(KERN_ERR, &phy->dev,
212 "Failed to resume nexus after reset 0x%x\n", tmp_res); 212 "Failed to resume nexus after reset 0x%x\n", tmp_res);
213 213
214 return TMF_RESP_FUNC_FAILED; 214 res = TMF_RESP_FUNC_FAILED;
215 out:
216 sas_put_local_phy(phy);
217 return res;
215} 218}
216 219
217static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun) 220static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 4bd88ef83cdf..b96e6044eda9 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -1332,7 +1332,7 @@ isci_task_request_complete(struct isci_host *ihost,
1332static int isci_reset_device(struct isci_host *ihost, 1332static int isci_reset_device(struct isci_host *ihost,
1333 struct isci_remote_device *idev) 1333 struct isci_remote_device *idev)
1334{ 1334{
1335 struct sas_phy *phy = sas_find_local_phy(idev->domain_dev); 1335 struct sas_phy *phy = sas_get_local_phy(idev->domain_dev);
1336 enum sci_status status; 1336 enum sci_status status;
1337 unsigned long flags; 1337 unsigned long flags;
1338 int rc; 1338 int rc;
@@ -1347,8 +1347,8 @@ static int isci_reset_device(struct isci_host *ihost,
1347 dev_dbg(&ihost->pdev->dev, 1347 dev_dbg(&ihost->pdev->dev,
1348 "%s: sci_remote_device_reset(%p) returned %d!\n", 1348 "%s: sci_remote_device_reset(%p) returned %d!\n",
1349 __func__, idev, status); 1349 __func__, idev, status);
1350 1350 rc = TMF_RESP_FUNC_FAILED;
1351 return TMF_RESP_FUNC_FAILED; 1351 goto out;
1352 } 1352 }
1353 spin_unlock_irqrestore(&ihost->scic_lock, flags); 1353 spin_unlock_irqrestore(&ihost->scic_lock, flags);
1354 1354
@@ -1369,7 +1369,8 @@ static int isci_reset_device(struct isci_host *ihost,
1369 } 1369 }
1370 1370
1371 dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__, idev); 1371 dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__, idev);
1372 1372 out:
1373 sas_put_local_phy(phy);
1373 return rc; 1374 return rc;
1374} 1375}
1375 1376
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
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index cd882230591f..b68a65390f0d 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -1474,10 +1474,11 @@ static int mvs_debug_issue_ssp_tmf(struct domain_device *dev,
1474static int mvs_debug_I_T_nexus_reset(struct domain_device *dev) 1474static int mvs_debug_I_T_nexus_reset(struct domain_device *dev)
1475{ 1475{
1476 int rc; 1476 int rc;
1477 struct sas_phy *phy = sas_find_local_phy(dev); 1477 struct sas_phy *phy = sas_get_local_phy(dev);
1478 int reset_type = (dev->dev_type == SATA_DEV || 1478 int reset_type = (dev->dev_type == SATA_DEV ||
1479 (dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1; 1479 (dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
1480 rc = sas_phy_reset(phy, reset_type); 1480 rc = sas_phy_reset(phy, reset_type);
1481 sas_put_local_phy(phy);
1481 msleep(2000); 1482 msleep(2000);
1482 return rc; 1483 return rc;
1483} 1484}
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index 310860e37d98..3b11edd4a50c 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -967,12 +967,14 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev)
967 967
968 pm8001_dev = dev->lldd_dev; 968 pm8001_dev = dev->lldd_dev;
969 pm8001_ha = pm8001_find_ha_by_dev(dev); 969 pm8001_ha = pm8001_find_ha_by_dev(dev);
970 phy = sas_find_local_phy(dev); 970 phy = sas_get_local_phy(dev);
971 971
972 if (dev_is_sata(dev)) { 972 if (dev_is_sata(dev)) {
973 DECLARE_COMPLETION_ONSTACK(completion_setstate); 973 DECLARE_COMPLETION_ONSTACK(completion_setstate);
974 if (scsi_is_sas_phy_local(phy)) 974 if (scsi_is_sas_phy_local(phy)) {
975 return 0; 975 rc = 0;
976 goto out;
977 }
976 rc = sas_phy_reset(phy, 1); 978 rc = sas_phy_reset(phy, 1);
977 msleep(2000); 979 msleep(2000);
978 rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , 980 rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
@@ -981,12 +983,14 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev)
981 rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha, 983 rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
982 pm8001_dev, 0x01); 984 pm8001_dev, 0x01);
983 wait_for_completion(&completion_setstate); 985 wait_for_completion(&completion_setstate);
984 } else{ 986 } else {
985 rc = sas_phy_reset(phy, 1); 987 rc = sas_phy_reset(phy, 1);
986 msleep(2000); 988 msleep(2000);
987 } 989 }
988 PM8001_EH_DBG(pm8001_ha, pm8001_printk(" for device[%x]:rc=%d\n", 990 PM8001_EH_DBG(pm8001_ha, pm8001_printk(" for device[%x]:rc=%d\n",
989 pm8001_dev->device_id, rc)); 991 pm8001_dev->device_id, rc));
992 out:
993 sas_put_local_phy(phy);
990 return rc; 994 return rc;
991} 995}
992 996
@@ -998,10 +1002,11 @@ int pm8001_lu_reset(struct domain_device *dev, u8 *lun)
998 struct pm8001_device *pm8001_dev = dev->lldd_dev; 1002 struct pm8001_device *pm8001_dev = dev->lldd_dev;
999 struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev); 1003 struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev);
1000 if (dev_is_sata(dev)) { 1004 if (dev_is_sata(dev)) {
1001 struct sas_phy *phy = sas_find_local_phy(dev); 1005 struct sas_phy *phy = sas_get_local_phy(dev);
1002 rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , 1006 rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
1003 dev, 1, 0); 1007 dev, 1, 0);
1004 rc = sas_phy_reset(phy, 1); 1008 rc = sas_phy_reset(phy, 1);
1009 sas_put_local_phy(phy);
1005 rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha, 1010 rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
1006 pm8001_dev, 0x01); 1011 pm8001_dev, 0x01);
1007 msleep(2000); 1012 msleep(2000);
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
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 2079b18467a1..55bab8633807 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -192,6 +192,7 @@ struct domain_device {
192 struct domain_device *parent; 192 struct domain_device *parent;
193 struct list_head siblings; /* devices on the same level */ 193 struct list_head siblings; /* devices on the same level */
194 struct asd_sas_port *port; /* shortcut to root of the tree */ 194 struct asd_sas_port *port; /* shortcut to root of the tree */
195 struct sas_phy *phy;
195 196
196 struct list_head dev_list_node; 197 struct list_head dev_list_node;
197 struct list_head disco_list_node; /* awaiting probe or destruct */ 198 struct list_head disco_list_node; /* awaiting probe or destruct */
@@ -243,7 +244,6 @@ struct asd_sas_port {
243 struct list_head destroy_list; 244 struct list_head destroy_list;
244 enum sas_linkrate linkrate; 245 enum sas_linkrate linkrate;
245 246
246 struct sas_phy *phy;
247 struct work_struct work; 247 struct work_struct work;
248 248
249/* public: */ 249/* public: */
@@ -429,6 +429,11 @@ static inline unsigned int to_sas_gpio_od(int device, int bit)
429 return 3 * device + bit; 429 return 3 * device + bit;
430} 430}
431 431
432static inline void sas_put_local_phy(struct sas_phy *phy)
433{
434 put_device(&phy->dev);
435}
436
432#ifdef CONFIG_SCSI_SAS_HOST_SMP 437#ifdef CONFIG_SCSI_SAS_HOST_SMP
433int try_test_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8 count); 438int try_test_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8 count);
434#else 439#else
@@ -684,7 +689,7 @@ extern int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
684 689
685extern void sas_ssp_task_response(struct device *dev, struct sas_task *task, 690extern void sas_ssp_task_response(struct device *dev, struct sas_task *task,
686 struct ssp_response_iu *iu); 691 struct ssp_response_iu *iu);
687struct sas_phy *sas_find_local_phy(struct domain_device *dev); 692struct sas_phy *sas_get_local_phy(struct domain_device *dev);
688 693
689int sas_request_addr(struct Scsi_Host *shost, u8 *addr); 694int sas_request_addr(struct Scsi_Host *shost, u8 *addr);
690 695
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
index 42817facaeda..98b3a20a0102 100644
--- a/include/scsi/scsi_transport_sas.h
+++ b/include/scsi/scsi_transport_sas.h
@@ -209,6 +209,12 @@ void sas_port_add_phy(struct sas_port *, struct sas_phy *);
209void sas_port_delete_phy(struct sas_port *, struct sas_phy *); 209void sas_port_delete_phy(struct sas_port *, struct sas_phy *);
210void sas_port_mark_backlink(struct sas_port *); 210void sas_port_mark_backlink(struct sas_port *);
211int scsi_is_sas_port(const struct device *); 211int scsi_is_sas_port(const struct device *);
212struct sas_phy *sas_port_get_phy(struct sas_port *port);
213static inline void sas_port_put_phy(struct sas_phy *phy)
214{
215 if (phy)
216 put_device(&phy->dev);
217}
212 218
213extern struct scsi_transport_template * 219extern struct scsi_transport_template *
214sas_attach_transport(struct sas_function_template *); 220sas_attach_transport(struct sas_function_template *);