Commit d044af17aacd03a1f4fced1af4b7570d205c8fd9

Authored by Dan Williams
1 parent 9affa289e2

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>

Showing 12 changed files with 453 additions and 427 deletions Side-by-side Diff

drivers/scsi/isci/Makefile
... ... @@ -9,7 +9,7 @@
9 9 obj-$(CONFIG_SCSI_ISCI) += isci.o
10 10 isci-objs := init.o phy.o request.o sata.o \
11 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 13 core/scic_sds_controller.o \
14 14 core/scic_sds_remote_device.o \
15 15 core/scic_sds_request.o \
drivers/scsi/isci/core/scic_config_parameters.h
... ... @@ -68,6 +68,7 @@
68 68 #include "sci_status.h"
69 69 #include "intel_sas.h"
70 70 #include "sci_controller_constants.h"
  71 +#include "probe_roms.h"
71 72  
72 73 struct scic_sds_controller;
73 74  
... ... @@ -224,44 +225,6 @@
224 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 228 * This structure/union specifies the various different OEM parameter sets
266 229 * available. Each type is specific to a hardware controller version.
267 230 *
... ... @@ -273,7 +236,7 @@
273 236 * Storage Controller Unit (SCU) Driver Standard (SDS) version
274 237 * 1.
275 238 */
276   - struct scic_sds_oem_parameters sds1;
  239 + struct scic_sds_oem_params sds1;
277 240  
278 241 };
279 242  
drivers/scsi/isci/core/scic_sds_controller.c
... ... @@ -2039,10 +2039,8 @@
2039 2039  
2040 2040 /* Initialize all of the phy parameter information. */
2041 2041 for (index = 0; index < SCI_MAX_PHYS; index++) {
2042   - /*
2043   - * Default to 3G (i.e. Gen 2) for now. User can override if
2044   - * they choose. */
2045   - scic->user_parameters.sds1.phys[index].max_speed_generation = 2;
  2042 + /* Default to 6G (i.e. Gen 3) for now. */
  2043 + scic->user_parameters.sds1.phys[index].max_speed_generation = 3;
2046 2044  
2047 2045 /* the frequencies cannot be 0 */
2048 2046 scic->user_parameters.sds1.phys[index].align_insertion_frequency = 0x7f;
drivers/scsi/isci/firmware/create_fw.c
... ... @@ -6,173 +6,86 @@
6 6 #include <fcntl.h>
7 7 #include <string.h>
8 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";
11   -char id[] = "#SCU MAGIC#";
12   -unsigned char version = 1;
13   -unsigned char sub_version = 0;
  13 +#include "create_fw.h"
  14 +#include "../probe_roms.h"
14 15  
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)
  16 +int write_blob(struct isci_orom *isci_orom)
56 17 {
57 18 FILE *fd;
58 19 int err;
  20 + size_t count;
59 21  
60 22 fd = fopen(blob_name, "w+");
61 23 if (!fd) {
62 24 perror("Open file for write failed");
  25 + fclose(fd);
63 26 return -EIO;
64 27 }
65 28  
66   - /* write id */
67   - err = fwrite((void *)id, sizeof(char), strlen(id)+1, fd);
68   - if (err == 0) {
69   - perror("write id failed");
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");
  29 + count = fwrite(isci_orom, sizeof(struct isci_orom), 1, fd);
  30 + if (count != 1) {
  31 + perror("Write data failed");
  32 + fclose(fd);
91 33 return -EIO;
92 34 }
93 35  
94   - /* write size */
95   - err = fputc(8, fd);
96   - if (err == EOF) {
97   - perror("write phy mask size failed");
98   - return -EIO;
99   - }
  36 + fclose(fd);
100 37  
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   - }
  38 + return 0;
  39 +}
107 40  
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   - }
  41 +void set_binary_values(struct isci_orom *isci_orom)
  42 +{
  43 + int ctrl_idx, phy_idx, port_idx;
114 44  
115   - /* write size */
116   - err = fputc(8, fd);
117   - if (err == EOF) {
118   - perror("write phy gen size failed");
119   - return -EIO;
120   - }
  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;
121 51  
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   - }
  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;
131 58  
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   - }
  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];
138 62  
139   - /* write size */
140   - err = fputc(8, fd);
141   - if (err == EOF) {
142   - perror("write sas addr size failed");
143   - return -EIO;
  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 + }
