From: Peter Jones Date: Mon, 1 Oct 2018 18:35:01 +0000 (-0400) Subject: sas: handle port expanders at all. X-Git-Tag: android-x86-8.1-r1~8 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=3e687d8072f3ed53ae727ec2cb99ae56dbcdf02b;p=android-x86%2Fexternal-efivar.git sas: handle port expanders at all. Signed-off-by: Peter Jones --- diff --git a/src/linux-ata.c b/src/linux-ata.c index 32cb993..43e5f4c 100644 --- a/src/linux-ata.c +++ b/src/linux-ata.c @@ -114,7 +114,8 @@ parse_ata(struct device *dev, const char *current, const char *root UNUSED) pos = parse_scsi_link(host + 1, &scsi_host, &scsi_bus, &scsi_device, - &scsi_target, &scsi_lun); + &scsi_target, &scsi_lun, + NULL, NULL, NULL); if (pos < 0) return -1; diff --git a/src/linux-sas.c b/src/linux-sas.c index 4d77d39..bb04fe8 100644 --- a/src/linux-sas.c +++ b/src/linux-sas.c @@ -28,6 +28,91 @@ #include "efiboot.h" +static int +get_port_expander_sas_address(uint64_t *sas_address, uint32_t scsi_host, + uint32_t local_port_id, + uint32_t remote_port_id, uint32_t remote_scsi_target) +{ + uint8_t *filebuf = NULL; + int rc; + + /* + * We find sas_address via this insanity: + * /sys/class/scsi_host/host2 -> ../../devices/pci0000:74/0000:74:02.0/host2/scsi_host/host2 + * /sys/devices/pci0000:74/0000:74:02.0/host2/scsi_host/host2/device -> ../../../host2 + * /sys/devices/pci0000:74/0000:74:02.0/host2/device -> ../../../host2 + * /sys/devices/host2/port-2:0/expander-2:0/sas_device/expander-2:0/sas_address + * + * But since host2 is always host2, we can skip most of that and just + * go for: + * /sys/devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/port-2:0:2/end_device-2:0:2/sas_device/end_device-2:0:2/sas_address + */ + +#if 0 /* previously thought this was right, but it's the expander's address, not the target's address */ + /* + * /sys/class/scsi_host/host2/device/port-2:0/expander-2:0/sas_device/expander-2:0/sas_address + * ... I think. I would have expected that to be port-2:0:0 and I + * don't understand why it isn't. (I do now; this is the expander not + * the port.) + */ + + debug("looking for /sys/class/scsi_host/host%d/device/port-%d:%d/expander-%d:%d/sas_device/expander-%d:%d/sas_address", + scsi_host, scsi_host, port_id, scsi_host, remote_scsi_target, scsi_host, remote_scsi_target); + rc = read_sysfs_file(&filebuf, + "class/scsi_host/host%d/device/port-%d:%d/expander-%d:%d/sas_device/expander-%d:%d/sas_address", + scsi_host, scsi_host, port_id, scsi_host, remote_scsi_target, scsi_host, remote_scsi_target); + if (rc < 0 || filebuf == NULL) { + debug("didn't find it."); + return -1; + } +#else + debug("looking for /sys/class/scsi_host/host%d/device/port-%d:%d/expander-%d:%d/port-%d:%d:%d/end_device-%d:%d:%d/sas_device/end_device-%d:%d:%d/sas_address", + scsi_host, + scsi_host, local_port_id, + scsi_host, remote_scsi_target, + scsi_host, remote_scsi_target, remote_port_id, + scsi_host, remote_scsi_target, remote_port_id, + scsi_host, remote_scsi_target, remote_port_id); + rc = read_sysfs_file(&filebuf, + "class/scsi_host/host%d/device/port-%d:%d/expander-%d:%d/port-%d:%d:%d/end_device-%d:%d:%d/sas_device/end_device-%d:%d:%d/sas_address", + scsi_host, + scsi_host, local_port_id, + scsi_host, remote_scsi_target, + scsi_host, remote_scsi_target, remote_port_id, + scsi_host, remote_scsi_target, remote_port_id, + scsi_host, remote_scsi_target, remote_port_id); + if (rc < 0 || filebuf == NULL) { + debug("didn't find it."); + return -1; + } +#endif + + rc = sscanf((char *)filebuf, "%"PRIx64, sas_address); + if (rc != 1) + return -1; + + return 0; +} + +static int +get_local_sas_address(uint64_t *sas_address, struct device *dev) +{ + int rc; + char *filebuf = NULL; + + rc = read_sysfs_file(&filebuf, + "class/block/%s/device/sas_address", + dev->disk_name); + if (rc < 0 || filebuf == NULL) + return -1; + + rc = sscanf((char *)filebuf, "%"PRIx64, sas_address); + if (rc != 1) + return -1; + + return 0; +} + /* * support for SAS devices * @@ -43,6 +128,24 @@ * /sys/class/block/sdc/device/sas_address * * I'm not sure at the moment if they're the same or not. + * + * There are also other devices that look like: + * + * 8:0 -> ../../devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/port-2:0:2/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda + * 8:1 -> ../../devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/port-2:0:2/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda/sda1 + * + * /sys/dev/block/8:0/device -> ../../../2:0:0:0 + * + * This exists: + * + * /sys/class/scsi_host/host2 -> ../../devices/pci0000:74/0000:74:02.0/host2/scsi_host/host2 + * /sys/devices/pci0000:74/0000:74:02.0/host2/scsi_host/host2/device -> ../../../host2 + * /sys/devices/pci0000:74/0000:74:02.0/host2/device -> ../../../host2 + * /sys/devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/sas_device/expander-2:0/sas_address + * + * but the device doesn't actually have a sas_host_address, because it's on a + * port expander, and sas_address doesn't directly exist under /sys/class/ + * anywhere. */ static ssize_t parse_sas(struct device *dev, const char *current, const char *root UNUSED) @@ -50,16 +153,19 @@ parse_sas(struct device *dev, const char *current, const char *root UNUSED) struct stat statbuf = { 0, }; int rc; uint32_t scsi_host, scsi_bus, scsi_device, scsi_target; + uint32_t local_port_id = 0, remote_port_id = 0; + uint32_t remote_scsi_target = 0; uint64_t scsi_lun; ssize_t pos; - uint8_t *filebuf = NULL; - uint64_t sas_address; + uint64_t sas_address = 0; debug("entry"); pos = parse_scsi_link(current, &scsi_host, &scsi_bus, &scsi_device, - &scsi_target, &scsi_lun); + &scsi_target, &scsi_lun, + &local_port_id, &remote_port_id, + &remote_scsi_target); /* * If we can't parse the scsi data, it isn't a sas device, so return 0 * not error. @@ -71,6 +177,7 @@ parse_sas(struct device *dev, const char *current, const char *root UNUSED) * Make sure it has the actual /SAS/ bits before we continue * validating all this junk. */ + debug("looking for /sys/class/scsi_host/host%d/host_sas_address", scsi_host); rc = sysfs_stat(&statbuf, "class/scsi_host/host%d/host_sas_address", scsi_host); @@ -79,21 +186,48 @@ parse_sas(struct device *dev, const char *current, const char *root UNUSED) * 0 not error. Later errors mean it is an ata device, but we can't * parse it right, so they return -1. */ - if (rc < 0) - return 0; - - /* - * we also need to get the actual sas_address from someplace... - */ - rc = read_sysfs_file(&filebuf, - "class/block/%s/device/sas_address", - dev->disk_name); - if (rc < 0 || filebuf == NULL) - return -1; + if (rc < 0) { + debug("didn't find it."); + /* + * If it's on a port expander, it won't have the + * host_sas_address, so we need to check if it's a sas_host + * instead. + * It may work to just check this to begin with, but I don't + * have such a device in front of me right now. + */ + debug("looking for /sys/class/sas_host/host%d", scsi_host); + rc = sysfs_stat(&statbuf, + "class/sas_host/host%d", scsi_host); + if (rc < 0) { + debug("didn't find it."); + return 0; + } + debug("found it."); - rc = sscanf((char *)filebuf, "%"PRIx64, &sas_address); - if (rc != 1) - return -1; + /* + * So it *is* a sas_host, and we have to fish the sas_address + * from the remote port + */ + rc = get_port_expander_sas_address(&sas_address, scsi_host, + local_port_id, + remote_port_id, + remote_scsi_target); + if (rc < 0) { + debug("Couldn't find port expander sas address"); + return 0; + } + } else { + /* + * we also need to get the actual sas_address from someplace... + */ + debug("found it."); + rc = get_local_sas_address(&sas_address, dev); + if (rc < 0) { + debug("Couldn't find sas address"); + return 0; + } + } + debug("sas address is 0x%"PRIx64, sas_address); dev->sas_info.sas_address = sas_address; diff --git a/src/linux-scsi.c b/src/linux-scsi.c index 2e4f710..a5e81cf 100644 --- a/src/linux-scsi.c +++ b/src/linux-scsi.c @@ -38,7 +38,9 @@ ssize_t HIDDEN parse_scsi_link(const char *current, uint32_t *scsi_host, uint32_t *scsi_bus, uint32_t *scsi_device, - uint32_t *scsi_target, uint64_t *scsi_lun) + uint32_t *scsi_target, uint64_t *scsi_lun, + uint32_t *local_port_id, uint32_t *remote_port_id, + uint32_t *remote_target_id) { int rc; int sz = 0; @@ -70,11 +72,32 @@ parse_scsi_link(const char *current, uint32_t *scsi_host, * /sys/block/sdc/device looks like: * device-> ../../../4:2:0:0 * + * OR + * + * 8:0 -> ../../devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/port-2:0:2/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda + * 8:1 -> ../../devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/port-2:0:2/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda/sda1 + * + * /sys/block/sda/device looks like: + * device -> ../../../2:0:0:0 * + * + * sas_address exists, but it's hard to find: + * /sys/devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/sas_device/expander-2:0/sas_address + * but sas_host_address is nowhere to be found, and sas_address + * doesn't directly exist under /sys/class/ anywhere. So you actually + * have to go to + * /sys/devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/sas_device/expander-2:0/sas_address + * and chop that off to + * /sys/devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/ + * and then add a bunch of port and end device crap to it to get: + * /sys/devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/port-2:0:2/end_device-2:0:2/sas_device/end_device-2:0:2/sas_address + */ /* * So we start when current is: * host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc/sdc1 + * or + * host2/port-2:0/expander-2:0/port-2:0:2/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda/sda1 */ uint32_t tosser0, tosser1, tosser2; @@ -91,6 +114,14 @@ parse_scsi_link(const char *current, uint32_t *scsi_host, sz += pos0; pos0 = 0; + /* + * We might have this next: + * port-2:0/expander-2:0/port-2:0:2/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda/sda1 + * or: + * port-2:0/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda/sda1 + * or maybe (not sure): + * port-2:0:2/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda/sda1 + */ debug("searching for port-4:0 or port-4:0:0"); rc = sscanf(current+sz, "port-%d:%d%n:%d%n", &tosser0, &tosser1, &pos0, &tosser2, &pos1); @@ -100,6 +131,52 @@ parse_scsi_link(const char *current, uint32_t *scsi_host, if (rc == 2 || rc == 3) { sz += pos0; pos0 = 0; + if (local_port_id && rc == 2) + *local_port_id = tosser1; + if (remote_port_id && rc == 3) + *remote_port_id = tosser2; + + if (current[sz] == '/') + sz += 1; + + /* + * We might have this next: + * expander-2:0/port-2:0:2/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda/sda1 + * ^ port id + * ^ scsi target id + * ^ host number + * ^ host number + * We don't actually care about either number in expander-.../, + * because they're replicated in all the other places. We just need + * to get past it. + */ + debug("searching for expander-4:0/"); + rc = sscanf(current+sz, "expander-%d:%d/%n", &tosser0, &tosser1, &pos0); + debug("current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0); + arrow(LOG_DEBUG, spaces, 9, pos0, rc, 2); + if (rc == 2) { + if (!remote_target_id) { + efi_error("Device is PHY is a remote target, but remote_target_id is NULL"); + return -1; + } + *remote_target_id = tosser1; + sz += pos0; + pos0 = 0; + + /* + * if we have that, we should have a 3-part port next + */ + debug("searching for port-2:0:2/"); + rc = sscanf(current+sz, "port-%d:%d:%d/%n", &tosser0, &tosser1, &tosser2, &pos0); + debug("current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0); + arrow(LOG_DEBUG, spaces, 9, pos0, rc, 3); + if (rc != 3) { + efi_error("Couldn't parse port expander port string"); + return -1; + } + sz += pos0; + } + pos0 = 0; /* next: * /end_device-4:0 @@ -107,22 +184,24 @@ parse_scsi_link(const char *current, uint32_t *scsi_host, * awesomely these are the exact same fields that go into port-blah, * but we don't care for now about any of them anyway. */ - debug("searching for /end_device-4:0/ or /end_device-4:0:0/"); - rc = sscanf(current + sz, "/end_device-%d:%d%n", &tosser0, &tosser1, &pos0); + debug("searching for end_device-4:0/ or end_device-4:0:0/"); + rc = sscanf(current + sz, "end_device-%d:%d%n", &tosser0, &tosser1, &pos0); debug("current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0); - arrow(LOG_DEBUG, spaces, 9, pos0, rc, 2); if (rc != 2) return -1; - sz += pos0; - pos0 = 0; - rc = sscanf(current + sz, ":%d%n", &tosser0, &pos0); - debug("current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0); - arrow(LOG_DEBUG, spaces, 9, pos0, rc, 2); + pos1 = 0; + rc = sscanf(current + sz + pos0, ":%d%n", &tosser2, &pos1); + arrow(LOG_DEBUG, spaces, 9, pos0, rc + 2, 2); + arrow(LOG_DEBUG, spaces, 9, pos0 + pos1, rc + 2, 3); if (rc != 0 && rc != 1) return -1; - sz += pos0; - pos0 = 0; + if (remote_port_id && rc == 1) + *remote_port_id = tosser2; + if (local_port_id && rc == 0) + *local_port_id = tosser1; + sz += pos0 + pos1; + pos0 = pos1 = 0; if (current[sz] == '/') sz += 1; @@ -156,6 +235,7 @@ parse_scsi_link(const char *current, uint32_t *scsi_host, return -1; sz += pos0; + debug("returning %d", sz); return sz; } @@ -191,7 +271,8 @@ parse_scsi(struct device *dev, const char *current, const char *root UNUSED) sz = parse_scsi_link(current, &scsi_host, &scsi_bus, &scsi_device, - &scsi_target, &scsi_lun); + &scsi_target, &scsi_lun, + NULL, NULL, NULL); if (sz < 0) return 0; diff --git a/src/linux.h b/src/linux.h index 7c7ea91..43a9b78 100644 --- a/src/linux.h +++ b/src/linux.h @@ -267,8 +267,10 @@ struct dev_probe { }; extern ssize_t parse_scsi_link(const char *current, uint32_t *host, - uint32_t *bus, uint32_t *device, - uint32_t *target, uint64_t *lun); + uint32_t *bus, uint32_t *device, + uint32_t *target, uint64_t *lun, + uint32_t *local_port_id, uint32_t *remote_port_id, + uint32_t *remote_target_id); /* device support implementations */ extern struct dev_probe pmem_parser;