Add support for error injection on PAPR family of devices. This is
particularly useful in running 'make check' on non-nfit platforms.

Signed-off-by: Santosh Sivaraj <sant...@fossix.org>
---
 ndctl/lib/libndctl.c  |   1 +
 ndctl/lib/papr.c      | 134 ++++++++++++++++++++++++++++++++++++++++++
 ndctl/lib/private.h   |   1 +
 ndctl/libndctl-papr.h |   7 +++
 4 files changed, 143 insertions(+)
 create mode 100644 ndctl/libndctl-papr.h

diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 232c531..95cdc14 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -904,6 +904,7 @@ static void *add_bus(void *parent, int id, const char 
*ctl_base)
        else {
                bus->has_of_node = 1;
                bus_name = "papr";
+               bus->ops = papr_bus_ops;
        }
 
        sprintf(path, "%s/device/%s/dsm_mask", ctl_base, bus_name);
diff --git a/ndctl/lib/papr.c b/ndctl/lib/papr.c
index f94f8aa..6ac3d3e 100644
--- a/ndctl/lib/papr.c
+++ b/ndctl/lib/papr.c
@@ -12,6 +12,7 @@
 #include <util/log.h>
 #include <ndctl.h>
 #include <ndctl/libndctl.h>
+#include <ndctl/libndctl-papr.h>
 #include <lib/private.h>
 #include "papr.h"
 
@@ -38,6 +39,33 @@
 /* return the pdsm command */
 #define to_pdsm_cmd(C) ((enum papr_pdsm)to_ndcmd(C)->nd_command)
 
