#include "scic_sds_port.h"
#include "scic_sds_remote_device.h"
#include "scic_sds_request.h"
-#include "scic_user_callback.h"
#include "sci_environment.h"
#include "sci_util.h"
#include "scu_completion_codes.h"
*
* This method initializes the phy startup operations for controller start.
*/
-void scic_sds_controller_initialize_phy_startup(
- struct scic_sds_controller *this_controller)
+enum sci_status scic_sds_controller_initialize_phy_startup(
+ struct scic_sds_controller *scic)
{
- this_controller->phy_startup_timer = scic_cb_timer_create(
- this_controller,
- scic_sds_controller_phy_startup_timeout_handler,
- this_controller
- );
+ struct isci_host *ihost = sci_object_get_association(scic);
- this_controller->next_phy_to_start = 0;
- this_controller->phy_startup_timer_pending = false;
+ scic->phy_startup_timer = isci_timer_create(ihost,
+ scic,
+ scic_sds_controller_phy_startup_timeout_handler);
+
+ if (scic->phy_startup_timer == NULL)
+ return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+ else {
+ scic->next_phy_to_start = 0;
+ scic->phy_startup_timer_pending = false;
+ }
+
+ return SCI_SUCCESS;
}
/**
* object.
*/
void scic_sds_controller_initialize_power_control(
- struct scic_sds_controller *this_controller)
+ struct scic_sds_controller *scic)
{
- this_controller->power_control.timer = scic_cb_timer_create(
- this_controller,
- scic_sds_controller_power_control_timer_handler,
- this_controller
- );
+ struct isci_host *ihost = sci_object_get_association(scic);
+ scic->power_control.timer = isci_timer_create(
+ ihost,
+ scic,
+ scic_sds_controller_power_control_timer_handler);
- memset(
- this_controller->power_control.requesters,
- 0,
- sizeof(this_controller->power_control.requesters)
- );
+ memset(scic->power_control.requesters,
+ 0,
+ sizeof(scic->power_control.requesters));
- this_controller->power_control.phys_waiting = 0;
+ scic->power_control.phys_waiting = 0;
+ scic->power_control.phys_granted_power = 0;
}
/* --------------------------------------------------------------------------- */
* 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(
*/
#define AFE_REGISTER_WRITE_DELAY 10
-static bool is_a0(void)
-{
- return isci_si_rev == ISCI_SI_REVA0;
-}
-
-static bool is_a2(void)
-{
- return isci_si_rev == ISCI_SI_REVA2;
-}
-
-static bool is_b0(void)
-{
- return isci_si_rev > ISCI_SI_REVA2;
-}
-
/* Initialize the AFE for this phy index. We need to read the AFE setup from
* the OEM parameters none
*/
void scic_sds_controller_afe_initialization(struct scic_sds_controller *scic)
{
+ const struct scic_sds_oem_params *oem = &scic->oem_parameters.sds1;
u32 afe_status;
u32 phy_id;
/* Clear DFX Status registers */
scu_afe_register_write(scic, afe_dfx_master_control0, 0x0081000f);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
/* Configure bias currents to normal */
if (is_a0())
scu_afe_register_write(scic, afe_bias_control, 0x00005500);
else
scu_afe_register_write(scic, afe_bias_control, 0x00005A00);
-
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
/* Enable PLL */
if (is_b0())
scu_afe_register_write(scic, afe_pll_control0, 0x80040A08);
else
scu_afe_register_write(scic, afe_pll_control0, 0x80040908);
-
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+
+ udelay(AFE_REGISTER_WRITE_DELAY);
/* Wait for the PLL to lock */
do {
afe_status = scu_afe_register_read(
scic, afe_common_block_status);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
} while ((afe_status & 0x00001000) == 0);
if (is_b0()) {
/* Shorten SAS SNW lock time (RxLock timer value from 76 us to 50 us) */
scu_afe_register_write(scic, afe_pmsn_master_control0, 0x7bcc96ad);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
}
for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) {
+ const struct sci_phy_oem_params *oem_phy = &oem->phys[phy_id];
+
if (is_b0()) {
/* Configure transmitter SSC parameters */
scu_afe_txreg_write(scic, phy_id, afe_tx_ssc_control, 0x00030000);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
} else {
/*
* All defaults, except the Receive Word Alignament/Comma Detect
* Enable....(0xe800) */
scu_afe_txreg_write(scic, phy_id, afe_xcvr_control0, 0x00004512);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
scu_afe_txreg_write(scic, phy_id, afe_xcvr_control1, 0x0050100F);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
}
/*
else {
/* Power down TX and RX (PWRDNTX and PWRDNRX) */
scu_afe_txreg_write(scic, phy_id, afe_channel_control, 0x000003d7);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
/*
* Power up TX and RX out from power down (PWRDNTX and PWRDNRX)
* & increase TX int & ext bias 20%....(0xe85c) */
scu_afe_txreg_write(scic, phy_id, afe_channel_control, 0x000003d4);
}
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
if (is_a0() || is_a2()) {
/* Enable TX equalization (0xe824) */
scu_afe_txreg_write(scic, phy_id, afe_tx_control, 0x00040000);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
}
/*
* RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0, TPD=0x0(TX Power On),
* RDD=0x0(RX Detect Enabled) ....(0xe800) */
scu_afe_txreg_write(scic, phy_id, afe_xcvr_control0, 0x00004100);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
/* Leave DFE/FFE on */
if (is_a0())
scu_afe_txreg_write(scic, phy_id, afe_rx_ssc_control0, 0x3F11103F);
else {
scu_afe_txreg_write(scic, phy_id, afe_rx_ssc_control0, 0x3F11103F);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
/* Enable TX equalization (0xe824) */
scu_afe_txreg_write(scic, phy_id, afe_tx_control, 0x00040000);
}
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
- scu_afe_txreg_write(scic, phy_id, afe_tx_amp_control0, 0x000E7C03);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ scu_afe_txreg_write(scic, phy_id, afe_tx_amp_control0, oem_phy->afe_tx_amp_control0);
+ udelay(AFE_REGISTER_WRITE_DELAY);
- scu_afe_txreg_write(scic, phy_id, afe_tx_amp_control1, 0x000E7C03);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ scu_afe_txreg_write(scic, phy_id, afe_tx_amp_control0, oem_phy->afe_tx_amp_control1);
+ udelay(AFE_REGISTER_WRITE_DELAY);
- scu_afe_txreg_write(scic, phy_id, afe_tx_amp_control2, 0x000E7C03);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ scu_afe_txreg_write(scic, phy_id, afe_tx_amp_control0, oem_phy->afe_tx_amp_control2);
+ udelay(AFE_REGISTER_WRITE_DELAY);
- scu_afe_txreg_write(scic, phy_id, afe_tx_amp_control3, 0x000E7C03);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ scu_afe_txreg_write(scic, phy_id, afe_tx_amp_control0, oem_phy->afe_tx_amp_control3);
+ udelay(AFE_REGISTER_WRITE_DELAY);
}
/* Transfer control to the PEs */
scu_afe_register_write(scic, afe_dfx_master_control0, 0x00010f00);
- scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
+ udelay(AFE_REGISTER_WRITE_DELAY);
}
/*
* none.
*/
static void scic_sds_controller_transition_to_ready(
- struct scic_sds_controller *this_controller,
+ struct scic_sds_controller *scic,
enum sci_status status)
{
- if (this_controller->parent.state_machine.current_state_id
- == SCI_BASE_CONTROLLER_STATE_STARTING) {
+ struct isci_host *ihost = sci_object_get_association(scic);
+
+ if (scic->parent.state_machine.current_state_id ==
+ SCI_BASE_CONTROLLER_STATE_STARTING) {
/*
* We move into the ready state, because some of the phys/ports
- * may be up and operational. */
+ * may be up and operational.
+ */
sci_base_state_machine_change_state(
- scic_sds_controller_get_base_state_machine(this_controller),
- SCI_BASE_CONTROLLER_STATE_READY
- );
+ scic_sds_controller_get_base_state_machine(scic),
+ SCI_BASE_CONTROLLER_STATE_READY);
- scic_cb_controller_start_complete(this_controller, status);
+ isci_host_start_complete(ihost, status);
}
}
-/**
- * This method is the general timeout handler for the controller. It will take
- * the correct timetout action based on the current controller state
- */
-void scic_sds_controller_timeout_handler(
- struct scic_sds_controller *scic)
+void scic_sds_controller_timeout_handler(void *_scic)
{
+ struct scic_sds_controller *scic = _scic;
+ struct isci_host *ihost = sci_object_get_association(scic);
enum sci_base_controller_states current_state;
current_state = sci_base_state_machine_get_state(
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(scic),
SCI_BASE_CONTROLLER_STATE_FAILED);
- scic_cb_controller_stop_complete(scic, SCI_FAILURE_TIMEOUT);
+ isci_host_stop_complete(ihost, SCI_FAILURE_TIMEOUT);
} else /* / @todo Now what do we want to do in this case? */
dev_err(scic_to_dev(scic),
"%s: Controller timer fired when controller was not "
__func__);
}
-/**
- * scic_sds_controller_get_port_configuration_mode
- * @this_controller: This is the controller to use to determine if we are using
- * manual or automatic port configuration.
- *
- * SCIC_PORT_CONFIGURATION_MODE
- */
-enum SCIC_PORT_CONFIGURATION_MODE scic_sds_controller_get_port_configuration_mode(
- struct scic_sds_controller *this_controller)
-{
- u32 index;
- enum SCIC_PORT_CONFIGURATION_MODE mode;
-
- mode = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
-
- for (index = 0; index < SCI_MAX_PORTS; index++) {
- if (this_controller->oem_parameters.sds1.ports[index].phy_mask != 0) {
- mode = SCIC_PORT_MANUAL_CONFIGURATION_MODE;
- break;
- }
- }
-
- return mode;
-}
-
enum sci_status scic_sds_controller_stop_ports(struct scic_sds_controller *scic)
{
u32 index;
enum sci_status status = SCI_SUCCESS;
for (index = 0; index < scic->logical_port_entries; index++) {
- port_status = scic_port_stop(&scic->port_table[index]);
+ struct scic_sds_port *sci_port = &scic->port_table[index];
+ SCI_BASE_PORT_HANDLER_T stop;
+
+ stop = sci_port->state_handlers->parent.stop_handler;
+ port_status = stop(&sci_port->parent);
if ((port_status != SCI_SUCCESS) &&
(port_status != SCI_FAILURE_INVALID_STATE)) {
"%s: Controller stop operation failed to "
"stop port %d because of status %d.\n",
__func__,
- scic->port_table[index].logical_port_index,
+ sci_port->logical_port_index,
port_status);
}
}
return status;
}
-/**
- *
- *
- *
- */
-static void scic_sds_controller_phy_timer_start(
- struct scic_sds_controller *this_controller)
+static inline void scic_sds_controller_phy_timer_start(
+ struct scic_sds_controller *scic)
{
- scic_cb_timer_start(
- this_controller,
- this_controller->phy_startup_timer,
- SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT
- );
+ isci_timer_start(scic->phy_startup_timer,
+ SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT);
- this_controller->phy_startup_timer_pending = true;
+ scic->phy_startup_timer_pending = true;
}
-/**
- *
- *
- *
- */
-void scic_sds_controller_phy_timer_stop(
- struct scic_sds_controller *this_controller)
+inline void scic_sds_controller_phy_timer_stop(
+ struct scic_sds_controller *scic)
{
- scic_cb_timer_stop(
- this_controller,
- this_controller->phy_startup_timer
- );
+ isci_timer_stop(scic->phy_startup_timer);
- this_controller->phy_startup_timer_pending = false;
+ scic->phy_startup_timer_pending = false;
}
/**
* This method is called internally by the controller object to start the next
- * phy on the controller. If all the phys have been starte, then this
+ * phy on the controller. If all the phys have been started, then this
* method will attempt to transition the controller to the READY state and
* inform the user (scic_cb_controller_start_complete()).
* @this_controller: This parameter specifies the controller object for which
*
* enum sci_status
*/
-enum sci_status scic_sds_controller_start_next_phy(
- struct scic_sds_controller *this_controller)
+enum sci_status scic_sds_controller_start_next_phy(struct scic_sds_controller *scic)
{
+ struct scic_sds_oem_params *oem = &scic->oem_parameters.sds1;
+ struct scic_sds_phy *sci_phy;
enum sci_status status;
status = SCI_SUCCESS;
- if (this_controller->phy_startup_timer_pending == false) {
- if (this_controller->next_phy_to_start == SCI_MAX_PHYS) {
- bool is_controller_start_complete = true;
- struct scic_sds_phy *the_phy;
- u8 index;
+ if (scic->phy_startup_timer_pending)
+ return status;
- for (index = 0; index < SCI_MAX_PHYS; index++) {
- the_phy = &this_controller->phy_table[index];
-
- if (scic_sds_phy_get_port(the_phy) != NULL) {
- /**
- * The controller start operation is complete if and only
- * if:
- * - all links have been given an opportunity to start
- * - have no indication of a connected device
- * - have an indication of a connected device and it has
- * finished the link training process.
- */
- if (
- (
- (the_phy->is_in_link_training == false)
- && (the_phy->parent.state_machine.current_state_id
- == SCI_BASE_PHY_STATE_INITIAL)
- )
- || (
- (the_phy->is_in_link_training == false)
- && (the_phy->parent.state_machine.current_state_id
- == SCI_BASE_PHY_STATE_STOPPED)
- )
- || (
- (the_phy->is_in_link_training == true)
- && (the_phy->parent.state_machine.current_state_id
- == SCI_BASE_PHY_STATE_STARTING)
- )
- ) {
- is_controller_start_complete = false;
- break;
- }
- }
- }
+ if (scic->next_phy_to_start >= SCI_MAX_PHYS) {
+ bool is_controller_start_complete = true;
+ u32 state;
+ u8 index;
- /*
- * The controller has successfully finished the start process.
- * Inform the SCI Core user and transition to the READY state. */
- if (is_controller_start_complete == true) {
- scic_sds_controller_transition_to_ready(
- this_controller, SCI_SUCCESS
- );
- scic_sds_controller_phy_timer_stop(this_controller);
- }
- } else {
- struct scic_sds_phy *the_phy;
-
- the_phy = &this_controller->phy_table[this_controller->next_phy_to_start];
-
- if (
- scic_sds_controller_get_port_configuration_mode(this_controller)
- == SCIC_PORT_MANUAL_CONFIGURATION_MODE
- ) {
- if (scic_sds_phy_get_port(the_phy) == NULL) {
- this_controller->next_phy_to_start++;
-
- /*
- * Caution recursion ahead be forwarned
- *
- * The PHY was never added to a PORT in MPC mode so start the next phy in sequence
- * This phy will never go link up and will not draw power the OEM parameters either
- * configured the phy incorrectly for the PORT or it was never assigned to a PORT */
- return scic_sds_controller_start_next_phy(this_controller);
- }
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ sci_phy = &scic->phy_table[index];
+ state = sci_phy->parent.state_machine.current_state_id;
+
+ if (!scic_sds_phy_get_port(sci_phy))
+ continue;
+
+ /* The controller start operation is complete iff:
+ * - all links have been given an opportunity to start
+ * - have no indication of a connected device
+ * - have an indication of a connected device and it has
+ * finished the link training process.
+ */
+ if ((sci_phy->is_in_link_training == false &&
+ state == SCI_BASE_PHY_STATE_INITIAL) ||
+ (sci_phy->is_in_link_training == false &&
+ state == SCI_BASE_PHY_STATE_STOPPED) ||
+ (sci_phy->is_in_link_training == true &&
+ state == SCI_BASE_PHY_STATE_STARTING)) {
+ is_controller_start_complete = false;
+ break;
}
+ }
- status = scic_sds_phy_start(the_phy);
-
- if (status == SCI_SUCCESS) {
- scic_sds_controller_phy_timer_start(this_controller);
- } else {
- dev_warn(scic_to_dev(this_controller),
- "%s: Controller stop operation failed "
- "to stop phy %d because of status "
- "%d.\n",
- __func__,
- this_controller->phy_table[this_controller->next_phy_to_start].phy_index,
- status);
+ /*
+ * The controller has successfully finished the start process.
+ * Inform the SCI Core user and transition to the READY state. */
+ if (is_controller_start_complete == true) {
+ scic_sds_controller_transition_to_ready(scic, SCI_SUCCESS);
+ scic_sds_controller_phy_timer_stop(scic);
+ }
+ } else {
+ sci_phy = &scic->phy_table[scic->next_phy_to_start];
+
+ if (oem->controller.mode_type == SCIC_PORT_MANUAL_CONFIGURATION_MODE) {
+ if (scic_sds_phy_get_port(sci_phy) == NULL) {
+ scic->next_phy_to_start++;
+
+ /* Caution recursion ahead be forwarned
+ *
+ * The PHY was never added to a PORT in MPC mode
+ * so start the next phy in sequence This phy
+ * will never go link up and will not draw power
+ * the OEM parameters either configured the phy
+ * incorrectly for the PORT or it was never
+ * assigned to a PORT
+ */
+ return scic_sds_controller_start_next_phy(scic);
}
+ }
- this_controller->next_phy_to_start++;
+ status = scic_sds_phy_start(sci_phy);
+
+ if (status == SCI_SUCCESS) {
+ scic_sds_controller_phy_timer_start(scic);
+ } else {
+ dev_warn(scic_to_dev(scic),
+ "%s: Controller stop operation failed "
+ "to stop phy %d because of status "
+ "%d.\n",
+ __func__,
+ scic->phy_table[scic->next_phy_to_start].phy_index,
+ status);
}
+
+ scic->next_phy_to_start++;
}
return status;
* ****************************************************************************- */
/**
+ * This function starts the power control timer for this controller object.
*
+ * @param scic
+ */
+static inline void scic_sds_controller_power_control_timer_start(
+ struct scic_sds_controller *scic)
+{
+ isci_timer_start(scic->power_control.timer,
+ SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL);
+
+ scic->power_control.timer_started = true;
+}
+
+/**
+ * This method stops the power control timer for this controller object.
*
- * This method starts the power control timer for this controller object.
+ * @param scic
*/
-static void scic_sds_controller_power_control_timer_start(
- struct scic_sds_controller *this_controller)
+static inline void scic_sds_controller_power_control_timer_stop(
+ struct scic_sds_controller *scic)
{
- scic_cb_timer_start(
- this_controller, this_controller->power_control.timer,
- SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL
- );
+ if (scic->power_control.timer_started) {
+ isci_timer_stop(scic->power_control.timer);
+ scic->power_control.timer_started = false;
+ }
+}
- this_controller->power_control.timer_started = true;
+/**
+ * This method stops and starts the power control timer for this controller
+ * object.
+ *
+ * @param scic
+ */
+static inline void scic_sds_controller_power_control_timer_restart(
+ struct scic_sds_controller *scic)
+{
+ scic_sds_controller_power_control_timer_stop(scic);
+ scic_sds_controller_power_control_timer_start(scic);
}
/**
this_controller = (struct scic_sds_controller *)controller;
+ this_controller->power_control.phys_granted_power = 0;
+
if (this_controller->power_control.phys_waiting == 0) {
this_controller->power_control.timer_started = false;
} else {
&& (this_controller->power_control.phys_waiting != 0);
i++) {
if (this_controller->power_control.requesters[i] != NULL) {
- the_phy = this_controller->power_control.requesters[i];
- this_controller->power_control.requesters[i] = NULL;
- this_controller->power_control.phys_waiting--;
- break;
+ if (this_controller->power_control.phys_granted_power <
+ this_controller->oem_parameters.sds1.controller.max_concurrent_dev_spin_up) {
+ the_phy = this_controller->power_control.requesters[i];
+ this_controller->power_control.requesters[i] = NULL;
+ this_controller->power_control.phys_waiting--;
+ this_controller->power_control.phys_granted_power++;
+ scic_sds_phy_consume_power_handler(the_phy);
+ } else {
+ break;
+ }
}
}
/*
* It doesn't matter if the power list is empty, we need to start the
- * timer in case another phy becomes ready. */
+ * timer in case another phy becomes ready.
+ */
scic_sds_controller_power_control_timer_start(this_controller);
-
- scic_sds_phy_consume_power_handler(the_phy);
}
}
{
BUG_ON(the_phy == NULL);
- if (
- (this_controller->power_control.timer_started)
- && (this_controller->power_control.requesters[the_phy->phy_index] == NULL)
- ) {
+ if (this_controller->power_control.phys_granted_power <
+ this_controller->oem_parameters.sds1.controller.max_concurrent_dev_spin_up) {
+ this_controller->power_control.phys_granted_power++;
+ scic_sds_phy_consume_power_handler(the_phy);
+
+ /*
+ * stop and start the power_control timer. When the timer fires, the
+ * no_of_phys_granted_power will be set to 0
+ */
+ scic_sds_controller_power_control_timer_restart(this_controller);
+ } else {
+ /* Add the phy in the waiting list */
this_controller->power_control.requesters[the_phy->phy_index] = the_phy;
this_controller->power_control.phys_waiting++;
- } else {
- scic_sds_controller_power_control_timer_start(this_controller);
- scic_sds_phy_consume_power_handler(the_phy);
}
}
break;
case SCU_COMPLETION_TYPE_UFI:
- scic_sds_controller_unsolicited_frame(this_controller, completion_entry);
- break;
-
- case SCU_COMPLETION_TYPE_EVENT:
- INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
- scic_sds_controller_event_completion(this_controller, completion_entry);
- break;
-
- case SCU_COMPLETION_TYPE_NOTIFY:
- /*
- * Presently we do the same thing with a notify event that we do with the
- * other event codes. */
- INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
- scic_sds_controller_event_completion(this_controller, completion_entry);
- break;
-
- default:
- dev_warn(scic_to_dev(this_controller),
- "%s: SCIC Controller received unknown "
- "completion type %x\n",
- __func__,
- completion_entry);
- break;
- }
- }
-
- /* Update the get register if we completed one or more entries */
- if (completion_count > 0) {
- this_controller->completion_queue_get =
- SMU_CQGR_GEN_BIT(ENABLE)
- | SMU_CQGR_GEN_BIT(EVENT_ENABLE)
- | event_cycle | SMU_CQGR_GEN_VAL(EVENT_POINTER, event_index)
- | get_cycle | SMU_CQGR_GEN_VAL(POINTER, get_index);
-
- SMU_CQGR_WRITE(this_controller,
- this_controller->completion_queue_get);
- }
-
- dev_dbg(scic_to_dev(this_controller),
- "%s: completion queue ending get:0x%08x\n",
- __func__,
- this_controller->completion_queue_get);
-
-}
-
-/**
- * This method is a private routine for processing the completion queue entries.
- * @this_controller:
- *
- */
-static void scic_sds_controller_transitioned_process_completions(
- struct scic_sds_controller *this_controller)
-{
- u32 completion_count = 0;
- u32 completion_entry;
- u32 get_index;
- u32 get_cycle;
- u32 event_index;
- u32 event_cycle;
-
- dev_dbg(scic_to_dev(this_controller),
- "%s: completion queue begining get:0x%08x\n",
- __func__,
- this_controller->completion_queue_get);
-
- /* Get the component parts of the completion queue */
- get_index = NORMALIZE_GET_POINTER(this_controller->completion_queue_get);
- get_cycle = SMU_CQGR_CYCLE_BIT & this_controller->completion_queue_get;
-
- event_index = NORMALIZE_EVENT_POINTER(this_controller->completion_queue_get);
- event_cycle = SMU_CQGR_EVENT_CYCLE_BIT & this_controller->completion_queue_get;
-
- while (
- NORMALIZE_GET_POINTER_CYCLE_BIT(get_cycle)
- == COMPLETION_QUEUE_CYCLE_BIT(
- this_controller->completion_queue[get_index])
- ) {
- completion_count++;
-
- completion_entry = this_controller->completion_queue[get_index];
- INCREMENT_COMPLETION_QUEUE_GET(this_controller, get_index, get_cycle);
-
- dev_dbg(scic_to_dev(this_controller),
- "%s: completion queue entry:0x%08x\n",
- __func__,
- completion_entry);
-
- switch (SCU_GET_COMPLETION_TYPE(completion_entry)) {
- case SCU_COMPLETION_TYPE_TASK:
- scic_sds_controller_task_completion(this_controller, completion_entry);
- break;
-
- case SCU_COMPLETION_TYPE_NOTIFY:
- case SCU_COMPLETION_TYPE_EVENT:
- /*
- * Presently we do the same thing with a notify event that we
- * do with the other event codes. */
- INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
- /* Fall-through */
-
- case SCU_COMPLETION_TYPE_SDMA:
- case SCU_COMPLETION_TYPE_UFI:
- default:
- dev_warn(scic_to_dev(this_controller),
- "%s: SCIC Controller ignoring completion type "
- "%x\n",
- __func__,
- completion_entry);
- break;
- }
- }
-
- /* Update the get register if we completed one or more entries */
- if (completion_count > 0) {
- this_controller->completion_queue_get =
- SMU_CQGR_GEN_BIT(ENABLE)
- | SMU_CQGR_GEN_BIT(EVENT_ENABLE)
- | event_cycle | SMU_CQGR_GEN_VAL(EVENT_POINTER, event_index)
- | get_cycle | SMU_CQGR_GEN_VAL(POINTER, get_index);
-
- SMU_CQGR_WRITE(this_controller, this_controller->completion_queue_get);
- }
-
- dev_dbg(scic_to_dev(this_controller),
- "%s: completion queue ending get:0x%08x\n",
- __func__,
- this_controller->completion_queue_get);
-}
-
-/*
- * ****************************************************************************-
- * * SCIC SDS Controller Interrupt and Completion functions
- * ****************************************************************************- */
-
-/**
- * This method provides standard (common) processing of interrupts for polling
- * and legacy based interrupts.
- * @controller:
- * @interrupt_status:
- *
- * This method returns a boolean (bool) indication as to whether an completions
- * are pending to be processed. true if an interrupt is to be processed false
- * if no interrupt was pending
- */
-static bool scic_sds_controller_standard_interrupt_handler(
- struct scic_sds_controller *this_controller,
- u32 interrupt_status)
-{
- bool is_completion_needed = false;
-
- if ((interrupt_status & SMU_ISR_QUEUE_ERROR) ||
- ((interrupt_status & SMU_ISR_QUEUE_SUSPEND) &&
- (!scic_sds_controller_completion_queue_has_entries(
- this_controller)))) {
- /*
- * We have a fatal error on the read of the completion queue bar
- * OR
- * We have a fatal error there is nothing in the completion queue
- * but we have a report from the hardware that the queue is full
- * / @todo how do we request the a controller reset */
- is_completion_needed = true;
- this_controller->encountered_fatal_error = true;
- }
-
- if (scic_sds_controller_completion_queue_has_entries(this_controller)) {
- is_completion_needed = true;
- }
-
- return is_completion_needed;
-}
-
-/**
- * This is the method provided to handle polling for interrupts for the
- * controller object.
- *
- * bool true if an interrupt is to be processed false if no interrupt was
- * pending
- */
-static bool scic_sds_controller_polling_interrupt_handler(
- struct scic_sds_controller *scic)
-{
- u32 interrupt_status;
-
- /*
- * In INTERRUPT_POLLING_MODE we exit the interrupt handler if the
- * hardware indicates nothing is pending. Since we are not being
- * called from a real interrupt, we don't want to confuse the hardware
- * by servicing the completion queue before the hardware indicates it
- * is ready. We'll simply wait for another polling interval and check
- * again.
- */
- interrupt_status = SMU_ISR_READ(scic);
- if ((interrupt_status &
- (SMU_ISR_COMPLETION |
- SMU_ISR_QUEUE_ERROR |
- SMU_ISR_QUEUE_SUSPEND)) == 0) {
- return false;
- }
-
- return scic_sds_controller_standard_interrupt_handler(
- scic, interrupt_status);
-}
-
-/**
- * This is the method provided to handle completions when interrupt polling is
- * in use.
- */
-static void scic_sds_controller_polling_completion_handler(
- struct scic_sds_controller *scic)
-{
- if (scic->encountered_fatal_error == true) {
- dev_err(scic_to_dev(scic),
- "%s: SCIC Controller has encountered a fatal error.\n",
- __func__);
-
- sci_base_state_machine_change_state(
- scic_sds_controller_get_base_state_machine(scic),
- SCI_BASE_CONTROLLER_STATE_FAILED);
- } else if (scic_sds_controller_completion_queue_has_entries(scic)) {
- if (scic->restrict_completions == false)
- scic_sds_controller_process_completions(scic);
- else
- scic_sds_controller_transitioned_process_completions(
- scic);
- }
-
- /*
- * The interrupt handler does not adjust the CQ's
- * get pointer. So, SCU's INTx pin stays asserted during the
- * interrupt handler even though it tries to clear the interrupt
- * source. Therefore, the completion handler must ensure that the
- * interrupt source is cleared. Otherwise, we get a spurious
- * interrupt for which the interrupt handler will not issue a
- * corresponding completion event. Also, we unmask interrupts.
- */
- SMU_ISR_WRITE(
- scic,
- (u32)(SMU_ISR_COMPLETION | SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND)
- );
-}
-
-/**
- * This is the method provided to handle legacy interrupts for the controller
- * object.
- *
- * bool true if an interrupt is processed false if no interrupt was processed
- */
-static bool scic_sds_controller_legacy_interrupt_handler(
- struct scic_sds_controller *scic)
-{
- u32 interrupt_status;
- bool is_completion_needed;
-
- interrupt_status = SMU_ISR_READ(scic);
- is_completion_needed = scic_sds_controller_standard_interrupt_handler(
- scic, interrupt_status);
-
- return is_completion_needed;
-}
-
-
-/**
- * This is the method provided to handle legacy completions it is expected that
- * the SCI User will call this completion handler anytime the interrupt
- * handler reports that it has handled an interrupt.
- */
-static void scic_sds_controller_legacy_completion_handler(
- struct scic_sds_controller *scic)
-{
- scic_sds_controller_polling_completion_handler(scic);
- SMU_IMR_WRITE(scic, 0x00000000);
-}
-
-/**
- * This is the method provided to handle an MSIX interrupt message when there
- * is just a single MSIX message being provided by the hardware. This mode
- * of operation is single vector mode.
- *
- * bool true if an interrupt is processed false if no interrupt was processed
- */
-static bool scic_sds_controller_single_vector_interrupt_handler(
- struct scic_sds_controller *scic)
-{
- u32 interrupt_status;
-
- /*
- * Mask the interrupts
- * There is a race in the hardware that could cause us not to be notified
- * of an interrupt completion if we do not take this step. We will unmask
- * the interrupts in the completion routine. */
- SMU_IMR_WRITE(scic, 0xFFFFFFFF);
-
- interrupt_status = SMU_ISR_READ(scic);
- interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
-
- if ((interrupt_status == 0) &&
- scic_sds_controller_completion_queue_has_entries(scic)) {
- /*
- * There is at least one completion queue entry to process so we can
- * return a success and ignore for now the case of an error interrupt */
- SMU_ISR_WRITE(scic, SMU_ISR_COMPLETION);
- return true;
- }
-
- if (interrupt_status != 0) {
- /*
- * There is an error interrupt pending so let it through and handle
- * in the callback */
- return true;
- }
-
- /*
- * Clear any offending interrupts since we could not find any to handle
- * and unmask them all */
- SMU_ISR_WRITE(scic, 0x00000000);
- SMU_IMR_WRITE(scic, 0x00000000);
-
- return false;
-}
-
-/**
- * This is the method provided to handle completions for a single MSIX message.
- */
-static void scic_sds_controller_single_vector_completion_handler(
- struct scic_sds_controller *scic)
-{
- u32 interrupt_status;
-
- interrupt_status = SMU_ISR_READ(scic);
- interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
-
- if (interrupt_status & SMU_ISR_QUEUE_ERROR) {
- dev_err(scic_to_dev(scic),
- "%s: SCIC Controller has encountered a fatal error.\n",
- __func__);
-
- /*
- * We have a fatal condition and must reset the controller
- * Leave the interrupt mask in place and get the controller reset */
- sci_base_state_machine_change_state(
- scic_sds_controller_get_base_state_machine(scic),
- SCI_BASE_CONTROLLER_STATE_FAILED);
- return;
- }
+ scic_sds_controller_unsolicited_frame(this_controller, completion_entry);
+ break;
- if ((interrupt_status & SMU_ISR_QUEUE_SUSPEND) &&
- !scic_sds_controller_completion_queue_has_entries(scic)) {
- dev_err(scic_to_dev(scic),
- "%s: SCIC Controller has encountered a fatal error.\n",
- __func__);
+ case SCU_COMPLETION_TYPE_EVENT:
+ INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
+ scic_sds_controller_event_completion(this_controller, completion_entry);
+ break;
- /*
- * We have a fatal condtion and must reset the controller
- * Leave the interrupt mask in place and get the controller reset */
- sci_base_state_machine_change_state(
- scic_sds_controller_get_base_state_machine(scic),
- SCI_BASE_CONTROLLER_STATE_FAILED);
- return;
+ case SCU_COMPLETION_TYPE_NOTIFY:
+ /*
+ * Presently we do the same thing with a notify event that we do with the
+ * other event codes. */
+ INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
+ scic_sds_controller_event_completion(this_controller, completion_entry);
+ break;
+
+ default:
+ dev_warn(scic_to_dev(this_controller),
+ "%s: SCIC Controller received unknown "
+ "completion type %x\n",
+ __func__,
+ completion_entry);
+ break;
+ }
}
- if (scic_sds_controller_completion_queue_has_entries(scic)) {
- scic_sds_controller_process_completions(scic);
+ /* Update the get register if we completed one or more entries */
+ if (completion_count > 0) {
+ this_controller->completion_queue_get =
+ SMU_CQGR_GEN_BIT(ENABLE)
+ | SMU_CQGR_GEN_BIT(EVENT_ENABLE)
+ | event_cycle | SMU_CQGR_GEN_VAL(EVENT_POINTER, event_index)
+ | get_cycle | SMU_CQGR_GEN_VAL(POINTER, get_index);
- /*
- * We dont care which interrupt got us to processing the completion queu
- * so clear them both. */
- SMU_ISR_WRITE(
- scic,
- (SMU_ISR_COMPLETION | SMU_ISR_QUEUE_SUSPEND));
+ SMU_CQGR_WRITE(this_controller,
+ this_controller->completion_queue_get);
}
- SMU_IMR_WRITE(scic, 0x00000000);
+ dev_dbg(scic_to_dev(this_controller),
+ "%s: completion queue ending get:0x%08x\n",
+ __func__,
+ this_controller->completion_queue_get);
+
}
-/**
- * This is the method provided to handle a MSIX message for a normal completion.
- *
- * bool true if an interrupt is processed false if no interrupt was processed
- */
bool scic_sds_controller_isr(struct scic_sds_controller *scic)
{
if (scic_sds_controller_completion_queue_has_entries(scic)) {
return false;
}
-/**
- * This is the method provided to handle the completions for a normal MSIX
- * message.
- */
void scic_sds_controller_completion_handler(struct scic_sds_controller *scic)
{
/* Empty out the completion queue */
SMU_IMR_WRITE(scic, 0x00000000);
}
-/**
- * This is the method provided to handle the error MSIX message interrupt.
- * This is the normal operating mode for the hardware if MSIX is enabled.
- *
- * bool true if an interrupt is processed false if no interrupt was processed
- */
-static bool scic_sds_controller_error_vector_interrupt_handler(
- struct scic_sds_controller *scic)
+bool scic_sds_controller_error_isr(struct scic_sds_controller *scic)
{
u32 interrupt_status;
interrupt_status = SMU_ISR_READ(scic);
+
interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
if (interrupt_status != 0) {
return false;
}
-/**
- * This is the method provided to handle the error completions when the
- * hardware is using two MSIX messages.
- */
-static void scic_sds_controller_error_vector_completion_handler(
- struct scic_sds_controller *scic)
+void scic_sds_controller_error_handler(struct scic_sds_controller *scic)
{
u32 interrupt_status;
SMU_ISR_WRITE(scic, SMU_ISR_QUEUE_SUSPEND);
} else {
- dev_err(scic_to_dev(scic),
- "%s: SCIC Controller reports CRC error on completion "
- "ISR %x\n",
- __func__,
+ dev_err(scic_to_dev(scic), "%s: status: %#x\n", __func__,
interrupt_status);
sci_base_state_machine_change_state(
}
-/*
- * ****************************************************************************-
- * * SCIC SDS Controller External Methods
- * ****************************************************************************- */
-
-/**
- * This method returns the sizeof the SCIC SDS Controller Object
- */
u32 scic_sds_controller_get_object_size(void)
{
return sizeof(struct scic_sds_controller);
if (link_up)
link_up(scic, sci_port, sci_phy);
else
- dev_warn(scic_to_dev(scic),
+ dev_dbg(scic_to_dev(scic),
"%s: SCIC Controller linkup event from phy %d in "
"unexpected state %d\n",
__func__,
if (link_down)
link_down(scic, sci_port, sci_phy);
else
- dev_warn(scic_to_dev(scic),
+ dev_dbg(scic_to_dev(scic),
"%s: SCIC Controller linkdown event from phy %d in "
"unexpected state %d\n",
__func__,
- sci_phy->phy_index,
- sci_base_state_machine_get_state(
- scic_sds_controller_get_base_state_machine(
- scic)));
+ sci_phy->phy_index, state);
+}
+
+/**
+ * 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 *scic,
+ struct scic_sds_remote_device *sci_dev)
+{
+ u32 state;
+ scic_sds_controller_device_handler_t started;
+
+ state = scic->parent.state_machine.current_state_id;
+ started = scic_sds_controller_state_handler_table[state].remote_device_started_handler;
+
+ if (started)
+ started(scic, sci_dev);
+ else {
+ dev_dbg(scic_to_dev(scic),
+ "%s: SCIC Controller 0x%p remote device started event "
+ "from device 0x%p in unexpected state %d\n",
+ __func__, scic, sci_dev, state);
+ }
+}
+
+/**
+ * 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 *scic,
+ struct scic_sds_remote_device *sci_dev)
+{
+
+ u32 state;
+ scic_sds_controller_device_handler_t stopped;
+
+ state = scic->parent.state_machine.current_state_id;
+ stopped = scic_sds_controller_state_handler_table[state].remote_device_stopped_handler;
+
+ if (stopped)
+ stopped(scic, sci_dev);
+ else {
+ dev_dbg(scic_to_dev(scic),
+ "%s: SCIC Controller 0x%p remote device stopped event "
+ "from device 0x%p in unexpected state %d\n",
+ __func__, scic, sci_dev, state);
+ }
}
+
+
/**
* This method will write to the SCU PCP register the request value. The method
* is used to suspend/resume ports, devices, and phys.
* This method sets user parameters and OEM parameters to default values.
* Users can override these values utilizing the scic_user_parameters_set()
* and scic_oem_parameters_set() methods.
- * @controller: This parameter specifies the controller for which to set the
+ * @scic: This parameter specifies the controller for which to set the
* configuration parameters to their default values.
*
*/
-static void scic_sds_controller_set_default_config_parameters(
- struct scic_sds_controller *this_controller)
+static void scic_sds_controller_set_default_config_parameters(struct scic_sds_controller *scic)
{
+ struct isci_host *ihost = sci_object_get_association(scic);
u16 index;
+ /* Default to APC mode. */
+ scic->oem_parameters.sds1.controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
+
+ /* Default to APC mode. */
+ scic->oem_parameters.sds1.controller.max_concurrent_dev_spin_up = 1;
+
/* Default to no SSC operation. */
- this_controller->oem_parameters.sds1.controller.do_enable_ssc = false;
+ scic->oem_parameters.sds1.controller.do_enable_ssc = false;
/* Initialize all of the port parameter information to narrow ports. */
for (index = 0; index < SCI_MAX_PORTS; index++) {
- this_controller->oem_parameters.sds1.ports[index].phy_mask = 0;
+ scic->oem_parameters.sds1.ports[index].phy_mask = 0;
}
/* Initialize all of the phy parameter information. */
for (index = 0; index < SCI_MAX_PHYS; index++) {
- /*
- * Default to 3G (i.e. Gen 2) for now. User can override if
- * they choose. */
- this_controller->user_parameters.sds1.phys[index].max_speed_generation = 2;
+ /* Default to 6G (i.e. Gen 3) for now. */
+ scic->user_parameters.sds1.phys[index].max_speed_generation = 3;
+
+ /* the frequencies cannot be 0 */
+ scic->user_parameters.sds1.phys[index].align_insertion_frequency = 0x7f;
+ scic->user_parameters.sds1.phys[index].in_connection_align_insertion_frequency = 0xff;
+ scic->user_parameters.sds1.phys[index].notify_enable_spin_up_insertion_frequency = 0x33;
/*
* Previous Vitesse based expanders had a arbitration issue that
* is worked around by having the upper 32-bits of SAS address
* with a value greater then the Vitesse company identifier.
* Hence, usage of 0x5FCFFFFF. */
- this_controller->oem_parameters.sds1.phys[index].sas_address.low
- = 0x00000001;
- this_controller->oem_parameters.sds1.phys[index].sas_address.high
- = 0x5FCFFFFF;
+ scic->oem_parameters.sds1.phys[index].sas_address.low = 0x1 + ihost->id;
+ scic->oem_parameters.sds1.phys[index].sas_address.high = 0x5FCFFFFF;
}
- this_controller->user_parameters.sds1.stp_inactivity_timeout = 5;
- this_controller->user_parameters.sds1.ssp_inactivity_timeout = 5;
- this_controller->user_parameters.sds1.stp_max_occupancy_timeout = 5;
- this_controller->user_parameters.sds1.ssp_max_occupancy_timeout = 20;
- this_controller->user_parameters.sds1.no_outbound_task_timeout = 5;
-
+ scic->user_parameters.sds1.stp_inactivity_timeout = 5;
+ scic->user_parameters.sds1.ssp_inactivity_timeout = 5;
+ scic->user_parameters.sds1.stp_max_occupancy_timeout = 5;
+ scic->user_parameters.sds1.ssp_max_occupancy_timeout = 20;
+ scic->user_parameters.sds1.no_outbound_task_timeout = 20;
}
/* Initialize the User and OEM parameters to default values. */
scic_sds_controller_set_default_config_parameters(controller);
- return SCI_SUCCESS;
+ return scic_controller_reset(controller);
}
/* --------------------------------------------------------------------------- */
* per interval - 1 (once OEM parameters are supported).
* Currently we assume only 1 phy per interval. */
- return (SCIC_SDS_SIGNATURE_FIS_TIMEOUT
+ return SCIC_SDS_SIGNATURE_FIS_TIMEOUT
+ SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT
- + ((SCI_MAX_PHYS - 1) * SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL));
+ + ((SCI_MAX_PHYS - 1) * SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL);
}
/* --------------------------------------------------------------------------- */
return status;
}
-/* --------------------------------------------------------------------------- */
-
-enum sci_status scic_controller_get_handler_methods(
- enum scic_interrupt_type interrupt_type,
- u16 message_count,
- struct scic_controller_handler_methods *handler_methods)
-{
- enum sci_status status = SCI_FAILURE_UNSUPPORTED_MESSAGE_COUNT;
-
- switch (interrupt_type) {
- case SCIC_LEGACY_LINE_INTERRUPT_TYPE:
- if (message_count == 0) {
- handler_methods[0].interrupt_handler
- = scic_sds_controller_legacy_interrupt_handler;
- handler_methods[0].completion_handler
- = scic_sds_controller_legacy_completion_handler;
-
- status = SCI_SUCCESS;
- }
- break;
-
- case SCIC_MSIX_INTERRUPT_TYPE:
- if (message_count == 1) {
- handler_methods[0].interrupt_handler
- = scic_sds_controller_single_vector_interrupt_handler;
- handler_methods[0].completion_handler
- = scic_sds_controller_single_vector_completion_handler;
-
- status = SCI_SUCCESS;
- } else if (message_count == 2) {
- handler_methods[0].interrupt_handler
- = scic_sds_controller_isr;
- handler_methods[0].completion_handler
- = scic_sds_controller_completion_handler;
-
- handler_methods[1].interrupt_handler
- = scic_sds_controller_error_vector_interrupt_handler;
- handler_methods[1].completion_handler
- = scic_sds_controller_error_vector_completion_handler;
-
- status = SCI_SUCCESS;
- }
- break;
-
- case SCIC_NO_INTERRUPTS:
- if (message_count == 0) {
-
- handler_methods[0].interrupt_handler
- = scic_sds_controller_polling_interrupt_handler;
- handler_methods[0].completion_handler
- = scic_sds_controller_polling_completion_handler;
-
- status = SCI_SUCCESS;
- }
- break;
-
- default:
- status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
- break;
- }
-
- return status;
-}
-
-/* --------------------------------------------------------------------------- */
-
enum sci_io_status scic_controller_start_io(
struct scic_sds_controller *scic,
struct scic_sds_remote_device *remote_device,
SMU_SMUSRCR_WRITE(scic, 0xFFFFFFFF);
/* Delay for 1ms to before clearing the CQP and UFQPR. */
- scic_cb_stall_execution(1000);
+ udelay(1000);
/* The write to the CQGR clears the CQP */
SMU_CQGR_WRITE(scic, 0x00000000);
struct scic_sds_controller *scic,
union scic_user_parameters *scic_parms)
{
- if (
- (scic->parent.state_machine.current_state_id
- == SCI_BASE_CONTROLLER_STATE_RESET)
- || (scic->parent.state_machine.current_state_id
- == SCI_BASE_CONTROLLER_STATE_INITIALIZING)
- || (scic->parent.state_machine.current_state_id
- == SCI_BASE_CONTROLLER_STATE_INITIALIZED)
- ) {
+ u32 state = scic->parent.state_machine.current_state_id;
+
+ if (state == SCI_BASE_CONTROLLER_STATE_RESET ||
+ state == SCI_BASE_CONTROLLER_STATE_INITIALIZING ||
+ state == SCI_BASE_CONTROLLER_STATE_INITIALIZED) {
u16 index;
/*
* Validate the user parameters. If they are not legal, then
- * return a failure. */
+ * return a failure.
+ */
for (index = 0; index < SCI_MAX_PHYS; index++) {
- if (!
- (scic_parms->sds1.phys[index].max_speed_generation
- <= SCIC_SDS_PARM_MAX_SPEED
- && scic_parms->sds1.phys[index].max_speed_generation
- > SCIC_SDS_PARM_NO_SPEED
- )
- )
+ struct sci_phy_user_params *user_phy;
+
+ user_phy = &scic_parms->sds1.phys[index];
+
+ if (!((user_phy->max_speed_generation <=
+ SCIC_SDS_PARM_MAX_SPEED) &&
+ (user_phy->max_speed_generation >
+ SCIC_SDS_PARM_NO_SPEED)))
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ if (user_phy->in_connection_align_insertion_frequency <
+ 3)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ if ((user_phy->in_connection_align_insertion_frequency <
+ 3) ||
+ (user_phy->align_insertion_frequency == 0) ||
+ (user_phy->
+ notify_enable_spin_up_insertion_frequency ==
+ 0))
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
+ if ((scic_parms->sds1.stp_inactivity_timeout == 0) ||
+ (scic_parms->sds1.ssp_inactivity_timeout == 0) ||
+ (scic_parms->sds1.stp_max_occupancy_timeout == 0) ||
+ (scic_parms->sds1.ssp_max_occupancy_timeout == 0) ||
+ (scic_parms->sds1.no_outbound_task_timeout == 0))
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
memcpy(&scic->user_parameters, scic_parms, sizeof(*scic_parms));
return SCI_SUCCESS;
struct scic_sds_controller *scic,
union scic_oem_parameters *scic_parms)
{
- if (
- (scic->parent.state_machine.current_state_id
- == SCI_BASE_CONTROLLER_STATE_RESET)
- || (scic->parent.state_machine.current_state_id
- == SCI_BASE_CONTROLLER_STATE_INITIALIZING)
- || (scic->parent.state_machine.current_state_id
- == SCI_BASE_CONTROLLER_STATE_INITIALIZED)
- ) {
+ u32 state = scic->parent.state_machine.current_state_id;
+
+ if (state == SCI_BASE_CONTROLLER_STATE_RESET ||
+ state == SCI_BASE_CONTROLLER_STATE_INITIALIZING ||
+ state == SCI_BASE_CONTROLLER_STATE_INITIALIZED) {
u16 index;
+ u8 combined_phy_mask = 0;
/*
* Validate the oem parameters. If they are not legal, then
* return a failure. */
for (index = 0; index < SCI_MAX_PORTS; index++) {
- if (scic_parms->sds1.ports[index].phy_mask > SCIC_SDS_PARM_PHY_MASK_MAX) {
+ if (scic_parms->sds1.ports[index].phy_mask > SCIC_SDS_PARM_PHY_MASK_MAX)
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
- }
}
for (index = 0; index < SCI_MAX_PHYS; index++) {
- if (
- scic_parms->sds1.phys[index].sas_address.high == 0
- && scic_parms->sds1.phys[index].sas_address.low == 0
- ) {
+ if ((scic_parms->sds1.phys[index].sas_address.high == 0) &&
+ (scic_parms->sds1.phys[index].sas_address.low == 0))
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
- }
}
- memcpy(&scic->oem_parameters, scic_parms, sizeof(*scic_parms));
+ if (scic_parms->sds1.controller.mode_type ==
+ SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE) {
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ if (scic_parms->sds1.ports[index].phy_mask != 0)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+ } else if (scic_parms->sds1.controller.mode_type ==
+ SCIC_PORT_MANUAL_CONFIGURATION_MODE) {
+ for (index = 0; index < SCI_MAX_PHYS; index++)
+ combined_phy_mask |= scic_parms->sds1.ports[index].phy_mask;
+
+ if (combined_phy_mask == 0)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ } else
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ if (scic_parms->sds1.controller.max_concurrent_dev_spin_up >
+ MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ scic->oem_parameters.sds1 = scic_parms->sds1;
+
return SCI_SUCCESS;
}
* * RESET STATE HANDLERS
* ***************************************************************************** */
-/**
- *
- * @controller: This is the struct sci_base_controller object which is cast into a
- * struct scic_sds_controller object.
- *
- * This method is the struct scic_sds_controller initialize handler for the reset
- * state. - Currently this function does nothing enum sci_status SCI_FAILURE This
- * function is not yet implemented and is a valid request from the reset state.
- */
-static enum sci_status scic_sds_controller_reset_state_initialize_handler(
- struct sci_base_controller *controller)
+static enum sci_status scic_sds_controller_reset_state_initialize_handler(struct sci_base_controller *base_scic)
{
- u32 index;
enum sci_status result = SCI_SUCCESS;
- struct scic_sds_controller *this_controller;
+ struct scic_sds_controller *scic;
+ struct isci_host *ihost;
+ u32 index;
- this_controller = (struct scic_sds_controller *)controller;
+ scic = container_of(base_scic, typeof(*scic), parent);
+ ihost = sci_object_get_association(scic);
sci_base_state_machine_change_state(
- scic_sds_controller_get_base_state_machine(this_controller),
- SCI_BASE_CONTROLLER_STATE_INITIALIZING
- );
+ scic_sds_controller_get_base_state_machine(scic),
+ SCI_BASE_CONTROLLER_STATE_INITIALIZING);
- this_controller->timeout_timer = scic_cb_timer_create(
- this_controller,
- (void (*)(void *))scic_sds_controller_timeout_handler,
- (void (*)(void *))controller);
+ scic->timeout_timer = isci_timer_create(ihost,
+ scic,
+ scic_sds_controller_timeout_handler);
- scic_sds_controller_initialize_phy_startup(this_controller);
+ scic_sds_controller_initialize_phy_startup(scic);
- scic_sds_controller_initialize_power_control(this_controller);
+ scic_sds_controller_initialize_power_control(scic);
/*
* There is nothing to do here for B0 since we do not have to
* program the AFE registers.
* / @todo The AFE settings are supposed to be correct for the B0 but
* / presently they seem to be wrong. */
- scic_sds_controller_afe_initialization(this_controller);
+ scic_sds_controller_afe_initialization(scic);
- if (SCI_SUCCESS == result) {
+ if (result == SCI_SUCCESS) {
u32 status;
u32 terminate_loop;
/* Take the hardware out of reset */
- SMU_SMUSRCR_WRITE(this_controller, 0x00000000);
+ SMU_SMUSRCR_WRITE(scic, 0x00000000);
/*
* / @todo Provide meaningfull error code for hardware failure
while (terminate_loop-- && (result != SCI_SUCCESS)) {
/* Loop until the hardware reports success */
- scic_cb_stall_execution(SCU_CONTEXT_RAM_INIT_STALL_TIME);
- status = SMU_SMUCSR_READ(this_controller);
+ udelay(SCU_CONTEXT_RAM_INIT_STALL_TIME);
+ status = SMU_SMUCSR_READ(scic);
- if ((status & SCU_RAM_INIT_COMPLETED) == SCU_RAM_INIT_COMPLETED) {
+ if ((status & SCU_RAM_INIT_COMPLETED) ==
+ SCU_RAM_INIT_COMPLETED)
result = SCI_SUCCESS;
- }
}
}
/*
* Determine what are the actaul device capacities that the
* hardware will support */
- device_context_capacity = SMU_DCC_READ(this_controller);
+ device_context_capacity = SMU_DCC_READ(scic);
- max_supported_ports =
- smu_dcc_get_max_ports(device_context_capacity);
- max_supported_devices =
- smu_dcc_get_max_remote_node_context(device_context_capacity);
- max_supported_io_requests =
- smu_dcc_get_max_task_context(device_context_capacity);
+ max_supported_ports = smu_dcc_get_max_ports(device_context_capacity);
+ max_supported_devices = smu_dcc_get_max_remote_node_context(device_context_capacity);
+ max_supported_io_requests = smu_dcc_get_max_task_context(device_context_capacity);
- /* Make all PEs that are unassigned match up with the logical ports */
+ /*
+ * Make all PEs that are unassigned match up with the
+ * logical ports
+ */
for (index = 0; index < max_supported_ports; index++) {
- scu_register_write(
- this_controller,
- this_controller->scu_registers->peg0.ptsg.protocol_engine[index],
- index
- );
+ struct scu_port_task_scheduler_group_registers *ptsg =
+ &scic->scu_registers->peg0.ptsg;
+
+ scu_register_write(scic,
+ ptsg->protocol_engine[index],
+ index);
}
/* Record the smaller of the two capacity values */
- this_controller->logical_port_entries =
- min(max_supported_ports, this_controller->logical_port_entries);
+ scic->logical_port_entries =
+ min(max_supported_ports, scic->logical_port_entries);
- this_controller->task_context_entries =
- min(max_supported_io_requests, this_controller->task_context_entries);
+ scic->task_context_entries =
+ min(max_supported_io_requests,
+ scic->task_context_entries);
- this_controller->remote_node_entries =
- min(max_supported_devices, this_controller->remote_node_entries);
+ scic->remote_node_entries =
+ min(max_supported_devices, scic->remote_node_entries);
/*
* Now that we have the correct hardware reported minimum values
* build the MDL for the controller. Default to a performance
- * configuration. */
- scic_controller_set_mode(this_controller, SCI_MODE_SPEED);
+ * configuration.
+ */
+ scic_controller_set_mode(scic, SCI_MODE_SPEED);
}
/* Initialize hardware PCI Relaxed ordering in DMA engines */
u32 dma_configuration;
/* Configure the payload DMA */
- dma_configuration = SCU_PDMACR_READ(this_controller);
- dma_configuration |= SCU_PDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
- SCU_PDMACR_WRITE(this_controller, dma_configuration);
+ dma_configuration = SCU_PDMACR_READ(scic);
+ dma_configuration |=
+ SCU_PDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
+ SCU_PDMACR_WRITE(scic, dma_configuration);
/* Configure the control DMA */
- dma_configuration = SCU_CDMACR_READ(this_controller);
- dma_configuration |= SCU_CDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
- SCU_CDMACR_WRITE(this_controller, dma_configuration);
+ dma_configuration = SCU_CDMACR_READ(scic);
+ dma_configuration |=
+ SCU_CDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
+ SCU_CDMACR_WRITE(scic, dma_configuration);
}
/*
* Initialize the PHYs before the PORTs because the PHY registers
- * are accessed during the port initialization. */
+ * are accessed during the port initialization.
+ */
if (result == SCI_SUCCESS) {
/* Initialize the phys */
for (index = 0;
(result == SCI_SUCCESS) && (index < SCI_MAX_PHYS);
index++) {
result = scic_sds_phy_initialize(
- &this_controller->phy_table[index],
- &this_controller->scu_registers->peg0.pe[index].ll
- );
+ &scic->phy_table[index],
+ &scic->scu_registers->peg0.pe[index].tl,
+ &scic->scu_registers->peg0.pe[index].ll);
}
}
if (result == SCI_SUCCESS) {
/* Initialize the logical ports */
for (index = 0;
- (index < this_controller->logical_port_entries)
- && (result == SCI_SUCCESS);
+ (index < scic->logical_port_entries) &&
+ (result == SCI_SUCCESS);
index++) {
result = scic_sds_port_initialize(
- &this_controller->port_table[index],
- &this_controller->scu_registers->peg0.pe[index].tl,
- &this_controller->scu_registers->peg0.ptsg.port[index],
- &this_controller->scu_registers->peg0.ptsg.protocol_engine,
- &this_controller->scu_registers->peg0.viit[index]
- );
+ &scic->port_table[index],
+ &scic->scu_registers->peg0.ptsg.port[index],
+ &scic->scu_registers->peg0.ptsg.protocol_engine,
+ &scic->scu_registers->peg0.viit[index]);
}
}
- if (SCI_SUCCESS == result) {
+ if (result == SCI_SUCCESS)
result = scic_sds_port_configuration_agent_initialize(
- this_controller,
- &this_controller->port_agent
- );
- }
+ scic,
+ &scic->port_agent);
/* Advance the controller state machine */
- if (result == SCI_SUCCESS) {
+ if (result == SCI_SUCCESS)
sci_base_state_machine_change_state(
- scic_sds_controller_get_base_state_machine(this_controller),
- SCI_BASE_CONTROLLER_STATE_INITIALIZED
- );
- } else {
+ scic_sds_controller_get_base_state_machine(scic),
+ SCI_BASE_CONTROLLER_STATE_INITIALIZED);
+ else
sci_base_state_machine_change_state(
- scic_sds_controller_get_base_state_machine(this_controller),
- SCI_BASE_CONTROLLER_STATE_FAILED
- );
- }
+ scic_sds_controller_get_base_state_machine(scic),
+ SCI_BASE_CONTROLLER_STATE_FAILED);
return result;
}
/**
*
- * @controller: This is the struct sci_base_controller object which is cast into a
- * struct scic_sds_controller object.
+ * @controller: This is the struct sci_base_controller object which is cast
+ * into a struct scic_sds_controller object.
* @timeout: This is the allowed time for the controller object to reach the
* started state.
*
- * This method is the struct scic_sds_controller start handler for the initialized
- * state. - Validate we have a good memory descriptor table - Initialze the
+ * This function is the struct scic_sds_controller start handler for the
+ * initialized state.
+ * - Validate we have a good memory descriptor table - Initialze the
* physical memory before programming the hardware - Program the SCU hardware
* with the physical memory addresses passed in the memory descriptor table. -
* Initialzie the TCi pool - Initialize the RNi pool - Initialize the
{
u16 index;
enum sci_status result;
- struct scic_sds_controller *this_controller;
+ struct scic_sds_controller *scic;
- this_controller = (struct scic_sds_controller *)controller;
+ scic = (struct scic_sds_controller *)controller;
- /* Make sure that the SCI User filled in the memory descriptor table correctly */
- result = scic_sds_controller_validate_memory_descriptor_table(this_controller);
+ /*
+ * Make sure that the SCI User filled in the memory descriptor
+ * table correctly
+ */
+ result = scic_sds_controller_validate_memory_descriptor_table(scic);
if (result == SCI_SUCCESS) {
- /* The memory descriptor list looks good so program the hardware */
- scic_sds_controller_ram_initialization(this_controller);
+ /*
+ * The memory descriptor list looks good so program the
+ * hardware
+ */
+ scic_sds_controller_ram_initialization(scic);
}
- if (SCI_SUCCESS == result) {
+ if (result == SCI_SUCCESS) {
/* Build the TCi free pool */
- sci_pool_initialize(this_controller->tci_pool);
- for (index = 0; index < this_controller->task_context_entries; index++) {
- sci_pool_put(this_controller->tci_pool, index);
- }
+ sci_pool_initialize(scic->tci_pool);
+ for (index = 0; index < scic->task_context_entries; index++)
+ sci_pool_put(scic->tci_pool, index);
/* Build the RNi free pool */
scic_sds_remote_node_table_initialize(
- &this_controller->available_remote_nodes,
- this_controller->remote_node_entries
- );
+ &scic->available_remote_nodes,
+ scic->remote_node_entries);
}
- if (SCI_SUCCESS == result) {
+ if (result == SCI_SUCCESS) {
/*
- * Before anything else lets make sure we will not be interrupted
- * by the hardware. */
- scic_controller_disable_interrupts(this_controller);
+ * Before anything else lets make sure we will not be
+ * interrupted by the hardware.
+ */
+ scic_controller_disable_interrupts(scic);
/* Enable the port task scheduler */
- scic_sds_controller_enable_port_task_scheduler(this_controller);
+ scic_sds_controller_enable_port_task_scheduler(scic);
- /* Assign all the task entries to this controller physical function */
- scic_sds_controller_assign_task_entries(this_controller);
+ /* Assign all the task entries to scic physical function */
+ scic_sds_controller_assign_task_entries(scic);
/* Now initialze the completion queue */
- scic_sds_controller_initialize_completion_queue(this_controller);
+ scic_sds_controller_initialize_completion_queue(scic);
/* Initialize the unsolicited frame queue for use */
- scic_sds_controller_initialize_unsolicited_frame_queue(this_controller);
+ scic_sds_controller_initialize_unsolicited_frame_queue(scic);
+ }
+
+ /* Start all of the ports on this controller */
+ for (index = 0;
+ (index < scic->logical_port_entries) && (result == SCI_SUCCESS);
+ index++) {
+ struct scic_sds_port *sci_port = &scic->port_table[index];
+
+ result = sci_port->state_handlers->parent.start_handler(
+ &sci_port->parent);
}
- if (SCI_SUCCESS == result) {
- scic_sds_controller_start_next_phy(this_controller);
+ if (result == SCI_SUCCESS) {
+ scic_sds_controller_start_next_phy(scic);
- scic_cb_timer_start(this_controller,
- this_controller->timeout_timer,
- timeout);
+ isci_timer_start(scic->timeout_timer, timeout);
sci_base_state_machine_change_state(
- scic_sds_controller_get_base_state_machine(this_controller),
- SCI_BASE_CONTROLLER_STATE_STARTING
- );
+ scic_sds_controller_get_base_state_machine(scic),
+ SCI_BASE_CONTROLLER_STATE_STARTING);
}
return result;
struct sci_base_controller *controller,
u32 timeout)
{
- struct scic_sds_controller *this_controller;
-
- this_controller = (struct scic_sds_controller *)controller;
+ struct scic_sds_controller *scic =
+ (struct scic_sds_controller *)controller;
- scic_cb_timer_start(this_controller,
- this_controller->timeout_timer,
- timeout);
+ isci_timer_start(scic->timeout_timer, timeout);
sci_base_state_machine_change_state(
- scic_sds_controller_get_base_state_machine(this_controller),
- SCI_BASE_CONTROLLER_STATE_STOPPING
- );
+ scic_sds_controller_get_base_state_machine(scic),
+ SCI_BASE_CONTROLLER_STATE_STOPPING);
return SCI_SUCCESS;
}
* 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] = {
.terminate_request = scic_sds_controller_default_request_handler,
},
[SCI_BASE_CONTROLLER_STATE_RESET] = {
+ .base.reset = scic_sds_controller_general_reset_handler,
.base.initialize = scic_sds_controller_reset_state_initialize_handler,
.base.start_io = scic_sds_controller_default_start_operation_handler,
.base.complete_io = scic_sds_controller_default_request_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,
* from the SCI_BASE_CONTROLLER_STATE_STARTING. - This function stops the
* controller starting timeout timer. none
*/
-static void scic_sds_controller_starting_state_exit(
+static inline void scic_sds_controller_starting_state_exit(
struct sci_base_object *object)
{
struct scic_sds_controller *scic = (struct scic_sds_controller *)object;
- scic_cb_timer_stop(scic, scic->timeout_timer);
+ isci_timer_stop(scic->timeout_timer);
}
/**
/**
*
- * @object: This is the struct sci_base_object which is cast to a struct scic_sds_controller
- * object.
+ * @object: This is the struct sci_base_object which is cast to a struct
+ * scic_sds_controller object.
*
- * This method implements the actions taken by the struct scic_sds_controller on exit
- * from the SCI_BASE_CONTROLLER_STATE_STOPPING. - This function stops the
- * controller stopping timeout timer. none
+ * This funciton implements the actions taken by the struct scic_sds_controller
+ * on exit from the SCI_BASE_CONTROLLER_STATE_STOPPING. -
+ * This function stops the controller stopping timeout timer.
*/
-static void scic_sds_controller_stopping_state_exit(
+static inline void scic_sds_controller_stopping_state_exit(
struct sci_base_object *object)
{
- struct scic_sds_controller *this_controller;
-
- this_controller = (struct scic_sds_controller *)object;
+ struct scic_sds_controller *scic =
+ (struct scic_sds_controller *)object;
- scic_cb_timer_stop(this_controller, this_controller->timeout_timer);
+ isci_timer_stop(scic->timeout_timer);
}
/**