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 #define NVME_SUBSYS_PATH "/sys/devices/virtual/nvme-subsystem/"
35 static int devpath_to_ll(const char *dev_path
, const char *entry
,
36 unsigned long long *val
);
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 struct sys_dev
*vmd
= NULL
;
61 enum sys_dev_type type
;
62 unsigned long long dev_id
;
63 unsigned long long class;
65 if (strcmp(driver
, "isci") == 0)
67 else if (strcmp(driver
, "ahci") == 0)
69 else if (strcmp(driver
, "nvme") == 0) {
70 /* if looking for nvme devs, first look for vmd */
71 vmd
= find_driver_devices("pci", "vmd");
73 } else if (strcmp(driver
, "vmd") == 0)
76 type
= SYS_DEV_UNKNOWN
;
78 sprintf(path
, "/sys/bus/%s/drivers/%s", bus
, driver
);
79 driver_dir
= opendir(path
);
85 for (de
= readdir(driver_dir
); de
; de
= readdir(driver_dir
)) {
89 /* is 'de' a device? check that the 'subsystem' link exists and
90 * that its target matches 'bus'
92 sprintf(path
, "/sys/bus/%s/drivers/%s/%s/subsystem",
93 bus
, driver
, de
->d_name
);
94 n
= readlink(path
, link
, sizeof(link
));
95 if (n
< 0 || n
>= (int)sizeof(link
))
98 c
= strrchr(link
, '/');
101 if (strncmp(bus
, c
+1, strlen(bus
)) != 0)
104 sprintf(path
, "/sys/bus/%s/drivers/%s/%s",
105 bus
, driver
, de
->d_name
);
107 /* if searching for nvme - skip vmd connected one */
108 if (type
== SYS_DEV_NVME
) {
110 char *rp
= realpath(path
, NULL
);
111 for (dev
= vmd
; dev
; dev
= dev
->next
) {
112 if ((strncmp(dev
->path
, rp
, strlen(dev
->path
)) == 0))
118 /* if it's not Intel device or mark as VMD connected - skip it. */
119 if (devpath_to_vendor(path
) != 0x8086 || skip
== 1)
122 if (devpath_to_ll(path
, "device", &dev_id
) != 0)
125 if (devpath_to_ll(path
, "class", &class) != 0)
129 * Each VMD device (domain) adds separate PCI bus, it is better
130 * to store path as a path to that bus (easier further
131 * determination which NVMe dev is connected to this particular
134 if (type
== SYS_DEV_VMD
) {
135 sprintf(path
, "/sys/bus/%s/drivers/%s/%s/domain/device",
136 bus
, driver
, de
->d_name
);
138 p
= realpath(path
, NULL
);
140 pr_err("Unable to get real path for '%s'\n", path
);
144 /* start / add list entry */
146 head
= xmalloc(sizeof(*head
));
149 list
->next
= xmalloc(sizeof(*head
));
158 list
->dev_id
= (__u16
) dev_id
;
159 list
->class = (__u32
) class;
164 if ((list
->pci_id
= strrchr(list
->path
, '/')) != NULL
)
167 closedir(driver_dir
);
179 static struct sys_dev
*intel_devices
=NULL
;
180 static time_t valid_time
= 0;
182 struct sys_dev
*device_by_id(__u16 device_id
)
184 struct sys_dev
*iter
;
186 for (iter
= intel_devices
; iter
!= NULL
; iter
= iter
->next
)
187 if (iter
->dev_id
== device_id
)
192 struct sys_dev
*device_by_id_and_path(__u16 device_id
, const char *path
)
194 struct sys_dev
*iter
;
196 for (iter
= intel_devices
; iter
!= NULL
; iter
= iter
->next
)
197 if ((iter
->dev_id
== device_id
) && strstr(iter
->path
, path
))
202 static int devpath_to_ll(const char *dev_path
, const char *entry
, unsigned long long *val
)
204 char path
[strlen(dev_path
) + strlen(entry
) + 2];
208 sprintf(path
, "%s/%s", dev_path
, entry
);
210 fd
= open(path
, O_RDONLY
);
213 n
= sysfs_fd_get_ll(fd
, val
);
218 __u16
devpath_to_vendor(const char *dev_path
)
220 char path
[strlen(dev_path
) + strlen("/vendor") + 1];
226 sprintf(path
, "%s/vendor", dev_path
);
228 fd
= open(path
, O_RDONLY
);
232 n
= read(fd
, vendor
, sizeof(vendor
));
233 if (n
== sizeof(vendor
)) {
234 vendor
[n
- 1] = '\0';
235 id
= strtoul(vendor
, NULL
, 16);
242 struct sys_dev
*find_intel_devices(void)
244 struct sys_dev
*ahci
, *isci
, *nvme
;
246 if (valid_time
> time(0) - 10)
247 return intel_devices
;
250 free_sys_dev(&intel_devices
);
252 isci
= find_driver_devices("pci", "isci");
253 ahci
= find_driver_devices("pci", "ahci");
254 /* Searching for NVMe will return list of NVMe and VMD controllers */
255 nvme
= find_driver_devices("pci", "nvme");
257 if (!isci
&& !ahci
) {
261 struct sys_dev
*elem
= ahci
;
266 struct sys_dev
*elem
= ahci
;
274 intel_devices
= ahci
;
275 valid_time
= time(0);
276 return intel_devices
;
280 * PCI Expansion ROM Data Structure Format */
281 struct pciExpDataStructFormat
{
286 __u16 pciDataStructLen
;
287 __u8 pciDataStructRev
;
288 } __attribute__ ((packed
));
290 struct orom_entry
*orom_entries
;
292 const struct orom_entry
*get_orom_entry_by_device_id(__u16 dev_id
)
294 struct orom_entry
*entry
;
295 struct devid_list
*devid
;
297 for (entry
= orom_entries
; entry
; entry
= entry
->next
) {
298 for (devid
= entry
->devid_list
; devid
; devid
= devid
->next
) {
299 if (devid
->devid
== dev_id
)
307 const struct imsm_orom
*get_orom_by_device_id(__u16 dev_id
)
309 const struct orom_entry
*entry
= get_orom_entry_by_device_id(dev_id
);
317 static struct orom_entry
*add_orom(const struct imsm_orom
*orom
)
319 struct orom_entry
*list
;
320 struct orom_entry
*prev
= NULL
;
322 for (list
= orom_entries
; list
; prev
= list
, list
= list
->next
)
325 list
= xmalloc(sizeof(struct orom_entry
));
327 list
->devid_list
= NULL
;
338 static void add_orom_device_id(struct orom_entry
*entry
, __u16 dev_id
)
340 struct devid_list
*list
;
341 struct devid_list
*prev
= NULL
;
343 for (list
= entry
->devid_list
; list
; prev
= list
, list
= list
->next
) {
344 if (list
->devid
== dev_id
)
347 list
= xmalloc(sizeof(struct devid_list
));
348 list
->devid
= dev_id
;
352 entry
->devid_list
= list
;
357 static int scan(const void *start
, const void *end
, const void *data
)
360 const struct imsm_orom
*imsm_mem
= NULL
;
361 int len
= (end
- start
);
362 struct pciExpDataStructFormat
*ptr
= (struct pciExpDataStructFormat
*)data
;
364 if (data
+ 0x18 > end
) {
365 dprintf("cannot find pciExpDataStruct \n");
369 dprintf("ptr->vendorID: %lx __le16_to_cpu(ptr->deviceID): %lx \n",
370 (ulong
) __le16_to_cpu(ptr
->vendorID
),
371 (ulong
) __le16_to_cpu(ptr
->deviceID
));
373 if (__le16_to_cpu(ptr
->vendorID
) != 0x8086)
376 if (get_orom_by_device_id(ptr
->deviceID
))
379 for (offset
= 0; offset
< len
; offset
+= 4) {
380 const void *mem
= start
+ offset
;
382 if ((memcmp(mem
, IMSM_OROM_SIGNATURE
, 4) == 0)) {
391 struct orom_entry
*orom
= add_orom(imsm_mem
);
393 /* only PciDataStructure with revision 3 and above supports devices list. */
394 if (ptr
->pciDataStructRev
>= 3 && ptr
->devListOffset
) {
395 const __u16
*dev_list
= (void *)ptr
+ ptr
->devListOffset
;
398 for (i
= 0; dev_list
[i
] != 0; i
++)
399 add_orom_device_id(orom
, dev_list
[i
]);
401 add_orom_device_id(orom
, __le16_to_cpu(ptr
->deviceID
));
407 const struct imsm_orom
*imsm_platform_test(struct sys_dev
*hba
)
409 struct imsm_orom orom
= {
410 .signature
= IMSM_OROM_SIGNATURE
,
411 .rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
412 IMSM_OROM_RLC_RAID10
| IMSM_OROM_RLC_RAID5
,
413 .sss
= IMSM_OROM_SSS_4kB
| IMSM_OROM_SSS_8kB
|
414 IMSM_OROM_SSS_16kB
| IMSM_OROM_SSS_32kB
|
415 IMSM_OROM_SSS_64kB
| IMSM_OROM_SSS_128kB
|
416 IMSM_OROM_SSS_256kB
| IMSM_OROM_SSS_512kB
|
417 IMSM_OROM_SSS_1MB
| IMSM_OROM_SSS_2MB
,
418 .dpa
= IMSM_OROM_DISKS_PER_ARRAY
,
419 .tds
= IMSM_OROM_TOTAL_DISKS
,
420 .vpa
= IMSM_OROM_VOLUMES_PER_ARRAY
,
421 .vphba
= IMSM_OROM_VOLUMES_PER_HBA
423 orom
.attr
= orom
.rlc
| IMSM_OROM_ATTR_ChecksumVerify
;
425 if (check_env("IMSM_TEST_OROM_NORAID5")) {
426 orom
.rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
427 IMSM_OROM_RLC_RAID10
;
429 if (check_env("IMSM_TEST_AHCI_EFI_NORAID5") && (hba
->type
== SYS_DEV_SAS
)) {
430 orom
.rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
431 IMSM_OROM_RLC_RAID10
;
433 if (check_env("IMSM_TEST_SCU_EFI_NORAID5") && (hba
->type
== SYS_DEV_SATA
)) {
434 orom
.rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
435 IMSM_OROM_RLC_RAID10
;
438 struct orom_entry
*ret
= add_orom(&orom
);
440 add_orom_device_id(ret
, hba
->dev_id
);
445 static const struct imsm_orom
*find_imsm_hba_orom(struct sys_dev
*hba
)
449 if (check_env("IMSM_TEST_OROM"))
450 return imsm_platform_test(hba
);
452 /* return empty OROM capabilities in EFI test mode */
453 if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI"))
456 find_intel_devices();
458 if (intel_devices
== NULL
)
461 /* scan option-rom memory looking for an imsm signature */
462 if (check_env("IMSM_SAFE_OROM_SCAN"))
466 if (probe_roms_init(align
) != 0)
469 /* ignore return value - True is returned if both adapater roms are found */
470 scan_adapter_roms(scan
);
473 return get_orom_by_device_id(hba
->dev_id
);
476 #define GUID_STR_MAX 37 /* according to GUID format:
477 * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */
479 #define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
481 {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
482 (b) & 0xff, ((b) >> 8) & 0xff, \
483 (c) & 0xff, ((c) >> 8) & 0xff, \
484 (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
486 #define SYS_EFI_VAR_PATH "/sys/firmware/efi/vars"
487 #define SYS_EFIVARS_PATH "/sys/firmware/efi/efivars"
488 #define SCU_PROP "RstScuV"
489 #define AHCI_PROP "RstSataV"
490 #define AHCI_SSATA_PROP "RstsSatV"
491 #define AHCI_TSATA_PROP "RsttSatV"
492 #define VMD_PROP "RstUefiV"
494 #define VENDOR_GUID \
495 EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, 0x1a, 0x04, 0xc6)
497 #define PCI_CLASS_RAID_CNTRL 0x010400
499 static int read_efi_var(void *buffer
, ssize_t buf_size
,
500 const char *variable_name
, struct efi_guid guid
)
503 char buf
[GUID_STR_MAX
];
507 snprintf(path
, PATH_MAX
, "%s/%s-%s", SYS_EFIVARS_PATH
, variable_name
, guid_str(buf
, guid
));
509 fd
= open(path
, O_RDONLY
);
513 /* read the variable attributes and ignore it */
514 n
= read(fd
, buf
, sizeof(__u32
));
520 /* read the variable data */
521 n
= read(fd
, buffer
, buf_size
);
529 static int read_efi_variable(void *buffer
, ssize_t buf_size
,
530 const char *variable_name
, struct efi_guid guid
)
533 char buf
[GUID_STR_MAX
];
535 ssize_t n
, var_data_len
;
537 /* Try to read the variable using the new efivarfs interface first.
538 * If that fails, fall back to the old sysfs-efivars interface. */
539 if (!read_efi_var(buffer
, buf_size
, variable_name
, guid
))
542 snprintf(path
, PATH_MAX
, "%s/%s-%s/size", SYS_EFI_VAR_PATH
, variable_name
, guid_str(buf
, guid
));
544 dprintf("EFI VAR: path=%s\n", path
);
545 /* get size of variable data */
546 dfd
= open(path
, O_RDONLY
);
550 n
= read(dfd
, &buf
, sizeof(buf
));
557 var_data_len
= strtoul(buf
, NULL
, 16);
558 if ((errno
== ERANGE
&& (var_data_len
== LONG_MAX
)) ||
559 (errno
!= 0 && var_data_len
== 0))
563 snprintf(path
, PATH_MAX
, "%s/%s-%s/data", SYS_EFI_VAR_PATH
, variable_name
, guid_str(buf
, guid
));
565 dprintf("EFI VAR: path=%s\n", path
);
566 dfd
= open(path
, O_RDONLY
);
570 n
= read(dfd
, buffer
, buf_size
);
572 if (n
!= var_data_len
|| n
< buf_size
) {
579 const struct imsm_orom
*find_imsm_efi(struct sys_dev
*hba
)
581 struct imsm_orom orom
;
582 struct orom_entry
*ret
;
583 static const char * const sata_efivars
[] = {AHCI_PROP
, AHCI_SSATA_PROP
,
587 if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI"))
588 return imsm_platform_test(hba
);
590 /* OROM test is set, return that there is no EFI capabilities */
591 if (check_env("IMSM_TEST_OROM"))
596 if (!read_efi_variable(&orom
, sizeof(orom
), SCU_PROP
,
602 if (hba
->class != PCI_CLASS_RAID_CNTRL
)
605 for (i
= 0; i
< ARRAY_SIZE(sata_efivars
); i
++) {
606 if (!read_efi_variable(&orom
, sizeof(orom
),
607 sata_efivars
[i
], VENDOR_GUID
))
611 if (i
== ARRAY_SIZE(sata_efivars
))
616 if (!read_efi_variable(&orom
, sizeof(orom
), VMD_PROP
,
624 ret
= add_orom(&orom
);
625 add_orom_device_id(ret
, hba
->dev_id
);
626 ret
->type
= hba
->type
;
631 const struct imsm_orom
*find_imsm_nvme(struct sys_dev
*hba
)
633 static struct orom_entry
*nvme_orom
;
635 if (hba
->type
!= SYS_DEV_NVME
)
639 struct imsm_orom nvme_orom_compat
= {
640 .signature
= IMSM_NVME_OROM_COMPAT_SIGNATURE
,
641 .rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
642 IMSM_OROM_RLC_RAID10
| IMSM_OROM_RLC_RAID5
,
643 .sss
= IMSM_OROM_SSS_4kB
| IMSM_OROM_SSS_8kB
|
644 IMSM_OROM_SSS_16kB
| IMSM_OROM_SSS_32kB
|
645 IMSM_OROM_SSS_64kB
| IMSM_OROM_SSS_128kB
,
646 .dpa
= IMSM_OROM_DISKS_PER_ARRAY_NVME
,
647 .tds
= IMSM_OROM_TOTAL_DISKS_NVME
,
648 .vpa
= IMSM_OROM_VOLUMES_PER_ARRAY
,
649 .vphba
= IMSM_OROM_TOTAL_DISKS_NVME
/ 2 * IMSM_OROM_VOLUMES_PER_ARRAY
,
650 .attr
= IMSM_OROM_ATTR_2TB
| IMSM_OROM_ATTR_2TB_DISK
,
651 .driver_features
= IMSM_OROM_CAPABILITIES_EnterpriseSystem
653 nvme_orom
= add_orom(&nvme_orom_compat
);
655 add_orom_device_id(nvme_orom
, hba
->dev_id
);
656 nvme_orom
->type
= SYS_DEV_NVME
;
657 return &nvme_orom
->orom
;
660 const struct imsm_orom
*find_imsm_capability(struct sys_dev
*hba
)
662 const struct imsm_orom
*cap
= get_orom_by_device_id(hba
->dev_id
);
667 if (hba
->type
== SYS_DEV_NVME
)
668 return find_imsm_nvme(hba
);
669 if ((cap
= find_imsm_efi(hba
)) != NULL
)
671 if ((cap
= find_imsm_hba_orom(hba
)) != NULL
)
677 /* Check whether the nvme device is represented by nvme subsytem,
678 * if yes virtual path should be changed to hardware device path,
679 * to allow IMSM capabilities detection.
681 * hardware path to device - if the device is represented via
682 * nvme virtual subsytem
683 * NULL - if the device is not represented via nvme virtual subsytem
685 char *get_nvme_multipath_dev_hw_path(const char *dev_path
)
691 if (strncmp(dev_path
, NVME_SUBSYS_PATH
, strlen(NVME_SUBSYS_PATH
)) != 0)
694 dir
= opendir(dev_path
);
698 for (ent
= readdir(dir
); ent
; ent
= readdir(dir
)) {
699 char buf
[strlen(dev_path
) + strlen(ent
->d_name
) + 1];
701 /* Check if dir is a controller, ignore namespaces*/
702 if (!(strncmp(ent
->d_name
, "nvme", 4) == 0) ||
703 (strrchr(ent
->d_name
, 'n') != &ent
->d_name
[0]))
706 sprintf(buf
, "%s/%s", dev_path
, ent
->d_name
);
707 rp
= realpath(buf
, NULL
);
715 char *devt_to_devpath(dev_t dev
)
721 sprintf(device
, "/sys/dev/block/%d:%d/device", major(dev
), minor(dev
));
723 rp
= realpath(device
, NULL
);
727 buf
= get_nvme_multipath_dev_hw_path(rp
);
736 char *diskfd_to_devpath(int fd
)
738 /* return the device path for a disk, return NULL on error or fd
739 * refers to a partition
743 if (fstat(fd
, &st
) != 0)
745 if (!S_ISBLK(st
.st_mode
))
748 return devt_to_devpath(st
.st_rdev
);
751 int path_attached_to_hba(const char *disk_path
, const char *hba_path
)
755 if (check_env("IMSM_TEST_AHCI_DEV") ||
756 check_env("IMSM_TEST_SCU_DEV")) {
760 if (!disk_path
|| !hba_path
)
762 dprintf("hba: %s - disk: %s\n", hba_path
, disk_path
);
763 if (strncmp(disk_path
, hba_path
, strlen(hba_path
)) == 0)
771 int devt_attached_to_hba(dev_t dev
, const char *hba_path
)
773 char *disk_path
= devt_to_devpath(dev
);
774 int rc
= path_attached_to_hba(disk_path
, hba_path
);
782 int disk_attached_to_hba(int fd
, const char *hba_path
)
784 char *disk_path
= diskfd_to_devpath(fd
);
785 int rc
= path_attached_to_hba(disk_path
, hba_path
);
793 char *vmd_domain_to_controller(struct sys_dev
*hba
, char *buf
)
802 if (hba
->type
!= SYS_DEV_VMD
)
805 dir
= opendir("/sys/bus/pci/drivers/vmd");
809 for (ent
= readdir(dir
); ent
; ent
= readdir(dir
)) {
810 sprintf(path
, "/sys/bus/pci/drivers/vmd/%s/domain/device",
813 if (!realpath(path
, buf
))
816 if (strncmp(buf
, hba
->path
, strlen(buf
)) == 0) {
817 sprintf(path
, "/sys/bus/pci/drivers/vmd/%s", ent
->d_name
);
819 return realpath(path
, buf
);
826 /* Verify that NVMe drive is supported by IMSM
831 int imsm_is_nvme_supported(int disk_fd
, int verbose
)
833 char nsid_path
[PATH_MAX
];
840 if (fstat(disk_fd
, &stb
))
843 snprintf(nsid_path
, PATH_MAX
-1, "/sys/dev/block/%d:%d/nsid",
844 major(stb
.st_rdev
), minor(stb
.st_rdev
));
846 if (load_sys(nsid_path
, buf
, sizeof(buf
))) {
847 pr_err("Cannot read %s, rejecting drive\n", nsid_path
);
850 if (strtoll(buf
, NULL
, 10) != 1) {
852 pr_err("Only first namespace is supported by IMSM, aborting\n");
858 /* Verify if multipath is supported by NVMe controller
863 int is_multipath_nvme(int disk_fd
)
865 char path_buf
[PATH_MAX
];
866 char ns_path
[PATH_MAX
];
867 char *kname
= fd2kname(disk_fd
);
871 sprintf(path_buf
, "/sys/block/%s", kname
);
873 if (!realpath(path_buf
, ns_path
))
876 if (strncmp(ns_path
, NVME_SUBSYS_PATH
, strlen(NVME_SUBSYS_PATH
)) == 0)