summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/isci/Makefile2
-rw-r--r--drivers/scsi/isci/core/scic_config_parameters.h41
-rw-r--r--drivers/scsi/isci/core/scic_sds_controller.c6
-rw-r--r--drivers/scsi/isci/firmware/create_fw.c197
-rw-r--r--drivers/scsi/isci/firmware/create_fw.h67
-rw-r--r--drivers/scsi/isci/host.c47
-rw-r--r--drivers/scsi/isci/host.h2
-rw-r--r--drivers/scsi/isci/init.c191
-rw-r--r--drivers/scsi/isci/isci.h39
-rw-r--r--drivers/scsi/isci/probe_roms.c133
-rw-r--r--drivers/scsi/isci/probe_roms.h130
-rw-r--r--firmware/isci/isci_firmware.bin.ihex25
12 files changed, 453 insertions, 427 deletions
diff --git a/drivers/scsi/isci/Makefile b/drivers/scsi/isci/Makefile
index d402d679a316..1252d768c42d 100644
--- a/drivers/scsi/isci/Makefile
+++ b/drivers/scsi/isci/Makefile
@@ -9,7 +9,7 @@ EXTRA_CFLAGS += -Idrivers/scsi/isci/core/ -Idrivers/scsi/isci/
obj-$(CONFIG_SCSI_ISCI) += isci.o
isci-objs := init.o phy.o request.o sata.o \
remote_device.o port.o timers.o \
- host.o task.o events.o \
+ host.o task.o events.o probe_roms.o \
core/scic_sds_controller.o \
core/scic_sds_remote_device.o \
core/scic_sds_request.o \
diff --git a/drivers/scsi/isci/core/scic_config_parameters.h b/drivers/scsi/isci/core/scic_config_parameters.h
index 485fefc08883..5e1345daf014 100644
--- a/drivers/scsi/isci/core/scic_config_parameters.h
+++ b/drivers/scsi/isci/core/scic_config_parameters.h
@@ -68,6 +68,7 @@
#include "sci_status.h"
#include "intel_sas.h"
#include "sci_controller_constants.h"
+#include "probe_roms.h"
struct scic_sds_controller;
@@ -224,44 +225,6 @@ union scic_user_parameters {
#define SCIC_SDS_PARM_PHY_MASK_MAX 0xF
/**
- * struct scic_sds_oem_parameters - This structure delineates the various OEM
- * parameters that must be set the core user.
- *
- *
- */
-struct scic_sds_oem_parameters {
- struct {
- /**
- * This field indicates whether Spread Spectrum Clocking (SSC)
- * should be enabled or disabled.
- */
- bool do_enable_ssc;
-
- } controller;
-
- struct {
- /**
- * This field specifies the phys to be contained inside a port.
- * The bit position in the mask specifies the index of the phy
- * to be contained in the port. Multiple bits (i.e. phys)
- * can be contained in a single port.
- */
- u8 phy_mask;
-
- } ports[SCI_MAX_PORTS];
-
- struct sci_phy_oem_params {
- /**
- * This field specifies the SAS address to be transmitted on
- * for this phy index.
- */
- struct sci_sas_address sas_address;
-
- } phys[SCI_MAX_PHYS];
-
-};
-
-/**
* This structure/union specifies the various different OEM parameter sets
* available. Each type is specific to a hardware controller version.
*
@@ -273,7 +236,7 @@ union scic_oem_parameters {
* Storage Controller Unit (SCU) Driver Standard (SDS) version
* 1.
*/
- struct scic_sds_oem_parameters sds1;
+ 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 799a04bc0938..e7f3711b4afc 100644
--- a/drivers/scsi/isci/core/scic_sds_controller.c
+++ b/drivers/scsi/isci/core/scic_sds_controller.c
@@ -2039,10 +2039,8 @@ static void scic_sds_controller_set_default_config_parameters(struct scic_sds_co
/* 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. */
- scic->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;
diff --git a/drivers/scsi/isci/firmware/create_fw.c b/drivers/scsi/isci/firmware/create_fw.c
index 442caac9675d..f8f96d6eb7df 100644
--- a/drivers/scsi/isci/firmware/create_fw.c
+++ b/drivers/scsi/isci/firmware/create_fw.c
@@ -6,157 +6,30 @@
#include <fcntl.h>
#include <string.h>
#include <errno.h>
+#include <asm/types.h>
+#include <strings.h>
+#include <stdint.h>
-char blob_name[] = "isci_firmware.bin";
-char id[] = "#SCU MAGIC#";
-unsigned char version = 1;
-unsigned char sub_version = 0;
-
-
-/*
- * For all defined arrays:
- * elements 0-3 are for SCU0, ports 0-3
- * elements 4-7 are for SCU1, ports 0-3
- *
- * valid configurations for one SCU are:
- * P0 P1 P2 P3
- * ----------------
- * 0xF,0x0,0x0,0x0 # 1 x4 port
- * 0x3,0x0,0x4,0x8 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are each x1
- * # ports
- * 0x1,0x2,0xC,0x0 # Phys 0 and 1 are each x1 ports, phy 2 and phy 3 are a x2
- * # port
- * 0x3,0x0,0xC,0x0 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are a x2 port
- * 0x1,0x2,0x4,0x8 # Each phy is a x1 port (this is the default configuration)
- *
- * 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).
- */
-unsigned int phy_mask[] = { 1, 2, 4, 8, 1, 2, 4, 8 };
-
-
-/* denotes SAS generation. i.e. 3: SAS Gen 3 6G */
-unsigned int phy_gen[] = { 3, 3, 3, 3, 3, 3, 3, 3 };
-
-/*
- * if there is a port/phy on which you do not wish to override the default
- * values, use the value "0000000000000000". SAS address of zero's is
- * considered invalid and will not be used.
- */
-unsigned long long sas_addr[] = { 0x5FCFFFFFF0000000ULL,
- 0x5FCFFFFFF1000000ULL,
- 0x5FCFFFFFF2000000ULL,
- 0x5FCFFFFFF3000000ULL,
- 0x5FCFFFFFF4000000ULL,
- 0x5FCFFFFFF5000000ULL,
- 0x5FCFFFFFF6000000ULL,
- 0x5FCFFFFFF7000000ULL };
-
-int write_blob(void)
+#include "create_fw.h"
+#include "../probe_roms.h"
+
+int write_blob(struct isci_orom *isci_orom)
{
FILE *fd;
int err;
+ size_t count;
fd = fopen(blob_name, "w+");
if (!fd) {
perror("Open file for write failed");
+ fclose(fd);
return -EIO;
}
- /* write id */
- err = fwrite((void *)id, sizeof(char), strlen(id)+1, fd);
- if (err == 0) {
- perror("write id failed");
- return err;
- }
-
- /* write version */
- err = fwrite((void *)&version, sizeof(version), 1, fd);
- if (err == 0) {
- perror("write version failed");
- return err;
- }
-
- /* write sub version */
- err = fwrite((void *)&sub_version, sizeof(sub_version), 1, fd);
- if (err == 0) {
- perror("write subversion failed");
- return err;
- }
-
- /* write phy mask header */
- err = fputc(0x1, fd);
- if (err == EOF) {
- perror("write phy mask header failed");
- return -EIO;
- }
-
- /* write size */
- err = fputc(8, fd);
- if (err == EOF) {
- perror("write phy mask size failed");
- return -EIO;
- }
-
- /* write phy masks */
- err = fwrite((void *)phy_mask, 1, sizeof(phy_mask), fd);
- if (err == 0) {
- perror("write phy_mask failed");
- return err;
- }
-
- /* write phy gen header */
- err = fputc(0x2, fd);
- if (err == EOF) {
- perror("write phy gen header failed");
- return -EIO;
- }
-
- /* write size */
- err = fputc(8, fd);
- if (err == EOF) {
- perror("write phy gen size failed");
- return -EIO;
- }
-
- /* write phy_gen */
- err = fwrite((void *)phy_gen,
- 1,
- sizeof(phy_gen),
- fd);
- if (err == 0) {
- perror("write phy_gen failed");
- return err;
- }
-
- /* write phy gen header */
- err = fputc(0x3, fd);
- if (err == EOF) {
- perror("write sas addr header failed");
- return -EIO;
- }
-
- /* write size */
- err = fputc(8, fd);
- if (err == EOF) {
- perror("write sas addr size failed");
- return -EIO;
- }
-
- /* write sas_addr */
- err = fwrite((void *)sas_addr,
- 1,
- sizeof(sas_addr),
- fd);
- if (err == 0) {
- perror("write sas_addr failed");
- return err;
- }
-
- /* write end header */
- err = fputc(0xff, fd);
- if (err == EOF) {
- perror("write end header failed");
+ count = fwrite(isci_orom, sizeof(struct isci_orom), 1, fd);
+ if (count != 1) {
+ perror("Write data failed");
+ fclose(fd);
return -EIO;
}
@@ -165,13 +38,53 @@ int write_blob(void)
return 0;
}
+void set_binary_values(struct isci_orom *isci_orom)
+{
+ int ctrl_idx, phy_idx, port_idx;
+
+ /* setting OROM signature */
+ strncpy(isci_orom->hdr.signature, sig, strlen(sig));
+ isci_orom->hdr.version = 0x10;
+ isci_orom->hdr.total_block_length = sizeof(struct isci_orom);
+ isci_orom->hdr.hdr_length = sizeof(struct sci_bios_oem_param_block_hdr);
+ isci_orom->hdr.num_elements = num_elements;
+
+ for (ctrl_idx = 0; ctrl_idx < 2; ctrl_idx++) {
+ isci_orom->ctrl[ctrl_idx].controller.mode_type = mode_type;
+ isci_orom->ctrl[ctrl_idx].controller.max_concurrent_dev_spin_up =
+ max_num_concurrent_dev_spin_up;
+ isci_orom->ctrl[ctrl_idx].controller.do_enable_ssc =
+ enable_ssc;
+
+ for (port_idx = 0; port_idx < 4; port_idx++)
+ isci_orom->ctrl[ctrl_idx].ports[port_idx].phy_mask =
+ phy_mask[ctrl_idx][port_idx];
+
+ for (phy_idx = 0; phy_idx < 4; phy_idx++) {
+ isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.high =
+ (__u32)(sas_addr[ctrl_idx][phy_idx] >> 32);
+ isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.low =
+ (__u32)(sas_addr[ctrl_idx][phy_idx]);
+ }
+ }
+}
+
int main(void)
{
int err;
+ struct isci_orom *isci_orom;
+
+ isci_orom = malloc(sizeof(struct isci_orom));
+ memset(isci_orom, 0, sizeof(struct isci_orom));
- err = write_blob();
- if (err < 0)
+ set_binary_values(isci_orom);
+
+ err = write_blob(isci_orom);
+ if (err < 0) {
+ free(isci_orom);
return err;
+ }
+ free(isci_orom);
return 0;
}
diff --git a/drivers/scsi/isci/firmware/create_fw.h b/drivers/scsi/isci/firmware/create_fw.h
new file mode 100644
index 000000000000..bedbe4fad181
--- /dev/null
+++ b/drivers/scsi/isci/firmware/create_fw.h
@@ -0,0 +1,67 @@
+#ifndef _CREATE_FW_H_
+#define _CREATE_FW_H_
+
+
+/* we are configuring for 2 SCUs */
+static const int num_elements = 2;
+
+/*
+ * For all defined arrays:
+ * elements 0-3 are for SCU0, ports 0-3
+ * elements 4-7 are for SCU1, ports 0-3
+ *
+ * valid configurations for one SCU are:
+ * P0 P1 P2 P3
+ * ----------------
+ * 0xF,0x0,0x0,0x0 # 1 x4 port
+ * 0x3,0x0,0x4,0x8 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are each x1
+ * # ports
+ * 0x1,0x2,0xC,0x0 # Phys 0 and 1 are each x1 ports, phy 2 and phy 3 are a x2
+ * # port
+ * 0x3,0x0,0xC,0x0 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are a x2 port
+ * 0x1,0x2,0x4,0x8 # Each phy is a x1 port (this is the default configuration)
+ *
+ * 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).
+ */
+#ifdef MPC
+static const __u8 phy_mask[2][4] = { {1, 2, 4, 8},
+ {1, 2, 4, 8} };
+#else /* APC (default) */
+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;
+
+/* enable of ssc operation */
+static const int enable_ssc;
+
+/* AFE_TX_AMP_CONTROL */
+static const unsigned int afe_tx_amp_control0 = 0x000e7c03;
+static const unsigned int afe_tx_amp_control1 = 0x000e7c03;
+static const unsigned int afe_tx_amp_control2 = 0x000e7c03;
+static const unsigned int afe_tx_amp_control3 = 0x000e7c03;
+
+/*
+ * if there is a port/phy on which you do not wish to override the default
+ * values, use the value "0000000000000000". SAS address of zero's is
+ * considered invalid and will not be used.
+ */
+static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFFF0000000ULL,
+ 0x5FCFFFFFF1000000ULL,
+ 0x5FCFFFFFF2000000ULL,
+ 0x5FCFFFFFF3000000ULL },
+ { 0x5FCFFFFFF4000000ULL,
+ 0x5FCFFFFFF5000000ULL,
+ 0x5FCFFFFFF6000000ULL,
+ 0x5FCFFFFFF7000000ULL } };
+
+static const char blob_name[] = "isci_firmware.bin";
+static const char sig[] = "ISCUOEMB";
+static const unsigned char version = 1;
+
+#endif
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index dc231c22ea93..bb5b54d361b0 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -61,6 +61,7 @@
#include "port.h"
#include "request.h"
#include "host.h"
+#include "probe_roms.h"
irqreturn_t isci_msix_isr(int vec, void *data)
{
@@ -419,6 +420,7 @@ int isci_host_init(struct isci_host *isci_host)
struct scic_sds_controller *controller;
union scic_oem_parameters scic_oem_params;
union scic_user_parameters scic_user_params;
+ struct isci_pci_info *pci_info = to_pci_info(isci_host->pdev);
isci_timer_list_construct(isci_host);
@@ -461,31 +463,32 @@ int isci_host_init(struct isci_host *isci_host)
sci_object_set_association(isci_host->core_controller,
(void *)isci_host);
- /* grab initial values stored in the controller object for OEM and USER
- * parameters */
- scic_oem_parameters_get(controller, &scic_oem_params);
+ /*
+ * grab initial values stored in the controller object for OEM and USER
+ * parameters
+ */
scic_user_parameters_get(controller, &scic_user_params);
+ status = scic_user_parameters_set(isci_host->core_controller,
+ &scic_user_params);
+ if (status != SCI_SUCCESS) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: scic_user_parameters_set failed\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ scic_oem_parameters_get(controller, &scic_oem_params);
- if (isci_firmware) {
- /* grab any OEM and USER parameters specified in binary blob */
+ /* grab any OEM parameters specified in orom */
+ if (pci_info->orom) {
status = isci_parse_oem_parameters(&scic_oem_params,
- isci_host->id,
- isci_firmware);
+ pci_info->orom,
+ isci_host->id);
if (status != SCI_SUCCESS) {
dev_warn(&isci_host->pdev->dev,
"parsing firmware oem parameters failed\n");
return -EINVAL;
}
-
- status = isci_parse_user_parameters(&scic_user_params,
- isci_host->id,
- isci_firmware);
- if (status != SCI_SUCCESS) {
- dev_warn(&isci_host->pdev->dev,
- "%s: isci_parse_user_parameters"
- " failed\n", __func__);
- return -EINVAL;
- }
} else {
status = scic_oem_parameters_set(isci_host->core_controller,
&scic_oem_params);
@@ -495,16 +498,6 @@ int isci_host_init(struct isci_host *isci_host)
__func__);
return -ENODEV;
}
-
-
- status = scic_user_parameters_set(isci_host->core_controller,
- &scic_user_params);
- if (status != SCI_SUCCESS) {
- dev_warn(&isci_host->pdev->dev,
- "%s: scic_user_parameters_set failed\n",
- __func__);
- return -ENODEV;
- }
}
tasklet_init(&isci_host->completion_tasklet,
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 889a7850255a..d012b69d8d61 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -140,8 +140,8 @@ static inline struct isci_remote_device *idev_by_id(struct isci_host *ihost, int
struct isci_pci_info {
struct msix_entry msix_entries[SCI_MAX_MSIX_INT];
- int core_lib_array_index;
struct isci_host *hosts[SCI_MAX_CONTROLLERS];
+ struct isci_orom *orom;
};
static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev)
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 3f2bb137bcb1..65519321e1cc 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -56,12 +56,15 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/efi.h>
#include <asm/string.h>
#include "isci.h"
#include "task.h"
#include "sci_controller_constants.h"
#include "scic_remote_device.h"
#include "sci_environment.h"
+#include "probe_roms.h"
static struct scsi_transport_template *isci_transport_template;
@@ -373,85 +376,6 @@ static int isci_setup_interrupts(struct pci_dev *pdev)
return err;
}
-/**
- * isci_parse_oem_parameters() - This method will take OEM parameters
- * from the module init parameters and copy them to oem_params. This will
- * only copy values that are not set to the module parameter default values
- * @oem_parameters: This parameter specifies the controller default OEM
- * parameters. It is expected that this has been initialized to the default
- * parameters for the controller
- *
- *
- */
-enum sci_status isci_parse_oem_parameters(union scic_oem_parameters *oem_params,
- int scu_index,
- struct isci_firmware *fw)
-{
- int i;
-
- /* check for valid inputs */
- if (!(scu_index >= 0
- && scu_index < SCI_MAX_CONTROLLERS
- && oem_params != NULL)) {
- return SCI_FAILURE;
- }
-
- for (i = 0; i < SCI_MAX_PHYS; i++) {
- int array_idx = i + (SCI_MAX_PHYS * scu_index);
- u64 sas_addr = fw->sas_addrs[array_idx];
-
- if (sas_addr != 0) {
- oem_params->sds1.phys[i].sas_address.low =
- (u32)(sas_addr & 0xffffffff);
- oem_params->sds1.phys[i].sas_address.high =
- (u32)((sas_addr >> 32) & 0xffffffff);
- }
- }
-
- for (i = 0; i < SCI_MAX_PORTS; i++) {
- int array_idx = i + (SCI_MAX_PORTS * scu_index);
- u32 pmask = fw->phy_masks[array_idx];
-
- oem_params->sds1.ports[i].phy_mask = pmask;
- }
-
- return SCI_SUCCESS;
-}
-
-/**
- * isci_parse_user_parameters() - This method will take user parameters
- * from the module init parameters and copy them to user_params. This will
- * only copy values that are not set to the module parameter default values
- * @user_parameters: This parameter specifies the controller default user
- * parameters. It is expected that this has been initialized to the default
- * parameters for the controller
- *
- *
- */
-enum sci_status isci_parse_user_parameters(
- union scic_user_parameters *user_params,
- int scu_index,
- struct isci_firmware *fw)
-{
- int i;
-
- if (!(scu_index >= 0
- && scu_index < SCI_MAX_CONTROLLERS
- && user_params != NULL)) {
- return SCI_FAILURE;
- }
-
- for (i = 0; i < SCI_MAX_PORTS; i++) {
- int array_idx = i + (SCI_MAX_PORTS * scu_index);
- u32 gen = fw->phy_gens[array_idx];
-
- user_params->sds1.phys[i].max_speed_generation = gen;
-
- }
-
- return SCI_SUCCESS;
-}
-
static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
{
struct isci_host *isci_host;
@@ -535,73 +459,13 @@ static void check_si_rev(struct pci_dev *pdev)
}
-static int isci_verify_firmware(const struct firmware *fw,
- struct isci_firmware *isci_fw)
-{
- const u8 *tmp;
-
- if (fw->size < ISCI_FIRMWARE_MIN_SIZE)
- return -EINVAL;
-
- tmp = fw->data;
-
- /* 12th char should be the NULL terminate for the ID string */
- if (tmp[11] != '\0')
- return -EINVAL;
-
- if (strncmp("#SCU MAGIC#", tmp, 11) != 0)
- return -EINVAL;
-
- isci_fw->id = tmp;
- isci_fw->version = fw->data[ISCI_FW_VER_OFS];
- isci_fw->subversion = fw->data[ISCI_FW_SUBVER_OFS];
-
- tmp = fw->data + ISCI_FW_DATA_OFS;
-
- while (*tmp != ISCI_FW_HDR_EOF) {
- switch (*tmp) {
- case ISCI_FW_HDR_PHYMASK:
- tmp++;
- isci_fw->phy_masks_size = *tmp;
- tmp++;
- isci_fw->phy_masks = (const u32 *)tmp;
- tmp += sizeof(u32) * isci_fw->phy_masks_size;
- break;
-
- case ISCI_FW_HDR_PHYGEN:
- tmp++;
- isci_fw->phy_gens_size = *tmp;
- tmp++;
- isci_fw->phy_gens = (const u32 *)tmp;
- tmp += sizeof(u32) * isci_fw->phy_gens_size;
- break;
-
- case ISCI_FW_HDR_SASADDR:
- tmp++;
- isci_fw->sas_addrs_size = *tmp;
- tmp++;
- isci_fw->sas_addrs = (const u64 *)tmp;
- tmp += sizeof(u64) * isci_fw->sas_addrs_size;
- break;
-
- default:
- pr_err("bad field in firmware binary blob\n");
- return -EINVAL;
- }
- }
-
- pr_info("isci firmware v%u.%u loaded.\n",
- isci_fw->version, isci_fw->subversion);
-
- return SCI_SUCCESS;
-}
-
static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct isci_pci_info *pci_info;
int err, i;
struct isci_host *isci_host;
const struct firmware *fw = NULL;
+ struct isci_orom *orom;
check_si_rev(pdev);
@@ -610,33 +474,32 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
return -ENOMEM;
pci_set_drvdata(pdev, pci_info);
- err = request_firmware(&fw, ISCI_FW_NAME, &pdev->dev);
- if (err) {
- dev_warn(&pdev->dev,
- "Loading firmware failed, using default values\n");
- dev_warn(&pdev->dev,
- "Default OEM configuration being used:"
- " 4 narrow ports, and default SAS Addresses\n");
- } else {
- isci_firmware = devm_kzalloc(&pdev->dev,
- sizeof(struct isci_firmware),
- GFP_KERNEL);
- if (isci_firmware) {
- err = isci_verify_firmware(fw, isci_firmware);
- if (err != SCI_SUCCESS) {
- dev_warn(&pdev->dev,
- "firmware verification failed\n");
- dev_warn(&pdev->dev,
- "Default OEM configuration being used:"
- " 4 narrow ports, and default SAS "
- "Addresses\n");
- devm_kfree(&pdev->dev, isci_firmware);
- isci_firmware = NULL;
- }
+ if (efi_enabled) {
+ /* do EFI parsing here */
+ orom = NULL;
+ } else
+ orom = isci_request_oprom(pdev);
+
+ if (!orom) {
+ orom = isci_request_firmware(pdev, fw);
+ if (!orom) {
+ /* TODO convert this to WARN_TAINT_ONCE once the
+ * orom/efi parameter support is widely available
+ */
+ dev_warn(&pdev->dev,
+ "Loading user firmware failed, using default "
+ "values\n");
+ dev_warn(&pdev->dev,
+ "Default OEM configuration being used: 4 "
+ "narrow ports, and default SAS Addresses\n");
}
- release_firmware(fw);
}
+ if (orom)
+ dev_info(&pdev->dev, "sas parameters (version: %#x) loaded\n",
+ orom->hdr.version);
+ pci_info->orom = orom;
+
err = isci_pci_init(pdev);
if (err)
return err;
diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h
index b3f63f1a46cf..83422d43c1d3 100644
--- a/drivers/scsi/isci/isci.h
+++ b/drivers/scsi/isci/isci.h
@@ -61,7 +61,6 @@
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
-#include <linux/firmware.h>
#include <linux/bug.h>
#include <scsi/libsas.h>
#include <scsi/scsi.h>
@@ -76,34 +75,6 @@
#include "task.h"
#include "sata.h"
-extern struct isci_firmware *isci_firmware;
-
-#define ISCI_FW_NAME "isci/isci_firmware.bin"
-
-#define ISCI_FIRMWARE_MIN_SIZE 149
-
-#define ISCI_FW_IDSIZE 12
-#define ISCI_FW_VER_OFS ISCI_FW_IDSIZE
-#define ISCI_FW_SUBVER_OFS ISCI_FW_VER_OFS + 1
-#define ISCI_FW_DATA_OFS ISCI_FW_SUBVER_OFS + 1
-
-#define ISCI_FW_HDR_PHYMASK 0x1
-#define ISCI_FW_HDR_PHYGEN 0x2
-#define ISCI_FW_HDR_SASADDR 0x3
-#define ISCI_FW_HDR_EOF 0xff
-
-struct isci_firmware {
- const u8 *id;
- u8 version;
- u8 subversion;
- const u32 *phy_masks;
- u8 phy_masks_size;
- const u32 *phy_gens;
- u8 phy_gens_size;
- const u64 *sas_addrs;
- u8 sas_addrs_size;
-};
-
irqreturn_t isci_msix_isr(int vec, void *data);
irqreturn_t isci_intx_isr(int vec, void *data);
irqreturn_t isci_error_isr(int vec, void *data);
@@ -113,14 +84,4 @@ void scic_sds_controller_completion_handler(struct scic_sds_controller *scic);
bool scic_sds_controller_error_isr(struct scic_sds_controller *scic);
void scic_sds_controller_error_handler(struct scic_sds_controller *scic);
-enum sci_status isci_parse_oem_parameters(
- union scic_oem_parameters *oem_params,
- int scu_index,
- struct isci_firmware *fw);
-
-enum sci_status isci_parse_user_parameters(
- union scic_user_parameters *user_params,
- int scu_index,
- struct isci_firmware *fw);
-
#endif /* __ISCI_H__ */
diff --git a/drivers/scsi/isci/probe_roms.c b/drivers/scsi/isci/probe_roms.c
new file mode 100644
index 000000000000..0b90e7c546c0
--- /dev/null
+++ b/drivers/scsi/isci/probe_roms.c
@@ -0,0 +1,133 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ */
+
+/* probe_roms - scan for oem parameters */
+
+#include <linux/kernel.h>
+#include <linux/firmware.h>
+#include <linux/uaccess.h>
+#include <asm/probe_roms.h>
+
+#include "isci.h"
+#include "task.h"
+#include "sci_controller_constants.h"
+#include "scic_remote_device.h"
+#include "sci_environment.h"
+#include "probe_roms.h"
+
+struct isci_orom *isci_request_oprom(struct pci_dev *pdev)
+{
+ void __iomem *oprom = pci_map_biosrom(pdev);
+ struct isci_orom *rom = NULL;
+ size_t len, i;
+
+ if (!oprom)
+ return NULL;
+
+ len = pci_biosrom_size(pdev);
+ rom = devm_kzalloc(&pdev->dev, sizeof(*rom), GFP_KERNEL);
+
+ for (i = 0; i < len && rom; i += ISCI_ROM_SIG_SIZE) {
+ memcpy_fromio(rom->hdr.signature, oprom + i, ISCI_ROM_SIG_SIZE);
+ if (memcmp(rom->hdr.signature, ISCI_ROM_SIG,
+ ISCI_ROM_SIG_SIZE) == 0) {
+ size_t copy_len = min(len - i, sizeof(*rom));
+
+ memcpy_fromio(rom, oprom + i, copy_len);
+ break;
+ }
+ }
+
+ if (i >= len) {
+ dev_err(&pdev->dev, "oprom parse error\n");
+ devm_kfree(&pdev->dev, rom);
+ rom = NULL;
+ }
+ pci_unmap_biosrom(oprom);
+
+ return rom;
+}
+
+/**
+ * isci_parse_oem_parameters() - This method will take OEM parameters
+ * from the module init parameters and copy them to oem_params. This will
+ * only copy values that are not set to the module parameter default values
+ * @oem_parameters: This parameter specifies the controller default OEM
+ * parameters. It is expected that this has been initialized to the default
+ * parameters for the controller
+ *
+ *
+ */
+enum sci_status isci_parse_oem_parameters(union scic_oem_parameters *oem_params,
+ struct isci_orom *orom, int scu_index)
+{
+ int i;
+
+ /* check for valid inputs */
+ if (!(scu_index >= 0
+ && scu_index < SCI_MAX_CONTROLLERS
+ && oem_params != NULL))
+ return -EINVAL;
+
+ for (i = 0; i < SCI_MAX_PHYS; i++) {
+ oem_params->sds1.phys[i].sas_address.low =
+ orom->ctrl[scu_index].phys[i].sas_address.low;
+ oem_params->sds1.phys[i].sas_address.high =
+ orom->ctrl[scu_index].phys[i].sas_address.high;
+ }
+
+ for (i = 0; i < SCI_MAX_PORTS; i++)
+ oem_params->sds1.ports[i].phy_mask =
+ orom->ctrl[scu_index].ports[i].phy_mask;
+
+ return 0;
+}
+
+struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw)
+{
+ struct isci_orom *orom = NULL, *data;
+
+ if (request_firmware(&fw, ISCI_FW_NAME, &pdev->dev) != 0)
+ return NULL;
+
+ if (fw->size < sizeof(*orom))
+ goto out;
+
+ data = (struct isci_orom *)fw->data;
+
+ if (strncmp(ISCI_ROM_SIG, data->hdr.signature,
+ strlen(ISCI_ROM_SIG)) != 0)
+ goto out;
+
+ orom = devm_kzalloc(&pdev->dev, fw->size, GFP_KERNEL);
+ if (!orom)
+ goto out;
+
+ memcpy(orom, fw->data, fw->size);
+
+ out:
+ release_firmware(fw);
+
+ return orom;
+}
diff --git a/drivers/scsi/isci/probe_roms.h b/drivers/scsi/isci/probe_roms.h
new file mode 100644
index 000000000000..76651c01895a
--- /dev/null
+++ b/drivers/scsi/isci/probe_roms.h
@@ -0,0 +1,130 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _ISCI_PROBE_ROMS_H_
+#define _ISCI_PROBE_ROMS_H_
+
+#ifdef __KERNEL__
+#include <linux/firmware.h>
+#include <linux/pci.h>
+
+struct isci_orom *isci_request_oprom(struct pci_dev *pdev);
+
+union scic_oem_parameters;
+struct isci_orom;
+
+enum sci_status isci_parse_oem_parameters(
+ union scic_oem_parameters *oem_params,
+ struct isci_orom *orom,
+ int scu_index);
+struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw);
+int isci_get_efi_var(struct pci_dev *pdev);
+#else
+#define SCI_MAX_PORTS 4
+#define SCI_MAX_PHYS 4
+#endif
+
+#define ISCI_FW_NAME "isci/isci_firmware.bin"
+
+#define ROMSIGNATURE 0xaa55
+
+#define ISCI_ROM_SIG "ISCUOEMB"
+#define ISCI_ROM_SIG_SIZE 8
+
+#define ISCI_EFI_VENDOR_GUID NULL_GUID
+#define ISCI_EFI_ATTRIBUTES 0
+#define ISCI_EFI_VAR_NAME "isci_oemb"
+
+struct sci_bios_oem_param_block_hdr {
+ uint8_t signature[ISCI_ROM_SIG_SIZE];
+ uint16_t total_block_length;
+ uint8_t hdr_length;
+ uint8_t version;
+ uint8_t preboot_source;
+ uint8_t num_elements;
+ uint8_t element_length;
+ uint8_t reserved[8];
+} __attribute__ ((packed));
+
+struct scic_sds_oem_params {
+ struct {
+ uint8_t mode_type;
+ uint8_t max_concurrent_dev_spin_up;
+ uint8_t do_enable_ssc;
+ uint8_t reserved;
+ } controller;
+
+ struct {
+ uint8_t phy_mask;
+ } ports[SCI_MAX_PORTS];
+
+ struct sci_phy_oem_params {
+ struct {
+ uint32_t high;
+ uint32_t low;
+ } sas_address;
+
+ uint32_t afe_tx_amp_control0;
+ uint32_t afe_tx_amp_control1;
+ uint32_t afe_tx_amp_control2;
+ uint32_t afe_tx_amp_control3;
+ } phys[SCI_MAX_PHYS];
+} __attribute__ ((packed));
+
+struct isci_orom {
+ struct sci_bios_oem_param_block_hdr hdr;
+ struct scic_sds_oem_params ctrl[2];
+} __attribute__ ((packed));
+
+#endif
diff --git a/firmware/isci/isci_firmware.bin.ihex b/firmware/isci/isci_firmware.bin.ihex
index 9fc9e60f399c..7f12b39e7910 100644
--- a/firmware/isci/isci_firmware.bin.ihex
+++ b/firmware/isci/isci_firmware.bin.ihex
@@ -1,11 +1,16 @@
-:1000000023534355204D4147494323000100010834
-:1000100001000000020000000400000008000000D1
-:1000200001000000020000000400000008000000C1
-:1000300002080300000003000000030000000300AA
-:1000400000000300000003000000030000000300A4
-:1000500000000308000000F0FFFFCF5F000000F188
-:10006000FFFFCF5F000000F2FFFFCF5F000000F353
-:10007000FFFFCF5F000000F4FFFFCF5F000000F53F
-:10008000FFFFCF5F000000F6FFFFCF5F000000F72B
-:05009000FFFFCF5FFF40
+:10000000495343554F454D42E70017100002000089
+:10001000000000000000000001000000000000FFE0
+:10002000FFCF5F000000F0000000000000000000B3
+:1000300000000000000000FFFFCF5F000000F100A3
+:10004000000000000000000000000000000000FFB1
+:10005000FFCF5F000000F200000000000000000081
+:1000600000000000000000FFFFCF5F000000F30071
+:100070000000000000000000000000000000000080
+:1000800001000000000000FFFFCF5F000000F4004F
+:10009000000000000000000000000000000000FF61
+:1000A000FFCF5F000000F50000000000000000002E
+:1000B00000000000000000FFFFCF5F000000F6001E
+:1000C000000000000000000000000000000000FF31
+:1000D000FFCF5F000000F7000000000000000000FC
+:0700E0000000000000000019
:00000001FF