Blame SOURCES/mdadm-3.3.2-imsm-support-for-OROMs-shared-by-multiple-HBAs.patch

2ddfcf
From 6b781d331bf52b01b9bafa6409ffb400f8c62895 Mon Sep 17 00:00:00 2001
2ddfcf
From: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
2ddfcf
Date: Wed, 19 Nov 2014 13:53:26 +0100
2ddfcf
Subject: [PATCH] imsm: support for OROMs shared by multiple HBAs
2ddfcf
2ddfcf
The IMSM platform code was based on an assumption that the OROM or UEFI
2ddfcf
capability structure (represented by struct imsm_orom) always belongs to
2ddfcf
only one HBA. This assumption is no longer valid, because of newer
2ddfcf
platforms with dual AHCI HBAs. Each HBA can have a separate OROM, but
2ddfcf
some versions have a combined OROM for both HBAs.
2ddfcf
2ddfcf
This patch implements this HBA-OROM relationship in struct orom_entry,
2ddfcf
which matches an OROM with a list of HBA PCI ids. All the detected
2ddfcf
orom_entries are stored and retrieved using a global array and the
2ddfcf
functions add_orom(), add_orom_device_id() and get_orom_by_device_id().
2ddfcf
This replaces the arrays: imsm_orom, populated_orom, imsm_efi,
2ddfcf
populated_efi.
2ddfcf
2ddfcf
The scan() function is extended to find all HBAs for an OROM. The list
2ddfcf
of their device ids is retrieved from the PCI Expansion ROM Data
2ddfcf
Structure, hence the additional field devListOffset in struct
2ddfcf
pciExpDataStructFormat.
2ddfcf
2ddfcf
In UEFI mode we can't read the PCI Expansion ROM Data Structure and the
2ddfcf
imsm_orom structures are stored in UEFI variables. They do not provide a
2ddfcf
similar device id list, so we also check the HBA PCI class to make sure
2ddfcf
that the HBA has RAID mode enabled.
2ddfcf
2ddfcf
In super-intel.c there are changes which allow spanning of IMSM
2ddfcf
containers over HBAs of the same type, but only if the HBAs share the
2ddfcf
same OROM.  This is done by comparing imsm_orom pointers, which (outside
2ddfcf
of platform-intel.c) always point to the global array containing all the
2ddfcf
detected oroms. Additional warnings are added to
2ddfcf
validate_container_imsm() to warn about potentially dangerous operations
2ddfcf
in all the possible cases, e.g. when an array is assembled using disks
2ddfcf
attached to HBAs with separate OROMs.
2ddfcf
2ddfcf
Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
2ddfcf
Signed-off-by: NeilBrown <neilb@suse.de>
2ddfcf
---
2ddfcf
 platform-intel.c | 248 ++++++++++++++++++++++++++++++++-----------------------
2ddfcf
 platform-intel.h |   5 +-
2ddfcf
 super-intel.c    | 134 +++++++++++++++++++++---------
2ddfcf
 3 files changed, 243 insertions(+), 144 deletions(-)
2ddfcf
2ddfcf
diff --git a/platform-intel.c b/platform-intel.c
2ddfcf
index f347382..f779d02 100644
2ddfcf
--- a/platform-intel.c
2ddfcf
+++ b/platform-intel.c
2ddfcf
@@ -59,6 +59,7 @@ struct sys_dev *find_driver_devices(const char *bus, const char *driver)
2ddfcf
 	struct sys_dev *list = NULL;
2ddfcf
 	enum sys_dev_type type;
2ddfcf
 	unsigned long long dev_id;
2ddfcf
+	unsigned long long class;
2ddfcf
 
2ddfcf
 	if (strcmp(driver, "isci") == 0)
2ddfcf
 		type = SYS_DEV_SAS;
2ddfcf
@@ -99,6 +100,9 @@ struct sys_dev *find_driver_devices(const char *bus, const char *driver)
2ddfcf
 		if (devpath_to_ll(path, "device", &dev_id) != 0)
2ddfcf
 			continue;
2ddfcf
 
2ddfcf
+		if (devpath_to_ll(path, "class", &class) != 0)
2ddfcf
+			continue;
2ddfcf
+
2ddfcf
 		/* start / add list entry */
2ddfcf
 		if (!head) {
2ddfcf
 			head = xmalloc(sizeof(*head));
2ddfcf
@@ -114,6 +118,7 @@ struct sys_dev *find_driver_devices(const char *bus, const char *driver)
2ddfcf
 		}
2ddfcf
 
2ddfcf
 		list->dev_id = (__u16) dev_id;
2ddfcf
+		list->class = (__u32) class;
2ddfcf
 		list->type = type;
2ddfcf
 		list->path = realpath(path, NULL);
2ddfcf
 		list->next = NULL;
