OSDN Git Service

Use the pci node's driver link to detect ATA in some cases
authorPeter Jones <pjones@redhat.com>
Thu, 7 Jun 2018 20:19:22 +0000 (16:19 -0400)
committerPeter Jones <pmjones@gmail.com>
Fri, 8 Jun 2018 19:11:37 +0000 (15:11 -0400)
src/linux-ata.c
src/linux-pci.c
src/linux-sata.c
src/linux-scsi.c
src/linux.c
src/linux.h

index 114be88..6a47ff3 100644 (file)
 
 #include "efiboot.h"
 
+bool HIDDEN
+is_pata(struct device *dev)
+{
+        if (!strncmp(dev->driver, "pata_", 5) ||
+            !strncmp(dev->driver, "ata_", 4))
+                return true;
+
+        if (dev->n_pci_devs > 0 &&
+            dev->pci_dev[dev->n_pci_devs - 1].driverlink) {
+                char *slash = dev->pci_dev[dev->n_pci_devs - 1].driverlink;
+
+                slash = strrchr(slash, '/');
+                if (slash &&
+                    (!strncmp(slash, "/ata_", 5) ||
+                     !strncmp(slash, "/pata_", 6)))
+                    return true;
+        }
+
+        return false;
+}
+
 /*
  * support for old-school ATA devices
  *
  * 11:0 -> ../../devices/pci0000:00/0000:00:11.5/ata3/host2/target2:0:0/2:0:0:0/block/sr0
  */
 static ssize_t
-parse_ata(struct device *dev, const char *current UNUSED)
+parse_ata(struct device *dev, const char *current)
 {
+        uint32_t scsi_host, scsi_bus, scsi_device, scsi_target;
+        uint64_t scsi_lun;
+        int pos;
+
         debug(DEBUG, "entry");
         /* IDE disks can have up to 64 partitions, or 6 bits worth,
          * and have one bit for the disk number.
@@ -70,14 +95,10 @@ parse_ata(struct device *dev, const char *current UNUSED)
                 dev->interface_type = ata;
                 set_part(dev, dev->minor & 0x3F);
         } else {
-                /*
-                 * If it isn't one of those majors, it isn't a PATA device.
-                 */
-                return 0;
+                debug(DEBUG, "If this is ATA, it isn't using a traditional IDE inode.");
         }
 
