diff options
Diffstat (limited to 'drivers/scsi/isci')
-rw-r--r-- | drivers/scsi/isci/Makefile | 2 | ||||
-rw-r--r-- | drivers/scsi/isci/core/scic_config_parameters.h | 41 | ||||
-rw-r--r-- | drivers/scsi/isci/core/scic_sds_controller.c | 6 | ||||
-rw-r--r-- | drivers/scsi/isci/firmware/create_fw.c | 197 | ||||
-rw-r--r-- | drivers/scsi/isci/firmware/create_fw.h | 67 | ||||
-rw-r--r-- | drivers/scsi/isci/host.c | 47 | ||||
-rw-r--r-- | drivers/scsi/isci/host.h | 2 | ||||
-rw-r--r-- | drivers/scsi/isci/init.c | 191 | ||||
-rw-r--r-- | drivers/scsi/isci/isci.h | 39 | ||||
-rw-r--r-- | drivers/scsi/isci/probe_roms.c | 133 | ||||
-rw-r--r-- | drivers/scsi/isci/probe_roms.h | 130 |
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/ | |||
9 | obj-$(CONFIG_SCSI_ISCI) += isci.o | 9 | obj-$(CONFIG_SCSI_ISCI) += isci.o |
10 | isci-objs := init.o phy.o request.o sata.o \ | 10 | isci-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 | ||
72 | struct scic_sds_controller; | 73 | struct 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 | */ | ||
232 | struct 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 | ||
10 | char blob_name[] = "isci_firmware.bin"; | 13 | #include "create_fw.h" |
11 | char id[] = "#SCU MAGIC#"; | 14 | #include "../probe_roms.h" |
12 | unsigned char version = 1; | 15 | |
13 | unsigned char sub_version = 0; | 16 | int 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 | */ | ||
35 | unsigned int phy_mask[] = { 1, 2, 4, 8, 1, 2, 4, 8 }; | ||
36 | |||
37 | |||
38 | /* denotes SAS generation. i.e. 3: SAS Gen 3 6G */ | ||
39 | unsigned 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 | */ | ||
46 | unsigned long long sas_addr[] = { 0x5FCFFFFFF0000000ULL, | ||
47 | 0x5FCFFFFFF1000000ULL, | ||
48 | 0x5FCFFFFFF2000000ULL, | ||
49 | 0x5FCFFFFFF3000000ULL, | ||
50 | 0x5FCFFFFFF4000000ULL, | ||
51 | 0x5FCFFFFFF5000000ULL, | ||
52 | 0x5FCFFFFFF6000000ULL, | ||
53 | 0x5FCFFFFFF7000000ULL }; | ||
54 | |||
55 | int 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 | ||
41 | void 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 | |||
168 | int main(void) | 72 | int 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 */ | ||
6 | static 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 | ||
28 | static const __u8 phy_mask[2][4] = { {1, 2, 4, 8}, | ||
29 | {1, 2, 4, 8} }; | ||
30 | #else /* APC (default) */ | ||
31 | static const __u8 phy_mask[2][4]; | ||
32 | #endif | ||
33 | |||
34 | /* discovery mode type (port auto config mode by default ) */ | ||
35 | static const int mode_type; | ||
36 | |||
37 | /* Maximum number of concurrent device spin up */ | ||
38 | static const int max_num_concurrent_dev_spin_up = 1; | ||
39 | |||
40 | /* enable of ssc operation */ | ||
41 | static const int enable_ssc; | ||
42 | |||
43 | /* AFE_TX_AMP_CONTROL */ | ||
44 | static const unsigned int afe_tx_amp_control0 = 0x000e7c03; | ||
45 | static const unsigned int afe_tx_amp_control1 = 0x000e7c03; | ||
46 | static const unsigned int afe_tx_amp_control2 = 0x000e7c03; | ||
47 | static 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 | */ | ||
54 | static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFFF0000000ULL, | ||
55 | 0x5FCFFFFFF1000000ULL, | ||
56 | 0x5FCFFFFFF2000000ULL, | ||
57 | 0x5FCFFFFFF3000000ULL }, | ||
58 | { 0x5FCFFFFFF4000000ULL, | ||
59 | 0x5FCFFFFFF5000000ULL, | ||
60 | 0x5FCFFFFFF6000000ULL, | ||
61 | 0x5FCFFFFFF7000000ULL } }; | ||
62 | |||
63 | static const char blob_name[] = "isci_firmware.bin"; | ||
64 | static const char sig[] = "ISCUOEMB"; | ||
65 | static 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 | ||
65 | irqreturn_t isci_msix_isr(int vec, void *data) | 66 | irqreturn_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 | ||
141 | struct isci_pci_info { | 141 | struct 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 | ||
147 | static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev) | 147 | 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 @@ | |||
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 | ||
66 | static struct scsi_transport_template *isci_transport_template; | 69 | static 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 | */ | ||
386 | enum 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 | */ | ||
431 | enum 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 | |||
455 | static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id) | 379 | static 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 | ||
538 | static 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 | |||
599 | static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 462 | static 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 | ||
79 | extern 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 | |||
95 | struct 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 | |||
107 | irqreturn_t isci_msix_isr(int vec, void *data); | 78 | irqreturn_t isci_msix_isr(int vec, void *data); |
108 | irqreturn_t isci_intx_isr(int vec, void *data); | 79 | irqreturn_t isci_intx_isr(int vec, void *data); |
109 | irqreturn_t isci_error_isr(int vec, void *data); | 80 | irqreturn_t isci_error_isr(int vec, void *data); |
@@ -113,14 +84,4 @@ void scic_sds_controller_completion_handler(struct scic_sds_controller *scic); | |||
113 | bool scic_sds_controller_error_isr(struct scic_sds_controller *scic); | 84 | bool scic_sds_controller_error_isr(struct scic_sds_controller *scic); |
114 | void scic_sds_controller_error_handler(struct scic_sds_controller *scic); | 85 | void scic_sds_controller_error_handler(struct scic_sds_controller *scic); |
115 | 86 | ||
116 | enum sci_status isci_parse_oem_parameters( | ||
117 | union scic_oem_parameters *oem_params, | ||
118 | int scu_index, | ||
119 | struct isci_firmware *fw); | ||
120 | |||
121 | enum 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 | |||
39 | struct 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 | */ | ||
82 | enum 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 | |||
107 | struct 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 | |||
62 | struct isci_orom *isci_request_oprom(struct pci_dev *pdev); | ||
63 | |||
64 | union scic_oem_parameters; | ||
65 | struct isci_orom; | ||
66 | |||
67 | enum sci_status isci_parse_oem_parameters( | ||
68 | union scic_oem_parameters *oem_params, | ||
69 | struct isci_orom *orom, | ||
70 | int scu_index); | ||
71 | struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw); | ||
72 | int 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 | |||
89 | struct 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 | |||
100 | struct 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 | |||
125 | struct 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 | ||