isci: add support for 2 more oem parmeters
authorHenryk Dembkowski <Henryk.Dembkowski@intel.com>
Thu, 24 Feb 2011 00:55:11 +0000 (16:55 -0800)
committerDan Williams <dan.j.williams@intel.com>
Sun, 3 Jul 2011 10:55:30 +0000 (03:55 -0700)
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>

drivers/scsi/isci/core/scic_config_parameters.h
drivers/scsi/isci/core/scic_sds_controller.c
drivers/scsi/isci/core/scic_sds_controller.h
drivers/scsi/isci/core/scic_sds_port_configuration_agent.c
drivers/scsi/isci/firmware/create_fw.h
drivers/scsi/isci/probe_roms.h
firmware/isci/isci_firmware.bin.ihex

index 5e1345d..f64f24f 100644 (file)
@@ -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;
-
 };
 
 /**
index e7f3711..12b2ad5 100644 (file)
@@ -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;
        }
index 9b8e55d..6386a64 100644 (file)
@@ -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);
index e26a4e6..7c95210 100644 (file)
@@ -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);
index bedbe4f..788a8de 100644 (file)
@@ -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;
 
index 96d8b92..69526ff 100644 (file)
@@ -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;
index 7f12b39..b1bb5cf 100644 (file)
@@ -1,11 +1,11 @@
 :10000000495343554F454D42E70017100002000089
-:10001000000000000000000001000000000000FFE0
+:10001000000000000000000101000000000000FFDF
 :10002000FFCF5F000000F0000000000000000000B3
 :1000300000000000000000FFFFCF5F000000F100A3
 :10004000000000000000000000000000000000FFB1
 :10005000FFCF5F000000F200000000000000000081
 :1000600000000000000000FFFFCF5F000000F30071
-:100070000000000000000000000000000000000080
+:10007000000000000000000000000000000000017F
 :1000800001000000000000FFFFCF5F000000F4004F
 :10009000000000000000000000000000000000FF61
 :1000A000FFCF5F000000F50000000000000000002E