diff mbox series

[ndctl,24/36] ndctl/dimm: Rework dimm command status reporting

Message ID 158300773196.2141307.16404460619761697075.stgit@dwillia2-desk3.amr.corp.intel.com (mailing list archive)
State New, archived
Headers show
Series Multiple topics / backlog for v68 | expand

Commit Message

Dan Williams Feb. 29, 2020, 8:22 p.m. UTC
The build currently spews many errors of the form:

hyperv.c: In function ‘alloc_hyperv_cmd’:
hyperv.c:61:25: warning: taking address of packed member of ‘struct nd_hyperv_health_info’ may result in an unaligned pointer value [-Waddress-of-packed-member]
   61 |  cmd->firmware_status = &hyperv->u.health_info.status;

Move the status reporting from passing an unaligned pointer to a new
->get_firmware_status() operation.

Link: https://github.com/pmem/ndctl/issues/131
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 ndctl/lib/ars.c       |   28 +++++++++++++++++++------
 ndctl/lib/hpe1.c      |   17 +++++++++++----
 ndctl/lib/hyperv.c    |    7 +++++-
 ndctl/lib/intel.c     |   56 +++++++++++++++++++++++++++++++++++--------------
 ndctl/lib/libndctl.c  |   39 ++++++++++++++++++++++++++--------
 ndctl/lib/msft.c      |    8 +++++--
 ndctl/lib/nfit.c      |   36 +++++++++++++++++++++-----------
 ndctl/lib/private.h   |    7 ++++--
 ndctl/libndctl-nfit.h |   11 ++++++++++
 9 files changed, 157 insertions(+), 52 deletions(-)
diff mbox series

Patch

diff --git a/ndctl/lib/ars.c b/ndctl/lib/ars.c
index d91a99d00d10..44871b2afde2 100644
--- a/ndctl/lib/ars.c
+++ b/ndctl/lib/ars.c
@@ -15,6 +15,22 @@ 
 #include <ndctl/libndctl.h>
 #include "private.h"
 
+static u32 get_ars_command_status(struct ndctl_cmd *cmd)
+{
+	switch (cmd->type) {
+	case ND_CMD_ARS_CAP:
+		return cmd->ars_cap->status;
+	case ND_CMD_ARS_START:
+		return cmd->ars_start->status;
+	case ND_CMD_ARS_STATUS:
+		return cmd->ars_status->status;
+	case ND_CMD_CLEAR_ERROR:
+		return cmd->clear_err->status;
+	}
+
+	return -1U;
+}
+
 NDCTL_EXPORT struct ndctl_cmd *ndctl_bus_cmd_new_ars_cap(struct ndctl_bus *bus,
 		unsigned long long address, unsigned long long len)
 {
@@ -35,9 +51,9 @@  NDCTL_EXPORT struct ndctl_cmd *ndctl_bus_cmd_new_ars_cap(struct ndctl_bus *bus,
 	cmd->bus = bus;
 	ndctl_cmd_ref(cmd);
 	cmd->type = ND_CMD_ARS_CAP;
+	cmd->get_firmware_status = get_ars_command_status;
 	cmd->size = size;
 	cmd->status = 1;
-	cmd->firmware_status = &cmd->ars_cap->status;
 	cmd->ars_cap->address = address;
 	cmd->ars_cap->length = len;
 
@@ -55,7 +71,7 @@  static bool __validate_ars_cap(struct ndctl_cmd *ars_cap)
 {
 	if (ars_cap->type != ND_CMD_ARS_CAP || ars_cap->status != 0)
 		return false;
-	if ((*ars_cap->firmware_status & ARS_STATUS_MASK) != 0)
+	if ((ars_cap->get_firmware_status(ars_cap) & ARS_STATUS_MASK) != 0)
 		return false;
 	return validate_clear_error(ars_cap);
 }
@@ -84,7 +100,7 @@  NDCTL_EXPORT struct ndctl_cmd *ndctl_bus_cmd_new_ars_start(struct ndctl_cmd *ars
 	if (!validate_ars_cap(ctx, ars_cap))
 		return NULL;
 
-	if (!(*ars_cap->firmware_status >> ARS_EXT_STATUS_SHIFT & type)) {
+	if (!(ars_cap->get_firmware_status(ars_cap) >> ARS_EXT_STATUS_SHIFT & type)) {
 		dbg(ctx, "ars_cap does not show requested type as supported\n");
 		return NULL;
 	}
@@ -97,9 +113,9 @@  NDCTL_EXPORT struct ndctl_cmd *ndctl_bus_cmd_new_ars_start(struct ndctl_cmd *ars
 	cmd->bus = bus;
 	ndctl_cmd_ref(cmd);
 	cmd->type = ND_CMD_ARS_START;
+	cmd->get_firmware_status = get_ars_command_status;
 	cmd->size = size;
 	cmd->status = 1;
-	cmd->firmware_status = &cmd->ars_start->status;
 	cmd->ars_start->address = ars_cap->ars_cap->address;
 	cmd->ars_start->length = ars_cap->ars_cap->length;
 	cmd->ars_start->type = type;
@@ -145,9 +161,9 @@  NDCTL_EXPORT struct ndctl_cmd *ndctl_bus_cmd_new_ars_status(struct ndctl_cmd *ar
 	cmd->bus = bus;
 	ndctl_cmd_ref(cmd);
 	cmd->type = ND_CMD_ARS_STATUS;
+	cmd->get_firmware_status = get_ars_command_status;
 	cmd->size = size;
 	cmd->status = 1;
-	cmd->firmware_status = &cmd->ars_status->status;
 	cmd->ars_status->out_length = ars_cap_cmd->max_ars_out;
 
 	return cmd;
@@ -325,9 +341,9 @@  NDCTL_EXPORT struct ndctl_cmd *ndctl_bus_cmd_new_clear_error(
 	ndctl_cmd_ref(clear_err);
 	clear_err->bus = bus;
 	clear_err->type = ND_CMD_CLEAR_ERROR;
+	clear_err->get_firmware_status = get_ars_command_status;
 	clear_err->size = size;
 	clear_err->status = 1;
-	clear_err->firmware_status = &clear_err->clear_err->status;
 	clear_err->clear_err->address = address;
 	clear_err->clear_err->length = len;
 
diff --git a/ndctl/lib/hpe1.c b/ndctl/lib/hpe1.c
index b26120e1d3e0..b5ee02608d31 100644
--- a/ndctl/lib/hpe1.c
+++ b/ndctl/lib/hpe1.c
@@ -23,6 +23,17 @@ 
 #define CMD_HPE1_SMART(_c) (CMD_HPE1(_c)->u.smart.data)
 #define CMD_HPE1_SMART_THRESH(_c) (CMD_HPE1(_c)->u.thresh.data)
 
+static u32 hpe1_get_firmware_status(struct ndctl_cmd *cmd)
+{
+	switch (cmd->hpe1->gen.nd_command) {
+	case NDN_HPE1_CMD_SMART:
+		return cmd->hpe1->u.smart.status;
+	case NDN_HPE1_CMD_SMART_THRESHOLD:
+		return cmd->hpe1->u.thresh.status;
+	}
+	return -1U;
+}
+
 static struct ndctl_cmd *hpe1_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
 {
 	struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm);
@@ -60,6 +71,7 @@  static struct ndctl_cmd *hpe1_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
 	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;
+	cmd->get_firmware_status = hpe1_get_firmware_status;
 
 	hpe1->u.smart.in_valid_flags = 0;
 	hpe1->u.smart.in_valid_flags |= NDN_HPE1_SMART_HEALTH_VALID;
@@ -70,8 +82,6 @@  static struct ndctl_cmd *hpe1_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
 	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;
 }
 
@@ -285,8 +295,7 @@  static struct ndctl_cmd *hpe1_dimm_cmd_new_smart_threshold(struct ndctl_dimm *di
 	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;
+	cmd->get_firmware_status = hpe1_get_firmware_status;
 
 	return cmd;
 }
diff --git a/ndctl/lib/hyperv.c b/ndctl/lib/hyperv.c
index 9b4fe122af2c..ba1b12111804 100644
--- a/ndctl/lib/hyperv.c
+++ b/ndctl/lib/hyperv.c
@@ -9,6 +9,11 @@ 
 #include "private.h"
 #include "hyperv.h"
 
+static u32 hyperv_get_firmware_status(struct ndctl_cmd *cmd)
+{
+	return cmd->hyperv->u.status;
+}
+
 static bool hyperv_cmd_is_supported(struct ndctl_dimm *dimm, int cmd)
 {
 	/*
@@ -50,6 +55,7 @@  static struct ndctl_cmd *alloc_hyperv_cmd(struct ndctl_dimm *dimm,
 
 	cmd->dimm = dimm;
 	cmd->type = ND_CMD_CALL;
+	cmd->get_firmware_status = hyperv_get_firmware_status;
 	cmd->size = size;
 	cmd->status = 1;
 
@@ -58,7 +64,6 @@  static struct ndctl_cmd *alloc_hyperv_cmd(struct ndctl_dimm *dimm,
 	hyperv->gen.nd_command = command;
 	hyperv->gen.nd_size_out = sizeof(hyperv->u.health_info);
 
-	cmd->firmware_status = &hyperv->u.health_info.status;
 	return cmd;
 }
 
diff --git a/ndctl/lib/intel.c b/ndctl/lib/intel.c
index d684bac03fec..ebcefd8b5ad2 100644
--- a/ndctl/lib/intel.c
+++ b/ndctl/lib/intel.c
@@ -16,13 +16,49 @@ 
 #include <ndctl/libndctl.h>
 #include "private.h"
 
+static unsigned int intel_cmd_get_firmware_status(struct ndctl_cmd *cmd)
+{
+	struct nd_pkg_intel *intel = cmd->intel;
+
+	switch (intel->gen.nd_command) {
+	case ND_INTEL_SMART:
+		return intel->smart.status;
+	case ND_INTEL_SMART_THRESHOLD:
+		return intel->thresh.status;
+	case ND_INTEL_SMART_SET_THRESHOLD:
+		return intel->set_thresh.status;
+	case ND_INTEL_SMART_INJECT:
+		return intel->inject.status;
+	case ND_INTEL_FW_GET_INFO:
+		return intel->info.status;
+	case ND_INTEL_FW_START_UPDATE:
+		return intel->start.status;
+	case ND_INTEL_FW_SEND_DATA: {
+		    struct nd_intel_fw_send_data *send = &intel->send;
+		    u32 status;
+
+		    /* the last dword after the payload is reserved for status */
+		    memcpy(&status, ((void *) send) + sizeof(*send) + send->length,
+				    sizeof(status));
+		    return status;
+	}
+	case ND_INTEL_FW_FINISH_UPDATE:
+		return intel->finish.status;
+	case ND_INTEL_FW_FINISH_STATUS_QUERY:
+		return intel->fquery.status;
+	case ND_INTEL_ENABLE_LSS_STATUS:
+		return intel->lss.status;
+	}
+	return -1U;
+}
+
 static int intel_cmd_xlat_firmware_status(struct ndctl_cmd *cmd)
 {
 	struct nd_pkg_intel *pkg = cmd->intel;
 	unsigned int status, ext_status;
 
-	status = (*cmd->firmware_status) & ND_INTEL_STATUS_MASK;
-	ext_status = (*cmd->firmware_status) & ND_INTEL_STATUS_EXTEND_MASK;
+	status = cmd->get_firmware_status(cmd) & ND_INTEL_STATUS_MASK;
+	ext_status = cmd->get_firmware_status(cmd) & ND_INTEL_STATUS_EXTEND_MASK;
 
 	/* Common statuses */
 	switch (status) {
@@ -91,6 +127,7 @@  static struct ndctl_cmd *alloc_intel_cmd(struct ndctl_dimm *dimm,
 	cmd->type = ND_CMD_CALL;
 	cmd->size = size;
 	cmd->status = 1;
+	cmd->get_firmware_status = intel_cmd_get_firmware_status;
 
 	*(cmd->intel) = (struct nd_pkg_intel) {
 		.gen = {
@@ -114,7 +151,6 @@  static struct ndctl_cmd *intel_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
 			0, sizeof(cmd->intel->smart));
 	if (!cmd)
 		return NULL;
-	cmd->firmware_status = &cmd->intel->smart.status;
 
 	return cmd;
 }
@@ -269,7 +305,6 @@  static struct ndctl_cmd *intel_dimm_cmd_new_smart_threshold(
 			0, sizeof(cmd->intel->thresh));
 	if (!cmd)
 		return NULL;
-	cmd->firmware_status = &cmd->intel->thresh.status;
 
 	return cmd;
 }
@@ -299,7 +334,6 @@  static struct ndctl_cmd *intel_dimm_cmd_new_smart_set_threshold(
 	set_thresh->spares = thresh->spares;
 	set_thresh->media_temperature = thresh->media_temperature;
 	set_thresh->ctrl_temperature = thresh->ctrl_temperature;
-	cmd->firmware_status = &set_thresh->status;
 
 	return cmd;
 }
@@ -360,7 +394,6 @@  static struct ndctl_cmd *intel_new_smart_inject(struct ndctl_dimm *dimm)
 			offsetof(struct nd_intel_smart_inject, status), 4);
 	if (!cmd)
 		return NULL;
-	cmd->firmware_status = &cmd->intel->inject.status;
 
 	return cmd;
 }
@@ -468,7 +501,6 @@  static struct ndctl_cmd *intel_dimm_cmd_new_fw_get_info(struct ndctl_dimm *dimm)
 	if (!cmd)
 		return NULL;
 
-	cmd->firmware_status = &cmd->intel->info.status;
 	return cmd;
 }
 
@@ -540,7 +572,6 @@  static struct ndctl_cmd *intel_dimm_cmd_new_fw_start(struct ndctl_dimm *dimm)
 	if (!cmd)
 		return NULL;
 
-	cmd->firmware_status = &cmd->intel->start.status;
 	return cmd;
 }
 
@@ -583,9 +614,6 @@  static struct ndctl_cmd *intel_dimm_cmd_new_fw_send(struct ndctl_cmd *start,
 	cmd->intel->send.offset = offset;
 	cmd->intel->send.length = len;
 	memcpy(cmd->intel->send.data, data, len);
-	/* the last dword is reserved for status */
-	cmd->firmware_status =
-		(unsigned int *)(&cmd->intel->send.data[0] + len);
 	return cmd;
 }
 
@@ -602,7 +630,6 @@  static struct ndctl_cmd *intel_dimm_cmd_new_fw_finish(struct ndctl_cmd *start)
 
 	cmd->intel->finish.context = start->intel->start.context;
 	cmd->intel->finish.ctrl_flags = 0;
-	cmd->firmware_status = &cmd->intel->finish.status;
 	return cmd;
 }
 
@@ -619,7 +646,6 @@  static struct ndctl_cmd *intel_dimm_cmd_new_fw_abort(struct ndctl_cmd *start)
 
 	cmd->intel->finish.context = start->intel->start.context;
 	cmd->intel->finish.ctrl_flags = 1;
-	cmd->firmware_status = &cmd->intel->finish.status;
 	return cmd;
 }
 
@@ -636,7 +662,6 @@  intel_dimm_cmd_new_fw_finish_query(struct ndctl_cmd *start)
 		return NULL;
 
 	cmd->intel->fquery.context = start->intel->start.context;
-	cmd->firmware_status = &cmd->intel->fquery.status;
 	return cmd;
 }
 
@@ -704,7 +729,7 @@  intel_cmd_fw_xlat_extend_firmware_status(struct ndctl_cmd *cmd,
 static enum ND_FW_STATUS
 intel_cmd_fw_xlat_firmware_status(struct ndctl_cmd *cmd)
 {
-	unsigned int status = *cmd->firmware_status;
+	unsigned int status = intel_cmd_get_firmware_status(cmd);
 
 	switch (status & ND_INTEL_STATUS_MASK) {
 	case ND_INTEL_STATUS_SUCCESS:
@@ -742,7 +767,6 @@  intel_dimm_cmd_new_lss(struct ndctl_dimm *dimm)
 		return NULL;
 
 	cmd->intel->lss.enable = 1;
-	cmd->firmware_status = &cmd->intel->lss.status;
 	return cmd;
 }
 
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 9ad1b7091dc0..97fd98545440 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -2506,6 +2506,23 @@  static struct nd_cmd_vendor_tail *to_vendor_tail(struct ndctl_cmd *cmd)
 	return tail;
 }
 
+static u32 cmd_get_firmware_status(struct ndctl_cmd *cmd)
+{
+	switch (cmd->type) {
+	case ND_CMD_VENDOR:
+		return to_vendor_tail(cmd)->status;
+	case ND_CMD_GET_CONFIG_SIZE:
+		return cmd->get_size->status;
+	case ND_CMD_GET_CONFIG_DATA:
+		return cmd->get_data->status;
+	case ND_CMD_SET_CONFIG_DATA:
+		return *(u32 *) (cmd->cmd_buf
+				+ sizeof(struct nd_cmd_set_config_hdr)
+				+ cmd->iter.max_xfer);
+	}
+	return -1U;
+}
+
 NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_vendor_specific(
 		struct ndctl_dimm *dimm, unsigned int opcode, size_t input_size,
 		size_t output_size)
@@ -2535,7 +2552,7 @@  NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_vendor_specific(
 	cmd->status = 1;
 	cmd->vendor->opcode = opcode;
 	cmd->vendor->in_length = input_size;
-	cmd->firmware_status = &to_vendor_tail(cmd)->status;
+	cmd->get_firmware_status = cmd_get_firmware_status;
 	to_vendor_tail(cmd)->out_length = output_size;
 
 	return cmd;
@@ -2600,7 +2617,7 @@  NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_cfg_size(struct ndctl_dimm *di
 	cmd->type = ND_CMD_GET_CONFIG_SIZE;
 	cmd->size = size;
 	cmd->status = 1;
-	cmd->firmware_status = &cmd->get_size->status;
+	cmd->get_firmware_status = cmd_get_firmware_status;
 
 	return cmd;
 }
@@ -2641,7 +2658,7 @@  NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_cfg_read(struct ndctl_cmd *cfg
 	cmd->status = 1;
 	cmd->get_data->in_offset = 0;
 	cmd->get_data->in_length = cfg_size->get_size->max_xfer;
-	cmd->firmware_status = &cmd->get_data->status;
+	cmd->get_firmware_status = cmd_get_firmware_status;
 	cmd->iter.init_offset = 0;
 	cmd->iter.offset = &cmd->get_data->in_offset;
 	cmd->iter.xfer = &cmd->get_data->in_length;
@@ -2728,8 +2745,7 @@  NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_cfg_write(struct ndctl_cmd *cf
 	cmd->status = 1;
 	cmd->set_data->in_offset = cfg_read->iter.init_offset;
 	cmd->set_data->in_length = cfg_read->iter.max_xfer;
-	cmd->firmware_status = (u32 *) (cmd->cmd_buf
-		+ sizeof(struct nd_cmd_set_config_hdr) + cfg_read->iter.max_xfer);
+	cmd->get_firmware_status = cmd_get_firmware_status;
 	cmd->iter.init_offset = cfg_read->iter.init_offset;
 	cmd->iter.offset = &cmd->set_data->in_offset;
 	cmd->iter.xfer = &cmd->set_data->in_length;
@@ -2936,7 +2952,7 @@  static int do_cmd(int fd, int ioctl_cmd, struct ndctl_cmd *cmd)
 		dbg(ctx, "bus: %d dimm: %#x cmd: %s%s%s status: %d fw: %d (%s)\n",
 				bus->id, dimm ? ndctl_dimm_get_handle(dimm) : 0,
 				name, sub_name ? ":" : "", sub_name ? sub_name : "",
-				rc, *(cmd->firmware_status), rc < 0 ?
+				rc, cmd->get_firmware_status(cmd), rc < 0 ?
 				strerror(errno) : "success");
 		if (rc < 0)
 			return -errno;
@@ -2960,7 +2976,7 @@  static int do_cmd(int fd, int ioctl_cmd, struct ndctl_cmd *cmd)
 		if (iter->dir == READ)
 			memcpy(iter->total_buf + offset, iter->data,
 					*(cmd->iter.xfer) - rc);
-		if (*(cmd->firmware_status) || rc) {
+		if (cmd->get_firmware_status(cmd) || rc) {
 			rc = offset + *(cmd->iter.xfer) - rc;
 			break;
 		}
@@ -2970,7 +2986,7 @@  static int do_cmd(int fd, int ioctl_cmd, struct ndctl_cmd *cmd)
 			bus->id, dimm ? ndctl_dimm_get_handle(dimm) : 0,
 			name, sub_name ? ":" : "", sub_name ? sub_name : "",
 			iter->total_xfer, iter->max_xfer, rc,
-			*(cmd->firmware_status),
+			cmd->get_firmware_status(cmd),
 			rc < 0 ? strerror(errno) : "success");
 
 	return rc;
@@ -2986,6 +3002,11 @@  NDCTL_EXPORT int ndctl_cmd_submit(struct ndctl_cmd *cmd)
 	struct ndctl_bus *bus = cmd_to_bus(cmd);
 	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
 
+	if (!cmd->get_firmware_status) {
+		err(ctx, "missing status retrieval\n");
+		return -EINVAL;
+	}
+
 	if (ioctl_cmd == 0) {
 		rc = -EINVAL;
 		goto out;
@@ -3054,7 +3075,7 @@  NDCTL_EXPORT int ndctl_cmd_get_status(struct ndctl_cmd *cmd)
 
 NDCTL_EXPORT unsigned int ndctl_cmd_get_firmware_status(struct ndctl_cmd *cmd)
 {
-	return *(cmd->firmware_status);
+	return cmd->get_firmware_status(cmd);
 }
 
 NDCTL_EXPORT const char *ndctl_region_get_devname(struct ndctl_region *region)
diff --git a/ndctl/lib/msft.c b/ndctl/lib/msft.c
index 19453cd86143..c060b1f2609e 100644
--- a/ndctl/lib/msft.c
+++ b/ndctl/lib/msft.c
@@ -22,6 +22,11 @@ 
 #define CMD_MSFT(_c) ((_c)->msft)
 #define CMD_MSFT_SMART(_c) (CMD_MSFT(_c)->u.smart.data)
 
+static u32 msft_get_firmware_status(struct ndctl_cmd *cmd)
+{
+	return cmd->msft->u.smart.status;
+}
+
 static struct ndctl_cmd *msft_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
 {
 	struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm);
@@ -58,8 +63,7 @@  static struct ndctl_cmd *msft_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
 	msft->gen.nd_size_in = offsetof(struct ndn_msft_smart, status);
 	msft->gen.nd_size_out = sizeof(msft->u.smart);
 	msft->u.smart.status = 0;
-
-	cmd->firmware_status = &msft->u.smart.status;
+	cmd->get_firmware_status = msft_get_firmware_status;
 
 	return cmd;
 }
diff --git a/ndctl/lib/nfit.c b/ndctl/lib/nfit.c
index b10edb1943e8..f9fbe73f7446 100644
--- a/ndctl/lib/nfit.c
+++ b/ndctl/lib/nfit.c
@@ -15,6 +15,24 @@ 
 #include "private.h"
 #include <ndctl/libndctl-nfit.h>
 
+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 NFIT_CMD_TRANSLATE_SPA:
+		return cmd_bus->xlat_spa.status;
+	case NFIT_CMD_ARS_INJECT_SET:
+		return cmd_bus->err_inj.status;
+	case NFIT_CMD_ARS_INJECT_CLEAR:
+		return cmd_bus->err_inj_clr.status;
+	case NFIT_CMD_ARS_INJECT_GET:
+		return cmd_bus->err_inj_stat.status;
+	}
+
+	return -1U;
+}
+
 /**
  * ndctl_bus_is_nfit_cmd_supported - ask nfit command is supported on @bus.
  * @bus: ndctl_bus instance
@@ -54,15 +72,15 @@  static struct ndctl_cmd *ndctl_bus_cmd_new_translate_spa(struct ndctl_bus *bus)
 	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 = &cmd->cmd_bus->gen;
 	pkg->nd_command = NFIT_CMD_TRANSLATE_SPA;
 	pkg->nd_size_in = sizeof(unsigned long long);
 	pkg->nd_size_out = spa_length;
 	pkg->nd_fw_size = spa_length;
-	translate_spa = (struct nd_cmd_translate_spa *)&pkg->nd_payload[0];
-	cmd->firmware_status = &translate_spa->status;
+	translate_spa = &cmd->cmd_bus->xlat_spa;
 	translate_spa->translate_length = spa_length;
 
 	return cmd;
@@ -146,7 +164,6 @@  int ndctl_bus_nfit_translate_spa(struct ndctl_bus *bus,
 
 struct ndctl_cmd *ndctl_bus_cmd_new_err_inj(struct ndctl_bus *bus)
 {
-	struct nd_cmd_ars_err_inj *err_inj;
 	size_t size, cmd_length;
 	struct nd_cmd_pkg *pkg;
 	struct ndctl_cmd *cmd;
@@ -160,6 +177,7 @@  struct ndctl_cmd *ndctl_bus_cmd_new_err_inj(struct ndctl_bus *bus)
 	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];
@@ -167,15 +185,12 @@  struct ndctl_cmd *ndctl_bus_cmd_new_err_inj(struct ndctl_bus *bus)
 	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;
-	err_inj = (struct nd_cmd_ars_err_inj *)&pkg->nd_payload[0];
-	cmd->firmware_status = &err_inj->status;
 
 	return cmd;
 }
 
 struct ndctl_cmd *ndctl_bus_cmd_new_err_inj_clr(struct ndctl_bus *bus)
 {
-	struct nd_cmd_ars_err_inj_clr *err_inj_clr;
 	size_t size, cmd_length;
 	struct nd_cmd_pkg *pkg;
 	struct ndctl_cmd *cmd;
@@ -189,6 +204,7 @@  struct ndctl_cmd *ndctl_bus_cmd_new_err_inj_clr(struct ndctl_bus *bus)
 	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];
@@ -196,8 +212,6 @@  struct ndctl_cmd *ndctl_bus_cmd_new_err_inj_clr(struct ndctl_bus *bus)
 	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;
-	err_inj_clr = (struct nd_cmd_ars_err_inj_clr *)&pkg->nd_payload[0];
-	cmd->firmware_status = &err_inj_clr->status;
 
 	return cmd;
 }
@@ -205,7 +219,6 @@  struct ndctl_cmd *ndctl_bus_cmd_new_err_inj_clr(struct ndctl_bus *bus)
 struct ndctl_cmd *ndctl_bus_cmd_new_err_inj_stat(struct ndctl_bus *bus,
 	u32 buf_size)
 {
-	struct nd_cmd_ars_err_inj_stat *err_inj_stat;
 	size_t size, cmd_length;
 	struct nd_cmd_pkg *pkg;
 	struct ndctl_cmd *cmd;
@@ -220,6 +233,7 @@  struct ndctl_cmd *ndctl_bus_cmd_new_err_inj_stat(struct ndctl_bus *bus,
 	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];
@@ -227,8 +241,6 @@  struct ndctl_cmd *ndctl_bus_cmd_new_err_inj_stat(struct ndctl_bus *bus,
 	pkg->nd_size_in = 0;
 	pkg->nd_size_out = cmd_length + buf_size;
 	pkg->nd_fw_size = pkg->nd_size_out;
-	err_inj_stat = (struct nd_cmd_ars_err_inj_stat *)&pkg->nd_payload[0];
-	cmd->firmware_status = &err_inj_stat->status;
 
 	return cmd;
 }
diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h
index 16bf8f953828..3c121bd00437 100644
--- a/ndctl/lib/private.h
+++ b/ndctl/lib/private.h
@@ -32,6 +32,7 @@ 
 #include "hpe1.h"
 #include "msft.h"
 #include "hyperv.h"
+#include "libndctl-nfit.h"
 
 struct nvdimm_data {
 	struct ndctl_cmd *cmd_read;
@@ -233,7 +234,7 @@  struct ndctl_namespace {
  * @type: cmd number
  * @size: total size of the ndctl_cmd allocation
  * @status: negative if failed, 0 if success, > 0 if never submitted
- * @firmware_status: NFIT command output status code
+ * @get_firmware_status: per command firmware status field retrieval
  * @iter: iterator for multi-xfer commands
  * @source: source cmd of an inherited iter.total_buf
  *
@@ -250,7 +251,7 @@  struct ndctl_cmd {
 	int type;
 	int size;
 	int status;
-	u32 *firmware_status;
+	u32 (*get_firmware_status)(struct ndctl_cmd *cmd);
 	struct ndctl_cmd_iter {
 		u32 init_offset;
 		u32 *offset;
@@ -268,6 +269,7 @@  struct ndctl_cmd {
 		struct nd_cmd_ars_status ars_status[0];
 		struct nd_cmd_clear_error clear_err[0];
 		struct nd_cmd_pkg pkg[0];
+		struct nd_cmd_bus cmd_bus[0];
 		struct ndn_pkg_hpe1 hpe1[0];
 		struct ndn_pkg_msft msft[0];
 		struct nd_pkg_hyperv hyperv[0];
@@ -341,6 +343,7 @@  struct ndctl_dimm_ops {
 	struct ndctl_cmd *(*new_ack_shutdown_count)(struct ndctl_dimm *);
 	int (*fw_update_supported)(struct ndctl_dimm *);
 	int (*xlat_firmware_status)(struct ndctl_cmd *);
+	u32 (*get_firmware_status)(struct ndctl_cmd *);
 };
 
 extern struct ndctl_dimm_ops * const intel_dimm_ops;
diff --git a/ndctl/libndctl-nfit.h b/ndctl/libndctl-nfit.h
index d5335c23d28b..8c4f72dfa7ec 100644
--- a/ndctl/libndctl-nfit.h
+++ b/ndctl/libndctl-nfit.h
@@ -17,6 +17,7 @@ 
 #define __LIBNDCTL_NFIT_H__
 
 #include <linux/types.h>
+#include <ndctl/ndctl.h>
 
 /*
  * libndctl-nfit.h : definitions for NFIT related commands/functions.
@@ -87,6 +88,16 @@  struct nd_cmd_ars_err_inj_stat {
 	} __attribute__((packed)) record[0];
 } __attribute__((packed));
 
+struct nd_cmd_bus {
+	struct nd_cmd_pkg gen;
+	union {
+		struct nd_cmd_ars_err_inj_stat err_inj_stat;
+		struct nd_cmd_ars_err_inj_clr err_inj_clr;
+		struct nd_cmd_ars_err_inj err_inj;
+		struct nd_cmd_translate_spa xlat_spa;
+	};
+};
+
 int ndctl_bus_is_nfit_cmd_supported(struct ndctl_bus *bus, int cmd);
 
 #endif /* __LIBNDCTL_NFIT_H__ */