"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "platform-intel.c" between
mdadm-4.1.tar.gz and mdadm-4.2.tar.gz

About: mdadm is a tool for creating, managing and monitoring device arrays using the "md" driver in Linux, also known as Software RAID arrays.

platform-intel.c  (mdadm-4.1):platform-intel.c  (mdadm-4.2)
skipping to change at line 33 skipping to change at line 33
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <dirent.h> #include <dirent.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <limits.h> #include <limits.h>
#define NVME_SUBSYS_PATH "/sys/devices/virtual/nvme-subsystem/"
static int devpath_to_ll(const char *dev_path, const char *entry, static int devpath_to_ll(const char *dev_path, const char *entry,
unsigned long long *val); unsigned long long *val);
static void free_sys_dev(struct sys_dev **list) static void free_sys_dev(struct sys_dev **list)
{ {
while (*list) { while (*list) {
struct sys_dev *next = (*list)->next; struct sys_dev *next = (*list)->next;
if ((*list)->path) if ((*list)->path)
free((*list)->path); free((*list)->path);
skipping to change at line 240 skipping to change at line 242
n = read(fd, vendor, sizeof(vendor)); n = read(fd, vendor, sizeof(vendor));
if (n == sizeof(vendor)) { if (n == sizeof(vendor)) {
vendor[n - 1] = '\0'; vendor[n - 1] = '\0';
id = strtoul(vendor, NULL, 16); id = strtoul(vendor, NULL, 16);
} }
close(fd); close(fd);
return id; return id;
} }
/* Description: Read text value of dev_path/entry field
* Parameters:
* dev_path - sysfs path to the device
* entry - entry to be read
* buf - buffer for read value
* len - size of buf
* verbose - error logging level
*/
int devpath_to_char(const char *dev_path, const char *entry, char *buf, int len,
int verbose)
{
char path[PATH_MAX];
snprintf(path, sizeof(path), "%s/%s", dev_path, entry);
if (load_sys(path, buf, len)) {
if (verbose)
pr_err("Cannot read %s, aborting\n", path);
return 1;
}
return 0;
}
struct sys_dev *find_intel_devices(void) struct sys_dev *find_intel_devices(void)
{ {
struct sys_dev *ahci, *isci, *nvme; struct sys_dev *ahci, *isci, *nvme;
if (valid_time > time(0) - 10) if (valid_time > time(0) - 10)
return intel_devices; return intel_devices;
if (intel_devices) if (intel_devices)
free_sys_dev(&intel_devices); free_sys_dev(&intel_devices);
skipping to change at line 489 skipping to change at line 514
{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
(b) & 0xff, ((b) >> 8) & 0xff, \ (b) & 0xff, ((b) >> 8) & 0xff, \
(c) & 0xff, ((c) >> 8) & 0xff, \ (c) & 0xff, ((c) >> 8) & 0xff, \
(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
#define SYS_EFI_VAR_PATH "/sys/firmware/efi/vars" #define SYS_EFI_VAR_PATH "/sys/firmware/efi/vars"
#define SYS_EFIVARS_PATH "/sys/firmware/efi/efivars" #define SYS_EFIVARS_PATH "/sys/firmware/efi/efivars"
#define SCU_PROP "RstScuV" #define SCU_PROP "RstScuV"
#define AHCI_PROP "RstSataV" #define AHCI_PROP "RstSataV"
#define AHCI_SSATA_PROP "RstsSatV" #define AHCI_SSATA_PROP "RstsSatV"
#define AHCI_CSATA_PROP "RstCSatV" #define AHCI_TSATA_PROP "RsttSatV"
#define VMD_PROP "RstUefiV" #define VMD_PROP "RstUefiV"
#define VENDOR_GUID \ #define VENDOR_GUID \
EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, 0x1a, 0x04, 0xc6) EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, 0x1a, 0x04, 0xc6)
#define PCI_CLASS_RAID_CNTRL 0x010400 #define PCI_CLASS_RAID_CNTRL 0x010400
static int read_efi_var(void *buffer, ssize_t buf_size, char *variable_name, str static int read_efi_var(void *buffer, ssize_t buf_size,
uct efi_guid guid) const char *variable_name, struct efi_guid guid)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
char buf[GUID_STR_MAX]; char buf[GUID_STR_MAX];
int fd; int fd;
ssize_t n; ssize_t n;
snprintf(path, PATH_MAX, "%s/%s-%s", SYS_EFIVARS_PATH, variable_name, gui d_str(buf, guid)); snprintf(path, PATH_MAX, "%s/%s-%s", SYS_EFIVARS_PATH, variable_name, gui d_str(buf, guid));
fd = open(path, O_RDONLY); fd = open(path, O_RDONLY);
if (fd < 0) if (fd < 0)
skipping to change at line 526 skipping to change at line 552
/* read the variable data */ /* read the variable data */
n = read(fd, buffer, buf_size); n = read(fd, buffer, buf_size);
close(fd); close(fd);
if (n < buf_size) if (n < buf_size)
return 1; return 1;
return 0; return 0;
} }
static int read_efi_variable(void *buffer, ssize_t buf_size, char *variable_name static int read_efi_variable(void *buffer, ssize_t buf_size,
, struct efi_guid guid) const char *variable_name, struct efi_guid guid)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
char buf[GUID_STR_MAX]; char buf[GUID_STR_MAX];
int dfd; int dfd;
ssize_t n, var_data_len; ssize_t n, var_data_len;
/* Try to read the variable using the new efivarfs interface first. /* Try to read the variable using the new efivarfs interface first.
* If that fails, fall back to the old sysfs-efivars interface. */ * If that fails, fall back to the old sysfs-efivars interface. */
if (!read_efi_var(buffer, buf_size, variable_name, guid)) if (!read_efi_var(buffer, buf_size, variable_name, guid))
return 0; return 0;
skipping to change at line 579 skipping to change at line 606
return 1; return 1;
} }
return 0; return 0;
} }
const struct imsm_orom *find_imsm_efi(struct sys_dev *hba) const struct imsm_orom *find_imsm_efi(struct sys_dev *hba)
{ {
struct imsm_orom orom; struct imsm_orom orom;
struct orom_entry *ret; struct orom_entry *ret;
int err; static const char * const sata_efivars[] = {AHCI_PROP, AHCI_SSATA_PROP,
AHCI_TSATA_PROP};
unsigned long i;
if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI")) if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI"))
return imsm_platform_test(hba); return imsm_platform_test(hba);
/* OROM test is set, return that there is no EFI capabilities */ /* OROM test is set, return that there is no EFI capabilities */
if (check_env("IMSM_TEST_OROM")) if (check_env("IMSM_TEST_OROM"))
return NULL; return NULL;
if (hba->type == SYS_DEV_SATA && hba->class != PCI_CLASS_RAID_CNTRL) switch (hba->type) {
return NULL; case SYS_DEV_SAS:
if (!read_efi_variable(&orom, sizeof(orom), SCU_PROP,
VENDOR_GUID))
break;
err = read_efi_variable(&orom, sizeof(orom), hba->type == SYS_DEV_SAS ? S return NULL;
CU_PROP : AHCI_PROP, VENDOR_GUID); case SYS_DEV_SATA:
if (hba->class != PCI_CLASS_RAID_CNTRL)
return NULL;
for (i = 0; i < ARRAY_SIZE(sata_efivars); i++) {
if (!read_efi_variable(&orom, sizeof(orom),
sata_efivars[i], VENDOR_GUID))
break;
/* try to read variable for second AHCI controller */
if (err && hba->type == SYS_DEV_SATA)
err = read_efi_variable(&orom, sizeof(orom), AHCI_SSATA_PROP, VEN
DOR_GUID);
/* try to read variable for combined AHCI controllers */
if (err && hba->type == SYS_DEV_SATA) {
static struct orom_entry *csata;
err = read_efi_variable(&orom, sizeof(orom), AHCI_CSATA_PROP, VEN
DOR_GUID);
if (!err) {
if (!csata)
csata = add_orom(&orom);
add_orom_device_id(csata, hba->dev_id);
csata->type = hba->type;
return &csata->orom;
} }
} if (i == ARRAY_SIZE(sata_efivars))
return NULL;
if (hba->type == SYS_DEV_VMD) { break;
err = read_efi_variable(&orom, sizeof(orom), VMD_PROP, VENDOR_GUI case SYS_DEV_VMD:
D); if (!read_efi_variable(&orom, sizeof(orom), VMD_PROP,
} VENDOR_GUID))
break;
if (err)
return NULL; return NULL;
default:
return NULL;
}
ret = add_orom(&orom); ret = add_orom(&orom);
add_orom_device_id(ret, hba->dev_id); add_orom_device_id(ret, hba->dev_id);
ret->type = hba->type; ret->type = hba->type;
return &ret->orom; return &ret->orom;
} }
const struct imsm_orom *find_imsm_nvme(struct sys_dev *hba) const struct imsm_orom *find_imsm_nvme(struct sys_dev *hba)
{ {
skipping to change at line 671 skipping to change at line 700
if (hba->type == SYS_DEV_NVME) if (hba->type == SYS_DEV_NVME)
return find_imsm_nvme(hba); return find_imsm_nvme(hba);
if ((cap = find_imsm_efi(hba)) != NULL) if ((cap = find_imsm_efi(hba)) != NULL)
return cap; return cap;
if ((cap = find_imsm_hba_orom(hba)) != NULL) if ((cap = find_imsm_hba_orom(hba)) != NULL)
return cap; return cap;
return NULL; return NULL;
} }
char *devt_to_devpath(dev_t dev) /* Check whether the nvme device is represented by nvme subsytem,
* if yes virtual path should be changed to hardware device path,
* to allow IMSM capabilities detection.
* Returns:
* hardware path to device - if the device is represented via
* nvme virtual subsytem
* NULL - if the device is not represented via nvme virtual subsytem
*/
char *get_nvme_multipath_dev_hw_path(const char *dev_path)
{ {
char device[46]; DIR *dir;
struct dirent *ent;
char *rp = NULL;
if (strncmp(dev_path, NVME_SUBSYS_PATH, strlen(NVME_SUBSYS_PATH)) != 0)
return NULL;
dir = opendir(dev_path);
if (!dir)
return NULL;
for (ent = readdir(dir); ent; ent = readdir(dir)) {
char buf[strlen(dev_path) + strlen(ent->d_name) + 1];
sprintf(device, "/sys/dev/block/%d:%d/device", major(dev), minor(dev)); /* Check if dir is a controller, ignore namespaces*/
return realpath(device, NULL); if (!(strncmp(ent->d_name, "nvme", 4) == 0) ||
(strrchr(ent->d_name, 'n') != &ent->d_name[0]))
continue;
sprintf(buf, "%s/%s", dev_path, ent->d_name);
rp = realpath(buf, NULL);
break;
}
closedir(dir);
return rp;
} }
char *diskfd_to_devpath(int fd) /* Description: Return part or whole realpath for the dev
* Parameters:
* dev - the device to be quered
* dev_level - level of "/device" entries. It allows to caller to access
* virtual or physical devices which are on "path" to quered
* one.
* buf - optional, must be PATH_MAX size. If set, then will be used.
*/
char *devt_to_devpath(dev_t dev, int dev_level, char *buf)
{
char device[PATH_MAX];
char *hw_path;
int i;
unsigned long device_free_len = sizeof(device) - 1;
char dev_str[] = "/device";
unsigned long dev_str_len = strlen(dev_str);
snprintf(device, sizeof(device), "/sys/dev/block/%d:%d", major(dev),
minor(dev));
/* If caller wants block device, return path to it even if it is exposed
* via virtual layer.
*/
if (dev_level == 0)
return realpath(device, buf);
device_free_len -= strlen(device);
for (i = 0; i < dev_level; i++) {
if (device_free_len < dev_str_len)
return NULL;
strncat(device, dev_str, device_free_len);
/* Resolve nvme-subsystem abstraction if needed
*/
device_free_len -= dev_str_len;
if (i == 0) {
char rp[PATH_MAX];
if (!realpath(device, rp))
return NULL;
hw_path = get_nvme_multipath_dev_hw_path(rp);
if (hw_path) {
strcpy(device, hw_path);
device_free_len = sizeof(device) -
strlen(device) - 1;
free(hw_path);
}
}
}
return realpath(device, buf);
}
char *diskfd_to_devpath(int fd, int dev_level, char *buf)
{ {
/* return the device path for a disk, return NULL on error or fd /* return the device path for a disk, return NULL on error or fd
* refers to a partition * refers to a partition
*/ */
struct stat st; struct stat st;
if (fstat(fd, &st) != 0) if (fstat(fd, &st) != 0)
return NULL; return NULL;
if (!S_ISBLK(st.st_mode)) if (!S_ISBLK(st.st_mode))
return NULL; return NULL;
return devt_to_devpath(st.st_rdev); return devt_to_devpath(st.st_rdev, dev_level, buf);
} }
int path_attached_to_hba(const char *disk_path, const char *hba_path) int path_attached_to_hba(const char *disk_path, const char *hba_path)
{ {
int rc; int rc;
if (check_env("IMSM_TEST_AHCI_DEV") || if (check_env("IMSM_TEST_AHCI_DEV") ||
check_env("IMSM_TEST_SCU_DEV")) { check_env("IMSM_TEST_SCU_DEV")) {
return 1; return 1;
} }
skipping to change at line 716 skipping to change at line 829
if (strncmp(disk_path, hba_path, strlen(hba_path)) == 0) if (strncmp(disk_path, hba_path, strlen(hba_path)) == 0)
rc = 1; rc = 1;
else else
rc = 0; rc = 0;
return rc; return rc;
} }
int devt_attached_to_hba(dev_t dev, const char *hba_path) int devt_attached_to_hba(dev_t dev, const char *hba_path)
{ {
char *disk_path = devt_to_devpath(dev); char *disk_path = devt_to_devpath(dev, 1, NULL);
int rc = path_attached_to_hba(disk_path, hba_path); int rc = path_attached_to_hba(disk_path, hba_path);
if (disk_path) if (disk_path)
free(disk_path); free(disk_path);
return rc; return rc;
} }
int disk_attached_to_hba(int fd, const char *hba_path) int disk_attached_to_hba(int fd, const char *hba_path)
{ {
char *disk_path = diskfd_to_devpath(fd); char *disk_path = diskfd_to_devpath(fd, 1, NULL);
int rc = path_attached_to_hba(disk_path, hba_path); int rc = path_attached_to_hba(disk_path, hba_path);
if (disk_path) if (disk_path)
free(disk_path); free(disk_path);
return rc; return rc;
} }
char *vmd_domain_to_controller(struct sys_dev *hba, char *buf) char *vmd_domain_to_controller(struct sys_dev *hba, char *buf)
{ {
skipping to change at line 769 skipping to change at line 882
if (strncmp(buf, hba->path, strlen(buf)) == 0) { if (strncmp(buf, hba->path, strlen(buf)) == 0) {
sprintf(path, "/sys/bus/pci/drivers/vmd/%s", ent->d_name) ; sprintf(path, "/sys/bus/pci/drivers/vmd/%s", ent->d_name) ;
closedir(dir); closedir(dir);
return realpath(path, buf); return realpath(path, buf);
} }
} }
closedir(dir); closedir(dir);
return NULL; return NULL;
} }
/* Scan over all controller's namespaces and compare nsid value to verify if
* current one is supported. The routine doesn't check IMSM capabilities for
* namespace. Only one nvme namespace is supported by IMSM.
* Paramteres:
* fd - open descriptor to the nvme namespace
* verbose - error logging level
* Returns:
* 1 - if namespace is supported
* 0 - otherwise
*/
int imsm_is_nvme_namespace_supported(int fd, int verbose)
{
DIR *dir = NULL;
struct dirent *ent;
char cntrl_path[PATH_MAX];
char ns_path[PATH_MAX];
unsigned long long lowest_nsid = ULLONG_MAX;
unsigned long long this_nsid;
int rv = 0;
if (!diskfd_to_devpath(fd, 1, cntrl_path) ||
!diskfd_to_devpath(fd, 0, ns_path)) {
if (verbose)
pr_err("Cannot get device paths\n");
goto abort;
}
if (devpath_to_ll(ns_path, "nsid", &this_nsid)) {
if (verbose)
pr_err("Cannot read nsid value for %s",
basename(ns_path));
goto abort;
}
dir = opendir(cntrl_path);
if (!dir)
goto abort;
/* The lowest nvme namespace is supported */
for (ent = readdir(dir); ent; ent = readdir(dir)) {
unsigned long long curr_nsid;
char curr_ns_path[PATH_MAX + 256];
if (!strstr(ent->d_name, "nvme"))
continue;
snprintf(curr_ns_path, sizeof(curr_ns_path), "%s/%s",
cntrl_path, ent->d_name);
if (devpath_to_ll(curr_ns_path, "nsid", &curr_nsid))
goto abort;
if (lowest_nsid > curr_nsid)
lowest_nsid = curr_nsid;
}
if (this_nsid == lowest_nsid)
rv = 1;
else if (verbose)
pr_err("IMSM is supported on the lowest NVMe namespace\n");
abort:
if (dir)
closedir(dir);
return rv;
}
/* Verify if multipath is supported by NVMe controller
* Returns:
* 0 - not supported
* 1 - supported
*/
int is_multipath_nvme(int disk_fd)
{
char ns_path[PATH_MAX];
if (!diskfd_to_devpath(disk_fd, 0, ns_path))
return 0;
if (strncmp(ns_path, NVME_SUBSYS_PATH, strlen(NVME_SUBSYS_PATH)) == 0)
return 1;
return 0;
}
 End of changes. 20 change blocks. 
42 lines changed or deleted 149 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)