* [ndctl PATCH 0/5] smart support and 'list' enhancements
@ 2016-04-07 1:06 Dan Williams
2016-04-07 1:07 ` [ndctl PATCH 1/5] ndctl: rebuild libndctl.h when libndctl.h.in changes Dan Williams
` (4 more replies)
0 siblings, 5 replies; 16+ messages in thread
From: Dan Williams @ 2016-04-07 1:06 UTC (permalink / raw)
To: linux-nvdimm
1/ Provide helper routines for higher level management software to issue
SMART data retrieval commands.
2/ Add a reference implementation of SMART data retrieval by extending
the 'list' command to emit json with SMART key/value data.
3/ With health information available it is useful to know which
namespaces are impacted by a dimm that reports a bad health status,
so a 'filter by dimm' mechanism is added to the 'list' command.
---
Dan Williams (5):
ndctl: rebuild libndctl.h when libndctl.h.in changes
ndctl: helper for S.M.A.R.T. data retrieval
ndctl, list: clean up default behavior
ndctl, list: add a '--health' option
ndctl, list: add 'filter by dimm' capability
Documentation/ndctl-list.txt | 29 ++++++++++++-
Makefile.am | 8 +++
builtin-list.c | 31 +++++++++++--
configure.ac | 26 +++++++++++
lib/libndctl-private.h | 1
lib/libndctl-smart.c | 81 +++++++++++++++++++++++++++++++++++
lib/libndctl.c | 1
lib/libndctl.sym | 10 ++++
lib/ndctl/libndctl.h.in | 55 ++++++++++++++++++++++++
ndctl.h | 29 +++++++++++++
test/libndctl.c | 68 +++++++++++++++++++++++++++++
util/filter.c | 83 ++++++++++++++++++++++++++++++++++++
util/filter.h | 5 ++
util/json.c | 97 ++++++++++++++++++++++++++++++++++++++++++
util/json.h | 1
15 files changed, 516 insertions(+), 9 deletions(-)
create mode 100644 lib/libndctl-smart.c
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 16+ messages in thread
* [ndctl PATCH 1/5] ndctl: rebuild libndctl.h when libndctl.h.in changes
2016-04-07 1:06 [ndctl PATCH 0/5] smart support and 'list' enhancements Dan Williams
@ 2016-04-07 1:07 ` Dan Williams
2016-04-07 8:29 ` Johannes Thumshirn
2016-04-07 1:07 ` [ndctl PATCH 2/5] ndctl: helper for S.M.A.R.T. data retrieval Dan Williams
` (3 subsequent siblings)
4 siblings, 1 reply; 16+ messages in thread
From: Dan Williams @ 2016-04-07 1:07 UTC (permalink / raw)
To: linux-nvdimm
Since libnctl.h is build via an AC_CONFIG_COMMANDS() statement we want
configure to re-run if libndctl.h.in is changed.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Makefile.am | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Makefile.am b/Makefile.am
index 7de3d3c3c9eb..379f6404671f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -29,7 +29,9 @@ AM_LDFLAGS = \
-Wl,--gc-sections \
-Wl,--as-needed
-BUILT_SOURCES = $(top_srcdir)/version.m4
+BUILT_SOURCES = $(top_srcdir)/version.m4 $(top_srcdir)/lib/ndctl/libndctl.h
+$(top_srcdir)/lib/ndctl/libndctl.h: $(top_srcdir)/lib/ndctl/libndctl.h.in
+ touch $(top_srcdir)/version.m4
$(top_srcdir)/version.m4: FORCE
$(AM_V_GEN)$(top_srcdir)/git-version-gen
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [ndctl PATCH 2/5] ndctl: helper for S.M.A.R.T. data retrieval
2016-04-07 1:06 [ndctl PATCH 0/5] smart support and 'list' enhancements Dan Williams
2016-04-07 1:07 ` [ndctl PATCH 1/5] ndctl: rebuild libndctl.h when libndctl.h.in changes Dan Williams
@ 2016-04-07 1:07 ` Dan Williams
2016-04-07 8:36 ` Johannes Thumshirn
2016-04-07 22:39 ` [ndctl PATCH v2] " Dan Williams
2016-04-07 1:07 ` [ndctl PATCH 3/5] ndctl, list: clean up default behavior Dan Williams
` (2 subsequent siblings)
4 siblings, 2 replies; 16+ messages in thread
From: Dan Williams @ 2016-04-07 1:07 UTC (permalink / raw)
To: linux-nvdimm
Helper functions to issue the "SMART and Health Info (Function Index 1)"
DSM and parse its results.
http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Makefile.am | 4 ++
configure.ac | 26 +++++++++++++++
lib/libndctl-private.h | 1 +
lib/libndctl-smart.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++
lib/libndctl.c | 1 +
lib/libndctl.sym | 10 ++++++
lib/ndctl/libndctl.h.in | 55 ++++++++++++++++++++++++++++++++
ndctl.h | 29 +++++++++++++++++
test/libndctl.c | 68 +++++++++++++++++++++++++++++++++++++++
9 files changed, 274 insertions(+), 1 deletion(-)
create mode 100644 lib/libndctl-smart.c
diff --git a/Makefile.am b/Makefile.am
index 379f6404671f..9c6b37410642 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -85,6 +85,10 @@ if ENABLE_ARS
lib_libndctl_la_SOURCES += lib/libndctl-ars.c
endif
+if ENABLE_SMART
+lib_libndctl_la_SOURCES += lib/libndctl-smart.c
+endif
+
bin_PROGRAMS = ndctl
ndctl_SOURCES = ndctl.c \
diff --git a/configure.ac b/configure.ac
index 1ab376885215..01f347a7f137 100644
--- a/configure.ac
+++ b/configure.ac
@@ -144,6 +144,25 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
)
AM_CONDITIONAL([ENABLE_CLEAR_ERROR], [test "x$enable_clear_err" = "xyes"])
+AC_MSG_CHECKING([for SMART support])
+AC_LANG(C)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #ifdef HAVE_NDCTL_H
+ #include <linux/ndctl.h>
+ #else
+ #include "ndctl.h"
+ #endif
+ ]], [[
+ int x = ND_SMART_HEALTH_VALID;
+ ]]
+ )], [AC_MSG_RESULT([yes])
+ enable_smart=yes
+ AC_DEFINE([HAVE_NDCTL_SMART], [1],
+ [Define to 1 if ndctl.h has SMART support.])
+ ], [AC_MSG_RESULT([no])]
+)
+AM_CONDITIONAL([ENABLE_SMART], [test "x$enable_smart" = "xyes"])
+
AC_CONFIG_COMMANDS([gen-libndctl.h],
[[
if test "x$enable_ars" = "xyes"; then
@@ -151,17 +170,24 @@ AC_CONFIG_COMMANDS([gen-libndctl.h],
else
enable_ars=0
fi
+ if test "x$enable_smart" = "xyes"; then
+ enable_smart=1
+ else
+ enable_smart=0
+ fi
if test "x$enable_clear_err" = "xyes"; then
enable_clear_err=1
else
enable_clear_err=0
fi
sed -e s/HAVE_NDCTL_ARS/$enable_ars/ \
+ -e s/HAVE_NDCTL_SMART/$enable_smart/ \
-e s/HAVE_NDCTL_CLEAR_ERROR/$enable_clear_err/ \
< lib/ndctl/libndctl.h.in > lib/ndctl/libndctl.h
]],
[[
enable_ars=$enable_ars
+ enable_smart=$enable_smart
enable_clear_err=$enable_clear_err
]])
diff --git a/lib/libndctl-private.h b/lib/libndctl-private.h
index 50b03743751f..37aed296a571 100644
--- a/lib/libndctl-private.h
+++ b/lib/libndctl-private.h
@@ -167,6 +167,7 @@ struct ndctl_cmd {
#ifdef HAVE_NDCTL_CLEAR_ERROR
struct nd_cmd_clear_error clear_err[0];
#endif
+ struct nd_cmd_smart smart[0];
struct nd_cmd_get_config_size get_size[0];
struct nd_cmd_get_config_data_hdr get_data[0];
struct nd_cmd_set_config_hdr set_data[0];
diff --git a/lib/libndctl-smart.c b/lib/libndctl-smart.c
new file mode 100644
index 000000000000..1013eddd45dc
--- /dev/null
+++ b/lib/libndctl-smart.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * 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.
+ */
+#include <stdlib.h>
+#include <limits.h>
+#include <ndctl/libndctl.h>
+#include "libndctl-private.h"
+
+NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
+{
+ struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm);
+ struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
+ struct ndctl_cmd *cmd;
+ size_t size;
+
+ BUILD_ASSERT(sizeof(struct nd_smart_payload) == 128);
+
+ if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_SMART)) {
+ dbg(ctx, "unsupported cmd\n");
+ return NULL;
+ }
+
+ size = sizeof(*cmd) + sizeof(struct nd_cmd_smart);
+ cmd = calloc(1, size);
+ if (!cmd)
+ return NULL;
+
+ cmd->dimm = dimm;
+ ndctl_cmd_ref(cmd);
+ cmd->type = ND_CMD_SMART;
+ cmd->size = size;
+ cmd->status = 1;
+ cmd->firmware_status = &cmd->smart->status;
+
+ return cmd;
+}
+
+static int smart_valid(struct ndctl_cmd *cmd)
+{
+ if (cmd->type != ND_CMD_SMART || cmd->status != 0)
+ return cmd->status < 0 ? cmd->status : -EINVAL;
+ return 0;
+}
+
+#define ndctl_cmd_get_field(cmd, field) \
+NDCTL_EXPORT unsigned int ndctl_cmd_smart_get_##field(struct ndctl_cmd *cmd) \
+{ \
+ struct nd_smart_payload *smart_data; \
+ if (smart_valid(cmd) < 0) \
+ return UINT_MAX; \
+ smart_data = (struct nd_smart_payload *) cmd->smart->data; \
+ return smart_data->field; \
+}
+
+ndctl_cmd_get_field(cmd, flags)
+ndctl_cmd_get_field(cmd, health)
+ndctl_cmd_get_field(cmd, temperature)
+ndctl_cmd_get_field(cmd, spares)
+ndctl_cmd_get_field(cmd, alarm_flags)
+ndctl_cmd_get_field(cmd, life_used)
+ndctl_cmd_get_field(cmd, shutdown_state)
+ndctl_cmd_get_field(cmd, vendor_size)
+
+NDCTL_EXPORT unsigned char *ndctl_cmd_smart_get_vendor_data(struct ndctl_cmd *cmd)
+{
+ struct nd_smart_payload *smart_data;
+
+ if (smart_valid(cmd) < 0)
+ return NULL;
+ smart_data = (struct nd_smart_payload *) cmd->smart->data;
+ return (unsigned char *) smart_data->vendor_data;
+}
diff --git a/lib/libndctl.c b/lib/libndctl.c
index 26de91af8a63..c25107f3eba7 100644
--- a/lib/libndctl.c
+++ b/lib/libndctl.c
@@ -26,6 +26,7 @@
#include <ccan/list/list.h>
#include <ccan/minmax/minmax.h>
#include <ccan/array_size/array_size.h>
+#include <ccan/build_assert/build_assert.h>
#ifdef HAVE_NDCTL_H
#include <linux/ndctl.h>
diff --git a/lib/libndctl.sym b/lib/libndctl.sym
index 5ff8848ee6d3..2a0d36d89f67 100644
--- a/lib/libndctl.sym
+++ b/lib/libndctl.sym
@@ -86,6 +86,16 @@ global:
ndctl_dimm_cmd_new_cfg_size;
ndctl_dimm_cmd_new_cfg_read;
ndctl_dimm_cmd_new_cfg_write;
+ ndctl_dimm_cmd_new_smart;
+ ndctl_cmd_smart_get_flags;
+ ndctl_cmd_smart_get_health;
+ ndctl_cmd_smart_get_temperature;
+ ndctl_cmd_smart_get_spares;
+ ndctl_cmd_smart_get_alarm_flags;
+ ndctl_cmd_smart_get_life_used;
+ ndctl_cmd_smart_get_shutdown_state;
+ ndctl_cmd_smart_get_vendor_size;
+ ndctl_cmd_smart_get_vendor_data;
ndctl_dimm_zero_labels;
ndctl_dimm_get_available_labels;
ndctl_region_get_first;
diff --git a/lib/ndctl/libndctl.h.in b/lib/ndctl/libndctl.h.in
index 2a05e0ba477c..37527a7251ff 100644
--- a/lib/ndctl/libndctl.h.in
+++ b/lib/ndctl/libndctl.h.in
@@ -252,6 +252,61 @@ static inline unsigned long long ndctl_cmd_clear_error_get_cleared(
}
#endif
+#define HAS_SMART HAVE_NDCTL_SMART
+#if HAS_SMART == 1
+struct ndctl_cmd *ndctl_dimm_cmd_new_smart(struct ndctl_dimm *dimm);
+unsigned int ndctl_cmd_smart_get_flags(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_health(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_temperature(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_spares(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_alarm_flags(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_life_used(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_shutdown_state(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_vendor_size(struct ndctl_cmd *cmd);
+unsigned char *ndctl_cmd_smart_get_vendor_data(struct ndctl_cmd *cmd);
+#else
+static inline struct ndctl_cmd *ndctl_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
+{
+ return NULL;
+}
+static inline unsigned int ndctl_cmd_smart_get_flags(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_health(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_temperature(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_spares(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_alarm_flags(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_life_used(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_shutdown_state(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_vendor_size(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned char *ndctl_cmd_smart_get_vendor_data(struct ndctl_cmd *cmd)
+{
+ return NULL;
+}
+#endif
+
struct ndctl_cmd *ndctl_dimm_cmd_new_vendor_specific(struct ndctl_dimm *dimm,
unsigned int opcode, size_t input_size, size_t output_size);
ssize_t ndctl_cmd_vendor_set_input(struct ndctl_cmd *cmd, void *buf,
diff --git a/ndctl.h b/ndctl.h
index 69b8e707fc49..445b4d6d4df0 100644
--- a/ndctl.h
+++ b/ndctl.h
@@ -20,6 +20,35 @@ struct nd_cmd_smart {
__u8 data[128];
} __attribute__((packed));
+enum {
+ ND_SMART_HEALTH_VALID = 1 << 0,
+ ND_SMART_TEMP_VALID = 1 << 1,
+ ND_SMART_SPARES_VALID = 1 << 2,
+ ND_SMART_ALARM_VALID = 1 << 3,
+ ND_SMART_USED_VALID = 1 << 4,
+ ND_SMART_SHUTDOWN_VALID = 1 << 5,
+ ND_SMART_VENDOR_VALID = 1 << 6,
+ ND_SMART_TEMP_TRIP = 1 << 0,
+ ND_SMART_SPARE_TRIP = 1 << 1,
+ ND_SMART_NON_CRITICAL_HEALTH = 1 << 0,
+ ND_SMART_CRITICAL_HEALTH = 1 << 1,
+ ND_SMART_FATAL_HEALTH = 1 << 2,
+};
+
+struct nd_smart_payload {
+ __u32 flags;
+ __u8 reserved0[4];
+ __u8 health;
+ __u16 temperature;
+ __u8 spares;
+ __u8 alarm_flags;
+ __u8 life_used;
+ __u8 shutdown_state;
+ __u8 reserved1;
+ __u32 vendor_size;
+ __u8 vendor_data[108];
+} __attribute__((packed));
+
struct nd_cmd_smart_threshold {
__u32 status;
__u8 data[8];
diff --git a/test/libndctl.c b/test/libndctl.c
index 0e9c830e68a1..11c05f590ad7 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -377,7 +377,7 @@ static struct region regions1[] = {
static unsigned long dimm_commands0 = 1UL << ND_CMD_GET_CONFIG_SIZE
| 1UL << ND_CMD_GET_CONFIG_DATA
- | 1UL << ND_CMD_SET_CONFIG_DATA;
+ | 1UL << ND_CMD_SET_CONFIG_DATA | 1UL << ND_CMD_SMART;
static unsigned long bus_commands0 = 1UL << ND_CMD_ARS_CAP
| 1UL << ND_CMD_ARS_START
@@ -1586,6 +1586,71 @@ static int check_set_config_data(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
return 0;
}
+#ifdef HAVE_NDCTL_SMART
+#define __check_smart(dimm, cmd, field) ({ \
+ if (ndctl_cmd_smart_get_##field(cmd) != smart_data.field) { \
+ fprintf(stderr, "%s dimm: %#x expected field %#x got: %#x\n", \
+ __func__, ndctl_dimm_get_handle(dimm), \
+ smart_data.field, \
+ ndctl_cmd_smart_get_##field(cmd)); \
+ ndctl_cmd_unref(cmd); \
+ return -ENXIO; \
+ } \
+})
+
+static int check_smart(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
+ struct check_cmd *check)
+{
+ static const struct nd_smart_payload smart_data = {
+ .flags = ND_SMART_HEALTH_VALID | ND_SMART_TEMP_VALID
+ | ND_SMART_SPARES_VALID | ND_SMART_ALARM_VALID
+ | ND_SMART_USED_VALID | ND_SMART_SHUTDOWN_VALID,
+ .health = ND_SMART_NON_CRITICAL_HEALTH,
+ .temperature = 23 * 16,
+ .spares = 75,
+ .alarm_flags = ND_SMART_SPARE_TRIP | ND_SMART_TEMP_TRIP,
+ .life_used = 5,
+ .shutdown_state = 0,
+ .vendor_size = 0,
+ };
+ struct ndctl_cmd *cmd = ndctl_dimm_cmd_new_smart(dimm);
+ int rc;
+
+ if (!cmd) {
+ fprintf(stderr, "%s: dimm: %#x failed to create cmd\n",
+ __func__, ndctl_dimm_get_handle(dimm));
+ return -ENXIO;
+ }
+
+ rc = ndctl_cmd_submit(cmd);
+ if (rc) {
+ fprintf(stderr, "%s: dimm: %#x failed to submit cmd: %d\n",
+ __func__, ndctl_dimm_get_handle(dimm), rc);
+ ndctl_cmd_unref(cmd);
+ return rc;
+ }
+
+ __check_smart(dimm, cmd, flags);
+ __check_smart(dimm, cmd, health);
+ __check_smart(dimm, cmd, temperature);
+ __check_smart(dimm, cmd, spares);
+ __check_smart(dimm, cmd, alarm_flags);
+ __check_smart(dimm, cmd, life_used);
+ __check_smart(dimm, cmd, shutdown_state);
+ __check_smart(dimm, cmd, vendor_size);
+
+ ndctl_cmd_unref(cmd);
+ return 0;
+}
+#else
+static int check_smart(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
+ struct check_cmd *check)
+{
+ fprintf(stderr, "%s: HAVE_NDCTL_SMART disabled, skipping\n", __func__);
+ return 0;
+}
+#endif
+
#ifdef HAVE_NDCTL_ARS
static int check_ars_cap(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
struct check_cmd *check)
@@ -1808,6 +1873,7 @@ static int check_commands(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
[ND_CMD_GET_CONFIG_SIZE] = { check_get_config_size },
[ND_CMD_GET_CONFIG_DATA] = { check_get_config_data },
[ND_CMD_SET_CONFIG_DATA] = { check_set_config_data },
+ [ND_CMD_SMART] = { check_smart },
[ND_CMD_SMART_THRESHOLD] = { },
};
static struct check_cmd __check_bus_cmds[] = {
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [ndctl PATCH 3/5] ndctl, list: clean up default behavior
2016-04-07 1:06 [ndctl PATCH 0/5] smart support and 'list' enhancements Dan Williams
2016-04-07 1:07 ` [ndctl PATCH 1/5] ndctl: rebuild libndctl.h when libndctl.h.in changes Dan Williams
2016-04-07 1:07 ` [ndctl PATCH 2/5] ndctl: helper for S.M.A.R.T. data retrieval Dan Williams
@ 2016-04-07 1:07 ` Dan Williams
2016-04-07 8:38 ` Johannes Thumshirn
2016-04-07 1:07 ` [ndctl PATCH 4/5] ndctl, list: add a '--health' option Dan Williams
2016-04-07 1:07 ` [ndctl PATCH 5/5] ndctl, list: add 'filter by dimm' capability Dan Williams
4 siblings, 1 reply; 16+ messages in thread
From: Dan Williams @ 2016-04-07 1:07 UTC (permalink / raw)
To: linux-nvdimm
Only list namespaces by default when no other option is specified.
Otherwise, to limit the listing to dimm info a user would need to run:
ndctl list --dimms --no-namespaces
...with the change this is reduced to:
ndctl list --dimms
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Documentation/ndctl-list.txt | 2 +-
builtin-list.c | 7 ++++---
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/Documentation/ndctl-list.txt b/Documentation/ndctl-list.txt
index abf3ff07cfa9..806548196118 100644
--- a/Documentation/ndctl-list.txt
+++ b/Documentation/ndctl-list.txt
@@ -79,7 +79,7 @@ include::xable-region-options.txt[]
-N::
--namespaces::
Include namespace info in the listing. Namespace info is
- included by default, specify '--no-namespaces' to omit.
+ listed by default if no other options are specified to the command.
-i::
--idle::
diff --git a/builtin-list.c b/builtin-list.c
index 413b36ac0208..df0871ab544a 100644
--- a/builtin-list.c
+++ b/builtin-list.c
@@ -22,9 +22,7 @@ static struct {
bool regions;
bool namespaces;
bool idle;
-} list = {
- .namespaces = true,
-};
+} list;
static struct {
const char *bus;
@@ -222,6 +220,9 @@ int cmd_list(int argc, const char **argv)
unsigned int type = 0;
int i, rc;
+ if (argc == 1)
+ list.namespaces = true;
+
argc = parse_options(argc, argv, options, u, 0);
for (i = 0; i < argc; i++)
error("unknown parameter \"%s\"\n", argv[i]);
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [ndctl PATCH 4/5] ndctl, list: add a '--health' option
2016-04-07 1:06 [ndctl PATCH 0/5] smart support and 'list' enhancements Dan Williams
` (2 preceding siblings ...)
2016-04-07 1:07 ` [ndctl PATCH 3/5] ndctl, list: clean up default behavior Dan Williams
@ 2016-04-07 1:07 ` Dan Williams
2016-04-07 8:41 ` Johannes Thumshirn
2016-04-07 22:42 ` [ndctl PATCH v2] " Dan Williams
2016-04-07 1:07 ` [ndctl PATCH 5/5] ndctl, list: add 'filter by dimm' capability Dan Williams
4 siblings, 2 replies; 16+ messages in thread
From: Dan Williams @ 2016-04-07 1:07 UTC (permalink / raw)
To: linux-nvdimm
Dump dimm smart data in the dimm listing when '--health' is specified.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Documentation/ndctl-list.txt | 19 ++++++++
builtin-list.c | 11 +++++
util/json.c | 97 ++++++++++++++++++++++++++++++++++++++++++
util/json.h | 1
4 files changed, 127 insertions(+), 1 deletion(-)
diff --git a/Documentation/ndctl-list.txt b/Documentation/ndctl-list.txt
index 806548196118..36398aa34b42 100644
--- a/Documentation/ndctl-list.txt
+++ b/Documentation/ndctl-list.txt
@@ -3,7 +3,7 @@ ndctl-list(1)
NAME
----
-ndctl-list - dump the platform nvdimm device topology in json
+ndctl-list - dump the platform nvdimm device topology and attributes in json
SYNOPSIS
--------
@@ -72,6 +72,23 @@ include::xable-region-options.txt[]
--dimms::
Include dimm info in the listing
+-H::
+--health::
+ Include dimm health info in the listing. For example:
+[verse]
+{
+ "dev":"nmem0",
+ "health":{
+ "health_state":"non-critical",
+ "temperature_celsius":23,
+ "spares_percentage":75,
+ "alarm_temperature":true,
+ "alarm_spares":true,
+ "life_used_percentage":5,
+ "shutdown_state":"clean"
+ }
+}
+
-R::
--regions::
Include region info in the listing
diff --git a/builtin-list.c b/builtin-list.c
index df0871ab544a..8b65767c37be 100644
--- a/builtin-list.c
+++ b/builtin-list.c
@@ -22,6 +22,7 @@ static struct {
bool regions;
bool namespaces;
bool idle;
+ bool health;
} list;
static struct {
@@ -200,6 +201,7 @@ int cmd_list(int argc, const char **argv)
"filter by region-type"),
OPT_BOOLEAN('B', "buses", &list.buses, "include bus info"),
OPT_BOOLEAN('D', "dimms", &list.dimms, "include dimm info"),
+ OPT_BOOLEAN('H', "health", &list.health, "include dimm health"),
OPT_BOOLEAN('R', "regions", &list.regions,
"include region info"),
OPT_BOOLEAN('N', "namespaces", &list.namespaces,
@@ -299,6 +301,15 @@ int cmd_list(int argc, const char **argv)
continue;
}
+ if (list.health) {
+ struct json_object *jhealth;
+
+ jhealth = util_dimm_health_to_json(dimm);
+ if (jhealth)
+ json_object_object_add(jdimm, "health",
+ jhealth);
+ }
+
/*
* Without a bus we are collecting dimms anonymously
* across the platform.
diff --git a/util/json.c b/util/json.c
index 288efee723ff..6e61372e4f69 100644
--- a/util/json.c
+++ b/util/json.c
@@ -61,6 +61,103 @@ struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm)
return NULL;
}
+struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm)
+{
+ struct json_object *jhealth = json_object_new_object();
+ struct json_object *jobj;
+ struct ndctl_cmd *cmd;
+ unsigned int flags;
+ int rc;
+
+ if (!jhealth)
+ return NULL;
+
+ cmd = ndctl_dimm_cmd_new_smart(dimm);
+ if (!cmd)
+ goto err;
+
+ rc = ndctl_cmd_submit(cmd);
+ if (rc || ndctl_cmd_get_firmware_status(cmd))
+ goto err;
+
+ flags = ndctl_cmd_smart_get_flags(cmd);
+ if (flags & ND_SMART_HEALTH_VALID) {
+ unsigned int health = ndctl_cmd_smart_get_health(cmd);
+
+ if (health & ND_SMART_FATAL_HEALTH)
+ jobj = json_object_new_string("fatal");
+ else if (health & ND_SMART_CRITICAL_HEALTH)
+ jobj = json_object_new_string("critical");
+ else if (health & ND_SMART_NON_CRITICAL_HEALTH)
+ jobj = json_object_new_string("non-critical");
+ else
+ jobj = json_object_new_string("ok");
+ if (jobj)
+ json_object_object_add(jhealth, "health_state", jobj);
+ }
+
+ if (flags & ND_SMART_TEMP_VALID) {
+ unsigned int temp = ndctl_cmd_smart_get_temperature(cmd);
+ bool negative = !!(temp & (1 << 15));
+ double t;
+
+ temp &= ~(1 << 15);
+ t = (double) temp / 16;
+ if (negative)
+ t *= -1;
+ jobj = json_object_new_double(t);
+ if (jobj)
+ json_object_object_add(jhealth, "temperature_celsius", jobj);
+ }
+
+ if (flags & ND_SMART_SPARES_VALID) {
+ unsigned int spares = ndctl_cmd_smart_get_spares(cmd);
+
+ jobj = json_object_new_int(spares);
+ if (jobj)
+ json_object_object_add(jhealth, "spares_percentage", jobj);
+ }
+
+ if (flags & ND_SMART_ALARM_VALID) {
+ unsigned int alarm_flags = ndctl_cmd_smart_get_spares(cmd);
+ bool temp_flag = !!(alarm_flags & ND_SMART_TEMP_TRIP);
+ bool spares_flag = !!(alarm_flags & ND_SMART_SPARE_TRIP);
+
+ jobj = json_object_new_boolean(temp_flag);
+ if (jobj)
+ json_object_object_add(jhealth, "alarm_temperature", jobj);
+
+ jobj = json_object_new_boolean(spares_flag);
+ if (jobj)
+ json_object_object_add(jhealth, "alarm_spares", jobj);
+ }
+
+ if (flags & ND_SMART_USED_VALID) {
+ unsigned int life_used = ndctl_cmd_smart_get_life_used(cmd);
+
+ jobj = json_object_new_int(life_used);
+ if (jobj)
+ json_object_object_add(jhealth, "life_used_percentage", jobj);
+ }
+
+ if (flags & ND_SMART_SHUTDOWN_VALID) {
+ unsigned int shutdown = ndctl_cmd_smart_get_shutdown_state(cmd);
+
+ jobj = json_object_new_string(shutdown ? "dirty" : "clean");
+ if (jobj)
+ json_object_object_add(jhealth, "shutdown_state", jobj);
+ }
+
+ ndctl_cmd_unref(cmd);
+ return jhealth;
+ err:
+ json_object_put(jhealth);
+ if (cmd)
+ ndctl_cmd_unref(cmd);
+ return NULL;
+}
+
+
bool util_namespace_active(struct ndctl_namespace *ndns)
{
struct ndctl_btt *btt = ndctl_namespace_get_btt(ndns);
diff --git a/util/json.h b/util/json.h
index 653bbd9beef1..79962cacc35c 100644
--- a/util/json.h
+++ b/util/json.h
@@ -6,6 +6,7 @@
bool util_namespace_active(struct ndctl_namespace *ndns);
struct json_object *util_bus_to_json(struct ndctl_bus *bus);
struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm);
+struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm);
struct json_object *util_mapping_to_json(struct ndctl_mapping *mapping);
struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns);
#endif /* __NDCTL_JSON_H__ */
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [ndctl PATCH 5/5] ndctl, list: add 'filter by dimm' capability
2016-04-07 1:06 [ndctl PATCH 0/5] smart support and 'list' enhancements Dan Williams
` (3 preceding siblings ...)
2016-04-07 1:07 ` [ndctl PATCH 4/5] ndctl, list: add a '--health' option Dan Williams
@ 2016-04-07 1:07 ` Dan Williams
2016-04-07 8:42 ` Johannes Thumshirn
4 siblings, 1 reply; 16+ messages in thread
From: Dan Williams @ 2016-04-07 1:07 UTC (permalink / raw)
To: linux-nvdimm
This is to support scenarios where the user is searching for information
relative to a given dimm. For example if a dimm is faltering, this
command can show all the namespaces impacted if the dimm failed:
ndctl list -d nmem0 -N
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Documentation/ndctl-list.txt | 8 ++++
builtin-list.c | 13 ++++++-
util/filter.c | 83 ++++++++++++++++++++++++++++++++++++++++++
util/filter.h | 5 +++
4 files changed, 107 insertions(+), 2 deletions(-)
diff --git a/Documentation/ndctl-list.txt b/Documentation/ndctl-list.txt
index 36398aa34b42..0a23ea130a1e 100644
--- a/Documentation/ndctl-list.txt
+++ b/Documentation/ndctl-list.txt
@@ -60,6 +60,14 @@ OPTIONS
--region=::
include::xable-region-options.txt[]
+-d::
+--dimm=::
+ An 'nmemX' device name, or dimm id number. Filter listing by
+ devices that reference the given dimm. For example to see all
+ namespaces comprised of storage capacity on nmem0:
+[verse]
+# ndctl list --dimm=nmem0 --namespaces
+
-t::
--type=::
Filter listing by region type ('pmem' or 'blk')
diff --git a/builtin-list.c b/builtin-list.c
index 8b65767c37be..885f61297a3c 100644
--- a/builtin-list.c
+++ b/builtin-list.c
@@ -29,6 +29,7 @@ static struct {
const char *bus;
const char *region;
const char *type;
+ const char *dimm;
} param;
static int did_fail;
@@ -197,6 +198,8 @@ int cmd_list(int argc, const char **argv)
OPT_STRING('b', "bus", ¶m.bus, "bus-id", "filter by bus"),
OPT_STRING('r', "region", ¶m.region, "region-id",
"filter by region"),
+ OPT_STRING('d', "dimm", ¶m.dimm, "dimm-id",
+ "filter by dimm"),
OPT_STRING('t', "type", ¶m.type, "region-type",
"filter by region-type"),
OPT_BOOLEAN('B', "buses", &list.buses, "include bus info"),
@@ -254,7 +257,8 @@ int cmd_list(int argc, const char **argv)
struct ndctl_region *region;
struct ndctl_dimm *dimm;
- if (!util_bus_filter(bus, param.bus))
+ if (!util_bus_filter(bus, param.bus)
+ || !util_bus_filter_by_dimm(bus, param.dimm))
continue;
if (list.buses) {
@@ -281,6 +285,9 @@ int cmd_list(int argc, const char **argv)
if (!list.dimms)
break;
+ if (!util_dimm_filter(dimm, param.dimm))
+ continue;
+
if (!list.idle && !ndctl_dimm_is_enabled(dimm))
continue;
@@ -320,7 +327,9 @@ int cmd_list(int argc, const char **argv)
ndctl_region_foreach(bus, region) {
struct json_object *jregion;
- if (!util_region_filter(region, param.region))
+ if (!util_region_filter(region, param.region)
+ || !util_region_filter_by_dimm(region,
+ param.dimm))
continue;
if (type && ndctl_region_get_type(region) != type)
diff --git a/util/filter.c b/util/filter.c
index 8c8dbf1a8887..ea0f4dd2da13 100644
--- a/util/filter.c
+++ b/util/filter.c
@@ -54,3 +54,86 @@ struct ndctl_region *util_region_filter(struct ndctl_region *region,
return NULL;
}
+
+struct ndctl_dimm *util_dimm_filter(struct ndctl_dimm *dimm, const char *ident)
+{
+ char *end = NULL;
+ const char *name;
+ unsigned long dimm_id, id;
+
+ if (!ident || strcmp(ident, "all") == 0)
+ return dimm;
+
+ dimm_id = strtoul(ident, &end, 0);
+ if (end == ident || end[0])
+ dimm_id = ULONG_MAX;
+
+ name = ndctl_dimm_get_devname(dimm);
+ id = ndctl_dimm_get_id(dimm);
+
+ if (dimm_id < ULONG_MAX && dimm_id == id)
+ return dimm;
+
+ if (dimm_id == ULONG_MAX && strcmp(ident, name) == 0)
+ return dimm;
+
+ return NULL;
+}
+
+struct ndctl_bus *util_bus_filter_by_dimm(struct ndctl_bus *bus,
+ const char *ident)
+{
+ char *end = NULL;
+ const char *name;
+ struct ndctl_dimm *dimm;
+ unsigned long dimm_id, id;
+
+ if (!ident || strcmp(ident, "all") == 0)
+ return bus;
+
+ dimm_id = strtoul(ident, &end, 0);
+ if (end == ident || end[0])
+ dimm_id = ULONG_MAX;
+
+ ndctl_dimm_foreach(bus, dimm) {
+ id = ndctl_dimm_get_id(dimm);
+ name = ndctl_dimm_get_devname(dimm);
+
+ if (dimm_id < ULONG_MAX && dimm_id == id)
+ return bus;
+
+ if (dimm_id == ULONG_MAX && strcmp(ident, name) == 0)
+ return bus;
+ }
+
+ return NULL;
+}
+
+struct ndctl_region *util_region_filter_by_dimm(struct ndctl_region *region,
+ const char *ident)
+{
+ char *end = NULL;
+ const char *name;
+ struct ndctl_dimm *dimm;
+ unsigned long dimm_id, id;
+
+ if (!ident || strcmp(ident, "all") == 0)
+ return region;
+
+ dimm_id = strtoul(ident, &end, 0);
+ if (end == ident || end[0])
+ dimm_id = ULONG_MAX;
+
+ ndctl_dimm_foreach_in_region(region, dimm) {
+ id = ndctl_dimm_get_id(dimm);
+ name = ndctl_dimm_get_devname(dimm);
+
+ if (dimm_id < ULONG_MAX && dimm_id == id)
+ return region;
+
+ if (dimm_id == ULONG_MAX && strcmp(ident, name) == 0)
+ return region;
+ }
+
+ return NULL;
+}
diff --git a/util/filter.h b/util/filter.h
index bc5c2557a65c..17ce895425fb 100644
--- a/util/filter.h
+++ b/util/filter.h
@@ -3,4 +3,9 @@
struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *ident);
struct ndctl_region *util_region_filter(struct ndctl_region *region,
const char *ident);
+struct ndctl_dimm *util_dimm_filter(struct ndctl_dimm *dimm, const char *ident);
+struct ndctl_bus *util_bus_filter_by_dimm(struct ndctl_bus *bus,
+ const char *ident);
+struct ndctl_region *util_region_filter_by_dimm(struct ndctl_region *region,
+ const char *ident);
#endif
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [ndctl PATCH 1/5] ndctl: rebuild libndctl.h when libndctl.h.in changes
2016-04-07 1:07 ` [ndctl PATCH 1/5] ndctl: rebuild libndctl.h when libndctl.h.in changes Dan Williams
@ 2016-04-07 8:29 ` Johannes Thumshirn
0 siblings, 0 replies; 16+ messages in thread
From: Johannes Thumshirn @ 2016-04-07 8:29 UTC (permalink / raw)
To: linux-nvdimm
On Mittwoch, 6. April 2016 18:07:04 CEST Dan Williams wrote:
> Since libnctl.h is build via an AC_CONFIG_COMMANDS() statement we want
> configure to re-run if libndctl.h.in is changed.
>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
Looks good,
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
--
Johannes Thumshirn Storage
jthumshirn@suse.de +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [ndctl PATCH 2/5] ndctl: helper for S.M.A.R.T. data retrieval
2016-04-07 1:07 ` [ndctl PATCH 2/5] ndctl: helper for S.M.A.R.T. data retrieval Dan Williams
@ 2016-04-07 8:36 ` Johannes Thumshirn
2016-04-07 22:39 ` [ndctl PATCH v2] " Dan Williams
1 sibling, 0 replies; 16+ messages in thread
From: Johannes Thumshirn @ 2016-04-07 8:36 UTC (permalink / raw)
To: linux-nvdimm
On Mittwoch, 6. April 2016 18:07:09 CEST Dan Williams wrote:
> Helper functions to issue the "SMART and Health Info (Function Index 1)"
> DSM and parse its results.
>
> http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
[...]
>
> +enum {
> + ND_SMART_HEALTH_VALID = 1 << 0,
> + ND_SMART_TEMP_VALID = 1 << 1,
> + ND_SMART_SPARES_VALID = 1 << 2,
> + ND_SMART_ALARM_VALID = 1 << 3,
> + ND_SMART_USED_VALID = 1 << 4,
> + ND_SMART_SHUTDOWN_VALID = 1 << 5,
> + ND_SMART_VENDOR_VALID = 1 << 6,
> + ND_SMART_TEMP_TRIP = 1 << 0,
> + ND_SMART_SPARE_TRIP = 1 << 1,
> + ND_SMART_NON_CRITICAL_HEALTH = 1 << 0,
> + ND_SMART_CRITICAL_HEALTH = 1 << 1,
> + ND_SMART_FATAL_HEALTH = 1 << 2,
> +};
Same applies here.
--
Johannes Thumshirn Storage
jthumshirn@suse.de +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [ndctl PATCH 3/5] ndctl, list: clean up default behavior
2016-04-07 1:07 ` [ndctl PATCH 3/5] ndctl, list: clean up default behavior Dan Williams
@ 2016-04-07 8:38 ` Johannes Thumshirn
0 siblings, 0 replies; 16+ messages in thread
From: Johannes Thumshirn @ 2016-04-07 8:38 UTC (permalink / raw)
To: linux-nvdimm
On Mittwoch, 6. April 2016 18:07:14 CEST Dan Williams wrote:
> Only list namespaces by default when no other option is specified.
> Otherwise, to limit the listing to dimm info a user would need to run:
>
> ndctl list --dimms --no-namespaces
>
> ...with the change this is reduced to:
>
> ndctl list --dimms
>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
Looks good,
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
--
Johannes Thumshirn Storage
jthumshirn@suse.de +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [ndctl PATCH 4/5] ndctl, list: add a '--health' option
2016-04-07 1:07 ` [ndctl PATCH 4/5] ndctl, list: add a '--health' option Dan Williams
@ 2016-04-07 8:41 ` Johannes Thumshirn
2016-04-07 13:16 ` Dan Williams
2016-04-07 22:42 ` [ndctl PATCH v2] " Dan Williams
1 sibling, 1 reply; 16+ messages in thread
From: Johannes Thumshirn @ 2016-04-07 8:41 UTC (permalink / raw)
To: linux-nvdimm
On Mittwoch, 6. April 2016 18:07:20 CEST Dan Williams wrote:
> Dump dimm smart data in the dimm listing when '--health' is specified.
>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
[...]
> @@ -200,6 +201,7 @@ int cmd_list(int argc, const char **argv)
> "filter by region-type"),
> OPT_BOOLEAN('B', "buses", &list.buses, "include bus info"),
> OPT_BOOLEAN('D', "dimms", &list.dimms, "include dimm info"),
> + OPT_BOOLEAN('H', "health", &list.health, "include dimm health"),
> OPT_BOOLEAN('R', "regions", &list.regions,
> "include region info"),
> OPT_BOOLEAN('N', "namespaces", &list.namespaces,
> @@ -299,6 +301,15 @@ int cmd_list(int argc, const char **argv)
> continue;
> }
>
> + if (list.health) {
> + struct json_object *jhealth;
> +
> + jhealth = util_dimm_health_to_json(dimm);
> + if (jhealth)
> + json_object_object_add(jdimm, "health",
> + jhealth);
Maybe some sort of error message for the else path? Either here or in
util_dimm_health_to_json()?
--
Johannes Thumshirn Storage
jthumshirn@suse.de +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [ndctl PATCH 5/5] ndctl, list: add 'filter by dimm' capability
2016-04-07 1:07 ` [ndctl PATCH 5/5] ndctl, list: add 'filter by dimm' capability Dan Williams
@ 2016-04-07 8:42 ` Johannes Thumshirn
0 siblings, 0 replies; 16+ messages in thread
From: Johannes Thumshirn @ 2016-04-07 8:42 UTC (permalink / raw)
To: linux-nvdimm
On Mittwoch, 6. April 2016 18:07:25 CEST Dan Williams wrote:
> This is to support scenarios where the user is searching for information
> relative to a given dimm. For example if a dimm is faltering, this
> command can show all the namespaces impacted if the dimm failed:
>
> ndctl list -d nmem0 -N
>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
Looks good,
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
--
Johannes Thumshirn Storage
jthumshirn@suse.de +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [ndctl PATCH 4/5] ndctl, list: add a '--health' option
2016-04-07 8:41 ` Johannes Thumshirn
@ 2016-04-07 13:16 ` Dan Williams
0 siblings, 0 replies; 16+ messages in thread
From: Dan Williams @ 2016-04-07 13:16 UTC (permalink / raw)
To: Johannes Thumshirn; +Cc: linux-nvdimm@lists.01.org
On Thu, Apr 7, 2016 at 1:41 AM, Johannes Thumshirn <jthumshirn@suse.de> wrote:
> On Mittwoch, 6. April 2016 18:07:20 CEST Dan Williams wrote:
>> Dump dimm smart data in the dimm listing when '--health' is specified.
>>
>> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
>> ---
>
> [...]
>
>> @@ -200,6 +201,7 @@ int cmd_list(int argc, const char **argv)
>> "filter by region-type"),
>> OPT_BOOLEAN('B', "buses", &list.buses, "include bus info"),
>> OPT_BOOLEAN('D', "dimms", &list.dimms, "include dimm info"),
>> + OPT_BOOLEAN('H', "health", &list.health, "include dimm health"),
>> OPT_BOOLEAN('R', "regions", &list.regions,
>> "include region info"),
>> OPT_BOOLEAN('N', "namespaces", &list.namespaces,
>> @@ -299,6 +301,15 @@ int cmd_list(int argc, const char **argv)
>> continue;
>> }
>>
>> + if (list.health) {
>> + struct json_object *jhealth;
>> +
>> + jhealth = util_dimm_health_to_json(dimm);
>> + if (jhealth)
>> + json_object_object_add(jdimm, "health",
>> + jhealth);
>
> Maybe some sort of error message for the else path? Either here or in
> util_dimm_health_to_json()?
Yeah, I wasn't sure how to differentiate "dimm does not support smart"
vs "dimm smart data retrieval failed" in this routine. However,
you're right a debug message at a minimum is needed.
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 16+ messages in thread
* [ndctl PATCH v2] ndctl: helper for S.M.A.R.T. data retrieval
2016-04-07 1:07 ` [ndctl PATCH 2/5] ndctl: helper for S.M.A.R.T. data retrieval Dan Williams
2016-04-07 8:36 ` Johannes Thumshirn
@ 2016-04-07 22:39 ` Dan Williams
2016-04-08 7:23 ` Johannes Thumshirn
1 sibling, 1 reply; 16+ messages in thread
From: Dan Williams @ 2016-04-07 22:39 UTC (permalink / raw)
To: linux-nvdimm
Helper functions to issue the "SMART and Health Info (Function Index 1)"
DSM and parse its results.
http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Changes in v2:
* pull in the updated ndctl.h from the kernel (jth)
* add helper routines for issuing smart threshold commands
* extend the unit test to validate smart threshold data passthrough
Makefile.am | 4 +
configure.ac | 26 +++++++++
lib/libndctl-private.h | 2 +
lib/libndctl-smart.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++
lib/libndctl.c | 1
lib/libndctl.sym | 14 +++++
lib/ndctl/libndctl.h.in | 75 ++++++++++++++++++++++++++
ndctl.h | 34 ++++++++++++
test/libndctl.c | 122 ++++++++++++++++++++++++++++++++++++++++++-
9 files changed, 410 insertions(+), 2 deletions(-)
create mode 100644 lib/libndctl-smart.c
diff --git a/Makefile.am b/Makefile.am
index 379f6404671f..9c6b37410642 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -85,6 +85,10 @@ if ENABLE_ARS
lib_libndctl_la_SOURCES += lib/libndctl-ars.c
endif
+if ENABLE_SMART
+lib_libndctl_la_SOURCES += lib/libndctl-smart.c
+endif
+
bin_PROGRAMS = ndctl
ndctl_SOURCES = ndctl.c \
diff --git a/configure.ac b/configure.ac
index 1ab376885215..01f347a7f137 100644
--- a/configure.ac
+++ b/configure.ac
@@ -144,6 +144,25 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
)
AM_CONDITIONAL([ENABLE_CLEAR_ERROR], [test "x$enable_clear_err" = "xyes"])
+AC_MSG_CHECKING([for SMART support])
+AC_LANG(C)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #ifdef HAVE_NDCTL_H
+ #include <linux/ndctl.h>
+ #else
+ #include "ndctl.h"
+ #endif
+ ]], [[
+ int x = ND_SMART_HEALTH_VALID;
+ ]]
+ )], [AC_MSG_RESULT([yes])
+ enable_smart=yes
+ AC_DEFINE([HAVE_NDCTL_SMART], [1],
+ [Define to 1 if ndctl.h has SMART support.])
+ ], [AC_MSG_RESULT([no])]
+)
+AM_CONDITIONAL([ENABLE_SMART], [test "x$enable_smart" = "xyes"])
+
AC_CONFIG_COMMANDS([gen-libndctl.h],
[[
if test "x$enable_ars" = "xyes"; then
@@ -151,17 +170,24 @@ AC_CONFIG_COMMANDS([gen-libndctl.h],
else
enable_ars=0
fi
+ if test "x$enable_smart" = "xyes"; then
+ enable_smart=1
+ else
+ enable_smart=0
+ fi
if test "x$enable_clear_err" = "xyes"; then
enable_clear_err=1
else
enable_clear_err=0
fi
sed -e s/HAVE_NDCTL_ARS/$enable_ars/ \
+ -e s/HAVE_NDCTL_SMART/$enable_smart/ \
-e s/HAVE_NDCTL_CLEAR_ERROR/$enable_clear_err/ \
< lib/ndctl/libndctl.h.in > lib/ndctl/libndctl.h
]],
[[
enable_ars=$enable_ars
+ enable_smart=$enable_smart
enable_clear_err=$enable_clear_err
]])
diff --git a/lib/libndctl-private.h b/lib/libndctl-private.h
index 50b03743751f..cbb0ed9f76b5 100644
--- a/lib/libndctl-private.h
+++ b/lib/libndctl-private.h
@@ -167,6 +167,8 @@ struct ndctl_cmd {
#ifdef HAVE_NDCTL_CLEAR_ERROR
struct nd_cmd_clear_error clear_err[0];
#endif
+ struct nd_cmd_smart smart[0];
+ struct nd_cmd_smart_threshold smart_t[0];
struct nd_cmd_get_config_size get_size[0];
struct nd_cmd_get_config_data_hdr get_data[0];
struct nd_cmd_set_config_hdr set_data[0];
diff --git a/lib/libndctl-smart.c b/lib/libndctl-smart.c
new file mode 100644
index 000000000000..e93ac8084892
--- /dev/null
+++ b/lib/libndctl-smart.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * 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.
+ */
+#include <stdlib.h>
+#include <limits.h>
+#include <ndctl/libndctl.h>
+#include "libndctl-private.h"
+
+NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
+{
+ struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm);
+ struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
+ struct ndctl_cmd *cmd;
+ size_t size;
+
+ BUILD_ASSERT(sizeof(struct nd_smart_payload) == 128);
+
+ if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_SMART)) {
+ dbg(ctx, "unsupported cmd\n");
+ return NULL;
+ }
+
+ size = sizeof(*cmd) + sizeof(struct nd_cmd_smart);
+ cmd = calloc(1, size);
+ if (!cmd)
+ return NULL;
+
+ cmd->dimm = dimm;
+ ndctl_cmd_ref(cmd);
+ cmd->type = ND_CMD_SMART;
+ cmd->size = size;
+ cmd->status = 1;
+ cmd->firmware_status = &cmd->smart->status;
+
+ return cmd;
+}
+
+static int smart_valid(struct ndctl_cmd *cmd)
+{
+ if (cmd->type != ND_CMD_SMART || cmd->status != 0)
+ return cmd->status < 0 ? cmd->status : -EINVAL;
+ return 0;
+}
+
+#define smart_get_field(cmd, field) \
+NDCTL_EXPORT unsigned int ndctl_cmd_smart_get_##field(struct ndctl_cmd *cmd) \
+{ \
+ struct nd_smart_payload *smart_data; \
+ if (smart_valid(cmd) < 0) \
+ return UINT_MAX; \
+ smart_data = (struct nd_smart_payload *) cmd->smart->data; \
+ return smart_data->field; \
+}
+
+smart_get_field(cmd, flags)
+smart_get_field(cmd, health)
+smart_get_field(cmd, temperature)
+smart_get_field(cmd, spares)
+smart_get_field(cmd, alarm_flags)
+smart_get_field(cmd, life_used)
+smart_get_field(cmd, shutdown_state)
+smart_get_field(cmd, vendor_size)
+
+NDCTL_EXPORT unsigned char *ndctl_cmd_smart_get_vendor_data(struct ndctl_cmd *cmd)
+{
+ struct nd_smart_payload *smart_data;
+
+ if (smart_valid(cmd) < 0)
+ return NULL;
+ smart_data = (struct nd_smart_payload *) cmd->smart->data;
+ return (unsigned char *) smart_data->vendor_data;
+}
+
+static int smart_threshold_valid(struct ndctl_cmd *cmd)
+{
+ if (cmd->type != ND_CMD_SMART_THRESHOLD || cmd->status != 0)
+ return cmd->status < 0 ? cmd->status : -EINVAL;
+ return 0;
+}
+
+#define smart_threshold_get_field(cmd, field) \
+NDCTL_EXPORT unsigned int ndctl_cmd_smart_threshold_get_##field( \
+ struct ndctl_cmd *cmd) \
+{ \
+ struct nd_smart_threshold_payload *smart_t_data; \
+ if (smart_threshold_valid(cmd) < 0) \
+ return UINT_MAX; \
+ smart_t_data = (struct nd_smart_threshold_payload *) \
+ cmd->smart_t->data; \
+ return smart_t_data->field; \
+}
+
+smart_threshold_get_field(cmd, alarm_control)
+smart_threshold_get_field(cmd, temperature)
+smart_threshold_get_field(cmd, spares)
+
+NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart_threshold(
+ struct ndctl_dimm *dimm)
+{
+ struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm);
+ struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
+ struct ndctl_cmd *cmd;
+ size_t size;
+
+ BUILD_ASSERT(sizeof(struct nd_smart_threshold_payload) == 8);
+
+ if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_SMART_THRESHOLD)) {
+ dbg(ctx, "unsupported cmd\n");
+ return NULL;
+ }
+
+ size = sizeof(*cmd) + sizeof(struct nd_cmd_smart_threshold);
+ cmd = calloc(1, size);
+ if (!cmd)
+ return NULL;
+
+ cmd->dimm = dimm;
+ ndctl_cmd_ref(cmd);
+ cmd->type = ND_CMD_SMART_THRESHOLD;
+ cmd->size = size;
+ cmd->status = 1;
+ cmd->firmware_status = &cmd->smart_t->status;
+
+ return cmd;
+}
diff --git a/lib/libndctl.c b/lib/libndctl.c
index 26de91af8a63..c25107f3eba7 100644
--- a/lib/libndctl.c
+++ b/lib/libndctl.c
@@ -26,6 +26,7 @@
#include <ccan/list/list.h>
#include <ccan/minmax/minmax.h>
#include <ccan/array_size/array_size.h>
+#include <ccan/build_assert/build_assert.h>
#ifdef HAVE_NDCTL_H
#include <linux/ndctl.h>
diff --git a/lib/libndctl.sym b/lib/libndctl.sym
index 5ff8848ee6d3..17a9085dd092 100644
--- a/lib/libndctl.sym
+++ b/lib/libndctl.sym
@@ -86,6 +86,20 @@ global:
ndctl_dimm_cmd_new_cfg_size;
ndctl_dimm_cmd_new_cfg_read;
ndctl_dimm_cmd_new_cfg_write;
+ ndctl_dimm_cmd_new_smart;
+ ndctl_cmd_smart_get_flags;
+ ndctl_cmd_smart_get_health;
+ ndctl_cmd_smart_get_temperature;
+ ndctl_cmd_smart_get_spares;
+ ndctl_cmd_smart_get_alarm_flags;
+ ndctl_cmd_smart_get_life_used;
+ ndctl_cmd_smart_get_shutdown_state;
+ ndctl_cmd_smart_get_vendor_size;
+ ndctl_cmd_smart_get_vendor_data;
+ ndctl_dimm_cmd_new_smart_threshold;
+ ndctl_cmd_smart_threshold_get_alarm_control;
+ ndctl_cmd_smart_threshold_get_temperature;
+ ndctl_cmd_smart_threshold_get_spares;
ndctl_dimm_zero_labels;
ndctl_dimm_get_available_labels;
ndctl_region_get_first;
diff --git a/lib/ndctl/libndctl.h.in b/lib/ndctl/libndctl.h.in
index 2a05e0ba477c..6c87155fd037 100644
--- a/lib/ndctl/libndctl.h.in
+++ b/lib/ndctl/libndctl.h.in
@@ -252,6 +252,81 @@ static inline unsigned long long ndctl_cmd_clear_error_get_cleared(
}
#endif
+#define HAS_SMART HAVE_NDCTL_SMART
+#if HAS_SMART == 1
+struct ndctl_cmd *ndctl_dimm_cmd_new_smart(struct ndctl_dimm *dimm);
+unsigned int ndctl_cmd_smart_get_flags(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_health(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_temperature(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_spares(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_alarm_flags(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_life_used(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_shutdown_state(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_vendor_size(struct ndctl_cmd *cmd);
+unsigned char *ndctl_cmd_smart_get_vendor_data(struct ndctl_cmd *cmd);
+struct ndctl_cmd *ndctl_dimm_cmd_new_smart_threshold(struct ndctl_dimm *dimm);
+unsigned int ndctl_cmd_smart_threshold_get_alarm_control(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_threshold_get_temperature(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_threshold_get_spares(struct ndctl_cmd *cmd);
+#else
+static inline struct ndctl_cmd *ndctl_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
+{
+ return NULL;
+}
+static inline unsigned int ndctl_cmd_smart_get_flags(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_health(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_temperature(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_spares(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_alarm_flags(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_life_used(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_shutdown_state(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned int ndctl_cmd_smart_get_vendor_size(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+static inline unsigned char *ndctl_cmd_smart_get_vendor_data(struct ndctl_cmd *cmd)
+{
+ return NULL;
+}
+struct ndctl_cmd *ndctl_dimm_cmd_new_smart_threshold(struct ndctl_dimm *dimm)
+{
+ return NULL;
+}
+unsigned int ndctl_cmd_smart_threshold_get_alarm_control(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+unsigned int ndctl_cmd_smart_threshold_get_temperature(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+unsigned int ndctl_cmd_smart_threshold_get_spares(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
+#endif
+
struct ndctl_cmd *ndctl_dimm_cmd_new_vendor_specific(struct ndctl_dimm *dimm,
unsigned int opcode, size_t input_size, size_t output_size);
ssize_t ndctl_cmd_vendor_set_input(struct ndctl_cmd *cmd, void *buf,
diff --git a/ndctl.h b/ndctl.h
index 69b8e707fc49..ef1cf722ba4d 100644
--- a/ndctl.h
+++ b/ndctl.h
@@ -20,11 +20,45 @@ struct nd_cmd_smart {
__u8 data[128];
} __attribute__((packed));
+#define ND_SMART_HEALTH_VALID (1 << 0)
+#define ND_SMART_TEMP_VALID (1 << 1)
+#define ND_SMART_SPARES_VALID (1 << 2)
+#define ND_SMART_ALARM_VALID (1 << 3)
+#define ND_SMART_USED_VALID (1 << 4)
+#define ND_SMART_SHUTDOWN_VALID (1 << 5)
+#define ND_SMART_VENDOR_VALID (1 << 6)
+#define ND_SMART_TEMP_TRIP (1 << 0)
+#define ND_SMART_SPARE_TRIP (1 << 1)
+#define ND_SMART_NON_CRITICAL_HEALTH (1 << 0)
+#define ND_SMART_CRITICAL_HEALTH (1 << 1)
+#define ND_SMART_FATAL_HEALTH (1 << 2)
+
+struct nd_smart_payload {
+ __u32 flags;
+ __u8 reserved0[4];
+ __u8 health;
+ __u16 temperature;
+ __u8 spares;
+ __u8 alarm_flags;
+ __u8 life_used;
+ __u8 shutdown_state;
+ __u8 reserved1;
+ __u32 vendor_size;
+ __u8 vendor_data[108];
+} __attribute__((packed));
+
struct nd_cmd_smart_threshold {
__u32 status;
__u8 data[8];
} __attribute__((packed));
+struct nd_smart_threshold_payload {
+ __u16 alarm_control;
+ __u16 temperature;
+ __u8 spares;
+ __u8 reserved[3];
+} __attribute__((packed));
+
struct nd_cmd_dimm_flags {
__u32 status;
__u32 flags;
diff --git a/test/libndctl.c b/test/libndctl.c
index 0e9c830e68a1..6cd8e62476fb 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -377,7 +377,8 @@ static struct region regions1[] = {
static unsigned long dimm_commands0 = 1UL << ND_CMD_GET_CONFIG_SIZE
| 1UL << ND_CMD_GET_CONFIG_DATA
- | 1UL << ND_CMD_SET_CONFIG_DATA;
+ | 1UL << ND_CMD_SET_CONFIG_DATA | 1UL << ND_CMD_SMART
+ | 1UL << ND_CMD_SMART_THRESHOLD;
static unsigned long bus_commands0 = 1UL << ND_CMD_ARS_CAP
| 1UL << ND_CMD_ARS_START
@@ -1586,6 +1587,122 @@ static int check_set_config_data(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
return 0;
}
+#ifdef HAVE_NDCTL_SMART
+#define __check_smart(dimm, cmd, field) ({ \
+ if (ndctl_cmd_smart_get_##field(cmd) != smart_data.field) { \
+ fprintf(stderr, "%s dimm: %#x expected field %#x got: %#x\n", \
+ __func__, ndctl_dimm_get_handle(dimm), \
+ smart_data.field, \
+ ndctl_cmd_smart_get_##field(cmd)); \
+ ndctl_cmd_unref(cmd); \
+ return -ENXIO; \
+ } \
+})
+
+static int check_smart(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
+ struct check_cmd *check)
+{
+ static const struct nd_smart_payload smart_data = {
+ .flags = ND_SMART_HEALTH_VALID | ND_SMART_TEMP_VALID
+ | ND_SMART_SPARES_VALID | ND_SMART_ALARM_VALID
+ | ND_SMART_USED_VALID | ND_SMART_SHUTDOWN_VALID,
+ .health = ND_SMART_NON_CRITICAL_HEALTH,
+ .temperature = 23 * 16,
+ .spares = 75,
+ .alarm_flags = ND_SMART_SPARE_TRIP | ND_SMART_TEMP_TRIP,
+ .life_used = 5,
+ .shutdown_state = 0,
+ .vendor_size = 0,
+ };
+ struct ndctl_cmd *cmd = ndctl_dimm_cmd_new_smart(dimm);
+ int rc;
+
+ if (!cmd) {
+ fprintf(stderr, "%s: dimm: %#x failed to create cmd\n",
+ __func__, ndctl_dimm_get_handle(dimm));
+ return -ENXIO;
+ }
+
+ rc = ndctl_cmd_submit(cmd);
+ if (rc) {
+ fprintf(stderr, "%s: dimm: %#x failed to submit cmd: %d\n",
+ __func__, ndctl_dimm_get_handle(dimm), rc);
+ ndctl_cmd_unref(cmd);
+ return rc;
+ }
+
+ __check_smart(dimm, cmd, flags);
+ __check_smart(dimm, cmd, health);
+ __check_smart(dimm, cmd, temperature);
+ __check_smart(dimm, cmd, spares);
+ __check_smart(dimm, cmd, alarm_flags);
+ __check_smart(dimm, cmd, life_used);
+ __check_smart(dimm, cmd, shutdown_state);
+ __check_smart(dimm, cmd, vendor_size);
+
+ ndctl_cmd_unref(cmd);
+ return 0;
+}
+
+#define __check_smart_threshold(dimm, cmd, field) ({ \
+ if (ndctl_cmd_smart_threshold_get_##field(cmd) != smart_t_data.field) { \
+ fprintf(stderr, "%s dimm: %#x expected field %#x got: %#x\n", \
+ __func__, ndctl_dimm_get_handle(dimm), \
+ smart_t_data.field, \
+ ndctl_cmd_smart_threshold_get_##field(cmd)); \
+ ndctl_cmd_unref(cmd); \
+ return -ENXIO; \
+ } \
+})
+
+static int check_smart_threshold(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
+ struct check_cmd *check)
+{
+ static const struct nd_smart_threshold_payload smart_t_data = {
+ .alarm_control = ND_SMART_SPARE_TRIP | ND_SMART_TEMP_TRIP,
+ .temperature = 40 * 16,
+ .spares = 5,
+ };
+ struct ndctl_cmd *cmd = ndctl_dimm_cmd_new_smart_threshold(dimm);
+ int rc;
+
+ if (!cmd) {
+ fprintf(stderr, "%s: dimm: %#x failed to create cmd\n",
+ __func__, ndctl_dimm_get_handle(dimm));
+ return -ENXIO;
+ }
+
+ rc = ndctl_cmd_submit(cmd);
+ if (rc) {
+ fprintf(stderr, "%s: dimm: %#x failed to submit cmd: %d\n",
+ __func__, ndctl_dimm_get_handle(dimm), rc);
+ ndctl_cmd_unref(cmd);
+ return rc;
+ }
+
+ __check_smart_threshold(dimm, cmd, alarm_control);
+ __check_smart_threshold(dimm, cmd, temperature);
+ __check_smart_threshold(dimm, cmd, spares);
+
+ ndctl_cmd_unref(cmd);
+ return 0;
+}
+#else
+static int check_smart(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
+ struct check_cmd *check)
+{
+ fprintf(stderr, "%s: HAVE_NDCTL_SMART disabled, skipping\n", __func__);
+ return 0;
+}
+
+static int check_smart_threshold(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
+ struct check_cmd *check)
+{
+ fprintf(stderr, "%s: HAVE_NDCTL_SMART disabled, skipping\n", __func__);
+ return 0;
+}
+#endif
+
#ifdef HAVE_NDCTL_ARS
static int check_ars_cap(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
struct check_cmd *check)
@@ -1808,7 +1925,8 @@ static int check_commands(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
[ND_CMD_GET_CONFIG_SIZE] = { check_get_config_size },
[ND_CMD_GET_CONFIG_DATA] = { check_get_config_data },
[ND_CMD_SET_CONFIG_DATA] = { check_set_config_data },
- [ND_CMD_SMART_THRESHOLD] = { },
+ [ND_CMD_SMART] = { check_smart },
+ [ND_CMD_SMART_THRESHOLD] = { check_smart_threshold },
};
static struct check_cmd __check_bus_cmds[] = {
[ND_CMD_ARS_CAP] = { check_ars_cap },
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [ndctl PATCH v2] ndctl, list: add a '--health' option
2016-04-07 1:07 ` [ndctl PATCH 4/5] ndctl, list: add a '--health' option Dan Williams
2016-04-07 8:41 ` Johannes Thumshirn
@ 2016-04-07 22:42 ` Dan Williams
2016-04-08 7:20 ` Johannes Thumshirn
1 sibling, 1 reply; 16+ messages in thread
From: Dan Williams @ 2016-04-07 22:42 UTC (permalink / raw)
To: linux-nvdimm
Dump dimm smart data in the dimm listing when '--health' is specified.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Changes in v2:
* add an error message if health retrieval fails unexpectedly (jth)
* add threshold data to the health listing
Documentation/ndctl-list.txt | 21 ++++++
builtin-list.c | 21 ++++++
util/json.c | 150 ++++++++++++++++++++++++++++++++++++++++++
util/json.h | 1
4 files changed, 192 insertions(+), 1 deletion(-)
diff --git a/Documentation/ndctl-list.txt b/Documentation/ndctl-list.txt
index 806548196118..a5f209f99408 100644
--- a/Documentation/ndctl-list.txt
+++ b/Documentation/ndctl-list.txt
@@ -3,7 +3,7 @@ ndctl-list(1)
NAME
----
-ndctl-list - dump the platform nvdimm device topology in json
+ndctl-list - dump the platform nvdimm device topology and attributes in json
SYNOPSIS
--------
@@ -72,6 +72,25 @@ include::xable-region-options.txt[]
--dimms::
Include dimm info in the listing
+-H::
+--health::
+ Include dimm health info in the listing. For example:
+[verse]
+{
+ "dev":"nmem0",
+ "health":{
+ "health_state":"non-critical",
+ "temperature_celsius":23,
+ "spares_percentage":75,
+ "alarm_temperature":true,
+ "alarm_spares":true,
+ "temperature_threshold":40,
+ "spares_threshold":5,
+ "life_used_percentage":5,
+ "shutdown_state":"clean"
+ }
+}
+
-R::
--regions::
Include region info in the listing
diff --git a/builtin-list.c b/builtin-list.c
index df0871ab544a..f930b9e44c2c 100644
--- a/builtin-list.c
+++ b/builtin-list.c
@@ -22,6 +22,7 @@ static struct {
bool regions;
bool namespaces;
bool idle;
+ bool health;
} list;
static struct {
@@ -200,6 +201,7 @@ int cmd_list(int argc, const char **argv)
"filter by region-type"),
OPT_BOOLEAN('B', "buses", &list.buses, "include bus info"),
OPT_BOOLEAN('D', "dimms", &list.dimms, "include dimm info"),
+ OPT_BOOLEAN('H', "health", &list.health, "include dimm health"),
OPT_BOOLEAN('R', "regions", &list.regions,
"include region info"),
OPT_BOOLEAN('N', "namespaces", &list.namespaces,
@@ -299,6 +301,25 @@ int cmd_list(int argc, const char **argv)
continue;
}
+ if (list.health) {
+ struct json_object *jhealth;
+
+ jhealth = util_dimm_health_to_json(dimm);
+ if (jhealth)
+ json_object_object_add(jdimm, "health",
+ jhealth);
+ else if (ndctl_dimm_is_cmd_supported(dimm,
+ ND_CMD_SMART)) {
+ /*
+ * Failed to retrieve health data from
+ * a dimm that otherwise supports smart
+ * data retrieval commands.
+ */
+ fail("\n");
+ continue;
+ }
+ }
+
/*
* Without a bus we are collecting dimms anonymously
* across the platform.
diff --git a/util/json.c b/util/json.c
index 288efee723ff..6369a4eec291 100644
--- a/util/json.c
+++ b/util/json.c
@@ -61,6 +61,156 @@ struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm)
return NULL;
}
+static double parse_smart_temperature(unsigned int temp)
+{
+ bool negative = !!(temp & (1 << 15));
+ double t;
+
+ temp &= ~(1 << 15);
+ t = temp;
+ t /= 16;
+ if (negative)
+ t *= -1;
+ return t;
+}
+
+static void smart_threshold_to_json(struct ndctl_dimm *dimm,
+ struct json_object *jhealth)
+{
+ unsigned int alarm_control;
+ struct json_object *jobj;
+ struct ndctl_cmd *cmd;
+ int rc;
+
+ cmd = ndctl_dimm_cmd_new_smart_threshold(dimm);
+ if (!cmd)
+ return;
+
+ rc = ndctl_cmd_submit(cmd);
+ if (rc || ndctl_cmd_get_firmware_status(cmd))
+ goto out;
+
+ alarm_control = ndctl_cmd_smart_threshold_get_alarm_control(cmd);
+ if (alarm_control & ND_SMART_TEMP_TRIP) {
+ unsigned int temp;
+ double t;
+
+ temp = ndctl_cmd_smart_threshold_get_temperature(cmd);
+ t = parse_smart_temperature(temp);
+ jobj = json_object_new_double(t);
+ if (jobj)
+ json_object_object_add(jhealth,
+ "temperature_threshold", jobj);
+ }
+
+ if (alarm_control & ND_SMART_SPARE_TRIP) {
+ unsigned int spares;
+
+ spares = ndctl_cmd_smart_threshold_get_spares(cmd);
+ jobj = json_object_new_int(spares);
+ if (jobj)
+ json_object_object_add(jhealth,
+ "spares_threshold", jobj);
+ }
+
+ out:
+ ndctl_cmd_unref(cmd);
+}
+
+struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm)
+{
+ struct json_object *jhealth = json_object_new_object();
+ struct json_object *jobj;
+ struct ndctl_cmd *cmd;
+ unsigned int flags;
+ int rc;
+
+ if (!jhealth)
+ return NULL;
+
+ cmd = ndctl_dimm_cmd_new_smart(dimm);
+ if (!cmd)
+ goto err;
+
+ rc = ndctl_cmd_submit(cmd);
+ if (rc || ndctl_cmd_get_firmware_status(cmd))
+ goto err;
+
+ flags = ndctl_cmd_smart_get_flags(cmd);
+ if (flags & ND_SMART_HEALTH_VALID) {
+ unsigned int health = ndctl_cmd_smart_get_health(cmd);
+
+ if (health & ND_SMART_FATAL_HEALTH)
+ jobj = json_object_new_string("fatal");
+ else if (health & ND_SMART_CRITICAL_HEALTH)
+ jobj = json_object_new_string("critical");
+ else if (health & ND_SMART_NON_CRITICAL_HEALTH)
+ jobj = json_object_new_string("non-critical");
+ else
+ jobj = json_object_new_string("ok");
+ if (jobj)
+ json_object_object_add(jhealth, "health_state", jobj);
+ }
+
+ if (flags & ND_SMART_TEMP_VALID) {
+ unsigned int temp = ndctl_cmd_smart_get_temperature(cmd);
+ double t = parse_smart_temperature(temp);
+
+ jobj = json_object_new_double(t);
+ if (jobj)
+ json_object_object_add(jhealth, "temperature_celsius", jobj);
+ }
+
+ if (flags & ND_SMART_SPARES_VALID) {
+ unsigned int spares = ndctl_cmd_smart_get_spares(cmd);
+
+ jobj = json_object_new_int(spares);
+ if (jobj)
+ json_object_object_add(jhealth, "spares_percentage", jobj);
+ }
+
+ if (flags & ND_SMART_ALARM_VALID) {
+ unsigned int alarm_flags = ndctl_cmd_smart_get_spares(cmd);
+ bool temp_flag = !!(alarm_flags & ND_SMART_TEMP_TRIP);
+ bool spares_flag = !!(alarm_flags & ND_SMART_SPARE_TRIP);
+
+ jobj = json_object_new_boolean(temp_flag);
+ if (jobj)
+ json_object_object_add(jhealth, "alarm_temperature", jobj);
+
+ jobj = json_object_new_boolean(spares_flag);
+ if (jobj)
+ json_object_object_add(jhealth, "alarm_spares", jobj);
+ }
+
+ smart_threshold_to_json(dimm, jhealth);
+
+ if (flags & ND_SMART_USED_VALID) {
+ unsigned int life_used = ndctl_cmd_smart_get_life_used(cmd);
+
+ jobj = json_object_new_int(life_used);
+ if (jobj)
+ json_object_object_add(jhealth, "life_used_percentage", jobj);
+ }
+
+ if (flags & ND_SMART_SHUTDOWN_VALID) {
+ unsigned int shutdown = ndctl_cmd_smart_get_shutdown_state(cmd);
+
+ jobj = json_object_new_string(shutdown ? "dirty" : "clean");
+ if (jobj)
+ json_object_object_add(jhealth, "shutdown_state", jobj);
+ }
+
+ ndctl_cmd_unref(cmd);
+ return jhealth;
+ err:
+ json_object_put(jhealth);
+ if (cmd)
+ ndctl_cmd_unref(cmd);
+ return NULL;
+}
+
+
bool util_namespace_active(struct ndctl_namespace *ndns)
{
struct ndctl_btt *btt = ndctl_namespace_get_btt(ndns);
diff --git a/util/json.h b/util/json.h
index 653bbd9beef1..79962cacc35c 100644
--- a/util/json.h
+++ b/util/json.h
@@ -6,6 +6,7 @@
bool util_namespace_active(struct ndctl_namespace *ndns);
struct json_object *util_bus_to_json(struct ndctl_bus *bus);
struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm);
+struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm);
struct json_object *util_mapping_to_json(struct ndctl_mapping *mapping);
struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns);
#endif /* __NDCTL_JSON_H__ */
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [ndctl PATCH v2] ndctl, list: add a '--health' option
2016-04-07 22:42 ` [ndctl PATCH v2] " Dan Williams
@ 2016-04-08 7:20 ` Johannes Thumshirn
0 siblings, 0 replies; 16+ messages in thread
From: Johannes Thumshirn @ 2016-04-08 7:20 UTC (permalink / raw)
To: Dan Williams; +Cc: linux-nvdimm
On Donnerstag, 7. April 2016 15:42:29 CEST Dan Williams wrote:
> Dump dimm smart data in the dimm listing when '--health' is specified.
>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
> Changes in v2:
> * add an error message if health retrieval fails unexpectedly (jth)
> * add threshold data to the health listing
Thanks for working that in,
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
--
Johannes Thumshirn Storage
jthumshirn@suse.de +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [ndctl PATCH v2] ndctl: helper for S.M.A.R.T. data retrieval
2016-04-07 22:39 ` [ndctl PATCH v2] " Dan Williams
@ 2016-04-08 7:23 ` Johannes Thumshirn
0 siblings, 0 replies; 16+ messages in thread
From: Johannes Thumshirn @ 2016-04-08 7:23 UTC (permalink / raw)
To: Dan Williams; +Cc: linux-nvdimm
On Donnerstag, 7. April 2016 15:39:04 CEST Dan Williams wrote:
> Helper functions to issue the "SMART and Health Info (Function Index 1)"
> DSM and parse its results.
>
> http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
> Changes in v2:
> * pull in the updated ndctl.h from the kernel (jth)
> * add helper routines for issuing smart threshold commands
> * extend the unit test to validate smart threshold data passthrough
Thanks,
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
--
Johannes Thumshirn Storage
jthumshirn@suse.de +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2016-04-08 7:23 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-04-07 1:06 [ndctl PATCH 0/5] smart support and 'list' enhancements Dan Williams
2016-04-07 1:07 ` [ndctl PATCH 1/5] ndctl: rebuild libndctl.h when libndctl.h.in changes Dan Williams
2016-04-07 8:29 ` Johannes Thumshirn
2016-04-07 1:07 ` [ndctl PATCH 2/5] ndctl: helper for S.M.A.R.T. data retrieval Dan Williams
2016-04-07 8:36 ` Johannes Thumshirn
2016-04-07 22:39 ` [ndctl PATCH v2] " Dan Williams
2016-04-08 7:23 ` Johannes Thumshirn
2016-04-07 1:07 ` [ndctl PATCH 3/5] ndctl, list: clean up default behavior Dan Williams
2016-04-07 8:38 ` Johannes Thumshirn
2016-04-07 1:07 ` [ndctl PATCH 4/5] ndctl, list: add a '--health' option Dan Williams
2016-04-07 8:41 ` Johannes Thumshirn
2016-04-07 13:16 ` Dan Williams
2016-04-07 22:42 ` [ndctl PATCH v2] " Dan Williams
2016-04-08 7:20 ` Johannes Thumshirn
2016-04-07 1:07 ` [ndctl PATCH 5/5] ndctl, list: add 'filter by dimm' capability Dan Williams
2016-04-07 8:42 ` Johannes Thumshirn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox