anitazha / rpms / ndctl

Forked from rpms/ndctl 2 years ago
Clone

Blame 0035-libcxl-add-support-for-command-query-and-submission.patch

Jeff Moyer 2c91dc
From 96afebd1b32ff839129f3bc0ba323ab5f04674ea Mon Sep 17 00:00:00 2001
Jeff Moyer 2c91dc
From: Vishal Verma <vishal.l.verma@intel.com>
Jeff Moyer 2c91dc
Date: Thu, 7 Oct 2021 02:21:27 -0600
Jeff Moyer 2c91dc
Subject: [PATCH 035/217] libcxl: add support for command query and submission
Jeff Moyer 2c91dc
Jeff Moyer 2c91dc
Add a set of APIs around 'cxl_cmd' for querying the kernel for supported
Jeff Moyer 2c91dc
commands, allocating and validating command structures against the
Jeff Moyer 2c91dc
supported set, and submitting the commands.
Jeff Moyer 2c91dc
Jeff Moyer 2c91dc
'Query Commands' and 'Send Command' are implemented as IOCTLs in the
Jeff Moyer 2c91dc
kernel. 'Query Commands' returns information about each supported
Jeff Moyer 2c91dc
command, such as flags governing its use, or input and output payload
Jeff Moyer 2c91dc
sizes. This information is used to validate command support, as well as
Jeff Moyer 2c91dc
set up input and output buffers for command submission.
Jeff Moyer 2c91dc
Jeff Moyer 2c91dc
Cc: Ben Widawsky <ben.widawsky@intel.com>
Jeff Moyer 2c91dc
Cc: Dan Williams <dan.j.williams@intel.com>
Jeff Moyer 2c91dc
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Jeff Moyer 2c91dc
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Jeff Moyer 2c91dc
---
Jeff Moyer 2c91dc
 cxl/lib/libcxl.c   | 390 +++++++++++++++++++++++++++++++++++++++++++++
Jeff Moyer 2c91dc
 cxl/lib/libcxl.sym |   9 ++
Jeff Moyer 2c91dc
 cxl/lib/private.h  |  33 ++++
Jeff Moyer 2c91dc
 cxl/libcxl.h       |  11 ++
Jeff Moyer 2c91dc
 4 files changed, 443 insertions(+)
Jeff Moyer 2c91dc
Jeff Moyer 2c91dc
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
Jeff Moyer 2c91dc
index c15e987..727d599 100644
Jeff Moyer 2c91dc
--- a/cxl/lib/libcxl.c
Jeff Moyer 2c91dc
+++ b/cxl/lib/libcxl.c
Jeff Moyer 2c91dc
@@ -9,14 +9,17 @@
Jeff Moyer 2c91dc
 #include <unistd.h>
Jeff Moyer 2c91dc
 #include <sys/stat.h>
Jeff Moyer 2c91dc
 #include <sys/types.h>
Jeff Moyer 2c91dc
+#include <sys/ioctl.h>
Jeff Moyer 2c91dc
 #include <sys/sysmacros.h>
Jeff Moyer 2c91dc
 #include <uuid/uuid.h>
Jeff Moyer 2c91dc
 #include <ccan/list/list.h>
Jeff Moyer 2c91dc
 #include <ccan/array_size/array_size.h>
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
 #include <util/log.h>
Jeff Moyer 2c91dc
+#include <util/size.h>
Jeff Moyer 2c91dc
 #include <util/sysfs.h>
Jeff Moyer 2c91dc
 #include <util/bitmap.h>
Jeff Moyer 2c91dc
+#include <cxl/cxl_mem.h>
Jeff Moyer 2c91dc
 #include <cxl/libcxl.h>
