* [ndctl PATCH v2 0/4] ndctl: add support for HPE type N SMART health data
@ 2016-09-13 17:41 Brian Boylston
2016-09-13 17:41 ` [ndctl PATCH v2 1/4] libndctl: introduce ndctl_smart_ops Brian Boylston
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Brian Boylston @ 2016-09-13 17:41 UTC (permalink / raw)
To: linux-nvdimm
This set of patches adds support for the HPE SMART DSM functions and enables
ndctl to report DIMM health data for HPE type N NVDIMMs. The relevant
firmware interfaces are described in [1].
The first patch virtualizes the ndctl_cmd_smart*() family of libndctl
interfaces into a set of ndctl_smart_ops, allowing runtime implementation
differentiation depending on the firmware support provided by a DIMM.
The second and third patches add miscellaneous pieces needed for the
final patch:
The fourth patch adds a set of ndctl_smart_ops for the HPE1 DSM family,
based on the firmware interfaces defined in [1]. These ndctl_smart_ops
translate the HPE1 DSM output to match the interface of the existing
Intel DSM-inspired smart_ops. This delivers health reporting parity for
HPE type N NVDIMMs, however:
When evaluating this ndctl_smart_ops approach, please consider our goal of
adding JSON exports for some of the additional health data defined in [1].
I expect this would entail adding additional accessor functions to
ndctl_smart_ops, but it's not clear whether or how to extend the existing
get_flags()/check flags/get_data() model used by util_dimm_health_to_json().
If you'd like to test these changes, note the following:
. Some of the DSM functions for HPE type N NVDIMMs, including the ones used
by this patch, require the acpi_ipmi kernel module to be loaded, and you
may need to manually modprobe it.
. Without [2], you'll need to include '--idle' in your ndctl invocation as
ndctl will consider type Ns to be disabled and will otherwise omit them.
. Without [3], "alarm_temperature" and "alarm_spares" will be inaccurate.
[1] https://github.com/HewlettPackard/hpe-nvm/raw/master/Documentation/NFIT_DSM_DDR4_NVDIMM-N_v84s.pdf
[2] https://lists.01.org/pipermail/linux-nvdimm/2016-August/006619.html
[3] https://lists.01.org/pipermail/linux-nvdimm/2016-September/006810.html
Changes in v2:
New approach: taught libndctl how to translate between the HPE1 DSM
family and the existing ndctl_cmd_smart*() libndctl interfaces
(as suggested by Dan).
Brian Boylston (4):
libndctl: introduce ndctl_smart_ops
libndctl: record dsm family in add_dimm()
libndctl: enable ND_CMD_CALL
libndctl: add support for the HPE1 family of DSM SMART functions
ndctl/Makefile.am | 1 +
ndctl/lib/libndctl-hpe1.c | 303 ++++++++++++++++++++++++++++++++++++++
ndctl/lib/libndctl-private.h | 22 +++
ndctl/lib/libndctl-smart.c | 111 +++++++++++---
ndctl/lib/libndctl.c | 20 ++-
ndctl/lib/ndctl-hpe1.h | 335 +++++++++++++++++++++++++++++++++++++++++++
ndctl/libndctl.h.in | 1 +
7 files changed, 769 insertions(+), 24 deletions(-)
create mode 100644 ndctl/lib/libndctl-hpe1.c
create mode 100644 ndctl/lib/ndctl-hpe1.h
--
2.8.3
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 9+ messages in thread
* [ndctl PATCH v2 1/4] libndctl: introduce ndctl_smart_ops
2016-09-13 17:41 [ndctl PATCH v2 0/4] ndctl: add support for HPE type N SMART health data Brian Boylston
@ 2016-09-13 17:41 ` Brian Boylston
2016-09-15 2:22 ` Dan Williams
2016-09-13 17:41 ` [ndctl PATCH v2 2/4] libndctl: record dsm family in add_dimm() Brian Boylston
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Brian Boylston @ 2016-09-13 17:41 UTC (permalink / raw)
To: linux-nvdimm
Add a layer of indirection for the ndctl_cmd_smart*() family of
interfaces. This will allow the underlying implementation to be
switched based on the DSM family supported by the DIMM.
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Brian Boylston <brian.boylston@hpe.com>
---
ndctl/lib/libndctl-private.h | 21 ++++++++
ndctl/lib/libndctl-smart.c | 111 ++++++++++++++++++++++++++++++++++---------
ndctl/lib/libndctl.c | 8 ++++
ndctl/libndctl.h.in | 1 +
4 files changed, 118 insertions(+), 23 deletions(-)
diff --git a/ndctl/lib/libndctl-private.h b/ndctl/lib/libndctl-private.h
index 65ef86d..8d2ebfc 100644
--- a/ndctl/lib/libndctl-private.h
+++ b/ndctl/lib/libndctl-private.h
@@ -201,6 +201,27 @@ struct ndctl_cmd {
};
};
+struct ndctl_smart_ops {
+ struct ndctl_cmd *(*new_smart)(struct ndctl_dimm *);
+ unsigned int (*smart_get_flags)(struct ndctl_cmd *);
+ unsigned int (*smart_get_health)(struct ndctl_cmd *);
+ unsigned int (*smart_get_temperature)(struct ndctl_cmd *);
+ unsigned int (*smart_get_spares)(struct ndctl_cmd *);
+ unsigned int (*smart_get_alarm_flags)(struct ndctl_cmd *);
+ unsigned int (*smart_get_life_used)(struct ndctl_cmd *);
+ unsigned int (*smart_get_shutdown_state)(struct ndctl_cmd *);
+ unsigned int (*smart_get_vendor_size)(struct ndctl_cmd *);
+ unsigned char *(*smart_get_vendor_data)(struct ndctl_cmd *);
+ struct ndctl_cmd *(*new_smart_threshold)(struct ndctl_dimm *);
+ unsigned int (*smart_threshold_get_alarm_control)(struct ndctl_cmd *);
+ unsigned int (*smart_threshold_get_temperature)(struct ndctl_cmd *);
+ unsigned int (*smart_threshold_get_spares)(struct ndctl_cmd *);
+};
+
+#if HAS_SMART == 1
+struct ndctl_smart_ops intel_smart_ops;
+#endif
+
/* internal library helpers for conditionally defined command numbers */
#ifdef HAVE_NDCTL_ARS
static const int nd_cmd_ars_status = ND_CMD_ARS_STATUS;
diff --git a/ndctl/lib/libndctl-smart.c b/ndctl/lib/libndctl-smart.c
index cba1e9d..a172541 100644
--- a/ndctl/lib/libndctl-smart.c
+++ b/ndctl/lib/libndctl-smart.c
@@ -16,7 +16,55 @@
#include <ndctl/libndctl.h>
#include "libndctl-private.h"
-NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
+/*
+ * The smart_dimm_op() and smart_cmd_op() macros are used here to
+ * define the wrappers around the ndctl_smart_ops:
+ */
+
+#define smart_dimm_op(name, op) \
+NDCTL_EXPORT struct ndctl_cmd *name( \
+ struct ndctl_dimm *dimm) \
+{ \
+ struct ndctl_smart_ops *ops = ndctl_dimm_get_smart_ops(dimm); \
+ if (ops && ops->op) \
+ return ops->op(dimm); \
+ else \
+ return NULL; \
+}
+
+smart_dimm_op(ndctl_dimm_cmd_new_smart, new_smart)
+smart_dimm_op(ndctl_dimm_cmd_new_smart_threshold, new_smart_threshold)
+
+#define smart_cmd_op(name, op, rettype, defretvalue) \
+NDCTL_EXPORT rettype name(struct ndctl_cmd *cmd) \
+{ \
+ if (cmd->dimm) { \
+ struct ndctl_smart_ops *ops = ndctl_dimm_get_smart_ops(cmd->dimm); \
+ if (ops && ops->op) \
+ return ops->op(cmd); \
+ } \
+ return defretvalue; \
+}
+
+smart_cmd_op(ndctl_cmd_smart_get_flags, smart_get_flags, unsigned int, 0)
+smart_cmd_op(ndctl_cmd_smart_get_health, smart_get_health, unsigned int, 0)
+smart_cmd_op(ndctl_cmd_smart_get_temperature, smart_get_temperature, unsigned int, 0)
+smart_cmd_op(ndctl_cmd_smart_get_spares, smart_get_spares, unsigned int, 0)
+smart_cmd_op(ndctl_cmd_smart_get_alarm_flags, smart_get_alarm_flags, unsigned int, 0)
+smart_cmd_op(ndctl_cmd_smart_get_life_used, smart_get_life_used, unsigned int, 0)
+smart_cmd_op(ndctl_cmd_smart_get_shutdown_state, smart_get_shutdown_state, unsigned int, 0)
+smart_cmd_op(ndctl_cmd_smart_get_vendor_size, smart_get_vendor_size, unsigned int, 0)
+smart_cmd_op(ndctl_cmd_smart_get_vendor_data, smart_get_vendor_data, unsigned char *, NULL)
+smart_cmd_op(ndctl_cmd_smart_threshold_get_alarm_control, smart_threshold_get_alarm_control, unsigned int, 0)
+smart_cmd_op(ndctl_cmd_smart_threshold_get_temperature, smart_threshold_get_temperature, unsigned int, 0)
+smart_cmd_op(ndctl_cmd_smart_threshold_get_spares, smart_threshold_get_spares, unsigned int, 0)
+
+/*
+ * The following intel_dimm_*() and intel_smart_*() functions implement
+ * the ndctl_smart_ops for the Intel DSM family (NVDIMM_FAMILY_INTEL):
+ */
+
+static struct ndctl_cmd *intel_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);
@@ -45,66 +93,66 @@ NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
return cmd;
}
-static int smart_valid(struct ndctl_cmd *cmd)
+static int intel_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) \
+#define intel_smart_get_field(cmd, field) \
+static unsigned int intel_cmd_smart_get_##field(struct ndctl_cmd *cmd) \
{ \
struct nd_smart_payload *smart_data; \
- if (smart_valid(cmd) < 0) \
+ if (intel_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)
+intel_smart_get_field(cmd, flags)
+intel_smart_get_field(cmd, health)
+intel_smart_get_field(cmd, temperature)
+intel_smart_get_field(cmd, spares)
+intel_smart_get_field(cmd, alarm_flags)
+intel_smart_get_field(cmd, life_used)
+intel_smart_get_field(cmd, shutdown_state)
+intel_smart_get_field(cmd, vendor_size)
-NDCTL_EXPORT unsigned char *ndctl_cmd_smart_get_vendor_data(struct ndctl_cmd *cmd)
+static unsigned char *intel_cmd_smart_get_vendor_data(struct ndctl_cmd *cmd)
{
struct nd_smart_payload *smart_data;
- if (smart_valid(cmd) < 0)
+ if (intel_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)
+static int intel_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( \
+#define intel_smart_threshold_get_field(cmd, field) \
+static unsigned int intel_cmd_smart_threshold_get_##field( \
struct ndctl_cmd *cmd) \
{ \
struct nd_smart_threshold_payload *smart_t_data; \
- if (smart_threshold_valid(cmd) < 0) \
+ if (intel_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)
+intel_smart_threshold_get_field(cmd, alarm_control)
+intel_smart_threshold_get_field(cmd, temperature)
+intel_smart_threshold_get_field(cmd, spares)
-NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart_threshold(
+static struct ndctl_cmd *intel_dimm_cmd_new_smart_threshold(
struct ndctl_dimm *dimm)
{
struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm);
@@ -133,3 +181,20 @@ NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart_threshold(
return cmd;
}
+
+struct ndctl_smart_ops intel_smart_ops = {
+ .new_smart = intel_dimm_cmd_new_smart,
+ .smart_get_flags = intel_cmd_smart_get_flags,
+ .smart_get_health = intel_cmd_smart_get_health,
+ .smart_get_temperature = intel_cmd_smart_get_temperature,
+ .smart_get_spares = intel_cmd_smart_get_spares,
+ .smart_get_alarm_flags = intel_cmd_smart_get_alarm_flags,
+ .smart_get_life_used = intel_cmd_smart_get_life_used,
+ .smart_get_shutdown_state = intel_cmd_smart_get_shutdown_state,
+ .smart_get_vendor_size = intel_cmd_smart_get_vendor_size,
+ .smart_get_vendor_data = intel_cmd_smart_get_vendor_data,
+ .new_smart_threshold = intel_dimm_cmd_new_smart_threshold,
+ .smart_threshold_get_alarm_control = intel_cmd_smart_threshold_get_alarm_control,
+ .smart_threshold_get_temperature = intel_cmd_smart_threshold_get_temperature,
+ .smart_threshold_get_spares = intel_cmd_smart_threshold_get_spares,
+};
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 93f79f7..9a9dc74 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -125,6 +125,7 @@ struct ndctl_bus {
struct ndctl_dimm {
struct kmod_module *module;
struct ndctl_bus *bus;
+ struct ndctl_smart_ops *smart_ops;
unsigned int handle, major, minor, serial;
unsigned short phys_id;
unsigned short vendor_id;
@@ -1149,6 +1150,8 @@ static int add_dimm(void *parent, int id, const char *dimm_base)
goto err_read;
dimm->dsm_mask = parse_commands(buf, 1);
+ dimm->smart_ops = &intel_smart_ops;
+
dimm->dimm_buf = calloc(1, strlen(dimm_base) + 50);
if (!dimm->dimm_buf)
goto err_read;
@@ -1459,6 +1462,11 @@ NDCTL_EXPORT struct ndctl_bus *ndctl_dimm_get_bus(struct ndctl_dimm *dimm)
return dimm->bus;
}
+NDCTL_EXPORT struct ndctl_smart_ops *ndctl_dimm_get_smart_ops(struct ndctl_dimm *dimm)
+{
+ return dimm->smart_ops;
+}
+
NDCTL_EXPORT struct ndctl_ctx *ndctl_dimm_get_ctx(struct ndctl_dimm *dimm)
{
return dimm->bus->ctx;
diff --git a/ndctl/libndctl.h.in b/ndctl/libndctl.h.in
index 451466a..679225c 100644
--- a/ndctl/libndctl.h.in
+++ b/ndctl/libndctl.h.in
@@ -150,6 +150,7 @@ unsigned int ndctl_dimm_handle_get_channel(struct ndctl_dimm *dimm);
unsigned int ndctl_dimm_handle_get_dimm(struct ndctl_dimm *dimm);
const char *ndctl_dimm_get_devname(struct ndctl_dimm *dimm);
struct ndctl_bus *ndctl_dimm_get_bus(struct ndctl_dimm *dimm);
+struct ndctl_smart_ops *ndctl_dimm_get_smart_ops(struct ndctl_dimm *dimm);
struct ndctl_ctx *ndctl_dimm_get_ctx(struct ndctl_dimm *dimm);
struct ndctl_dimm *ndctl_dimm_get_by_handle(struct ndctl_bus *bus,
unsigned int handle);
--
2.8.3
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [ndctl PATCH v2 2/4] libndctl: record dsm family in add_dimm()
2016-09-13 17:41 [ndctl PATCH v2 0/4] ndctl: add support for HPE type N SMART health data Brian Boylston
2016-09-13 17:41 ` [ndctl PATCH v2 1/4] libndctl: introduce ndctl_smart_ops Brian Boylston
@ 2016-09-13 17:41 ` Brian Boylston
2016-09-15 0:44 ` Dan Williams
2016-09-13 17:41 ` [ndctl PATCH v2 3/4] libndctl: enable ND_CMD_CALL Brian Boylston
2016-09-13 17:41 ` [ndctl PATCH v2 4/4] libndctl: add support for the HPE1 family of DSM SMART functions Brian Boylston
3 siblings, 1 reply; 9+ messages in thread
From: Brian Boylston @ 2016-09-13 17:41 UTC (permalink / raw)
To: linux-nvdimm
The recorded DSM family can be used to provide family-specific
functionality.
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Brian Boylston <brian.boylston@hpe.com>
---
ndctl/lib/libndctl.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 9a9dc74..c824d83 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -136,6 +136,7 @@ struct ndctl_dimm {
unsigned short subsystem_revision_id;
unsigned short manufacturing_date;
unsigned char manufacturing_location;
+ unsigned long dsm_family;
unsigned long dsm_mask;
char *unique_id;
char *dimm_path;
@@ -1145,6 +1146,11 @@ static int add_dimm(void *parent, int id, const char *dimm_base)
if (sscanf(buf, "%d:%d", &dimm->major, &dimm->minor) != 2)
goto err_read;
+ sprintf(path, "%s/nfit/family", dimm_base);
+ if (sysfs_read_attr(ctx, path, buf) < 0)
+ goto err_read;
+ dimm->dsm_family = strtoul(buf, NULL, 0);
+
sprintf(path, "%s/commands", dimm_base);
if (sysfs_read_attr(ctx, path, buf) < 0)
goto err_read;
--
2.8.3
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [ndctl PATCH v2 3/4] libndctl: enable ND_CMD_CALL
2016-09-13 17:41 [ndctl PATCH v2 0/4] ndctl: add support for HPE type N SMART health data Brian Boylston
2016-09-13 17:41 ` [ndctl PATCH v2 1/4] libndctl: introduce ndctl_smart_ops Brian Boylston
2016-09-13 17:41 ` [ndctl PATCH v2 2/4] libndctl: record dsm family in add_dimm() Brian Boylston
@ 2016-09-13 17:41 ` Brian Boylston
2016-09-13 17:41 ` [ndctl PATCH v2 4/4] libndctl: add support for the HPE1 family of DSM SMART functions Brian Boylston
3 siblings, 0 replies; 9+ messages in thread
From: Brian Boylston @ 2016-09-13 17:41 UTC (permalink / raw)
To: linux-nvdimm
. Enable parsing /sys/bus/nd/devices/nmemX/commands for ND_CMD_CALL
. Enable translation of ND_CMD_CALL to ND_IOCTL_CALL
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Brian Boylston <brian.boylston@hpe.com>
---
ndctl/lib/libndctl.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index c824d83..1e07520 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -719,7 +719,7 @@ static int to_dsm_index(const char *name, int dimm)
int i, end_cmd;
if (dimm) {
- end_cmd = ND_CMD_VENDOR;
+ end_cmd = ND_CMD_CALL;
cmd_name_fn = nvdimm_cmd_name;
} else {
end_cmd = nd_cmd_clear_error;
@@ -2184,6 +2184,7 @@ static int to_ioctl_cmd(int cmd, int dimm)
case ND_CMD_GET_CONFIG_DATA: return ND_IOCTL_GET_CONFIG_DATA;
case ND_CMD_SET_CONFIG_DATA: return ND_IOCTL_SET_CONFIG_DATA;
case ND_CMD_VENDOR: return ND_IOCTL_VENDOR;
+ case ND_CMD_CALL: return ND_IOCTL_CALL;
case ND_CMD_VENDOR_EFFECT_LOG_SIZE:
case ND_CMD_VENDOR_EFFECT_LOG:
default:
--
2.8.3
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [ndctl PATCH v2 4/4] libndctl: add support for the HPE1 family of DSM SMART functions
2016-09-13 17:41 [ndctl PATCH v2 0/4] ndctl: add support for HPE type N SMART health data Brian Boylston
` (2 preceding siblings ...)
2016-09-13 17:41 ` [ndctl PATCH v2 3/4] libndctl: enable ND_CMD_CALL Brian Boylston
@ 2016-09-13 17:41 ` Brian Boylston
3 siblings, 0 replies; 9+ messages in thread
From: Brian Boylston @ 2016-09-13 17:41 UTC (permalink / raw)
To: linux-nvdimm
This patch introduces a set of ndctl_smart_ops for the HPE1 DSM family.
The implementation calls the HPE1 DSM functions defined in [1] and
translates the results to match the existing Intel DSM-inspired
smart_ops. This delivers health reporting parity for HPE type N
NVDIMMs, but we are planning a future patch to add reporting for some of
the additional health data defined in [1].
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Brian Boylston <brian.boylston@hpe.com>
---
ndctl/Makefile.am | 1 +
ndctl/lib/libndctl-hpe1.c | 303 ++++++++++++++++++++++++++++++++++++++
ndctl/lib/libndctl-private.h | 1 +
ndctl/lib/libndctl.c | 5 +-
ndctl/lib/ndctl-hpe1.h | 335 +++++++++++++++++++++++++++++++++++++++++++
5 files changed, 644 insertions(+), 1 deletion(-)
create mode 100644 ndctl/lib/libndctl-hpe1.c
create mode 100644 ndctl/lib/ndctl-hpe1.h
diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
index 04f3a63..fdec355 100644
--- a/ndctl/Makefile.am
+++ b/ndctl/Makefile.am
@@ -31,6 +31,7 @@ endif
if ENABLE_SMART
lib_libndctl_la_SOURCES += lib/libndctl-smart.c
+lib_libndctl_la_SOURCES += lib/libndctl-hpe1.c
endif
bin_PROGRAMS = ndctl
diff --git a/ndctl/lib/libndctl-hpe1.c b/ndctl/lib/libndctl-hpe1.c
new file mode 100644
index 0000000..b61acf4
--- /dev/null
+++ b/ndctl/lib/libndctl-hpe1.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2016 Hewlett Packard Enterprise Development LP
+ * 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 <util/log.h>
+#include <ndctl/libndctl.h>
+#include "libndctl-private.h"
+
+#include "ndctl-hpe1.h"
+
+#define CMD_HPE1(_c) ((struct ndn_pkg_hpe1 *)((_c)->cmd_buf))
+#define CMD_HPE1_SMART(_c) \
+ ((struct ndn_hpe1_smart_data *)(CMD_HPE1(_c)->u.smart.data))
+#define CMD_HPE1_SMART_THRESH(_c) \
+ ((struct ndn_hpe1_smart_threshold_data *)(CMD_HPE1(_c)->u.thresh.data))
+
+static struct ndctl_cmd *hpe1_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;
+ struct ndn_pkg_hpe1 *hpe1;
+
+ if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_CALL)) {
+ dbg(ctx, "unsupported cmd\n");
+ return NULL;
+ }
+
+ size = sizeof(*cmd) + sizeof(struct ndn_pkg_hpe1);
+ cmd = calloc(1, size);
+ if (!cmd)
+ return NULL;
+
+ cmd->dimm = dimm;
+ ndctl_cmd_ref(cmd);
+ cmd->type = ND_CMD_CALL;
+ cmd->size = size;
+ cmd->status = 1;
+
+ hpe1 = CMD_HPE1(cmd);
+ hpe1->gen.nd_family = NVDIMM_FAMILY_HPE1;
+ hpe1->gen.nd_command = NDN_HPE1_CMD_SMART;
+ hpe1->gen.nd_fw_size = 0;
+ hpe1->gen.nd_size_in = offsetof(struct ndn_hpe1_smart, status);
+ hpe1->gen.nd_size_out = sizeof(hpe1->u.smart);
+ hpe1->u.smart.status = 3;
+
+ hpe1->u.smart.in_valid_flags = 0;
+ hpe1->u.smart.in_valid_flags |= NDN_HPE1_SMART_HEALTH_VALID;
+ hpe1->u.smart.in_valid_flags |= NDN_HPE1_SMART_TEMP_VALID;
+ hpe1->u.smart.in_valid_flags |= NDN_HPE1_SMART_SPARES_VALID;
+ hpe1->u.smart.in_valid_flags |= NDN_HPE1_SMART_ALARM_VALID;
+ hpe1->u.smart.in_valid_flags |= NDN_HPE1_SMART_USED_VALID;
+ hpe1->u.smart.in_valid_flags |= NDN_HPE1_SMART_SHUTDOWN_VALID;
+ hpe1->u.smart.in_valid_flags |= NDN_HPE1_SMART_VENDOR_VALID;
+
+ cmd->firmware_status = &hpe1->u.smart.status;
+
+ return cmd;
+}
+
+static int hpe1_smart_valid(struct ndctl_cmd *cmd)
+{
+ if (cmd->type != ND_CMD_CALL ||
+ cmd->size != sizeof(*cmd) + sizeof(struct ndn_pkg_hpe1) ||
+ CMD_HPE1(cmd)->gen.nd_family != NVDIMM_FAMILY_HPE1 ||
+ CMD_HPE1(cmd)->gen.nd_command != NDN_HPE1_CMD_SMART ||
+ cmd->status != 0)
+ return cmd->status < 0 ? cmd->status : -EINVAL;
+ return 0;
+}
+
+static unsigned int hpe1_cmd_smart_get_flags(struct ndctl_cmd *cmd)
+{
+ unsigned int hpe1flags;
+ unsigned int flags;
+
+ if (hpe1_smart_valid(cmd) < 0)
+ return UINT_MAX;
+
+ hpe1flags = CMD_HPE1_SMART(cmd)->out_valid_flags;
+ flags = 0;
+ if (hpe1flags & NDN_HPE1_SMART_HEALTH_VALID)
+ flags |= ND_SMART_HEALTH_VALID;
+ if (hpe1flags & NDN_HPE1_SMART_TEMP_VALID)
+ flags |= ND_SMART_TEMP_VALID ;
+ if (hpe1flags & NDN_HPE1_SMART_SPARES_VALID)
+ flags |= ND_SMART_SPARES_VALID;
+ if (hpe1flags & NDN_HPE1_SMART_ALARM_VALID)
+ flags |= ND_SMART_ALARM_VALID;
+ if (hpe1flags & NDN_HPE1_SMART_USED_VALID)
+ flags |= ND_SMART_USED_VALID;
+ if (hpe1flags & NDN_HPE1_SMART_SHUTDOWN_VALID)
+ flags |= ND_SMART_SHUTDOWN_VALID;
+ if (hpe1flags & NDN_HPE1_SMART_VENDOR_VALID)
+ flags |= ND_SMART_VENDOR_VALID;
+
+ return flags;
+}
+
+static unsigned int hpe1_cmd_smart_get_health(struct ndctl_cmd *cmd)
+{
+ unsigned char hpe1health;
+ unsigned int health;
+
+ if (hpe1_smart_valid(cmd) < 0)
+ return UINT_MAX;
+
+ hpe1health = CMD_HPE1_SMART(cmd)->stat_summary;
+ health = 0;
+ if (hpe1health & NDN_HPE1_SMART_NONCRIT_HEALTH)
+ health |= ND_SMART_NON_CRITICAL_HEALTH;;
+ if (hpe1health & NDN_HPE1_SMART_CRITICAL_HEALTH)
+ health |= ND_SMART_CRITICAL_HEALTH;
+ if (hpe1health & NDN_HPE1_SMART_FATAL_HEALTH)
+ health |= ND_SMART_FATAL_HEALTH;
+
+ return health;
+}
+
+static unsigned int hpe1_cmd_smart_get_temperature(struct ndctl_cmd *cmd)
+{
+ if (hpe1_smart_valid(cmd) < 0)
+ return UINT_MAX;
+
+ return CMD_HPE1_SMART(cmd)->curr_temp;
+}
+
+static unsigned int hpe1_cmd_smart_get_spares(struct ndctl_cmd *cmd)
+{
+ if (hpe1_smart_valid(cmd) < 0)
+ return UINT_MAX;
+
+ return CMD_HPE1_SMART(cmd)->spare_blocks;
+}
+
+static unsigned int hpe1_cmd_smart_get_alarm_flags(struct ndctl_cmd *cmd)
+{
+ unsigned int hpe1flags;
+ unsigned int flags;
+
+ if (hpe1_smart_valid(cmd) < 0)
+ return UINT_MAX;
+
+ hpe1flags = CMD_HPE1_SMART(cmd)->alarm_trips;
+ flags = 0;
+ if (hpe1flags & NDN_HPE1_SMART_TEMP_TRIP)
+ flags |= ND_SMART_TEMP_TRIP;
+ if (hpe1flags & NDN_HPE1_SMART_SPARE_TRIP)
+ flags |= ND_SMART_SPARE_TRIP;
+
+ return flags;
+}
+
+static unsigned int hpe1_cmd_smart_get_life_used(struct ndctl_cmd *cmd)
+{
+ if (hpe1_smart_valid(cmd) < 0)
+ return UINT_MAX;
+
+ return CMD_HPE1_SMART(cmd)->device_life;
+}
+
+static unsigned int hpe1_cmd_smart_get_shutdown_state(struct ndctl_cmd *cmd)
+{
+ unsigned int shutdown;
+
+ if (hpe1_smart_valid(cmd) < 0)
+ return UINT_MAX;
+
+ shutdown = CMD_HPE1_SMART(cmd)->last_shutdown_stat;
+ if (shutdown == NDN_HPE1_SMART_LASTSAVEGOOD)
+ return 0;
+ else
+ return 1;
+}
+
+static unsigned int hpe1_cmd_smart_get_vendor_size(struct ndctl_cmd *cmd)
+{
+ if (hpe1_smart_valid(cmd) < 0)
+ return UINT_MAX;
+
+ return CMD_HPE1_SMART(cmd)->vndr_spec_data_size;
+}
+
+static unsigned char *hpe1_cmd_smart_get_vendor_data(struct ndctl_cmd *cmd)
+{
+ if (hpe1_smart_valid(cmd) < 0)
+ return NULL;
+
+ return CMD_HPE1_SMART(cmd)->vnd_spec_data;
+}
+
+
+static struct ndctl_cmd *hpe1_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;
+ struct ndn_pkg_hpe1 *hpe1;
+
+ if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_CALL)) {
+ dbg(ctx, "unsupported cmd\n");
+ return NULL;
+ }
+
+ size = sizeof(*cmd) + sizeof(struct ndn_pkg_hpe1);
+ cmd = calloc(1, size);
+ if (!cmd)
+ return NULL;
+
+ cmd->dimm = dimm;
+ ndctl_cmd_ref(cmd);
+ cmd->type = ND_CMD_CALL;
+ cmd->size = size;
+ cmd->status = 1;
+
+ hpe1 = CMD_HPE1(cmd);
+ hpe1->gen.nd_family = NVDIMM_FAMILY_HPE1;
+ hpe1->gen.nd_command = NDN_HPE1_CMD_SMART_THRESHOLD;
+ hpe1->gen.nd_fw_size = 0;
+ hpe1->gen.nd_size_in = offsetof(struct ndn_hpe1_smart_threshold, status);
+ hpe1->gen.nd_size_out = sizeof(hpe1->u.smart);
+ hpe1->u.thresh.status = 3;
+
+ cmd->firmware_status = &hpe1->u.thresh.status;
+
+ return cmd;
+}
+
+static int hpe1_smart_threshold_valid(struct ndctl_cmd *cmd)
+{
+ if (cmd->type != ND_CMD_CALL ||
+ cmd->size != sizeof(*cmd) + sizeof(struct ndn_pkg_hpe1) ||
+ CMD_HPE1(cmd)->gen.nd_family != NVDIMM_FAMILY_HPE1 ||
+ CMD_HPE1(cmd)->gen.nd_command != NDN_HPE1_CMD_SMART_THRESHOLD ||
+ cmd->status != 0)
+ return cmd->status < 0 ? cmd->status : -EINVAL;
+ return 0;
+}
+
+static unsigned int hpe1_cmd_smart_threshold_get_alarm_control(struct ndctl_cmd *cmd)
+{
+ unsigned int hpe1flags;
+ unsigned int flags;
+
+ if (hpe1_smart_threshold_valid(cmd) < 0)
+ return UINT_MAX;
+
+ hpe1flags = CMD_HPE1_SMART_THRESH(cmd)->threshold_alarm_ctl;
+ flags = 0;
+ if (hpe1flags & NDN_HPE1_SMART_TEMP_TRIP)
+ flags |= ND_SMART_TEMP_TRIP;
+ if (hpe1flags & NDN_HPE1_SMART_SPARE_TRIP)
+ flags |= ND_SMART_SPARE_TRIP;
+
+ return flags;
+}
+
+static unsigned int hpe1_cmd_smart_threshold_get_temperature(struct ndctl_cmd *cmd)
+{
+ if (hpe1_smart_threshold_valid(cmd) < 0)
+ return UINT_MAX;
+
+ return CMD_HPE1_SMART_THRESH(cmd)->temp_threshold;
+}
+
+static unsigned int hpe1_cmd_smart_threshold_get_spares(struct ndctl_cmd *cmd)
+{
+ if (hpe1_smart_threshold_valid(cmd) < 0)
+ return UINT_MAX;
+
+ return CMD_HPE1_SMART_THRESH(cmd)->spare_block_threshold;
+}
+
+struct ndctl_smart_ops hpe1_smart_ops = {
+ .new_smart = hpe1_dimm_cmd_new_smart,
+ .smart_get_flags = hpe1_cmd_smart_get_flags,
+ .smart_get_health = hpe1_cmd_smart_get_health,
+ .smart_get_temperature = hpe1_cmd_smart_get_temperature,
+ .smart_get_spares = hpe1_cmd_smart_get_spares,
+ .smart_get_alarm_flags = hpe1_cmd_smart_get_alarm_flags,
+ .smart_get_life_used = hpe1_cmd_smart_get_life_used,
+ .smart_get_shutdown_state = hpe1_cmd_smart_get_shutdown_state,
+ .smart_get_vendor_size = hpe1_cmd_smart_get_vendor_size,
+ .smart_get_vendor_data = hpe1_cmd_smart_get_vendor_data,
+ .new_smart_threshold = hpe1_dimm_cmd_new_smart_threshold,
+ .smart_threshold_get_alarm_control = hpe1_cmd_smart_threshold_get_alarm_control,
+ .smart_threshold_get_temperature = hpe1_cmd_smart_threshold_get_temperature,
+ .smart_threshold_get_spares = hpe1_cmd_smart_threshold_get_spares,
+};
diff --git a/ndctl/lib/libndctl-private.h b/ndctl/lib/libndctl-private.h
index 8d2ebfc..52a3c71 100644
--- a/ndctl/lib/libndctl-private.h
+++ b/ndctl/lib/libndctl-private.h
@@ -220,6 +220,7 @@ struct ndctl_smart_ops {
#if HAS_SMART == 1
struct ndctl_smart_ops intel_smart_ops;
+struct ndctl_smart_ops hpe1_smart_ops;
#endif
/* internal library helpers for conditionally defined command numbers */
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 1e07520..c4c8cae 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -1156,7 +1156,10 @@ static int add_dimm(void *parent, int id, const char *dimm_base)
goto err_read;
dimm->dsm_mask = parse_commands(buf, 1);
- dimm->smart_ops = &intel_smart_ops;
+ if (dimm->dsm_family == NVDIMM_FAMILY_HPE1)
+ dimm->smart_ops = &hpe1_smart_ops;
+ else
+ dimm->smart_ops = &intel_smart_ops;
dimm->dimm_buf = calloc(1, strlen(dimm_base) + 50);
if (!dimm->dimm_buf)
diff --git a/ndctl/lib/ndctl-hpe1.h b/ndctl/lib/ndctl-hpe1.h
new file mode 100644
index 0000000..0d41aab
--- /dev/null
+++ b/ndctl/lib/ndctl-hpe1.h
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2016 Hewlett Packard Enterprise Development LP
+ * Copyright (c) 2014-2015, 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.
+ */
+#ifndef __NDCTL_HPE1_H__
+#define __NDCTL_HPE1_H__
+
+enum {
+ NDN_HPE1_CMD_QUERY = 0,
+
+ /* non-root commands */
+ NDN_HPE1_CMD_SMART = 1,
+ NDN_HPE1_CMD_SMART_THRESHOLD = 2,
+ NDN_HPE1_CMD_GET_CONFIG_SIZE = 4,
+ NDN_HPE1_CMD_GET_CONFIG_DATA = 5,
+ NDN_HPE1_CMD_SET_CONFIG_DATA = 6,
+ NDN_HPE1_CMD_GET_IDENT = 10,
+ NDN_HPE1_CMD_GET_ES_IDENT = 11,
+ NDN_HPE1_CMD_GET_LAST_BACKUP = 12,
+ NDN_HPE1_CMD_SET_LIFE_THRESHOLD = 13,
+ NDN_HPE1_CMD_ERRINJ_QUERY = 18,
+ NDN_HPE1_CMD_ERRINJ_INJECT = 19,
+ NDN_HPE1_CMD_ERRINJ_STATUS = 20,
+};
+
+/* NDN_HPE1_CMD_SMART */
+struct ndn_hpe1_smart {
+ __u32 in_valid_flags;
+ __u32 status;
+ __u8 data[124];
+} __attribute__((packed));
+
+/* ndn_hpe1_smart.in_valid_flags / ndn_hpe1_smart_data.out_valid_flags */
+#define NDN_HPE1_SMART_HEALTH_VALID (1 << 0)
+#define NDN_HPE1_SMART_TEMP_VALID (1 << 1)
+#define NDN_HPE1_SMART_SPARES_VALID (1 << 2)
+#define NDN_HPE1_SMART_ALARM_VALID (1 << 3)
+#define NDN_HPE1_SMART_USED_VALID (1 << 4)
+#define NDN_HPE1_SMART_SHUTDOWN_VALID (1 << 5)
+#define NDN_HPE1_SMART_STATS_VALID (1 << 6)
+#define NDN_HPE1_SMART_DETAIL_VALID (1 << 7)
+#define NDN_HPE1_SMART_ENERGY_VALID (1 << 8)
+#define NDN_HPE1_SMART_VENDOR_VALID (1 << 9)
+#define NDN_HPE1_SMART_NOTIFIED (1 << 31)
+
+/* ndn_hpe1_smart_data.stat_summary */
+#define NDN_HPE1_SMART_NONCRIT_HEALTH (1 << 0)
+#define NDN_HPE1_SMART_CRITICAL_HEALTH (1 << 1)
+#define NDN_HPE1_SMART_FATAL_HEALTH (1 << 2)
+
+/* ndn_hpe1_smart_data.alarm_trips */
+#define NDN_HPE1_SMART_TEMP_TRIP (1 << 0)
+#define NDN_HPE1_SMART_SPARE_TRIP (1 << 1)
+#define NDN_HPE1_SMART_LIFEWARN_TRIP (1 << 2)
+#define NDN_HPE1_SMART_LIFEERR_TRIP (1 << 3)
+#define NDN_HPE1_SMART_ESLIFEWARN_TRIP (1 << 4)
+#define NDN_HPE1_SMART_ESLIFEERR_TRIP (1 << 5)
+#define NDN_HPE1_SMART_ESTEMPWARN_TRIP (1 << 6)
+#define NDN_HPE1_SMART_ESTEMPERR_TRIP (1 << 7)
+
+/* ndn_hpe1_smart_data.last_shutdown_stat */
+#define NDN_HPE1_SMART_LASTSAVEGOOD (1 << 1)
+
+/* ndn_hpe1_smart_data.mod_hlth_stat */
+#define NDN_HPE1_SMART_ES_FAILURE (1 << 0)
+#define NDN_HPE1_SMART_CTLR_FAILURE (1 << 1)
+#define NDN_HPE1_SMART_UE_TRIP (1 << 2)
+#define NDN_HPE1_SMART_CE_TRIP (1 << 3)
+#define NDN_HPE1_SMART_SAVE_FAILED (1 << 4)
+#define NDN_HPE1_SMART_RESTORE_FAILED (1 << 5)
+#define NDN_HPE1_SMART_ARM_FAILED (1 << 6)
+#define NDN_HPE1_SMART_ERASE_FAILED (1 << 7)
+#define NDN_HPE1_SMART_CONFIG_ERROR (1 << 8)
+#define NDN_HPE1_SMART_FW_ERROR (1 << 9)
+#define NDN_HPE1_SMART_VENDOR_ERROR (1 << 10)
+
+struct ndn_hpe1_smart_data {
+ __u32 out_valid_flags;
+ __u8 stat_summary;
+ __u16 curr_temp;
+ __u8 spare_blocks;
+ __u16 alarm_trips;
+ __u8 device_life;
+ __u8 last_shutdown_stat;
+ __u16 last_save_op_dur;
+ __u16 last_restore_op_dur;
+ __u16 last_erase_op_dur;
+ __u16 res1;
+ __u32 save_ops;
+ __u32 restore_ops;
+ __u32 erase_ops;
+ __u32 life_save_ops;
+ __u32 life_restore_ops;
+ __u32 life_erase_ops;
+ __u32 life_mod_pwr_cycles;
+ __u32 mod_hlth_stat;
+ __u32 energy_src_check;
+ __u8 energy_src_life_percent;
+ __u16 energy_src_curr_temp;
+ __u8 res2;
+ __u16 energy_src_total_runtime;
+ __u16 vndr_spec_data_size;
+ __u8 vnd_spec_data[60];
+} __attribute__((packed));
+
+/* NDN_HPE1_CMD_SMART_THRESHOLD */
+struct ndn_hpe1_smart_threshold {
+ __u32 status;
+ __u8 data[32];
+} __attribute__((packed));
+
+struct ndn_hpe1_smart_threshold_data {
+ __u16 threshold_alarm_ctl;
+ __u16 temp_threshold;
+ __u8 spare_block_threshold;
+ __u8 res1[3];
+ __u8 dev_lifewarn_threshold;
+ __u8 dev_lifeerr_threshold;
+ __u8 res2[6];
+ __u8 es_lifewarn_threshold;
+ __u8 es_lifeerr_threshold;
+ __u8 es_tempwarn_threshold;
+ __u8 es_temperr_threshold;
+ __u8 res3[4];
+ __u64 res4;
+} __attribute__((packed));
+
+/* NDN_HPE1_CMD_GET_CONFIG_SIZE */
+struct ndn_hpe1_get_config_size {
+ __u32 status;
+ __u32 config_size;
+ __u32 max_xfer;
+} __attribute__((packed));
+
+/* NDN_HPE1_CMD_GET_CONFIG_DATA */
+struct ndn_hpe1_get_config_data_hdr {
+ __u32 in_offset;
+ __u32 in_length;
+ __u32 status;
+ __u8 out_buf[0];
+} __attribute__((packed));
+
+/* NDN_HPE1_CMD_SET_CONFIG_DATA */
+struct ndn_hpe1_set_config_hdr {
+ __u32 in_offset;
+ __u32 in_length;
+ __u8 in_buf[0];
+} __attribute__((packed));
+
+
+/* ndn_hpe1_get_id.sup_backup_trigger */
+#define NDN_HPE1_BKUP_SUPPORT_CKE (1 << 0)
+#define NDN_HPE1_BKUP_SUPPORT_EXTERNAL (1 << 1)
+#define NDN_HPE1_BKUP_SUPPORT_12V (1 << 2)
+#define NDN_HPE1_BKUP_SUPPORT_I2C (1 << 3)
+#define NDN_HPE1_BKUP_SUPPORT_SAVEN (1 << 4)
+
+/* NDN_HPE1_CMD_GET_IDENT */
+struct ndn_hpe1_get_id {
+ __u32 status;
+ __u8 spec_rev;
+ __u8 num_stnd_pages;
+ __u32 hw_rev;
+ __u8 sup_backup_trigger;
+ __u16 max_op_retries;
+ __u8 __res1[3];
+ __u32 backup_op_timeout;
+ __u32 restore_op_timeout;
+ __u32 erase_op_timeout;
+ __u32 arm_op_timeout;
+ __u32 fw_op_timeout;
+ __u32 region_block_size;
+ __u16 min_op_temp;
+ __u16 max_op_temp;
+ __u8 curr_fw_slot;
+ __u8 res2[1];
+ __u16 num_fw_slots;
+ __u8 fw_slot_revision[0];
+} __attribute__((packed));
+
+/* ndn_hpe1_get_energy_src_id.attr */
+#define NDN_HPE1_ES_ATTR_BUILTIN (1 << 0)
+#define NDN_HPE1_ES_ATTR_TETHERED (1 << 1)
+#define NDN_HPE1_ES_ATTR_SHARED (1 << 2)
+
+/* ndn_hpe1_get_energy_src_id.tech */
+#define NDN_HPE1_ES_TECH_UNDEFINED (1 << 0)
+#define NDN_HPE1_ES_TECH_SUPERCAP (1 << 1)
+#define NDN_HPE1_ES_TECH_BATTERY (1 << 2)
+#define NDN_HPE1_ES_TECH_HYBRIDCAP (1 << 3)
+
+/* NDN_HPE1_CMD_GET_ES_IDENT */
+struct ndn_hpe1_get_energy_src_id {
+ __u32 status;
+ __u8 energy_src_policy;
+ __u8 attr;
+ __u8 tech;
+ __u8 reserved;
+ __u16 hw_rev;
+ __u16 fw_rev;
+ __u32 charge_timeout;
+ __u16 min_op_temp;
+ __u16 max_op_temp;
+} __attribute__((packed));
+
+/* ndn_hpe1_last_backup_info.last_backup_initiation */
+#define NDN_HPE1_LASTBKUP_SAVEN (1 << 0)
+#define NDN_HPE1_LASTBKUP_EXTERNAL (1 << 1)
+#define NDN_HPE1_LASTBKUP_CKE (1 << 2)
+#define NDN_HPE1_LASTBKUP_FW (1 << 3)
+#define NDN_HPE1_LASTBKUP_RESETN (1 << 4)
+
+/* ndn_hpe1_last_backup_info.ctlr_backup_stat */
+#define NDN_HPE1_LASTBKUP_GTG (1 << 0)
+#define NDN_HPE1_LASTBKUP_SDRAM_FAULT (1 << 1)
+#define NDN_HPE1_LASTBKUP_GEN_FAULT (1 << 2)
+
+/* NDN_HPE1_CMD_GET_LAST_BACKUP */
+struct ndn_hpe1_get_last_backup {
+ __u32 status;
+ __u32 last_backup_info;
+} __attribute__((packed));
+
+struct ndn_hpe1_last_backup_info {
+ __u8 backup_image;
+ __u8 backup_cmplt_stat;
+ __u8 last_backup_initiation;
+ __u8 ctlr_backup_stat;
+} __attribute__((packed));
+
+
+/* NDN_HPE1_CMD_SET_LIFE_THRESHOLD */
+struct ndn_hpe1_set_lifetime_threshold {
+ __u8 in_nvm_lifetime_warn_threshold;
+ __u32 status;
+} __attribute__((packed));
+
+
+/* ndn_hpe1_inj_err.in_err_typ
+ * ndn_hpe1_get_inj_err_status.err_inj_type
+ * log2(ndn_hpe1_query_err_inj_cap.err_inj_cap)
+ */
+enum {
+ NDN_HPE1_EINJ_DEV_NONCRIT = 1,
+ NDN_HPE1_EINJ_DEV_CRIT = 2,
+ NDN_HPE1_EINJ_DEV_FATAL = 3,
+ NDN_HPE1_EINJ_UE_BACKUP = 4,
+ NDN_HPE1_EINJ_UE_RESTORE = 5,
+ NDN_HPE1_EINJ_UE_ERASE = 6,
+ NDN_HPE1_EINJ_UE_ARM = 7,
+ NDN_HPE1_EINJ_BADBLOCK = 8,
+ NDN_HPE1_EINJ_ES_FAULT = 9,
+ NDN_HPE1_EINJ_ES_LOWCHARGE = 10,
+ NDN_HPE1_EINJ_ES_TEMPWARN = 11,
+ NDN_HPE1_EINJ_ES_TEMPERR = 12,
+ NDN_HPE1_EINJ_ES_LIFEWARN = 13,
+ NDN_HPE1_EINJ_ES_LIFEERR = 14,
+ NDN_HPE1_EINJ_DEV_LIFEWARN = 15,
+ NDN_HPE1_EINJ_DEV_LIFEERR = 16,
+ NDN_HPE1_EINJ_FWUPDATE_ERR = 17,
+ NDN_HPE1_EINJ_CTRL_ERR = 18,
+};
+
+/* ndn_hpe1_inj_err.in_options / ndn_hpe1_get_inj_err_status.err_inj_opt */
+enum {
+ NDN_HPE1_EINJ_OPT_SINGLE = 0,
+ NDN_HPE1_EINJ_OPT_PERSISTENT = 1,
+ NDN_HPE1_EINJ_OPT_CLEAR = 2,
+};
+
+/* ndn_hpe1_get_inj_err_status.err_inj_stat_info */
+enum {
+ NDN_HPE1_EINJ_STAT_NONE = 0,
+ NDN_HPE1_EINJ_STAT_INJECTED = 1,
+ NDN_HPE1_EINJ_STAT_PENDING = 2,
+};
+
+/* NDN_HPE1_CMD_ERRINJ_QUERY */
+struct ndn_hpe1_query_err_inj_cap {
+ __u32 status;
+ __u8 err_inj_cap[32];
+} __attribute__((packed));
+
+
+/* NDN_HPE1_CMD_ERRINJ_INJECT */
+struct ndn_hpe1_inj_err {
+ __u8 in_err_typ;
+ __u8 in_options;
+ __u32 status;
+} __attribute__((packed));
+
+/* NDN_HPE1_CMD_ERRINJ_STATUS */
+struct ndn_hpe1_get_inj_err_status {
+ __u32 status;
+ __u8 err_inj_stat_info;
+ __u8 err_inj_type;
+ __u8 err_inj_opt;
+} __attribute__((packed));
+
+union ndn_hpe1_cmd {
+ __u64 query;
+ struct ndn_hpe1_smart smart;
+ struct ndn_hpe1_smart_threshold thresh;
+ struct ndn_hpe1_get_config_size get_size;
+ struct ndn_hpe1_get_config_data_hdr get_data;
+ struct ndn_hpe1_get_id get_id;
+ struct ndn_hpe1_get_energy_src_id get_energy_src_id;
+ struct ndn_hpe1_get_last_backup get_last_backup;
+ struct ndn_hpe1_last_backup_info last_backup_info;
+ struct ndn_hpe1_set_lifetime_threshold set_life_thresh;
+ struct ndn_hpe1_query_err_inj_cap err_cap;
+ struct ndn_hpe1_inj_err inj_err;
+ struct ndn_hpe1_get_inj_err_status inj_err_stat;
+
+ unsigned char buf[128];
+};
+
+struct ndn_pkg_hpe1 {
+ struct nd_cmd_pkg gen;
+ union ndn_hpe1_cmd u;
+} __attribute__((packed));
+
+#define NDN_IOCTL_HPE1_PASSTHRU _IOWR(ND_IOCTL, ND_CMD_CALL, \
+ struct ndn_pkg_hpe1)
+
+#endif /* __NDCTL_HPE1_H__ */
--
2.8.3
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [ndctl PATCH v2 2/4] libndctl: record dsm family in add_dimm()
2016-09-13 17:41 ` [ndctl PATCH v2 2/4] libndctl: record dsm family in add_dimm() Brian Boylston
@ 2016-09-15 0:44 ` Dan Williams
2016-09-15 18:17 ` Boylston, Brian
0 siblings, 1 reply; 9+ messages in thread
From: Dan Williams @ 2016-09-15 0:44 UTC (permalink / raw)
To: Brian Boylston; +Cc: linux-nvdimm
On Tue, Sep 13, 2016 at 10:41 AM, Brian Boylston <brian.boylston@hpe.com> wrote:
> The recorded DSM family can be used to provide family-specific
> functionality.
>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Brian Boylston <brian.boylston@hpe.com>
> ---
> ndctl/lib/libndctl.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
> index 9a9dc74..c824d83 100644
> --- a/ndctl/lib/libndctl.c
> +++ b/ndctl/lib/libndctl.c
> @@ -136,6 +136,7 @@ struct ndctl_dimm {
> unsigned short subsystem_revision_id;
> unsigned short manufacturing_date;
> unsigned char manufacturing_location;
> + unsigned long dsm_family;
> unsigned long dsm_mask;
> char *unique_id;
> char *dimm_path;
> @@ -1145,6 +1146,11 @@ static int add_dimm(void *parent, int id, const char *dimm_base)
> if (sscanf(buf, "%d:%d", &dimm->major, &dimm->minor) != 2)
> goto err_read;
>
> + sprintf(path, "%s/nfit/family", dimm_base);
> + if (sysfs_read_attr(ctx, path, buf) < 0)
> + goto err_read;
> + dimm->dsm_family = strtoul(buf, NULL, 0);
Hmm I don't think it should it be fatal to add_dimm() for a failure to
have a family. It's reasonable for a DIMM to exist in the NFIT, but
have no DSMs or a DSM implementation that is new to the kernel. Can
we make this continue on and teach consumers of ->dsm_family that it
might be an error value?
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [ndctl PATCH v2 1/4] libndctl: introduce ndctl_smart_ops
2016-09-13 17:41 ` [ndctl PATCH v2 1/4] libndctl: introduce ndctl_smart_ops Brian Boylston
@ 2016-09-15 2:22 ` Dan Williams
0 siblings, 0 replies; 9+ messages in thread
From: Dan Williams @ 2016-09-15 2:22 UTC (permalink / raw)
To: Brian Boylston; +Cc: linux-nvdimm
On Tue, Sep 13, 2016 at 10:41 AM, Brian Boylston <brian.boylston@hpe.com> wrote:
> Add a layer of indirection for the ndctl_cmd_smart*() family of
> interfaces. This will allow the underlying implementation to be
> switched based on the DSM family supported by the DIMM.
>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Brian Boylston <brian.boylston@hpe.com>
> ---
> ndctl/lib/libndctl-private.h | 21 ++++++++
> ndctl/lib/libndctl-smart.c | 111 ++++++++++++++++++++++++++++++++++---------
> ndctl/lib/libndctl.c | 8 ++++
> ndctl/libndctl.h.in | 1 +
> 4 files changed, 118 insertions(+), 23 deletions(-)
Looks good to me and passes my regression tests.
Just one minor comment below:
>
> diff --git a/ndctl/lib/libndctl-private.h b/ndctl/lib/libndctl-private.h
> index 65ef86d..8d2ebfc 100644
> --- a/ndctl/lib/libndctl-private.h
> +++ b/ndctl/lib/libndctl-private.h
> @@ -201,6 +201,27 @@ struct ndctl_cmd {
> };
> };
>
> +struct ndctl_smart_ops {
> + struct ndctl_cmd *(*new_smart)(struct ndctl_dimm *);
> + unsigned int (*smart_get_flags)(struct ndctl_cmd *);
> + unsigned int (*smart_get_health)(struct ndctl_cmd *);
> + unsigned int (*smart_get_temperature)(struct ndctl_cmd *);
> + unsigned int (*smart_get_spares)(struct ndctl_cmd *);
> + unsigned int (*smart_get_alarm_flags)(struct ndctl_cmd *);
> + unsigned int (*smart_get_life_used)(struct ndctl_cmd *);
> + unsigned int (*smart_get_shutdown_state)(struct ndctl_cmd *);
> + unsigned int (*smart_get_vendor_size)(struct ndctl_cmd *);
> + unsigned char *(*smart_get_vendor_data)(struct ndctl_cmd *);
> + struct ndctl_cmd *(*new_smart_threshold)(struct ndctl_dimm *);
> + unsigned int (*smart_threshold_get_alarm_control)(struct ndctl_cmd *);
> + unsigned int (*smart_threshold_get_temperature)(struct ndctl_cmd *);
> + unsigned int (*smart_threshold_get_spares)(struct ndctl_cmd *);
> +};
> +
> +#if HAS_SMART == 1
> +struct ndctl_smart_ops intel_smart_ops;
> +#endif
> +
> /* internal library helpers for conditionally defined command numbers */
> #ifdef HAVE_NDCTL_ARS
> static const int nd_cmd_ars_status = ND_CMD_ARS_STATUS;
> diff --git a/ndctl/lib/libndctl-smart.c b/ndctl/lib/libndctl-smart.c
> index cba1e9d..a172541 100644
> --- a/ndctl/lib/libndctl-smart.c
> +++ b/ndctl/lib/libndctl-smart.c
> @@ -16,7 +16,55 @@
> #include <ndctl/libndctl.h>
> #include "libndctl-private.h"
>
> -NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
> +/*
> + * The smart_dimm_op() and smart_cmd_op() macros are used here to
> + * define the wrappers around the ndctl_smart_ops:
> + */
> +
> +#define smart_dimm_op(name, op) \
> +NDCTL_EXPORT struct ndctl_cmd *name( \
> + struct ndctl_dimm *dimm) \
> +{ \
> + struct ndctl_smart_ops *ops = ndctl_dimm_get_smart_ops(dimm); \
> + if (ops && ops->op) \
> + return ops->op(dimm); \
> + else \
> + return NULL; \
> +}
> +
> +smart_dimm_op(ndctl_dimm_cmd_new_smart, new_smart)
> +smart_dimm_op(ndctl_dimm_cmd_new_smart_threshold, new_smart_threshold)
There's only two of these routines and I don't suppose there will need
to have many more variants in the future. Let's just open code them
and not use a macro. The rest looks good.
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 9+ messages in thread
* RE: [ndctl PATCH v2 2/4] libndctl: record dsm family in add_dimm()
2016-09-15 0:44 ` Dan Williams
@ 2016-09-15 18:17 ` Boylston, Brian
2016-09-15 19:27 ` Dan Williams
0 siblings, 1 reply; 9+ messages in thread
From: Boylston, Brian @ 2016-09-15 18:17 UTC (permalink / raw)
To: Dan Williams; +Cc: linux-nvdimm
Dan Williams wrote on 2016-09-14:
> On Tue, Sep 13, 2016 at 10:41 AM, Brian Boylston <brian.boylston@hpe.com> wrote:
>> The recorded DSM family can be used to provide family-specific
>> functionality.
>>
>> Cc: Dan Williams <dan.j.williams@intel.com>
>> Signed-off-by: Brian Boylston <brian.boylston@hpe.com>
>> ---
>> ndctl/lib/libndctl.c | 6 ++++++
>> 1 file changed, 6 insertions(+)
>>
>> diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
>> index 9a9dc74..c824d83 100644
>> --- a/ndctl/lib/libndctl.c
>> +++ b/ndctl/lib/libndctl.c
>> @@ -136,6 +136,7 @@ struct ndctl_dimm {
>> unsigned short subsystem_revision_id;
>> unsigned short manufacturing_date;
>> unsigned char manufacturing_location;
>> + unsigned long dsm_family;
>> unsigned long dsm_mask;
>> char *unique_id;
>> char *dimm_path;
>> @@ -1145,6 +1146,11 @@ static int add_dimm(void *parent, int id, const char *dimm_base)
>> if (sscanf(buf, "%d:%d", &dimm->major, &dimm->minor) != 2)
>> goto err_read;
>>
>> + sprintf(path, "%s/nfit/family", dimm_base);
>> + if (sysfs_read_attr(ctx, path, buf) < 0)
>> + goto err_read;
>> + dimm->dsm_family = strtoul(buf, NULL, 0);
>
>
> Hmm I don't think it should it be fatal to add_dimm() for a failure to
> have a family. It's reasonable for a DIMM to exist in the NFIT, but
> have no DSMs or a DSM implementation that is new to the kernel. Can
> we make this continue on and teach consumers of ->dsm_family that it
> might be an error value?
Sure. Some of the other values collected in add_dimm() use -1 as an
error or not available value; ok to use that for dsm_family?
Also, should I add a public accessor function such as
ndctl_dimm_get_dsm_family()? (although there wouldn't be a consumer yet)
Thanks!
Brian
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [ndctl PATCH v2 2/4] libndctl: record dsm family in add_dimm()
2016-09-15 18:17 ` Boylston, Brian
@ 2016-09-15 19:27 ` Dan Williams
0 siblings, 0 replies; 9+ messages in thread
From: Dan Williams @ 2016-09-15 19:27 UTC (permalink / raw)
To: Boylston, Brian; +Cc: linux-nvdimm
On Thu, Sep 15, 2016 at 11:17 AM, Boylston, Brian
<brian.boylston@hpe.com> wrote:
> Dan Williams wrote on 2016-09-14:
>> On Tue, Sep 13, 2016 at 10:41 AM, Brian Boylston <brian.boylston@hpe.com> wrote:
>>> The recorded DSM family can be used to provide family-specific
>>> functionality.
>>>
>>> Cc: Dan Williams <dan.j.williams@intel.com>
>>> Signed-off-by: Brian Boylston <brian.boylston@hpe.com>
>>> ---
>>> ndctl/lib/libndctl.c | 6 ++++++
>>> 1 file changed, 6 insertions(+)
>>>
>>> diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
>>> index 9a9dc74..c824d83 100644
>>> --- a/ndctl/lib/libndctl.c
>>> +++ b/ndctl/lib/libndctl.c
>>> @@ -136,6 +136,7 @@ struct ndctl_dimm {
>>> unsigned short subsystem_revision_id;
>>> unsigned short manufacturing_date;
>>> unsigned char manufacturing_location;
>>> + unsigned long dsm_family;
>>> unsigned long dsm_mask;
>>> char *unique_id;
>>> char *dimm_path;
>>> @@ -1145,6 +1146,11 @@ static int add_dimm(void *parent, int id, const char *dimm_base)
>>> if (sscanf(buf, "%d:%d", &dimm->major, &dimm->minor) != 2)
>>> goto err_read;
>>>
>>> + sprintf(path, "%s/nfit/family", dimm_base);
>>> + if (sysfs_read_attr(ctx, path, buf) < 0)
>>> + goto err_read;
>>> + dimm->dsm_family = strtoul(buf, NULL, 0);
>>
>>
>> Hmm I don't think it should it be fatal to add_dimm() for a failure to
>> have a family. It's reasonable for a DIMM to exist in the NFIT, but
>> have no DSMs or a DSM implementation that is new to the kernel. Can
>> we make this continue on and teach consumers of ->dsm_family that it
>> might be an error value?
>
> Sure. Some of the other values collected in add_dimm() use -1 as an
> error or not available value; ok to use that for dsm_family?
Sounds good.
> Also, should I add a public accessor function such as
> ndctl_dimm_get_dsm_family()? (although there wouldn't be a consumer yet)
I'm not opposed to it for informational purposes, but I like the
current direction where it doesn't really matter and the other ndctl
routines are taught how to multiplex for different families.
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2016-09-15 19:27 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-13 17:41 [ndctl PATCH v2 0/4] ndctl: add support for HPE type N SMART health data Brian Boylston
2016-09-13 17:41 ` [ndctl PATCH v2 1/4] libndctl: introduce ndctl_smart_ops Brian Boylston
2016-09-15 2:22 ` Dan Williams
2016-09-13 17:41 ` [ndctl PATCH v2 2/4] libndctl: record dsm family in add_dimm() Brian Boylston
2016-09-15 0:44 ` Dan Williams
2016-09-15 18:17 ` Boylston, Brian
2016-09-15 19:27 ` Dan Williams
2016-09-13 17:41 ` [ndctl PATCH v2 3/4] libndctl: enable ND_CMD_CALL Brian Boylston
2016-09-13 17:41 ` [ndctl PATCH v2 4/4] libndctl: add support for the HPE1 family of DSM SMART functions Brian Boylston
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.