libnvme API design

Daniel Wagner dwagner at suse.de
Thu Oct 9 04:07:47 PDT 2025


Hi Christoph,

As you have suggested the command API should be inverted, that is the
only stable API will be nvme_submit_admin_passthru and struct
nvme_passthru_cmd and a bunch of helpers to initialize the cmd.

I've done updated a bunch of the identify commands and below is the
result. I think we could reduce the number of helpers a bit,

  nvme_nvm_init_identify_ns vs nvme_nvm_init_identify_ns_csi.

Is this what you had in mind (obviously I haven't gone the whole way to
macros only, I like some type safty)?

Cheers,
Daniel


static inline
void nvme_nvm_init_identify(struct nvme_passthru_cmd *cmd,
			    enum nvme_identify_cns cns,
			    void *data, __u32 len)
{
	__u32 cdw10 = NVME_SET(cns, IDENTIFY_CDW10_CNS);
	__u32 cdw11 = NVME_SET(NVME_CSI_NVM, IDENTIFY_CDW11_CSI);

	memset(cmd, 0, sizeof(*cmd));
	
	cmd->opcode	= nvme_admin_identify;
	cmd->cdw10	= cdw10;
	cmd->cdw11	= cdw11;
	cmd->data_len	= len;
	cmd->addr	= (__u64)(uintptr_t)data;
}

static inline
void nvme_nvm_init_identify_ns(struct nvme_passthru_cmd *cmd,
			       __u32 nsid, struct nvme_id_ns *ns)
{
	nvme_nvm_init_identify(cmd,
			       NVME_IDENTIFY_CNS_NS,
			       ns, sizeof(*ns));
	cmd->nsid = nsid;
}

static inline
void nvme_nvm_init_identify_allocated_ns(struct nvme_passthru_cmd *cmd,
					 __u32 nsid, struct nvme_id_ns *ns)
{
	nvme_nvm_init_identify(cmd,
			       NVME_IDENTIFY_CNS_ALLOCATED_NS,
			       ns, sizeof(*ns));
	cmd->nsid = nsid;
}

static inline
void nvme_nvm_init_identify_active_ns_list(struct nvme_passthru_cmd *cmd,
					   __u32 nsid, struct nvme_ns_list *list)
{
	nvme_nvm_init_identify(cmd,
			       NVME_IDENTIFY_CNS_NS_ACTIVE_LIST,
			       list, sizeof(*list));
	cmd->nsid = nsid;
}

static inline
void nvme_identify_allocated_ns_list(struct nvme_passthru_cmd *cmd,
				     __u32 nsid, struct nvme_ns_list *list)
{
	nvme_nvm_init_identify(cmd,
			       NVME_IDENTIFY_CNS_ALLOCATED_NS_LIST,
			       list, sizeof(*list));
	cmd->nsid = nsid;
}

static inline
void nvme_identify_ctrl_list(struct nvme_passthru_cmd *cmd,
			     __u16 cntid,
			     struct nvme_ctrl_list *cntlist)
{
	nvme_nvm_init_identify(cmd,
			       NVME_IDENTIFY_CNS_CTRL_LIST,
			       cntlist, sizeof(*cntlist));
	cmd->cdw10 |= NVME_SET(cntid, IDENTIFY_CDW10_CNTID);
}

static inline
void nvme_nvm_init_identify_nsid_ctrl_list(struct nvme_passthru_cmd *cmd,
					   __u32 nsid, __u16 cntid,
					   struct nvme_ctrl_list *cntlist)
{
	nvme_nvm_init_identify(cmd,
			       NVME_IDENTIFY_CNS_NS_CTRL_LIST,
			       cntlist, sizeof(*cntlist));
	cmd->nsid = nsid;
	cmd->cdw10 |= NVME_SET(cntid, IDENTIFY_CDW10_CNTID);
}

static inline
void nvme_nvm_init_identify_ns_descs(struct nvme_passthru_cmd *cmd,
				     __u32 nsid,
				     struct nvme_ns_id_desc *descs)
{
	nvme_nvm_init_identify(cmd,
			       NVME_IDENTIFY_CNS_NS_DESC_LIST,
			       descs, sizeof(*descs));
	cmd->nsid = nsid;
}

static inline
void nvme_nvm_init_identify_nvmset_list(struct nvme_passthru_cmd *cmd,
					__u16 nvmsetid,
					struct nvme_id_nvmset_list *nvmset)
{
	nvme_nvm_init_identify(cmd,
			       NVME_IDENTIFY_CNS_NVMSET_LIST,
			       nvmset, sizeof(*nvmset));
	cmd->cdw11 |=  NVME_SET(nvmsetid, IDENTIFY_CDW11_CNSSPECID);
}

static inline
void nvme_nvm_init_identify_primary_ctrl(struct nvme_passthru_cmd *cmd,
					 __u16 cntid,
					 struct nvme_primary_ctrl_cap *cap)
{
	nvme_nvm_init_identify(cmd,
			     NVME_IDENTIFY_CNS_PRIMARY_CTRL_CAP,
			     cap, sizeof(*cap));
	cmd->cdw10 |= NVME_SET(cntid, IDENTIFY_CDW10_CNTID);
}

static inline
void nvme_nvm_init_identify_secondary_ctrl_list(struct nvme_passthru_cmd *cmd,
						__u16 cntid,
						struct nvme_secondary_ctrl_list *sc_list)
{
	nvme_nvm_init_identify(cmd,
			     NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST,
			     sc_list, sizeof(*sc_list));
	cmd->cdw10 |= NVME_SET(cntid, IDENTIFY_CDW10_CNTID);
}

static inline
void nvme_nvme_init_identify_uuid(struct nvme_passthru_cmd *cmd,
				  struct nvme_id_uuid_list *uuid_list)
{
	nvme_nvm_init_identify(cmd,
			       NVME_IDENTIFY_CNS_UUID_LIST,
			       uuid_list, sizeof(*uuid_list));
}

static inline
void nvme_nvm_init_identify_ns_csi(struct nvme_passthru_cmd *cmd,
				   __u32 nsid, enum nvme_csi csi,
				   __u8 uidx, void *data)
{
	nvme_nvm_init_identify(cmd,
			       csi,
			       data, NVME_IDENTIFY_DATA_SIZE);
	cmd->nsid = nsid;
	cmd->cdw14 |= NVME_SET(uidx, IDENTIFY_CDW14_UUID);
}

struct nvme_passthru_cmd cmd;
__u32 len = NVME_IDENTIFY_CNS_CTRL;

if (partial)
	len = offsetof(struct nvme_id_ctrl, rab);

nvme_nvm_init_identify(&cmd, NVME_IDENTIFY_CNS_CTRL, &id, len);

rc = nvme_submit_admin_passthru(hdl, &cmd, NULL);



More information about the Linux-nvme mailing list