]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
imsm: retrieve nvme serial from sysfs
authorArtur Paszkiewicz <artur.paszkiewicz@intel.com>
Thu, 6 Oct 2016 09:13:09 +0000 (11:13 +0200)
committerJes Sorensen <Jes.Sorensen@redhat.com>
Fri, 7 Oct 2016 15:18:32 +0000 (11:18 -0400)
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@intel.com>
Reviewed-by: Tomasz Majchrzak <tomasz.majchrzak@intel.com>
Reviewed-by: Alexey Obitotskiy <aleksey.obitotskiy@intel.com>
Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
sg_io.c
super-intel.c

diff --git a/sg_io.c b/sg_io.c
index 50ad180d5c4db9b55abd4ad288c8b2e6a4fb9cf7..42c91e1e9c6be4deb7a96d7a78c0c29dd9aaaa01 100644 (file)
--- a/sg_io.c
+++ b/sg_io.c
 
 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;
 }
index cfc8904e2d2cca5df92a54933a3d50ca6ccc5dff..1304737f6fc1ee525cbe7fbbc9556e221365dc66 100644 (file)
@@ -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) {