mdadm/platform-intel.c

769 lines
18 KiB
C
Raw Normal View History

/*
* Intel(R) Matrix Storage Manager hardware and firmware support routines
*
* Copyright (C) 2008 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "mdadm.h"
#include "platform-intel.h"
#include "probe_roms.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
static int devpath_to_ll(const char *dev_path, const char *entry,
unsigned long long *val);
static void free_sys_dev(struct sys_dev **list)
{
while (*list) {
struct sys_dev *next = (*list)->next;
if ((*list)->path)
free((*list)->path);
free(*list);
*list = next;
}
}
struct sys_dev *find_driver_devices(const char *bus, const char *driver)
{
/* search sysfs for devices driven by 'driver' */
char path[PATH_MAX];
char link[PATH_MAX];
char *c, *p;
DIR *driver_dir;
struct dirent *de;
struct sys_dev *head = NULL;
struct sys_dev *list = NULL;
struct sys_dev *vmd = NULL;
enum sys_dev_type type;
unsigned long long dev_id;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
unsigned long long class;
if (strcmp(driver, "isci") == 0)
type = SYS_DEV_SAS;
else if (strcmp(driver, "ahci") == 0)
type = SYS_DEV_SATA;
else if (strcmp(driver, "nvme") == 0) {
/* if looking for nvme devs, first look for vmd */
vmd = find_driver_devices("pci", "vmd");
type = SYS_DEV_NVME;
} else if (strcmp(driver, "vmd") == 0)
type = SYS_DEV_VMD;
else
type = SYS_DEV_UNKNOWN;
sprintf(path, "/sys/bus/%s/drivers/%s", bus, driver);
driver_dir = opendir(path);
if (!driver_dir) {
if (vmd)
free_sys_dev(&vmd);
return NULL;
}
for (de = readdir(driver_dir); de; de = readdir(driver_dir)) {
int n;
int skip = 0;
/* is 'de' a device? check that the 'subsystem' link exists and
* that its target matches 'bus'
*/
sprintf(path, "/sys/bus/%s/drivers/%s/%s/subsystem",
bus, driver, de->d_name);
n = readlink(path, link, sizeof(link));
if (n < 0 || n >= (int)sizeof(link))
continue;
link[n] = '\0';
c = strrchr(link, '/');
if (!c)
continue;
if (strncmp(bus, c+1, strlen(bus)) != 0)
continue;
sprintf(path, "/sys/bus/%s/drivers/%s/%s",
bus, driver, de->d_name);
/* if searching for nvme - skip vmd connected one */
if (type == SYS_DEV_NVME) {
struct sys_dev *dev;
char *rp = realpath(path, NULL);
for (dev = vmd; dev; dev = dev->next) {
if ((strncmp(dev->path, rp, strlen(dev->path)) == 0))
skip = 1;
}
free(rp);
}
/* if it's not Intel device or mark as VMD connected - skip it. */
if (devpath_to_vendor(path) != 0x8086 || skip == 1)
continue;
if (devpath_to_ll(path, "device", &dev_id) != 0)
continue;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
if (devpath_to_ll(path, "class", &class) != 0)
continue;
/*
* Each VMD device (domain) adds separate PCI bus, it is better
* to store path as a path to that bus (easier further
* determination which NVMe dev is connected to this particular
* VMD domain).
*/
if (type == SYS_DEV_VMD) {
sprintf(path, "/sys/bus/%s/drivers/%s/%s/domain/device",
bus, driver, de->d_name);
}
p = realpath(path, NULL);
if (p == NULL) {
pr_err("Unable to get real path for '%s'\n", path);
continue;
}
/* start / add list entry */
if (!head) {
head = xmalloc(sizeof(*head));
list = head;
} else {
list->next = xmalloc(sizeof(*head));
list = list->next;
}
if (!list) {
free_sys_dev(&head);
break;
}
list->dev_id = (__u16) dev_id;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
list->class = (__u32) class;
list->type = type;
list->next = NULL;
list->path = p;
if ((list->pci_id = strrchr(list->path, '/')) != NULL)
list->pci_id++;
}
closedir(driver_dir);
if (vmd) {
if (list)
list->next = vmd;
else
head = vmd;
}
return head;
}
static struct sys_dev *intel_devices=NULL;
static time_t valid_time = 0;
struct sys_dev *device_by_id(__u16 device_id)
{
struct sys_dev *iter;
for (iter = intel_devices; iter != NULL; iter = iter->next)
if (iter->dev_id == device_id)
return iter;
return NULL;
}
struct sys_dev *device_by_id_and_path(__u16 device_id, const char *path)
{
struct sys_dev *iter;
for (iter = intel_devices; iter != NULL; iter = iter->next)
if ((iter->dev_id == device_id) && strstr(iter->path, path))
return iter;
return NULL;
}
static int devpath_to_ll(const char *dev_path, const char *entry, unsigned long long *val)
{
char path[strlen(dev_path) + strlen(entry) + 2];
int fd;
int n;
sprintf(path, "%s/%s", dev_path, entry);
fd = open(path, O_RDONLY);
if (fd < 0)
return -1;
n = sysfs_fd_get_ll(fd, val);
close(fd);
return n;
}
__u16 devpath_to_vendor(const char *dev_path)
{
char path[strlen(dev_path) + strlen("/vendor") + 1];
char vendor[7];
int fd;
__u16 id = 0xffff;
int n;
sprintf(path, "%s/vendor", dev_path);
fd = open(path, O_RDONLY);
if (fd < 0)
return 0xffff;
n = read(fd, vendor, sizeof(vendor));
if (n == sizeof(vendor)) {
vendor[n - 1] = '\0';
id = strtoul(vendor, NULL, 16);
}
close(fd);
return id;
}
struct sys_dev *find_intel_devices(void)
{
struct sys_dev *ahci, *isci, *nvme;
if (valid_time > time(0) - 10)
return intel_devices;
if (intel_devices)
free_sys_dev(&intel_devices);
isci = find_driver_devices("pci", "isci");
ahci = find_driver_devices("pci", "ahci");
/* Searching for NVMe will return list of NVMe and VMD controllers */
nvme = find_driver_devices("pci", "nvme");
if (!isci && !ahci) {
ahci = nvme;
} else if (!ahci) {
ahci = isci;
struct sys_dev *elem = ahci;
while (elem->next)
elem = elem->next;
elem->next = nvme;
} else {
struct sys_dev *elem = ahci;
while (elem->next)
elem = elem->next;
elem->next = isci;
while (elem->next)
elem = elem->next;
elem->next = nvme;
}
intel_devices = ahci;
valid_time = time(0);
return intel_devices;
}
/*
* PCI Expansion ROM Data Structure Format */
struct pciExpDataStructFormat {
__u8 ver[4];
__u16 vendorID;
__u16 deviceID;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
__u16 devListOffset;
__u16 pciDataStructLen;
__u8 pciDataStructRev;
} __attribute__ ((packed));
struct orom_entry *orom_entries;
const struct orom_entry *get_orom_entry_by_device_id(__u16 dev_id)
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
{
struct orom_entry *entry;
struct devid_list *devid;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
for (entry = orom_entries; entry; entry = entry->next) {
for (devid = entry->devid_list; devid; devid = devid->next) {
if (devid->devid == dev_id)
return entry;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
}
}
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
return NULL;
}
const struct imsm_orom *get_orom_by_device_id(__u16 dev_id)
{
const struct orom_entry *entry = get_orom_entry_by_device_id(dev_id);
if (entry)
return &entry->orom;
return NULL;
}
static struct orom_entry *add_orom(const struct imsm_orom *orom)
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
{
struct orom_entry *list;
struct orom_entry *prev = NULL;
for (list = orom_entries; list; prev = list, list = list->next)
;
list = xmalloc(sizeof(struct orom_entry));
list->orom = *orom;
list->devid_list = NULL;
list->next = NULL;
if (prev == NULL)
orom_entries = list;
else
prev->next = list;
return list;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
}
static void add_orom_device_id(struct orom_entry *entry, __u16 dev_id)
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
{
struct devid_list *list;
struct devid_list *prev = NULL;
for (list = entry->devid_list; list; prev = list, list = list->next) {
if (list->devid == dev_id)
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
return;
}
list = xmalloc(sizeof(struct devid_list));
list->devid = dev_id;
list->next = NULL;
if (prev == NULL)
entry->devid_list = list;
else
prev->next = list;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
}
static int scan(const void *start, const void *end, const void *data)
{
int offset;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
const struct imsm_orom *imsm_mem = NULL;
int len = (end - start);
struct pciExpDataStructFormat *ptr= (struct pciExpDataStructFormat *)data;
if (data + 0x18 > end) {
dprintf("cannot find pciExpDataStruct \n");
return 0;
}
dprintf("ptr->vendorID: %lx __le16_to_cpu(ptr->deviceID): %lx \n",
(ulong) __le16_to_cpu(ptr->vendorID),
(ulong) __le16_to_cpu(ptr->deviceID));
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
if (__le16_to_cpu(ptr->vendorID) != 0x8086)
return 0;
if (get_orom_by_device_id(ptr->deviceID))
return 0;
for (offset = 0; offset < len; offset += 4) {
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
const void *mem = start + offset;
if ((memcmp(mem, IMSM_OROM_SIGNATURE, 4) == 0)) {
imsm_mem = mem;
break;
}
}
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
if (!imsm_mem)
return 0;
struct orom_entry *orom = add_orom(imsm_mem);
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
/* only PciDataStructure with revision 3 and above supports devices list. */
if (ptr->pciDataStructRev >= 3 && ptr->devListOffset) {
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
const __u16 *dev_list = (void *)ptr + ptr->devListOffset;
int i;
for (i = 0; dev_list[i] != 0; i++)
add_orom_device_id(orom, dev_list[i]);
} else {
add_orom_device_id(orom, __le16_to_cpu(ptr->deviceID));
}
return 0;
}
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
const struct imsm_orom *imsm_platform_test(struct sys_dev *hba)
{
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
struct imsm_orom orom = {
.signature = IMSM_OROM_SIGNATURE,
.rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
IMSM_OROM_RLC_RAID10 | IMSM_OROM_RLC_RAID5,
.sss = IMSM_OROM_SSS_4kB | IMSM_OROM_SSS_8kB |
IMSM_OROM_SSS_16kB | IMSM_OROM_SSS_32kB |
IMSM_OROM_SSS_64kB | IMSM_OROM_SSS_128kB |
IMSM_OROM_SSS_256kB | IMSM_OROM_SSS_512kB |
IMSM_OROM_SSS_1MB | IMSM_OROM_SSS_2MB,
.dpa = IMSM_OROM_DISKS_PER_ARRAY,
.tds = IMSM_OROM_TOTAL_DISKS,
.vpa = IMSM_OROM_VOLUMES_PER_ARRAY,
.vphba = IMSM_OROM_VOLUMES_PER_HBA
};
orom.attr = orom.rlc | IMSM_OROM_ATTR_ChecksumVerify;
if (check_env("IMSM_TEST_OROM_NORAID5")) {
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
orom.rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
IMSM_OROM_RLC_RAID10;
}
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
if (check_env("IMSM_TEST_AHCI_EFI_NORAID5") && (hba->type == SYS_DEV_SAS)) {
orom.rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
IMSM_OROM_RLC_RAID10;
}
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
if (check_env("IMSM_TEST_SCU_EFI_NORAID5") && (hba->type == SYS_DEV_SATA)) {
orom.rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
IMSM_OROM_RLC_RAID10;
}
struct orom_entry *ret = add_orom(&orom);
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
add_orom_device_id(ret, hba->dev_id);
return &ret->orom;
}
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
static const struct imsm_orom *find_imsm_hba_orom(struct sys_dev *hba)
{
unsigned long align;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
if (check_env("IMSM_TEST_OROM"))
return imsm_platform_test(hba);
/* return empty OROM capabilities in EFI test mode */
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI"))
return NULL;
find_intel_devices();
if (intel_devices == NULL)
return NULL;
/* scan option-rom memory looking for an imsm signature */
if (check_env("IMSM_SAFE_OROM_SCAN"))
align = 2048;
else
align = 512;
if (probe_roms_init(align) != 0)
return NULL;
probe_roms();
/* ignore return value - True is returned if both adapater roms are found */
scan_adapter_roms(scan);
probe_roms_exit();
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
return get_orom_by_device_id(hba->dev_id);
}
#define GUID_STR_MAX 37 /* according to GUID format:
* xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */
#define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
((struct efi_guid) \
{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
(b) & 0xff, ((b) >> 8) & 0xff, \
(c) & 0xff, ((c) >> 8) & 0xff, \
(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
#define SYS_EFI_VAR_PATH "/sys/firmware/efi/vars"
#define SYS_EFIVARS_PATH "/sys/firmware/efi/efivars"
#define SCU_PROP "RstScuV"
#define AHCI_PROP "RstSataV"
#define AHCI_SSATA_PROP "RstsSatV"
#define AHCI_CSATA_PROP "RstCSatV"
#define VMD_PROP "RstUefiV"
#define VENDOR_GUID \
EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, 0x1a, 0x04, 0xc6)
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
#define PCI_CLASS_RAID_CNTRL 0x010400
static int read_efi_var(void *buffer, ssize_t buf_size, char *variable_name, struct efi_guid guid)
{
char path[PATH_MAX];
char buf[GUID_STR_MAX];
int fd;
ssize_t n;
snprintf(path, PATH_MAX, "%s/%s-%s", SYS_EFIVARS_PATH, variable_name, guid_str(buf, guid));
fd = open(path, O_RDONLY);
if (fd < 0)
return 1;
/* read the variable attributes and ignore it */
n = read(fd, buf, sizeof(__u32));
if (n < 0) {
close(fd);
return 1;
}
/* read the variable data */
n = read(fd, buffer, buf_size);
close(fd);
if (n < buf_size)
return 1;
return 0;
}
static int read_efi_variable(void *buffer, ssize_t buf_size, char *variable_name, struct efi_guid guid)
{
char path[PATH_MAX];
char buf[GUID_STR_MAX];
int dfd;
ssize_t n, var_data_len;
/* Try to read the variable using the new efivarfs interface first.
* If that fails, fall back to the old sysfs-efivars interface. */
if (!read_efi_var(buffer, buf_size, variable_name, guid))
return 0;
snprintf(path, PATH_MAX, "%s/%s-%s/size", SYS_EFI_VAR_PATH, variable_name, guid_str(buf, guid));
dprintf("EFI VAR: path=%s\n", path);
/* get size of variable data */
dfd = open(path, O_RDONLY);
if (dfd < 0)
return 1;
n = read(dfd, &buf, sizeof(buf));
close(dfd);
if (n < 0)
return 1;
buf[n] = '\0';
errno = 0;
var_data_len = strtoul(buf, NULL, 16);
if ((errno == ERANGE && (var_data_len == LONG_MAX)) ||
(errno != 0 && var_data_len == 0))
return 1;
/* get data */
snprintf(path, PATH_MAX, "%s/%s-%s/data", SYS_EFI_VAR_PATH, variable_name, guid_str(buf, guid));
dprintf("EFI VAR: path=%s\n", path);
dfd = open(path, O_RDONLY);
if (dfd < 0)
return 1;
n = read(dfd, buffer, buf_size);
close(dfd);
if (n != var_data_len || n < buf_size) {
return 1;
}
return 0;
}
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
const struct imsm_orom *find_imsm_efi(struct sys_dev *hba)
{
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
struct imsm_orom orom;
struct orom_entry *ret;
int err;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI"))
return imsm_platform_test(hba);
/* OROM test is set, return that there is no EFI capabilities */
if (check_env("IMSM_TEST_OROM"))
return NULL;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
if (hba->type == SYS_DEV_SATA && hba->class != PCI_CLASS_RAID_CNTRL)
return NULL;
err = read_efi_variable(&orom, sizeof(orom), hba->type == SYS_DEV_SAS ? SCU_PROP : AHCI_PROP, VENDOR_GUID);
/* 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, VENDOR_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, VENDOR_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 (hba->type == SYS_DEV_VMD) {
err = read_efi_variable(&orom, sizeof(orom), VMD_PROP, VENDOR_GUID);
}
if (err)
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
return NULL;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
ret = add_orom(&orom);
add_orom_device_id(ret, hba->dev_id);
ret->type = hba->type;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
return &ret->orom;
}
const struct imsm_orom *find_imsm_nvme(struct sys_dev *hba)
{
static struct orom_entry *nvme_orom;
if (hba->type != SYS_DEV_NVME)
return NULL;
if (!nvme_orom) {
struct imsm_orom nvme_orom_compat = {
.signature = IMSM_NVME_OROM_COMPAT_SIGNATURE,
.rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
IMSM_OROM_RLC_RAID10 | IMSM_OROM_RLC_RAID5,
.sss = IMSM_OROM_SSS_4kB | IMSM_OROM_SSS_8kB |
IMSM_OROM_SSS_16kB | IMSM_OROM_SSS_32kB |
IMSM_OROM_SSS_64kB | IMSM_OROM_SSS_128kB,
.dpa = IMSM_OROM_DISKS_PER_ARRAY_NVME,
.tds = IMSM_OROM_TOTAL_DISKS_NVME,
.vpa = IMSM_OROM_VOLUMES_PER_ARRAY,
.vphba = IMSM_OROM_TOTAL_DISKS_NVME / 2 * IMSM_OROM_VOLUMES_PER_ARRAY,
.attr = IMSM_OROM_ATTR_2TB | IMSM_OROM_ATTR_2TB_DISK,
.driver_features = IMSM_OROM_CAPABILITIES_EnterpriseSystem
};
nvme_orom = add_orom(&nvme_orom_compat);
}
add_orom_device_id(nvme_orom, hba->dev_id);
nvme_orom->type = SYS_DEV_NVME;
return &nvme_orom->orom;
}
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
const struct imsm_orom *find_imsm_capability(struct sys_dev *hba)
{
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
const struct imsm_orom *cap = get_orom_by_device_id(hba->dev_id);
if (cap)
return cap;
if (hba->type == SYS_DEV_NVME)
return find_imsm_nvme(hba);
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
if ((cap = find_imsm_efi(hba)) != NULL)
return cap;
imsm: support for OROMs shared by multiple HBAs The IMSM platform code was based on an assumption that the OROM or UEFI capability structure (represented by struct imsm_orom) always belongs to only one HBA. This assumption is no longer valid, because of newer platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but some versions have a combined OROM for both HBAs. This patch implements this HBA-OROM relationship in struct orom_entry, which matches an OROM with a list of HBA PCI ids. All the detected orom_entries are stored and retrieved using a global array and the functions add_orom(), add_orom_device_id() and get_orom_by_device_id(). This replaces the arrays: imsm_orom, populated_orom, imsm_efi, populated_efi. The scan() function is extended to find all HBAs for an OROM. The list of their device ids is retrieved from the PCI Expansion ROM Data Structure, hence the additional field devListOffset in struct pciExpDataStructFormat. In UEFI mode we can't read the PCI Expansion ROM Data Structure and the imsm_orom structures are stored in UEFI variables. They do not provide a similar device id list, so we also check the HBA PCI class to make sure that the HBA has RAID mode enabled. In super-intel.c there are changes which allow spanning of IMSM containers over HBAs of the same type, but only if the HBAs share the same OROM. This is done by comparing imsm_orom pointers, which (outside of platform-intel.c) always point to the global array containing all the detected oroms. Additional warnings are added to validate_container_imsm() to warn about potentially dangerous operations in all the possible cases, e.g. when an array is assembled using disks attached to HBAs with separate OROMs. Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
2014-11-19 13:53:26 +01:00
if ((cap = find_imsm_hba_orom(hba)) != NULL)
return cap;
return NULL;
}
char *devt_to_devpath(dev_t dev)
{
char device[46];
sprintf(device, "/sys/dev/block/%d:%d/device", major(dev), minor(dev));
return realpath(device, NULL);
}
char *diskfd_to_devpath(int fd)
{
/* return the device path for a disk, return NULL on error or fd
* refers to a partition
*/
struct stat st;
if (fstat(fd, &st) != 0)
return NULL;
if (!S_ISBLK(st.st_mode))
return NULL;
return devt_to_devpath(st.st_rdev);
}
int path_attached_to_hba(const char *disk_path, const char *hba_path)
{
int rc;
if (check_env("IMSM_TEST_AHCI_DEV") ||
check_env("IMSM_TEST_SCU_DEV")) {
return 1;
}
if (!disk_path || !hba_path)
return 0;
dprintf("hba: %s - disk: %s\n", hba_path, disk_path);
if (strncmp(disk_path, hba_path, strlen(hba_path)) == 0)
rc = 1;
else
rc = 0;
return rc;
}
int devt_attached_to_hba(dev_t dev, const char *hba_path)
{
char *disk_path = devt_to_devpath(dev);
int rc = path_attached_to_hba(disk_path, hba_path);
if (disk_path)
free(disk_path);
return rc;
}
int disk_attached_to_hba(int fd, const char *hba_path)
{
char *disk_path = diskfd_to_devpath(fd);
int rc = path_attached_to_hba(disk_path, hba_path);
if (disk_path)
free(disk_path);
return rc;
}
char *vmd_domain_to_controller(struct sys_dev *hba, char *buf)
{
struct dirent *ent;
DIR *dir;
char path[PATH_MAX];
if (!hba)
return NULL;
if (hba->type != SYS_DEV_VMD)
return NULL;
dir = opendir("/sys/bus/pci/drivers/vmd");
if (!dir)
return NULL;
for (ent = readdir(dir); ent; ent = readdir(dir)) {
sprintf(path, "/sys/bus/pci/drivers/vmd/%s/domain/device",
ent->d_name);
if (!realpath(path, buf))
continue;
if (strncmp(buf, hba->path, strlen(buf)) == 0) {
sprintf(path, "/sys/bus/pci/drivers/vmd/%s", ent->d_name);
closedir(dir);
return realpath(path, buf);
}
}
closedir(dir);
return NULL;
}