|
|
ab4840 |
libndctl: add support for the MSFT family of DSM functions
|
|
|
ab4840 |
|
|
|
ab4840 |
BZ:
|
|
|
ab4840 |
|
|
|
ab4840 |
commit 2cf2acca0288389a39ac823a42a5e048575d52db
|
|
|
ab4840 |
Author: Lijun Pan <Lijun.Pan@dell.com>
|
|
|
ab4840 |
Date: Thu Apr 6 12:17:38 2017 -0500
|
|
|
ab4840 |
|
|
|
ab4840 |
libndctl: add support for the MSFT family of DSM functions
|
|
|
ab4840 |
|
|
|
ab4840 |
This patch retrieves the health data from NVDIMM-N via
|
|
|
ab4840 |
the MSFT _DSM function[1], following JESD245A[2] standards.
|
|
|
ab4840 |
Now 'ndctl list --dimms --health --idle' could work
|
|
|
ab4840 |
on MSFT type NVDIMM-N, but limited to health_state,
|
|
|
ab4840 |
temperature_celsius, and life_used_percentage.
|
|
|
ab4840 |
|
|
|
ab4840 |
Sample output of 'ndclt list --dimms --health --idle'
|
|
|
ab4840 |
{
|
|
|
ab4840 |
"dev":"nmem0",
|
|
|
ab4840 |
"id":"802c-0f-1711-1648dd20",
|
|
|
ab4840 |
"state":"disabled",
|
|
|
ab4840 |
"health":{
|
|
|
ab4840 |
"health_state":"ok",
|
|
|
ab4840 |
"temperature_celsius":27.000000,
|
|
|
ab4840 |
"life_used_percentage":3
|
|
|
ab4840 |
}
|
|
|
ab4840 |
}
|
|
|
ab4840 |
|
|
|
ab4840 |
[1]. https://msdn.microsoft.com/library/windows/hardware/mt604741
|
|
|
ab4840 |
[2]. https://www.jedec.org/sites/default/files/docs/JESD245A.pdf
|
|
|
ab4840 |
|
|
|
ab4840 |
Cc: Stuart Hayes <Stuart.Hayes@dell.com>
|
|
|
ab4840 |
Signed-off-by: Lijun Pan <Lijun.Pan@dell.com>
|
|
|
ab4840 |
Tested-by: Linda Knippers <linda.knippers@hpe.com>
|
|
|
ab4840 |
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
|
|
|
ab4840 |
|
|
|
ab4840 |
diff -up ndctl-56/ndctl/lib/Makefile.am.orig ndctl-56/ndctl/lib/Makefile.am
|
|
|
ab4840 |
--- ndctl-56/ndctl/lib/Makefile.am.orig 2017-02-07 16:16:07.000000000 -0500
|
|
|
ab4840 |
+++ ndctl-56/ndctl/lib/Makefile.am 2017-05-24 15:41:41.203723211 -0400
|
|
|
ab4840 |
@@ -32,6 +32,7 @@ endif
|
|
|
ab4840 |
if ENABLE_SMART
|
|
|
ab4840 |
libndctl_la_SOURCES += libndctl-smart.c
|
|
|
ab4840 |
libndctl_la_SOURCES += libndctl-hpe1.c
|
|
|
ab4840 |
+libndctl_la_SOURCES += libndctl-msft.c
|
|
|
ab4840 |
endif
|
|
|
ab4840 |
|
|
|
ab4840 |
EXTRA_DIST += libndctl.sym
|
|
|
ab4840 |
diff -up ndctl-56/ndctl/lib/libndctl-msft.c.orig ndctl-56/ndctl/lib/libndctl-msft.c
|
|
|
ab4840 |
--- ndctl-56/ndctl/lib/libndctl-msft.c.orig 2017-05-24 15:41:41.205723213 -0400
|
|
|
ab4840 |
+++ ndctl-56/ndctl/lib/libndctl-msft.c 2017-05-24 15:41:41.204723212 -0400
|
|
|
ab4840 |
@@ -0,0 +1,140 @@
|
|
|
ab4840 |
+/*
|
|
|
ab4840 |
+ * Copyright (C) 2016-2017 Dell, Inc.
|
|
|
ab4840 |
+ * Copyright (C) 2016 Hewlett Packard Enterprise Development LP
|
|
|
ab4840 |
+ * Copyright (c) 2016, Intel Corporation.
|
|
|
ab4840 |
+ *
|
|
|
ab4840 |
+ * This program is free software; you can redistribute it and/or modify it
|
|
|
ab4840 |
+ * under the terms and conditions of the GNU Lesser General Public License,
|
|
|
ab4840 |
+ * version 2.1, as published by the Free Software Foundation.
|
|
|
ab4840 |
+ *
|
|
|
ab4840 |
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
|
|
|
ab4840 |
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
ab4840 |
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
|
|
ab4840 |
+ * more details.
|
|
|
ab4840 |
+ */
|
|
|
ab4840 |
+#include <stdlib.h>
|
|
|
ab4840 |
+#include <limits.h>
|
|
|
ab4840 |
+#include <util/log.h>
|
|
|
ab4840 |
+#include <ndctl/libndctl.h>
|
|
|
ab4840 |
+#include "libndctl-private.h"
|
|
|
ab4840 |
+#include "ndctl-msft.h"
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+#define CMD_MSFT(_c) ((_c)->msft)
|
|
|
ab4840 |
+#define CMD_MSFT_SMART(_c) (CMD_MSFT(_c)->u.smart.data)
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+static struct ndctl_cmd *msft_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
|
|
|
ab4840 |
+{
|
|
|
ab4840 |
+ struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm);
|
|
|
ab4840 |
+ struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
|
|
|
ab4840 |
+ struct ndctl_cmd *cmd;
|
|
|
ab4840 |
+ size_t size;
|
|
|
ab4840 |
+ struct ndn_pkg_msft *msft;
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_CALL)) {
|
|
|
ab4840 |
+ dbg(ctx, "unsupported cmd\n");
|
|
|
ab4840 |
+ return NULL;
|
|
|
ab4840 |
+ }
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ size = sizeof(*cmd) + sizeof(struct ndn_pkg_msft);
|
|
|
ab4840 |
+ cmd = calloc(1, size);
|
|
|
ab4840 |
+ if (!cmd)
|
|
|
ab4840 |
+ return NULL;
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ cmd->dimm = dimm;
|
|
|
ab4840 |
+ ndctl_cmd_ref(cmd);
|
|
|
ab4840 |
+ cmd->type = ND_CMD_CALL;
|
|
|
ab4840 |
+ cmd->size = size;
|
|
|
ab4840 |
+ cmd->status = 1;
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ msft = CMD_MSFT(cmd);
|
|
|
ab4840 |
+ msft->gen.nd_family = NVDIMM_FAMILY_MSFT;
|
|
|
ab4840 |
+ msft->gen.nd_command = NDN_MSFT_CMD_SMART;
|
|
|
ab4840 |
+ msft->gen.nd_fw_size = 0;
|
|
|
ab4840 |
+ msft->gen.nd_size_in = offsetof(struct ndn_msft_smart, status);
|
|
|
ab4840 |
+ msft->gen.nd_size_out = sizeof(msft->u.smart);
|
|
|
ab4840 |
+ msft->u.smart.status = 0;
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ cmd->firmware_status = &msft->u.smart.status;
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ return cmd;
|
|
|
ab4840 |
+}
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+static int msft_smart_valid(struct ndctl_cmd *cmd)
|
|
|
ab4840 |
+{
|
|
|
ab4840 |
+ if (cmd->type != ND_CMD_CALL ||
|
|
|
ab4840 |
+ cmd->size != sizeof(*cmd) + sizeof(struct ndn_pkg_msft) ||
|
|
|
ab4840 |
+ CMD_MSFT(cmd)->gen.nd_family != NVDIMM_FAMILY_MSFT ||
|
|
|
ab4840 |
+ CMD_MSFT(cmd)->gen.nd_command != NDN_MSFT_CMD_SMART ||
|
|
|
ab4840 |
+ cmd->status != 0)
|
|
|
ab4840 |
+ return cmd->status < 0 ? cmd->status : -EINVAL;
|
|
|
ab4840 |
+ return 0;
|
|
|
ab4840 |
+}
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+static unsigned int msft_cmd_smart_get_flags(struct ndctl_cmd *cmd)
|
|
|
ab4840 |
+{
|
|
|
ab4840 |
+ if (msft_smart_valid(cmd) < 0)
|
|
|
ab4840 |
+ return UINT_MAX;
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ /* below health data can be retrieved via MSFT _DSM function 11 */
|
|
|
ab4840 |
+ return NDN_MSFT_SMART_HEALTH_VALID |
|
|
|
ab4840 |
+ NDN_MSFT_SMART_TEMP_VALID |
|
|
|
ab4840 |
+ NDN_MSFT_SMART_USED_VALID;
|
|
|
ab4840 |
+}
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+static unsigned int num_set_bit_health(__u16 num)
|
|
|
ab4840 |
+{
|
|
|
ab4840 |
+ int i;
|
|
|
ab4840 |
+ __u16 n = num & 0x7FFF;
|
|
|
ab4840 |
+ unsigned int count = 0;
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ for (i = 0; i < 15; i++)
|
|
|
ab4840 |
+ if (!!(n & (1 << i)))
|
|
|
ab4840 |
+ count++;
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ return count;
|
|
|
ab4840 |
+}
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+static unsigned int msft_cmd_smart_get_health(struct ndctl_cmd *cmd)
|
|
|
ab4840 |
+{
|
|
|
ab4840 |
+ unsigned int health;
|
|
|
ab4840 |
+ unsigned int num;
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ if (msft_smart_valid(cmd) < 0)
|
|
|
ab4840 |
+ return UINT_MAX;
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ num = num_set_bit_health(CMD_MSFT_SMART(cmd)->health);
|
|
|
ab4840 |
+ if (num == 0)
|
|
|
ab4840 |
+ health = 0;
|
|
|
ab4840 |
+ else if (num < 2)
|
|
|
ab4840 |
+ health = ND_SMART_NON_CRITICAL_HEALTH;
|
|
|
ab4840 |
+ else if (num < 3)
|
|
|
ab4840 |
+ health = ND_SMART_CRITICAL_HEALTH;
|
|
|
ab4840 |
+ else
|
|
|
ab4840 |
+ health = ND_SMART_FATAL_HEALTH;
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ return health;
|
|
|
ab4840 |
+}
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+static unsigned int msft_cmd_smart_get_temperature(struct ndctl_cmd *cmd)
|
|
|
ab4840 |
+{
|
|
|
ab4840 |
+ if (msft_smart_valid(cmd) < 0)
|
|
|
ab4840 |
+ return UINT_MAX;
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ return CMD_MSFT_SMART(cmd)->temp * 16;
|
|
|
ab4840 |
+}
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+static unsigned int msft_cmd_smart_get_life_used(struct ndctl_cmd *cmd)
|
|
|
ab4840 |
+{
|
|
|
ab4840 |
+ if (msft_smart_valid(cmd) < 0)
|
|
|
ab4840 |
+ return UINT_MAX;
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ return 100 - CMD_MSFT_SMART(cmd)->nvm_lifetime;
|
|
|
ab4840 |
+}
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+struct ndctl_smart_ops * const msft_smart_ops = &(struct ndctl_smart_ops) {
|
|
|
ab4840 |
+ .new_smart = msft_dimm_cmd_new_smart,
|
|
|
ab4840 |
+ .smart_get_flags = msft_cmd_smart_get_flags,
|
|
|
ab4840 |
+ .smart_get_health = msft_cmd_smart_get_health,
|
|
|
ab4840 |
+ .smart_get_temperature = msft_cmd_smart_get_temperature,
|
|
|
ab4840 |
+ .smart_get_life_used = msft_cmd_smart_get_life_used,
|
|
|
ab4840 |
+};
|
|
|
ab4840 |
diff -up ndctl-56/ndctl/lib/libndctl-private.h.orig ndctl-56/ndctl/lib/libndctl-private.h
|
|
|
ab4840 |
--- ndctl-56/ndctl/lib/libndctl-private.h.orig 2017-02-07 16:16:07.000000000 -0500
|
|
|
ab4840 |
+++ ndctl-56/ndctl/lib/libndctl-private.h 2017-05-24 15:41:41.206723214 -0400
|
|
|
ab4840 |
@@ -32,6 +32,7 @@
|
|
|
ab4840 |
#include <ccan/endian/endian.h>
|
|
|
ab4840 |
#include <ccan/short_types/short_types.h>
|
|
|
ab4840 |
#include "ndctl-hpe1.h"
|
|
|
ab4840 |
+#include "ndctl-msft.h"
|
|
|
ab4840 |
|
|
|
ab4840 |
#define SZ_16M 0x01000000
|
|
|
ab4840 |
|
|
|
ab4840 |
@@ -196,6 +197,7 @@ struct ndctl_cmd {
|
|
|
ab4840 |
struct nd_cmd_clear_error clear_err[0];
|
|
|
ab4840 |
#endif
|
|
|
ab4840 |
struct ndn_pkg_hpe1 hpe1[0];
|
|
|
ab4840 |
+ struct ndn_pkg_msft msft[0];
|
|
|
ab4840 |
struct nd_cmd_smart smart[0];
|
|
|
ab4840 |
struct nd_cmd_smart_threshold smart_t[0];
|
|
|
ab4840 |
struct nd_cmd_get_config_size get_size[0];
|
|
|
ab4840 |
@@ -226,9 +228,11 @@ struct ndctl_smart_ops {
|
|
|
ab4840 |
#if HAS_SMART == 1
|
|
|
ab4840 |
struct ndctl_smart_ops * const intel_smart_ops;
|
|
|
ab4840 |
struct ndctl_smart_ops * const hpe1_smart_ops;
|
|
|
ab4840 |
+struct ndctl_smart_ops * const msft_smart_ops;
|
|
|
ab4840 |
#else
|
|
|
ab4840 |
static struct ndctl_smart_ops * const intel_smart_ops = NULL;
|
|
|
ab4840 |
static struct ndctl_smart_ops * const hpe1_smart_ops = NULL;
|
|
|
ab4840 |
+static struct ndctl_smart_ops * const msft_smart_ops = NULL;
|
|
|
ab4840 |
#endif
|
|
|
ab4840 |
|
|
|
ab4840 |
/* internal library helpers for conditionally defined command numbers */
|
|
|
ab4840 |
diff -up ndctl-56/ndctl/lib/libndctl.c.orig ndctl-56/ndctl/lib/libndctl.c
|
|
|
ab4840 |
--- ndctl-56/ndctl/lib/libndctl.c.orig 2017-02-07 16:16:07.000000000 -0500
|
|
|
ab4840 |
+++ ndctl-56/ndctl/lib/libndctl.c 2017-05-24 15:41:41.208723216 -0400
|
|
|
ab4840 |
@@ -1254,6 +1254,8 @@ static void *add_dimm(void *parent, int
|
|
|
ab4840 |
dimm->dsm_family = strtoul(buf, NULL, 0);
|
|
|
ab4840 |
if (dimm->dsm_family == NVDIMM_FAMILY_HPE1)
|
|
|
ab4840 |
dimm->smart_ops = hpe1_smart_ops;
|
|
|
ab4840 |
+ if (dimm->dsm_family == NVDIMM_FAMILY_MSFT)
|
|
|
ab4840 |
+ dimm->smart_ops = msft_smart_ops;
|
|
|
ab4840 |
|
|
|
ab4840 |
dimm->formats = formats;
|
|
|
ab4840 |
sprintf(path, "%s/nfit/format", dimm_base);
|
|
|
ab4840 |
diff -up ndctl-56/ndctl/lib/ndctl-msft.h.orig ndctl-56/ndctl/lib/ndctl-msft.h
|
|
|
ab4840 |
--- ndctl-56/ndctl/lib/ndctl-msft.h.orig 2017-05-24 15:41:41.210723218 -0400
|
|
|
ab4840 |
+++ ndctl-56/ndctl/lib/ndctl-msft.h 2017-05-24 15:41:41.209723217 -0400
|
|
|
ab4840 |
@@ -0,0 +1,63 @@
|
|
|
ab4840 |
+/*
|
|
|
ab4840 |
+ * Copyright (C) 2016-2017 Dell, Inc.
|
|
|
ab4840 |
+ * Copyright (C) 2016 Hewlett Packard Enterprise Development LP
|
|
|
ab4840 |
+ * Copyright (c) 2014-2015, Intel Corporation.
|
|
|
ab4840 |
+ *
|
|
|
ab4840 |
+ * This program is free software; you can redistribute it and/or modify it
|
|
|
ab4840 |
+ * under the terms and conditions of the GNU Lesser General Public License,
|
|
|
ab4840 |
+ * version 2.1, as published by the Free Software Foundation.
|
|
|
ab4840 |
+ *
|
|
|
ab4840 |
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
|
|
|
ab4840 |
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
ab4840 |
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
|
|
ab4840 |
+ * more details.
|
|
|
ab4840 |
+ */
|
|
|
ab4840 |
+#ifndef __NDCTL_MSFT_H__
|
|
|
ab4840 |
+#define __NDCTL_MSFT_H__
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+enum {
|
|
|
ab4840 |
+ NDN_MSFT_CMD_QUERY = 0,
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+ /* non-root commands */
|
|
|
ab4840 |
+ NDN_MSFT_CMD_SMART = 11,
|
|
|
ab4840 |
+};
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+/* NDN_MSFT_CMD_SMART */
|
|
|
ab4840 |
+#define NDN_MSFT_SMART_HEALTH_VALID ND_SMART_HEALTH_VALID
|
|
|
ab4840 |
+#define NDN_MSFT_SMART_TEMP_VALID ND_SMART_TEMP_VALID
|
|
|
ab4840 |
+#define NDN_MSFT_SMART_USED_VALID ND_SMART_USED_VALID
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+/*
|
|
|
ab4840 |
+ * This is actually function 11 data,
|
|
|
ab4840 |
+ * This is the closest I can find to match smart
|
|
|
ab4840 |
+ * Microsoft _DSM does not have smart function
|
|
|
ab4840 |
+ */
|
|
|
ab4840 |
+struct ndn_msft_smart_data {
|
|
|
ab4840 |
+ __u16 health;
|
|
|
ab4840 |
+ __u16 temp;
|
|
|
ab4840 |
+ __u8 err_thresh_stat;
|
|
|
ab4840 |
+ __u8 warn_thresh_stat;
|
|
|
ab4840 |
+ __u8 nvm_lifetime;
|
|
|
ab4840 |
+ __u8 count_dram_uncorr_err;
|
|
|
ab4840 |
+ __u8 count_dram_corr_err;
|
|
|
ab4840 |
+} __attribute__((packed));
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+struct ndn_msft_smart {
|
|
|
ab4840 |
+ __u32 status;
|
|
|
ab4840 |
+ union {
|
|
|
ab4840 |
+ __u8 buf[9];
|
|
|
ab4840 |
+ struct ndn_msft_smart_data data[0];
|
|
|
ab4840 |
+ };
|
|
|
ab4840 |
+} __attribute__((packed));
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+union ndn_msft_cmd {
|
|
|
ab4840 |
+ __u32 query;
|
|
|
ab4840 |
+ struct ndn_msft_smart smart;
|
|
|
ab4840 |
+} __attribute__((packed));
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+struct ndn_pkg_msft {
|
|
|
ab4840 |
+ struct nd_cmd_pkg gen;
|
|
|
ab4840 |
+ union ndn_msft_cmd u;
|
|
|
ab4840 |
+} __attribute__((packed));
|
|
|
ab4840 |
+
|
|
|
ab4840 |
+#endif /* __NDCTL_MSFT_H__ */
|