diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-11-30 14:57:34 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-29 16:11:54 -0500 |
commit | 9277699121b81891e303ada0a53fa1d04b7ffe72 (patch) | |
tree | ed8fde54c953025be2a59697dd912f581536c782 | |
parent | fca4ecbdc440337b3c257b38c2f4cc8d0ca0286c (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.c | 31 | ||||
-rw-r--r-- | drivers/scsi/isci/port.h | 3 | ||||
-rw-r--r-- | drivers/scsi/isci/task.c | 24 |
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, | |||
305 | static void isci_port_hard_reset_complete(struct isci_port *isci_port, | 305 | static 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 | ||
1616 | static 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 | |||
1613 | int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport, | 1621 | int 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 | ||
1332 | static int isci_reset_device(struct isci_host *ihost, | 1332 | static 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; |