aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci
diff options
context:
space:
mode:
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>2012-03-09 01:41:48 -0500
committerDan Williams <dan.j.williams@intel.com>2012-05-17 17:33:36 -0400
commit6f48844e3f16b7d8a1f9a1a11bd9a11089a5292f (patch)
treeaeb95746d05e7bab2b33a9351443e03152e4dfa4 /drivers/scsi/isci
parentfc25f79af321c01a739150ba2c09435cf977a63d (diff)
isci: Manage the link layer hang detect timer for RNC suspensions.
For STP devices under certain protocol conditions, an RNC will not suspend until the current transfer state is broken with a SYNC/ESC sequence from the SCU. The SYNC/ESC driven by expiration of the SCU link layer hang detect timer, which has too small a dynamic range to support slow SATA devices, so normally it is disabled. This change enables the timer with the minimum period at the point when the suspension is requested. Note that there is potential collateral damage to other open connections to slow SATA devices on the same port, since there is no alternative but to enable the LLHANG timer on every phy in the port for the current suspension request - there is no way to tell on which phy the RNC in question is currently active. Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci')
-rw-r--r--drivers/scsi/isci/port.c26
-rw-r--r--drivers/scsi/isci/port.h5
-rw-r--r--drivers/scsi/isci/remote_device.h7
-rw-r--r--drivers/scsi/isci/remote_node_context.c15
4 files changed, 51 insertions, 2 deletions
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index 0a3aec118097..ed206c5a00a6 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -1548,6 +1548,29 @@ static void sci_port_failed_state_enter(struct sci_base_state_machine *sm)
1548 isci_port_hard_reset_complete(iport, SCI_FAILURE_TIMEOUT); 1548 isci_port_hard_reset_complete(iport, SCI_FAILURE_TIMEOUT);
1549} 1549}
1550 1550
1551void sci_port_set_hang_detection_timeout(struct isci_port *iport, u32 timeout)
1552{
1553 int phy_index;
1554 u32 phy_mask = iport->active_phy_mask;
1555
1556 if (timeout)
1557 ++iport->hang_detect_users;
1558 else if (iport->hang_detect_users > 1)
1559 --iport->hang_detect_users;
1560 else
1561 iport->hang_detect_users = 0;
1562
1563 if (timeout || (iport->hang_detect_users == 0)) {
1564 for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) {
1565 if ((phy_mask >> phy_index) & 1) {
1566 writel(timeout,
1567 &iport->phy_table[phy_index]
1568 ->link_layer_registers
1569 ->link_layer_hang_detection_timeout);
1570 }
1571 }
1572 }
1573}
1551/* --------------------------------------------------------------------------- */ 1574/* --------------------------------------------------------------------------- */
1552 1575
1553static const struct sci_base_state sci_port_state_table[] = { 1576static const struct sci_base_state sci_port_state_table[] = {
@@ -1596,6 +1619,7 @@ void sci_port_construct(struct isci_port *iport, u8 index,
1596 1619
1597 iport->started_request_count = 0; 1620 iport->started_request_count = 0;
1598 iport->assigned_device_count = 0; 1621 iport->assigned_device_count = 0;
1622 iport->hang_detect_users = 0;
1599 1623
1600 iport->reserved_rni = SCU_DUMMY_INDEX; 1624 iport->reserved_rni = SCU_DUMMY_INDEX;
1601 iport->reserved_tag = SCI_CONTROLLER_INVALID_IO_TAG; 1625 iport->reserved_tag = SCI_CONTROLLER_INVALID_IO_TAG;
@@ -1733,7 +1757,7 @@ void isci_port_formed(struct asd_sas_phy *phy)
1733 struct isci_host *ihost = phy->ha->lldd_ha; 1757 struct isci_host *ihost = phy->ha->lldd_ha;
1734 struct isci_phy *iphy = to_iphy(phy); 1758 struct isci_phy *iphy = to_iphy(phy);
1735 struct asd_sas_port *port = phy->port; 1759 struct asd_sas_port *port = phy->port;
1736 struct isci_port *iport; 1760 struct isci_port *iport = NULL;
1737 unsigned long flags; 1761 unsigned long flags;
1738 int i; 1762 int i;
1739 1763
diff --git a/drivers/scsi/isci/port.h b/drivers/scsi/isci/port.h
index f8bd1e8dbfea..861e8f72811b 100644
--- a/drivers/scsi/isci/port.h
+++ b/drivers/scsi/isci/port.h
@@ -111,6 +111,7 @@ struct isci_port {
111 u16 reserved_tag; 111 u16 reserved_tag;
112 u32 started_request_count; 112 u32 started_request_count;
113 u32 assigned_device_count; 113 u32 assigned_device_count;
114 u32 hang_detect_users;
114 u32 not_ready_reason; 115 u32 not_ready_reason;
115 struct isci_phy *phy_table[SCI_MAX_PHYS]; 116 struct isci_phy *phy_table[SCI_MAX_PHYS];
116 struct isci_host *owning_controller; 117 struct isci_host *owning_controller;
@@ -269,6 +270,10 @@ void sci_port_get_attached_sas_address(
269 struct isci_port *iport, 270 struct isci_port *iport,
270 struct sci_sas_address *sas_address); 271 struct sci_sas_address *sas_address);
271 272
273void sci_port_set_hang_detection_timeout(
274 struct isci_port *isci_port,
275 u32 timeout);
276
272void isci_port_formed(struct asd_sas_phy *); 277void isci_port_formed(struct asd_sas_phy *);
273void isci_port_deformed(struct asd_sas_phy *); 278void isci_port_deformed(struct asd_sas_phy *);
274 279
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 4a67ff0eb94e..4850b58edbe6 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -301,6 +301,13 @@ static inline void sci_remote_device_decrement_request_count(struct isci_remote_
301 idev->started_request_count--; 301 idev->started_request_count--;
302} 302}
303 303
304static inline void isci_dev_set_hang_detection_timeout(
305 struct isci_remote_device *idev,
306 u32 timeout)
307{
308 sci_port_set_hang_detection_timeout(idev->owning_port, timeout);
309}
310
304enum sci_status sci_remote_device_frame_handler( 311enum sci_status sci_remote_device_frame_handler(
305 struct isci_remote_device *idev, 312 struct isci_remote_device *idev,
306 u32 frame_index); 313 u32 frame_index);
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 8ce5a35891e1..3a55ba66b8ac 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -316,6 +316,15 @@ static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_
316 sci_remote_node_context_continue_state_transitions(rnc); 316 sci_remote_node_context_continue_state_transitions(rnc);
317} 317}
318 318
319static void sci_remote_node_context_await_suspend_state_exit(
320 struct sci_base_state_machine *sm)
321{
322 struct sci_remote_node_context *rnc
323 = container_of(sm, typeof(*rnc), sm);
324
325 isci_dev_set_hang_detection_timeout(rnc_to_dev(rnc), 0);
326}
327
319static const struct sci_base_state sci_remote_node_context_state_table[] = { 328static const struct sci_base_state sci_remote_node_context_state_table[] = {
320 [SCI_RNC_INITIAL] = { 329 [SCI_RNC_INITIAL] = {
321 .enter_state = sci_remote_node_context_initial_state_enter, 330 .enter_state = sci_remote_node_context_initial_state_enter,
@@ -338,7 +347,9 @@ static const struct sci_base_state sci_remote_node_context_state_table[] = {
338 [SCI_RNC_TX_RX_SUSPENDED] = { 347 [SCI_RNC_TX_RX_SUSPENDED] = {
339 .enter_state = sci_remote_node_context_tx_rx_suspended_state_enter, 348 .enter_state = sci_remote_node_context_tx_rx_suspended_state_enter,
340 }, 349 },
341 [SCI_RNC_AWAIT_SUSPENSION] = { }, 350 [SCI_RNC_AWAIT_SUSPENSION] = {
351 .exit_state = sci_remote_node_context_await_suspend_state_exit,
352 },
342}; 353};
343 354
344void sci_remote_node_context_construct(struct sci_remote_node_context *rnc, 355void sci_remote_node_context_construct(struct sci_remote_node_context *rnc,
@@ -513,6 +524,8 @@ enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *
513 if (suspend_type == SCI_SOFTWARE_SUSPENSION) { 524 if (suspend_type == SCI_SOFTWARE_SUSPENSION) {
514 sci_remote_device_post_request(rnc_to_dev(sci_rnc), 525 sci_remote_device_post_request(rnc_to_dev(sci_rnc),
515 SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX); 526 SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX);
527 isci_dev_set_hang_detection_timeout(rnc_to_dev(sci_rnc),
528 0x00000001);
516 } 529 }
517 530
518 sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION); 531 sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION);