Skip to content

Commit

Permalink
Add NVDIMM-P support
Browse files Browse the repository at this point in the history
  • Loading branch information
vathpela committed Dec 4, 2017
1 parent d735fda commit be657aa
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 33 deletions.
10 changes: 9 additions & 1 deletion src/creator.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
25 changes: 25 additions & 0 deletions src/dp-message.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}
8 changes: 8 additions & 0 deletions src/include/efivar/efivar-dp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions src/libefivar.map.in
Original file line number Diff line number Diff line change
Expand Up @@ -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;
157 changes: 126 additions & 31 deletions src/linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;

Expand Down
3 changes: 2 additions & 1 deletion src/linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down

0 comments on commit be657aa

Please sign in to comment.