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
