diff options
-rw-r--r-- | drivers/scsi/isci/host.c | 59 | ||||
-rw-r--r-- | drivers/scsi/isci/port_config.c | 33 |
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 | */ | ||
475 | static 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 | |||
469 | static void sci_apc_agent_configure_ports(struct isci_host *ihost, | 486 | static 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; |