Commit c658b109 authored by Pawel Marek's avatar Pawel Marek Committed by Dan Williams
Browse files

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: default avatarPawel Marek <pawel.marek@intel.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 3ff0121a
Loading
Loading
Loading
Loading
+110 −19
Original line number Diff line number Diff line
@@ -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,10 +261,16 @@ void scic_sds_controller_initialize_phy_startup(
		this_controller
		);

	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(
@@ -1698,6 +1704,91 @@ void scic_sds_controller_link_down(
					scic)));
}

/**
 * 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.
@@ -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,
+28 −1
Original line number Diff line number Diff line
@@ -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
@@ -631,6 +639,23 @@ void scic_sds_controller_link_down(
	struct scic_sds_port *the_port,
	struct scic_sds_phy *the_phy);

/*
 * *****************************************************************************
 * * 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_ */
+55 −28
Original line number Diff line number Diff line
@@ -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));
@@ -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;

	/* 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
		);
			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);
}

/**
+3 −0
Original line number Diff line number Diff line
@@ -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(
+0 −21
Original line number Diff line number Diff line
@@ -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;
}

Loading