144 69 }
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;
161   - }
162   -
163   - fclose(fd);
164   -
165   - return 0;
166 70 }
167 71  
168 72 int main(void)
169 73 {
170 74 int err;
  75 + struct isci_orom *isci_orom;
171 76  
172   - err = write_blob();
173   - if (err < 0)
  77 + isci_orom = malloc(sizeof(struct isci_orom));
  78 + memset(isci_orom, 0, sizeof(struct isci_orom));
  79 +
  80 + set_binary_values(isci_orom);
  81 +
  82 + err = write_blob(isci_orom);
  83 + if (err < 0) {
  84 + free(isci_orom);
174 85 return err;
  86 + }
175 87  
  88 + free(isci_orom);
176 89 return 0;
177 90 }
drivers/scsi/isci/firmware/create_fw.h
  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
drivers/scsi/isci/host.c
... ... @@ -61,6 +61,7 @@
61 61 #include "port.h"
62 62 #include "request.h"
63 63 #include "host.h"
  64 +#include "probe_roms.h"
64 65  
65 66 irqreturn_t isci_msix_isr(int vec, void *data)
66 67 {
... ... @@ -419,6 +420,7 @@
419 420 struct scic_sds_controller *controller;
420 421 union scic_oem_parameters scic_oem_params;
421 422 union scic_user_parameters scic_user_params;
  423 + struct isci_pci_info *pci_info = to_pci_info(isci_host->pdev);
422 424  
423 425 isci_timer_list_construct(isci_host);
424 426  
425 427  
426 428  
427 429  
428 430  
429 431  
... ... @@ -461,47 +463,38 @@
461 463 sci_object_set_association(isci_host->core_controller,
462 464 (void *)isci_host);
463 465  
464   - /* grab initial values stored in the controller object for OEM and USER
465   - * parameters */
466   - scic_oem_parameters_get(controller, &scic_oem_params);
  466 + /*
  467 + * grab initial values stored in the controller object for OEM and USER
  468 + * parameters
  469 + */
467 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 + }
468 479  
469   - if (isci_firmware) {
470   - /* grab any OEM and USER parameters specified in binary blob */
  480 + scic_oem_parameters_get(controller, &scic_oem_params);
  481 +
  482 + /* grab any OEM parameters specified in orom */
  483 + if (pci_info->orom) {
471 484 status = isci_parse_oem_parameters(&scic_oem_params,
472   - isci_host->id,
473   - isci_firmware);
  485 + pci_info->orom,
  486 + isci_host->id);
474 487 if (status != SCI_SUCCESS) {
475 488 dev_warn(&isci_host->pdev->dev,
476 489 "parsing firmware oem parameters failed\n");
477 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 492 } else {
490 493 status = scic_oem_parameters_set(isci_host->core_controller,
491 494 &scic_oem_params);
492 495 if (status != SCI_SUCCESS) {
493 496 dev_warn(&isci_host->pdev->dev,
494 497 "%s: scic_oem_parameters_set failed\n",
495   - __func__);
496   - return -ENODEV;
497   - }
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 498 __func__);
506 499 return -ENODEV;
507 500 }
drivers/scsi/isci/host.h
... ... @@ -140,8 +140,8 @@
140 140  
141 141 struct isci_pci_info {
142 142 struct msix_entry msix_entries[SCI_MAX_MSIX_INT];
143   - int core_lib_array_index;
144 143 struct isci_host *hosts[SCI_MAX_CONTROLLERS];
  144 + struct isci_orom *orom;
145 145 };
146 146  
147 147 static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev)
drivers/scsi/isci/init.c
... ... @@ -56,12 +56,15 @@
56 56 #include <linux/kernel.h>
57 57 #include <linux/init.h>
58 58 #include <linux/module.h>
  59 +#include <linux/firmware.h>
  60 +#include <linux/efi.h>
59 61 #include <asm/string.h>
60 62 #include "isci.h"
61 63 #include "task.h"
62 64 #include "sci_controller_constants.h"
63 65 #include "scic_remote_device.h"
64 66 #include "sci_environment.h"
  67 +#include "probe_roms.h"
