* [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
* 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
* [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
* 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
* [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
* 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
* [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
* 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
* [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
* 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 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, 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
* [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 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
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