[PATCH] imsm: retrieve nvme serial from sysfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Don't rely on SCSI ioctl for reading NVMe serials - SCSI emulation for
NVMe devices can be disabled in the kernel config. Instead, try to get a
serial from /sys/block/nvme*/device/serial. If that fails for whatever
reason (i.e. no such attribute in old kernels) - fall back to the SCSI
method.

This also moves some SCSI-specific code from imsm_read_serial() to
scsi_get_serial().

Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@xxxxxxxxx>
Reviewed-by: Tomasz Majchrzak <tomasz.majchrzak@xxxxxxxxx>
Reviewed-by: Alexey Obitotskiy <aleksey.obitotskiy@xxxxxxxxx>
---
 sg_io.c       | 23 +++++++++++++++++++----
 super-intel.c | 46 +++++++++++++++++++++++++++-------------------
 2 files changed, 46 insertions(+), 23 deletions(-)

diff --git a/sg_io.c b/sg_io.c
index 50ad180..42c91e1 100644
--- a/sg_io.c
+++ b/sg_io.c
@@ -23,20 +23,35 @@
 
 int scsi_get_serial(int fd, void *buf, size_t buf_len)
 {
-	unsigned char inq_cmd[] = {INQUIRY, 1, 0x80, 0, buf_len, 0};
+	unsigned char rsp_buf[255];
+	unsigned char inq_cmd[] = {INQUIRY, 1, 0x80, 0, sizeof(rsp_buf), 0};
 	unsigned char sense[32];
 	struct sg_io_hdr io_hdr;
+	int rv;
+	unsigned int rsp_len;
 
 	memset(&io_hdr, 0, sizeof(io_hdr));
 	io_hdr.interface_id = 'S';
 	io_hdr.cmdp = inq_cmd;
 	io_hdr.cmd_len = sizeof(inq_cmd);
-	io_hdr.dxferp = buf;
-	io_hdr.dxfer_len = buf_len;
+	io_hdr.dxferp = rsp_buf;
+	io_hdr.dxfer_len = sizeof(rsp_buf);
 	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
 	io_hdr.sbp = sense;
 	io_hdr.mx_sb_len = sizeof(sense);
 	io_hdr.timeout = 5000;
 
-	return ioctl(fd, SG_IO, &io_hdr);
+	rv = ioctl(fd, SG_IO, &io_hdr);
+
+	if (rv)
+		return rv;
+
+	rsp_len = rsp_buf[3];
+
+	if (!rsp_len || buf_len < rsp_len)
+		return -1;
+
+	memcpy(buf, &rsp_buf[4], rsp_len);
+
+	return 0;
 }
diff --git a/super-intel.c b/super-intel.c
index cfc8904..1304737 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -3331,23 +3331,40 @@ static void fd2devname(int fd, char *name)
 	}
 }
 
+static int nvme_get_serial(int fd, void *buf, size_t buf_len)
+{
+	char path[60];
+	char *name = fd2kname(fd);
+
+	if (!name)
+		return 1;
+
+	if (strncmp(name, "nvme", 4) != 0)
+		return 1;
+
+	snprintf(path, sizeof(path) - 1, "/sys/block/%s/device/serial", name);
+
+	return load_sys(path, buf, buf_len);
+}
+
 extern int scsi_get_serial(int fd, void *buf, size_t buf_len);
 
 static int imsm_read_serial(int fd, char *devname,
 			    __u8 serial[MAX_RAID_SERIAL_LEN])
 {
-	unsigned char scsi_serial[255];
+	char buf[50];
 	int rv;
-	int rsp_len;
 	int len;
 	char *dest;
 	char *src;
-	char *rsp_buf;
-	int i;
+	unsigned int i;
+
+	memset(buf, 0, sizeof(buf));
 
-	memset(scsi_serial, 0, sizeof(scsi_serial));
+	rv = nvme_get_serial(fd, buf, sizeof(buf));
 
-	rv = scsi_get_serial(fd, scsi_serial, sizeof(scsi_serial));
+	if (rv)
+		rv = scsi_get_serial(fd, buf, sizeof(buf));
 
 	if (rv && check_env("IMSM_DEVNAME_AS_SERIAL")) {
 		memset(serial, 0, MAX_RAID_SERIAL_LEN);
@@ -3362,20 +3379,11 @@ static int imsm_read_serial(int fd, char *devname,
 		return rv;
 	}
 
-	rsp_len = scsi_serial[3];
-	if (!rsp_len) {
-		if (devname)
-			pr_err("Failed to retrieve serial for %s\n",
-			       devname);
-		return 2;
-	}
-	rsp_buf = (char *) &scsi_serial[4];
-
 	/* trim all whitespace and non-printable characters and convert
 	 * ':' to ';'
 	 */
-	for (i = 0, dest = rsp_buf; i < rsp_len; i++) {
-		src = &rsp_buf[i];
+	for (i = 0, dest = buf; i < sizeof(buf) && buf[i]; i++) {
+		src = &buf[i];
 		if (*src > 0x20) {
 			/* ':' is reserved for use in placeholder serial
 			 * numbers for missing disks
@@ -3386,8 +3394,8 @@ static int imsm_read_serial(int fd, char *devname,
 				*dest++ = *src;
 		}
 	}
-	len = dest - rsp_buf;
-	dest = rsp_buf;
+	len = dest - buf;
+	dest = buf;
 
 	/* truncate leading characters */
 	if (len > MAX_RAID_SERIAL_LEN) {
-- 
2.10.0

--
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux RAID Wiki]     [ATA RAID]     [Linux SCSI Target Infrastructure]     [Linux Block]     [Linux IDE]     [Linux SCSI]     [Linux Hams]     [Device Mapper]     [Device Mapper Cryptographics]     [Kernel]     [Linux Admin]     [Linux Net]     [GFS]     [RPM]     [git]     [Yosemite Forum]


  Powered by Linux