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 bool imsm_orom_has_raid0(const struct imsm_orom
*orom
)
37 return imsm_rlc_has_bit(orom
, IMSM_OROM_RLC_RAID0
);
40 static bool imsm_orom_has_raid1(const struct imsm_orom
*orom
)
42 return imsm_rlc_has_bit(orom
, IMSM_OROM_RLC_RAID1
);
45 static bool imsm_orom_has_raid10(const struct imsm_orom
*orom
)
47 return imsm_rlc_has_bit(orom
, IMSM_OROM_RLC_RAID10
);
50 static bool imsm_orom_has_raid5(const struct imsm_orom
*orom
)
52 return imsm_rlc_has_bit(orom
, IMSM_OROM_RLC_RAID5
);
55 /* IMSM platforms do not define how many disks are allowed for each level,
56 * but there are some global limitations we need to follow.
58 static bool imsm_orom_support_raid_disks_count_raid0(const int raid_disks
)
63 static bool imsm_orom_support_raid_disks_count_raid1(const int raid_disks
)
70 static bool imsm_orom_support_raid_disks_count_raid5(const int raid_disks
)
77 static bool imsm_orom_support_raid_disks_count_raid10(const int raid_disks
)
79 /* raid_disks count must be higher than 4 and even */
80 if (raid_disks
>= 4 && (raid_disks
& 1) == 0)
85 struct imsm_level_ops imsm_level_ops
[] = {
86 {0, imsm_orom_has_raid0
, imsm_orom_support_raid_disks_count_raid0
, "raid0"},
87 {1, imsm_orom_has_raid1
, imsm_orom_support_raid_disks_count_raid1
, "raid1"},
88 {5, imsm_orom_has_raid5
, imsm_orom_support_raid_disks_count_raid5
, "raid5"},
89 {10, imsm_orom_has_raid10
, imsm_orom_support_raid_disks_count_raid10
, "raid10"},
90 {-1, NULL
, NULL
, NULL
}
93 static int devpath_to_ll(const char *dev_path
, const char *entry
,
94 unsigned long long *val
);
96 static void free_sys_dev(struct sys_dev
**list
)
99 struct sys_dev
*next
= (*list
)->next
;
108 struct sys_dev
*find_driver_devices(const char *bus
, const char *driver
)
110 /* search sysfs for devices driven by 'driver' */
116 struct sys_dev
*head
= NULL
;
117 struct sys_dev
*list
= NULL
;
118 struct sys_dev
*vmd
= NULL
;
119 enum sys_dev_type type
;
120 unsigned long long dev_id
;
121 unsigned long long class;
123 if (strcmp(driver
, "isci") == 0)
125 else if (strcmp(driver
, "ahci") == 0) {
126 vmd
= find_driver_devices("pci", "vmd");
128 } else if (strcmp(driver
, "nvme") == 0) {
129 /* if looking for nvme devs, first look for vmd */
130 vmd
= find_driver_devices("pci", "vmd");
132 } else if (strcmp(driver
, "vmd") == 0)
135 type
= SYS_DEV_UNKNOWN
;
137 sprintf(path
, "/sys/bus/%s/drivers/%s", bus
, driver
);
138 driver_dir
= opendir(path
);
144 for (de
= readdir(driver_dir
); de
; de
= readdir(driver_dir
)) {
148 /* is 'de' a device? check that the 'subsystem' link exists and
149 * that its target matches 'bus'
151 sprintf(path
, "/sys/bus/%s/drivers/%s/%s/subsystem",
152 bus
, driver
, de
->d_name
);
153 n
= readlink(path
, link
, sizeof(link
));
154 if (n
< 0 || n
>= (int)sizeof(link
))
157 c
= strrchr(link
, '/');
160 if (strncmp(bus
, c
+1, strlen(bus
)) != 0)
163 sprintf(path
, "/sys/bus/%s/drivers/%s/%s",
164 bus
, driver
, de
->d_name
);
166 /* if searching for nvme - skip vmd connected one */
167 if (type
== SYS_DEV_NVME
) {
169 char *rp
= realpath(path
, NULL
);
170 for (dev
= vmd
; dev
; dev
= dev
->next
) {
171 if ((strncmp(dev
->path
, rp
, strlen(dev
->path
)) == 0))
177 /* change sata type if under a vmd controller */
178 if (type
== SYS_DEV_SATA
) {
180 char *rp
= realpath(path
, NULL
);
181 for (dev
= vmd
; dev
; dev
= dev
->next
) {
182 if ((strncmp(dev
->path
, rp
, strlen(dev
->path
)) == 0))
183 type
= SYS_DEV_SATA_VMD
;
188 /* if it's not Intel device or mark as VMD connected - skip it. */
189 if (devpath_to_vendor(path
) != 0x8086 || skip
== 1)
192 if (devpath_to_ll(path
, "device", &dev_id
) != 0)
195 if (devpath_to_ll(path
, "class", &class) != 0)
199 * Each VMD device (domain) adds separate PCI bus, it is better
200 * to store path as a path to that bus (easier further
201 * determination which NVMe dev is connected to this particular
204 if (type
== SYS_DEV_VMD
) {
205 sprintf(path
, "/sys/bus/%s/drivers/%s/%s/domain/device",
206 bus
, driver
, de
->d_name
);
208 p
= realpath(path
, NULL
);
210 pr_err("Unable to get real path for '%s'\n", path
);
214 /* start / add list entry */
216 head
= xmalloc(sizeof(*head
));
219 list
->next
= xmalloc(sizeof(*head
));
228 list
->dev_id
= (__u16
) dev_id
;
229 list
->class = (__u32
) class;
234 if ((list
->pci_id
= strrchr(list
->path
, '/')) != NULL
)
237 closedir(driver_dir
);
239 /* nvme vmd needs a list separate from sata vmd */
240 if (vmd
&& type
== SYS_DEV_NVME
) {
250 static struct sys_dev
*intel_devices
=NULL
;
251 static time_t valid_time
= 0;
253 struct sys_dev
*device_by_id(__u16 device_id
)
255 struct sys_dev
*iter
;
257 for (iter
= intel_devices
; iter
!= NULL
; iter
= iter
->next
)
258 if (iter
->dev_id
== device_id
)
263 struct sys_dev
*device_by_id_and_path(__u16 device_id
, const char *path
)
265 struct sys_dev
*iter
;
267 for (iter
= intel_devices
; iter
!= NULL
; iter
= iter
->next
)
268 if ((iter
->dev_id
== device_id
) && strstr(iter
->path
, path
))
273 static int devpath_to_ll(const char *dev_path
, const char *entry
, unsigned long long *val
)
275 char path
[strnlen(dev_path
, PATH_MAX
) + strnlen(entry
, PATH_MAX
) + 2];
279 sprintf(path
, "%s/%s", dev_path
, entry
);
281 fd
= open(path
, O_RDONLY
);
284 n
= sysfs_fd_get_ll(fd
, val
);
289 __u16
devpath_to_vendor(const char *dev_path
)
291 char path
[strlen(dev_path
) + strlen("/vendor") + 1];
297 sprintf(path
, "%s/vendor", dev_path
);
299 fd
= open(path
, O_RDONLY
);
303 n
= read(fd
, vendor
, sizeof(vendor
));
304 if (n
== sizeof(vendor
)) {
305 vendor
[n
- 1] = '\0';
306 id
= strtoul(vendor
, NULL
, 16);
313 /* Description: Read text value of dev_path/entry field
315 * dev_path - sysfs path to the device
316 * entry - entry to be read
317 * buf - buffer for read value
319 * verbose - error logging level
321 int devpath_to_char(const char *dev_path
, const char *entry
, char *buf
, int len
,
326 snprintf(path
, sizeof(path
), "%s/%s", dev_path
, entry
);
327 if (load_sys(path
, buf
, len
)) {
329 pr_err("Cannot read %s, aborting\n", path
);
336 struct sys_dev
*find_intel_devices(void)
338 struct sys_dev
*ahci
, *isci
, *nvme
;
340 if (valid_time
> time(0) - 10)
341 return intel_devices
;
344 free_sys_dev(&intel_devices
);
346 isci
= find_driver_devices("pci", "isci");
347 /* Searching for AHCI will return list of SATA and SATA VMD controllers */
348 ahci
= find_driver_devices("pci", "ahci");
349 /* Searching for NVMe will return list of NVMe and VMD controllers */
350 nvme
= find_driver_devices("pci", "nvme");
352 if (!isci
&& !ahci
) {
356 struct sys_dev
*elem
= ahci
;
361 struct sys_dev
*elem
= ahci
;
369 intel_devices
= ahci
;
370 valid_time
= time(0);
371 return intel_devices
;
375 * PCI Expansion ROM Data Structure Format */
376 struct pciExpDataStructFormat
{
381 __u16 pciDataStructLen
;
382 __u8 pciDataStructRev
;
383 } __attribute__ ((packed
));
385 struct orom_entry
*orom_entries
;
387 const struct orom_entry
*get_orom_entry_by_device_id(__u16 dev_id
)
389 struct orom_entry
*entry
;
390 struct devid_list
*devid
;
392 for (entry
= orom_entries
; entry
; entry
= entry
->next
) {
393 for (devid
= entry
->devid_list
; devid
; devid
= devid
->next
) {
394 if (devid
->devid
== dev_id
)
402 const struct imsm_orom
*get_orom_by_device_id(__u16 dev_id
)
404 const struct orom_entry
*entry
= get_orom_entry_by_device_id(dev_id
);
412 static struct orom_entry
*add_orom(const struct imsm_orom
*orom
)
414 struct orom_entry
*list
;
415 struct orom_entry
*prev
= NULL
;
417 for (list
= orom_entries
; list
; prev
= list
, list
= list
->next
)
420 list
= xmalloc(sizeof(struct orom_entry
));
422 list
->devid_list
= NULL
;
433 static void add_orom_device_id(struct orom_entry
*entry
, __u16 dev_id
)
435 struct devid_list
*list
;
436 struct devid_list
*prev
= NULL
;
438 for (list
= entry
->devid_list
; list
; prev
= list
, list
= list
->next
) {
439 if (list
->devid
== dev_id
)
442 list
= xmalloc(sizeof(struct devid_list
));
443 list
->devid
= dev_id
;
447 entry
->devid_list
= list
;
452 static int scan(const void *start
, const void *end
, const void *data
)
455 const struct imsm_orom
*imsm_mem
= NULL
;
456 int len
= (end
- start
);
457 struct pciExpDataStructFormat
*ptr
= (struct pciExpDataStructFormat
*)data
;
459 if (data
+ 0x18 > end
) {
460 dprintf("cannot find pciExpDataStruct \n");
464 dprintf("ptr->vendorID: %lx __le16_to_cpu(ptr->deviceID): %lx \n",
465 (ulong
) __le16_to_cpu(ptr
->vendorID
),
466 (ulong
) __le16_to_cpu(ptr
->deviceID
));
468 if (__le16_to_cpu(ptr
->vendorID
) != 0x8086)
471 if (get_orom_by_device_id(ptr
->deviceID
))
474 for (offset
= 0; offset
< len
; offset
+= 4) {
475 const void *mem
= start
+ offset
;
477 if ((memcmp(mem
, IMSM_OROM_SIGNATURE
, 4) == 0)) {
486 struct orom_entry
*orom
= add_orom(imsm_mem
);
488 /* only PciDataStructure with revision 3 and above supports devices list. */
489 if (ptr
->pciDataStructRev
>= 3 && ptr
->devListOffset
) {
490 const __u16
*dev_list
= (void *)ptr
+ ptr
->devListOffset
;
493 for (i
= 0; dev_list
[i
] != 0; i
++)
494 add_orom_device_id(orom
, dev_list
[i
]);
496 add_orom_device_id(orom
, __le16_to_cpu(ptr
->deviceID
));
502 const struct imsm_orom
*imsm_platform_test(struct sys_dev
*hba
)
504 struct imsm_orom orom
= {
505 .signature
= IMSM_OROM_SIGNATURE
,
506 .rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
507 IMSM_OROM_RLC_RAID10
| IMSM_OROM_RLC_RAID5
,
508 .sss
= IMSM_OROM_SSS_4kB
| IMSM_OROM_SSS_8kB
|
509 IMSM_OROM_SSS_16kB
| IMSM_OROM_SSS_32kB
|
510 IMSM_OROM_SSS_64kB
| IMSM_OROM_SSS_128kB
|
511 IMSM_OROM_SSS_256kB
| IMSM_OROM_SSS_512kB
|
512 IMSM_OROM_SSS_1MB
| IMSM_OROM_SSS_2MB
,
513 .dpa
= IMSM_OROM_DISKS_PER_ARRAY
,
514 .tds
= IMSM_OROM_TOTAL_DISKS
,
515 .vpa
= IMSM_OROM_VOLUMES_PER_ARRAY
,
516 .vphba
= IMSM_OROM_VOLUMES_PER_HBA
518 orom
.attr
= orom
.rlc
| IMSM_OROM_ATTR_ChecksumVerify
;
520 if (check_env("IMSM_TEST_OROM_NORAID5")) {
521 orom
.rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
522 IMSM_OROM_RLC_RAID10
;
524 if (check_env("IMSM_TEST_AHCI_EFI_NORAID5") && (hba
->type
== SYS_DEV_SAS
)) {
525 orom
.rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
526 IMSM_OROM_RLC_RAID10
;
528 if (check_env("IMSM_TEST_SCU_EFI_NORAID5") && (hba
->type
== SYS_DEV_SATA
)) {
529 orom
.rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
530 IMSM_OROM_RLC_RAID10
;
533 struct orom_entry
*ret
= add_orom(&orom
);
535 add_orom_device_id(ret
, hba
->dev_id
);
540 static const struct imsm_orom
*find_imsm_hba_orom(struct sys_dev
*hba
)
544 if (check_env("IMSM_TEST_OROM"))
545 return imsm_platform_test(hba
);
547 /* return empty OROM capabilities in EFI test mode */
548 if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI"))
551 find_intel_devices();
553 if (intel_devices
== NULL
)
556 /* scan option-rom memory looking for an imsm signature */
557 if (check_env("IMSM_SAFE_OROM_SCAN"))
561 if (probe_roms_init(align
) != 0)
564 /* ignore return value - True is returned if both adapater roms are found */
565 scan_adapter_roms(scan
);
568 return get_orom_by_device_id(hba
->dev_id
);
571 #define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
573 {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
574 (b) & 0xff, ((b) >> 8) & 0xff, \
575 (c) & 0xff, ((c) >> 8) & 0xff, \
576 (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
578 #define SYS_EFI_VAR_PATH "/sys/firmware/efi/vars"
579 #define SYS_EFIVARS_PATH "/sys/firmware/efi/efivars"
580 #define SCU_PROP "RstScuV"
581 #define AHCI_PROP "RstSataV"
582 #define AHCI_SSATA_PROP "RstsSatV"
583 #define AHCI_TSATA_PROP "RsttSatV"
584 #define VROC_VMD_PROP "RstUefiV"
585 #define RST_VMD_PROP "RstVmdV"
587 #define VENDOR_GUID \
588 EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, 0x1a, 0x04, 0xc6)
590 #define PCI_CLASS_RAID_CNTRL 0x010400
592 static int read_efi_var(void *buffer
, ssize_t buf_size
,
593 const char *variable_name
, struct efi_guid guid
)
596 char buf
[GUID_STR_MAX
];
600 snprintf(path
, PATH_MAX
, "%s/%s-%s", SYS_EFIVARS_PATH
, variable_name
, guid_str(buf
, guid
));
602 fd
= open(path
, O_RDONLY
);
606 /* read the variable attributes and ignore it */
607 n
= read(fd
, buf
, sizeof(__u32
));
613 /* read the variable data */
614 n
= read(fd
, buffer
, buf_size
);
622 static int read_efi_variable(void *buffer
, ssize_t buf_size
,
623 const char *variable_name
, struct efi_guid guid
)
626 char buf
[GUID_STR_MAX
];
628 ssize_t n
, var_data_len
;
630 /* Try to read the variable using the new efivarfs interface first.
631 * If that fails, fall back to the old sysfs-efivars interface. */
632 if (!read_efi_var(buffer
, buf_size
, variable_name
, guid
))
635 snprintf(path
, PATH_MAX
, "%s/%s-%s/size", SYS_EFI_VAR_PATH
, variable_name
, guid_str(buf
, guid
));
637 dprintf("EFI VAR: path=%s\n", path
);
638 /* get size of variable data */
639 dfd
= open(path
, O_RDONLY
);
643 n
= read(dfd
, &buf
, sizeof(buf
));
650 var_data_len
= strtoul(buf
, NULL
, 16);
651 if ((errno
== ERANGE
&& (var_data_len
== LONG_MAX
)) ||
652 (errno
!= 0 && var_data_len
== 0))
656 snprintf(path
, PATH_MAX
, "%s/%s-%s/data", SYS_EFI_VAR_PATH
, variable_name
, guid_str(buf
, guid
));
658 dprintf("EFI VAR: path=%s\n", path
);
659 dfd
= open(path
, O_RDONLY
);
663 n
= read(dfd
, buffer
, buf_size
);
665 if (n
!= var_data_len
|| n
< buf_size
) {
672 const struct imsm_orom
*find_imsm_efi(struct sys_dev
*hba
)
674 struct imsm_orom orom
;
675 struct orom_entry
*ret
;
676 static const char * const sata_efivars
[] = {AHCI_PROP
, AHCI_SSATA_PROP
,
678 static const char * const vmd_efivars
[] = {VROC_VMD_PROP
, RST_VMD_PROP
};
681 if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI"))
682 return imsm_platform_test(hba
);
684 /* OROM test is set, return that there is no EFI capabilities */
685 if (check_env("IMSM_TEST_OROM"))
690 if (!read_efi_variable(&orom
, sizeof(orom
), SCU_PROP
,
696 if (hba
->class != PCI_CLASS_RAID_CNTRL
)
699 for (i
= 0; i
< ARRAY_SIZE(sata_efivars
); i
++) {
700 if (!read_efi_variable(&orom
, sizeof(orom
),
701 sata_efivars
[i
], VENDOR_GUID
))
705 if (i
== ARRAY_SIZE(sata_efivars
))
710 case SYS_DEV_SATA_VMD
:
711 for (i
= 0; i
< ARRAY_SIZE(vmd_efivars
); i
++) {
712 if (!read_efi_variable(&orom
, sizeof(orom
),
713 vmd_efivars
[i
], VENDOR_GUID
))
717 if (i
== ARRAY_SIZE(vmd_efivars
))
725 ret
= add_orom(&orom
);
726 add_orom_device_id(ret
, hba
->dev_id
);
727 ret
->type
= hba
->type
;
732 const struct imsm_orom
*find_imsm_nvme(struct sys_dev
*hba
)
734 static struct orom_entry
*nvme_orom
;
736 if (hba
->type
!= SYS_DEV_NVME
)
740 struct imsm_orom nvme_orom_compat
= {
741 .signature
= IMSM_NVME_OROM_COMPAT_SIGNATURE
,
742 .rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
743 IMSM_OROM_RLC_RAID10
| IMSM_OROM_RLC_RAID5
,
744 .sss
= IMSM_OROM_SSS_4kB
| IMSM_OROM_SSS_8kB
|
745 IMSM_OROM_SSS_16kB
| IMSM_OROM_SSS_32kB
|
746 IMSM_OROM_SSS_64kB
| IMSM_OROM_SSS_128kB
,
747 .dpa
= IMSM_OROM_DISKS_PER_ARRAY_NVME
,
748 .tds
= IMSM_OROM_TOTAL_DISKS_NVME
,
749 .vpa
= IMSM_OROM_VOLUMES_PER_ARRAY
,
750 .vphba
= IMSM_OROM_TOTAL_DISKS_NVME
/ 2 * IMSM_OROM_VOLUMES_PER_ARRAY
,
751 .attr
= IMSM_OROM_ATTR_2TB
| IMSM_OROM_ATTR_2TB_DISK
,
752 .driver_features
= IMSM_OROM_CAPABILITIES_EnterpriseSystem
754 nvme_orom
= add_orom(&nvme_orom_compat
);
756 add_orom_device_id(nvme_orom
, hba
->dev_id
);
757 nvme_orom
->type
= SYS_DEV_NVME
;
758 return &nvme_orom
->orom
;
761 #define VMD_REGISTER_OFFSET 0x3FC
762 #define VMD_REGISTER_SKU_SHIFT 1
763 #define VMD_REGISTER_SKU_MASK (0x00000007)
764 #define VMD_REGISTER_SKU_PREMIUM 2
765 #define MD_REGISTER_VER_MAJOR_SHIFT 4
766 #define MD_REGISTER_VER_MAJOR_MASK (0x0000000F)
767 #define MD_REGISTER_VER_MINOR_SHIFT 8
768 #define MD_REGISTER_VER_MINOR_MASK (0x0000000F)
771 * read_vmd_register() - Reads VMD register and writes contents to buff ptr
772 * @buff: buffer for vmd register data, should be the size of uint32_t
774 * Return: 0 on success, 1 on error
776 int read_vmd_register(uint32_t *buff
, struct sys_dev
*hba
)
779 char vmd_pci_config_path
[PATH_MAX
];
781 if (!vmd_domain_to_controller(hba
, vmd_pci_config_path
))
784 strncat(vmd_pci_config_path
, "/config", PATH_MAX
- strnlen(vmd_pci_config_path
, PATH_MAX
));
786 fd
= open(vmd_pci_config_path
, O_RDONLY
);
790 if (pread(fd
, buff
, sizeof(uint32_t), VMD_REGISTER_OFFSET
) != sizeof(uint32_t)) {
799 * add_vmd_orom() - Adds VMD orom cap to orom list, writes orom_entry ptr into vmd_orom
800 * @vmd_orom: pointer to orom entry pointer
802 * Return: 0 on success, 1 on error
804 int add_vmd_orom(struct orom_entry
**vmd_orom
, struct sys_dev
*hba
)
807 uint32_t vmd_register_data
;
808 struct imsm_orom vmd_orom_cap
= {
809 .signature
= IMSM_VMD_OROM_COMPAT_SIGNATURE
,
810 .sss
= IMSM_OROM_SSS_4kB
| IMSM_OROM_SSS_8kB
|
811 IMSM_OROM_SSS_16kB
| IMSM_OROM_SSS_32kB
|
812 IMSM_OROM_SSS_64kB
| IMSM_OROM_SSS_128kB
,
813 .dpa
= IMSM_OROM_DISKS_PER_ARRAY_NVME
,
814 .tds
= IMSM_OROM_TOTAL_DISKS_VMD
,
815 .vpa
= IMSM_OROM_VOLUMES_PER_ARRAY
,
816 .vphba
= IMSM_OROM_VOLUMES_PER_HBA_VMD
,
817 .attr
= IMSM_OROM_ATTR_2TB
| IMSM_OROM_ATTR_2TB_DISK
,
818 .driver_features
= IMSM_OROM_CAPABILITIES_EnterpriseSystem
|
819 IMSM_OROM_CAPABILITIES_TPV
822 if (read_vmd_register(&vmd_register_data
, hba
) != 0)
825 sku
= (uint8_t)((vmd_register_data
>> VMD_REGISTER_SKU_SHIFT
) &
826 VMD_REGISTER_SKU_MASK
);
828 if (sku
== VMD_REGISTER_SKU_PREMIUM
)
829 vmd_orom_cap
.rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
830 IMSM_OROM_RLC_RAID10
| IMSM_OROM_RLC_RAID5
;
832 vmd_orom_cap
.rlc
= IMSM_OROM_RLC_RAID_CNG
;
834 vmd_orom_cap
.major_ver
= (uint8_t)
835 ((vmd_register_data
>> MD_REGISTER_VER_MAJOR_SHIFT
) &
836 MD_REGISTER_VER_MAJOR_MASK
);
837 vmd_orom_cap
.minor_ver
= (uint8_t)
838 ((vmd_register_data
>> MD_REGISTER_VER_MINOR_SHIFT
) &
839 MD_REGISTER_VER_MINOR_MASK
);
841 *vmd_orom
= add_orom(&vmd_orom_cap
);
846 const struct imsm_orom
*find_imsm_vmd(struct sys_dev
*hba
)
848 static struct orom_entry
*vmd_orom
;
850 if (hba
->type
!= SYS_DEV_VMD
)
853 if (!vmd_orom
&& add_vmd_orom(&vmd_orom
, hba
) != 0)
856 add_orom_device_id(vmd_orom
, hba
->dev_id
);
857 vmd_orom
->type
= SYS_DEV_VMD
;
858 return &vmd_orom
->orom
;
861 const struct imsm_orom
*find_imsm_capability(struct sys_dev
*hba
)
863 const struct imsm_orom
*cap
= get_orom_by_device_id(hba
->dev_id
);
868 if (hba
->type
== SYS_DEV_NVME
)
869 return find_imsm_nvme(hba
);
871 cap
= find_imsm_efi(hba
);
875 if (hba
->type
== SYS_DEV_VMD
) {
876 cap
= find_imsm_vmd(hba
);
881 cap
= find_imsm_hba_orom(hba
);
888 /* Check whether the nvme device is represented by nvme subsytem,
889 * if yes virtual path should be changed to hardware device path,
890 * to allow IMSM capabilities detection.
892 * hardware path to device - if the device is represented via
893 * nvme virtual subsytem
894 * NULL - if the device is not represented via nvme virtual subsytem
896 char *get_nvme_multipath_dev_hw_path(const char *dev_path
)
902 if (strncmp(dev_path
, NVME_SUBSYS_PATH
, strlen(NVME_SUBSYS_PATH
)) != 0)
905 dir
= opendir(dev_path
);
909 for (ent
= readdir(dir
); ent
; ent
= readdir(dir
)) {
910 char buf
[strlen(dev_path
) + strlen(ent
->d_name
) + 1];
912 /* Check if dir is a controller, ignore namespaces*/
913 if (!(strncmp(ent
->d_name
, "nvme", 4) == 0) ||
914 (strrchr(ent
->d_name
, 'n') != &ent
->d_name
[0]))
917 sprintf(buf
, "%s/%s", dev_path
, ent
->d_name
);
918 rp
= realpath(buf
, NULL
);
926 /* Description: Return part or whole realpath for the dev
928 * dev - the device to be quered
929 * dev_level - level of "/device" entries. It allows to caller to access
930 * virtual or physical devices which are on "path" to quered
932 * buf - optional, must be PATH_MAX size. If set, then will be used.
934 char *devt_to_devpath(dev_t dev
, int dev_level
, char *buf
)
936 char device
[PATH_MAX
];
939 unsigned long device_free_len
= sizeof(device
) - 1;
940 char dev_str
[] = "/device";
941 unsigned long dev_str_len
= strlen(dev_str
);
943 snprintf(device
, sizeof(device
), "/sys/dev/block/%d:%d", major(dev
),
946 /* If caller wants block device, return path to it even if it is exposed
950 return realpath(device
, buf
);
952 device_free_len
-= strlen(device
);
953 for (i
= 0; i
< dev_level
; i
++) {
954 if (device_free_len
< dev_str_len
)
957 strncat(device
, dev_str
, device_free_len
);
959 /* Resolve nvme-subsystem abstraction if needed
961 device_free_len
-= dev_str_len
;
965 if (!realpath(device
, rp
))
967 hw_path
= get_nvme_multipath_dev_hw_path(rp
);
969 strcpy(device
, hw_path
);
970 device_free_len
= sizeof(device
) -
977 return realpath(device
, buf
);
980 char *diskfd_to_devpath(int fd
, int dev_level
, char *buf
)
982 /* return the device path for a disk, return NULL on error or fd
983 * refers to a partition
987 if (fstat(fd
, &st
) != 0)
989 if (!S_ISBLK(st
.st_mode
))
992 return devt_to_devpath(st
.st_rdev
, dev_level
, buf
);
995 int path_attached_to_hba(const char *disk_path
, const char *hba_path
)
999 if (check_env("IMSM_TEST_AHCI_DEV") ||
1000 check_env("IMSM_TEST_SCU_DEV")) {
1004 if (!disk_path
|| !hba_path
)
1006 dprintf("hba: %s - disk: %s\n", hba_path
, disk_path
);
1007 if (strncmp(disk_path
, hba_path
, strlen(hba_path
)) == 0)
1015 int devt_attached_to_hba(dev_t dev
, const char *hba_path
)
1017 char *disk_path
= devt_to_devpath(dev
, 1, NULL
);
1018 int rc
= path_attached_to_hba(disk_path
, hba_path
);
1026 int disk_attached_to_hba(int fd
, const char *hba_path
)
1028 char *disk_path
= diskfd_to_devpath(fd
, 1, NULL
);
1029 int rc
= path_attached_to_hba(disk_path
, hba_path
);
1037 char *vmd_domain_to_controller(struct sys_dev
*hba
, char *buf
)
1041 char path
[PATH_MAX
];
1046 if (hba
->type
!= SYS_DEV_VMD
)
1049 dir
= opendir("/sys/bus/pci/drivers/vmd");
1053 for (ent
= readdir(dir
); ent
; ent
= readdir(dir
)) {
1054 sprintf(path
, "/sys/bus/pci/drivers/vmd/%s/domain/device",
1057 if (!realpath(path
, buf
))
1060 if (strncmp(buf
, hba
->path
, strlen(buf
)) == 0) {
1061 sprintf(path
, "/sys/bus/pci/drivers/vmd/%s", ent
->d_name
);
1063 return realpath(path
, buf
);
1071 /* Scan over all controller's namespaces and compare nsid value to verify if
1072 * current one is supported. The routine doesn't check IMSM capabilities for
1073 * namespace. Only one nvme namespace is supported by IMSM.
1075 * fd - open descriptor to the nvme namespace
1076 * verbose - error logging level
1078 * 1 - if namespace is supported
1081 int imsm_is_nvme_namespace_supported(int fd
, int verbose
)
1085 char cntrl_path
[PATH_MAX
];
1086 char ns_path
[PATH_MAX
];
1087 unsigned long long lowest_nsid
= ULLONG_MAX
;
1088 unsigned long long this_nsid
;
1092 if (!diskfd_to_devpath(fd
, 1, cntrl_path
) ||
1093 !diskfd_to_devpath(fd
, 0, ns_path
)) {
1095 pr_err("Cannot get device paths\n");
1100 if (devpath_to_ll(ns_path
, "nsid", &this_nsid
)) {
1102 pr_err("Cannot read nsid value for %s",
1107 dir
= opendir(cntrl_path
);
1111 /* The lowest nvme namespace is supported */
1112 for (ent
= readdir(dir
); ent
; ent
= readdir(dir
)) {
1113 unsigned long long curr_nsid
;
1114 char curr_ns_path
[PATH_MAX
+ 256];
1116 if (!strstr(ent
->d_name
, "nvme"))
1119 snprintf(curr_ns_path
, sizeof(curr_ns_path
), "%s/%s",
1120 cntrl_path
, ent
->d_name
);
1122 if (devpath_to_ll(curr_ns_path
, "nsid", &curr_nsid
))
1125 if (lowest_nsid
> curr_nsid
)
1126 lowest_nsid
= curr_nsid
;
1129 if (this_nsid
== lowest_nsid
)
1132 pr_err("IMSM is supported on the lowest NVMe namespace\n");
1141 /* Verify if multipath is supported by NVMe controller
1146 int is_multipath_nvme(int disk_fd
)
1148 char ns_path
[PATH_MAX
];
1150 if (!diskfd_to_devpath(disk_fd
, 0, ns_path
))
1153 if (strncmp(ns_path
, NVME_SUBSYS_PATH
, strlen(NVME_SUBSYS_PATH
)) == 0)