From: Lijun Pan <[email protected]>

Add Microsoft's specific _DSM interface to retrieve the NVDIMM
health data from the server platforms supporting this interface.
Please refer to Microsoft _DSM spec[1] and JESD245A[2].

[1]. https://msdn.microsoft.com/library/windows/hardware/mt604741
[2]. https://www.jedec.org/sites/default/files/docs/JESD245A.pdf

Cc: Stuart Hayes <[email protected]>
Signed-off-by: Lijun Pan <[email protected]>
---
 ndctl/Makefile.am      |   3 +-
 ndctl/builtin-list.c   |   6 ++-
 ndctl/lib/libndctl.c   |   5 ++
 ndctl/lib/libndctl.sym |   1 +
 ndctl/lib/ndctl-msft.h |  57 ++++++++++++++++++++++
 ndctl/libndctl.h.in    |   1 +
 ndctl/util/json-msft.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++
 util/json.h            |   1 +
 8 files changed, 197 insertions(+), 2 deletions(-)
 create mode 100644 ndctl/lib/ndctl-msft.h
 create mode 100644 ndctl/util/json-msft.c

diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
index c563e94..f85f9cb 100644
--- a/ndctl/Makefile.am
+++ b/ndctl/Makefile.am
@@ -10,7 +10,8 @@ ndctl_SOURCES = ndctl.c \
                 ../util/log.c \
                builtin-list.c \
                builtin-test.c \
-               ../util/json.c
+               ../util/json.c \
+               util/json-msft.c
 
 if ENABLE_SMART
 ndctl_SOURCES += util/json-smart.c