+/**
+ * ndctl_bus_is_papr_cmd_supported - check if command is supported on @bus.
+ * @bus: ndctl_bus instance
+ * @cmd: papr command number (defined as PAPR_PDSM_XXX in papr-pdsm.h)
+ *
+ * Return 1: command is supported. Return 0: command is not supported.
+ *
+ */
+NDCTL_EXPORT int ndctl_bus_is_papr_cmd_supported(struct ndctl_bus *bus,
+                                                int cmd)
+{
+       return !!(bus->nfit_dsm_mask & (1ULL << cmd));
+}
+
+static int papr_is_errinj_supported(struct ndctl_bus *bus)
+{
+       if (!ndctl_bus_is_papr_scm(bus))
+               return 0;
+
+       if (ndctl_bus_is_papr_cmd_supported(bus, PAPR_PDSM_INJECT_SET) &&
+           ndctl_bus_is_papr_cmd_supported(bus, PAPR_PDSM_INJECT_CLEAR) &&
+           ndctl_bus_is_papr_cmd_supported(bus, PAPR_PDSM_INJECT_GET))
+               return 1;
+
+       return 0;
+}
+
 static bool papr_cmd_is_supported(struct ndctl_dimm *dimm, int cmd)
 {
        /* Handle this separately to support monitor mode */
@@ -559,3 +587,109 @@ struct ndctl_dimm_ops * const papr_dimm_ops = &(struct 
ndctl_dimm_ops) {
                = papr_cmd_smart_threshold_set_ctrl_temperature,
        .smart_threshold_set_spares = papr_cmd_smart_threshold_set_spares,
 };
+
+static u32 bus_get_firmware_status(struct ndctl_cmd *cmd)
+{
+       struct nd_cmd_bus *cmd_bus = cmd->cmd_bus;
+
+       switch (cmd_bus->gen.nd_command) {
+       case PAPR_PDSM_INJECT_SET:
+               return cmd_bus->err_inj.status;
+       case PAPR_PDSM_INJECT_CLEAR:
+               return cmd_bus->err_inj_clr.status;
+       case PAPR_PDSM_INJECT_GET:
+               return cmd_bus->err_inj_stat.status;
+       }
+
+       return -1U;
+}
+
+static struct ndctl_cmd *papr_bus_cmd_new_err_inj(struct ndctl_bus *bus)
+{
+       size_t size, cmd_length;
+       struct nd_cmd_pkg *pkg;
+       struct ndctl_cmd *cmd;
+
+       cmd_length = sizeof(struct nd_cmd_ars_err_inj);
+       size = sizeof(*cmd) + sizeof(*pkg) + cmd_length;
+       cmd = calloc(1, size);
+       if (!cmd)
+               return NULL;
+
+       cmd->bus = bus;
+       ndctl_cmd_ref(cmd);
+       cmd->type = ND_CMD_CALL;
+       cmd->get_firmware_status = bus_get_firmware_status;
+       cmd->size = size;
+       cmd->status = 1;
+       pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0];
+       pkg->nd_command = PAPR_PDSM_INJECT_SET;
+       pkg->nd_size_in = offsetof(struct nd_cmd_ars_err_inj, status);
+       pkg->nd_size_out = cmd_length - pkg->nd_size_in;
+       pkg->nd_fw_size = pkg->nd_size_out;
+
+       return cmd;
+}
+
+static struct ndctl_cmd *papr_bus_cmd_new_err_inj_clr(struct ndctl_bus *bus)
+{
+       size_t size, cmd_length;
+       struct nd_cmd_pkg *pkg;
+       struct ndctl_cmd *cmd;
+
+       cmd_length = sizeof(struct nd_cmd_ars_err_inj_clr);
+       size = sizeof(*cmd) + sizeof(*pkg) + cmd_length;
+       cmd = calloc(1, size);
+       if (!cmd)
+               return NULL;
+
+       cmd->bus = bus;
+       ndctl_cmd_ref(cmd);
+       cmd->type = ND_CMD_CALL;
+       cmd->get_firmware_status = bus_get_firmware_status;
+       cmd->size = size;
+       cmd->status = 1;
+       pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0];
+       pkg->nd_command = PAPR_PDSM_INJECT_CLEAR;
+       pkg->nd_size_in = offsetof(struct nd_cmd_ars_err_inj_clr, status);
+       pkg->nd_size_out = cmd_length - pkg->nd_size_in;
+       pkg->nd_fw_size = pkg->nd_size_out;
+
+       return cmd;
+}
+
+static struct ndctl_cmd *papr_bus_cmd_new_err_inj_stat(struct ndctl_bus *bus,
+                                               u32 buf_size)
+{
+       size_t size, cmd_length;
+       struct nd_cmd_pkg *pkg;
+       struct ndctl_cmd *cmd;
+
+
+       cmd_length = sizeof(struct nd_cmd_ars_err_inj_stat);
+       size = sizeof(*cmd) + sizeof(*pkg) + cmd_length + buf_size;
+       cmd = calloc(1, size);
+       if (!cmd)
+               return NULL;
+
+       cmd->bus = bus;
+       ndctl_cmd_ref(cmd);
+       cmd->type = ND_CMD_CALL;
+       cmd->get_firmware_status = bus_get_firmware_status;
+       cmd->size = size;
+       cmd->status = 1;
+       pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0];
+       pkg->nd_command = PAPR_PDSM_INJECT_GET;
+       pkg->nd_size_in = 0;
+       pkg->nd_size_out = cmd_length + buf_size;
+       pkg->nd_fw_size = pkg->nd_size_out;
+
+       return cmd;
+}
+
+struct ndctl_bus_ops *const papr_bus_ops = &(struct ndctl_bus_ops) {
+       .new_err_inj = papr_bus_cmd_new_err_inj,
+       .new_err_inj_clr = papr_bus_cmd_new_err_inj_clr,
+       .new_err_inj_stat = papr_bus_cmd_new_err_inj_stat,
+       .err_inj_supported = papr_is_errinj_supported,
+};
diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h
index 0f36c67..96d890b 100644
--- a/ndctl/lib/private.h
+++ b/ndctl/lib/private.h
@@ -383,6 +383,7 @@ struct ndctl_bus_ops {
 };
 
 extern struct ndctl_bus_ops * const nfit_bus_ops;
+extern struct ndctl_bus_ops * const papr_bus_ops;
 
 struct ndctl_cmd *ndctl_bus_cmd_new_err_inj(struct ndctl_bus *bus);
 struct ndctl_cmd *ndctl_bus_cmd_new_err_inj_clr(struct ndctl_bus *bus);
diff --git a/ndctl/libndctl-papr.h b/ndctl/libndctl-papr.h
new file mode 100644
index 0000000..1658d8e
--- /dev/null
+++ b/ndctl/libndctl-papr.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+#ifndef __LIBNDCTL_PAPR_H__
+#define __LIBNDCTL_PAPR_H__
+
+int ndctl_bus_is_papr_cmd_supported(struct ndctl_bus *bus, int cmd);
+#endif
-- 
2.31.1
_______________________________________________
Linux-nvdimm mailing list -- linux-nvdimm@lists.01.org
To unsubscribe send an email to linux-nvdimm-le...@lists.01.org

Reply via email to