Jeff Moyer 2c91dc
 #include "private.h"
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
@@ -343,3 +346,390 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev
Jeff Moyer 2c91dc
 {
Jeff Moyer 2c91dc
 	return memdev->firmware_version;
Jeff Moyer 2c91dc
 }
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	if (!cmd)
Jeff Moyer 2c91dc
+		return;
Jeff Moyer 2c91dc
+	if (--cmd->refcount == 0) {
Jeff Moyer 2c91dc
+		free(cmd->query_cmd);
Jeff Moyer 2c91dc
+		free(cmd->send_cmd);
Jeff Moyer 2c91dc
+		free(cmd->input_payload);
Jeff Moyer 2c91dc
+		free(cmd->output_payload);
Jeff Moyer 2c91dc
+		free(cmd);
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+CXL_EXPORT void cxl_cmd_ref(struct cxl_cmd *cmd)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	cmd->refcount++;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static int cxl_cmd_alloc_query(struct cxl_cmd *cmd, int num_cmds)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	size_t size;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (!cmd)
Jeff Moyer 2c91dc
+		return -EINVAL;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (cmd->query_cmd != NULL)
Jeff Moyer 2c91dc
+		free(cmd->query_cmd);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	size = struct_size(cmd->query_cmd, commands, num_cmds);
Jeff Moyer 2c91dc
+	if (size == SIZE_MAX)
Jeff Moyer 2c91dc
+		return -EOVERFLOW;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	cmd->query_cmd = calloc(1, size);
Jeff Moyer 2c91dc
+	if (!cmd->query_cmd)
Jeff Moyer 2c91dc
+		return -ENOMEM;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	cmd->query_cmd->n_commands = num_cmds;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	return 0;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static struct cxl_cmd *cxl_cmd_new(struct cxl_memdev *memdev)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_cmd *cmd;
Jeff Moyer 2c91dc
+	size_t size;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	size = sizeof(*cmd);
Jeff Moyer 2c91dc
+	cmd = calloc(1, size);
Jeff Moyer 2c91dc
+	if (!cmd)
Jeff Moyer 2c91dc
+		return NULL;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	cxl_cmd_ref(cmd);
Jeff Moyer 2c91dc
+	cmd->memdev = memdev;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	return cmd;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static int __do_cmd(struct cxl_cmd *cmd, int ioctl_cmd, int fd)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	void *cmd_buf;
Jeff Moyer 2c91dc
+	int rc;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	switch (ioctl_cmd) {
Jeff Moyer 2c91dc
+	case CXL_MEM_QUERY_COMMANDS:
Jeff Moyer 2c91dc
+		cmd_buf = cmd->query_cmd;
Jeff Moyer 2c91dc
+		break;
Jeff Moyer 2c91dc
+	case CXL_MEM_SEND_COMMAND:
Jeff Moyer 2c91dc
+		cmd_buf = cmd->send_cmd;
Jeff Moyer 2c91dc
+		break;
Jeff Moyer 2c91dc
+	default:
Jeff Moyer 2c91dc
+		return -EINVAL;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	rc = ioctl(fd, ioctl_cmd, cmd_buf);
Jeff Moyer 2c91dc
+	if (rc < 0)
Jeff Moyer 2c91dc
+		rc = -errno;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	return rc;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static int do_cmd(struct cxl_cmd *cmd, int ioctl_cmd)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	char *path;
Jeff Moyer 2c91dc
+	struct stat st;
Jeff Moyer 2c91dc
+	unsigned int major, minor;
Jeff Moyer 2c91dc
+	int rc = 0, fd;
Jeff Moyer 2c91dc
+	struct cxl_memdev *memdev = cmd->memdev;
Jeff Moyer 2c91dc
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
Jeff Moyer 2c91dc
+	const char *devname = cxl_memdev_get_devname(memdev);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	major = cxl_memdev_get_major(memdev);
Jeff Moyer 2c91dc
+	minor = cxl_memdev_get_minor(memdev);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (asprintf(&path, "/dev/cxl/%s", devname) < 0)
Jeff Moyer 2c91dc
+		return -ENOMEM;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	fd = open(path, O_RDWR);
Jeff Moyer 2c91dc
+	if (fd < 0) {
Jeff Moyer 2c91dc
+		err(ctx, "failed to open %s: %s\n", path, strerror(errno));
Jeff Moyer 2c91dc
+		rc = -errno;
Jeff Moyer 2c91dc
+		goto out;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (fstat(fd, &st) >= 0 && S_ISCHR(st.st_mode)
Jeff Moyer 2c91dc
+			&& major(st.st_rdev) == major
Jeff Moyer 2c91dc
+			&& minor(st.st_rdev) == minor) {
Jeff Moyer 2c91dc
+		rc = __do_cmd(cmd, ioctl_cmd, fd);
Jeff Moyer 2c91dc
+	} else {
Jeff Moyer 2c91dc
+		err(ctx, "failed to validate %s as a CXL memdev node\n", path);
Jeff Moyer 2c91dc
+		rc = -ENXIO;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+	close(fd);
Jeff Moyer 2c91dc
+out:
Jeff Moyer 2c91dc
+	free(path);
Jeff Moyer 2c91dc
+	return rc;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static int alloc_do_query(struct cxl_cmd *cmd, int num_cmds)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(cmd->memdev);
Jeff Moyer 2c91dc
+	int rc;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	rc = cxl_cmd_alloc_query(cmd, num_cmds);
Jeff Moyer 2c91dc
+	if (rc)
Jeff Moyer 2c91dc
+		return rc;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	rc = do_cmd(cmd, CXL_MEM_QUERY_COMMANDS);
Jeff Moyer 2c91dc
+	if (rc < 0)
Jeff Moyer 2c91dc
+		err(ctx, "%s: query commands failed: %s\n",
Jeff Moyer 2c91dc
+			cxl_memdev_get_devname(cmd->memdev),
Jeff Moyer 2c91dc
+			strerror(-rc));
Jeff Moyer 2c91dc
+	return rc;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static int cxl_cmd_do_query(struct cxl_cmd *cmd)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_memdev *memdev = cmd->memdev;
Jeff Moyer 2c91dc
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
Jeff Moyer 2c91dc
+	const char *devname = cxl_memdev_get_devname(memdev);
Jeff Moyer 2c91dc
+	int rc, n_commands;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	switch (cmd->query_status) {
Jeff Moyer 2c91dc
+	case CXL_CMD_QUERY_OK:
Jeff Moyer 2c91dc
+		return 0;
Jeff Moyer 2c91dc
+	case CXL_CMD_QUERY_UNSUPPORTED:
Jeff Moyer 2c91dc
+		return -EOPNOTSUPP;
Jeff Moyer 2c91dc
+	case CXL_CMD_QUERY_NOT_RUN:
Jeff Moyer 2c91dc
+		break;
Jeff Moyer 2c91dc
+	default:
Jeff Moyer 2c91dc
+		err(ctx, "%s: Unknown query_status %d\n",
Jeff Moyer 2c91dc
+			devname, cmd->query_status);
Jeff Moyer 2c91dc
+		return -EINVAL;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	rc = alloc_do_query(cmd, 0);
Jeff Moyer 2c91dc
+	if (rc)
Jeff Moyer 2c91dc
+		return rc;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	n_commands = cmd->query_cmd->n_commands;
Jeff Moyer 2c91dc
+	dbg(ctx, "%s: supports %d commands\n", devname, n_commands);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	return alloc_do_query(cmd, n_commands);
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static int cxl_cmd_validate(struct cxl_cmd *cmd, u32 cmd_id)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_memdev *memdev = cmd->memdev;
Jeff Moyer 2c91dc
+	struct cxl_mem_query_commands *query = cmd->query_cmd;
Jeff Moyer 2c91dc
+	const char *devname = cxl_memdev_get_devname(memdev);
Jeff Moyer 2c91dc
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
Jeff Moyer 2c91dc
+	u32 i;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	for (i = 0; i < query->n_commands; i++) {
Jeff Moyer 2c91dc
+		struct cxl_command_info *cinfo = &query->commands[i];
Jeff Moyer 2c91dc
+		const char *cmd_name = cxl_command_names[cinfo->id].name;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+		if (cinfo->id != cmd_id)
Jeff Moyer 2c91dc
+			continue;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+		dbg(ctx, "%s: %s: in: %d, out %d, flags: %#08x\n",
Jeff Moyer 2c91dc
+			devname, cmd_name, cinfo->size_in,
Jeff Moyer 2c91dc
+			cinfo->size_out, cinfo->flags);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+		cmd->query_idx = i;
Jeff Moyer 2c91dc
+		cmd->query_status = CXL_CMD_QUERY_OK;
Jeff Moyer 2c91dc
+		return 0;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+	cmd->query_status = CXL_CMD_QUERY_UNSUPPORTED;
Jeff Moyer 2c91dc
+	return -EOPNOTSUPP;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+CXL_EXPORT int cxl_cmd_set_input_payload(struct cxl_cmd *cmd, void *buf,
Jeff Moyer 2c91dc
+		int size)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_memdev *memdev = cmd->memdev;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (size > memdev->payload_max || size < 0)
Jeff Moyer 2c91dc
+		return -EINVAL;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (!buf) {
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+		/* If the user didn't supply a buffer, allocate it */
Jeff Moyer 2c91dc
+		cmd->input_payload = calloc(1, size);
Jeff Moyer 2c91dc
+		if (!cmd->input_payload)
Jeff Moyer 2c91dc
+			return -ENOMEM;
Jeff Moyer 2c91dc
+		cmd->send_cmd->in.payload = (u64)cmd->input_payload;
Jeff Moyer 2c91dc
+	} else {
Jeff Moyer 2c91dc
+		/*
Jeff Moyer 2c91dc
+		 * Use user-buffer as is. If an automatic allocation was
Jeff Moyer 2c91dc
+		 * previously made (based on a fixed size from query),
Jeff Moyer 2c91dc
+		 * it will get freed during unref.
Jeff Moyer 2c91dc
+		 */
Jeff Moyer 2c91dc
+		cmd->send_cmd->in.payload = (u64)buf;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+	cmd->send_cmd->in.size = size;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	return 0;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+CXL_EXPORT int cxl_cmd_set_output_payload(struct cxl_cmd *cmd, void *buf,
Jeff Moyer 2c91dc
+		int size)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_memdev *memdev = cmd->memdev;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (size > memdev->payload_max || size < 0)
Jeff Moyer 2c91dc
+		return -EINVAL;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (!buf) {
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+		/* If the user didn't supply a buffer, allocate it */
Jeff Moyer 2c91dc
+		cmd->output_payload = calloc(1, size);
Jeff Moyer 2c91dc
+		if (!cmd->output_payload)
Jeff Moyer 2c91dc
+			return -ENOMEM;
Jeff Moyer 2c91dc
+		cmd->send_cmd->out.payload = (u64)cmd->output_payload;
Jeff Moyer 2c91dc
+	} else {
Jeff Moyer 2c91dc
+		/*
Jeff Moyer 2c91dc
+		 * Use user-buffer as is. If an automatic allocation was
Jeff Moyer 2c91dc
+		 * previously made (based on a fixed size from query),
Jeff Moyer 2c91dc
+		 * it will get freed during unref.
Jeff Moyer 2c91dc
+		 */
Jeff Moyer 2c91dc
+		cmd->send_cmd->out.payload = (u64)buf;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+	cmd->send_cmd->out.size = size;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	return 0;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static int cxl_cmd_alloc_send(struct cxl_cmd *cmd, u32 cmd_id)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_mem_query_commands *query = cmd->query_cmd;
Jeff Moyer 2c91dc
+	struct cxl_command_info *cinfo = &query->commands[cmd->query_idx];
Jeff Moyer 2c91dc
+	size_t size;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (!query)
Jeff Moyer 2c91dc
+		return -EINVAL;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	size = sizeof(struct cxl_send_command);
Jeff Moyer 2c91dc
+	cmd->send_cmd = calloc(1, size);
Jeff Moyer 2c91dc
+	if (!cmd->send_cmd)
Jeff Moyer 2c91dc
+		return -ENOMEM;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (cinfo->id != cmd_id)
Jeff Moyer 2c91dc
+		return -EINVAL;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	cmd->send_cmd->id = cmd_id;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (cinfo->size_in > 0) {
Jeff Moyer 2c91dc
+		cmd->input_payload = calloc(1, cinfo->size_in);
Jeff Moyer 2c91dc
+		if (!cmd->input_payload)
Jeff Moyer 2c91dc
+			return -ENOMEM;
Jeff Moyer 2c91dc
+		cmd->send_cmd->in.payload = (u64)cmd->input_payload;
Jeff Moyer 2c91dc
+		cmd->send_cmd->in.size = cinfo->size_in;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+	if (cinfo->size_out > 0) {
Jeff Moyer 2c91dc
+		cmd->output_payload = calloc(1, cinfo->size_out);
Jeff Moyer 2c91dc
+		if (!cmd->output_payload)
Jeff Moyer 2c91dc
+			return -ENOMEM;
Jeff Moyer 2c91dc
+		cmd->send_cmd->out.payload = (u64)cmd->output_payload;
Jeff Moyer 2c91dc
+		cmd->send_cmd->out.size = cinfo->size_out;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	return 0;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static struct cxl_cmd *cxl_cmd_new_generic(struct cxl_memdev *memdev,
Jeff Moyer 2c91dc
+		u32 cmd_id)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	const char *devname = cxl_memdev_get_devname(memdev);
Jeff Moyer 2c91dc
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
Jeff Moyer 2c91dc
+	struct cxl_cmd *cmd;
Jeff Moyer 2c91dc
+	int rc;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	cmd = cxl_cmd_new(memdev);
Jeff Moyer 2c91dc
+	if (!cmd)
Jeff Moyer 2c91dc
+		return NULL;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	rc = cxl_cmd_do_query(cmd);
Jeff Moyer 2c91dc
+	if (rc) {
Jeff Moyer 2c91dc
+		err(ctx, "%s: query returned: %s\n", devname, strerror(-rc));
Jeff Moyer 2c91dc
+		goto fail;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	rc = cxl_cmd_validate(cmd, cmd_id);
Jeff Moyer 2c91dc
+	if (rc) {
Jeff Moyer 2c91dc
+		errno = -rc;
Jeff Moyer 2c91dc
+		goto fail;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	rc = cxl_cmd_alloc_send(cmd, cmd_id);
Jeff Moyer 2c91dc
+	if (rc) {
Jeff Moyer 2c91dc
+		errno = -rc;
Jeff Moyer 2c91dc
+		goto fail;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	cmd->status = 1;
Jeff Moyer 2c91dc
+	return cmd;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+fail:
Jeff Moyer 2c91dc
+	cxl_cmd_unref(cmd);
Jeff Moyer 2c91dc
+	return NULL;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+CXL_EXPORT const char *cxl_cmd_get_devname(struct cxl_cmd *cmd)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	return cxl_memdev_get_devname(cmd->memdev);
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+CXL_EXPORT struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev,
Jeff Moyer 2c91dc
+		int opcode)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_cmd *cmd;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	/* opcode '0' is reserved */
Jeff Moyer 2c91dc
+	if (opcode <= 0) {
Jeff Moyer 2c91dc
+		errno = EINVAL;
Jeff Moyer 2c91dc
+		return NULL;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_RAW);
Jeff Moyer 2c91dc
+	if (!cmd)
Jeff Moyer 2c91dc
+		return NULL;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	cmd->send_cmd->raw.opcode = opcode;
Jeff Moyer 2c91dc
+	return cmd;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+CXL_EXPORT int cxl_cmd_submit(struct cxl_cmd *cmd)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_memdev *memdev = cmd->memdev;
Jeff Moyer 2c91dc
+	const char *devname = cxl_memdev_get_devname(memdev);
Jeff Moyer 2c91dc
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
Jeff Moyer 2c91dc
+	int rc;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	switch (cmd->query_status) {
Jeff Moyer 2c91dc
+	case CXL_CMD_QUERY_OK:
Jeff Moyer 2c91dc
+		break;
Jeff Moyer 2c91dc
+	case CXL_CMD_QUERY_UNSUPPORTED:
Jeff Moyer 2c91dc
+		return -EOPNOTSUPP;
Jeff Moyer 2c91dc
+	case CXL_CMD_QUERY_NOT_RUN:
Jeff Moyer 2c91dc
+		return -EINVAL;
Jeff Moyer 2c91dc
+	default:
Jeff Moyer 2c91dc
+		err(ctx, "%s: Unknown query_status %d\n",
Jeff Moyer 2c91dc
+			devname, cmd->query_status);
Jeff Moyer 2c91dc
+		return -EINVAL;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	dbg(ctx, "%s: submitting SEND cmd: in: %d, out: %d\n", devname,
Jeff Moyer 2c91dc
+		cmd->send_cmd->in.size, cmd->send_cmd->out.size);
Jeff Moyer 2c91dc
+	rc = do_cmd(cmd, CXL_MEM_SEND_COMMAND);
Jeff Moyer 2c91dc
+	cmd->status = cmd->send_cmd->retval;
Jeff Moyer 2c91dc
+	dbg(ctx, "%s: got SEND cmd: in: %d, out: %d, retval: %d, status: %d\n",
Jeff Moyer 2c91dc
+		devname, cmd->send_cmd->in.size, cmd->send_cmd->out.size,
Jeff Moyer 2c91dc
+		rc, cmd->status);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	return rc;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+CXL_EXPORT int cxl_cmd_get_mbox_status(struct cxl_cmd *cmd)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	return cmd->status;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+CXL_EXPORT int cxl_cmd_get_out_size(struct cxl_cmd *cmd)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	return cmd->send_cmd->out.size;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
Jeff Moyer 2c91dc
index 2616e5c..3900f90 100644
Jeff Moyer 2c91dc
--- a/cxl/lib/libcxl.sym
Jeff Moyer 2c91dc
+++ b/cxl/lib/libcxl.sym
Jeff Moyer 2c91dc
@@ -20,6 +20,15 @@ global:
Jeff Moyer 2c91dc
 	cxl_memdev_get_pmem_size;
Jeff Moyer 2c91dc
 	cxl_memdev_get_ram_size;
Jeff Moyer 2c91dc
 	cxl_memdev_get_firmware_verison;
Jeff Moyer 2c91dc
+	cxl_cmd_get_devname;
Jeff Moyer 2c91dc
+	cxl_cmd_new_raw;
Jeff Moyer 2c91dc
+	cxl_cmd_set_input_payload;
Jeff Moyer 2c91dc
+	cxl_cmd_set_output_payload;
Jeff Moyer 2c91dc
+	cxl_cmd_ref;
Jeff Moyer 2c91dc
+	cxl_cmd_unref;
Jeff Moyer 2c91dc
+	cxl_cmd_submit;
Jeff Moyer 2c91dc
+	cxl_cmd_get_mbox_status;
Jeff Moyer 2c91dc
+	cxl_cmd_get_out_size;
Jeff Moyer 2c91dc
 local:
Jeff Moyer 2c91dc
         *;
Jeff Moyer 2c91dc
 };
Jeff Moyer 2c91dc
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
Jeff Moyer 2c91dc
index fc88fa1..87ca17e 100644
Jeff Moyer 2c91dc
--- a/cxl/lib/private.h
Jeff Moyer 2c91dc
+++ b/cxl/lib/private.h
Jeff Moyer 2c91dc
@@ -4,6 +4,9 @@
Jeff Moyer 2c91dc
 #define _LIBCXL_PRIVATE_H_
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
 #include <libkmod.h>
Jeff Moyer 2c91dc
+#include <cxl/cxl_mem.h>
Jeff Moyer 2c91dc
+#include <ccan/endian/endian.h>
Jeff Moyer 2c91dc
+#include <ccan/short_types/short_types.h>
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
 #define CXL_EXPORT __attribute__ ((visibility("default")))
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
@@ -21,6 +24,36 @@ struct cxl_memdev {
Jeff Moyer 2c91dc
 	struct kmod_module *module;
Jeff Moyer 2c91dc
 };
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
+enum cxl_cmd_query_status {
Jeff Moyer 2c91dc
+	CXL_CMD_QUERY_NOT_RUN = 0,
Jeff Moyer 2c91dc
+	CXL_CMD_QUERY_OK,
Jeff Moyer 2c91dc
+	CXL_CMD_QUERY_UNSUPPORTED,
Jeff Moyer 2c91dc
+};
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+/**
Jeff Moyer 2c91dc
+ * struct cxl_cmd - CXL memdev command
Jeff Moyer 2c91dc
+ * @memdev: the memory device to which the command is being sent
Jeff Moyer 2c91dc
+ * @query_cmd: structure for the Linux 'Query commands' ioctl
Jeff Moyer 2c91dc
+ * @send_cmd: structure for the Linux 'Send command' ioctl
Jeff Moyer 2c91dc
+ * @input_payload: buffer for input payload managed by libcxl
Jeff Moyer 2c91dc
+ * @output_payload: buffer for output payload managed by libcxl
Jeff Moyer 2c91dc
+ * @refcount: reference for passing command buffer around
Jeff Moyer 2c91dc
+ * @query_status: status from query_commands
Jeff Moyer 2c91dc
+ * @query_idx: index of 'this' command in the query_commands array
Jeff Moyer 2c91dc
+ * @status: command return status from the device
Jeff Moyer 2c91dc
+ */
Jeff Moyer 2c91dc
+struct cxl_cmd {
Jeff Moyer 2c91dc
+	struct cxl_memdev *memdev;
Jeff Moyer 2c91dc
+	struct cxl_mem_query_commands *query_cmd;
Jeff Moyer 2c91dc
+	struct cxl_send_command *send_cmd;
Jeff Moyer 2c91dc
+	void *input_payload;
Jeff Moyer 2c91dc
+	void *output_payload;
Jeff Moyer 2c91dc
+	int refcount;
Jeff Moyer 2c91dc
+	int query_status;
Jeff Moyer 2c91dc
+	int query_idx;
Jeff Moyer 2c91dc
+	int status;
Jeff Moyer 2c91dc
+};
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
 static inline int check_kmod(struct kmod_ctx *kmod_ctx)
Jeff Moyer 2c91dc
 {
Jeff Moyer 2c91dc
 	return kmod_ctx ? 0 : -ENXIO;
Jeff Moyer 2c91dc
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
Jeff Moyer 2c91dc
index fd06790..6e87b80 100644
Jeff Moyer 2c91dc
--- a/cxl/libcxl.h
Jeff Moyer 2c91dc
+++ b/cxl/libcxl.h
Jeff Moyer 2c91dc
@@ -48,6 +48,17 @@ const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);
Jeff Moyer 2c91dc
              memdev != NULL; \
Jeff Moyer 2c91dc
              memdev = cxl_memdev_get_next(memdev))
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
+struct cxl_cmd;
Jeff Moyer 2c91dc
+const char *cxl_cmd_get_devname(struct cxl_cmd *cmd);
Jeff Moyer 2c91dc
+struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);
Jeff Moyer 2c91dc
+int cxl_cmd_set_input_payload(struct cxl_cmd *cmd, void *in, int size);
Jeff Moyer 2c91dc
+int cxl_cmd_set_output_payload(struct cxl_cmd *cmd, void *out, int size);
Jeff Moyer 2c91dc
+void cxl_cmd_ref(struct cxl_cmd *cmd);
Jeff Moyer 2c91dc
+void cxl_cmd_unref(struct cxl_cmd *cmd);
Jeff Moyer 2c91dc
+int cxl_cmd_submit(struct cxl_cmd *cmd);
Jeff Moyer 2c91dc
+int cxl_cmd_get_mbox_status(struct cxl_cmd *cmd);
Jeff Moyer 2c91dc
+int cxl_cmd_get_out_size(struct cxl_cmd *cmd);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
 #ifdef __cplusplus
Jeff Moyer 2c91dc
 } /* extern "C" */
Jeff Moyer 2c91dc
 #endif
Jeff Moyer 2c91dc
-- 
Jeff Moyer 2c91dc
2.27.0
Jeff Moyer 2c91dc