aboutsummaryrefslogtreecommitdiffstats
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/
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
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 @@
1:1000000023534355204D4147494323000100010834 1:10000000495343554F454D42E70017100002000089
2:1000100001000000020000000400000008000000D1 2:10001000000000000000000001000000000000FFE0
3:1000200001000000020000000400000008000000C1 3:10002000FFCF5F000000F0000000000000000000B3
4:1000300002080300000003000000030000000300AA 4:1000300000000000000000FFFFCF5F000000F100A3
5:1000400000000300000003000000030000000300A4 5:10004000000000000000000000000000000000FFB1
6:1000500000000308000000F0FFFFCF5F000000F188 6:10005000FFCF5F000000F200000000000000000081
7:10006000FFFFCF5F000000F2FFFFCF5F000000F353 7:1000600000000000000000FFFFCF5F000000F30071
8:10007000FFFFCF5F000000F4FFFFCF5F000000F53F 8:100070000000000000000000000000000000000080
9:10008000FFFFCF5F000000F6FFFFCF5F000000F72B 9:1000800001000000000000FFFFCF5F000000F4004F
10:05009000FFFFCF5FFF40 10:10009000000000000000000000000000000000FF61
11:1000A000FFCF5F000000F50000000000000000002E
12:1000B00000000000000000FFFFCF5F000000F6001E
13:1000C000000000000000000000000000000000FF31
14:1000D000FFCF5F000000F7000000000000000000FC
15:0700E0000000000000000019
11:00000001FF 16:00000001FF