isci: controller stop/start fixes
authorPawel Marek <pawel.marek@intel.com>
Tue, 1 Mar 2011 20:31:06 +0000 (12:31 -0800)
committerDan Williams <dan.j.williams@intel.com>
Sun, 3 Jul 2011 10:55:29 +0000 (03:55 -0700)
Core reworks to support stopping and re-starting the controller, lays the
groundwork for phy disable / re-enable and fixes other bugs around port/phy
setup/teardown.

Signed-off-by: Pawel Marek <pawel.marek@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/scsi/isci/core/scic_sds_controller.c
drivers/scsi/isci/core/scic_sds_controller.h
drivers/scsi/isci/core/scic_sds_phy.c
drivers/scsi/isci/core/scic_sds_phy.h
drivers/scsi/isci/core/scic_sds_port.c
drivers/scsi/isci/core/scic_sds_remote_device.c

index 5e26df7..deee7eb 100644 (file)
@@ -252,7 +252,7 @@ static void scic_sds_controller_phy_startup_timeout_handler(
  *
  * This method initializes the phy startup operations for controller start.
  */
-void scic_sds_controller_initialize_phy_startup(
+enum sci_status scic_sds_controller_initialize_phy_startup(
        struct scic_sds_controller *this_controller)
 {
        this_controller->phy_startup_timer = isci_event_timer_create(
@@ -261,8 +261,14 @@ void scic_sds_controller_initialize_phy_startup(
                this_controller
                );
 
-       this_controller->next_phy_to_start = 0;
-       this_controller->phy_startup_timer_pending = false;
+       if (this_controller->phy_startup_timer == NULL) {
+               return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+       } else {
+               this_controller->next_phy_to_start = 0;
+               this_controller->phy_startup_timer_pending = false;
+       }
+
+       return SCI_SUCCESS;
 }
 
 /**
@@ -305,7 +311,7 @@ void scic_sds_controller_initialize_power_control(
  *    to build the memory table.
  *
  */
-static void scic_sds_controller_build_memory_descriptor_table(
+void scic_sds_controller_build_memory_descriptor_table(
        struct scic_sds_controller *this_controller)
 {
        sci_base_mde_construct(
@@ -1699,6 +1705,91 @@ void scic_sds_controller_link_down(
 }
 
 /**
+ * This method is called by the remote device to inform the controller
+ * that this remote device has started.
+ *
+ */
+
+void scic_sds_controller_remote_device_started(
+       struct scic_sds_controller *this_controller,
+       struct scic_sds_remote_device  *the_device)
+{
+       u32 state;
+       scic_sds_controller_device_handler_t remote_device_started_handler;
+
+       state = this_controller->parent.state_machine.current_state_id;
+       remote_device_started_handler = scic_sds_controller_state_handler_table[state].remote_device_started_handler;
+
+       if (remote_device_started_handler != NULL)
+               remote_device_started_handler(this_controller, the_device);
+       else {
+               dev_warn(scic_to_dev(this_controller),
+               "%s: SCIC Controller 0x%p remote device started event "
+               "from device 0x%p in unexpected state  %d\n",
+               __func__,
+               this_controller,
+               the_device,
+               sci_base_state_machine_get_state(
+                       scic_sds_controller_get_base_state_machine(
+                               this_controller)));
+       }
+}
+
+/**
+ * This is a helper method to determine if any remote devices on this
+ * controller are still in the stopping state.
+ *
+ */
+bool scic_sds_controller_has_remote_devices_stopping(
+       struct scic_sds_controller *this_controller)
+{
+       u32 index;
+
+       for (index = 0; index < this_controller->remote_node_entries; index++) {
+               if ((this_controller->device_table[index] != NULL) &&
+                  (this_controller->device_table[index]->parent.state_machine.current_state_id
+                   == SCI_BASE_REMOTE_DEVICE_STATE_STOPPING))
+                       return true;
+       }
+
+       return false;
+}
+
+/**
+ * This method is called by the remote device to inform the controller
+ * object that the remote device has stopped.
+ *
+ */
+
+void scic_sds_controller_remote_device_stopped(
+       struct scic_sds_controller  *this_controller,
+       struct scic_sds_remote_device *the_device)
+{
+
+       u32 state;
+       scic_sds_controller_device_handler_t remote_device_stopped_handler;
+
+       state = this_controller->parent.state_machine.current_state_id;
+       remote_device_stopped_handler = scic_sds_controller_state_handler_table[state].remote_device_stopped_handler;
+
+       if (remote_device_stopped_handler != NULL)
+               remote_device_stopped_handler(this_controller, the_device);
+       else {
+               dev_warn(scic_to_dev(this_controller),
+               "%s: SCIC Controller 0x%p remote device stopped event "
+               "from device 0x%p in unexpected state  %d\n",
+               __func__,
+               this_controller,
+               the_device,
+               sci_base_state_machine_get_state(
+                       scic_sds_controller_get_base_state_machine(
+                               this_controller)));
+       }
+}
+
+
+
+/**
  * This method will write to the SCU PCP register the request value. The method
  *    is used to suspend/resume ports, devices, and phys.
  * @this_controller:
@@ -3461,23 +3552,22 @@ static enum sci_status scic_sds_controller_stopping_state_complete_io_handler(
  *    struct scic_sds_controller object.
  * @remote_device: This is struct sci_base_remote_device which is cast to a
  *    struct scic_sds_remote_device object.
- * @io_request: This is the struct sci_base_request which is cast to a
- *    SCIC_SDS_IO_REQUEST object.
  *
  * This method is called when the struct scic_sds_controller is in a stopping state
- * and the complete task handler is called. - This function is not yet
- * implemented enum sci_status SCI_FAILURE
- */
-
-/*
- * *****************************************************************************
- * * STOPPED STATE HANDLERS
- * ***************************************************************************** */
-
-/*
- * *****************************************************************************
- * * FAILED STATE HANDLERS
- * ***************************************************************************** */
+ * and the remote device has stopped.
+ **/
+void scic_sds_controller_stopping_state_device_stopped_handler(
+       struct scic_sds_controller *controller,
+       struct scic_sds_remote_device *remote_device
+)
+{
+       if (!scic_sds_controller_has_remote_devices_stopping(controller)) {
+               sci_base_state_machine_change_state(
+                       &controller->parent.state_machine,
+                       SCI_BASE_CONTROLLER_STATE_STOPPED
+               );
+       }
+}
 
 const struct scic_sds_controller_state_handler scic_sds_controller_state_handler_table[] = {
        [SCI_BASE_CONTROLLER_STATE_INITIAL] = {
@@ -3537,6 +3627,7 @@ const struct scic_sds_controller_state_handler scic_sds_controller_state_handler
                .base.complete_io  = scic_sds_controller_stopping_state_complete_io_handler,
                .base.continue_io  = scic_sds_controller_default_request_handler,
                .terminate_request = scic_sds_controller_default_request_handler,
+               .remote_device_stopped_handler = scic_sds_controller_stopping_state_device_stopped_handler,
        },
        [SCI_BASE_CONTROLLER_STATE_STOPPED] = {
                .base.reset        = scic_sds_controller_general_reset_handler,
index 3e0477d..9b8e55d 100644 (file)
@@ -120,6 +120,7 @@ enum SCIC_SDS_CONTROLLER_MEMORY_DESCRIPTORS {
        SCU_MAX_MDES
 };
 
+
 /**
  *
  *
@@ -390,6 +391,11 @@ struct scic_sds_controller {
 typedef void (*scic_sds_controller_phy_handler_t)(struct scic_sds_controller *,
                                                  struct scic_sds_port *,
                                                  struct scic_sds_phy *);
+
+typedef void (*scic_sds_controller_device_handler_t)(struct scic_sds_controller *,
+                                                 struct scic_sds_remote_device *);
+
+
 /**
  * struct scic_sds_controller_state_handler -
  *
@@ -402,6 +408,8 @@ struct scic_sds_controller_state_handler {
        sci_base_controller_request_handler_t terminate_request;
        scic_sds_controller_phy_handler_t link_up;
        scic_sds_controller_phy_handler_t link_down;
+       scic_sds_controller_device_handler_t remote_device_started_handler;
+       scic_sds_controller_device_handler_t remote_device_stopped_handler;
 };
 
 extern const struct scic_sds_controller_state_handler
@@ -633,6 +641,23 @@ void scic_sds_controller_link_down(
 
 /*
  * *****************************************************************************
+ * * CORE CONTROLLER REMOTE DEVICE MESSAGE PROCESSING
+ * ***************************************************************************** */
+
+bool scic_sds_controller_has_remote_devices_stopping(
+       struct scic_sds_controller *this_controller);
+
+void scic_sds_controller_remote_device_started(
+       struct scic_sds_controller *this_controller,
+       struct scic_sds_remote_device *the_device);
+
+void scic_sds_controller_remote_device_stopped(
+       struct scic_sds_controller *this_controller,
+       struct scic_sds_remote_device *the_device);
+
+
+/*
+ * *****************************************************************************
  * * CORE CONTROLLER PRIVATE METHODS
  * ***************************************************************************** */
 
@@ -688,8 +713,10 @@ void scic_sds_controller_register_setup(
 void scic_sds_controller_reset_hardware(
        struct scic_sds_controller *this_controller);
 
+enum sci_status scic_sds_controller_initialize_phy_startup(
+       struct scic_sds_controller *this_controller);
 
-void scic_sds_controller_initialize_phy_startup(
+void scic_sds_controller_build_memory_descriptor_table(
        struct scic_sds_controller *this_controller);
 
 #endif /* _SCIC_SDS_CONTROLLER_H_ */
index d4a5e38..ba9e557 100644 (file)
@@ -257,7 +257,7 @@ scic_sds_phy_link_layer_initialization(struct scic_sds_phy *sci_phy,
  * restart the starting substate machine since we dont know what has actually
  * happening.
  */
-static void scic_sds_phy_sata_timeout(void *phy)
+void scic_sds_phy_sata_timeout(void *phy)
 {
        struct scic_sds_phy *sci_phy = phy;
 
@@ -303,6 +303,7 @@ void scic_sds_phy_construct(
        this_phy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN;
        this_phy->link_layer_registers = NULL;
        this_phy->max_negotiated_speed = SCI_SAS_NO_LINK_RATE;
+       this_phy->sata_timeout_timer = NULL;
 
        /* Clear out the identification buffer data */
        memset(&this_phy->phy_type, 0, sizeof(this_phy->phy_type));
@@ -365,8 +366,8 @@ void scic_sds_phy_set_port(
  */
 enum sci_status scic_sds_phy_initialize(
        struct scic_sds_phy *sci_phy,
-       struct scu_transport_layer_registers __iomem *transport_layer_registers,
-       struct scu_link_layer_registers __iomem *link_layer_registers)
+               struct scu_transport_layer_registers __iomem *transport_layer_registers,
+               struct scu_link_layer_registers __iomem *link_layer_registers)
 {
        /* Create the SIGNATURE FIS Timeout timer for this phy */
        sci_phy->sata_timeout_timer = isci_event_timer_create(
@@ -757,6 +758,23 @@ static void scic_sds_phy_restart_starting_state(
                );
 }
 
+/* ****************************************************************************
+   * SCIC SDS PHY general handlers
+   ************************************************************************** */
+static enum sci_status scic_sds_phy_starting_substate_general_stop_handler(
+       struct sci_base_phy *phy)
+{
+       struct scic_sds_phy *this_phy;
+       this_phy = (struct scic_sds_phy *)phy;
+
+       sci_base_state_machine_stop(&this_phy->starting_substate_machine);
+
+       sci_base_state_machine_change_state(&phy->state_machine,
+                                                SCI_BASE_PHY_STATE_STOPPED);
+
+       return SCI_SUCCESS;
+}
+
 /*
  * *****************************************************************************
  * * SCIC SDS PHY EVENT_HANDLERS
@@ -1436,12 +1454,10 @@ static enum sci_status scic_sds_phy_starting_substate_await_sata_power_consume_p
        return SCI_SUCCESS;
 }
 
-/* --------------------------------------------------------------------------- */
-
 const struct scic_sds_phy_state_handler scic_sds_phy_starting_substate_handler_table[] = {
        [SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL] = {
                .parent.start_handler    = scic_sds_phy_default_start_handler,
-               .parent.stop_handler     = scic_sds_phy_default_stop_handler,
+               .parent.stop_handler     = scic_sds_phy_starting_substate_general_stop_handler,
                .parent.reset_handler    = scic_sds_phy_default_reset_handler,
                .parent.destruct_handler = scic_sds_phy_default_destroy_handler,
                .frame_handler           = scic_sds_phy_default_frame_handler,
@@ -1450,7 +1466,7 @@ const struct scic_sds_phy_state_handler scic_sds_phy_starting_substate_handler_t
        },
        [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN] = {
                .parent.start_handler    = scic_sds_phy_default_start_handler,
-               .parent.stop_handler     = scic_sds_phy_default_stop_handler,
+               .parent.stop_handler     = scic_sds_phy_starting_substate_general_stop_handler,
                .parent.reset_handler    = scic_sds_phy_default_reset_handler,
                .parent.destruct_handler = scic_sds_phy_default_destroy_handler,
                .frame_handler           = scic_sds_phy_default_frame_handler,
@@ -1459,7 +1475,7 @@ const struct scic_sds_phy_state_handler scic_sds_phy_starting_substate_handler_t
        },
        [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN] = {
                .parent.start_handler    = scic_sds_phy_default_start_handler,
-               .parent.stop_handler     = scic_sds_phy_default_stop_handler,
+               .parent.stop_handler     = scic_sds_phy_starting_substate_general_stop_handler,
                .parent.reset_handler    = scic_sds_phy_default_reset_handler,
                .parent.destruct_handler = scic_sds_phy_default_destroy_handler,
                .frame_handler           = scic_sds_phy_default_frame_handler,
@@ -1477,7 +1493,7 @@ const struct scic_sds_phy_state_handler scic_sds_phy_starting_substate_handler_t
        },
        [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER] = {
                .parent.start_handler    = scic_sds_phy_default_start_handler,
-               .parent.stop_handler     = scic_sds_phy_default_stop_handler,
+               .parent.stop_handler     = scic_sds_phy_starting_substate_general_stop_handler,
                .parent.reset_handler    = scic_sds_phy_default_reset_handler,
                .parent.destruct_handler = scic_sds_phy_default_destroy_handler,
                .frame_handler           = scic_sds_phy_default_frame_handler,
@@ -1486,7 +1502,7 @@ const struct scic_sds_phy_state_handler scic_sds_phy_starting_substate_handler_t
        },
        [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER] = {
                .parent.start_handler    = scic_sds_phy_default_start_handler,
-               .parent.stop_handler     = scic_sds_phy_default_stop_handler,
+               .parent.stop_handler     = scic_sds_phy_starting_substate_general_stop_handler,
                .parent.reset_handler    = scic_sds_phy_default_reset_handler,
                .parent.destruct_handler = scic_sds_phy_default_destroy_handler,
                .frame_handler           = scic_sds_phy_default_frame_handler,
@@ -1495,7 +1511,7 @@ const struct scic_sds_phy_state_handler scic_sds_phy_starting_substate_handler_t
        },
        [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN] = {
                .parent.start_handler    = scic_sds_phy_default_start_handler,
-               .parent.stop_handler     = scic_sds_phy_default_stop_handler,
+               .parent.stop_handler     = scic_sds_phy_starting_substate_general_stop_handler,
                .parent.reset_handler    = scic_sds_phy_default_reset_handler,
                .parent.destruct_handler = scic_sds_phy_default_destroy_handler,
                .frame_handler           = scic_sds_phy_default_frame_handler,
@@ -1504,7 +1520,7 @@ const struct scic_sds_phy_state_handler scic_sds_phy_starting_substate_handler_t
        },
        [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN] = {
                .parent.start_handler    = scic_sds_phy_default_start_handler,
-               .parent.stop_handler     = scic_sds_phy_default_stop_handler,
+               .parent.stop_handler     = scic_sds_phy_starting_substate_general_stop_handler,
                .parent.reset_handler    = scic_sds_phy_default_reset_handler,
                .parent.destruct_handler = scic_sds_phy_default_destroy_handler,
                .frame_handler           = scic_sds_phy_default_frame_handler,
@@ -1513,7 +1529,7 @@ const struct scic_sds_phy_state_handler scic_sds_phy_starting_substate_handler_t
        },
        [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF] = {
                .parent.start_handler    = scic_sds_phy_default_start_handler,
-               .parent.stop_handler     = scic_sds_phy_default_stop_handler,
+               .parent.stop_handler     = scic_sds_phy_starting_substate_general_stop_handler,
                .parent.reset_handler    = scic_sds_phy_default_reset_handler,
                .parent.destruct_handler = scic_sds_phy_default_destroy_handler,
                .frame_handler           = scic_sds_phy_starting_substate_await_sig_fis_frame_handler,
@@ -1522,7 +1538,7 @@ const struct scic_sds_phy_state_handler scic_sds_phy_starting_substate_handler_t
        },
        [SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL] = {
                .parent.start_handler    = scic_sds_phy_default_start_handler,
-               .parent.stop_handler     = scic_sds_phy_default_stop_handler,
+               .parent.stop_handler     = scic_sds_phy_starting_substate_general_stop_handler,
                .parent.reset_handler    = scic_sds_phy_default_reset_handler,
                .parent.destruct_handler = scic_sds_phy_default_destroy_handler,
                .frame_handler           = scic_sds_phy_default_frame_handler,
@@ -2153,17 +2169,22 @@ enum sci_status scic_sds_phy_default_consume_power_handler(
  * start it. - The phy state machine is transitioned to the
  * SCI_BASE_PHY_STATE_STARTING. enum sci_status SCI_SUCCESS
  */
-static enum sci_status scic_sds_phy_stopped_state_start_handler(
-       struct sci_base_phy *phy)
+static enum sci_status scic_sds_phy_stopped_state_start_handler(struct sci_base_phy *phy)
 {
        struct scic_sds_phy *this_phy;
 
        this_phy = (struct scic_sds_phy *)phy;
 
-       sci_base_state_machine_change_state(
-               scic_sds_phy_get_base_state_machine(this_phy),
-               SCI_BASE_PHY_STATE_STARTING
-               );
+       /* Create the SIGNATURE FIS Timeout timer for this phy */
+       this_phy->sata_timeout_timer = isci_event_timer_create(
+               scic_sds_phy_get_controller(this_phy),
+               scic_sds_phy_sata_timeout, this_phy);
+
+       if (this_phy->sata_timeout_timer != NULL) {
+               sci_base_state_machine_change_state(
+                       scic_sds_phy_get_base_state_machine(this_phy),
+                       SCI_BASE_PHY_STATE_STARTING);
+       }
 
        return SCI_SUCCESS;
 }
@@ -2185,7 +2206,7 @@ static enum sci_status scic_sds_phy_stopped_state_destroy_handler(
 
        this_phy = (struct scic_sds_phy *)phy;
 
-       /* @todo what do we actually need to do here? */
+       /* @todo what do we actually need to do here? */
        return SCI_SUCCESS;
 }
 
@@ -2500,7 +2521,7 @@ static void scic_sds_phy_initial_state_enter(
 
        this_phy = (struct scic_sds_phy *)object;
 
-       scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_STOPPED);
+       scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_INITIAL);
 }
 
 /**
@@ -2512,18 +2533,24 @@ static void scic_sds_phy_initial_state_enter(
  * handlers for the phy object base state machine initial state. - The SCU
  * hardware is requested to stop the protocol engine. none
  */
-static void scic_sds_phy_stopped_state_enter(
-       struct sci_base_object *object)
+static void scic_sds_phy_stopped_state_enter(struct sci_base_object *object)
 {
-       struct scic_sds_phy *this_phy;
+       struct scic_sds_phy *sci_phy;
 
-       this_phy = (struct scic_sds_phy *)object;
+       sci_phy = (struct scic_sds_phy *)object;
 
        /* / @todo We need to get to the controller to place this PE in a reset state */
 
-       scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_STOPPED);
+       scic_sds_phy_set_base_state_handlers(sci_phy, SCI_BASE_PHY_STATE_STOPPED);
 
-       scu_link_layer_stop_protocol_engine(this_phy);
+       if (sci_phy->sata_timeout_timer != NULL) {
+               isci_event_timer_destroy(scic_sds_phy_get_controller(sci_phy),
+                                        sci_phy->sata_timeout_timer);
+
+               sci_phy->sata_timeout_timer = NULL;
+       }
+
+       scu_link_layer_stop_protocol_engine(sci_phy);
 }
 
 /**
index dc450c3..b611e33 100644 (file)
@@ -401,6 +401,9 @@ enum sci_status scic_sds_phy_stop(
 enum sci_status scic_sds_phy_reset(
        struct scic_sds_phy *this_phy);
 
+void scic_sds_phy_sata_timeout(
+       void *cookie);
+
 /* --------------------------------------------------------------------------- */
 
 void scic_sds_phy_suspend(
index 2a193d3..410c9a1 100644 (file)
@@ -625,27 +625,6 @@ enum sci_status scic_sds_port_initialize(
        this_port->port_pe_configuration_register = port_configuration_regsiter;
        this_port->viit_registers                 = viit_registers;
 
-       /*
-        * If this is not the dummy port make the assignment of
-        * the timer and start the state machine */
-       if (this_port->physical_port_index != SCI_MAX_PORTS) {
-               /* / @todo should we create the timer at create time? */
-               this_port->timer_handle = isci_event_timer_create(
-                       scic_sds_port_get_controller(this_port),
-                       scic_sds_port_timeout_handler,
-                       this_port
-                       );
-
-       } else {
-               /*
-                * Force the dummy port into a condition where it rejects all requests
-                * as its in an invalid state for any operation.
-                * / @todo should we set a set of specical handlers for the dummy port? */
-               scic_sds_port_set_base_state_handlers(
-                       this_port, SCI_BASE_PORT_STATE_STOPPED
-                       );
-       }
-
        return SCI_SUCCESS;
 }
 
index a7cb4bc..0ac6ca0 100644 (file)
@@ -1822,6 +1822,11 @@ static void scic_sds_remote_device_stopped_state_enter(
                        SCI_SUCCESS
                        );
        }
+
+       scic_sds_controller_remote_device_stopped(
+               scic_sds_remote_device_get_controller(this_device),
+               this_device
+       );
 }
 
 /**
@@ -1875,6 +1880,11 @@ static void scic_sds_remote_device_starting_state_exit(
                this_device,
                SCI_SUCCESS
                );
+
+       scic_sds_controller_remote_device_started(
+               scic_sds_remote_device_get_controller(this_device),
+               this_device
+       );
 }
 
 /**