diff --git a/ndctl/builtin-list.c b/ndctl/builtin-list.c
index e8d0070..d4e1d23 100644
--- a/ndctl/builtin-list.c
+++ b/ndctl/builtin-list.c
@@ -349,7 +349,11 @@ int cmd_list(int argc, const char **argv, void *ctx)
                        if (list.health) {
                                struct json_object *jhealth;
 
-                               jhealth = util_dimm_health_to_json(dimm);
+                               if (ndctl_dimm_get_dsm_family(dimm) == 
NVDIMM_FAMILY_MSFT)
+                                       jhealth = 
util_dimm_health_to_json_msft(dimm);
+                               else
+                                       jhealth = 
util_dimm_health_to_json(dimm);
+
                                if (jhealth)
                                        json_object_object_add(jdimm, "health",
                                                        jhealth);
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 565c969..019db9a 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -1361,6 +1361,11 @@ NDCTL_EXPORT unsigned char 
ndctl_dimm_get_manufacturing_location(
        return dimm->manufacturing_location;
 }
 
+NDCTL_EXPORT unsigned long ndctl_dimm_get_dsm_family(struct ndctl_dimm *dimm)
+{
+       return dimm->dsm_family;
+}
+
 NDCTL_EXPORT unsigned short ndctl_dimm_get_format(struct ndctl_dimm *dimm)
 {
        return dimm->format[0];
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index be2e368..b1d6e6f 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -48,6 +48,7 @@ global:
        ndctl_dimm_get_subsystem_vendor;
        ndctl_dimm_get_subsystem_device;
        ndctl_dimm_get_subsystem_revision;
+       ndctl_dimm_get_dsm_family;
        ndctl_dimm_get_format;
        ndctl_dimm_get_formats;
        ndctl_dimm_get_formatN;
diff --git a/ndctl/lib/ndctl-msft.h b/ndctl/lib/ndctl-msft.h
new file mode 100644
index 0000000..4985c24
--- /dev/null
+++ b/ndctl/lib/ndctl-msft.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016-2017 Dell, Inc.
+ * Author: Lijun Pan <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
+#ifndef _NDCTL_DELL_H_
+#define _NDCTL_DELL_H_
+
+#define DEV_NAME_MAX_LENGTH    12
+#define DEV_ID_MAX_LENGTH      3
+#define DEV_ID_MAX             128
+
+/* REFER TO SPEC 
https://msdn.microsoft.com/en-us/library/windows/hardware/mt604741(v=vs.85).aspx
 */
+#define SIZE_IN_FUNC0 0
+#define SIZE_IN_FUNC1 0
+#define SIZE_IN_FUNC2 0
+#define SIZE_IN_FUNC3 0
+#define SIZE_IN_FUNC4 0
+#define SIZE_IN_FUNC5 0
+#define SIZE_IN_FUNC7 0
+#define SIZE_IN_FUNC10 0
+#define SIZE_IN_FUNC11 0
+#define SIZE_IN_FUNC12 0
+
+#define SIZE_OUT_FUNC0 4
+#define SIZE_OUT_FUNC1 50
+#define SIZE_OUT_FUNC2 12
+#define SIZE_OUT_FUNC3 19
+#define SIZE_OUT_FUNC4 12
+#define SIZE_OUT_FUNC5 6
+#define SIZE_OUT_FUNC7 8
+#define SIZE_OUT_FUNC10 5
+#define SIZE_OUT_FUNC11 13
+#define SIZE_OUT_FUNC12 11
+#define SIZE_OUT_MAX 50
+
+#define FUNC0 0
+#define FUNC1 1
+#define FUNC2 2
+#define FUNC3 3
+#define FUNC4 4
+#define FUNC5 5
+#define FUNC7 7
+#define FUNC10 10
+#define FUNC11 11
+#define FUNC12 12
+
+#endif
diff --git a/ndctl/libndctl.h.in b/ndctl/libndctl.h.in
index c27581d..fb2c6e1 100644
--- a/ndctl/libndctl.h.in
+++ b/ndctl/libndctl.h.in
@@ -129,6 +129,7 @@ unsigned short ndctl_dimm_get_subsystem_device(struct 
ndctl_dimm *dimm);
 unsigned short ndctl_dimm_get_manufacturing_date(struct ndctl_dimm *dimm);
 unsigned char ndctl_dimm_get_manufacturing_location(struct ndctl_dimm *dimm);
 unsigned short ndctl_dimm_get_subsystem_revision(struct ndctl_dimm *dimm);
+unsigned long ndctl_dimm_get_dsm_family(struct ndctl_dimm *dimm);
 unsigned short ndctl_dimm_get_format(struct ndctl_dimm *dimm);
 int ndctl_dimm_get_formats(struct ndctl_dimm *dimm);
 int ndctl_dimm_get_formatN(struct ndctl_dimm *dimm, int i);
diff --git a/ndctl/util/json-msft.c b/ndctl/util/json-msft.c
new file mode 100644
index 0000000..9e41fde
--- /dev/null
+++ b/ndctl/util/json-msft.c
@@ -0,0 +1,125 @@
+#include <limits.h>
+#include <util/json.h>
+#include <uuid/uuid.h>
+#include <json-c/json.h>
+#include <ndctl/libndctl.h>
+#include <ccan/array_size/array_size.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#ifdef HAVE_NDCTL_H
+#include <linux/ndctl.h>
+#else
+#include <ndctl.h>
+#endif
+
+#include "ndctl-msft.h"
+
+static int call_func(int func_num, int size_in, int size_out,
+               int fd, unsigned char *payload) {
+       struct nd_cmd_pkg *pkg;
+       int error;
+       int i;
+
+       memset(payload, 0, SIZE_OUT_MAX);
+       pkg = malloc(sizeof(struct nd_cmd_pkg) + size_in + size_out);
+       if (!pkg)
+               return -ENOMEM;
+
+       pkg->nd_family = NVDIMM_FAMILY_MSFT;
+       pkg->nd_command = func_num;
+       pkg->nd_size_in = size_in;
+       pkg->nd_size_out = size_out;
+       pkg->nd_fw_size = 0;
+
+       for (i = 0; i < 9; i++)
+               pkg->nd_reserved2[i] = 0;
+
+       for (i = 0; i < size_in; i++)
+               pkg->nd_payload[i] = 0;
+
+       for (i = 0; i < size_out; i++)
+               pkg->nd_payload[i + size_in] = 0;
+
+       error = ioctl(fd, ND_IOCTL_CALL, pkg);
+
+       if (error) {
+               fprintf(stderr, "ioctl returned errno %d\n", errno);
+               free(pkg);
+               return error;
+       }
+
+       for (i = 0; i < size_out; i++)
+               payload[i] = pkg->nd_payload[i + size_in];
+
+       free(pkg);
+       return 0;
+}
+
+struct json_object *util_dimm_health_to_json_msft(struct ndctl_dimm *dimm)
+{
+
+       struct json_object *jhealth = json_object_new_object();
+       struct json_object *jobj;
+       char dev_name[DEV_NAME_MAX_LENGTH + 1];
+       unsigned char payload[SIZE_OUT_MAX];
+       char str[100];
+       int fd;
+       int error;
+       int number;
+       double temp;
+
+       memset(dev_name, 0, DEV_NAME_MAX_LENGTH + 1);
+       snprintf(dev_name, DEV_NAME_MAX_LENGTH + 1, "/dev/nmem%d", 
ndctl_dimm_get_id(dimm));
+       fd = open(dev_name, O_RDWR);
+       if (fd == -1) {
+               fprintf(stderr, "error opening %s errno=%d\n", dev_name, errno);
+               goto err_fd;
+       }
+
+       error = call_func(FUNC10, SIZE_IN_FUNC10, SIZE_OUT_FUNC10, fd, payload);
+       if (!error) {
+               if (!!(payload[4] & 0x0F))
+                       jobj = json_object_new_string("critical");
+               else
+                       jobj = json_object_new_string("ok");
+               if (jobj)
+                       json_object_object_add(jhealth, "health_state", jobj);
+       }
+
+       error = call_func(FUNC11, SIZE_IN_FUNC11, SIZE_OUT_FUNC11, fd, payload);
+       if (!error) {
+               /* refer to JESD245 spec section 7.8 to calculate the 
temperature */
+               number = (payload[7] & 0x0F) << 4 | (payload[6] & 0xF0) >> 4;
+               temp = number + !!(payload[6] & 0x08) * 0.5 + !!(payload[6] & 
0x04) * 0.25;
+               jobj = json_object_new_double(temp);
+               if (jobj)
+                       json_object_object_add(jhealth, "temperature_celsius", 
jobj);
+
+               memset(str, 0, 100);
+               snprintf(str, 100, "%d%%", payload[10]);
+               jobj = json_object_new_string(str);
+               if (jobj)
+                       json_object_object_add(jhealth, "NVM_Lifetime", jobj);
+       }
+
+       error = call_func(FUNC4, SIZE_IN_FUNC4, SIZE_OUT_FUNC4, fd, payload);
+       if (!error) {
+               if (!!(payload[4] & 0x1))
+                       jobj = json_object_new_string("success");
+               else
+                       jobj = json_object_new_string("failure");
+               if (jobj)
+                       json_object_object_add(jhealth, "last_save_operation", 
jobj);
+       }
+
+       close(fd);
+       return jhealth;
+
+err_fd:
+       json_object_put(jhealth);
+
+       return NULL;
+}
diff --git a/util/json.h b/util/json.h
index a9afb2d..3a41977 100644
--- a/util/json.h
+++ b/util/json.h
@@ -29,4 +29,5 @@ static inline struct json_object *util_dimm_health_to_json(
        return NULL;
 }
 #endif
+struct json_object *util_dimm_health_to_json_msft(struct ndctl_dimm *dimm);
 #endif /* __NDCTL_JSON_H__ */
-- 
1.8.3.1

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

Reply via email to