OSDN Git Service

Add NVDIMM-P support
authorPeter Jones <pjones@redhat.com>
Mon, 4 Dec 2017 22:27:57 +0000 (17:27 -0500)
committerPeter Jones <pjones@redhat.com>
Mon, 4 Dec 2017 22:27:57 +0000 (17:27 -0500)
src/creator.c
src/dp-message.c
src/include/efivar/efivar-dp.h
src/libefivar.map.in
src/linux.c
src/linux.h

index 6747eee..c8739f4 100644 (file)
@@ -239,6 +239,9 @@ efi_va_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size,
                off += sz;
        }
 
+       if (info.interface_type == nd_pmem)
+               options |= EFIBOOT_ABBREV_FILE;
+
        if (!(options & EFIBOOT_ABBREV_FILE)) {
                int disk_fd;
                int saved_errno;
@@ -362,7 +365,12 @@ efi_generate_file_device_path(uint8_t *buf, ssize_t size,
 
        va_start(ap, options);
 
-       ret = efi_va_generate_file_device_path_from_esp(buf, size,
+       if (!strcmp(parent_devpath, "/dev/block"))
+               ret = efi_va_generate_file_device_path_from_esp(buf, size,
+                                                       child_devpath, rc,
+                                                       relpath, options, ap);
+       else
+               ret = efi_va_generate_file_device_path_from_esp(buf, size,
                                                        parent_devpath, rc,
                                                        relpath, options, ap);
        saved_errno = errno;
index 235bc7f..eada00f 100644 (file)
@@ -622,6 +622,11 @@ _format_message_dn(char *buf, size_t size, const_efidp dp)
                format(buf, size, off, "Dns", ")");
                break;
        }
+       case EFIDP_MSG_NVDIMM:
+               format(buf, size, off, "NVDIMM", "NVDIMM(");
+               format_guid(buf, size, off, "NVDIMM", &dp->nvdimm.uuid);
+               format(buf, size, off, "NVDIMM", ")");
+               break;
        default:
                format(buf, size, off, "Msg", "Msg(%d,", dp->subtype);
                format_hex(buf, size, off, "Msg", (uint8_t *)dp+4,
@@ -802,3 +807,23 @@ efidp_make_sas(uint8_t *buf, ssize_t size, uint64_t sas_address)
 
        return sz;
 }
+
+ssize_t
+__attribute__((__visibility__ ("default")))
+efidp_make_nvdimm(uint8_t *buf, ssize_t size, efi_guid_t *uuid)
+{
+       efidp_nvdimm *nvdimm = (efidp_nvdimm *)buf;
+       ssize_t req = sizeof (*nvdimm);
+       ssize_t sz;
+
+       sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE,
+                               EFIDP_MSG_NVDIMM, sizeof (*nvdimm));
+       if (size && sz == req) {
+               memcpy(&nvdimm->uuid, uuid, sizeof(*uuid));
+       }
+
+       if (sz < 0)
+               efi_error("efidp_make_generic failed");
+
+       return sz;
+}
index eb644fa..9bbb5de 100644 (file)
@@ -705,6 +705,13 @@ typedef struct {
        efi_ip_addr_t   addrs[];
 } EFIVAR_PACKED efidp_dns;
 
+#define EFIDP_MSG_NVDIMM       0x20
+typedef struct {
+       efidp_header    header;
+       efi_guid_t      uuid;
+} EFIVAR_PACKED efidp_nvdimm;
+extern ssize_t efidp_make_nvdimm(uint8_t *buf, ssize_t size, efi_guid_t *uuid);
+
 /* Each media subtype */
 #define EFIDP_MEDIA_HD         0x1
 typedef struct {
@@ -869,6 +876,7 @@ typedef union {
        efidp_emmc emmc;
        efidp_btle btle;
        efidp_dns dns;
+       efidp_nvdimm nvdimm;
        efidp_hd hd;
        efidp_cdrom cdrom;
        efidp_media_vendor media_vendor;
index a95a505..6677266 100644 (file)
@@ -114,3 +114,7 @@ LIBEFIVAR_1.30 {
 LIBEFIVAR_1.32 {
        global: efi_guid_ux_capsule;
 } LIBEFIVAR_1.30;
+
+LIBEFIVAR_1.33 {
+       global: efidp_make_nvdimm;
+} LIBEFIVAR_1.32;
index 143f2c1..1b24006 100644 (file)
@@ -77,7 +77,13 @@ set_disk_and_part_name(struct disk_info *info)
         * If there's a better way to figure this out, it'd be good, because
         * I don't want to have to change this for every new disk type...
         */
-       if (!strcmp(penultimate, "block")) {
+       if (!strncmp(ultimate, "pmem", 4)) {
+               if (!info->disk_name) {
+                       info->disk_name = strdup(ultimate);
+                       if (!info->disk_name)
+                               return -1;
+               }
+       } else if (!strcmp(penultimate, "block")) {
                if (!info->disk_name) {
                        info->disk_name = strdup(ultimate);
                        if (!info->disk_name)
@@ -204,6 +210,27 @@ find_parent_devpath(const char * const child, char **parent)
        return 0;
 }
 
+/* NVDIMM-P paths */
+static int
+sysfs_test_pmem(const char *buf)
+{
+       char *driverbuf = NULL;
+       int rc;
+
+       rc = sysfs_readlink(&driverbuf,
+                           "/sys/dev/block/%s/device/driver", buf);
+       if (rc < 0 || !driverbuf)
+               return 0;
+
+       char *driver = strrchr(driverbuf, '/');
+       if (!driver || !*driver)
+               return -1;
+       driver+=1;
+       if (!strcmp(driver, "nd_pmem"))
+               return 1;
+       return 0;
+}
+
 static int
 sysfs_test_nvme(const char *buf, ssize_t size)
 {
@@ -328,6 +355,46 @@ sysfs_sata_get_port_info(uint32_t print_id, struct disk_info *info)
        return 0;
 }
 
+/* pmem12s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
+ * dev: 259:0
+ * device -> ../../../btt12.1
+ * device/uuid: 0cee166e-dd56-4bc2-99d2-2544b69025b8
+ * 259:0 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
+ *
+ * pmem12.1s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.2/block/pmem12.1s
+ * dev: 259:1
+ * device -> ../../../btt12.2
+ * device/uuid: 78d94521-91f7-47db-b3a7-51b764281940
+ * 259:1 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.2/block/pmem12.1s
+ *
+ * pmem12.2 -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/pfn12.1/block/pmem12.2
+ * dev: 259:2
+ * device -> ../../../pfn12.1
+ * device/uuid: 829c5205-89a5-4581-9819-df7d7754c622
+ * 259:2 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/pfn12.1/block/pmem12.2
+ */
+static ssize_t
+sysfs_parse_pmem(uint8_t *buf,  ssize_t size, ssize_t *off,
+                const char *pbuf, ssize_t psize __attribute__((__unused__)),
+                ssize_t *poff __attribute__((__unused__)),
+                struct disk_info *info)
+{
+       uint8_t *filebuf = NULL;
+       int rc;
+
+       rc = read_sysfs_file(&filebuf,
+                            "/sys/class/block/%s/device/uuid", pbuf);
+       if ((rc < 0 && errno == ENOENT) || filebuf == NULL)
+               return -1;
+
+       rc = efi_str_to_guid((char *)filebuf, &info->nvdimm_label);
+       if (rc < 0)
+               return -1;
+
+       *off = efidp_make_nvdimm(buf, size, &info->nvdimm_label);
+       return *off;
+}
+
 static ssize_t
 sysfs_parse_nvme(uint8_t *buf, ssize_t size, ssize_t *off,
                const char *pbuf, ssize_t psize, ssize_t *poff,
@@ -764,44 +831,72 @@ make_blockdev_path(uint8_t *buf, ssize_t size, struct disk_info *info)
        }
 
        /*
-        * the sysfs path basically looks like:
+        * the sysfs path basically looks like one of:
         * ../../devices/pci$PCI_STUFF/$BLOCKDEV_STUFF/block/$DISK/$PART
+        * ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
         */
-       rc = sscanf(linkbuf+loff, "../../devices/%n", &lsz);
-       if (rc != 0)
+       rc = sysfs_test_pmem(linkbuf+loff);
+       if (rc < 0) {
+               efi_error("sysfs_test_pmem(\"%s\") failed", linkbuf+loff);
                return -1;
-       loff += lsz;
+       }
+       else if (rc > 0) {
+               ssize_t linksz=0;
+               info->interface_type = nd_pmem;
+               rc = sysfs_parse_pmem(buf+off, size?size-off:0, &sz,
+                                     linkbuf+loff, PATH_MAX-off,
+                                     &linksz, info);
+               if (rc < 0)
+                       return -1;
+               loff += linksz;
+               off += sz;
+               found = 1;
+       }
 
-       ssize_t tmplsz=0;
-       sz = make_pci_path(buf, size, linkbuf+loff, &tmplsz);
-       if (sz < 0)
-               return -1;
-       loff += tmplsz;
-       off += sz;
+       if (!found) {
+               rc = sscanf(linkbuf+loff, "../../devices/%n", &lsz);
+               if (rc != 0) {
+                       efi_error("scanf(\"%s\", %s, &lz) failed",
+                                 linkbuf+loff, "../../devices/%n");
+                       return -1;
+               }
+               loff += lsz;
 
-       char *tmppath = strdupa(linkbuf);
-       if (!tmppath)
-               return -1;
-       tmppath[loff] = '\0';
-       rc = sysfs_readlink(&driverbuf, "/sys/dev/block/%s/driver", tmppath);
-       if (rc < 0 || !driverbuf)
-               return -1;
+               ssize_t tmplsz=0;
+               sz = make_pci_path(buf, size, linkbuf+loff, &tmplsz);
+               if (sz < 0)
+                       return -1;
+               loff += tmplsz;
+               off += sz;
 
-       char *driver = strrchr(driverbuf, '/');
-       if (!driver || !*driver)
-               return -1;
-       driver+=1;
+               char *tmppath;
+               tmppath = strdupa(linkbuf);
+               if (!tmppath)
+                       return -1;
+               tmppath[loff] = '\0';
+               rc = sysfs_readlink(&driverbuf, "/sys/dev/block/%s/driver",
+                                   tmppath);
+               if (rc < 0 || !driverbuf)
+                       return -1;
 
-       if (!strncmp(driver, "pata_", 5) || !(strcmp(driver, "ata_piix")))
-               info->interface_type = ata;
+               char *driver = strrchr(driverbuf, '/');
+               if (!driver || !*driver)
+                       return -1;
+               driver+=1;
+
+               if (!strncmp(driver, "pata_", 5) ||
+                   !(strcmp(driver, "ata_piix")))
+                       info->interface_type = ata;
+       }
 
-       if (info->interface_type == interface_type_unknown ||
-           info->interface_type == atapi ||
-           info->interface_type == usb ||
-           info->interface_type == i1394 ||
-           info->interface_type == fibre ||
-           info->interface_type == i2o ||
-           info->interface_type == md) {
+       if (!found &&
+           (info->interface_type == interface_type_unknown ||
+            info->interface_type == atapi ||
+            info->interface_type == usb ||
+            info->interface_type == i1394 ||
+            info->interface_type == fibre ||
+            info->interface_type == i2o ||
+            info->interface_type == md)) {
                uint32_t tosser;
                int tmpoff;
 
index 7f7bc86..a42b920 100644 (file)
@@ -86,6 +86,7 @@ struct disk_info {
                struct sas_info sas_info;
                struct sata_info sata_info;
                struct nvme_info nvme_info;
+               efi_guid_t nvdimm_label;
        };
 
        char *disk_name;
@@ -96,7 +97,7 @@ enum _bus_type {bus_type_unknown, isa, pci};
 enum _interface_type {interface_type_unknown,
                      ata, atapi, scsi, sata, sas, usb,
                      i1394, fibre, i2o, md,
-                     virtblk, nvme};
+                     virtblk, nvme, nd_pmem};
 
 extern int eb_disk_info_from_fd(int fd, struct disk_info *info);
 extern int set_disk_and_part_name(struct disk_info *info);