aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-11-30 14:57:34 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-29 16:11:54 -0500
commit9277699121b81891e303ada0a53fa1d04b7ffe72 (patch)
treeed8fde54c953025be2a59697dd912f581536c782
parentfca4ecbdc440337b3c257b38c2f4cc8d0ca0286c (diff)
[SCSI] isci: fix interpretation of "hard" reset
A hard reset to isci in the direct-attached case is one where the driver internally manages debouncing the link. In the sas-expander-attached case a hard reset is one that clears affiliations. The driver should not be prematurely dropping affiliations at run time, that decision (to force expander hard resets to ata devices) is left to userspace to manage. So, arrange for I_T_nexus resets to be sas-link-resets in the expander-attached case and isci-hard-resets in the direct-attached case. Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r--drivers/scsi/isci/port.c31
-rw-r--r--drivers/scsi/isci/port.h3
-rw-r--r--drivers/scsi/isci/task.c24
3 files changed, 37 insertions, 21 deletions
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index f9d20c1e63ca..e55ef65f5212 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -305,7 +305,9 @@ static void port_state_machine_change(struct isci_port *iport,
305static void isci_port_hard_reset_complete(struct isci_port *isci_port, 305static void isci_port_hard_reset_complete(struct isci_port *isci_port,
306 enum sci_status completion_status) 306 enum sci_status completion_status)
307{ 307{
308 dev_dbg(&isci_port->isci_host->pdev->dev, 308 struct isci_host *ihost = isci_port->owning_controller;
309
310 dev_dbg(&ihost->pdev->dev,
309 "%s: isci_port = %p, completion_status=%x\n", 311 "%s: isci_port = %p, completion_status=%x\n",
310 __func__, isci_port, completion_status); 312 __func__, isci_port, completion_status);
311 313
@@ -316,23 +318,24 @@ static void isci_port_hard_reset_complete(struct isci_port *isci_port,
316 318
317 /* The reset failed. The port state is now SCI_PORT_FAILED. */ 319 /* The reset failed. The port state is now SCI_PORT_FAILED. */
318 if (isci_port->active_phy_mask == 0) { 320 if (isci_port->active_phy_mask == 0) {
321 int phy_idx = isci_port->last_active_phy;
322 struct isci_phy *iphy = &ihost->phys[phy_idx];
319 323
320 /* Generate the link down now to the host, since it 324 /* Generate the link down now to the host, since it
321 * was intercepted by the hard reset state machine when 325 * was intercepted by the hard reset state machine when
322 * it really happened. 326 * it really happened.
323 */ 327 */
324 isci_port_link_down(isci_port->isci_host, 328 isci_port_link_down(ihost, iphy, isci_port);
325 &isci_port->isci_host->phys[
326 isci_port->last_active_phy],
327 isci_port);
328 } 329 }
329 /* Advance the port state so that link state changes will be 330 /* Advance the port state so that link state changes will be
330 * noticed. 331 * noticed.
331 */ 332 */
332 port_state_machine_change(isci_port, SCI_PORT_SUB_WAITING); 333 port_state_machine_change(isci_port, SCI_PORT_SUB_WAITING);
333 334
334 } 335 }
335 complete_all(&isci_port->hard_reset_complete); 336 clear_bit(IPORT_RESET_PENDING, &isci_port->state);
337 wake_up(&ihost->eventq);
338
336} 339}
337 340
338/* This method will return a true value if the specified phy can be assigned to 341/* This method will return a true value if the specified phy can be assigned to
@@ -1610,6 +1613,11 @@ void sci_port_broadcast_change_received(struct isci_port *iport, struct isci_phy
1610 isci_port_bc_change_received(ihost, iport, iphy); 1613 isci_port_bc_change_received(ihost, iport, iphy);
1611} 1614}
1612 1615
1616static void wait_port_reset(struct isci_host *ihost, struct isci_port *iport)
1617{
1618 wait_event(ihost->eventq, !test_bit(IPORT_RESET_PENDING, &iport->state));
1619}
1620
1613int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport, 1621int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport,
1614 struct isci_phy *iphy) 1622 struct isci_phy *iphy)
1615{ 1623{
@@ -1620,9 +1628,8 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor
1620 dev_dbg(&ihost->pdev->dev, "%s: iport = %p\n", 1628 dev_dbg(&ihost->pdev->dev, "%s: iport = %p\n",
1621 __func__, iport); 1629 __func__, iport);
1622 1630
1623 init_completion(&iport->hard_reset_complete);
1624
1625 spin_lock_irqsave(&ihost->scic_lock, flags); 1631 spin_lock_irqsave(&ihost->scic_lock, flags);
1632 set_bit(IPORT_RESET_PENDING, &iport->state);
1626 1633
1627 #define ISCI_PORT_RESET_TIMEOUT SCIC_SDS_SIGNATURE_FIS_TIMEOUT 1634 #define ISCI_PORT_RESET_TIMEOUT SCIC_SDS_SIGNATURE_FIS_TIMEOUT
1628 status = sci_port_hard_reset(iport, ISCI_PORT_RESET_TIMEOUT); 1635 status = sci_port_hard_reset(iport, ISCI_PORT_RESET_TIMEOUT);
@@ -1630,7 +1637,7 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor
1630 spin_unlock_irqrestore(&ihost->scic_lock, flags); 1637 spin_unlock_irqrestore(&ihost->scic_lock, flags);
1631 1638
1632 if (status == SCI_SUCCESS) { 1639 if (status == SCI_SUCCESS) {
1633 wait_for_completion(&iport->hard_reset_complete); 1640 wait_port_reset(ihost, iport);
1634 1641
1635 dev_dbg(&ihost->pdev->dev, 1642 dev_dbg(&ihost->pdev->dev,
1636 "%s: iport = %p; hard reset completion\n", 1643 "%s: iport = %p; hard reset completion\n",
@@ -1644,6 +1651,8 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor
1644 __func__, iport, iport->hard_reset_status); 1651 __func__, iport, iport->hard_reset_status);
1645 } 1652 }
1646 } else { 1653 } else {
1654 clear_bit(IPORT_RESET_PENDING, &iport->state);
1655 wake_up(&ihost->eventq);
1647 ret = TMF_RESP_FUNC_FAILED; 1656 ret = TMF_RESP_FUNC_FAILED;
1648 1657
1649 dev_err(&ihost->pdev->dev, 1658 dev_err(&ihost->pdev->dev,
diff --git a/drivers/scsi/isci/port.h b/drivers/scsi/isci/port.h
index 265972939e3a..a0dcdaeac3b2 100644
--- a/drivers/scsi/isci/port.h
+++ b/drivers/scsi/isci/port.h
@@ -98,7 +98,8 @@ struct isci_port {
98 struct isci_host *isci_host; 98 struct isci_host *isci_host;
99 struct list_head remote_dev_list; 99 struct list_head remote_dev_list;
100 struct list_head domain_dev_list; 100 struct list_head domain_dev_list;
101 struct completion hard_reset_complete; 101 #define IPORT_RESET_PENDING 0
102 unsigned long state;
102 enum sci_status hard_reset_status; 103 enum sci_status hard_reset_status;
103 struct sci_base_state_machine sm; 104 struct sci_base_state_machine sm;
104 bool ready_exit; 105 bool ready_exit;
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index b96e6044eda9..c4d324ccee11 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -1330,29 +1330,35 @@ isci_task_request_complete(struct isci_host *ihost,
1330} 1330}
1331 1331
1332static int isci_reset_device(struct isci_host *ihost, 1332static int isci_reset_device(struct isci_host *ihost,
1333 struct domain_device *dev,
1333 struct isci_remote_device *idev) 1334 struct isci_remote_device *idev)
1334{ 1335{
1335 struct sas_phy *phy = sas_get_local_phy(idev->domain_dev);
1336 enum sci_status status;
1337 unsigned long flags;
1338 int rc; 1336 int rc;
1337 unsigned long flags;
1338 enum sci_status status;
1339 struct sas_phy *phy = sas_get_local_phy(dev);
1340 struct isci_port *iport = dev->port->lldd_port;
1339 1341
1340 dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev); 1342 dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev);
1341 1343
1342 spin_lock_irqsave(&ihost->scic_lock, flags); 1344 spin_lock_irqsave(&ihost->scic_lock, flags);
1343 status = sci_remote_device_reset(idev); 1345 status = sci_remote_device_reset(idev);
1344 if (status != SCI_SUCCESS) { 1346 spin_unlock_irqrestore(&ihost->scic_lock, flags);
1345 spin_unlock_irqrestore(&ihost->scic_lock, flags);
1346 1347
1348 if (status != SCI_SUCCESS) {
1347 dev_dbg(&ihost->pdev->dev, 1349 dev_dbg(&ihost->pdev->dev,
1348 "%s: sci_remote_device_reset(%p) returned %d!\n", 1350 "%s: sci_remote_device_reset(%p) returned %d!\n",
1349 __func__, idev, status); 1351 __func__, idev, status);
1350 rc = TMF_RESP_FUNC_FAILED; 1352 rc = TMF_RESP_FUNC_FAILED;
1351 goto out; 1353 goto out;
1352 } 1354 }
1353 spin_unlock_irqrestore(&ihost->scic_lock, flags);
1354 1355
1355 rc = sas_phy_reset(phy, true); 1356 if (scsi_is_sas_phy_local(phy)) {
1357 struct isci_phy *iphy = &ihost->phys[phy->number];
1358
1359 rc = isci_port_perform_hard_reset(ihost, iport, iphy);
1360 } else
1361 rc = sas_phy_reset(phy, !dev_is_sata(dev));
1356 1362
1357 /* Terminate in-progress I/O now. */ 1363 /* Terminate in-progress I/O now. */
1358 isci_remote_device_nuke_requests(ihost, idev); 1364 isci_remote_device_nuke_requests(ihost, idev);
@@ -1390,7 +1396,7 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev)
1390 goto out; 1396 goto out;
1391 } 1397 }
1392 1398
1393 ret = isci_reset_device(ihost, idev); 1399 ret = isci_reset_device(ihost, dev, idev);
1394 out: 1400 out:
1395 isci_put_device(idev); 1401 isci_put_device(idev);
1396 return ret; 1402 return ret;
@@ -1413,7 +1419,7 @@ int isci_bus_reset_handler(struct scsi_cmnd *cmd)
1413 goto out; 1419 goto out;
1414 } 1420 }
1415 1421
1416 ret = isci_reset_device(ihost, idev); 1422 ret = isci_reset_device(ihost, dev, idev);
1417 out: 1423 out:
1418 isci_put_device(idev); 1424 isci_put_device(idev);
1419 return ret; 1425 return ret;