diff options
author | Dan Williams <dan.j.williams@intel.com> | 2008-12-08 16:59:18 -0700 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2008-12-08 16:59:18 -0700 |
commit | b390f6106143b13eba389ebbee17460f1c2138da (patch) | |
tree | e132d7e88b0c1059e0d7099ef831a0a655a09d72 /platform-intel.c | |
parent | 39795f9cda7ae4cf57e1743d61a909507de9eef8 (diff) | |
download | mdadm-b390f6106143b13eba389ebbee17460f1c2138da.tar.gz |
imsm: detect option-rom capabilities
The option-rom advertises its capabilities in a data structure located in
the platform ROM region 0xc0000-0xf0000. Attempt to detect the option-rom
and limit array creation to the platform's capabilities.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'platform-intel.c')
-rw-r--r-- | platform-intel.c | 178 |
1 files changed, 178 insertions, 0 deletions
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 <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> + +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; +} |