2ddfcf
@@ -127,16 +132,6 @@ struct sys_dev *find_driver_devices(const char *bus, const char *driver)
2ddfcf
 static struct sys_dev *intel_devices=NULL;
2ddfcf
 static time_t valid_time = 0;
2ddfcf
 
2ddfcf
-static enum sys_dev_type device_type_by_id(__u16 device_id)
2ddfcf
-{
2ddfcf
-	struct sys_dev *iter;
2ddfcf
-
2ddfcf
-	for(iter = intel_devices; iter != NULL; iter = iter->next)
2ddfcf
-		if (iter->dev_id == device_id)
2ddfcf
-			return iter->type;
2ddfcf
-	return SYS_DEV_UNKNOWN;
2ddfcf
-}
2ddfcf
-
2ddfcf
 static int devpath_to_ll(const char *dev_path, const char *entry, unsigned long long *val)
2ddfcf
 {
2ddfcf
 	char path[strlen(dev_path) + strlen(entry) + 2];
2ddfcf
@@ -209,16 +204,79 @@ struct pciExpDataStructFormat {
2ddfcf
 	__u8  ver[4];
2ddfcf
 	__u16 vendorID;
2ddfcf
 	__u16 deviceID;
2ddfcf
+	__u16 devListOffset;
2ddfcf
 } __attribute__ ((packed));
2ddfcf
 
2ddfcf
-static struct imsm_orom imsm_orom[SYS_DEV_MAX];
2ddfcf
-static int populated_orom[SYS_DEV_MAX];
2ddfcf
+struct devid_list {
2ddfcf
+	__u16 devid;
2ddfcf
+	struct devid_list *next;
2ddfcf
+};
2ddfcf
+
2ddfcf
+struct orom_entry {
2ddfcf
+	struct imsm_orom orom;
2ddfcf
+	struct devid_list *devid_list;
2ddfcf
+};
2ddfcf
+
2ddfcf
+static struct orom_entry oroms[SYS_DEV_MAX];
2ddfcf
+
2ddfcf
+const struct imsm_orom *get_orom_by_device_id(__u16 dev_id)
2ddfcf
+{
2ddfcf
+	int i;
2ddfcf
+	struct devid_list *list;
2ddfcf
+
2ddfcf
+	for (i = 0; i < SYS_DEV_MAX; i++) {
2ddfcf
+		for (list = oroms[i].devid_list; list; list = list->next) {
2ddfcf
+			if (list->devid == dev_id)
2ddfcf
+				return &oroms[i].orom;
2ddfcf
+		}
2ddfcf
+	}
2ddfcf
+	return NULL;
2ddfcf
+}
2ddfcf
+
2ddfcf
+static const struct imsm_orom *add_orom(const struct imsm_orom *orom)
2ddfcf
+{
2ddfcf
+	int i;
2ddfcf
+
2ddfcf
+	for (i = 0; i < SYS_DEV_MAX; i++) {
2ddfcf
+		if (&oroms[i].orom == orom)
2ddfcf
+			return orom;
2ddfcf
+		if (oroms[i].orom.signature[0] == 0) {
2ddfcf
+			oroms[i].orom = *orom;
2ddfcf
+			return &oroms[i].orom;
2ddfcf
+		}
2ddfcf
+	}
2ddfcf
+	return NULL;
2ddfcf
+}
2ddfcf
+
2ddfcf
+static void add_orom_device_id(const struct imsm_orom *orom, __u16 dev_id)
2ddfcf
+{
2ddfcf
+	int i;
2ddfcf
+	struct devid_list *list;
2ddfcf
+	struct devid_list *prev = NULL;
2ddfcf
+
2ddfcf
+	for (i = 0; i < SYS_DEV_MAX; i++) {
2ddfcf
+		if (&oroms[i].orom == orom) {
2ddfcf
+			for (list = oroms[i].devid_list; list; prev = list, list = list->next) {
2ddfcf
+				if (list->devid == dev_id)
2ddfcf
+					return;
2ddfcf
+			}
2ddfcf
+			list = xmalloc(sizeof(struct devid_list));
2ddfcf
+			list->devid = dev_id;
2ddfcf
+			list->next = NULL;
2ddfcf
+
2ddfcf
+			if (prev == NULL)
2ddfcf
+				oroms[i].devid_list = list;
2ddfcf
+			else
2ddfcf
+				prev->next = list;
2ddfcf
+			return;
2ddfcf
+		}
2ddfcf
+	}
2ddfcf
+}
2ddfcf
 
2ddfcf
 static int scan(const void *start, const void *end, const void *data)
2ddfcf
 {
2ddfcf
 	int offset;
2ddfcf
-	const struct imsm_orom *imsm_mem;
2ddfcf
-	int dev;
2ddfcf
+	const struct imsm_orom *imsm_mem = NULL;
2ddfcf
 	int len = (end - start);
2ddfcf
 	struct pciExpDataStructFormat *ptr= (struct pciExpDataStructFormat *)data;
2ddfcf
 
2ddfcf
@@ -231,81 +289,83 @@ static int scan(const void *start, const void *end, const void *data)
2ddfcf
 		(ulong) __le16_to_cpu(ptr->vendorID),
2ddfcf
 		(ulong) __le16_to_cpu(ptr->deviceID));
2ddfcf
 
2ddfcf
-	if (__le16_to_cpu(ptr->vendorID) == 0x8086) {
2ddfcf
-		/* serach  attached intel devices by device id from OROM */
2ddfcf
-		dev = device_type_by_id(__le16_to_cpu(ptr->deviceID));
2ddfcf
-		if (dev == SYS_DEV_UNKNOWN)
2ddfcf
-			return 0;
2ddfcf
-	}
2ddfcf
-	else
2ddfcf
+	if (__le16_to_cpu(ptr->vendorID) != 0x8086)
2ddfcf
 		return 0;
2ddfcf
 
2ddfcf
 	for (offset = 0; offset < len; offset += 4) {
2ddfcf
-		imsm_mem = start + offset;
2ddfcf
-		if ((memcmp(imsm_mem->signature, "$VER", 4) == 0)) {
2ddfcf
-			imsm_orom[dev] = *imsm_mem;
2ddfcf
-			populated_orom[dev] = 1;
2ddfcf
-			return populated_orom[SYS_DEV_SATA] && populated_orom[SYS_DEV_SAS];
2ddfcf
+		const void *mem = start + offset;
2ddfcf
+
2ddfcf
+		if ((memcmp(mem, IMSM_OROM_SIGNATURE, 4) == 0)) {
2ddfcf
+			imsm_mem = mem;
2ddfcf
+			break;
2ddfcf
 		}
2ddfcf
 	}
2ddfcf
+
2ddfcf
+	if (!imsm_mem)
2ddfcf
+		return 0;
2ddfcf
+
2ddfcf
+	const struct imsm_orom *orom = add_orom(imsm_mem);
2ddfcf
+
2ddfcf
+	if (ptr->devListOffset) {
2ddfcf
+		const __u16 *dev_list = (void *)ptr + ptr->devListOffset;
2ddfcf
+		int i;
2ddfcf
+
2ddfcf
+		for (i = 0; dev_list[i] != 0; i++)
2ddfcf
+			add_orom_device_id(orom, dev_list[i]);
2ddfcf
+	} else {
2ddfcf
+		add_orom_device_id(orom, __le16_to_cpu(ptr->deviceID));
2ddfcf
+	}
2ddfcf
+
2ddfcf
 	return 0;
2ddfcf
 }
2ddfcf
 
2ddfcf
-const struct imsm_orom *imsm_platform_test(enum sys_dev_type hba_id, int *populated,
2ddfcf
-					   struct imsm_orom *imsm_orom)
2ddfcf
+const struct imsm_orom *imsm_platform_test(struct sys_dev *hba)
2ddfcf
 {
2ddfcf
-	memset(imsm_orom, 0, sizeof(*imsm_orom));
2ddfcf
-	imsm_orom->rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
2ddfcf
-				IMSM_OROM_RLC_RAID10 | IMSM_OROM_RLC_RAID5;
2ddfcf
-	imsm_orom->sss = IMSM_OROM_SSS_4kB | IMSM_OROM_SSS_8kB |
2ddfcf
-				IMSM_OROM_SSS_16kB | IMSM_OROM_SSS_32kB |
2ddfcf
-				IMSM_OROM_SSS_64kB | IMSM_OROM_SSS_128kB |
2ddfcf
-				IMSM_OROM_SSS_256kB | IMSM_OROM_SSS_512kB |
2ddfcf
-				IMSM_OROM_SSS_1MB | IMSM_OROM_SSS_2MB;
2ddfcf
-	imsm_orom->dpa = IMSM_OROM_DISKS_PER_ARRAY;
2ddfcf
-	imsm_orom->tds = IMSM_OROM_TOTAL_DISKS;
2ddfcf
-	imsm_orom->vpa = IMSM_OROM_VOLUMES_PER_ARRAY;
2ddfcf
-	imsm_orom->vphba = IMSM_OROM_VOLUMES_PER_HBA;
2ddfcf
-	imsm_orom->attr = imsm_orom->rlc | IMSM_OROM_ATTR_ChecksumVerify;
2ddfcf
-	*populated = 1;
2ddfcf
+	struct imsm_orom orom = {
2ddfcf
+		.signature = IMSM_OROM_SIGNATURE,
2ddfcf
+		.rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
2ddfcf
+					IMSM_OROM_RLC_RAID10 | IMSM_OROM_RLC_RAID5,
2ddfcf
+		.sss = IMSM_OROM_SSS_4kB | IMSM_OROM_SSS_8kB |
2ddfcf
+					IMSM_OROM_SSS_16kB | IMSM_OROM_SSS_32kB |
2ddfcf
+					IMSM_OROM_SSS_64kB | IMSM_OROM_SSS_128kB |
2ddfcf
+					IMSM_OROM_SSS_256kB | IMSM_OROM_SSS_512kB |
2ddfcf
+					IMSM_OROM_SSS_1MB | IMSM_OROM_SSS_2MB,
2ddfcf
+		.dpa = IMSM_OROM_DISKS_PER_ARRAY,
2ddfcf
+		.tds = IMSM_OROM_TOTAL_DISKS,
2ddfcf
+		.vpa = IMSM_OROM_VOLUMES_PER_ARRAY,
2ddfcf
+		.vphba = IMSM_OROM_VOLUMES_PER_HBA
2ddfcf
+	};
2ddfcf
+	orom.attr = orom.rlc | IMSM_OROM_ATTR_ChecksumVerify;
2ddfcf
 
2ddfcf
 	if (check_env("IMSM_TEST_OROM_NORAID5")) {
2ddfcf
-		imsm_orom->rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
2ddfcf
+		orom.rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
2ddfcf
 				IMSM_OROM_RLC_RAID10;
2ddfcf
 	}
2ddfcf
-	if (check_env("IMSM_TEST_AHCI_EFI_NORAID5") && (hba_id == SYS_DEV_SAS)) {
2ddfcf
-		imsm_orom->rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
2ddfcf
+	if (check_env("IMSM_TEST_AHCI_EFI_NORAID5") && (hba->type == SYS_DEV_SAS)) {
2ddfcf
+		orom.rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
2ddfcf
 				IMSM_OROM_RLC_RAID10;
2ddfcf
 	}
2ddfcf
-	if (check_env("IMSM_TEST_SCU_EFI_NORAID5") && (hba_id == SYS_DEV_SATA)) {
2ddfcf
-		imsm_orom->rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
2ddfcf
+	if (check_env("IMSM_TEST_SCU_EFI_NORAID5") && (hba->type == SYS_DEV_SATA)) {
2ddfcf
+		orom.rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
2ddfcf
 				IMSM_OROM_RLC_RAID10;
2ddfcf
 	}
2ddfcf
 
2ddfcf
-	return imsm_orom;
2ddfcf
+	const struct imsm_orom *ret = add_orom(&orom;;
2ddfcf
+
2ddfcf
+	add_orom_device_id(ret, hba->dev_id);
2ddfcf
+
2ddfcf
+	return ret;
2ddfcf
 }
2ddfcf
 
2ddfcf
-static const struct imsm_orom *find_imsm_hba_orom(enum sys_dev_type hba_id)
2ddfcf
+static const struct imsm_orom *find_imsm_hba_orom(struct sys_dev *hba)
2ddfcf
 {
2ddfcf
 	unsigned long align;
2ddfcf
 
2ddfcf
-	if (hba_id >= SYS_DEV_MAX)
2ddfcf
-		return NULL;
2ddfcf
+	if (check_env("IMSM_TEST_OROM"))
2ddfcf
+		return imsm_platform_test(hba);
2ddfcf
 
2ddfcf
-	/* it's static data so we only need to read it once */
2ddfcf
-	if (populated_orom[hba_id]) {
2ddfcf
-		dprintf("OROM CAP: %p, pid: %d pop: %d\n",
2ddfcf
-			&imsm_orom[hba_id], (int) getpid(), populated_orom[hba_id]);
2ddfcf
-		return &imsm_orom[hba_id];
2ddfcf
-	}
2ddfcf
-	if (check_env("IMSM_TEST_OROM")) {
2ddfcf
-		dprintf("OROM CAP: %p,  pid: %d pop: %d\n",
2ddfcf
-			&imsm_orom[hba_id], (int) getpid(), populated_orom[hba_id]);
2ddfcf
-		return imsm_platform_test(hba_id, &populated_orom[hba_id], &imsm_orom[hba_id]);
2ddfcf
-	}
2ddfcf
 	/* return empty OROM capabilities in EFI test mode */
2ddfcf
-	if (check_env("IMSM_TEST_AHCI_EFI") ||
2ddfcf
-	    check_env("IMSM_TEST_SCU_EFI"))
2ddfcf
+	if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI"))
2ddfcf
 		return NULL;
2ddfcf
 
2ddfcf
 	find_intel_devices();
2ddfcf
@@ -325,9 +385,7 @@ static const struct imsm_orom *find_imsm_hba_orom(enum sys_dev_type hba_id)
2ddfcf
 	scan_adapter_roms(scan);
2ddfcf
 	probe_roms_exit();
2ddfcf
 
2ddfcf
-	if (populated_orom[hba_id])
2ddfcf
-		return &imsm_orom[hba_id];
2ddfcf
-	return NULL;
2ddfcf
+	return get_orom_by_device_id(hba->dev_id);
2ddfcf
 }
2ddfcf
 
2ddfcf
 #define GUID_STR_MAX	37  /* according to GUID format:
2ddfcf
@@ -347,9 +405,7 @@ static const struct imsm_orom *find_imsm_hba_orom(enum sys_dev_type hba_id)
2ddfcf
 #define VENDOR_GUID \
2ddfcf
 	EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, 0x1a, 0x04, 0xc6)
2ddfcf
 
2ddfcf
-int populated_efi[SYS_DEV_MAX] = { 0, 0 };
2ddfcf
-
2ddfcf
-static struct imsm_orom imsm_efi[SYS_DEV_MAX];
2ddfcf
+#define PCI_CLASS_RAID_CNTRL 0x010400
2ddfcf
 
2ddfcf
 int read_efi_variable(void *buffer, ssize_t buf_size, char *variable_name, struct efi_guid guid)
2ddfcf
 {
2ddfcf
@@ -395,54 +451,40 @@ int read_efi_variable(void *buffer, ssize_t buf_size, char *variable_name, struc
2ddfcf
 	return 0;
2ddfcf
 }
2ddfcf
 
2ddfcf
-const struct imsm_orom *find_imsm_efi(enum sys_dev_type hba_id)
2ddfcf
+const struct imsm_orom *find_imsm_efi(struct sys_dev *hba)
2ddfcf
 {
2ddfcf
-	if (hba_id >= SYS_DEV_MAX)
2ddfcf
-		return NULL;
2ddfcf
+	struct imsm_orom orom;
2ddfcf
+	const struct imsm_orom *ret;
2ddfcf
 
2ddfcf
-	dprintf("EFI CAP: %p,  pid: %d pop: %d\n",
2ddfcf
-		&imsm_efi[hba_id], (int) getpid(), populated_efi[hba_id]);
2ddfcf
+	if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI"))
2ddfcf
+		return imsm_platform_test(hba);
2ddfcf
 
2ddfcf
-	/* it's static data so we only need to read it once */
2ddfcf
-	if (populated_efi[hba_id]) {
2ddfcf
-		dprintf("EFI CAP: %p, pid: %d pop: %d\n",
2ddfcf
-			&imsm_efi[hba_id], (int) getpid(), populated_efi[hba_id]);
2ddfcf
-		return &imsm_efi[hba_id];
2ddfcf
-	}
2ddfcf
-	if (check_env("IMSM_TEST_AHCI_EFI") ||
2ddfcf
-	    check_env("IMSM_TEST_SCU_EFI")) {
2ddfcf
-		dprintf("OROM CAP: %p,  pid: %d pop: %d\n",
2ddfcf
-			&imsm_efi[hba_id], (int) getpid(), populated_efi[hba_id]);
2ddfcf
-		return imsm_platform_test(hba_id, &populated_efi[hba_id], &imsm_efi[hba_id]);
2ddfcf
-	}
2ddfcf
 	/* OROM test is set, return that there is no EFI capabilities */
2ddfcf
 	if (check_env("IMSM_TEST_OROM"))
2ddfcf
 		return NULL;
2ddfcf
 
2ddfcf
-	if (read_efi_variable(&imsm_efi[hba_id], sizeof(imsm_efi[0]), hba_id == SYS_DEV_SAS ? SCU_PROP : AHCI_PROP, VENDOR_GUID)) {
2ddfcf
-		populated_efi[hba_id] = 0;
2ddfcf
+	if (hba->type == SYS_DEV_SATA && hba->class != PCI_CLASS_RAID_CNTRL)
2ddfcf
 		return NULL;
2ddfcf
-	}
2ddfcf
 
2ddfcf
-	populated_efi[hba_id] = 1;
2ddfcf
-	return &imsm_efi[hba_id];
2ddfcf
-}
2ddfcf
+	if (read_efi_variable(&orom, sizeof(orom), hba->type == SYS_DEV_SAS ? SCU_PROP : AHCI_PROP, VENDOR_GUID))
2ddfcf
+		return NULL;
2ddfcf
 
2ddfcf
-/*
2ddfcf
- * backward interface compatibility
2ddfcf
- */
2ddfcf
-const struct imsm_orom *find_imsm_orom(void)
2ddfcf
-{
2ddfcf
-	return find_imsm_hba_orom(SYS_DEV_SATA);
2ddfcf
+	ret = add_orom(&orom;;
2ddfcf
+	add_orom_device_id(ret, hba->dev_id);
2ddfcf
+
2ddfcf
+	return ret;
2ddfcf
 }
2ddfcf
 
2ddfcf
-const struct imsm_orom *find_imsm_capability(enum sys_dev_type hba_id)
2ddfcf
+const struct imsm_orom *find_imsm_capability(struct sys_dev *hba)
2ddfcf
 {
2ddfcf
-	const struct imsm_orom *cap=NULL;
2ddfcf
+	const struct imsm_orom *cap = get_orom_by_device_id(hba->dev_id);
2ddfcf
+
2ddfcf
+	if (cap)
2ddfcf
+		return cap;
2ddfcf
 
2ddfcf
-	if ((cap = find_imsm_efi(hba_id)) != NULL)
2ddfcf
+	if ((cap = find_imsm_efi(hba)) != NULL)
2ddfcf
 		return cap;
2ddfcf
-	if ((cap = find_imsm_hba_orom(hba_id)) != NULL)
2ddfcf
+	if ((cap = find_imsm_hba_orom(hba)) != NULL)
2ddfcf
 		return cap;
2ddfcf
 	return NULL;
2ddfcf
 }
2ddfcf
diff --git a/platform-intel.h b/platform-intel.h
2ddfcf
index 8226be3..e41f386 100644
2ddfcf
--- a/platform-intel.h
2ddfcf
+++ b/platform-intel.h
2ddfcf
@@ -22,6 +22,7 @@
2ddfcf
 /* The IMSM Capability (IMSM AHCI and ISCU OROM/EFI variable) Version Table definition */
2ddfcf
 struct imsm_orom {
2ddfcf
 	__u8 signature[4];
2ddfcf
+	#define IMSM_OROM_SIGNATURE "$VER"
2ddfcf
 	__u8 table_ver_major; /* Currently 2 (can change with future revs) */
2ddfcf
 	__u8 table_ver_minor; /* Currently 2 (can change with future revs) */
2ddfcf
 	__u16 major_ver; /* Example: 8 as in 8.6.0.1020 */
2ddfcf
@@ -180,6 +181,7 @@ struct sys_dev {
2ddfcf
 	char *path;
2ddfcf
 	char *pci_id;
2ddfcf
 	__u16  dev_id;
2ddfcf
+	__u32  class;
2ddfcf
 	struct sys_dev *next;
2ddfcf
 };
2ddfcf
 
2ddfcf
@@ -201,10 +203,11 @@ static inline char *guid_str(char *buf, struct efi_guid guid)
2ddfcf
 char *diskfd_to_devpath(int fd);
2ddfcf
 struct sys_dev *find_driver_devices(const char *bus, const char *driver);
2ddfcf
 struct sys_dev *find_intel_devices(void);
2ddfcf
-const struct imsm_orom *find_imsm_capability(enum sys_dev_type hba_id);
2ddfcf
+const struct imsm_orom *find_imsm_capability(struct sys_dev *hba);
2ddfcf
 const struct imsm_orom *find_imsm_orom(void);
2ddfcf
 int disk_attached_to_hba(int fd, const char *hba_path);
2ddfcf
 int devt_attached_to_hba(dev_t dev, const char *hba_path);
2ddfcf
 char *devt_to_devpath(dev_t dev);
2ddfcf
 int path_attached_to_hba(const char *disk_path, const char *hba_path);
2ddfcf
 const char *get_sys_dev_type(enum sys_dev_type);
2ddfcf
+const struct imsm_orom *get_orom_by_device_id(__u16 device_id);
2ddfcf
diff --git a/super-intel.c b/super-intel.c
2ddfcf
index e28ac7d..dabf011 100644
2ddfcf
--- a/super-intel.c
2ddfcf
+++ b/super-intel.c
2ddfcf
@@ -555,11 +555,26 @@ static int attach_hba_to_super(struct intel_super *super, struct sys_dev *device
2ddfcf
 	if (super->hba == NULL) {
2ddfcf
 		super->hba = alloc_intel_hba(device);
2ddfcf
 		return 1;
2ddfcf
-	} else
2ddfcf
-		/* IMSM metadata disallows to attach disks to multiple
2ddfcf
-		 * controllers.
2ddfcf
-		 */
2ddfcf
+	}
2ddfcf
+
2ddfcf
+	hba = super->hba;
2ddfcf
+	/* Intel metadata allows for all disks attached to the same type HBA.
2ddfcf
+	 * Do not sypport odf HBA types mixing
2ddfcf
+	 */
2ddfcf
+	if (device->type != hba->type)
2ddfcf
+		return 2;
2ddfcf
+
2ddfcf
+	/* Multiple same type HBAs can be used if they share the same OROM */
2ddfcf
+	const struct imsm_orom *device_orom = get_orom_by_device_id(device->dev_id);
2ddfcf
+
2ddfcf
+	if (device_orom != super->orom)
2ddfcf
 		return 2;
2ddfcf
+
2ddfcf
+	while (hba->next)
2ddfcf
+		hba = hba->next;
2ddfcf
+
2ddfcf
+	hba->next = alloc_intel_hba(device);
2ddfcf
+	return 1;
2ddfcf
 }
2ddfcf
 
2ddfcf
 static struct sys_dev* find_disk_attached_hba(int fd, const char *devname)
2ddfcf
@@ -1886,13 +1901,12 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
2ddfcf
 		if (!list)
2ddfcf
 			return 2;
2ddfcf
 		for (hba = list; hba; hba = hba->next) {
2ddfcf
-			orom = find_imsm_capability(hba->type);
2ddfcf
-			if (!orom) {
2ddfcf
-				result = 2;
2ddfcf
+			if (find_imsm_capability(hba)) {
2ddfcf
+				result = 0;
2ddfcf
 				break;
2ddfcf
 			}
2ddfcf
 			else
2ddfcf
-				result = 0;
2ddfcf
+				result = 2;
2ddfcf
 		}
2ddfcf
 		return result;
2ddfcf
 	}
2ddfcf
@@ -1909,7 +1923,7 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
2ddfcf
 	for (hba = list; hba; hba = hba->next) {
2ddfcf
 		if (controller_path && (compare_paths(hba->path,controller_path) != 0))
2ddfcf
 			continue;
2ddfcf
-		orom = find_imsm_capability(hba->type);
2ddfcf
+		orom = find_imsm_capability(hba);
2ddfcf
 		if (!orom)
2ddfcf
 			pr_err("imsm capabilities not found for controller: %s (type %s)\n",
2ddfcf
 				hba->path, get_sys_dev_type(hba->type));
2ddfcf
@@ -1954,7 +1968,7 @@ static int export_detail_platform_imsm(int verbose, char *controller_path)
2ddfcf
 	for (hba = list; hba; hba = hba->next) {
2ddfcf
 		if (controller_path && (compare_paths(hba->path,controller_path) != 0))
2ddfcf
 			continue;
2ddfcf
-		orom = find_imsm_capability(hba->type);
2ddfcf
+		orom = find_imsm_capability(hba);
2ddfcf
 		if (!orom) {
2ddfcf
 			if (verbose > 0)
2ddfcf
 				pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_IMSM_CAPABLE_DEVICE_UNDER_%s\n",hba->path);
2ddfcf
@@ -3087,13 +3101,18 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst)
2ddfcf
 	 * use the same Intel hba
2ddfcf
 	 * If not on Intel hba at all, allow anything.
2ddfcf
 	 */
2ddfcf
-	if (!check_env("IMSM_NO_PLATFORM")) {
2ddfcf
-		if (first->hba && sec->hba &&
2ddfcf
-		    strcmp(first->hba->path, sec->hba->path) != 0)  {
2ddfcf
+	if (!check_env("IMSM_NO_PLATFORM") && first->hba && sec->hba) {
2ddfcf
+		if (first->hba->type != sec->hba->type) {
2ddfcf
+			fprintf(stderr,
2ddfcf
+				"HBAs of devices do not match %s != %s\n",
2ddfcf
+				get_sys_dev_type(first->hba->type),
2ddfcf
+				get_sys_dev_type(sec->hba->type));
2ddfcf
+			return 3;
2ddfcf
+		}
2ddfcf
+		if (first->orom != sec->orom) {
2ddfcf
 			fprintf(stderr,
2ddfcf
-				"HBAs of devices does not match %s != %s\n",
2ddfcf
-				first->hba ? first->hba->path : NULL,
2ddfcf
-				sec->hba ? sec->hba->path : NULL);
2ddfcf
+				"HBAs of devices do not match %s != %s\n",
2ddfcf
+				first->hba->pci_id, sec->hba->pci_id);
2ddfcf
 			return 3;
2ddfcf
 		}
2ddfcf
 	}
2ddfcf
@@ -3832,14 +3851,13 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
2ddfcf
 					fprintf(stderr, ", ");
2ddfcf
 				hba = hba->next;
2ddfcf
 			}
2ddfcf
-
2ddfcf
-			fprintf(stderr, ").\n");
2ddfcf
-			cont_err("Mixing devices attached to multiple controllers "
2ddfcf
-				 "is not allowed.\n");
2ddfcf
+			fprintf(stderr, ").\n"
2ddfcf
+				"    Mixing devices attached to different controllers "
2ddfcf
+				"is not allowed.\n");
2ddfcf
 		}
2ddfcf
 		return 2;
2ddfcf
 	}
2ddfcf
-	super->orom = find_imsm_capability(hba_name->type);
2ddfcf
+	super->orom = find_imsm_capability(hba_name);
2ddfcf
 	if (!super->orom)
2ddfcf
 		return 3;
2ddfcf
 	return 0;
2ddfcf
@@ -9061,32 +9079,68 @@ int open_backup_targets(struct mdinfo *info, int raid_disks, int *raid_fds,
2ddfcf
  ******************************************************************************/
2ddfcf
 int validate_container_imsm(struct mdinfo *info)
2ddfcf
 {
2ddfcf
-	if (!check_env("IMSM_NO_PLATFORM")) {
2ddfcf
-		struct sys_dev *idev;
2ddfcf
-		struct mdinfo *dev;
2ddfcf
-		char *hba_path = NULL;
2ddfcf
-		char *dev_path = devt_to_devpath(makedev(info->disk.major,
2ddfcf
-										info->disk.minor));
2ddfcf
+	if (check_env("IMSM_NO_PLATFORM"))
2ddfcf
+		return 0;
2ddfcf
 
2ddfcf
-		for (idev = find_intel_devices(); idev; idev = idev->next) {
2ddfcf
-			if (strstr(dev_path, idev->path)) {
2ddfcf
-				hba_path = idev->path;
2ddfcf
-				break;
2ddfcf
-			}
2ddfcf
+	struct sys_dev *idev;
2ddfcf
+	struct sys_dev *hba = NULL;
2ddfcf
+	struct sys_dev *intel_devices = find_intel_devices();
2ddfcf
+	char *dev_path = devt_to_devpath(makedev(info->disk.major,
2ddfcf
+									info->disk.minor));
2ddfcf
+
2ddfcf
+	for (idev = intel_devices; idev; idev = idev->next) {
2ddfcf
+		if (dev_path && strstr(dev_path, idev->path)) {
2ddfcf
+			hba = idev;
2ddfcf
+			break;
2ddfcf
 		}
2ddfcf
+	}
2ddfcf
+	if (dev_path)
2ddfcf
 		free(dev_path);
2ddfcf
 
2ddfcf
-		if (hba_path) {
2ddfcf
-			for (dev = info->next; dev; dev = dev->next) {
2ddfcf
-				if (!devt_attached_to_hba(makedev(dev->disk.major,
2ddfcf
-						dev->disk.minor), hba_path)) {
2ddfcf
-					pr_err("WARNING - IMSM container assembled with disks under different HBAs!\n"
2ddfcf
-						"       This operation is not supported and can lead to data loss.\n");
2ddfcf
-					return 1;
2ddfcf
-				}
2ddfcf
+	if (!hba) {
2ddfcf
+		pr_err("WARNING - Cannot detect HBA for device %s!\n",
2ddfcf
+				devid2kname(makedev(info->disk.major, info->disk.minor)));
2ddfcf
+		return 1;
2ddfcf
+	}
2ddfcf
+
2ddfcf
+	const struct imsm_orom *orom = get_orom_by_device_id(hba->dev_id);
2ddfcf
+	struct mdinfo *dev;
2ddfcf
+
2ddfcf
+	for (dev = info->next; dev; dev = dev->next) {
2ddfcf
+		dev_path = devt_to_devpath(makedev(dev->disk.major, dev->disk.minor));
2ddfcf
+
2ddfcf
+		struct sys_dev *hba2 = NULL;
2ddfcf
+		for (idev = intel_devices; idev; idev = idev->next) {
2ddfcf
+			if (dev_path && strstr(dev_path, idev->path)) {
2ddfcf
+				hba2 = idev;
2ddfcf
+				break;
2ddfcf
 			}
2ddfcf
 		}
2ddfcf
+		if (dev_path)
2ddfcf
+			free(dev_path);
2ddfcf
+
2ddfcf
+		const struct imsm_orom *orom2 = hba2 == NULL ? NULL :
2ddfcf
+				get_orom_by_device_id(hba2->dev_id);
2ddfcf
+
2ddfcf
+		if (hba2 && hba->type != hba2->type) {
2ddfcf
+			pr_err("WARNING - HBAs of devices do not match %s != %s\n",
2ddfcf
+				get_sys_dev_type(hba->type), get_sys_dev_type(hba2->type));
2ddfcf
+			return 1;
2ddfcf
+		}
2ddfcf
+
2ddfcf
+		if (orom != orom2) {
2ddfcf
+			pr_err("WARNING - IMSM container assembled with disks under different HBAs!\n"
2ddfcf
+				"       This operation is not supported and can lead to data loss.\n");
2ddfcf
+			return 1;
2ddfcf
+		}
2ddfcf
+
2ddfcf
+		if (!orom) {
2ddfcf
+			pr_err("WARNING - IMSM container assembled with disks under HBAs without IMSM platform support!\n"
2ddfcf
+				"       This operation is not supported and can lead to data loss.\n");
2ddfcf
+			return 1;
2ddfcf
+		}
2ddfcf
 	}
2ddfcf
+
2ddfcf
 	return 0;
2ddfcf
 }
2ddfcf
 #ifndef MDASSEMBLE
2ddfcf
-- 
2ddfcf
2.4.3
2ddfcf