From c658b109d3a9444293700471a278a741a1e5033d Mon Sep 17 00:00:00 2001 From: Pawel Marek Date: Tue, 1 Mar 2011 12:31:06 -0800 Subject: isci: controller stop/start fixes 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 Signed-off-by: Dan Williams --- drivers/scsi/isci/core/scic_sds_controller.c | 129 ++++++++++++++++++++---- drivers/scsi/isci/core/scic_sds_controller.h | 29 +++++- drivers/scsi/isci/core/scic_sds_phy.c | 83 ++++++++++----- drivers/scsi/isci/core/scic_sds_phy.h | 3 + drivers/scsi/isci/core/scic_sds_port.c | 21 ---- drivers/scsi/isci/core/scic_sds_remote_device.c | 10 ++ 6 files changed, 206 insertions(+), 69 deletions(-) diff --git a/drivers/scsi/isci/core/scic_sds_controller.c b/drivers/scsi/isci/core/scic_sds_controller.c index 5e26df7..deee7eb 100644 --- a/drivers/scsi/isci/core/scic_sds_controller.c +++ b/drivers/scsi/isci/core/scic_sds_controller.c @@ -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, diff --git a/drivers/scsi/isci/core/scic_sds_controller.h b/drivers/scsi/isci/core/scic_sds_controller.h index 3e0477d..9b8e55d 100644 --- a/drivers/scsi/isci/core/scic_sds_controller.h +++ b/drivers/scsi/isci/core/scic_sds_controller.h @@ -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_ */ diff --git a/drivers/scsi/isci/core/scic_sds_phy.c b/drivers/scsi/isci/core/scic_sds_phy.c index d4a5e38..ba9e557 100644 --- a/drivers/scsi/isci/core/scic_sds_phy.c +++ b/drivers/scsi/isci/core/scic_sds_phy.c @@ -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); } /** diff --git a/drivers/scsi/isci/core/scic_sds_phy.h b/drivers/scsi/isci/core/scic_sds_phy.h index dc450c3..b611e33 100644 --- a/drivers/scsi/isci/core/scic_sds_phy.h +++ b/drivers/scsi/isci/core/scic_sds_phy.h @@ -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( diff --git a/drivers/scsi/isci/core/scic_sds_port.c b/drivers/scsi/isci/core/scic_sds_port.c index 2a193d3..410c9a1 100644 --- a/drivers/scsi/isci/core/scic_sds_port.c +++ b/drivers/scsi/isci/core/scic_sds_port.c @@ -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; } diff --git a/drivers/scsi/isci/core/scic_sds_remote_device.c b/drivers/scsi/isci/core/scic_sds_remote_device.c index a7cb4bc..0ac6ca0 100644 --- a/drivers/scsi/isci/core/scic_sds_remote_device.c +++ b/drivers/scsi/isci/core/scic_sds_remote_device.c @@ -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 + ); } /** -- cgit v1.1