2 * Intel(R) Matrix Storage Manager hardware and firmware support routines
4 * Copyright (C) 2008 Intel Corporation
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "platform-intel.h"
21 #include "probe_roms.h"
29 #include <sys/types.h>
33 static int devpath_to_ll(const char *dev_path
, const char *entry
,
34 unsigned long long *val
);
36 static __u16
devpath_to_vendor(const char *dev_path
);
38 static void free_sys_dev(struct sys_dev
**list
)
41 struct sys_dev
*next
= (*list
)->next
;
50 struct sys_dev
*find_driver_devices(const char *bus
, const char *driver
)
52 /* search sysfs for devices driven by 'driver' */
58 struct sys_dev
*head
= NULL
;
59 struct sys_dev
*list
= NULL
;
60 enum sys_dev_type type
;
61 unsigned long long dev_id
;
62 unsigned long long class;
64 if (strcmp(driver
, "isci") == 0)
66 else if (strcmp(driver
, "ahci") == 0)
68 else if (strcmp(driver
, "nvme") == 0)
71 type
= SYS_DEV_UNKNOWN
;
73 sprintf(path
, "/sys/bus/%s/drivers/%s", bus
, driver
);
74 driver_dir
= opendir(path
);
77 for (de
= readdir(driver_dir
); de
; de
= readdir(driver_dir
)) {
80 /* is 'de' a device? check that the 'subsystem' link exists and
81 * that its target matches 'bus'
83 sprintf(path
, "/sys/bus/%s/drivers/%s/%s/subsystem",
84 bus
, driver
, de
->d_name
);
85 n
= readlink(path
, link
, sizeof(link
));
86 if (n
< 0 || n
>= (int)sizeof(link
))
89 c
= strrchr(link
, '/');
92 if (strncmp(bus
, c
+1, strlen(bus
)) != 0)
95 sprintf(path
, "/sys/bus/%s/drivers/%s/%s",
96 bus
, driver
, de
->d_name
);
98 /* if it's not Intel device skip it. */
99 if (devpath_to_vendor(path
) != 0x8086)
102 if (devpath_to_ll(path
, "device", &dev_id
) != 0)
105 if (devpath_to_ll(path
, "class", &class) != 0)
108 /* start / add list entry */
110 head
= xmalloc(sizeof(*head
));
113 list
->next
= xmalloc(sizeof(*head
));
122 list
->dev_id
= (__u16
) dev_id
;
123 list
->class = (__u32
) class;
125 list
->path
= realpath(path
, NULL
);
127 if ((list
->pci_id
= strrchr(list
->path
, '/')) != NULL
)
130 closedir(driver_dir
);
134 static struct sys_dev
*intel_devices
=NULL
;
135 static time_t valid_time
= 0;
137 struct sys_dev
*device_by_id(__u16 device_id
)
139 struct sys_dev
*iter
;
141 for (iter
= intel_devices
; iter
!= NULL
; iter
= iter
->next
)
142 if (iter
->dev_id
== device_id
)
147 static int devpath_to_ll(const char *dev_path
, const char *entry
, unsigned long long *val
)
149 char path
[strlen(dev_path
) + strlen(entry
) + 2];
153 sprintf(path
, "%s/%s", dev_path
, entry
);
155 fd
= open(path
, O_RDONLY
);
158 n
= sysfs_fd_get_ll(fd
, val
);
163 static __u16
devpath_to_vendor(const char *dev_path
)
165 char path
[strlen(dev_path
) + strlen("/vendor") + 1];
171 sprintf(path
, "%s/vendor", dev_path
);
173 fd
= open(path
, O_RDONLY
);
177 n
= read(fd
, vendor
, sizeof(vendor
));
178 if (n
== sizeof(vendor
)) {
179 vendor
[n
- 1] = '\0';
180 id
= strtoul(vendor
, NULL
, 16);
187 struct sys_dev
*find_intel_devices(void)
189 struct sys_dev
*ahci
, *isci
, *nvme
;
191 if (valid_time
> time(0) - 10)
192 return intel_devices
;
195 free_sys_dev(&intel_devices
);
197 isci
= find_driver_devices("pci", "isci");
198 ahci
= find_driver_devices("pci", "ahci");
199 nvme
= find_driver_devices("pci", "nvme");
201 if (!isci
&& !ahci
) {
205 struct sys_dev
*elem
= ahci
;
210 struct sys_dev
*elem
= ahci
;
218 intel_devices
= ahci
;
219 valid_time
= time(0);
220 return intel_devices
;
224 * PCI Expansion ROM Data Structure Format */
225 struct pciExpDataStructFormat
{
230 } __attribute__ ((packed
));
232 static struct orom_entry oroms
[SYS_DEV_MAX
];
234 const struct orom_entry
*get_oroms(void)
236 return (const struct orom_entry
*)&oroms
;
239 const struct imsm_orom
*get_orom_by_device_id(__u16 dev_id
)
242 struct devid_list
*list
;
244 for (i
= 0; i
< SYS_DEV_MAX
; i
++) {
245 for (list
= oroms
[i
].devid_list
; list
; list
= list
->next
) {
246 if (list
->devid
== dev_id
)
247 return &oroms
[i
].orom
;
253 static const struct imsm_orom
*add_orom(const struct imsm_orom
*orom
)
257 for (i
= 0; i
< SYS_DEV_MAX
; i
++) {
258 if (&oroms
[i
].orom
== orom
)
260 if (oroms
[i
].orom
.signature
[0] == 0) {
261 oroms
[i
].orom
= *orom
;
262 return &oroms
[i
].orom
;
268 static void add_orom_device_id(const struct imsm_orom
*orom
, __u16 dev_id
)
271 struct devid_list
*list
;
272 struct devid_list
*prev
= NULL
;
274 for (i
= 0; i
< SYS_DEV_MAX
; i
++) {
275 if (&oroms
[i
].orom
== orom
) {
276 for (list
= oroms
[i
].devid_list
; list
; prev
= list
, list
= list
->next
) {
277 if (list
->devid
== dev_id
)
280 list
= xmalloc(sizeof(struct devid_list
));
281 list
->devid
= dev_id
;
285 oroms
[i
].devid_list
= list
;
293 static int scan(const void *start
, const void *end
, const void *data
)
296 const struct imsm_orom
*imsm_mem
= NULL
;
297 int len
= (end
- start
);
298 struct pciExpDataStructFormat
*ptr
= (struct pciExpDataStructFormat
*)data
;
300 if (data
+ 0x18 > end
) {
301 dprintf("cannot find pciExpDataStruct \n");
305 dprintf("ptr->vendorID: %lx __le16_to_cpu(ptr->deviceID): %lx \n",
306 (ulong
) __le16_to_cpu(ptr
->vendorID
),
307 (ulong
) __le16_to_cpu(ptr
->deviceID
));
309 if (__le16_to_cpu(ptr
->vendorID
) != 0x8086)
312 for (offset
= 0; offset
< len
; offset
+= 4) {
313 const void *mem
= start
+ offset
;
315 if ((memcmp(mem
, IMSM_OROM_SIGNATURE
, 4) == 0)) {
324 const struct imsm_orom
*orom
= add_orom(imsm_mem
);
326 if (ptr
->devListOffset
) {
327 const __u16
*dev_list
= (void *)ptr
+ ptr
->devListOffset
;
330 for (i
= 0; dev_list
[i
] != 0; i
++)
331 add_orom_device_id(orom
, dev_list
[i
]);
333 add_orom_device_id(orom
, __le16_to_cpu(ptr
->deviceID
));
339 const struct imsm_orom
*imsm_platform_test(struct sys_dev
*hba
)
341 struct imsm_orom orom
= {
342 .signature
= IMSM_OROM_SIGNATURE
,
343 .rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
344 IMSM_OROM_RLC_RAID10
| IMSM_OROM_RLC_RAID5
,
345 .sss
= IMSM_OROM_SSS_4kB
| IMSM_OROM_SSS_8kB
|
346 IMSM_OROM_SSS_16kB
| IMSM_OROM_SSS_32kB
|
347 IMSM_OROM_SSS_64kB
| IMSM_OROM_SSS_128kB
|
348 IMSM_OROM_SSS_256kB
| IMSM_OROM_SSS_512kB
|
349 IMSM_OROM_SSS_1MB
| IMSM_OROM_SSS_2MB
,
350 .dpa
= IMSM_OROM_DISKS_PER_ARRAY
,
351 .tds
= IMSM_OROM_TOTAL_DISKS
,
352 .vpa
= IMSM_OROM_VOLUMES_PER_ARRAY
,
353 .vphba
= IMSM_OROM_VOLUMES_PER_HBA
355 orom
.attr
= orom
.rlc
| IMSM_OROM_ATTR_ChecksumVerify
;
357 if (check_env("IMSM_TEST_OROM_NORAID5")) {
358 orom
.rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
359 IMSM_OROM_RLC_RAID10
;
361 if (check_env("IMSM_TEST_AHCI_EFI_NORAID5") && (hba
->type
== SYS_DEV_SAS
)) {
362 orom
.rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
363 IMSM_OROM_RLC_RAID10
;
365 if (check_env("IMSM_TEST_SCU_EFI_NORAID5") && (hba
->type
== SYS_DEV_SATA
)) {
366 orom
.rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
367 IMSM_OROM_RLC_RAID10
;
370 const struct imsm_orom
*ret
= add_orom(&orom
);
372 add_orom_device_id(ret
, hba
->dev_id
);
377 static const struct imsm_orom
*find_imsm_hba_orom(struct sys_dev
*hba
)
381 if (check_env("IMSM_TEST_OROM"))
382 return imsm_platform_test(hba
);
384 /* return empty OROM capabilities in EFI test mode */
385 if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI"))
388 find_intel_devices();
390 if (intel_devices
== NULL
)
393 /* scan option-rom memory looking for an imsm signature */
394 if (check_env("IMSM_SAFE_OROM_SCAN"))
398 if (probe_roms_init(align
) != 0)
401 /* ignore return value - True is returned if both adapater roms are found */
402 scan_adapter_roms(scan
);
405 return get_orom_by_device_id(hba
->dev_id
);
408 #define GUID_STR_MAX 37 /* according to GUID format:
409 * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */
411 #define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
413 {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
414 (b) & 0xff, ((b) >> 8) & 0xff, \
415 (c) & 0xff, ((c) >> 8) & 0xff, \
416 (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
418 #define SYS_EFI_VAR_PATH "/sys/firmware/efi/vars"
419 #define SYS_EFIVARS_PATH "/sys/firmware/efi/efivars"
420 #define SCU_PROP "RstScuV"
421 #define AHCI_PROP "RstSataV"
422 #define AHCI_SSATA_PROP "RstsSatV"
423 #define AHCI_CSATA_PROP "RstCSatV"
425 #define VENDOR_GUID \
426 EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, 0x1a, 0x04, 0xc6)
428 #define PCI_CLASS_RAID_CNTRL 0x010400
430 static int read_efi_var(void *buffer
, ssize_t buf_size
, char *variable_name
, struct efi_guid guid
)
433 char buf
[GUID_STR_MAX
];
437 snprintf(path
, PATH_MAX
, "%s/%s-%s", SYS_EFIVARS_PATH
, variable_name
, guid_str(buf
, guid
));
439 fd
= open(path
, O_RDONLY
);
443 /* read the variable attributes and ignore it */
444 n
= read(fd
, buf
, sizeof(__u32
));
450 /* read the variable data */
451 n
= read(fd
, buffer
, buf_size
);
459 static int read_efi_variable(void *buffer
, ssize_t buf_size
, char *variable_name
, struct efi_guid guid
)
462 char buf
[GUID_STR_MAX
];
464 ssize_t n
, var_data_len
;
466 /* Try to read the variable using the new efivarfs interface first.
467 * If that fails, fall back to the old sysfs-efivars interface. */
468 if (!read_efi_var(buffer
, buf_size
, variable_name
, guid
))
471 snprintf(path
, PATH_MAX
, "%s/%s-%s/size", SYS_EFI_VAR_PATH
, variable_name
, guid_str(buf
, guid
));
473 dprintf("EFI VAR: path=%s\n", path
);
474 /* get size of variable data */
475 dfd
= open(path
, O_RDONLY
);
479 n
= read(dfd
, &buf
, sizeof(buf
));
486 var_data_len
= strtoul(buf
, NULL
, 16);
487 if ((errno
== ERANGE
&& (var_data_len
== LONG_MAX
))
488 || (errno
!= 0 && var_data_len
== 0))
492 snprintf(path
, PATH_MAX
, "%s/%s-%s/data", SYS_EFI_VAR_PATH
, variable_name
, guid_str(buf
, guid
));
494 dprintf("EFI VAR: path=%s\n", path
);
495 dfd
= open(path
, O_RDONLY
);
499 n
= read(dfd
, buffer
, buf_size
);
501 if (n
!= var_data_len
|| n
< buf_size
) {
508 const struct imsm_orom
*find_imsm_efi(struct sys_dev
*hba
)
510 struct imsm_orom orom
;
511 const struct imsm_orom
*ret
;
514 if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI"))
515 return imsm_platform_test(hba
);
517 /* OROM test is set, return that there is no EFI capabilities */
518 if (check_env("IMSM_TEST_OROM"))
521 if (hba
->type
== SYS_DEV_SATA
&& hba
->class != PCI_CLASS_RAID_CNTRL
)
524 err
= read_efi_variable(&orom
, sizeof(orom
), hba
->type
== SYS_DEV_SAS
? SCU_PROP
: AHCI_PROP
, VENDOR_GUID
);
526 /* try to read variable for second AHCI controller */
527 if (err
&& hba
->type
== SYS_DEV_SATA
)
528 err
= read_efi_variable(&orom
, sizeof(orom
), AHCI_SSATA_PROP
, VENDOR_GUID
);
530 /* try to read variable for combined AHCI controllers */
531 if (err
&& hba
->type
== SYS_DEV_SATA
) {
532 static const struct imsm_orom
*csata
;
534 err
= read_efi_variable(&orom
, sizeof(orom
), AHCI_CSATA_PROP
, VENDOR_GUID
);
537 csata
= add_orom(&orom
);
538 add_orom_device_id(csata
, hba
->dev_id
);
546 ret
= add_orom(&orom
);
547 add_orom_device_id(ret
, hba
->dev_id
);
552 const struct imsm_orom
*find_imsm_nvme(struct sys_dev
*hba
)
554 static const struct imsm_orom
*nvme_orom
;
556 if (hba
->type
!= SYS_DEV_NVME
)
560 struct imsm_orom nvme_orom_compat
= {
561 .signature
= IMSM_NVME_OROM_COMPAT_SIGNATURE
,
562 .rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
563 IMSM_OROM_RLC_RAID10
| IMSM_OROM_RLC_RAID5
,
564 .sss
= IMSM_OROM_SSS_4kB
| IMSM_OROM_SSS_8kB
|
565 IMSM_OROM_SSS_16kB
| IMSM_OROM_SSS_32kB
|
566 IMSM_OROM_SSS_64kB
| IMSM_OROM_SSS_128kB
,
567 .dpa
= IMSM_OROM_DISKS_PER_ARRAY_NVME
,
568 .tds
= IMSM_OROM_TOTAL_DISKS_NVME
,
569 .vpa
= IMSM_OROM_VOLUMES_PER_ARRAY
,
570 .vphba
= IMSM_OROM_TOTAL_DISKS_NVME
/ 2 * IMSM_OROM_VOLUMES_PER_ARRAY
,
571 .attr
= IMSM_OROM_ATTR_2TB
| IMSM_OROM_ATTR_2TB_DISK
,
572 .driver_features
= IMSM_OROM_CAPABILITIES_EnterpriseSystem
574 nvme_orom
= add_orom(&nvme_orom_compat
);
576 add_orom_device_id(nvme_orom
, hba
->dev_id
);
580 const struct imsm_orom
*find_imsm_capability(struct sys_dev
*hba
)
582 const struct imsm_orom
*cap
= get_orom_by_device_id(hba
->dev_id
);
587 if (hba
->type
== SYS_DEV_NVME
)
588 return find_imsm_nvme(hba
);
589 if ((cap
= find_imsm_efi(hba
)) != NULL
)
591 if ((cap
= find_imsm_hba_orom(hba
)) != NULL
)
597 char *devt_to_devpath(dev_t dev
)
601 sprintf(device
, "/sys/dev/block/%d:%d/device", major(dev
), minor(dev
));
602 return realpath(device
, NULL
);
605 char *diskfd_to_devpath(int fd
)
607 /* return the device path for a disk, return NULL on error or fd
608 * refers to a partition
612 if (fstat(fd
, &st
) != 0)
614 if (!S_ISBLK(st
.st_mode
))
617 return devt_to_devpath(st
.st_rdev
);
620 int path_attached_to_hba(const char *disk_path
, const char *hba_path
)
624 if (check_env("IMSM_TEST_AHCI_DEV") ||
625 check_env("IMSM_TEST_SCU_DEV")) {
629 if (!disk_path
|| !hba_path
)
631 dprintf("hba: %s - disk: %s\n", hba_path
, disk_path
);
632 if (strncmp(disk_path
, hba_path
, strlen(hba_path
)) == 0)
640 int devt_attached_to_hba(dev_t dev
, const char *hba_path
)
642 char *disk_path
= devt_to_devpath(dev
);
643 int rc
= path_attached_to_hba(disk_path
, hba_path
);
651 int disk_attached_to_hba(int fd
, const char *hba_path
)
653 char *disk_path
= diskfd_to_devpath(fd
);
654 int rc
= path_attached_to_hba(disk_path
, hba_path
);