-        if (!strncmp(dev->driver, "pata_", 5) ||
-                   !(strcmp(dev->driver, "ata_piix"))) {
+        if (is_pata(dev)) {
                 dev->interface_type = ata;
         } else {
                 /*
@@ -87,12 +108,46 @@ parse_ata(struct device *dev, const char *current UNUSED)
                 return 0;
         }
 
+        char *host = strstr(current, "/host");
+        if (!host)
+                return -1;
+
+        pos = parse_scsi_link(host + 1, &scsi_host,
+                              &scsi_bus, &scsi_device,
+                              &scsi_target, &scsi_lun);
+        if (pos < 0)
+                return -1;
+
+        dev->ata_info.scsi_host = scsi_host;
+        dev->ata_info.scsi_bus = scsi_bus;
+        dev->ata_info.scsi_device = scsi_device;
+        dev->ata_info.scsi_target = scsi_target;
+        dev->ata_info.scsi_lun = scsi_lun;
+
         char *block = strstr(current, "/block/");
         if (!block)
                 return -1;
         return block + 1 - current;
 }
 
+static ssize_t
+dp_create_ata(struct device *dev,
+              uint8_t *buf, ssize_t size, ssize_t off)
+{
+        ssize_t sz;
+
+        debug(DEBUG, "entry");
+
+        sz = efidp_make_atapi(buf + off, size ? size - off : 0,
+                              dev->ata_info.scsi_device,
+                              dev->ata_info.scsi_target - 1,
+                              dev->ata_info.scsi_lun);
+        if (sz < 0)
+                efi_error("efidp_make_atapi() failed");
+
+        return sz;
+}
+
 enum interface_type ata_iftypes[] = { ata, atapi, unknown };
 
 struct dev_probe ata_parser = {
@@ -100,5 +155,5 @@ struct dev_probe ata_parser = {
         .iftypes = ata_iftypes,
         .flags = DEV_PROVIDES_HD,
         .parse = parse_ata,
-        .create = NULL,
+        .create = dp_create_ata,
 };
index 2f6d920..87878c3 100644 (file)
@@ -157,6 +157,21 @@ parse_pci(struct device *dev, const char *current)
                 dev->pci_dev[i].pci_bus = bus;
                 dev->pci_dev[i].pci_device = device;
                 dev->pci_dev[i].pci_function = function;
+                char *tmp = strndup(current, devpart-current+1);
+                char *linkbuf = NULL;
+                if (!tmp) {
+                        efi_error("could not allocate memory");
+                        return -1;
+                }
+                tmp[devpart - current] = '\0';
+                rc = sysfs_readlink(&linkbuf, "class/block/%s/driver", tmp);
+                free(tmp);
+                if (rc < 0) {
+                        efi_error("Could not find driver for pci device");
+                        return -1;
+                }
+                dev->pci_dev[i].driverlink = strdup(linkbuf);
+                debug(DEBUG, "driver:%s\n", linkbuf);
                 dev->n_pci_devs += 1;
         }
 
@@ -172,6 +187,9 @@ dp_create_pci(struct device *dev,
         debug(DEBUG, "entry buf:%p size:%zd off:%zd", buf, size, off);
 
         if (dev->pci_root.pci_root_acpi_uid_str) {
+                debug(DEBUG, "creating acpi_hid_ex dp hid:0x%08x uid:\"%s\"",
+                      dev->pci_root.pci_root_acpi_hid,
+                      dev->pci_root.pci_root_acpi_uid_str);
                 new = efidp_make_acpi_hid_ex(buf + off, size ? size - off : 0,
                                             dev->pci_root.pci_root_acpi_hid,
                                             0, 0, "",
@@ -182,6 +200,9 @@ dp_create_pci(struct device *dev,
                         return new;
                 }
         } else {
+                debug(DEBUG, "creating acpi_hid dp hid:0x%08x uid:0x%0"PRIx64,
+                      dev->pci_root.pci_root_acpi_hid,
+                      dev->pci_root.pci_root_acpi_uid);
                 new = efidp_make_acpi_hid(buf + off, size ? size - off : 0,
                                          dev->pci_root.pci_root_acpi_hid,
                                          dev->pci_root.pci_root_acpi_uid);
@@ -193,7 +214,9 @@ dp_create_pci(struct device *dev,
         off += new;
         sz += new;
 
+        debug(DEBUG, "creating PCI device path nodes");
         for (unsigned int i = 0; i < dev->n_pci_devs; i++) {
+                debug(DEBUG, "creating PCI device path node %u", i);
                 new = efidp_make_pci(buf + off, size ? size - off : 0,
                                     dev->pci_dev[i].pci_device,
                                     dev->pci_dev[i].pci_function);
index bd26536..a670ad9 100644 (file)
@@ -157,6 +157,10 @@ parse_sata(struct device *dev, const char *devlink)
         pos = 0;
 
         debug(DEBUG, "entry");
+        if (is_pata(dev)) {
+                debug(DEBUG, "This is a PATA device; skipping.");
+                return 0;
+        }
 
         /* find the ata info:
          * ata1/host0/target0:0:0/0:0:0:0
index b751a31..87f2f7f 100644 (file)
@@ -42,7 +42,7 @@ parse_scsi_link(const char *current, uint32_t *scsi_host,
 {
         int rc;
         int sz = 0;
-        int pos = 0;
+        int pos0 = 0, pos1 = 0;
         char *spaces;
 
         sz = strlen(current);
@@ -76,78 +76,85 @@ parse_scsi_link(const char *current, uint32_t *scsi_host,
          * So we start when current is:
          * host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc/sdc1
          */
-        uint32_t tosser0, tosser1;
+        uint32_t tosser0, tosser1, tosser2;
 
         /* ignore a bunch of stuff
          *    host4/port-4:0
          * or host4/port-4:0:0
          */
-        debug(DEBUG, "searching for host4/port-4:0 or host4/port-4:0:0");
-        rc = sscanf(current, "host%d/port-%d:%d%n", scsi_host, &tosser0,
-                    &tosser1, &pos);
-        debug(DEBUG, "current:\"%s\" rc:%d pos:%d\n", current+sz, rc, pos);
-        arrow(DEBUG, spaces, 9, pos, rc, 3);
-        if (rc != 3)
-                return -1;
-        sz += pos;
-        pos = 0;
-
-        rc = sscanf(current + sz, ":%d%n", &tosser0, &pos);
-        debug(DEBUG, "current:\"%s\" rc:%d pos:%d\n", current+sz, rc, pos);
-        arrow(DEBUG, spaces, 9, pos, rc, 1);
-        if (rc != 0 && rc != 1)
+        debug(DEBUG, "searching for host4/");
+        rc = sscanf(current, "host%d/%n", scsi_host, &pos0);
+        debug(DEBUG, "current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0);
+        arrow(DEBUG, spaces, 9, pos0, rc, 1);
+        if (rc != 1)
                 return -1;
-        sz += pos;
-        pos = 0;
-
-        /* next:
-         *    /end_device-4:0
-         * or /end_device-4:0:0
-         * 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(DEBUG, "searching for /end_device-4:0 or /end_device-4:0:0");
-        rc = sscanf(current + sz, "/end_device-%d:%d%n", &tosser0, &tosser1, &pos);
-        debug(DEBUG, "current:\"%s\" rc:%d pos:%d\n", current+sz, rc, pos);
-        arrow(DEBUG, spaces, 9, pos, rc, 2);
-        if (rc != 2)
+        sz += pos0;
+        pos0 = 0;
+
+        debug(DEBUG, "searching for port-4:0 or port-4:0:0");
+        rc = sscanf(current, "port-%d:%d%n:%d%n", &tosser0,
+                    &tosser1, &pos0, &tosser2, &pos1);
+        debug(DEBUG, "current:\"%s\" rc:%d pos0:%d pos1:%d\n", current+sz, rc, pos0, pos1);
+        arrow(DEBUG, spaces, 9, pos0, rc, 2);
+        arrow(DEBUG, spaces, 9, pos1, rc, 3);
+        if (rc == 2 || rc == 3) {
+                sz += pos0;
+                pos0 = 0;
+
+                /* next:
+                 *    /end_device-4:0
+                 * or /end_device-4:0:0
+                 * 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(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(DEBUG, "current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0);
+                arrow(DEBUG, spaces, 9, pos0, rc, 2);
+                if (rc != 2)
+                        return -1;
+                sz += pos0;
+                pos0 = 0;
+
+                rc = sscanf(current + sz, ":%d%n", &tosser0, &pos0);
+                debug(DEBUG, "current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0);
+                arrow(DEBUG, spaces, 9, pos0, rc, 2);
+                if (rc != 0 && rc != 1)
+                        return -1;
+                sz += pos0;
+                pos0 = 0;
+
+                if (current[sz] == '/')
+                        sz += 1;
+        } else if (rc != 0) {
                 return -1;
-        sz += pos;
-        pos = 0;
-
-        rc = sscanf(current + sz, ":%d%n", &tosser0, &pos);
-        debug(DEBUG, "current:\"%s\" rc:%d pos:%d\n", current+sz, rc, pos);
-        arrow(DEBUG, spaces, 9, pos, rc, 2);
-        if (rc != 0 && rc != 1)
-                return -1;
-        sz += pos;
-        pos = 0;
+        }
 
         /* now:
          * /target4:0:0/
          */
         uint64_t tosser3;
-        debug(DEBUG, "searching for /target4:0:0/");
-        rc = sscanf(current + sz, "/target%d:%d:%"PRIu64"/%n", &tosser0, &tosser1,
-                    &tosser3, &pos);
-        debug(DEBUG, "current:\"%s\" rc:%d pos:%d\n", current+sz, rc, pos);
-        arrow(DEBUG, spaces, 9, pos, rc, 3);
+        debug(DEBUG, "searching for target4:0:0/");
+        rc = sscanf(current + sz, "target%d:%d:%"PRIu64"/%n", &tosser0, &tosser1,
+                    &tosser3, &pos0);
+        debug(DEBUG, "current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0);
+        arrow(DEBUG, spaces, 9, pos0, rc, 3);
         if (rc != 3)
                 return -1;
-        sz += pos;
-        pos = 0;
+        sz += pos0;
+        pos0 = 0;
 
         /* now:
          * %d:%d:%d:%llu/
          */
         debug(DEBUG, "searching for 4:0:0:0/");
         rc = sscanf(current + sz, "%d:%d:%d:%"PRIu64"/%n",
-                    scsi_bus, scsi_device, scsi_target, scsi_lun, &pos);
-        debug(DEBUG, "current:\"%s\" rc:%d pos:%d\n", current+sz, rc, pos);
-        arrow(DEBUG, spaces, 9, pos, rc, 4);
+                    scsi_bus, scsi_device, scsi_target, scsi_lun, &pos0);
+        debug(DEBUG, "current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0);
+        arrow(DEBUG, spaces, 9, pos0, rc, 4);
         if (rc != 4)
                 return -1;
-        sz += pos;
+        sz += pos0;
 
         return sz;
 }
index 7d5fe16..88930d0 100644 (file)
@@ -280,6 +280,10 @@ device_free(struct device *dev)
                         free(dev->part_name);
         }
 
+        for (unsigned int i = 0; i < dev->n_pci_devs; i++)
+                if (dev->pci_dev[i].driverlink)
+                        free(dev->pci_dev[i].driverlink);
+
         if (dev->pci_dev)
                 free(dev->pci_dev);
 
index 99ac438..71f766f 100644 (file)
@@ -34,6 +34,7 @@ struct pci_dev_info {
         uint8_t pci_bus;
         uint8_t pci_device;
         uint8_t pci_function;
+        char *driverlink;
 };
 
 struct scsi_info {
@@ -65,6 +66,15 @@ struct sata_info {
         uint32_t ata_print_id;
 };
 
+struct ata_info {
+        uint32_t scsi_bus;
+        uint32_t scsi_device;
+        uint32_t scsi_target;
+        uint64_t scsi_lun;
+
+        uint32_t scsi_host;
+};
+
 struct nvme_info {
         int32_t ctrl_id;
         int32_t ns_id;
@@ -114,6 +124,7 @@ struct device {
                                 struct scsi_info scsi_info;
                                 struct sas_info sas_info;
                                 struct sata_info sata_info;
+                                struct ata_info ata_info;
                                 struct nvme_info nvme_info;
                                 efi_guid_t nvdimm_label;
                         };
@@ -128,7 +139,7 @@ extern int HIDDEN set_disk_and_part_name(struct device *dev);
 extern int HIDDEN set_part(struct device *dev, int value);
 extern int HIDDEN set_part_name(struct device *dev, const char * const fmt, ...);
 extern int HIDDEN set_disk_name(struct device *dev, const char * const fmt, ...);
-
+extern bool HIDDEN is_pata(struct device *dev);
 extern int HIDDEN make_blockdev_path(uint8_t *buf, ssize_t size,
                                      struct device *dev);