aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci/host.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2012-02-29 04:07:56 -0500
committerDan Williams <dan.j.williams@intel.com>2012-05-17 15:27:12 -0400
commit50a92d93148ec073efd2456b007e04ecae452086 (patch)
tree1a81ac87e301bdb7bd809daea52bd7be0b3b21b4 /drivers/scsi/isci/host.c
parenteb608c3cb3f0a6b99252ea6a69fc0d2bbecf1f4f (diff)
isci: fix 'link-up' events occur after 'start-complete'
The call to wait_for_start() is meant to ensure that all links have been given a chance to come up before letting the kernel proceed with probing. However, the implementation is not correctly syncing with the port configuration agent. In the MPC case the ports are hard-coded, in the APC case we need to wait for the port-configuration to form ports from the started phys. Towards that end increase the timeout for the APC agent to form ports, and delay start complete until all phys are out of link-training. Cc: <stable@vger.kernel.org> Cc: Richard Boyd <richard.g.boyd@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci/host.c')
-rw-r--r--drivers/scsi/isci/host.c67
1 files changed, 36 insertions, 31 deletions
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 95c3da66ea4b..577a8369274c 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -816,7 +816,7 @@ static void sci_controller_initialize_unsolicited_frame_queue(struct isci_host *
816 &ihost->scu_registers->sdma.unsolicited_frame_put_pointer); 816 &ihost->scu_registers->sdma.unsolicited_frame_put_pointer);
817} 817}
818 818
819static void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status) 819void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status)
820{ 820{
821 if (ihost->sm.current_state_id == SCIC_STARTING) { 821 if (ihost->sm.current_state_id == SCIC_STARTING) {
822 /* 822 /*
@@ -843,6 +843,7 @@ static bool is_phy_starting(struct isci_phy *iphy)
843 case SCI_PHY_SUB_AWAIT_SATA_POWER: 843 case SCI_PHY_SUB_AWAIT_SATA_POWER:
844 case SCI_PHY_SUB_AWAIT_SATA_PHY_EN: 844 case SCI_PHY_SUB_AWAIT_SATA_PHY_EN:
845 case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN: 845 case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN:
846 case SCI_PHY_SUB_AWAIT_OSSP_EN:
846 case SCI_PHY_SUB_AWAIT_SIG_FIS_UF: 847 case SCI_PHY_SUB_AWAIT_SIG_FIS_UF:
847 case SCI_PHY_SUB_FINAL: 848 case SCI_PHY_SUB_FINAL:
848 return true; 849 return true;
@@ -851,6 +852,39 @@ static bool is_phy_starting(struct isci_phy *iphy)
851 } 852 }
852} 853}
853 854
855bool is_controller_start_complete(struct isci_host *ihost)
856{
857 int i;
858
859 for (i = 0; i < SCI_MAX_PHYS; i++) {
860 struct isci_phy *iphy = &ihost->phys[i];
861 u32 state = iphy->sm.current_state_id;
862
863 /* in apc mode we need to check every phy, in
864 * mpc mode we only need to check phys that have
865 * been configured into a port
866 */
867 if (is_port_config_apc(ihost))
868 /* pass */;
869 else if (!phy_get_non_dummy_port(iphy))
870 continue;
871
872 /* The controller start operation is complete iff:
873 * - all links have been given an opportunity to start
874 * - have no indication of a connected device
875 * - have an indication of a connected device and it has
876 * finished the link training process.
877 */
878 if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) ||
879 (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) ||
880 (iphy->is_in_link_training == true && is_phy_starting(iphy)) ||
881 (ihost->port_agent.phy_ready_mask != ihost->port_agent.phy_configured_mask))
882 return false;
883 }
884
885 return true;
886}
887
854/** 888/**
855 * sci_controller_start_next_phy - start phy 889 * sci_controller_start_next_phy - start phy
856 * @scic: controller 890 * @scic: controller
@@ -871,36 +905,7 @@ static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost)
871 return status; 905 return status;
872 906
873 if (ihost->next_phy_to_start >= SCI_MAX_PHYS) { 907 if (ihost->next_phy_to_start >= SCI_MAX_PHYS) {
874 bool is_controller_start_complete = true; 908 if (is_controller_start_complete(ihost)) {
875 u32 state;
876 u8 index;
877
878 for (index = 0; index < SCI_MAX_PHYS; index++) {
879 iphy = &ihost->phys[index];
880 state = iphy->sm.current_state_id;
881
882 if (!phy_get_non_dummy_port(iphy))
883 continue;
884
885 /* The controller start operation is complete iff:
886 * - all links have been given an opportunity to start
887 * - have no indication of a connected device
888 * - have an indication of a connected device and it has
889 * finished the link training process.
890 */
891 if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) ||
892 (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) ||
893 (iphy->is_in_link_training == true && is_phy_starting(iphy)) ||
894 (ihost->port_agent.phy_ready_mask != ihost->port_agent.phy_configured_mask)) {
895 is_controller_start_complete = false;
896 break;
897 }
898 }
899
900 /*
901 * The controller has successfully finished the start process.
902 * Inform the SCI Core user and transition to the READY state. */
903 if (is_controller_start_complete == true) {
904 sci_controller_transition_to_ready(ihost, SCI_SUCCESS); 909 sci_controller_transition_to_ready(ihost, SCI_SUCCESS);
905 sci_del_timer(&ihost->phy_timer); 910 sci_del_timer(&ihost->phy_timer);
906 ihost->phy_startup_timer_pending = false; 911 ihost->phy_startup_timer_pending = false;