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.willi...@intel.com>
Signed-off-by: Brian Boylston <brian.boyls...@hpe.com>
---
Changes in v3:
  - Dropped the smart_dimm_op() macro and open coded
    ndctl_dimm_cmd_new_smart() and ndctl_dimm_cmd_new_smart_threshold().
    (suggested by Dan)
  - I realized that v2 wouldn't compile if HAS_SMART was not 1, so I
    changed intel_smart_ops and hpe1_smart_ops into pointers and set them
    to NULL if HAS_SMART != 1.  They are const because that seems to
    avoid compiler warnings about unused variables in cases where
    libndctl-private.h is included by something other than libndctl.c.

 ndctl/lib/libndctl-private.h |  23 +++++++++
 ndctl/lib/libndctl-smart.c   | 116 ++++++++++++++++++++++++++++++++++---------
 ndctl/lib/libndctl.c         |   7 +++
 ndctl/libndctl.h.in          |   1 +
 4 files changed, 124 insertions(+), 23 deletions(-)

diff --git a/ndctl/lib/libndctl-private.h b/ndctl/lib/libndctl-private.h
index 65ef86d..5ff4fec 100644
--- a/ndctl/lib/libndctl-private.h
+++ b/ndctl/lib/libndctl-private.h
@@ -201,6 +201,29 @@ 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 * const intel_smart_ops;
+#else
+static struct ndctl_smart_ops * const intel_smart_ops = NULL;
+#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..73a49ef 100644
--- a/ndctl/lib/libndctl-smart.c
+++ b/ndctl/lib/libndctl-smart.c
@@ -16,7 +16,60 @@
 #include <ndctl/libndctl.h>
 #include "libndctl-private.h"
 
-NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart(struct ndctl_dimm 
*dimm)
+/*
+ * Define the wrappers around the ndctl_smart_ops:
+ */
+
+NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart(
+               struct ndctl_dimm *dimm)
+{
+       struct ndctl_smart_ops *ops = ndctl_dimm_get_smart_ops(dimm);
+       if (ops && ops->new_smart)
+               return ops->new_smart(dimm);
+       else
+               return NULL;
+}
+
+NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart_threshold(
+               struct ndctl_dimm *dimm)
+{
+       struct ndctl_smart_ops *ops = ndctl_dimm_get_smart_ops(dimm);
+       if (ops && ops->new_smart_threshold)
+               return ops->new_smart_threshold(dimm);
+       else
+               return NULL;
+}
+
+#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 +98,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 +186,20 @@ NDCTL_EXPORT struct ndctl_cmd 
*ndctl_dimm_cmd_new_smart_threshold(
 
        return cmd;
 }
+
+struct ndctl_smart_ops * const intel_smart_ops = &(struct ndctl_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..3c9a506 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;
@@ -1163,6 +1164,7 @@ static int add_dimm(void *parent, int id, const char 
*dimm_base)
                goto err_read;
        dimm->module = to_module(ctx, buf);
 
+       dimm->smart_ops = intel_smart_ops;
        dimm->handle = -1;
        dimm->phys_id = -1;
        dimm->serial = -1;
@@ -1459,6 +1461,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

Reply via email to