X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=platform-intel.c;h=cb6c7dc81b86f12bfee56a9348fac55651f24e0c;hb=refs%2Fheads%2Fmdadm-3.2.x;hp=f5f57b796786aff7313bb7487f4ae044f60c6da4;hpb=1a90147116b680f9d5b93c82c4b96f28a7bf5645;p=thirdparty%2Fmdadm.git diff --git a/platform-intel.c b/platform-intel.c index f5f57b79..cb6c7dc8 100644 --- a/platform-intel.c +++ b/platform-intel.c @@ -31,6 +31,9 @@ #include +static int devpath_to_ll(const char *dev_path, const char *entry, + unsigned long long *val); + static __u16 devpath_to_vendor(const char *dev_path); void free_sys_dev(struct sys_dev **list) @@ -56,6 +59,7 @@ struct sys_dev *find_driver_devices(const char *bus, const char *driver) struct sys_dev *head = NULL; struct sys_dev *list = NULL; enum sys_dev_type type; + unsigned long long dev_id; if (strcmp(driver, "isci") == 0) type = SYS_DEV_SAS; @@ -93,6 +97,9 @@ struct sys_dev *find_driver_devices(const char *bus, const char *driver) if (devpath_to_vendor(path) != 0x8086) continue; + if (devpath_to_ll(path, "device", &dev_id) != 0) + continue; + /* start / add list entry */ if (!head) { head = malloc(sizeof(*head)); @@ -107,6 +114,7 @@ struct sys_dev *find_driver_devices(const char *bus, const char *driver) break; } + list->dev_id = (__u16) dev_id; list->type = type; list->path = canonicalize_file_name(path); list->next = NULL; @@ -118,6 +126,35 @@ struct sys_dev *find_driver_devices(const char *bus, const char *driver) } +static struct sys_dev *intel_devices=NULL; + +static enum sys_dev_type device_type_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->type; + return SYS_DEV_UNKNOWN; +} + +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; +} + + static __u16 devpath_to_vendor(const char *dev_path) { char path[strlen(dev_path) + strlen("/vendor") + 1]; @@ -160,17 +197,6 @@ struct sys_dev *find_intel_devices(void) return ahci; } -static int platform_has_intel_devices(void) -{ - struct sys_dev *devices; - devices = find_intel_devices(); - if (devices) { - free_sys_dev(&devices); - return 1; - } - return 0; -} - /* * PCI Expansion ROM Data Structure Format */ struct pciExpDataStructFormat { @@ -190,22 +216,27 @@ static int scan(const void *start, const void *end, const void *data) 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)); - if ((__le16_to_cpu(ptr->vendorID) == 0x8086) && - (__le16_to_cpu(ptr->deviceID) == 0x2822)) - dev = SYS_DEV_SATA; - else if ((__le16_to_cpu(ptr->vendorID) == 0x8086) && - (__le16_to_cpu(ptr->deviceID) == 0x1D60)) - dev = SYS_DEV_SAS; + if (__le16_to_cpu(ptr->vendorID) == 0x8086) { + /* serach attached intel devices by device id from OROM */ + dev = device_type_by_id(__le16_to_cpu(ptr->deviceID)); + if (dev == SYS_DEV_UNKNOWN) + return 0; + } else return 0; for (offset = 0; offset < len; offset += 4) { imsm_mem = start + offset; - if (memcmp(imsm_mem->signature, "$VER", 4) == 0) { + if ((memcmp(imsm_mem->signature, "$VER", 4) == 0)) { imsm_orom[dev] = *imsm_mem; populated_orom[dev] = 1; return populated_orom[SYS_DEV_SATA] && populated_orom[SYS_DEV_SAS]; @@ -274,7 +305,13 @@ static const struct imsm_orom *find_imsm_hba_orom(enum sys_dev_type hba_id) check_env("IMSM_TEST_SCU_EFI")) return NULL; - if (!platform_has_intel_devices()) + + if (intel_devices != NULL) + free_sys_dev(&intel_devices); + + intel_devices = find_intel_devices(); + + if (intel_devices == NULL) return NULL; /* scan option-rom memory looking for an imsm signature */ @@ -285,10 +322,14 @@ static const struct imsm_orom *find_imsm_hba_orom(enum sys_dev_type hba_id) if (probe_roms_init(align) != 0) return NULL; probe_roms(); - /* ignore result - True is returned if both are found */ + /* ignore return value - True is returned if both adapater roms are found */ scan_adapter_roms(scan); probe_roms_exit(); + if (intel_devices != NULL) + free_sys_dev(&intel_devices); + intel_devices = NULL; + if (populated_orom[hba_id]) return &imsm_orom[hba_id]; return NULL; @@ -304,6 +345,95 @@ static const struct imsm_orom *find_imsm_hba_orom(enum sys_dev_type hba_id) (c) & 0xff, ((c) >> 8) & 0xff, \ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) + +#define SYS_EFI_VAR_PATH "/sys/firmware/efi/vars" +#define SCU_PROP "RstScuV" +#define AHCI_PROP "RstSataV" + +#define VENDOR_GUID \ + EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, 0x1a, 0x04, 0xc6) + +int populated_efi[SYS_DEV_MAX] = { 0, 0 }; + +static struct imsm_orom imsm_efi[SYS_DEV_MAX]; + +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; + + 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; +} + +const struct imsm_orom *find_imsm_efi(enum sys_dev_type hba_id) +{ + if (hba_id >= SYS_DEV_MAX) + return NULL; + + dprintf("EFI CAP: %p, pid: %d pop: %d\n", + &imsm_efi[hba_id], (int) getpid(), populated_efi[hba_id]); + + /* it's static data so we only need to read it once */ + if (populated_efi[hba_id]) { + dprintf("EFI CAP: %p, pid: %d pop: %d\n", + &imsm_efi[hba_id], (int) getpid(), populated_efi[hba_id]); + return &imsm_efi[hba_id]; + } + if (check_env("IMSM_TEST_AHCI_EFI") || + check_env("IMSM_TEST_SCU_EFI")) { + dprintf("OROM CAP: %p, pid: %d pop: %d\n", + &imsm_efi[hba_id], (int) getpid(), populated_efi[hba_id]); + return imsm_platform_test(hba_id, &populated_efi[hba_id], &imsm_efi[hba_id]); + } + /* OROM test is set, return that there is no EFI capabilities */ + if (check_env("IMSM_TEST_OROM")) + return NULL; + + if (read_efi_variable(&imsm_efi[hba_id], sizeof(imsm_efi[0]), hba_id == SYS_DEV_SAS ? SCU_PROP : AHCI_PROP, VENDOR_GUID)) { + populated_efi[hba_id] = 0; + return NULL; + } + + populated_efi[hba_id] = 1; + return &imsm_efi[hba_id]; +} + /* * backward interface compatibility */ @@ -316,6 +446,9 @@ const struct imsm_orom *find_imsm_capability(enum sys_dev_type hba_id) { const struct imsm_orom *cap=NULL; + + if ((cap = find_imsm_efi(hba_id)) != NULL) + return cap; if ((cap = find_imsm_hba_orom(hba_id)) != NULL) return cap; return NULL;