aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorMarcin Tomczak <marcin.tomczak@intel.com>2012-01-04 04:33:31 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-01-16 02:46:59 -0500
commitbe778341812dc75b1c515fab6ebd39c0daf1e2bc (patch)
treef690ff71352d7b0447c7e97e3d1eee929115819c /drivers/scsi
parent472d4d2cfbc169f3868a5f63ce727a482a2fd487 (diff)
[SCSI] isci: fix io failures while wide port links are coming up
When the first phy of a wide port comes up, don't report the port ready yet, always wait for 250 miliseconds then config the port with all phys added to the port. So that we can avoid reporting wide port device too early to kernel, which caused the first IOs (report luns, inquirys) failed due to not all the phys are configured into its port. Changes also made that the phys in a wide port don't need to go through half second wait time for consuming power. Signed-off-by: Marcin Tomczak <marcin.tomczak@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/isci/host.c59
-rw-r--r--drivers/scsi/isci/port_config.c33
2 files changed, 76 insertions, 16 deletions
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 7e4d709dc201..1a65d6514237 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -899,7 +899,8 @@ static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost)
899 */ 899 */
900 if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) || 900 if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) ||
901 (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) || 901 (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) ||
902 (iphy->is_in_link_training == true && is_phy_starting(iphy))) { 902 (iphy->is_in_link_training == true && is_phy_starting(iphy)) ||
903 (ihost->port_agent.phy_ready_mask != ihost->port_agent.phy_configured_mask)) {
903 is_controller_start_complete = false; 904 is_controller_start_complete = false;
904 break; 905 break;
905 } 906 }
@@ -1904,6 +1905,31 @@ static void power_control_timeout(unsigned long data)
1904 ihost->power_control.phys_waiting--; 1905 ihost->power_control.phys_waiting--;
1905 ihost->power_control.phys_granted_power++; 1906 ihost->power_control.phys_granted_power++;
1906 sci_phy_consume_power_handler(iphy); 1907 sci_phy_consume_power_handler(iphy);
1908
1909 if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) {
1910 u8 j;
1911
1912 for (j = 0; j < SCI_MAX_PHYS; j++) {
1913 struct isci_phy *requester = ihost->power_control.requesters[j];
1914
1915 /*
1916 * Search the power_control queue to see if there are other phys
1917 * attached to the same remote device. If found, take all of
1918 * them out of await_sas_power state.
1919 */
1920 if (requester != NULL && requester != iphy) {
1921 u8 other = memcmp(requester->frame_rcvd.iaf.sas_addr,
1922 iphy->frame_rcvd.iaf.sas_addr,
1923 sizeof(requester->frame_rcvd.iaf.sas_addr));
1924
1925 if (other == 0) {
1926 ihost->power_control.requesters[j] = NULL;
1927 ihost->power_control.phys_waiting--;
1928 sci_phy_consume_power_handler(requester);
1929 }
1930 }
1931 }
1932 }
1907 } 1933 }
1908 1934
1909 /* 1935 /*
@@ -1938,9 +1964,34 @@ void sci_controller_power_control_queue_insert(struct isci_host *ihost,
1938 ihost->power_control.timer_started = true; 1964 ihost->power_control.timer_started = true;
1939 1965
1940 } else { 1966 } else {
1941 /* Add the phy in the waiting list */ 1967 /*
1942 ihost->power_control.requesters[iphy->phy_index] = iphy; 1968 * There are phys, attached to the same sas address as this phy, are
1943 ihost->power_control.phys_waiting++; 1969 * already in READY state, this phy don't need wait.
1970 */
1971 u8 i;
1972 struct isci_phy *current_phy;
1973
1974 for (i = 0; i < SCI_MAX_PHYS; i++) {
1975 u8 other;
1976 current_phy = &ihost->phys[i];
1977
1978 other = memcmp(current_phy->frame_rcvd.iaf.sas_addr,
1979 iphy->frame_rcvd.iaf.sas_addr,
1980 sizeof(current_phy->frame_rcvd.iaf.sas_addr));
1981
1982 if (current_phy->sm.current_state_id == SCI_PHY_READY &&
1983 current_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS &&
1984 other == 0) {
1985 sci_phy_consume_power_handler(iphy);
1986 break;
1987 }
1988 }
1989
1990 if (i == SCI_MAX_PHYS) {
1991 /* Add the phy in the waiting list */
1992 ihost->power_control.requesters[iphy->phy_index] = iphy;
1993 ihost->power_control.phys_waiting++;
1994 }
1944 } 1995 }
1945} 1996}
1946 1997
diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c
index 37d15d3165da..6d1e9544cbe5 100644
--- a/drivers/scsi/isci/port_config.c
+++ b/drivers/scsi/isci/port_config.c
@@ -466,6 +466,23 @@ sci_apc_agent_validate_phy_configuration(struct isci_host *ihost,
466 return sci_port_configuration_agent_validate_ports(ihost, port_agent); 466 return sci_port_configuration_agent_validate_ports(ihost, port_agent);
467} 467}
468 468
469/*
470 * This routine will restart the automatic port configuration timeout
471 * timer for the next time period. This could be caused by either a link
472 * down event or a link up event where we can not yet tell to which a phy
473 * belongs.
474 */
475static void sci_apc_agent_start_timer(
476 struct sci_port_configuration_agent *port_agent,
477 u32 timeout)
478{
479 if (port_agent->timer_pending)
480 sci_del_timer(&port_agent->timer);
481
482 port_agent->timer_pending = true;
483 sci_mod_timer(&port_agent->timer, timeout);
484}
485
469static void sci_apc_agent_configure_ports(struct isci_host *ihost, 486static void sci_apc_agent_configure_ports(struct isci_host *ihost,
470 struct sci_port_configuration_agent *port_agent, 487 struct sci_port_configuration_agent *port_agent,
471 struct isci_phy *iphy, 488 struct isci_phy *iphy,
@@ -565,17 +582,8 @@ static void sci_apc_agent_configure_ports(struct isci_host *ihost,
565 break; 582 break;
566 583
567 case SCIC_SDS_APC_START_TIMER: 584 case SCIC_SDS_APC_START_TIMER:
568 /* 585 sci_apc_agent_start_timer(port_agent,
569 * This can occur for either a link down event, or a link 586 SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION);
570 * up event where we cannot yet tell the port to which a
571 * phy belongs.
572 */
573 if (port_agent->timer_pending)
574 sci_del_timer(&port_agent->timer);
575
576 port_agent->timer_pending = true;
577 sci_mod_timer(&port_agent->timer,
578 SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION);
579 break; 587 break;
580 588
581 case SCIC_SDS_APC_SKIP_PHY: 589 case SCIC_SDS_APC_SKIP_PHY:
@@ -607,7 +615,8 @@ static void sci_apc_agent_link_up(struct isci_host *ihost,
607 if (!iport) { 615 if (!iport) {
608 /* the phy is not the part of this port */ 616 /* the phy is not the part of this port */
609 port_agent->phy_ready_mask |= 1 << phy_index; 617 port_agent->phy_ready_mask |= 1 << phy_index;
610 sci_apc_agent_configure_ports(ihost, port_agent, iphy, true); 618 sci_apc_agent_start_timer(port_agent,
619 SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION);
611 } else { 620 } else {
612 /* the phy is already the part of the port */ 621 /* the phy is already the part of the port */
613 u32 port_state = iport->sm.current_state_id; 622 u32 port_state = iport->sm.current_state_id;