aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-03-08 12:52:49 -0500
committerDan Williams <dan.j.williams@intel.com>2011-07-03 06:55:30 -0400
commitd044af17aacd03a1f4fced1af4b7570d205c8fd9 (patch)
tree1304fd0c7fa979fb229a4bf57771e9e6cde7b37d /drivers/scsi
parent9affa289e2f9ef4721e85edbde86466524bfe957 (diff)
isci: Add support for probing OROM for OEM params
We need to scan the OROM for signature and grab the OEM parameters. We also need to do the same for EFI. If all fails then we resort to user binary blob, and if that fails then we go to the defaults. Share the format with the create_fw utility so that all possible sources of the parameters are in-sync. Signed-off-by: Dave Jiang <dave.jiang@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi')
-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
11 files changed, 438 insertions, 417 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/
9obj-$(CONFIG_SCSI_ISCI) += isci.o 9obj-$(CONFIG_SCSI_ISCI) += isci.o
10isci-objs := init.o phy.o request.o sata.o \ 10isci-objs := init.o phy.o request.o sata.o \
11 remote_device.o port.o timers.o \ 11 remote_device.o port.o timers.o \
12 host.o task.o events.o \ 12 host.o task.o events.o probe_roms.o \
13 core/scic_sds_controller.o \ 13 core/scic_sds_controller.o \
14 core/scic_sds_remote_device.o \ 14 core/scic_sds_remote_device.o \
15 core/scic_sds_request.o \ 15 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 @@
68#include "sci_status.h" 68#include "sci_status.h"
69#include "intel_sas.h" 69#include "intel_sas.h"
70#include "sci_controller_constants.h" 70#include "sci_controller_constants.h"
71#include "probe_roms.h"
71 72
72struct scic_sds_controller; 73struct scic_sds_controller;
73 74
@@ -224,44 +225,6 @@ union scic_user_parameters {
224#define SCIC_SDS_PARM_PHY_MASK_MAX 0xF 225#define SCIC_SDS_PARM_PHY_MASK_MAX 0xF
225 226
226/** 227/**
227 * struct scic_sds_oem_parameters - This structure delineates the various OEM
228 * parameters that must be set the core user.
229 *
230 *
231 */
232struct scic_sds_oem_parameters {
233 struct {
234 /**
235 * This field indicates whether Spread Spectrum Clocking (SSC)
236 * should be enabled or disabled.
237 */
238 bool do_enable_ssc;
239
240 } controller;
241
242 struct {
243 /**
244 * This field specifies the phys to be contained inside a port.
245 * The bit position in the mask specifies the index of the phy
246 * to be contained in the port. Multiple bits (i.e. phys)
247 * can be contained in a single port.
248 */
249 u8 phy_mask;
250
251 } ports[SCI_MAX_PORTS];
252
253 struct sci_phy_oem_params {
254 /**
255 * This field specifies the SAS address to be transmitted on
256 * for this phy index.
257 */
258 struct sci_sas_address sas_address;
259
260 } phys[SCI_MAX_PHYS];
261
262};
263
264/**
265 * This structure/union specifies the various different OEM parameter sets 228 * This structure/union specifies the various different OEM parameter sets
266 * available. Each type is specific to a hardware controller version. 229 * available. Each type is specific to a hardware controller version.
267 * 230 *
@@ -273,7 +236,7 @@ union scic_oem_parameters {
273 * Storage Controller Unit (SCU) Driver Standard (SDS) version 236 * Storage Controller Unit (SCU) Driver Standard (SDS) version
274 * 1. 237 * 1.
275 */ 238 */
276 struct scic_sds_oem_parameters sds1; 239 struct scic_sds_oem_params sds1;
277 240
278}; 241};
279 242
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
2039 2039
2040 /* Initialize all of the phy parameter information. */ 2040 /* Initialize all of the phy parameter information. */
2041 for (index = 0; index < SCI_MAX_PHYS; index++) { 2041 for (index = 0; index < SCI_MAX_PHYS; index++) {
2042 /* 2042 /* Default to 6G (i.e. Gen 3) for now. */
2043 * Default to 3G (i.e. Gen 2) for now. User can override if 2043 scic->user_parameters.sds1.phys[index].max_speed_generation = 3;
2044 * they choose. */
2045 scic->user_parameters.sds1.phys[index].max_speed_generation = 2;
2046 2044
2047 /* the frequencies cannot be 0 */ 2045 /* the frequencies cannot be 0 */
2048 scic->user_parameters.sds1.phys[index].align_insertion_frequency = 0x7f; 2046 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 @@
6#include <fcntl.h> 6#include <fcntl.h>
7#include <string.h> 7#include <string.h>
8#include <errno.h> 8#include <errno.h>
9#include <asm/types.h>
10#include <strings.h>
11#include <stdint.h>
9 12
10char blob_name[] = "isci_firmware.bin"; 13#include "create_fw.h"
11char id[] = "#SCU MAGIC#"; 14#include "../probe_roms.h"
12unsigned char version = 1; 15
13unsigned char sub_version = 0; 16int write_blob(struct isci_orom *isci_orom)
14
15
16/*
17 * For all defined arrays:
18 * elements 0-3 are for SCU0, ports 0-3
19 * elements 4-7 are for SCU1, ports 0-3
20 *
21 * valid configurations for one SCU are:
22 * P0 P1 P2 P3
23 * ----------------
24 * 0xF,0x0,0x0,0x0 # 1 x4 port
25 * 0x3,0x0,0x4,0x8 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are each x1
26 * # ports
27 * 0x1,0x2,0xC,0x0 # Phys 0 and 1 are each x1 ports, phy 2 and phy 3 are a x2
28 * # port
29 * 0x3,0x0,0xC,0x0 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are a x2 port
30 * 0x1,0x2,0x4,0x8 # Each phy is a x1 port (this is the default configuration)
31 *
32 * if there is a port/phy on which you do not wish to override the default
33 * values, use the value assigned to UNINIT_PARAM (255).
34 */
35unsigned int phy_mask[] = { 1, 2, 4, 8, 1, 2, 4, 8 };
36
37
38/* denotes SAS generation. i.e. 3: SAS Gen 3 6G */
39unsigned int phy_gen[] = { 3, 3, 3, 3, 3, 3, 3, 3 };
40
41/*
42 * if there is a port/phy on which you do not wish to override the default
43 * values, use the value "0000000000000000". SAS address of zero's is
44 * considered invalid and will not be used.
45 */
46unsigned long long sas_addr[] = { 0x5FCFFFFFF0000000ULL,
47 0x5FCFFFFFF1000000ULL,
48 0x5FCFFFFFF2000000ULL,
49 0x5FCFFFFFF3000000ULL,
50 0x5FCFFFFFF4000000ULL,
51 0x5FCFFFFFF5000000ULL,
52 0x5FCFFFFFF6000000ULL,
53 0x5FCFFFFFF7000000ULL };
54
55int write_blob(void)
56{ 17{
57 FILE *fd; 18 FILE *fd;
58 int err; 19 int err;
20 size_t count;
59 21
60 fd = fopen(blob_name, "w+"); 22 fd = fopen(blob_name, "w+");
61 if (!fd) { 23 if (!fd) {
62 perror("Open file for write failed"); 24 perror("Open file for write failed");
25 fclose(fd);
63 return -EIO; 26 return -EIO;
64 } 27 }
65 28
66 /* write id */ 29 count = fwrite(isci_orom, sizeof(struct isci_orom), 1, fd);
67 err = fwrite((void *)id, sizeof(char), strlen(id)+1, fd); 30 if (count != 1) {
68 if (err == 0) { 31 perror("Write data failed");
69 perror("write id failed"); 32 fclose(fd);
70 return err;
71 }
72
73 /* write version */
74 err = fwrite((void *)&version, sizeof(version), 1, fd);
75 if (err == 0) {
76 perror("write version failed");
77 return err;
78 }
79
80 /* write sub version */
81 err = fwrite((void *)&sub_version, sizeof(sub_version), 1, fd);
82 if (err == 0) {
83 perror("write subversion failed");
84 return err;
85 }
86
87 /* write phy mask header */
88 err = fputc(0x1, fd);
89 if (err == EOF) {
90 perror("write phy mask header failed");
91 return -EIO;
92 }
93
94 /* write size */
95 err = fputc(8, fd);
96 if (err == EOF) {
97 perror("write phy mask size failed");
98 return -EIO;
99 }
100
101 /* write phy masks */
102 err = fwrite((void *)phy_mask, 1, sizeof(phy_mask), fd);
103 if (err == 0) {
104 perror("write phy_mask failed");
105 return err;
106 }
107
108 /* write phy gen header */
109 err = fputc(0x2, fd);
110 if (err == EOF) {
111 perror("write phy gen header failed");
112 return -EIO;
113 }
114
115 /* write size */
116 err = fputc(8, fd);
117 if (err == EOF) {
118 perror("write phy gen size failed");
119 return -EIO;
120 }
121
122 /* write phy_gen */
123 err = fwrite((void *)phy_gen,
124 1,
125 sizeof(phy_gen),
126 fd);
127 if (err == 0) {
128 perror("write phy_gen failed");
129 return err;
130 }
131
132 /* write phy gen header */
133 err = fputc(0x3, fd);
134 if (err == EOF) {
135 perror("write sas addr header failed");
136 return -EIO;
137 }
138
139 /* write size */
140 err = fputc(8, fd);
141 if (err == EOF) {
142 perror("write sas addr size failed");
143 return -EIO;
144 }
145
146 /* write sas_addr */
147 err = fwrite((void *)sas_addr,
148 1,
149 sizeof(sas_addr),
150 fd);
151 if (err == 0) {
152 perror("write sas_addr failed");
153 return err;
154 }
155
156 /* write end header */
157 err = fputc(0xff, fd);
158 if (err == EOF) {
159 perror("write end header failed");
160 return -EIO; 33 return -EIO;
161 } 34 }
162 35
@@ -165,13 +38,53 @@ int write_blob(void)
165 return 0; 38 return 0;
166} 39}
167 40
41void set_binary_values(struct isci_orom *isci_orom)
42{
43 int ctrl_idx, phy_idx, port_idx;
44
45 /* setting OROM signature */
46 strncpy(isci_orom->hdr.signature, sig, strlen(sig));
47 isci_orom->hdr.version = 0x10;
48 isci_orom->hdr.total_block_length = sizeof(struct isci_orom);
49 isci_orom->hdr.hdr_length = sizeof(struct sci_bios_oem_param_block_hdr);
50 isci_orom->hdr.num_elements = num_elements;
51
52 for (ctrl_idx = 0; ctrl_idx < 2; ctrl_idx++) {
53 isci_orom->ctrl[ctrl_idx].controller.mode_type = mode_type;
54 isci_orom->ctrl[ctrl_idx].controller.max_concurrent_dev_spin_up =
55 max_num_concurrent_dev_spin_up;
56 isci_orom->ctrl[ctrl_idx].controller.do_enable_ssc =
57 enable_ssc;
58
59 for (port_idx = 0; port_idx < 4; port_idx++)
60 isci_orom->ctrl[ctrl_idx].ports[port_idx].phy_mask =
61 phy_mask[ctrl_idx][port_idx];
62
63 for (phy_idx = 0; phy_idx < 4; phy_idx++) {
64 isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.high =
65 (__u32)(sas_addr[ctrl_idx][phy_idx] >> 32);
66 isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.low =
67 (__u32)(sas_addr[ctrl_idx][phy_idx]);
68 }
69 }
70}
71
168int main(void) 72int main(void)
169{ 73{
170 int err; 74 int err;
75 struct isci_orom *isci_orom;
76
77 isci_orom = malloc(sizeof(struct isci_orom));
78 memset(isci_orom, 0, sizeof(struct isci_orom));
171 79
172 err = write_blob(); 80 set_binary_values(isci_orom);
173 if (err < 0) 81
82 err = write_blob(isci_orom);
83 if (err < 0) {
84 free(isci_orom);
174 return err; 85 return err;
86 }
175 87
88 free(isci_orom);
176 return 0; 89 return 0;
177} 90}
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 @@
1#ifndef _CREATE_FW_H_
2#define _CREATE_FW_H_
3
4
5/* we are configuring for 2 SCUs */
6static const int num_elements = 2;
7
8/*
9 * For all defined arrays:
10 * elements 0-3 are for SCU0, ports 0-3
11 * elements 4-7 are for SCU1, ports 0-3
12 *
13 * valid configurations for one SCU are:
14 * P0 P1 P2 P3
15 * ----------------
16 * 0xF,0x0,0x0,0x0 # 1 x4 port
17 * 0x3,0x0,0x4,0x8 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are each x1
18 * # ports
19 * 0x1,0x2,0xC,0x0 # Phys 0 and 1 are each x1 ports, phy 2 and phy 3 are a x2
20 * # port
21 * 0x3,0x0,0xC,0x0 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are a x2 port
22 * 0x1,0x2,0x4,0x8 # Each phy is a x1 port (this is the default configuration)
23 *
24 * if there is a port/phy on which you do not wish to override the default
25 * values, use the value assigned to UNINIT_PARAM (255).
26 */
27#ifdef MPC
28static const __u8 phy_mask[2][4] = { {1, 2, 4, 8},
29 {1, 2, 4, 8} };
30#else /* APC (default) */
31static const __u8 phy_mask[2][4];
32#endif
33
34/* discovery mode type (port auto config mode by default ) */
35static const int mode_type;
36
37/* Maximum number of concurrent device spin up */
38static const int max_num_concurrent_dev_spin_up = 1;
39
40/* enable of ssc operation */
41static const int enable_ssc;
42
43/* AFE_TX_AMP_CONTROL */
44static const unsigned int afe_tx_amp_control0 = 0x000e7c03;
45static const unsigned int afe_tx_amp_control1 = 0x000e7c03;
46static const unsigned int afe_tx_amp_control2 = 0x000e7c03;
47static const unsigned int afe_tx_amp_control3 = 0x000e7c03;
48
49/*
50 * if there is a port/phy on which you do not wish to override the default
51 * values, use the value "0000000000000000". SAS address of zero's is
52 * considered invalid and will not be used.
53 */
54static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFFF0000000ULL,
55 0x5FCFFFFFF1000000ULL,
56 0x5FCFFFFFF2000000ULL,
57 0x5FCFFFFFF3000000ULL },
58 { 0x5FCFFFFFF4000000ULL,
59 0x5FCFFFFFF5000000ULL,
60 0x5FCFFFFFF6000000ULL,
61 0x5FCFFFFFF7000000ULL } };
62
63static const char blob_name[] = "isci_firmware.bin";
64static const char sig[] = "ISCUOEMB";
65static const unsigned char version = 1;
66
67#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 @@
61#include "port.h" 61#include "port.h"
62#include "request.h" 62#include "request.h"
63#include "host.h" 63#include "host.h"
64#include "probe_roms.h"
64 65
65irqreturn_t isci_msix_isr(int vec, void *data) 66irqreturn_t isci_msix_isr(int vec, void *data)
66{ 67{
@@ -419,6 +420,7 @@ int isci_host_init(struct isci_host *isci_host)
419 struct scic_sds_controller *controller; 420 struct scic_sds_controller *controller;
420 union scic_oem_parameters scic_oem_params; 421 union scic_oem_parameters scic_oem_params;
421 union scic_user_parameters scic_user_params; 422 union scic_user_parameters scic_user_params;
423 struct isci_pci_info *pci_info = to_pci_info(isci_host->pdev);
422 424
423 isci_timer_list_construct(isci_host); 425 isci_timer_list_construct(isci_host);
424 426
@@ -461,31 +463,32 @@ int isci_host_init(struct isci_host *isci_host)
461 sci_object_set_association(isci_host->core_controller, 463 sci_object_set_association(isci_host->core_controller,
462 (void *)isci_host); 464 (void *)isci_host);
463 465
464 /* grab initial values stored in the controller object for OEM and USER 466 /*
465 * parameters */ 467 * grab initial values stored in the controller object for OEM and USER
466 scic_oem_parameters_get(controller, &scic_oem_params); 468 * parameters
469 */
467 scic_user_parameters_get(controller, &scic_user_params); 470 scic_user_parameters_get(controller, &scic_user_params);
471 status = scic_user_parameters_set(isci_host->core_controller,
472 &scic_user_params);
473 if (status != SCI_SUCCESS) {
474 dev_warn(&isci_host->pdev->dev,
475 "%s: scic_user_parameters_set failed\n",
476 __func__);
477 return -ENODEV;
478 }
479
480 scic_oem_parameters_get(controller, &scic_oem_params);
468 481
469 if (isci_firmware) { 482 /* grab any OEM parameters specified in orom */
470 /* grab any OEM and USER parameters specified in binary blob */ 483 if (pci_info->orom) {
471 status = isci_parse_oem_parameters(&scic_oem_params, 484 status = isci_parse_oem_parameters(&scic_oem_params,
472 isci_host->id, 485 pci_info->orom,
473 isci_firmware); 486 isci_host->id);
474 if (status != SCI_SUCCESS) { 487 if (status != SCI_SUCCESS) {
475 dev_warn(&isci_host->pdev->dev, 488 dev_warn(&isci_host->pdev->dev,
476 "parsing firmware oem parameters failed\n"); 489 "parsing firmware oem parameters failed\n");
477 return -EINVAL; 490 return -EINVAL;
478 } 491 }
479
480 status = isci_parse_user_parameters(&scic_user_params,
481 isci_host->id,
482 isci_firmware);
483 if (status != SCI_SUCCESS) {
484 dev_warn(&isci_host->pdev->dev,
485 "%s: isci_parse_user_parameters"
486 " failed\n", __func__);
487 return -EINVAL;
488 }
489 } else { 492 } else {
490 status = scic_oem_parameters_set(isci_host->core_controller, 493 status = scic_oem_parameters_set(isci_host->core_controller,
491 &scic_oem_params); 494 &scic_oem_params);
@@ -495,16 +498,6 @@ int isci_host_init(struct isci_host *isci_host)
495 __func__); 498 __func__);
496 return -ENODEV; 499 return -ENODEV;
497 } 500 }
498
499
500 status = scic_user_parameters_set(isci_host->core_controller,
501 &scic_user_params);
502 if (status != SCI_SUCCESS) {
503 dev_warn(&isci_host->pdev->dev,
504 "%s: scic_user_parameters_set failed\n",
505 __func__);
506 return -ENODEV;
507 }
508 } 501 }
509 502
510 tasklet_init(&isci_host->completion_tasklet, 503 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
140 140
141struct isci_pci_info { 141struct isci_pci_info {
142 struct msix_entry msix_entries[SCI_MAX_MSIX_INT]; 142 struct msix_entry msix_entries[SCI_MAX_MSIX_INT];
143 int core_lib_array_index;
144 struct isci_host *hosts[SCI_MAX_CONTROLLERS]; 143 struct isci_host *hosts[SCI_MAX_CONTROLLERS];
144 struct isci_orom *orom;
145}; 145};
146 146
147static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev) 147static 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 @@
56#include <linux/kernel.h> 56#include <linux/kernel.h>
57#include <linux/init.h> 57#include <linux/init.h>
58#include <linux/module.h> 58#include <linux/module.h>
59#include <linux/firmware.h>
60#include <linux/efi.h>
59#include <asm/string.h> 61#include <asm/string.h>
60#include "isci.h" 62#include "isci.h"
61#include "task.h" 63#include "task.h"
62#include "sci_controller_constants.h" 64#include "sci_controller_constants.h"
63#include "scic_remote_device.h" 65#include "scic_remote_device.h"
64#include "sci_environment.h" 66#include "sci_environment.h"
67#include "probe_roms.h"
65 68
66static struct scsi_transport_template *isci_transport_template; 69static struct scsi_transport_template *isci_transport_template;
67 70
@@ -373,85 +376,6 @@ static int isci_setup_interrupts(struct pci_dev *pdev)
373 return err; 376 return err;
374} 377}
375 378
376/**
377 * isci_parse_oem_parameters() - This method will take OEM parameters
378 * from the module init parameters and copy them to oem_params. This will
379 * only copy values that are not set to the module parameter default values
380 * @oem_parameters: This parameter specifies the controller default OEM
381 * parameters. It is expected that this has been initialized to the default
382 * parameters for the controller
383 *
384 *
385 */
386enum sci_status isci_parse_oem_parameters(union scic_oem_parameters *oem_params,
387 int scu_index,
388 struct isci_firmware *fw)
389{
390 int i;
391
392 /* check for valid inputs */
393 if (!(scu_index >= 0
394 && scu_index < SCI_MAX_CONTROLLERS
395 && oem_params != NULL)) {
396 return SCI_FAILURE;
397 }
398
399 for (i = 0; i < SCI_MAX_PHYS; i++) {
400 int array_idx = i + (SCI_MAX_PHYS * scu_index);
401 u64 sas_addr = fw->sas_addrs[array_idx];
402
403 if (sas_addr != 0) {
404 oem_params->sds1.phys[i].sas_address.low =
405 (u32)(sas_addr & 0xffffffff);
406 oem_params->sds1.phys[i].sas_address.high =
407 (u32)((sas_addr >> 32) & 0xffffffff);
408 }
409 }
410
411 for (i = 0; i < SCI_MAX_PORTS; i++) {
412 int array_idx = i + (SCI_MAX_PORTS * scu_index);
413 u32 pmask = fw->phy_masks[array_idx];
414
415 oem_params->sds1.ports[i].phy_mask = pmask;
416 }
417
418 return SCI_SUCCESS;
419}
420
421/**
422 * isci_parse_user_parameters() - This method will take user parameters
423 * from the module init parameters and copy them to user_params. This will
424 * only copy values that are not set to the module parameter default values
425 * @user_parameters: This parameter specifies the controller default user
426 * parameters. It is expected that this has been initialized to the default
427 * parameters for the controller
428 *
429 *
430 */
431enum sci_status isci_parse_user_parameters(
432 union scic_user_parameters *user_params,
433 int scu_index,
434 struct isci_firmware *fw)
435{
436 int i;
437
438 if (!(scu_index >= 0
439 && scu_index < SCI_MAX_CONTROLLERS
440 && user_params != NULL)) {
441 return SCI_FAILURE;
442 }
443
444 for (i = 0; i < SCI_MAX_PORTS; i++) {
445 int array_idx = i + (SCI_MAX_PORTS * scu_index);
446 u32 gen = fw->phy_gens[array_idx];
447
448 user_params->sds1.phys[i].max_speed_generation = gen;
449
450 }
451
452 return SCI_SUCCESS;
453}
454
455static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id) 379static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
456{ 380{
457 struct isci_host *isci_host; 381 struct isci_host *isci_host;
@@ -535,73 +459,13 @@ static void check_si_rev(struct pci_dev *pdev)
535 459
536} 460}
537 461
538static int isci_verify_firmware(const struct firmware *fw,
539 struct isci_firmware *isci_fw)
540{
541 const u8 *tmp;
542
543 if (fw->size < ISCI_FIRMWARE_MIN_SIZE)
544 return -EINVAL;
545
546 tmp = fw->data;
547
548 /* 12th char should be the NULL terminate for the ID string */
549 if (tmp[11] != '\0')
550 return -EINVAL;
551
552 if (strncmp("#SCU MAGIC#", tmp, 11) != 0)
553 return -EINVAL;
554
555 isci_fw->id = tmp;
556 isci_fw->version = fw->data[ISCI_FW_VER_OFS];
557 isci_fw->subversion = fw->data[ISCI_FW_SUBVER_OFS];
558
559 tmp = fw->data + ISCI_FW_DATA_OFS;
560
561 while (*tmp != ISCI_FW_HDR_EOF) {
562 switch (*tmp) {
563 case ISCI_FW_HDR_PHYMASK:
564 tmp++;
565 isci_fw->phy_masks_size = *tmp;
566 tmp++;
567 isci_fw->phy_masks = (const u32 *)tmp;
568 tmp += sizeof(u32) * isci_fw->phy_masks_size;
569 break;
570
571 case ISCI_FW_HDR_PHYGEN:
572 tmp++;
573 isci_fw->phy_gens_size = *tmp;
574 tmp++;
575 isci_fw->phy_gens = (const u32 *)tmp;
576 tmp += sizeof(u32) * isci_fw->phy_gens_size;
577 break;
578
579 case ISCI_FW_HDR_SASADDR:
580 tmp++;
581 isci_fw->sas_addrs_size = *tmp;
582 tmp++;
583 isci_fw->sas_addrs = (const u64 *)tmp;
584 tmp += sizeof(u64) * isci_fw->sas_addrs_size;
585 break;
586
587 default:
588 pr_err("bad field in firmware binary blob\n");
589 return -EINVAL;
590 }
591 }
592
593 pr_info("isci firmware v%u.%u loaded.\n",
594 isci_fw->version, isci_fw->subversion);
595
596 return SCI_SUCCESS;
597}
598
599static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 462static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
600{ 463{
601 struct isci_pci_info *pci_info; 464 struct isci_pci_info *pci_info;
602 int err, i; 465 int err, i;
603 struct isci_host *isci_host; 466 struct isci_host *isci_host;
604 const struct firmware *fw = NULL; 467 const struct firmware *fw = NULL;
468 struct isci_orom *orom;
605 469
606 check_si_rev(pdev); 470 check_si_rev(pdev);
607 471
@@ -610,33 +474,32 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
610 return -ENOMEM; 474 return -ENOMEM;
611 pci_set_drvdata(pdev, pci_info); 475 pci_set_drvdata(pdev, pci_info);
612 476
613 err = request_firmware(&fw, ISCI_FW_NAME, &pdev->dev); 477 if (efi_enabled) {
614 if (err) { 478 /* do EFI parsing here */
615 dev_warn(&pdev->dev, 479 orom = NULL;
616 "Loading firmware failed, using default values\n"); 480 } else
617 dev_warn(&pdev->dev, 481 orom = isci_request_oprom(pdev);
618 "Default OEM configuration being used:" 482
619 " 4 narrow ports, and default SAS Addresses\n"); 483 if (!orom) {
620 } else { 484 orom = isci_request_firmware(pdev, fw);
621 isci_firmware = devm_kzalloc(&pdev->dev, 485 if (!orom) {
622 sizeof(struct isci_firmware), 486 /* TODO convert this to WARN_TAINT_ONCE once the
623 GFP_KERNEL); 487 * orom/efi parameter support is widely available
624 if (isci_firmware) { 488 */
625 err = isci_verify_firmware(fw, isci_firmware); 489 dev_warn(&pdev->dev,
626 if (err != SCI_SUCCESS) { 490 "Loading user firmware failed, using default "
627 dev_warn(&pdev->dev, 491 "values\n");
628 "firmware verification failed\n"); 492 dev_warn(&pdev->dev,
629 dev_warn(&pdev->dev, 493 "Default OEM configuration being used: 4 "
630 "Default OEM configuration being used:" 494 "narrow ports, and default SAS Addresses\n");
631 " 4 narrow ports, and default SAS "
632 "Addresses\n");
633 devm_kfree(&pdev->dev, isci_firmware);
634 isci_firmware = NULL;
635 }
636 } 495 }
637 release_firmware(fw);
638 } 496 }
639 497
498 if (orom)
499 dev_info(&pdev->dev, "sas parameters (version: %#x) loaded\n",
500 orom->hdr.version);
501 pci_info->orom = orom;
502
640 err = isci_pci_init(pdev); 503 err = isci_pci_init(pdev);
641 if (err) 504 if (err)
642 return err; 505 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 @@
61#include <linux/types.h> 61#include <linux/types.h>
62#include <linux/spinlock.h> 62#include <linux/spinlock.h>
63#include <linux/interrupt.h> 63#include <linux/interrupt.h>
64#include <linux/firmware.h>
65#include <linux/bug.h> 64#include <linux/bug.h>
66#include <scsi/libsas.h> 65#include <scsi/libsas.h>
67#include <scsi/scsi.h> 66#include <scsi/scsi.h>
@@ -76,34 +75,6 @@
76#include "task.h" 75#include "task.h"
77#include "sata.h" 76#include "sata.h"
78 77
79extern struct isci_firmware *isci_firmware;
80
81#define ISCI_FW_NAME "isci/isci_firmware.bin"
82
83#define ISCI_FIRMWARE_MIN_SIZE 149
84
85#define ISCI_FW_IDSIZE 12
86#define ISCI_FW_VER_OFS ISCI_FW_IDSIZE
87#define ISCI_FW_SUBVER_OFS ISCI_FW_VER_OFS + 1
88#define ISCI_FW_DATA_OFS ISCI_FW_SUBVER_OFS + 1
89
90#define ISCI_FW_HDR_PHYMASK 0x1
91#define ISCI_FW_HDR_PHYGEN 0x2
92#define ISCI_FW_HDR_SASADDR 0x3
93#define ISCI_FW_HDR_EOF 0xff
94
95struct isci_firmware {
96 const u8 *id;
97 u8 version;
98 u8 subversion;
99 const u32 *phy_masks;
100 u8 phy_masks_size;
101 const u32 *phy_gens;
102 u8 phy_gens_size;
103 const u64 *sas_addrs;
104 u8 sas_addrs_size;
105};
106
107irqreturn_t isci_msix_isr(int vec, void *data); 78irqreturn_t isci_msix_isr(int vec, void *data);
108irqreturn_t isci_intx_isr(int vec, void *data); 79irqreturn_t isci_intx_isr(int vec, void *data);
109irqreturn_t isci_error_isr(int vec, void *data); 80irqreturn_t isci_error_isr(int vec, void *data);
@@ -113,14 +84,4 @@ void scic_sds_controller_completion_handler(struct scic_sds_controller *scic);
113bool scic_sds_controller_error_isr(struct scic_sds_controller *scic); 84bool scic_sds_controller_error_isr(struct scic_sds_controller *scic);
114void scic_sds_controller_error_handler(struct scic_sds_controller *scic); 85void scic_sds_controller_error_handler(struct scic_sds_controller *scic);
115 86
116enum sci_status isci_parse_oem_parameters(
117 union scic_oem_parameters *oem_params,
118 int scu_index,
119 struct isci_firmware *fw);
120
121enum sci_status isci_parse_user_parameters(
122 union scic_user_parameters *user_params,
123 int scu_index,
124 struct isci_firmware *fw);
125
126#endif /* __ISCI_H__ */ 87#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 @@
1/*
2 * This file is provided under a dual BSD/GPLv2 license. When using or
3 * redistributing this file, you may do so under either license.
4 *
5 * GPL LICENSE SUMMARY
6 *
7 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21 * The full GNU General Public License is included in this distribution
22 * in the file called LICENSE.GPL.
23 */
24
25/* probe_roms - scan for oem parameters */
26
27#include <linux/kernel.h>
28#include <linux/firmware.h>
29#include <linux/uaccess.h>
30#include <asm/probe_roms.h>
31
32#include "isci.h"
33#include "task.h"
34#include "sci_controller_constants.h"
35#include "scic_remote_device.h"
36#include "sci_environment.h"
37#include "probe_roms.h"
38
39struct isci_orom *isci_request_oprom(struct pci_dev *pdev)
40{
41 void __iomem *oprom = pci_map_biosrom(pdev);
42 struct isci_orom *rom = NULL;
43 size_t len, i;
44
45 if (!oprom)
46 return NULL;
47
48 len = pci_biosrom_size(pdev);
49 rom = devm_kzalloc(&pdev->dev, sizeof(*rom), GFP_KERNEL);
50
51 for (i = 0; i < len && rom; i += ISCI_ROM_SIG_SIZE) {
52 memcpy_fromio(rom->hdr.signature, oprom + i, ISCI_ROM_SIG_SIZE);
53 if (memcmp(rom->hdr.signature, ISCI_ROM_SIG,
54 ISCI_ROM_SIG_SIZE) == 0) {
55 size_t copy_len = min(len - i, sizeof(*rom));
56
57 memcpy_fromio(rom, oprom + i, copy_len);
58 break;
59 }
60 }
61
62 if (i >= len) {
63 dev_err(&pdev->dev, "oprom parse error\n");
64 devm_kfree(&pdev->dev, rom);
65 rom = NULL;
66 }
67 pci_unmap_biosrom(oprom);
68
69 return rom;
70}
71
72/**
73 * isci_parse_oem_parameters() - This method will take OEM parameters
74 * from the module init parameters and copy them to oem_params. This will
75 * only copy values that are not set to the module parameter default values
76 * @oem_parameters: This parameter specifies the controller default OEM
77 * parameters. It is expected that this has been initialized to the default
78 * parameters for the controller
79 *
80 *
81 */
82enum sci_status isci_parse_oem_parameters(union scic_oem_parameters *oem_params,
83 struct isci_orom *orom, int scu_index)
84{
85 int i;
86
87 /* check for valid inputs */
88 if (!(scu_index >= 0
89 && scu_index < SCI_MAX_CONTROLLERS
90 && oem_params != NULL))
91 return -EINVAL;
92
93 for (i = 0; i < SCI_MAX_PHYS; i++) {
94 oem_params->sds1.phys[i].sas_address.low =
95 orom->ctrl[scu_index].phys[i].sas_address.low;
96 oem_params->sds1.phys[i].sas_address.high =
97 orom->ctrl[scu_index].phys[i].sas_address.high;
98 }
99
100 for (i = 0; i < SCI_MAX_PORTS; i++)
101 oem_params->sds1.ports[i].phy_mask =
102 orom->ctrl[scu_index].ports[i].phy_mask;
103
104 return 0;
105}
106
107struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw)
108{
109 struct isci_orom *orom = NULL, *data;
110
111 if (request_firmware(&fw, ISCI_FW_NAME, &pdev->dev) != 0)
112 return NULL;
113
114 if (fw->size < sizeof(*orom))
115 goto out;
116
117 data = (struct isci_orom *)fw->data;
118
119 if (strncmp(ISCI_ROM_SIG, data->hdr.signature,
120 strlen(ISCI_ROM_SIG)) != 0)
121 goto out;
122
123 orom = devm_kzalloc(&pdev->dev, fw->size, GFP_KERNEL);
124 if (!orom)
125 goto out;
126
127 memcpy(orom, fw->data, fw->size);
128
129 out:
130 release_firmware(fw);
131
132 return orom;
133}
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 @@
1/*
2 * This file is provided under a dual BSD/GPLv2 license. When using or
3 * redistributing this file, you may do so under either license.
4 *
5 * GPL LICENSE SUMMARY
6 *
7 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21 * The full GNU General Public License is included in this distribution
22 * in the file called LICENSE.GPL.
23 *
24 * BSD LICENSE
25 *
26 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 *
33 * * Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * * Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in
37 * the documentation and/or other materials provided with the
38 * distribution.
39 * * Neither the name of Intel Corporation nor the names of its
40 * contributors may be used to endorse or promote products derived
41 * from this software without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 */
55#ifndef _ISCI_PROBE_ROMS_H_
56#define _ISCI_PROBE_ROMS_H_
57
58#ifdef __KERNEL__
59#include <linux/firmware.h>
60#include <linux/pci.h>
61
62struct isci_orom *isci_request_oprom(struct pci_dev *pdev);
63
64union scic_oem_parameters;
65struct isci_orom;
66
67enum sci_status isci_parse_oem_parameters(
68 union scic_oem_parameters *oem_params,
69 struct isci_orom *orom,
70 int scu_index);
71struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw);
72int isci_get_efi_var(struct pci_dev *pdev);
73#else
74#define SCI_MAX_PORTS 4
75#define SCI_MAX_PHYS 4
76#endif
77
78#define ISCI_FW_NAME "isci/isci_firmware.bin"
79
80#define ROMSIGNATURE 0xaa55
81
82#define ISCI_ROM_SIG "ISCUOEMB"
83#define ISCI_ROM_SIG_SIZE 8
84
85#define ISCI_EFI_VENDOR_GUID NULL_GUID
86#define ISCI_EFI_ATTRIBUTES 0
87#define ISCI_EFI_VAR_NAME "isci_oemb"
88
89struct sci_bios_oem_param_block_hdr {
90 uint8_t signature[ISCI_ROM_SIG_SIZE];
91 uint16_t total_block_length;
92 uint8_t hdr_length;
93 uint8_t version;
94 uint8_t preboot_source;
95 uint8_t num_elements;
96 uint8_t element_length;
97 uint8_t reserved[8];
98} __attribute__ ((packed));
99
100struct scic_sds_oem_params {
101 struct {
102 uint8_t mode_type;
103 uint8_t max_concurrent_dev_spin_up;
104 uint8_t do_enable_ssc;
105 uint8_t reserved;
106 } controller;
107
108 struct {
109 uint8_t phy_mask;
110 } ports[SCI_MAX_PORTS];
111
112 struct sci_phy_oem_params {
113 struct {
114 uint32_t high;
115 uint32_t low;
116 } sas_address;
117
118 uint32_t afe_tx_amp_control0;
119 uint32_t afe_tx_amp_control1;
120 uint32_t afe_tx_amp_control2;
121 uint32_t afe_tx_amp_control3;
122 } phys[SCI_MAX_PHYS];
123} __attribute__ ((packed));
124
125struct isci_orom {
126 struct sci_bios_oem_param_block_hdr hdr;
127 struct scic_sds_oem_params ctrl[2];
128} __attribute__ ((packed));
129
130#endif