File efivar-nvme-no-kernel-header.patch of Package efivar

From 8910f45c27fadba0904f707e7c40ad80bf828f7e Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Fri, 19 Feb 2016 18:53:00 -0500
Subject: [PATCH] libefiboot: rework NVME so we get EUI right and don't need
 kernel headers

The headers are broken enough on various distros that it's better to
avoid them entirely.

Signed-off-by: Peter Jones <pjones@redhat.com>
---
 src/linux.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++--------------
 src/linux.h |   8 ++++
 2 files changed, 106 insertions(+), 29 deletions(-)

diff --git a/src/linux.c b/src/linux.c
index 0063476..084e9c2 100644
--- a/src/linux.c
+++ b/src/linux.c
@@ -23,11 +23,6 @@
 #include <limits.h>
 #include <linux/ethtool.h>
 #include <linux/version.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
-#include <linux/nvme_ioctl.h>
-#else
-#include <linux/nvme.h>
-#endif
 #include <linux/sockios.h>
 #include <net/if.h>
 #include <scsi/scsi.h>
@@ -48,17 +43,6 @@
 
 int
 __attribute__((__visibility__ ("hidden")))
-eb_nvme_ns_id(int fd, uint32_t *ns_id)
-{
-	uint64_t ret = ioctl(fd, NVME_IOCTL_ID, NULL);
-	if ((int)ret < 0)
-		return ret;
-	*ns_id = (uint32_t)ret;
-	return 0;
-}
-
-int
-__attribute__((__visibility__ ("hidden")))
 set_disk_and_part_name(struct disk_info *info)
 {
 	char *linkbuf;
@@ -168,6 +152,23 @@ get_partition_number(const char *devpath)
 }
 
 static int
+sysfs_test_nvme(const char *buf, ssize_t size)
+{
+	int rc;
+
+	int32_t tosser0;
+	int32_t ctrl_id;
+	int32_t ns_id;
+
+	errno = 0;
+	rc = sscanf(buf, "nvme/nvme%d/nvme%dn%d", &tosser0, &ctrl_id, &ns_id);
+	if (rc < 1)
+		return (errno == 0) ? 0 : -1;
+
+	return 1;
+}
+
+static int
 sysfs_test_sata(const char *buf, ssize_t size)
 {
 	if (!strncmp(buf, "ata", MIN(size,3)))
@@ -259,6 +260,69 @@ sysfs_sata_get_port_info(uint32_t print_id, struct disk_info *info)
 }
 
 static ssize_t
+sysfs_parse_nvme(uint8_t *buf, ssize_t size, ssize_t *off,
+		const char *pbuf, ssize_t psize, ssize_t *poff,
+		struct disk_info *info)
+{
+	int rc;
+	int psz = 0;
+	char *filebuf = NULL;
+
+	*poff = 0;
+	*off = 0;
+
+	int32_t tosser0;
+	int32_t ctrl_id;
+	int32_t ns_id;
+
+	/* buf is:
+	 * nvme/nvme0/nvme0n1
+	 */
+	rc = sscanf(pbuf+*poff, "nvme/nvme%d/nvme%dn%d%n", &tosser0,
+		    &ctrl_id, &ns_id, &psz);
+	if (rc != 3)
+		return -1;
+	*poff += psz;
+
+	info->nvme_info.ctrl_id = ctrl_id;
+	info->nvme_info.ns_id = ns_id;
+	info->nvme_info.has_eui = 0;
+	info->interface_type = nvme;
+
+	/*
+	 * now fish the eui out of sysfs is there is one...
+	 */
+	rc = read_sysfs_file(&filebuf,
+			     "/sys/class/block/nvme%dn%d/device/eui",
+			     ctrl_id, ns_id);
+	if (rc >= 0) {
+		uint8_t eui[8];
+		if (rc < 23) {
+			errno = EINVAL;
+			return -1;
+		}
+		rc = sscanf(filebuf,
+			    "%02hhx-%02hhx-%02hhx-%02hhx-"
+			    "%02hhx-%02hhx-%02hhx-%02hhx",
+			    &eui[0], &eui[1], &eui[2], &eui[3],
+			    &eui[4], &eui[5], &eui[6], &eui[7]);
+		if (rc < 8) {
+			errno = EINVAL;
+			return -1;
+		}
+		info->nvme_info.has_eui = 1;
+		memcpy(info->nvme_info.eui, eui, sizeof(eui));
+	}
+
+	*off = efidp_make_nvme(buf, size,
+			       info->nvme_info.ns_id,
+			       info->nvme_info.has_eui ? info->nvme_info.eui
+						       : NULL);
+	return *off;
+}
+
+
+static ssize_t
 sysfs_parse_sata(uint8_t *buf, ssize_t size, ssize_t *off,
 		 const char *pbuf, ssize_t psize, ssize_t *poff,
 		 struct disk_info *info)
@@ -665,20 +729,25 @@ make_blockdev_path(uint8_t *buf, ssize_t size, int fd, struct disk_info *info)
 			loff += tmpoff;
 			found = 1;
 		}
+	}
 
-		if (!found) {
-			uint32_t ns_id=0;
-			int rc = eb_nvme_ns_id(fd, &ns_id);
-			if (rc >= 0) {
-				sz = efidp_make_nvme(buf+off, size?size-off:0,
-						     ns_id, NULL);
-				if (sz < 0)
-					return -1;
-
-				info->interface_type = nvme;
-				off += sz;
-				found = 1;
-			}
+	/* /dev/nvme0n1 looks like:
+	 * /sys/dev/block/259:0 -> ../../devices/pci0000:00/0000:00:1d.0/0000:05:00.0/nvme/nvme0/nvme0n1
+	 */
+	if (!found) {
+		rc = sysfs_test_nvme(linkbuf+loff, PATH_MAX-off);
+		if (rc < 0)
+			return -1;
+		else if (rc > 0) {
+			ssize_t linksz;
+			rc = sysfs_parse_nvme(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;
 		}
 	}
 
diff --git a/src/linux.h b/src/linux.h
index 5e8d003..539fb23 100644
--- a/src/linux.h
+++ b/src/linux.h
@@ -60,6 +60,13 @@ struct sata_info {
 	uint32_t ata_pmp;
 };
 
+struct nvme_info {
+	int32_t ctrl_id;
+	int32_t ns_id;
+	int has_eui;
+	uint8_t eui[8];
+};
+
 struct disk_info {
 	int interface_type;
 	unsigned int controllernum;
@@ -76,6 +83,7 @@ struct disk_info {
 		struct scsi_info scsi_info;
 		struct sas_info sas_info;
 		struct sata_info sata_info;
+		struct nvme_info nvme_info;
 	};
 
 	char *disk_name;
-- 
2.7.2

openSUSE Build Service is sponsored by