libnvme API design

Daniel Wagner dwagner at suse.de
Tue Oct 14 08:29:54 PDT 2025


On Tue, Oct 14, 2025 at 06:20:11AM +0200, Christoph Hellwig wrote:
> On Mon, Oct 13, 2025 at 04:22:32PM +0200, Daniel Wagner wrote:
> > Or we just keep the nvme_nvm prefix. I've checked the existing callssites
> > in nvme-cli for the Identify command. There are none.
> 
> For the NVM command set specific ID NS/CTRL I'd keep it.  Most of the
> Identify CNS values are not command set specifivc, so it won't affect
> much code anyway.

So after studying the spec a bit closer I updated the Identify command
API slightly so it follows the spec. That resolved the inconsistent
naming scheme and which arguments which function should get. Agreed, the
current function names are now a bit expressive but it makes it way
simpler to follow the code and the spec (also avoid inconsistent naming)

The change is unit tested, so I think most obvious bugs are gone. On the
callsite the change is straight forward:

@@ -439,6 +439,7 @@ static int test_admin_id_cb(struct nvme_mi_ep *ep,
 static void test_admin_id(nvme_mi_ep_t ep)
 {
        struct nvme_transport_handle *hdl;
+       struct nvme_passthru_cmd cmd;
        struct nvme_id_ctrl id;
        int rc;

@@ -447,7 +448,8 @@ static void test_admin_id(nvme_mi_ep_t ep)
        hdl = nvme_mi_init_transport_handle(ep, 5);
        assert(hdl);

-       rc = nvme_identify_ctrl(hdl, &id);
+       nvme_init_identify_ctrl(&cmd, &id);
+       rc = nvme_submit_admin_passthru(hdl, &cmd, NULL);
        assert(rc == 0);
 }

I am posting only a part of the code here, the full change is
here:

https://github.com/nvme-experiments/libnvme/issues/49
https://github.com/nvme-experiments/libnvme/commit/b96cdf71fa73761152816c54e56cc2cc3db237a0

/**
 * nvme_init_identify() - Initialize passthru command for
 * NVMe Identify
 * @cmd:	Command data structure to initialize
 * @nsid:	Namespace identifier
 * @csi:	Command Set Identifier
 * @cns:	The Controller or Namespace structure,
 *              see @enum nvme_identify_cns
 * @data:	User space destination address to transfer the data
 * @len:	Length of provided user buffer to hold the data in bytes
 *
 * Prepare the @cmd data structure for the NVMe Identify command.
 */
static inline void nvme_init_identify(
		struct nvme_passthru_cmd *cmd, __u32 nsid, enum nvme_csi csi,
		enum nvme_identify_cns cns, void *data, __u32 len)
{
	__u32 cdw10 = NVME_FIELD_ENCODE(cns,
					NVME_IDENTIFY_CDW10_CNS_SHIFT,
					NVME_IDENTIFY_CDW10_CNS_MASK);
	__u32 cdw11 = NVME_FIELD_ENCODE(csi,
					NVME_IDENTIFY_CDW11_CSI_SHIFT,
					NVME_IDENTIFY_CDW11_CSI_MASK);

	memset(cmd, 0, sizeof(*cmd));

	cmd->opcode	= nvme_admin_identify;
	cmd->nsid	= nsid;
	cmd->cdw10	= cdw10;
	cmd->cdw11	= cdw11;
	cmd->data_len	= len;
	cmd->addr	= (__u64)(uintptr_t)data;
}

/**
 * nvme_init_identify_ns() - Initialize passthru command for
 * NVMe Identify Namespace data structure
 * @cmd:	Command data structure to initialize
 * @nsid:	Namespace identifier
 * @id:		User space destination address to transfer the data
 *
 * Initializes the passthru command buffer for the Identify command with
 * CNS value %NVME_IDENTIFY_CNS_NS.
 */
static inline void nvme_init_identify_ns(
		struct nvme_passthru_cmd *cmd, __u32 nsid,
		struct nvme_id_ns *id)
{
	nvme_init_identify(cmd, nsid, NVME_CSI_NVM,
			   NVME_IDENTIFY_CNS_NS,
			   id, sizeof(*id));
}

/**
 * nvme_init_identify_ctrl() - Initialize passthru command for
 * NVMe Identify Controller data structure
 * @cmd:	Command data structure to initialize
 * @id:		User space destination address to transfer the data,
 *
 * Initializes the passthru command buffer for the Identify command with
 * CNS value %NVME_IDENTIFY_CNS_CTRL.
 */
static inline void nvme_init_identify_ctrl(
		struct nvme_passthru_cmd *cmd, struct nvme_id_ctrl *id)
{
	nvme_init_identify(cmd, NVME_NSID_NONE, NVME_CSI_NVM,
			   NVME_IDENTIFY_CNS_CTRL,
			   id, sizeof(*id));
}

/**
 * nvme_init_identify_active_ns_list() - Initialize passthru command for
 * Active Namespaces ID list
 * @cmd:	Command data structure to initialize
 * @nsid:	Namespace identifier
 * @list:	User space destination address to transfer the data
 *
 * Initializes the passthru command buffer for the Identify command with
 * CNS value %NVME_IDENTIFY_CNS_NS_ACTIVE_LIST.
 */
static inline void nvme_init_identify_active_ns_list(
		struct nvme_passthru_cmd *cmd, __u32 nsid,
		struct nvme_ns_list *list)
{
	nvme_init_identify(cmd, nsid, NVME_CSI_NVM,
			   NVME_IDENTIFY_CNS_NS_ACTIVE_LIST,
			   list, sizeof(*list));
}

/**
 * nvme_init_identify_ns_descs_list() - Initialize passthru command for
 * Namespace Descriptor list
 * @cmd:	Command data structure to initialize
 * @nsid:	The namespace id to retrieve descriptors
 * @descs:	User space destination address to transfer the data
 *
 * Initializes the passthru command buffer for the Identify command with
 * CNS value %NVME_IDENTIFY_CNS_NS_DESC_LIST.
 */
static inline void nvme_init_identify_ns_descs_list(
		struct nvme_passthru_cmd *cmd, __u32 nsid,
		struct nvme_ns_id_desc *descs)
{
	nvme_init_identify(cmd, nsid, NVME_CSI_NVM,
			   NVME_IDENTIFY_CNS_NS_DESC_LIST,
			   descs, NVME_IDENTIFY_DATA_SIZE);
}

/**
 * nvme_init_identify_nvmset_list() - Initialize passthru command for
 * NVM Set List data structure
 * @cmd:	Command data structure to initialize
 * @nsid:	Namespace identifier
 * @nvmsetid:	NVM Set Identifier
 * @nvmset:	User space destination address to transfer the data
 *
 * Initializes the passthru command buffer for the Identify command with
 * CNS value %NVME_IDENTIFY_CNS_NS_ACTIVE_LIST.
 */
static inline void nvme_init_identify_nvmset_list(
		struct nvme_passthru_cmd *cmd, __u32 nsid,
		__u16 nvmsetid, struct nvme_id_nvmset_list *nvmset)
{
	nvme_init_identify(cmd, nsid, NVME_CSI_NVM,
			   NVME_IDENTIFY_CNS_NVMSET_LIST,
			   nvmset, sizeof(*nvmset));
	cmd->cdw11 |= NVME_FIELD_ENCODE(nvmsetid,
					NVME_IDENTIFY_CDW11_CNSSPECID_SHIFT,
					NVME_IDENTIFY_CDW11_CNSSPECID_MASK);
}

[...]

If this is generally okay, we start with updating the other patches
accordingly.



More information about the Linux-nvme mailing list