Linux-NVDIMM Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [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", &param.bus, "bus-id", "filter by bus"),
 		OPT_STRING('r', "region", &param.region, "region-id",
 				"filter by region"),
+		OPT_STRING('d', "dimm", &param.dimm, "dimm-id",
+				"filter by dimm"),
 		OPT_STRING('t', "type", &param.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