aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci
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
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')
-rw-r--r--drivers/scsi/isci/host.c67
-rw-r--r--drivers/scsi/isci/host.h3
-rw-r--r--drivers/scsi/isci/port_config.c18
3 files changed, 50 insertions, 38 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;
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index a89c0e3c5a14..9dc910b9d921 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -109,6 +109,8 @@ struct sci_port_configuration_agent;
109typedef void (*port_config_fn)(struct isci_host *, 109typedef void (*port_config_fn)(struct isci_host *,
110 struct sci_port_configuration_agent *, 110 struct sci_port_configuration_agent *,
111 struct isci_port *, struct isci_phy *); 111 struct isci_port *, struct isci_phy *);
112bool is_port_config_apc(struct isci_host *ihost);
113bool is_controller_start_complete(struct isci_host *ihost);
112 114
113struct sci_port_configuration_agent { 115struct sci_port_configuration_agent {
114 u16 phy_configured_mask; 116 u16 phy_configured_mask;
@@ -473,6 +475,7 @@ void isci_host_completion_routine(unsigned long data);
473void isci_host_deinit(struct isci_host *); 475void isci_host_deinit(struct isci_host *);
474void sci_controller_disable_interrupts(struct isci_host *ihost); 476void sci_controller_disable_interrupts(struct isci_host *ihost);
475bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost); 477bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost);
478void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status);
476 479
477enum sci_status sci_controller_start_io( 480enum sci_status sci_controller_start_io(
478 struct isci_host *ihost, 481 struct isci_host *ihost,
diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c
index 6d1e9544cbe5..cd962da4a57a 100644
--- a/drivers/scsi/isci/port_config.c
+++ b/drivers/scsi/isci/port_config.c
@@ -57,7 +57,7 @@
57 57
58#define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10) 58#define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10)
59#define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10) 59#define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10)
60#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (250) 60#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (1000)
61 61
62enum SCIC_SDS_APC_ACTIVITY { 62enum SCIC_SDS_APC_ACTIVITY {
63 SCIC_SDS_APC_SKIP_PHY, 63 SCIC_SDS_APC_SKIP_PHY,
@@ -472,13 +472,9 @@ sci_apc_agent_validate_phy_configuration(struct isci_host *ihost,
472 * down event or a link up event where we can not yet tell to which a phy 472 * down event or a link up event where we can not yet tell to which a phy
473 * belongs. 473 * belongs.
474 */ 474 */
475static void sci_apc_agent_start_timer( 475static void sci_apc_agent_start_timer(struct sci_port_configuration_agent *port_agent,
476 struct sci_port_configuration_agent *port_agent, 476 u32 timeout)
477 u32 timeout)
478{ 477{
479 if (port_agent->timer_pending)
480 sci_del_timer(&port_agent->timer);
481
482 port_agent->timer_pending = true; 478 port_agent->timer_pending = true;
483 sci_mod_timer(&port_agent->timer, timeout); 479 sci_mod_timer(&port_agent->timer, timeout);
484} 480}
@@ -697,6 +693,9 @@ static void apc_agent_timeout(unsigned long data)
697 &ihost->phys[index], false); 693 &ihost->phys[index], false);
698 } 694 }
699 695
696 if (is_controller_start_complete(ihost))
697 sci_controller_transition_to_ready(ihost, SCI_SUCCESS);
698
700done: 699done:
701 spin_unlock_irqrestore(&ihost->scic_lock, flags); 700 spin_unlock_irqrestore(&ihost->scic_lock, flags);
702} 701}
@@ -732,6 +731,11 @@ void sci_port_configuration_agent_construct(
732 } 731 }
733} 732}
734 733
734bool is_port_config_apc(struct isci_host *ihost)
735{
736 return ihost->port_agent.link_up_handler == sci_apc_agent_link_up;
737}
738
735enum sci_status sci_port_configuration_agent_initialize( 739enum sci_status sci_port_configuration_agent_initialize(
736 struct isci_host *ihost, 740 struct isci_host *ihost,
737 struct sci_port_configuration_agent *port_agent) 741 struct sci_port_configuration_agent *port_agent)