65 68  
66 69 static struct scsi_transport_template *isci_transport_template;
67 70  
... ... @@ -373,85 +376,6 @@
373 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 379 static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
456 380 {
457 381 struct isci_host *isci_host;
458 382  
... ... @@ -535,73 +459,13 @@
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 462 static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
600 463 {
601 464 struct isci_pci_info *pci_info;
602 465 int err, i;
603 466 struct isci_host *isci_host;
604 467 const struct firmware *fw = NULL;
  468 + struct isci_orom *orom;
605 469  
606 470 check_si_rev(pdev);
607 471  
608 472  
609 473  
... ... @@ -610,32 +474,31 @@
610 474 return -ENOMEM;
611 475 pci_set_drvdata(pdev, pci_info);
612 476  
613   - err = request_firmware(&fw, ISCI_FW_NAME, &pdev->dev);
614   - if (err) {
615   - dev_warn(&pdev->dev,
616   - "Loading firmware failed, using default values\n");
617   - dev_warn(&pdev->dev,
618   - "Default OEM configuration being used:"
619   - " 4 narrow ports, and default SAS Addresses\n");
620   - } else {
621   - isci_firmware = devm_kzalloc(&pdev->dev,
622   - sizeof(struct isci_firmware),
623   - GFP_KERNEL);
624   - if (isci_firmware) {
625   - err = isci_verify_firmware(fw, isci_firmware);
626   - if (err != SCI_SUCCESS) {
627   - dev_warn(&pdev->dev,
628   - "firmware verification failed\n");
629   - dev_warn(&pdev->dev,
630   - "Default OEM configuration being used:"
631   - " 4 narrow ports, and default SAS "
632   - "Addresses\n");
633   - devm_kfree(&pdev->dev, isci_firmware);
634   - isci_firmware = NULL;
635   - }
  477 + if (efi_enabled) {
  478 + /* do EFI parsing here */
  479 + orom = NULL;
  480 + } else
  481 + orom = isci_request_oprom(pdev);
  482 +
  483 + if (!orom) {
  484 + orom = isci_request_firmware(pdev, fw);
  485 + if (!orom) {
  486 + /* TODO convert this to WARN_TAINT_ONCE once the
  487 + * orom/efi parameter support is widely available
  488 + */
  489 + dev_warn(&pdev->dev,
  490 + "Loading user firmware failed, using default "
  491 + "values\n");
  492 + dev_warn(&pdev->dev,
  493 + "Default OEM configuration being used: 4 "
  494 + "narrow ports, and default SAS Addresses\n");
636 495 }
637   - release_firmware(fw);
638 496 }
  497 +
  498 + if (orom)
  499 + dev_info(&pdev->dev, "sas parameters (version: %#x) loaded\n",
  500 + orom->hdr.version);
  501 + pci_info->orom = orom;
639 502  
640 503 err = isci_pci_init(pdev);
641 504 if (err)
drivers/scsi/isci/isci.h
... ... @@ -61,7 +61,6 @@
61 61 #include <linux/types.h>
62 62 #include <linux/spinlock.h>
63 63 #include <linux/interrupt.h>
64   -#include <linux/firmware.h>
65 64 #include <linux/bug.h>
66 65 #include <scsi/libsas.h>
67 66 #include <scsi/scsi.h>
... ... @@ -76,34 +75,6 @@
76 75 #include "task.h"
77 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 78 irqreturn_t isci_msix_isr(int vec, void *data);
108 79 irqreturn_t isci_intx_isr(int vec, void *data);
109 80 irqreturn_t isci_error_isr(int vec, void *data);
... ... @@ -112,16 +83,6 @@
112 83 void scic_sds_controller_completion_handler(struct scic_sds_controller *scic);
113 84 bool scic_sds_controller_error_isr(struct scic_sds_controller *scic);
114 85 void scic_sds_controller_error_handler(struct scic_sds_controller *scic);
115   -
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 86  
126 87 #endif /* __ISCI_H__ */
drivers/scsi/isci/probe_roms.c
  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 +}
drivers/scsi/isci/probe_roms.h
  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
firmware/isci/isci_firmware.bin.ihex
1   -:1000000023534355204D4147494323000100010834
2   -:1000100001000000020000000400000008000000D1
3   -:1000200001000000020000000400000008000000C1
4   -:1000300002080300000003000000030000000300AA
5   -:1000400000000300000003000000030000000300A4
6   -:1000500000000308000000F0FFFFCF5F000000F188
7   -:10006000FFFFCF5F000000F2FFFFCF5F000000F353
8   -:10007000FFFFCF5F000000F4FFFFCF5F000000F53F
9   -:10008000FFFFCF5F000000F6FFFFCF5F000000F72B
10   -:05009000FFFFCF5FFF40
  1 +:10000000495343554F454D42E70017100002000089
  2 +:10001000000000000000000001000000000000FFE0
  3 +:10002000FFCF5F000000F0000000000000000000B3
  4 +:1000300000000000000000FFFFCF5F000000F100A3
  5 +:10004000000000000000000000000000000000FFB1
  6 +:10005000FFCF5F000000F200000000000000000081
  7 +:1000600000000000000000FFFFCF5F000000F30071
  8 +:100070000000000000000000000000000000000080
  9 +:1000800001000000000000FFFFCF5F000000F4004F
  10 +:10009000000000000000000000000000000000FF61
  11 +:1000A000FFCF5F000000F50000000000000000002E
  12 +:1000B00000000000000000FFFFCF5F000000F6001E
  13 +:1000C000000000000000000000000000000000FF31
  14 +:1000D000FFCF5F000000F7000000000000000000FC
  15 +:0700E0000000000000000019
11 16 :00000001FF