diff --git a/platform-intel.c b/platform-intel.c new file mode 100644 index 0000000..6cd5830 --- /dev/null +++ b/platform-intel.c @@ -0,0 +1,178 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +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[256]; + char link[256]; + char *c; + DIR *driver_dir; + struct dirent *de; + struct sys_dev *head = NULL; + struct sys_dev *list = NULL; + + sprintf(path, "/sys/bus/%s/drivers/%s", bus, driver); + driver_dir = opendir(path); + if (!driver_dir) + return NULL; + for (de = readdir(driver_dir); de; de = readdir(driver_dir)) { + /* 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); + if (readlink(path, link, sizeof(link)) < 0) + continue; + c = strrchr(link, '/'); + if (!c) + continue; + if (strncmp(bus, c+1, strlen(bus)) != 0) + continue; + + /* start / add list entry */ + if (!head) { + head = malloc(sizeof(*head)); + list = head; + } else { + list->next = malloc(sizeof(*head)); + list = list->next; + } + + if (!list) { + free_sys_dev(&head); + break; + } + + /* generate canonical path name for the device */ + sprintf(path, "/sys/bus/%s/drivers/%s/%s", + bus, driver, de->d_name); + list->path = canonicalize_file_name(path); + list->next = NULL; + } + + return head; +} + +__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; +} + +static int platform_has_intel_ahci(void) +{ + struct sys_dev *devices = find_driver_devices("pci", "ahci"); + struct sys_dev *dev; + int ret = 0; + + for (dev = devices; dev; dev = dev->next) + if (devpath_to_vendor(dev->path) == 0x8086) { + ret = 1; + break; + } + + free_sys_dev(&devices); + + return ret; +} + + +static struct imsm_orom imsm_orom; +static int scan(const void *start, const void *end) +{ + int offset; + const struct imsm_orom *imsm_mem; + int len = (end - start); + + for (offset = 0; offset < len; offset += 4) { + imsm_mem = start + offset; + if (memcmp(imsm_mem->signature, "$VER", 4) == 0) { + imsm_orom = *imsm_mem; + return 1; + } + } + + return 0; +} + +const struct imsm_orom *find_imsm_orom(void) +{ + static int populated = 0; + + /* it's static data so we only need to read it once */ + if (populated) + return &imsm_orom; + + if (!platform_has_intel_ahci()) + return NULL; + + /* scan option-rom memory looking for an imsm signature */ + if (probe_roms_init() != 0) + return NULL; + probe_roms(); + populated = scan_adapter_roms(scan); + probe_roms_exit(); + + if (populated) + return &imsm_orom; + return NULL; +} diff --git a/platform-intel.h b/platform-intel.h new file mode 100644 index 0000000..9252002 --- /dev/null +++ b/platform-intel.h @@ -0,0 +1,89 @@ +/* + * 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 + +/* The IMSM OROM Version Table definition */ +struct imsm_orom { + __u8 signature[4]; + __u8 table_ver_major; /* Currently 2 (can change with future revs) */ + __u8 table_ver_minor; /* Currently 2 (can change with future revs) */ + __u16 major_ver; /* Example: 8 as in 8.6.0.1020 */ + __u16 minor_ver; /* Example: 6 as in 8.6.0.1020 */ + __u16 hotfix_ver; /* Example: 0 as in 8.6.0.1020 */ + __u16 build; /* Example: 1020 as in 8.6.0.1020 */ + __u8 len; /* number of bytes in this entire table */ + __u8 checksum; /* checksum of all the bytes in this table */ + __u16 rlc; /* RAID Level Capability */ + /* we assume the cpu is x86 as the orom should not be found + * anywhere else + */ + #define IMSM_OROM_RLC_RAID0 (1 << 0) + #define IMSM_OROM_RLC_RAID1 (1 << 1) + #define IMSM_OROM_RLC_RAID10 (1 << 2) + #define IMSM_OROM_RLC_RAID1E (1 << 3) + #define IMSM_OROM_RLC_RAID5 (1 << 4) + #define IMSM_OROM_RLC_RAID_CNG (1 << 5) + __u16 sss; /* Strip Size Supported */ + #define IMSM_OROM_SSS_2kB (1 << 0) + #define IMSM_OROM_SSS_4kB (1 << 1) + #define IMSM_OROM_SSS_8kB (1 << 2) + #define IMSM_OROM_SSS_16kB (1 << 3) + #define IMSM_OROM_SSS_32kB (1 << 4) + #define IMSM_OROM_SSS_64kB (1 << 5) + #define IMSM_OROM_SSS_128kB (1 << 6) + #define IMSM_OROM_SSS_256kB (1 << 7) + #define IMSM_OROM_SSS_512kB (1 << 8) + #define IMSM_OROM_SSS_1MB (1 << 9) + #define IMSM_OROM_SSS_2MB (1 << 10) + #define IMSM_OROM_SSS_4MB (1 << 11) + #define IMSM_OROM_SSS_8MB (1 << 12) + #define IMSM_OROM_SSS_16MB (1 << 13) + #define IMSM_OROM_SSS_32MB (1 << 14) + #define IMSM_OROM_SSS_64MB (1 << 15) + __u16 dpa; /* Disks Per Array supported */ + __u16 tds; /* Total Disks Supported */ + __u8 vpa; /* # Volumes Per Array supported */ + __u8 vphba; /* # Volumes Per Host Bus Adapter supported */ + /* Attributes supported. This should map to the + * attributes in the MPB. Also, lower 16 bits + * should match/duplicate RLC bits above. + */ + __u32 attr; + #define IMSM_OROM_ATTR_RAID0 IMSM_OROM_RLC_RAID0 + #define IMSM_OROM_ATTR_RAID1 IMSM_OROM_RLC_RAID1 + #define IMSM_OROM_ATTR_RAID10 IMSM_OROM_RLC_RAID10 + #define IMSM_OROM_ATTR_RAID1E IMSM_OROM_RLC_RAID1E + #define IMSM_OROM_ATTR_RAID5 IMSM_OROM_RLC_RAID5 + #define IMSM_OROM_ATTR_RAID_CNG IMSM_OROM_RLC_RAID_CNG + #define IMSM_OROM_ATTR_2TB (1 << 29) + #define IMSM_OROM_ATTR_PM (1 << 30) + #define IMSM_OROM_ATTR_ChecksumVerify (1 << 31) + __u32 reserved1; + __u32 reserved2; +} __attribute__((packed)); + +struct sys_dev { + char *path; + struct sys_dev *next; +}; + +struct sys_dev *find_driver_devices(const char *bus, const char *driver); +__u16 devpath_to_vendor(const char *dev_path); +void free_sys_dev(struct sys_dev **list); +const struct imsm_orom *find_imsm_orom(void);