diff options
-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; |