Blame SOURCES/0039-sas-handle-port-expanders-at-all.patch

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