summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenryk Dembkowski <Henryk.Dembkowski@intel.com>2011-02-24 03:55:11 +0300
committerDan Williams <dan.j.williams@intel.com>2011-07-03 14:55:30 +0400
commit07373a5caa29e4159ef1ea5e72985ddaf013519a (patch)
tree0ea13c0ede1012dec6e6d491ed181418e62453ee
parent8db37aabaceb3dcd18754c1e782d4474e4052c81 (diff)
downloadlinux-07373a5caa29e4159ef1ea5e72985ddaf013519a.tar.xz
isci: add support for 2 more oem parmeters
1/ add OEM paramater support for mode_type (MPC vs APC) 2/ add OEM parameter support for max_number_concurrent_device_spin_up 3/ cleanup scic_sds_controller_start_next_phy todo: hook up the amp control afe parameters into the afe init code Signed-off-by: Henryk Dembkowski <henryk.dembkowski@intel.com> Signed-off-by: Jacek Danecki <Jacek.Danecki@intel.com> [cleaned up scic_sds_controller_start_next_phy] Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--drivers/scsi/isci/core/scic_config_parameters.h3
-rw-r--r--drivers/scsi/isci/core/scic_sds_controller.c271
-rw-r--r--drivers/scsi/isci/core/scic_sds_controller.h30
-rw-r--r--drivers/scsi/isci/core/scic_sds_port_configuration_agent.c2
-rw-r--r--drivers/scsi/isci/firmware/create_fw.h7
-rw-r--r--drivers/scsi/isci/probe_roms.h14
-rw-r--r--firmware/isci/isci_firmware.bin.ihex4
7 files changed, 176 insertions, 155 deletions
diff --git a/drivers/scsi/isci/core/scic_config_parameters.h b/drivers/scsi/isci/core/scic_config_parameters.h
index 5e1345daf014..f64f24fad5a3 100644
--- a/drivers/scsi/isci/core/scic_config_parameters.h
+++ b/drivers/scsi/isci/core/scic_config_parameters.h
@@ -224,6 +224,8 @@ union scic_user_parameters {
*/
#define SCIC_SDS_PARM_PHY_MASK_MAX 0xF
+#define MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT 4
+
/**
* This structure/union specifies the various different OEM parameter sets
* available. Each type is specific to a hardware controller version.
@@ -237,7 +239,6 @@ union scic_oem_parameters {
* 1.
*/
struct scic_sds_oem_params sds1;
-
};
/**
diff --git a/drivers/scsi/isci/core/scic_sds_controller.c b/drivers/scsi/isci/core/scic_sds_controller.c
index e7f3711b4afc..12b2ad5a28b0 100644
--- a/drivers/scsi/isci/core/scic_sds_controller.c
+++ b/drivers/scsi/isci/core/scic_sds_controller.c
@@ -293,6 +293,7 @@ void scic_sds_controller_initialize_power_control(
);
this_controller->power_control.phys_waiting = 0;
+ this_controller->power_control.phys_granted_power = 0;
}
/* --------------------------------------------------------------------------- */
@@ -770,31 +771,6 @@ void scic_sds_controller_timeout_handler(
__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;
@@ -859,7 +835,7 @@ void scic_sds_controller_phy_timer_stop(
/**
* 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
@@ -867,101 +843,88 @@ void scic_sds_controller_phy_timer_stop(
*
* 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);
+ 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;
}
- } 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);
- }
+ /*
+ * 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);
}
+ }
- status = scic_sds_phy_start(the_phy);
+ status = scic_sds_phy_start(sci_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);
- }
-
- this_controller->next_phy_to_start++;
+ 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;
@@ -1059,6 +1022,31 @@ static void scic_sds_controller_power_control_timer_start(
}
/**
+ * This method stops the power control timer for this controller object.
+ *
+ * @param scic
+ */
+void scic_sds_controller_power_control_timer_stop(struct scic_sds_controller *scic)
+{
+ if (scic->power_control.timer_started) {
+ isci_event_timer_stop(scic, scic->power_control.timer);
+ scic->power_control.timer_started = false;
+ }
+}
+
+/**
+ * This method stops and starts the power control timer for this controller object.
+ *
+ * @param scic
+ */
+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);
+}
+
+/**
*
*
*
@@ -1070,6 +1058,8 @@ static void scic_sds_controller_power_control_timer_handler(
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 {
@@ -1081,19 +1071,24 @@ static void scic_sds_controller_power_control_timer_handler(
&& (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);
}
}
@@ -1109,15 +1104,20 @@ void scic_sds_controller_power_control_queue_insert(
{
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);
}
}
@@ -2021,7 +2021,7 @@ void scic_sds_controller_release_frame(
* 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.
*
*/
@@ -2029,6 +2029,12 @@ static void scic_sds_controller_set_default_config_parameters(struct scic_sds_co
{
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. */
scic->oem_parameters.sds1.controller.do_enable_ssc = false;
@@ -2607,6 +2613,7 @@ enum sci_status scic_oem_parameters_set(
== SCI_BASE_CONTROLLER_STATE_INITIALIZED)
) {
u16 index;
+ u8 combined_phy_mask = 0;
/*
* Validate the oem parameters. If they are not legal, then
@@ -2626,6 +2633,24 @@ enum sci_status scic_oem_parameters_set(
}
}
+ 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;
+
memcpy(&scic->oem_parameters, scic_parms, sizeof(*scic_parms));
return SCI_SUCCESS;
}
diff --git a/drivers/scsi/isci/core/scic_sds_controller.h b/drivers/scsi/isci/core/scic_sds_controller.h
index 9b8e55d62910..6386a64896c0 100644
--- a/drivers/scsi/isci/core/scic_sds_controller.h
+++ b/drivers/scsi/isci/core/scic_sds_controller.h
@@ -122,23 +122,6 @@ enum SCIC_SDS_CONTROLLER_MEMORY_DESCRIPTORS {
/**
- *
- *
- * Allowed PORT configuration modes APC Automatic PORT configuration mode is
- * defined by the OEM configuration parameters providing no PHY_MASK parameters
- * for any PORT. i.e. There are no phys assigned to any of the ports at start.
- * MPC Manual PORT configuration mode is defined by the OEM configuration
- * parameters providing a PHY_MASK value for any PORT. It is assumed that any
- * PORT with no PHY_MASK is an invalid port and not all PHYs must be assigned.
- * A PORT_PHY mask that assigns just a single PHY to a port and no other PHYs
- * being assigned is sufficient to declare manual PORT configuration.
- */
-enum SCIC_PORT_CONFIGURATION_MODE {
- SCIC_PORT_MANUAL_CONFIGURATION_MODE,
- SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE
-};
-
-/**
* struct scic_power_control -
*
* This structure defines the fields for managing power control for direct
@@ -164,6 +147,11 @@ struct scic_power_control {
u8 phys_waiting;
/**
+ * This field is used to keep track of how many phys have been granted to consume power
+ */
+ u8 phys_granted_power;
+
+ /**
* This field is an array of phys that we are waiting on. The phys are direct
* mapped into requesters via struct scic_sds_phy.phy_index
*/
@@ -560,14 +548,6 @@ u32 scic_sds_controller_get_object_size(void);
/* --------------------------------------------------------------------------- */
-
-/* --------------------------------------------------------------------------- */
-
-enum SCIC_PORT_CONFIGURATION_MODE scic_sds_controller_get_port_configuration_mode(
- struct scic_sds_controller *this_controller);
-
-/* --------------------------------------------------------------------------- */
-
void scic_sds_controller_post_request(
struct scic_sds_controller *this_controller,
u32 request);
diff --git a/drivers/scsi/isci/core/scic_sds_port_configuration_agent.c b/drivers/scsi/isci/core/scic_sds_port_configuration_agent.c
index e26a4e69b3ac..7c9521049ae7 100644
--- a/drivers/scsi/isci/core/scic_sds_port_configuration_agent.c
+++ b/drivers/scsi/isci/core/scic_sds_port_configuration_agent.c
@@ -822,7 +822,7 @@ enum sci_status scic_sds_port_configuration_agent_initialize(
enum sci_status status = SCI_SUCCESS;
enum SCIC_PORT_CONFIGURATION_MODE mode;
- mode = scic_sds_controller_get_port_configuration_mode(controller);
+ mode = controller->oem_parameters.sds1.controller.mode_type;
if (mode == SCIC_PORT_MANUAL_CONFIGURATION_MODE) {
status = scic_sds_mpc_agent_validate_phy_configuration(controller, port_agent);
diff --git a/drivers/scsi/isci/firmware/create_fw.h b/drivers/scsi/isci/firmware/create_fw.h
index bedbe4fad181..788a8de0c2bc 100644
--- a/drivers/scsi/isci/firmware/create_fw.h
+++ b/drivers/scsi/isci/firmware/create_fw.h
@@ -1,5 +1,6 @@
#ifndef _CREATE_FW_H_
#define _CREATE_FW_H_
+#include "../probe_roms.h"
/* we are configuring for 2 SCUs */
@@ -24,16 +25,16 @@ static const int num_elements = 2;
* if there is a port/phy on which you do not wish to override the default
* values, use the value assigned to UNINIT_PARAM (255).
*/
+/* discovery mode type (port auto config mode by default ) */
#ifdef MPC
+static const int mode_type = SCIC_PORT_MANUAL_CONFIGURATION_MODE;
static const __u8 phy_mask[2][4] = { {1, 2, 4, 8},
{1, 2, 4, 8} };
#else /* APC (default) */
+static const int mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
static const __u8 phy_mask[2][4];
#endif
-/* discovery mode type (port auto config mode by default ) */
-static const int mode_type;
-
/* Maximum number of concurrent device spin up */
static const int max_num_concurrent_dev_spin_up = 1;
diff --git a/drivers/scsi/isci/probe_roms.h b/drivers/scsi/isci/probe_roms.h
index 96d8b9212457..69526ffa8474 100644
--- a/drivers/scsi/isci/probe_roms.h
+++ b/drivers/scsi/isci/probe_roms.h
@@ -86,6 +86,20 @@ struct isci_orom *isci_get_efi_var(struct pci_dev *pdev);
#define ISCI_EFI_ATTRIBUTES 0
#define ISCI_EFI_VAR_NAME "isci_oemb"
+/* Allowed PORT configuration modes APC Automatic PORT configuration mode is
+ * defined by the OEM configuration parameters providing no PHY_MASK parameters
+ * for any PORT. i.e. There are no phys assigned to any of the ports at start.
+ * MPC Manual PORT configuration mode is defined by the OEM configuration
+ * parameters providing a PHY_MASK value for any PORT. It is assumed that any
+ * PORT with no PHY_MASK is an invalid port and not all PHYs must be assigned.
+ * A PORT_PHY mask that assigns just a single PHY to a port and no other PHYs
+ * being assigned is sufficient to declare manual PORT configuration.
+ */
+enum SCIC_PORT_CONFIGURATION_MODE {
+ SCIC_PORT_MANUAL_CONFIGURATION_MODE = 0,
+ SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE = 1
+};
+
struct sci_bios_oem_param_block_hdr {
uint8_t signature[ISCI_ROM_SIG_SIZE];
uint16_t total_block_length;
diff --git a/firmware/isci/isci_firmware.bin.ihex b/firmware/isci/isci_firmware.bin.ihex
index 7f12b39e7910..b1bb5cf4499c 100644
--- a/firmware/isci/isci_firmware.bin.ihex
+++ b/firmware/isci/isci_firmware.bin.ihex
@@ -1,11 +1,11 @@
:10000000495343554F454D42E70017100002000089
-:10001000000000000000000001000000000000FFE0
+:10001000000000000000000101000000000000FFDF
:10002000FFCF5F000000F0000000000000000000B3
:1000300000000000000000FFFFCF5F000000F100A3
:10004000000000000000000000000000000000FFB1
:10005000FFCF5F000000F200000000000000000081
:1000600000000000000000FFFFCF5F000000F30071
-:100070000000000000000000000000000000000080
+:10007000000000000000000000000000000000017F
:1000800001000000000000FFFFCF5F000000F4004F
:10009000000000000000000000000000000000FF61
:1000A000FFCF5F000000F50000000000000000002E