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