// SPDX-License-Identifier: LGPL-2.1-or-later
/*
 * This file is part of libnvme.
 * Copyright (c) 2020 Western Digital Corporation or its affiliates.
 *
 * Authors: Keith Busch <keith.busch@wdc.com>
 *	    Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
 */

#ifndef _LIBNVME_IOCTL_H
#define _LIBNVME_IOCTL_H

#include <stddef.h>
#include <sys/ioctl.h>
#include "types.h"
#include "api-types.h"

/*
 * We can not always count on the kernel UAPI being installed. Use the same
 * 'ifdef' guard to avoid double definitions just in case.
 */
#ifndef _UAPI_LINUX_NVME_IOCTL_H
#define _UAPI_LINUX_NVME_IOCTL_H

#ifndef _LINUX_NVME_IOCTL_H
#define _LINUX_NVME_IOCTL_H

/**
 * DOC: ioctl.h
 *
 * Linux NVMe ioctl interface functions
 */

/* '0' is interpreted by the kernel to mean 'apply the default timeout' */
#define NVME_DEFAULT_IOCTL_TIMEOUT 0

/**
 * struct nvme_passthru_cmd - nvme passthrough command structure
 * @opcode:	Operation code, see &enum nvme_io_opcodes and &enum nvme_admin_opcodes
 * @flags:	Not supported: intended for command flags (eg: SGL, FUSE)
 * @rsvd1:	Reserved for future use
 * @nsid:	Namespace Identifier, or Fabrics type
 * @cdw2:	Command Dword 2 (no spec defined use)
 * @cdw3:	Command Dword 3 (no spec defined use)
 * @metadata:	User space address to metadata buffer (NULL if not used)
 * @addr:	User space address to data buffer (NULL if not used)
 * @metadata_len: Metadata buffer transfer length
 * @data_len:	Data buffer transfer length
 * @cdw10:	Command Dword 10 (command specific)
 * @cdw11:	Command Dword 11 (command specific)
 * @cdw12:	Command Dword 12 (command specific)
 * @cdw13:	Command Dword 13 (command specific)
 * @cdw14:	Command Dword 14 (command specific)
 * @cdw15:	Command Dword 15 (command specific)
 * @timeout_ms:	If non-zero, overrides system default timeout in milliseconds
 * @result:	Set on completion to the command's CQE DWORD 0 controller response
 */
struct nvme_passthru_cmd {
	__u8	opcode;
	__u8	flags;
	__u16	rsvd1;
	__u32	nsid;
	__u32	cdw2;
	__u32	cdw3;
	__u64	metadata;
	__u64	addr;
	__u32	metadata_len;
	__u32	data_len;
	__u32	cdw10;
	__u32	cdw11;
	__u32	cdw12;
	__u32	cdw13;
	__u32	cdw14;
	__u32	cdw15;
	__u32	timeout_ms;
	__u32	result;
};

/**
 * struct nvme_passthru_cmd64 - 64-bit nvme passthrough command structure
 * @opcode:	Operation code, see &enum nvme_io_opcodes and &enum nvme_admin_opcodes
 * @flags:	Not supported: intended for command flags (eg: SGL, FUSE)
 * @rsvd1:	Reserved for future use
 * @nsid:	Namespace Identifier, or Fabrics type
 * @cdw2:	Command Dword 2 (no spec defined use)
 * @cdw3:	Command Dword 3 (no spec defined use)
 * @metadata:	User space address to metadata buffer (NULL if not used)
 * @addr:	User space address to data buffer (NULL if not used)
 * @metadata_len: Metadata buffer transfer length
 * @data_len:	Data buffer transfer length
 * @cdw10:	Command Dword 10 (command specific)
 * @cdw11:	Command Dword 11 (command specific)
 * @cdw12:	Command Dword 12 (command specific)
 * @cdw13:	Command Dword 13 (command specific)
 * @cdw14:	Command Dword 14 (command specific)
 * @cdw15:	Command Dword 15 (command specific)
 * @timeout_ms:	If non-zero, overrides system default timeout in milliseconds
 * @rsvd2:	Reserved for future use (and fills an implicit struct pad
 * @result:	Set on completion to the command's CQE DWORD 0-1 controller response
 */
struct nvme_passthru_cmd64 {
	__u8    opcode;
	__u8    flags;
	__u16   rsvd1;
	__u32   nsid;
	__u32   cdw2;
	__u32   cdw3;
	__u64   metadata;
	__u64   addr;
	__u32   metadata_len;
	__u32   data_len;
	__u32   cdw10;
	__u32   cdw11;
	__u32   cdw12;
	__u32   cdw13;
	__u32   cdw14;
	__u32   cdw15;
	__u32   timeout_ms;
	__u32   rsvd2;
	__u64   result;
};

/**
 * struct nvme_uring_cmd - nvme uring command structure
 * @opcode:	Operation code, see &enum nvme_io_opcodes and &enum nvme_admin_opcodes
 * @flags:	Not supported: intended for command flags (eg: SGL, FUSE)
 * @rsvd1:	Reserved for future use
 * @nsid:	Namespace Identifier, or Fabrics type
 * @cdw2:	Command Dword 2 (no spec defined use)
 * @cdw3:	Command Dword 3 (no spec defined use)
 * @metadata:	User space address to metadata buffer (NULL if not used)
 * @addr:	User space address to data buffer (NULL if not used)
 * @metadata_len: Metadata buffer transfer length
 * @data_len:	Data buffer transfer length
 * @cdw10:	Command Dword 10 (command specific)
 * @cdw11:	Command Dword 11 (command specific)
 * @cdw12:	Command Dword 12 (command specific)
 * @cdw13:	Command Dword 13 (command specific)
 * @cdw14:	Command Dword 14 (command specific)
 * @cdw15:	Command Dword 15 (command specific)
 * @timeout_ms:	If non-zero, overrides system default timeout in milliseconds
 * @rsvd2:	Reserved for future use (and fills an implicit struct pad
 */
struct nvme_uring_cmd {
	__u8	opcode;
	__u8	flags;
	__u16	rsvd1;
	__u32	nsid;
	__u32	cdw2;
	__u32	cdw3;
	__u64	metadata;
	__u64	addr;
	__u32	metadata_len;
	__u32	data_len;
	__u32	cdw10;
	__u32	cdw11;
	__u32	cdw12;
	__u32	cdw13;
	__u32	cdw14;
	__u32	cdw15;
	__u32	timeout_ms;
	__u32   rsvd2;
};

#define NVME_IOCTL_ID		_IO('N', 0x40)
#define NVME_IOCTL_RESET	_IO('N', 0x44)
#define NVME_IOCTL_SUBSYS_RESET	_IO('N', 0x45)
#define NVME_IOCTL_RESCAN	_IO('N', 0x46)
#define NVME_IOCTL_ADMIN_CMD	_IOWR('N', 0x41, struct nvme_passthru_cmd)
#define NVME_IOCTL_IO_CMD	_IOWR('N', 0x43, struct nvme_passthru_cmd)
#define NVME_IOCTL_ADMIN64_CMD  _IOWR('N', 0x47, struct nvme_passthru_cmd64)
#define NVME_IOCTL_IO64_CMD     _IOWR('N', 0x48, struct nvme_passthru_cmd64)

/* io_uring async commands: */
#define NVME_URING_CMD_IO	_IOWR('N', 0x80, struct nvme_uring_cmd)
#define NVME_URING_CMD_IO_VEC	_IOWR('N', 0x81, struct nvme_uring_cmd)

#endif /* _UAPI_LINUX_NVME_IOCTL_H */

#endif /* _LINUX_NVME_IOCTL_H */

/**
 * sizeof_args - Helper function used to determine structure sizes
 * @type:	Argument structure type
 * @member:	Member inside the type
 * @align:	Alignment information
 */
#define sizeof_args(type, member, align)					\
({										\
	type s;									\
	size_t t = offsetof(type, member) + sizeof(s.member);			\
	size_t p = (sizeof(align) - (t % sizeof(align))) % sizeof(align);	\
	t + p;									\
})

/**
 * nvme_submit_admin_passthru64() - Submit a 64-bit nvme passthrough admin
 *				    command
 * @fd:		File descriptor of nvme device
 * @cmd:	The nvme admin command to send
 * @result:	Optional field to return the result from the CQE DW0-1
 *
 * Uses NVME_IOCTL_ADMIN64_CMD for the ioctl request.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_submit_admin_passthru64(int fd, struct nvme_passthru_cmd64 *cmd,
				 __u64 *result);

/**
 * nvme_admin_passthru64() - Submit a 64-bit nvme passthrough command
 * @fd:		File descriptor of nvme device
 * @opcode:	The nvme io command to send
 * @flags:	NVMe command flags (not used)
 * @rsvd:	Reserved for future use
 * @nsid:	Namespace identifier
 * @cdw2:	Command dword 2
 * @cdw3:	Command dword 3
 * @cdw10:	Command dword 10
 * @cdw11:	Command dword 11
 * @cdw12:	Command dword 12
 * @cdw13:	Command dword 13
 * @cdw14:	Command dword 14
 * @cdw15:	Command dword 15
 * @data_len:	Length of the data transferred in this command in bytes
 * @data:	Pointer to user address of the data buffer
 * @metadata_len:Length of metadata transferred in this command
 * @metadata:	Pointer to user address of the metadata buffer
 * @timeout_ms:	How long the kernel waits for the command to complete
 * @result:	Optional field to return the result from the CQE dword 0
 *
 * Parameterized form of nvme_submit_admin_passthru64(). This sets up and
 * submits a &struct nvme_passthru_cmd64.
 *
 * Known values for @opcode are defined in &enum nvme_admin_opcode.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_admin_passthru64(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
		__u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11,
		__u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15,
		__u32 data_len, void *data, __u32 metadata_len, void *metadata,
		__u32 timeout_ms, __u64 *result);

/**
 * nvme_submit_admin_passthru() - Submit an nvme passthrough admin command
 * @fd:		File descriptor of nvme device
 * @cmd:	The nvme admin command to send
 * @result:	Optional field to return the result from the CQE DW0
 *
 * Uses NVME_IOCTL_ADMIN_CMD for the ioctl request.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_submit_admin_passthru(int fd, struct nvme_passthru_cmd *cmd,
			       __u32 *result);

/**
 * nvme_admin_passthru() - Submit an nvme passthrough command
 * @fd:		File descriptor of nvme device
 * @opcode:	The nvme io command to send
 * @flags:	NVMe command flags (not used)
 * @rsvd:	Reserved for future use
 * @nsid:	Namespace identifier
 * @cdw2:	Command dword 2
 * @cdw3:	Command dword 3
 * @cdw10:	Command dword 10
 * @cdw11:	Command dword 11
 * @cdw12:	Command dword 12
 * @cdw13:	Command dword 13
 * @cdw14:	Command dword 14
 * @cdw15:	Command dword 15
 * @data_len:	Length of the data transferred in this command in bytes
 * @data:	Pointer to user address of the data buffer
 * @metadata_len:Length of metadata transferred in this command
 * @metadata:	Pointer to user address of the metadata buffer
 * @timeout_ms:	How long the kernel waits for the command to complete
 * @result:	Optional field to return the result from the CQE dword 0
 *
 * Parameterized form of nvme_submit_admin_passthru(). This sets up and
 * submits a &struct nvme_passthru_cmd.
 *
 * Known values for @opcode are defined in &enum nvme_admin_opcode.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_admin_passthru(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
		__u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11,
		__u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15,
		__u32 data_len, void *data, __u32 metadata_len, void *metadata,
		__u32 timeout_ms, __u32 *result);

/**
 * nvme_submit_io_passthru64() - Submit a 64-bit nvme passthrough command
 * @fd:		File descriptor of nvme device
 * @cmd:	The nvme io command to send
 * @result:	Optional field to return the result from the CQE DW0-1
 *
 * Uses NVME_IOCTL_IO64_CMD for the ioctl request.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_submit_io_passthru64(int fd, struct nvme_passthru_cmd64 *cmd,
			    __u64 *result);

/**
 * nvme_io_passthru64() - Submit an nvme io passthrough command
 * @fd:		File descriptor of nvme device
 * @opcode:	The nvme io command to send
 * @flags:	NVMe command flags (not used)
 * @rsvd:	Reserved for future use
 * @nsid:	Namespace identifier
 * @cdw2:	Command dword 2
 * @cdw3:	Command dword 3
 * @cdw10:	Command dword 10
 * @cdw11:	Command dword 11
 * @cdw12:	Command dword 12
 * @cdw13:	Command dword 13
 * @cdw14:	Command dword 14
 * @cdw15:	Command dword 15
 * @data_len:	Length of the data transferred in this command in bytes
 * @data:	Pointer to user address of the data buffer
 * @metadata_len:Length of metadata transferred in this command
 * @metadata:	Pointer to user address of the metadata buffer
 * @timeout_ms:	How long the kernel waits for the command to complete
 * @result:	Optional field to return the result from the CQE dword 0
 *
 * Parameterized form of nvme_submit_io_passthru64(). This sets up and submits
 * a &struct nvme_passthru_cmd64.
 *
 * Known values for @opcode are defined in &enum nvme_io_opcode.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_io_passthru64(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
		__u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11,
		__u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15,
		__u32 data_len, void *data, __u32 metadata_len, void *metadata,
		__u32 timeout_ms, __u64 *result);

/**
 * nvme_submit_io_passthru() - Submit an nvme passthrough command
 * @fd:		File descriptor of nvme device
 * @cmd:	The nvme io command to send
 * @result:	Optional field to return the result from the CQE dword 0
 * @result:	Optional field to return the result from the CQE DW0
 *
 * Uses NVME_IOCTL_IO_CMD for the ioctl request.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_submit_io_passthru(int fd, struct nvme_passthru_cmd *cmd,
			    __u32 *result);

/**
 * nvme_io_passthru() - Submit an nvme io passthrough command
 * @fd:		File descriptor of nvme device
 * @opcode:	The nvme io command to send
 * @flags:	NVMe command flags (not used)
 * @rsvd:	Reserved for future use
 * @nsid:	Namespace identifier
 * @cdw2:	Command dword 2
 * @cdw3:	Command dword 3
 * @cdw10:	Command dword 10
 * @cdw11:	Command dword 11
 * @cdw12:	Command dword 12
 * @cdw13:	Command dword 13
 * @cdw14:	Command dword 14
 * @cdw15:	Command dword 15
 * @data_len:	Length of the data transferred in this command in bytes
 * @data:	Pointer to user address of the data buffer
 * @metadata_len:Length of metadata transferred in this command
 * @metadata:	Pointer to user address of the metadata buffer
 * @timeout_ms:	How long the kernel waits for the command to complete
 * @result:	Optional field to return the result from the CQE dword 0
 *
 * Parameterized form of nvme_submit_io_passthru(). This sets up and submits
 * a &struct nvme_passthru_cmd.
 *
 * Known values for @opcode are defined in &enum nvme_io_opcode.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_io_passthru(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
		__u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11,
		__u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15,
		__u32 data_len, void *data, __u32 metadata_len, void *metadata,
		__u32 timeout_ms, __u32 *result);

/**
 * nvme_subsystem_reset() - Initiate a subsystem reset
 * @fd:		File descriptor of nvme device
 *
 * This should only be sent to controller handles, not to namespaces.
 *
 * Return: Zero if a subsystem reset was initiated or -1 with errno set
 * otherwise.
 */
int nvme_subsystem_reset(int fd);

/**
 * nvme_ctrl_reset() - Initiate a controller reset
 * @fd:		File descriptor of nvme device
 *
 * This should only be sent to controller handles, not to namespaces.
 *
 * Return: 0 if a reset was initiated or -1 with errno set otherwise.
 */
int nvme_ctrl_reset(int fd);

/**
 * nvme_ns_rescan() - Initiate a controller rescan
 * @fd:		File descriptor of nvme device
 *
 * This should only be sent to controller handles, not to namespaces.
 *
 * Return: 0 if a rescan was initiated or -1 with errno set otherwise.
 */
int nvme_ns_rescan(int fd);

/**
 * nvme_get_nsid() - Retrieve the NSID from a namespace file descriptor
 * @fd:		File descriptor of nvme namespace
 * @nsid:	User pointer to namespace id
 *
 * This should only be sent to namespace handles, not to controllers. The
 * kernel's interface returns the nsid as the return value. This is unfortunate
 * for many architectures that are incapable of allowing distinguishing a
 * namespace id > 0x80000000 from a negative error number.
 *
 * Return: 0 if @nsid was set successfully or -1 with errno set otherwise.
 */
int nvme_get_nsid(int fd, __u32 *nsid);

/**
 * nvme_identify() - Send the NVMe Identify command
 * @args:	&struct nvme_identify_args argument structure
 *
 * The Identify command returns a data buffer that describes information about
 * the NVM subsystem, the controller or the namespace(s).
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_identify(struct nvme_identify_args *args);

static inline int nvme_identify_cns_nsid(int fd, enum nvme_identify_cns cns,
					 __u32 nsid, void *data)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = data,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = cns,
		.csi = NVME_CSI_NVM,
		.nsid = nsid,
		.cntid = NVME_CNTLID_NONE,
		.cns_specific_id = NVME_CNSSPECID_NONE,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_ctrl() - Retrieves nvme identify controller
 * @fd:		File descriptor of nvme device
 * @id:		User space destination address to transfer the data,
 *
 * Sends nvme identify with CNS value %NVME_IDENTIFY_CNS_CTRL.
 *
 * See &struct nvme_id_ctrl for details on the data returned.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_ctrl(int fd, struct nvme_id_ctrl *id)
{
	return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_CTRL,
				      NVME_NSID_NONE, id);
}

/**
 * nvme_identify_ns() - Retrieves nvme identify namespace
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace to identify
 * @ns:		User space destination address to transfer the data
 *
 * If the Namespace Identifier (NSID) field specifies an active NSID, then the
 * Identify Namespace data structure is returned to the host for that specified
 * namespace.
 *
 * If the controller supports the Namespace Management capability and the NSID
 * field is set to %NVME_NSID_ALL, then the controller returns an Identify Namespace
 * data structure that specifies capabilities that are common across namespaces
 * for this controller.
 *
 * See &struct nvme_id_ns for details on the structure returned.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_ns(int fd, __u32 nsid, struct nvme_id_ns *ns)
{
	return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_NS, nsid, ns);
}

/**
 * nvme_identify_allocated_ns() - Same as nvme_identify_ns, but only for
 *				  allocated namespaces
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace to identify
 * @ns:		User space destination address to transfer the data
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_allocated_ns(int fd, __u32 nsid,
			struct nvme_id_ns *ns)
{
	return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_ALLOCATED_NS,
				      nsid, ns);
}

/**
 * nvme_identify_active_ns_list() - Retrieves active namespaces id list
 * @fd:		File descriptor of nvme device
 * @nsid:	Return namespaces greater than this identifier
 * @list:	User space destination address to transfer the data
 *
 * A list of 1024 namespace IDs is returned to the host containing NSIDs in
 * increasing order that are greater than the value specified in the Namespace
 * Identifier (nsid) field of the command.
 *
 * See &struct nvme_ns_list for the definition of the returned structure.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_active_ns_list(int fd, __u32 nsid,
			struct nvme_ns_list *list)
{
	return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_NS_ACTIVE_LIST,
				      nsid, list);
}

/**
 * nvme_identify_allocated_ns_list() - Retrieves allocated namespace id list
 * @fd:		File descriptor of nvme device
 * @nsid:	Return namespaces greater than this identifier
 * @list:	User space destination address to transfer the data
 *
 * A list of 1024 namespace IDs is returned to the host containing NSIDs in
 * increasing order that are greater than the value specified in the Namespace
 * Identifier (nsid) field of the command.
 *
 * See &struct nvme_ns_list for the definition of the returned structure.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_allocated_ns_list(int fd, __u32 nsid,
			struct nvme_ns_list *list)
{
	return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_ALLOCATED_NS_LIST,
				      nsid, list);
}

/**
 * nvme_identify_ctrl_list() - Retrieves identify controller list
 * @fd:		File descriptor of nvme device
 * @cntid:	Starting CNTLID to return in the list
 * @cntlist:	User space destination address to transfer the data
 *
 * Up to 2047 controller identifiers is returned containing a controller
 * identifier greater than or equal to the controller identifier  specified in
 * @cntid.
 *
 * See &struct nvme_ctrl_list for a definition of the structure returned.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_ctrl_list(int fd, __u16 cntid,
			struct nvme_ctrl_list *cntlist)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = cntlist,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_CTRL_LIST,
		.csi = NVME_CSI_NVM,
		.nsid = NVME_NSID_NONE,
		.cntid = cntid,
		.cns_specific_id = NVME_CNSSPECID_NONE,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_nsid_ctrl_list() - Retrieves controller list attached to an nsid
 * @fd:		File descriptor of nvme device
 * @nsid:	Return controllers that are attached to this nsid
 * @cntid:	Starting CNTLID to return in the list
 * @cntlist:	User space destination address to transfer the data
 *
 * Up to 2047 controller identifiers are returned containing a controller
 * identifier greater than or equal to the controller identifier  specified in
 * @cntid attached to @nsid.
 *
 * See &struct nvme_ctrl_list for a definition of the structure returned.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1
 */
static inline int nvme_identify_nsid_ctrl_list(int fd, __u32 nsid, __u16 cntid,
			struct nvme_ctrl_list *cntlist)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = cntlist,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_NS_CTRL_LIST,
		.csi = NVME_CSI_NVM,
		.nsid = nsid,
		.cntid = cntid,
		.cns_specific_id = NVME_CNSSPECID_NONE,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_ns_descs() - Retrieves namespace descriptor list
 * @fd:		File descriptor of nvme device
 * @nsid:	The namespace id to retrieve descriptors
 * @descs:	User space destination address to transfer the data
 *
 * A list of Namespace Identification Descriptor structures is returned to the
 * host for the namespace specified in the Namespace Identifier (NSID) field if
 * it is an active NSID.
 *
 * The data returned is in the form of an array of 'struct nvme_ns_id_desc'.
 *
 * See &struct nvme_ns_id_desc for the definition of the returned structure.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_ns_descs(int fd, __u32 nsid,
			struct nvme_ns_id_desc *descs)
{
	return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_NS_DESC_LIST,
				      nsid, descs);
}

/**
 * nvme_identify_nvmset_list() - Retrieves NVM Set List
 * @fd:		File descriptor of nvme device
 * @nvmsetid:	NVM Set Identifier
 * @nvmset:	User space destination address to transfer the data
 *
 * Retrieves an NVM Set List, &struct nvme_id_nvmset_list. The data structure
 * is an ordered list by NVM Set Identifier, starting with the first NVM Set
 * Identifier supported by the NVM subsystem that is equal to or greater than
 * the NVM Set Identifier.
 *
 * See &struct nvme_id_nvmset_list for the definition of the returned structure.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_nvmset_list(int fd, __u16 nvmsetid,
			struct nvme_id_nvmset_list *nvmset)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = nvmset,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_NVMSET_LIST,
		.csi = NVME_CSI_NVM,
		.nsid = NVME_NSID_NONE,
		.cntid = NVME_CNTLID_NONE,
		.cns_specific_id = nvmsetid,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_primary_ctrl() - Retrieve NVMe Primary Controller
 *				  identification
 * @fd:		File descriptor of nvme device
 * @cntid:	Return controllers starting at this identifier
 * @cap:	User space destination buffer address to transfer the data
 *
 * See &struct nvme_primary_ctrl_cap for the definition of the returned structure, @cap.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_primary_ctrl(int fd, __u16 cntid,
			struct nvme_primary_ctrl_cap *cap)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = cap,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_PRIMARY_CTRL_CAP,
		.csi = NVME_CSI_NVM,
		.nsid = NVME_NSID_NONE,
		.cntid = cntid,
		.cns_specific_id = NVME_CNSSPECID_NONE,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_secondary_ctrl_list() - Retrieves secondary controller list
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace identifier
 * @cntid:	Return controllers starting at this identifier
 * @sc_list:	User space destination address to transfer the data
 *
 * A Secondary Controller List is returned to the host for up to 127 secondary
 * controllers associated with the primary controller processing this command.
 * The list contains entries for controller identifiers greater than or equal
 * to the value specified in the Controller Identifier (cntid).
 *
 * See &struct nvme_secondary_ctrls_list for a definition of the returned
 * structure.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_secondary_ctrl_list(int fd, __u32 nsid,
			__u16 cntid, struct nvme_secondary_ctrl_list *sc_list)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = sc_list,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST,
		.csi = NVME_CSI_NVM,
		.nsid = nsid,
		.cntid = cntid,
		.cns_specific_id = NVME_CNSSPECID_NONE,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_ns_granularity() - Retrieves namespace granularity
 *				    identification
 * @fd:		File descriptor of nvme device
 * @gr_list:	User space destination address to transfer the data
 *
 * If the controller supports reporting of Namespace Granularity, then a
 * Namespace Granularity List is returned to the host for up to sixteen
 * namespace granularity descriptors
 *
 * See &struct nvme_id_ns_granularity_list for the definition of the returned
 * structure.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_ns_granularity(int fd,
			struct nvme_id_ns_granularity_list *gr_list)
{
	return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_NS_GRANULARITY,
				      NVME_NSID_NONE, gr_list);
}

/**
 * nvme_identify_uuid() - Retrieves device's UUIDs
 * @fd:		File descriptor of nvme device
 * @uuid_list:	User space destination address to transfer the data
 *
 * Each UUID List entry is either 0h, the NVMe Invalid UUID, or a valid UUID.
 * Valid UUIDs are those which are non-zero and are not the NVMe Invalid UUID.
 *
 * See &struct nvme_id_uuid_list for the definition of the returned structure.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_uuid(int fd, struct nvme_id_uuid_list *uuid_list)
{
	return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_UUID_LIST,
				      NVME_NSID_NONE, uuid_list);
}

/**
 * nvme_identify_ns_csi() - I/O command set specific identify namespace data
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace to identify
 * @uuidx:	UUID Index for differentiating vendor specific encoding
 * @csi:	Command Set Identifier
 * @data:	User space destination address to transfer the data
 *
 * An I/O Command Set specific Identify Namespace data structure is returned
 * for the namespace specified in @nsid.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_ns_csi(int fd, __u32 nsid, __u8 uuidx,
			enum nvme_csi csi, void *data)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = data,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_CSI_NS,
		.csi = csi,
		.nsid = nsid,
		.cntid = NVME_CNTLID_NONE,
		.cns_specific_id = NVME_CNSSPECID_NONE,
		.uuidx = uuidx,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_ctrl_csi() - I/O command set specific Identify Controller data
 * @fd:		File descriptor of nvme device
 * @csi:	Command Set Identifier
 * @data:	User space destination address to transfer the data
 *
 * An I/O Command Set specific Identify Controller data structure is returned
 * to the host for the controller processing the command. The specific Identify
 * Controller data structure to be returned is specified by @csi.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_ctrl_csi(int fd, enum nvme_csi csi, void *data)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = data,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_CSI_CTRL,
		.csi = csi,
		.nsid = NVME_NSID_NONE,
		.cntid = NVME_CNTLID_NONE,
		.cns_specific_id = NVME_CNSSPECID_NONE,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_active_ns_list_csi() - Active namespace ID list associated with a specified I/O command set
 * @fd:		File descriptor of nvme device
 * @nsid:	Return namespaces greater than this identifier
 * @csi:	Command Set Identifier
 * @ns_list:	User space destination address to transfer the data
 *
 * A list of 1024 namespace IDs is returned to the host containing active
 * NSIDs in increasing order that are greater than the value specified in
 * the Namespace Identifier (nsid) field of the command and matching the
 * I/O Command Set specified in the @csi argument.
 *
 * See &struct nvme_ns_list for the definition of the returned structure.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_active_ns_list_csi(int fd, __u32 nsid,
			enum nvme_csi csi, struct nvme_ns_list *ns_list)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = ns_list,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_CSI_NS_ACTIVE_LIST,
		.csi = csi,
		.nsid = nsid,
		.cntid = NVME_CNTLID_NONE,
		.cns_specific_id = NVME_CNSSPECID_NONE,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_allocated_ns_list_csi() - Allocated namespace ID list associated with a specified I/O command set
 * @fd:		File descriptor of nvme device
 * @nsid:	Return namespaces greater than this identifier
 * @csi:	Command Set Identifier
 * @ns_list:	User space destination address to transfer the data
 *
 * A list of 1024 namespace IDs is returned to the host containing allocated
 * NSIDs in increasing order that are greater than the value specified in
 * the @nsid field of the command and matching the I/O Command Set
 * specified in the @csi argument.
 *
 * See &struct nvme_ns_list for the definition of the returned structure.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_allocated_ns_list_csi(int fd, __u32 nsid,
			enum nvme_csi csi, struct nvme_ns_list *ns_list)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = ns_list,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_CSI_ALLOCATED_NS_LIST,
		.csi = csi,
		.nsid = nsid,
		.cntid = NVME_CNTLID_NONE,
		.cns_specific_id = NVME_CNSSPECID_NONE,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_independent_identify_ns() - I/O command set independent Identify namespace data
 * @fd:		File descriptor of nvme device
 * @nsid:	Return namespaces greater than this identifier
 * @ns:		I/O Command Set Independent Identify Namespace data
 *		structure
 *
 * The I/O command set independent Identify namespace data structure for
 * the namespace identified with @ns is returned to the host.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_independent_identify_ns(int fd, __u32 nsid,
			struct nvme_id_independent_id_ns *ns)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = ns,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_CSI_INDEPENDENT_ID_NS,
		.csi = NVME_CSI_NVM,
		.nsid = nsid,
		.cntid = NVME_CNTLID_NONE,
		.cns_specific_id = NVME_CNSSPECID_NONE,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_ns_csi_user_data_format() - Identify namespace user data format
 * @fd:		File descriptor of nvme device
 * @user_data_format: Return namespaces capability of identifier
 * @uuidx:	UUID selection, if supported
 * @csi:	Command Set Identifier
 * @data:	User space destination address to transfer the data
 *
 * Identify Namespace data structure for the specified User Data Format
 * index containing the namespace capabilities for the NVM Command Set.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_ns_csi_user_data_format(int fd,
			__u16 user_data_format, __u8 uuidx,
			enum nvme_csi csi, void *data)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = data,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_NS_USER_DATA_FORMAT,
		.csi = csi,
		.nsid = NVME_NSID_NONE,
		.cntid = NVME_CNTLID_NONE,
		.cns_specific_id = user_data_format,
		.uuidx = uuidx,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_iocs_ns_csi_user_data_format() - Identify I/O command set namespace data structure
 * @fd:		File descriptor of nvme device
 * @user_data_format: Return namespaces capability of identifier
 * @uuidx:	UUID selection, if supported
 * @csi:	Command Set Identifier
 * @data:	User space destination address to transfer the data
 *
 * I/O Command Set specific Identify Namespace data structure for
 * the specified User Data Format index containing the namespace
 * capabilities for the I/O Command Set specified in the CSI field.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_iocs_ns_csi_user_data_format(int fd,
			__u16 user_data_format, __u8 uuidx,
			enum nvme_csi csi, void *data)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = data,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_CSI_NS_USER_DATA_FORMAT,
		.csi = csi,
		.nsid = NVME_NSID_NONE,
		.cntid = NVME_CNTLID_NONE,
		.cns_specific_id = user_data_format,
		.uuidx = uuidx,
	};

	return nvme_identify(&args);
}

/**
 * nvme_nvm_identify_ctrl() - Identify controller data
 * @fd:	File descriptor of nvme device
 * @id:	User space destination address to transfer the data
 *
 * Return an identify controller data structure to the host of
 * processing controller.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_nvm_identify_ctrl(int fd, struct nvme_id_ctrl_nvm *id)
{
	return nvme_identify_ctrl_csi(fd, NVME_CSI_NVM, id);
}

/**
 * nvme_identify_domain_list() - Domain list data
 * @fd:		File descriptor of nvme device
 * @domid:	Domain ID
 * @list:	User space destination address to transfer data
 *
 * A list of 31 domain IDs is returned to the host containing domain
 * attributes in increasing order that are greater than the value
 * specified in the @domid field.
 *
 * See &struct nvme_identify_domain_attr for the definition of the
 * returned structure.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_domain_list(int fd, __u16 domid,
			struct nvme_id_domain_list *list)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = list,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_DOMAIN_LIST,
		.csi = NVME_CSI_NVM,
		.nsid = NVME_NSID_NONE,
		.cntid = NVME_CNTLID_NONE,
		.cns_specific_id = domid,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_endurance_group_list() - Endurance group list data
 * @fd:		File descriptor of nvme device
 * @endgrp_id:	Endurance group identifier
 * @list:	Array of endurance group identifiers
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_endurance_group_list(int fd, __u16 endgrp_id,
			struct nvme_id_endurance_group_list *list)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = list,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_ENDURANCE_GROUP_ID,
		.csi = NVME_CSI_NVM,
		.nsid = NVME_NSID_NONE,
		.cntid = NVME_CNTLID_NONE,
		.cns_specific_id = endgrp_id,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_identify_iocs() - I/O command set data structure
 * @fd:		File descriptor of nvme device
 * @cntlid:	Controller ID
 * @iocs:	User space destination address to transfer the data
 *
 * Retrieves list of the controller's supported io command set vectors. See
 * &struct nvme_id_iocs.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_identify_iocs(int fd, __u16 cntlid,
			struct nvme_id_iocs *iocs)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = iocs,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_COMMAND_SET_STRUCTURE,
		.csi = NVME_CSI_NVM,
		.nsid = NVME_NSID_NONE,
		.cntid = cntlid,
		.cns_specific_id = NVME_CNSSPECID_NONE,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_zns_identify_ns() - ZNS identify namespace data
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace to identify
 * @data:	User space destination address to transfer the data
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_zns_identify_ns(int fd, __u32 nsid,
			struct nvme_zns_id_ns *data)
{
	struct nvme_identify_args args = {
		.result = NULL,
		.data = data,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.cns = NVME_IDENTIFY_CNS_CSI_NS,
		.csi = NVME_CSI_ZNS,
		.nsid = nsid,
		.cntid = NVME_CNTLID_NONE,
		.cns_specific_id = NVME_CNSSPECID_NONE,
	};

	return nvme_identify(&args);
}

/**
 * nvme_zns_identify_ctrl() - ZNS identify controller data
 * @fd:	File descriptor of nvme device
 * @id:	User space destination address to transfer the data
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_zns_identify_ctrl(int fd, struct nvme_zns_id_ctrl *id)
{
	return nvme_identify_ctrl_csi(fd, NVME_CSI_ZNS, id);
}

/**
 * nvme_get_log() - NVMe Admin Get Log command
 * @args:	&struct nvme_get_log_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_log(struct nvme_get_log_args *args);

static inline int nvme_get_nsid_log(int fd, bool rae,
			enum nvme_cmd_get_log_lid lid,
			__u32 nsid, __u32 len, void *log)
{
	struct nvme_get_log_args args = {
		.lpo = 0,
		.result = NULL,
		.log = log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = lid,
		.len = len,
		.nsid = nsid,
		.csi = NVME_CSI_NVM,
		.lsi = NVME_LOG_LSI_NONE,
		.lsp = NVME_LOG_LSP_NONE,
		.uuidx = NVME_UUID_NONE,
		.rae = rae,
		.ot = false,
	};

	return nvme_get_log(&args);
}

static inline int nvme_get_log_simple(int fd, enum nvme_cmd_get_log_lid lid,
				      __u32 len, void *log)
{
	return nvme_get_nsid_log(fd, false, lid, NVME_NSID_ALL, len, log);
}

/**
 * nvme_get_log_supported_log_pages() - Retrieve nmve supported log pages
 * @fd:		File descriptor of nvme device
 * @rae:	Retain asynchronous events
 * @log:	Array of LID supported and Effects data structures
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_supported_log_pages(int fd, bool rae,
			struct nvme_supported_log_pages *log)
{
	return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_SUPPORTED_LOG_PAGES,
				 NVME_NSID_ALL, sizeof(*log), log);
}

/**
 * nvme_get_log_error() - Retrieve nvme error log
 * @fd:		File descriptor of nvme device
 * @nr_entries:	Number of error log entries allocated
 * @rae:	Retain asynchronous events
 * @err_log:	Array of error logs of size 'entries'
 *
 * This log page describes extended error information for a command that
 * completed with error, or may report an error that is not specific to a
 * particular command.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_error(int fd, unsigned int nr_entries, bool rae,
				     struct nvme_error_log_page *err_log)
{
	return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_ERROR,
				 NVME_NSID_ALL, sizeof(*err_log) * nr_entries,
				 err_log);
}

/**
 * nvme_get_log_smart() - Retrieve nvme smart log
 * @fd:		File descriptor of nvme device
 * @nsid:	Optional namespace identifier
 * @rae:	Retain asynchronous events
 * @smart_log:	User address to store the smart log
 *
 * This log page provides SMART and general health information. The information
 * provided is over the life of the controller and is retained across power
 * cycles. To request the controller log page, the namespace identifier
 * specified is FFFFFFFFh. The controller may also support requesting the log
 * page on a per namespace basis, as indicated by bit 0 of the LPA field in the
 * Identify Controller data structure.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_smart(int fd, __u32 nsid, bool rae,
				     struct nvme_smart_log *smart_log)
{
	return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_SMART,
				 nsid, sizeof(*smart_log), smart_log);
}

/**
 * nvme_get_log_fw_slot() - Retrieves the controller firmware log
 * @fd:		File descriptor of nvme device
 * @rae:	Retain asynchronous events
 * @fw_log:	User address to store the log page
 *
 * This log page describes the firmware revision stored in each firmware slot
 * supported. The firmware revision is indicated as an ASCII string. The log
 * page also indicates the active slot number.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_fw_slot(int fd, bool rae,
			struct nvme_firmware_slot *fw_log)
{
	return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_FW_SLOT,
				 NVME_NSID_ALL, sizeof(*fw_log), fw_log);
}

/**
 * nvme_get_log_changed_ns_list() - Retrieve namespace changed list
 * @fd:		File descriptor of nvme device
 * @rae:	Retain asynchronous events
 * @ns_log:	User address to store the log page
 *
 * This log page describes namespaces attached to this controller that have
 * changed since the last time the namespace was identified, been added, or
 * deleted.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_changed_ns_list(int fd, bool rae,
			struct nvme_ns_list *ns_log)
{
	return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_CHANGED_NS,
				 NVME_NSID_ALL, sizeof(*ns_log), ns_log);
}

/**
 * nvme_get_log_cmd_effects() - Retrieve nvme command effects log
 * @fd:		File descriptor of nvme device
 * @csi:	Command Set Identifier
 * @effects_log:User address to store the effects log
 *
 * This log page describes the commands that the controller supports and the
 * effects of those commands on the state of the NVM subsystem.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_cmd_effects(int fd, enum nvme_csi csi,
			struct nvme_cmd_effects_log *effects_log)
{
	struct nvme_get_log_args args = {
		.lpo = 0,
		.result = NULL,
		.log = effects_log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_CMD_EFFECTS,
		.len = sizeof(*effects_log),
		.nsid = NVME_NSID_ALL,
		.csi = csi,
		.lsi = NVME_LOG_LSI_NONE,
		.lsp = NVME_LOG_LSP_NONE,
		.uuidx = NVME_UUID_NONE,
		.rae = false,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_device_self_test() - Retrieve the device self test log
 * @fd:		File descriptor of nvme device
 * @log:	Userspace address of the log payload
 *
 * The log page indicates the status of an in progress self test and the
 * percent complete of that operation, and the results of the previous 20
 * self-test operations.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_device_self_test(int fd,
			struct nvme_self_test_log *log)
{
	return nvme_get_nsid_log(fd, false, NVME_LOG_LID_DEVICE_SELF_TEST,
				 NVME_NSID_ALL, sizeof(*log), log);
}

/**
 * nvme_get_log_create_telemetry_host() - Create host telemetry log
 * @fd:		File descriptor of nvme device
 * @log:	Userspace address of the log payload
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_create_telemetry_host(int fd,
			struct nvme_telemetry_log *log)
{
	struct nvme_get_log_args args = {
		.lpo = 0,
		.result = NULL,
		.log = log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_TELEMETRY_HOST,
		.len = sizeof(*log),
		.nsid = NVME_NSID_NONE,
		.csi = NVME_CSI_NVM,
		.lsi = NVME_LOG_LSI_NONE,
		.lsp = NVME_LOG_TELEM_HOST_LSP_CREATE,
		.uuidx = NVME_UUID_NONE,
		.rae = false,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_telemetry_host() - Get Telemetry Host-Initiated log page
 * @fd:		File descriptor of nvme device
 * @offset:	Offset into the telemetry data
 * @len:	Length of provided user buffer to hold the log data in bytes
 * @log:	User address for log page data
 *
 * Retrieves the Telemetry Host-Initiated log page at the requested offset
 * using the previously existing capture.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_telemetry_host(int fd, __u64 offset,
			__u32 len, void *log)
{
	struct nvme_get_log_args args = {
		.lpo = offset,
		.result = NULL,
		.log = log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_TELEMETRY_HOST,
		.len = len,
		.nsid = NVME_NSID_NONE,
		.csi = NVME_CSI_NVM,
		.lsi = NVME_LOG_LSI_NONE,
		.lsp = NVME_LOG_TELEM_HOST_LSP_RETAIN,
		.uuidx = NVME_UUID_NONE,
		.rae = false,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_telemetry_ctrl() - Get Telemetry Controller-Initiated log page
 * @fd:		File descriptor of nvme device
 * @rae:	Retain asynchronous events
 * @offset:	Offset into the telemetry data
 * @len:	Length of provided user buffer to hold the log data in bytes
 * @log:	User address for log page data
 *
 * Retrieves the Telemetry Controller-Initiated log page at the requested offset
 * using the previously existing capture.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_telemetry_ctrl(int fd, bool rae,
			__u64 offset, __u32 len, void *log)
{
	struct nvme_get_log_args args = {
		.lpo = offset,
		.result = NULL,
		.log = log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_TELEMETRY_CTRL,
		.len = len,
		.nsid = NVME_NSID_NONE,
		.csi = NVME_CSI_NVM,
		.lsi = NVME_LOG_LSI_NONE,
		.lsp = NVME_LOG_LSP_NONE,
		.uuidx = NVME_UUID_NONE,
		.rae = rae,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_endurance_group() - Get Endurance Group log
 * @fd:		File descriptor of nvme device
 * @endgid:	Starting group identifier to return in the list
 * @log:	User address to store the endurance log
 *
 * This log page indicates if an Endurance Group Event has occurred for a
 * particular Endurance Group. If an Endurance Group Event has occurred, the
 * details of the particular event are included in the Endurance Group
 * Information log page for that Endurance Group. An asynchronous event is
 * generated when an entry for an Endurance Group is newly added to this log
 * page.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_endurance_group(int fd, __u16 endgid,
			struct nvme_endurance_group_log *log)
{
	struct nvme_get_log_args args = {
		.lpo = 0,
		.result = NULL,
		.log = log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_ENDURANCE_GROUP,
		.len = sizeof(*log),
		.nsid = NVME_NSID_NONE,
		.csi = NVME_CSI_NVM,
		.lsi = endgid,
		.lsp = NVME_LOG_LSP_NONE,
		.uuidx = NVME_UUID_NONE,
		.rae = false,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_predictable_lat_nvmset() - Predictable Latency Per NVM Set
 * @fd:		File descriptor of nvme device
 * @nvmsetid:	NVM set id
 * @log:	User address to store the predictable latency log
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_predictable_lat_nvmset(int fd, __u16 nvmsetid,
			struct nvme_nvmset_predictable_lat_log *log)
{
	struct nvme_get_log_args args = {
		.lpo = 0,
		.result = NULL,
		.log = log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_PREDICTABLE_LAT_NVMSET,
		.len = sizeof(*log),
		.nsid = NVME_NSID_NONE,
		.csi = NVME_CSI_NVM,
		.lsi = nvmsetid,
		.lsp = NVME_LOG_LSP_NONE,
		.uuidx = NVME_UUID_NONE,
		.rae = false,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_predictable_lat_event() - Retrieve Predictable Latency Event Aggregate Log Page
 * @fd:		File descriptor of nvme device
 * @rae:	Retain asynchronous events
 * @offset:	Offset into the predictable latency event
 * @len:	Length of provided user buffer to hold the log data in bytes
 * @log:	User address for log page data
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_predictable_lat_event(int fd, bool rae,
			__u32 offset, __u32 len, void *log)
{
	struct nvme_get_log_args args = {
		.lpo = offset,
		.result = NULL,
		.log = log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_PREDICTABLE_LAT_AGG,
		.len = len,
		.nsid = NVME_NSID_NONE,
		.csi = NVME_CSI_NVM,
		.lsi = NVME_LOG_LSI_NONE,
		.lsp = NVME_LOG_LSP_NONE,
		.uuidx = NVME_UUID_NONE,
		.rae = rae,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_ana() - Retrieve Asymmetric Namespace Access log page
 * @fd:		File descriptor of nvme device
 * @lsp:	Log specific, see &enum nvme_get_log_ana_lsp
 * @rae:	Retain asynchronous events
 * @offset:	Offset to the start of the log page
 * @len:	The allocated length of the log page
 * @log:	User address to store the ana log
 *
 * This log consists of a header describing the log and descriptors containing
 * the asymmetric namespace access information for ANA Groups that contain
 * namespaces that are attached to the controller processing the command.
 *
 * See &struct nvme_ana_rsp_hdr for the definition of the returned structure.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_ana(int fd, enum nvme_log_ana_lsp lsp, bool rae,
				   __u64 offset, __u32 len, void *log)
{
	struct nvme_get_log_args args = {
		.lpo = offset,
		.result = NULL,
		.log = log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_ANA,
		.len = len,
		.nsid = NVME_NSID_NONE,
		.csi = NVME_CSI_NVM,
		.lsi = NVME_LOG_LSI_NONE,
		.lsp = (__u8)lsp,
		.uuidx = NVME_UUID_NONE,
		.rae = false,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_ana_groups() - Retrieve Asymmetric Namespace Access groups only log page
 * @fd:		File descriptor of nvme device
 * @rae:	Retain asynchronous events
 * @len:	The allocated length of the log page
 * @log:	User address to store the ana group log
 *
 * See &struct nvme_ana_group_desc for the definition of the returned structure.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_ana_groups(int fd, bool rae, __u32 len,
			    struct nvme_ana_group_desc *log)
{
	return nvme_get_log_ana(fd, NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY, rae, 0,
				len, log);
}

/**
 * nvme_get_log_lba_status() - Retrieve LBA Status
 * @fd:		File descriptor of nvme device
 * @rae:	Retain asynchronous events
 * @offset:	Offset to the start of the log page
 * @len:	The allocated length of the log page
 * @log:	User address to store the log page
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_lba_status(int fd, bool rae,
			__u64 offset, __u32 len, void *log)
{
	struct nvme_get_log_args args = {
		.lpo = offset,
		.result = NULL,
		.log = log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_LBA_STATUS,
		.len = len,
		.nsid = NVME_NSID_NONE,
		.csi = NVME_CSI_NVM,
		.lsi = NVME_LOG_LSI_NONE,
		.lsp = NVME_LOG_LSP_NONE,
		.uuidx = NVME_UUID_NONE,
		.rae = rae,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_endurance_grp_evt() - Retrieve Rotational Media Information
 * @fd:		File descriptor of nvme device
 * @rae:	Retain asynchronous events
 * @offset:	Offset to the start of the log page
 * @len:	The allocated length of the log page
 * @log:	User address to store the log page
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_endurance_grp_evt(int fd, bool rae,
			__u32 offset, __u32 len, void *log)
{
	struct nvme_get_log_args args = {
		.lpo = offset,
		.result = NULL,
		.log = log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_ENDURANCE_GRP_EVT,
		.len = len,
		.nsid = NVME_NSID_NONE,
		.csi = NVME_CSI_NVM,
		.lsi = NVME_LOG_LSI_NONE,
		.lsp = NVME_LOG_LSP_NONE,
		.uuidx = NVME_UUID_NONE,
		.rae = rae,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_fid_supported_effects() - Retrieve Feature Identifiers Supported and Effects
 * @fd:		File descriptor of nvme device
 * @rae:	Retain asynchronous events
 * @log:	FID Supported and Effects data structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise
 */
static inline int nvme_get_log_fid_supported_effects(int fd, bool rae,
			struct nvme_fid_supported_effects_log *log)
{
	return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_FID_SUPPORTED_EFFECTS,
				 NVME_NSID_NONE, sizeof(*log), log);
}

/**
 * nvme_get_log_mi_cmd_supported_effects() - displays the MI Commands Supported by the controller
 * @fd:     File descriptor of nvme device
 * @rae:    Retain asynchronous events
 * @log:    MI Command Supported and Effects data structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise
 */
static inline int nvme_get_log_mi_cmd_supported_effects(int fd, bool rae,
			struct nvme_mi_cmd_supported_effects_log *log)
{
	return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_MI_CMD_SUPPORTED_EFFECTS,
				 NVME_NSID_NONE, sizeof(*log), log);
}

/**
 * nvme_get_log_boot_partition() - Retrieve Boot Partition
 * @fd:		File descriptor of nvme device
 * @rae:	Retain asynchronous events
 * @lsp:	The log specified field of LID
 * @len:	The allocated size, minimum
 *		struct nvme_boot_partition
 * @part:	User address to store the log page
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise
 */
static inline int nvme_get_log_boot_partition(int fd, bool rae,
			__u8 lsp, __u32 len, struct nvme_boot_partition *part)
{
	struct nvme_get_log_args args = {
		.lpo = 0,
		.result = NULL,
		.log = part,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_BOOT_PARTITION,
		.len = len,
		.nsid = NVME_NSID_NONE,
		.csi = NVME_CSI_NVM,
		.lsi = NVME_LOG_LSI_NONE,
		.lsp = NVME_LOG_LSP_NONE,
		.uuidx = NVME_UUID_NONE,
		.rae = rae,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_discovery() - Retrieve Discovery log page
 * @fd:		File descriptor of nvme device
 * @rae:	Retain asynchronous events
 * @offset:	Offset of this log to retrieve
 * @len:	The allocated size for this portion of the log
 * @log:	User address to store the discovery log
 *
 * Supported only by fabrics discovery controllers, returning discovery
 * records.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_discovery(int fd, bool rae,
			__u32 offset, __u32 len, void *log)
{
	struct nvme_get_log_args args = {
		.lpo = offset,
		.result = NULL,
		.log = log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_DISCOVER,
		.len = len,
		.nsid = NVME_NSID_NONE,
		.csi = NVME_CSI_NVM,
		.lsi = NVME_LOG_LSI_NONE,
		.lsp = NVME_LOG_LSP_NONE,
		.uuidx = NVME_UUID_NONE,
		.rae = rae,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_media_unit_stat() - Retrieve Media Unit Status
 * @fd:		File descriptor of nvme device
 * @domid:	Domain Identifier selection, if supported
 * @mus:	User address to store the Media Unit statistics log
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise
 */
static inline int nvme_get_log_media_unit_stat(int fd, __u16 domid,
			struct nvme_media_unit_stat_log *mus)
{
	struct nvme_get_log_args args = {
		.lpo = 0,
		.result = NULL,
		.log = mus,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_MEDIA_UNIT_STATUS,
		.len = sizeof(*mus),
		.nsid = NVME_NSID_NONE,
		.csi = NVME_CSI_NVM,
		.lsi = domid,
		.lsp = NVME_LOG_LSP_NONE,
		.uuidx = NVME_UUID_NONE,
		.rae = false,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_support_cap_config_list() - Retrieve Supported Capacity Configuration List
 * @fd:		File descriptor of nvme device
 * @domid:	Domain Identifier selection, if supported
 * @cap:	User address to store supported capabilities config list
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise
 */
static inline int nvme_get_log_support_cap_config_list(int fd, __u16 domid,
			struct nvme_supported_cap_config_list_log *cap)
{
	struct nvme_get_log_args args = {
		.lpo = 0,
		.result = NULL,
		.log = cap,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_SUPPORTED_CAP_CONFIG_LIST,
		.len = sizeof(*cap),
		.nsid = NVME_NSID_NONE,
		.csi = NVME_CSI_NVM,
		.lsi = domid,
		.lsp = NVME_LOG_LSP_NONE,
		.uuidx = NVME_UUID_NONE,
		.rae = false,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_reservation() - Retrieve Reservation Notification
 * @fd:		File descriptor of nvme device
 * @rae:	Retain asynchronous events
 * @log:	User address to store the reservation log
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise
 */
static inline int nvme_get_log_reservation(int fd, bool rae,
			struct nvme_resv_notification_log *log)
{
	return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_RESERVATION,
				 NVME_NSID_ALL, sizeof(*log), log);
}

/**
 * nvme_get_log_sanitize() - Retrieve Sanitize Status
 * @fd:		File descriptor of nvme device
 * @rae:	Retain asynchronous events
 * @log:	User address to store the sanitize log
 *
 * The Sanitize Status log page reports sanitize operation time estimates and
 * information about the most recent sanitize operation.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_sanitize(int fd, bool rae,
			struct nvme_sanitize_log_page *log)
{
	return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_SANITIZE,
				 NVME_NSID_ALL, sizeof(*log), log);
}

/**
 * nvme_get_log_zns_changed_zones() - Retrieve list of zones that have changed
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace ID
 * @rae:	Retain asynchronous events
 * @log:	User address to store the changed zone log
 *
 * The list of zones that have changed state due to an exceptional event.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_zns_changed_zones(int fd, __u32 nsid, bool rae,
			struct nvme_zns_changed_zone_log *log)
{
	struct nvme_get_log_args args = {
		.lpo = 0,
		.result = NULL,
		.log = log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_ZNS_CHANGED_ZONES,
		.len = sizeof(*log),
		.nsid = nsid,
		.csi = NVME_CSI_ZNS,
		.lsi = NVME_LOG_LSI_NONE,
		.lsp = NVME_LOG_LSP_NONE,
		.uuidx = NVME_UUID_NONE,
		.rae = rae,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_get_log_persistent_event() - Retrieve Persistent Event Log
 * @fd:		File descriptor of nvme device
 * @action:	Action the controller should take during processing this command
 * @size:	Size of @pevent_log
 * @pevent_log:	User address to store the persistent event log
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_log_persistent_event(int fd,
			enum nvme_pevent_log_action action,
			__u32 size, void *pevent_log)
{
	struct nvme_get_log_args args = {
		.lpo = 0,
		.result = NULL,
		.log = pevent_log,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid = NVME_LOG_LID_PERSISTENT_EVENT,
		.len = size,
		.nsid = NVME_NSID_ALL,
		.csi = NVME_CSI_NVM,
		.lsi = NVME_LOG_LSI_NONE,
		.lsp = (__u8)action,
		.uuidx = NVME_UUID_NONE,
		.rae = false,
		.ot = false,
	};
	return nvme_get_log(&args);
}

/**
 * nvme_set_features() - Set a feature attribute
 * @args:	&struct nvme_set_features_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features(struct nvme_set_features_args *args);

/**
 * nvme_set_features_data() - Helper function for @nvme_set_features()
 * @fd:		File descriptor of nvme device
 * @fid:	Feature identifier
 * @nsid:	Namespace ID, if applicable
 * @cdw11:	Value to set the feature to
 * @save:	Save value across power states
 * @data_len:	Length of feature data, if applicable, in bytes
 * @data:	User address of feature data, if applicable
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_set_features_data(int fd, __u8 fid, __u32 nsid,
			__u32 cdw11, bool save, __u32 data_len, void *data,
			__u32 *result)
{
	struct nvme_set_features_args args = {
		.result = result,
		.data = data,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.nsid = nsid,
		.cdw11 = cdw11,
		.cdw12 = 0,
		.cdw13 = 0,
		.cdw15 = 0,
		.data_len = data_len,
		.save = save,
		.uuidx = 0,
		.fid = fid,
	};
	return nvme_set_features(&args);
}

/**
 * nvme_set_features_simple() - Helper function for @nvme_set_features()
 * @fd:		File descriptor of nvme device
 * @fid:	Feature identifier
 * @nsid:	Namespace ID, if applicable
 * @cdw11:	Value to set the feature to
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_set_features_simple(int fd, __u8 fid, __u32 nsid,
			__u32 cdw11, bool save, __u32 *result)
{
	return nvme_set_features_data(fd, fid, nsid, cdw11, save, 0, NULL,
				 result);
}

/**
 * nvme_set_features_arbitration() - Set arbitration features
 * @fd:		File descriptor of nvme device
 * @ab:		Arbitration Burst
 * @lpw:	Low Priority Weight
 * @mpw:	Medium Priority Weight
 * @hpw:	High Priority Weight
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_arbitration(int fd, __u8 ab, __u8 lpw, __u8 mpw,
				  __u8 hpw, bool  save, __u32 *result);

/**
 * nvme_set_features_power_mgmt() - Set power management feature
 * @fd:		File descriptor of nvme device
 * @ps:		Power State
 * @wh:		Workload Hint
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_power_mgmt(int fd, __u8 ps, __u8 wh, bool save,
				 __u32 *result);

/**
 * nvme_set_features_lba_range() - Set LBA range feature
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace ID
 * @nr_ranges:	Number of ranges in @data
 * @save:	Save value across power states
 * @data:	User address of feature data
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_lba_range(int fd, __u32 nsid, __u32 nr_ranges, bool save,
				struct nvme_lba_range_type *data, __u32 *result);

/**
 * nvme_set_features_temp_thresh() - Set temperature threshold feature
 * @fd:		File descriptor of nvme device
 * @tmpth:	Temperature Threshold
 * @tmpsel:	Threshold Temperature Select
 * @thsel:	Threshold Type Select
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_temp_thresh(int fd, __u16 tmpth, __u8 tmpsel,
				  enum nvme_feat_tmpthresh_thsel thsel,
				  bool save, __u32 *result);

/**
 * nvme_set_features_err_recovery() - Set error recovery feature
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace ID
 * @tler:	Time-limited error recovery value
 * @dulbe:	Deallocated or Unwritten Logical Block Error Enable
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_err_recovery(int fd, __u32 nsid, __u16 tler,
				   bool dulbe, bool save, __u32 *result);

/**
 * nvme_set_features_volatile_wc() - Set volatile write cache feature
 * @fd:		File descriptor of nvme device
 * @wce:	Write cache enable
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_volatile_wc(int fd, bool wce, bool save,
				  __u32 *result);

/**
 * nvme_set_features_irq_coalesce() - Set IRQ coalesce feature
 * @fd:		File descriptor of nvme device
 * @thr:	Aggregation Threshold
 * @time:	Aggregation Time
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_irq_coalesce(int fd, __u8 thr, __u8 time,
				   bool save, __u32 *result);

/**
 * nvme_set_features_irq_config() - Set IRQ config feature
 * @fd:		File descriptor of nvme device
 * @iv:		Interrupt Vector
 * @cd:		Coalescing Disable
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_irq_config(int fd, __u16 iv, bool cd, bool save,
				 __u32 *result);

/**
 * nvme_set_features_write_atomic() - Set write atomic feature
 * @fd:		File descriptor of nvme device
 * @dn:		Disable Normal
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_write_atomic(int fd, bool dn, bool save,
				   __u32 *result);

/**
 * nvme_set_features_async_event() - Set asynchronous event feature
 * @fd:		File descriptor of nvme device
 * @events:	Events to enable
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_async_event(int fd, __u32 events, bool save,
				  __u32 *result);

/**
 * nvme_set_features_auto_pst() - Set autonomous power state feature
 * @fd:		File descriptor of nvme device
 * @apste:	Autonomous Power State Transition Enable
 * @apst:	Autonomous Power State Transition
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_auto_pst(int fd, bool apste, bool save,
			       struct nvme_feat_auto_pst *apst,
			       __u32 *result);

/**
 * nvme_set_features_timestamp() - Set timestamp feature
 * @fd:		File descriptor of nvme device
 * @save:	Save value across power states
 * @timestamp:	The current timestamp value to assign to this feature
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_timestamp(int fd, bool save, __u64 timestamp);

/**
 * nvme_set_features_hctm() - Set thermal management feature
 * @fd:		File descriptor of nvme device
 * @tmt2:	Thermal Management Temperature 2
 * @tmt1:	Thermal Management Temperature 1
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_hctm(int fd, __u16 tmt2, __u16 tmt1, bool save,
			   __u32 *result);

/**
 * nvme_set_features_nopsc() - Set non-operational power state feature
 * @fd:		File descriptor of nvme device
 * @noppme:	Non-Operational Power State Permissive Mode Enable
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_nopsc(int fd, bool noppme, bool save, __u32 *result);

/**
 * nvme_set_features_rrl() - Set read recovery level feature
 * @fd:		File descriptor of nvme device
 * @rrl:	Read recovery level setting
 * @nvmsetid:	NVM set id
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_rrl(int fd, __u8 rrl, __u16 nvmsetid, bool save,
			  __u32 *result);

/**
 * nvme_set_features_plm_config() - Set predictable latency feature
 * @fd:		File descriptor of nvme device
 * @enable:	Predictable Latency Enable
 * @nvmsetid:	NVM Set Identifier
 * @save:	Save value across power states
 * @data:	Pointer to structure nvme_plm_config
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_plm_config(int fd, bool enable, __u16 nvmsetid,
				 bool save, struct nvme_plm_config *data,
				 __u32 *result);

/**
 * nvme_set_features_plm_window() - Set window select feature
 * @fd:		File descriptor of nvme device
 * @sel:	Window Select
 * @nvmsetid:	NVM Set Identifier
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_plm_window(int fd, enum nvme_feat_plm_window_select sel,
				 __u16 nvmsetid, bool save, __u32 *result);

/**
 * nvme_set_features_lba_sts_interval() - Set LBA status information feature
 * @fd:		File descriptor of nvme device
 * @save:	Save value across power states
 * @lsiri:	LBA Status Information Report Interval
 * @lsipi:	LBA Status Information Poll Interval
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_lba_sts_interval(int fd, __u16 lsiri, __u16 lsipi,
				       bool save, __u32 *result);

/**
 * nvme_set_features_host_behavior() - Set host behavior feature
 * @fd:		File descriptor of nvme device
 * @save:	Save value across power states
 * @data:	Pointer to structure nvme_feat_host_behavior
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_host_behavior(int fd, bool save,
				    struct nvme_feat_host_behavior *data);

/**
 * nvme_set_features_sanitize() - Set sanitize feature
 * @fd:		File descriptor of nvme device
 * @nodrm:	No-Deallocate Response Mode
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_sanitize(int fd, bool nodrm, bool save, __u32 *result);

/**
 * nvme_set_features_endurance_evt_cfg() - Set endurance event config feature
 * @fd:		File descriptor of nvme device
 * @endgid:	Endurance Group Identifier
 * @egwarn:	Flags to enable warning, see &enum nvme_eg_critical_warning_flags
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_endurance_evt_cfg(int fd, __u16 endgid, __u8 egwarn,
					bool save, __u32 *result);

/**
 * nvme_set_features_sw_progress() - Set pre-boot software load count feature
 * @fd:		File descriptor of nvme device
 * @pbslc:	Pre-boot Software Load Count
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_sw_progress(int fd, __u8 pbslc, bool save,
				  __u32 *result);

/**
 * nvme_set_features_host_id() - Set enable extended host identifers feature
 * @fd:		File descriptor of nvme device
 * @exhid:	Enable Extended Host Identifier
 * @save:	Save value across power states
 * @hostid:	Host ID to set
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_host_id(int fd, bool exhid, bool save, __u8 *hostid);

/**
 * nvme_set_features_resv_mask() - Set reservation notification mask feature
 * @fd:		File descriptor of nvme device
 * @mask:	Reservation Notification Mask Field
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_resv_mask(int fd, __u32 mask, bool save, __u32 *result);

/**
 * nvme_set_features_resv_persist() - Set persist through power loss feature
 * @fd:		File descriptor of nvme device
 * @ptpl:	Persist Through Power Loss
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_resv_persist(int fd, bool ptpl, bool save, __u32 *result);

/**
 * nvme_set_features_write_protect() - Set write protect feature
 * @fd:		File descriptor of nvme device
 * @state:	Write Protection State
 * @save:	Save value across power states
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_features_write_protect(int fd, enum nvme_feat_nswpcfg_state state,
				    bool save, __u32 *result);

/**
 * nvme_get_features() - Retrieve a feature attribute
 * @args:	&struct nvme_get_features_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features(struct nvme_get_features_args *args);

/**
 * nvme_get_features_data() - Helper function for @nvme_get_features()
 * @fd:		File descriptor of nvme device
 * @fid:	Feature identifier
 * @nsid:	Namespace ID, if applicable
 * @data_len:	Length of feature data, if applicable, in bytes
 * @data:	User address of feature data, if applicable
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_features_data(int fd, enum nvme_features_id fid,
			__u32 nsid, __u32 data_len, void *data, __u32 *result)
{
	struct nvme_get_features_args args = {
		.result = result,
		.data = data,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.nsid = nsid,
		.sel = NVME_GET_FEATURES_SEL_CURRENT,
		.cdw11 = 0,
		.data_len = data_len,
		.fid = (__u8)fid,
		.uuidx = NVME_UUID_NONE,
	};

	return nvme_get_features(&args);
}

/**
 * nvme_get_features_simple() - Helper function for @nvme_get_features()
 * @fd:		File descriptor of nvme device
 * @fid:	Feature identifier
 * @nsid:	Namespace ID, if applicable
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_get_features_simple(int fd, enum nvme_features_id fid,
			__u32 nsid, __u32 *result)
{
	return nvme_get_features_data(fd, fid, nsid, 0, NULL, result);
}

/**
 * nvme_get_features_arbitration() - Get arbitration feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_arbitration(int fd, enum nvme_get_features_sel sel,
				  __u32 *result);

/**
 * nvme_get_features_power_mgmt() - Get power management feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_power_mgmt(int fd, enum nvme_get_features_sel sel,
				 __u32 *result);

/**
 * nvme_get_features_lba_range() - Get LBA range feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @data:	User address of feature data, if applicable
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_lba_range(int fd, enum nvme_get_features_sel sel,
				struct nvme_lba_range_type *data,
				__u32 *result);

/**
 * nvme_get_features_temp_thresh() - Get temperature threshold feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_temp_thresh(int fd, enum nvme_get_features_sel sel,
				  __u32 *result);

/**
 * nvme_get_features_err_recovery() - Get error recovery feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_err_recovery(int fd, enum nvme_get_features_sel sel,
				   __u32 *result);

/**
 * nvme_get_features_volatile_wc() - Get volatile write cache feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_volatile_wc(int fd, enum nvme_get_features_sel sel,
				  __u32 *result);

/**
 * nvme_get_features_num_queues() - Get number of queues feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_num_queues(int fd, enum nvme_get_features_sel sel,
				 __u32 *result);

/**
 * nvme_get_features_irq_coalesce() - Get IRQ coalesce feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_irq_coalesce(int fd, enum nvme_get_features_sel sel,
				   __u32 *result);

/**
 * nvme_get_features_irq_config() - Get IRQ config feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @iv:
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_irq_config(int fd, enum nvme_get_features_sel sel,
				 __u16 iv, __u32 *result);

/**
 * nvme_get_features_write_atomic() - Get write atomic feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_write_atomic(int fd, enum nvme_get_features_sel sel,
				   __u32 *result);

/**
 * nvme_get_features_async_event() - Get asynchronous event feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_async_event(int fd, enum nvme_get_features_sel sel,
				  __u32 *result);

/**
 * nvme_get_features_auto_pst() - Get autonomous power state feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @apst:
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_auto_pst(int fd, enum nvme_get_features_sel sel,
			       struct nvme_feat_auto_pst *apst, __u32 *result);

/**
 * nvme_get_features_host_mem_buf() - Get host memory buffer feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_host_mem_buf(int fd, enum nvme_get_features_sel sel,
				   __u32 *result);

/**
 * nvme_get_features_timestamp() - Get timestamp feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @ts:		Current timestamp
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_timestamp(int fd, enum nvme_get_features_sel sel,
				struct nvme_timestamp *ts);

/**
 * nvme_get_features_kato() - Get keep alive timeout feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_kato(int fd, enum nvme_get_features_sel sel, __u32 *result);

/**
 * nvme_get_features_hctm() - Get thermal management feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_hctm(int fd, enum nvme_get_features_sel sel, __u32 *result);

/**
 * nvme_get_features_nopsc() - Get non-operational power state feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_nopsc(int fd, enum nvme_get_features_sel sel, __u32 *result);

/**
 * nvme_get_features_rrl() - Get read recovery level feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_rrl(int fd, enum nvme_get_features_sel sel, __u32 *result);

/**
 * nvme_get_features_plm_config() - Get predictable latency feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @nvmsetid:	NVM set id
 * @data:
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_plm_config(int fd, enum nvme_get_features_sel sel,
				 __u16 nvmsetid, struct nvme_plm_config *data,
				 __u32 *result);

/**
 * nvme_get_features_plm_window() - Get window select feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @nvmsetid:	NVM set id
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_plm_window(int fd, enum nvme_get_features_sel sel,
	__u16 nvmsetid, __u32 *result);

/**
 * nvme_get_features_lba_sts_interval() - Get LBA status information feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_lba_sts_interval(int fd, enum nvme_get_features_sel sel,
				       __u32 *result);

/**
 * nvme_get_features_host_behavior() - Get host behavior feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @data:	Pointer to structure nvme_feat_host_behavior
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_host_behavior(int fd, enum nvme_get_features_sel sel,
				    struct nvme_feat_host_behavior *data,
				    __u32 *result);

/**
 * nvme_get_features_sanitize() - Get sanitize feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_sanitize(int fd, enum nvme_get_features_sel sel,
				__u32 *result);

/**
 * nvme_get_features_endurance_event_cfg() - Get endurance event config feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @endgid:	Endurance Group Identifier
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_endurance_event_cfg(int fd, enum nvme_get_features_sel sel,
					  __u16 endgid, __u32 *result);

/**
 * nvme_get_features_sw_progress() - Get software progress feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_sw_progress(int fd, enum nvme_get_features_sel sel,
				  __u32 *result);

/**
 * nvme_get_features_host_id() - Get host id feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @exhid:	Enable Extended Host Identifier
 * @len:	Length of @hostid
 * @hostid:	Buffer for returned host ID
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_host_id(int fd, enum nvme_get_features_sel sel,
			      bool exhid, __u32 len, __u8 *hostid);

/**
 * nvme_get_features_resv_mask() - Get reservation mask feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_resv_mask(int fd, enum nvme_get_features_sel sel,
				__u32 *result);

/**
 * nvme_get_features_resv_persist() - Get reservation persist feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_resv_persist(int fd, enum nvme_get_features_sel sel,
				   __u32 *result);

/**
 * nvme_get_features_write_protect() - Get write protect feature
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace ID
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_write_protect(int fd, __u32 nsid,
				    enum nvme_get_features_sel sel,
				    __u32 *result);

/**
 * nvme_get_features_iocs_profile() - Get IOCS profile feature
 * @fd:		File descriptor of nvme device
 * @sel:	Select which type of attribute to return, see &enum nvme_get_features_sel
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_features_iocs_profile(int fd, enum nvme_get_features_sel sel,
				   __u32 *result);

/**
 * nvme_format_nvm() - Format nvme namespace(s)
 * @args:	&struct nvme_format_nvme_args argument structure
 *
 * The Format NVM command low level formats the NVM media. This command is used
 * by the host to change the LBA data size and/or metadata size. A low level
 * format may destroy all data and metadata associated with all namespaces or
 * only the specific namespace associated with the command
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_format_nvm(struct nvme_format_nvm_args *args);

/**
 * nvme_ns_mgmt() - Issue a Namespace management command
 * @args:	&struct nvme_ns_mgmt_args Argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_ns_mgmt(struct nvme_ns_mgmt_args *args);

/**
 * nvme_ns_mgmt_create() - Create a non attached namespace
 * @fd:		File descriptor of nvme device
 * @ns:		Namespace identification that defines ns creation parameters
 * @nsid:		On success, set to the namespace id that was created
 * @timeout:		Override the default timeout to this value in milliseconds;
 *			set to 0 to use the system default.
 * @csi:		Command Set Identifier
 *
 * On successful creation, the namespace exists in the subsystem, but is not
 * attached to any controller. Use the nvme_ns_attach_ctrls() to assign the
 * namespace to one or more controllers.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_ns_mgmt_create(int fd, struct nvme_id_ns *ns,
			__u32 *nsid, __u32 timeout, __u8 csi)
{
	struct nvme_ns_mgmt_args args = {
		.result = nsid,
		.ns = ns,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = timeout,
		.nsid = NVME_NSID_NONE,
		.sel = NVME_NS_MGMT_SEL_CREATE,
		.csi = csi,
	};

	return nvme_ns_mgmt(&args);
}

/**
 * nvme_ns_mgmt_delete() - Delete a non attached namespace
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace identifier to delete
 *
 * It is recommended that a namespace being deleted is not attached to any
 * controller. Use the nvme_ns_detach_ctrls() first if the namespace is still
 * attached.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_ns_mgmt_delete(int fd, __u32 nsid)
{
	struct nvme_ns_mgmt_args args = {
		.result = NULL,
		.ns = NULL,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = 0,
		.nsid = nsid,
		.sel = NVME_NS_MGMT_SEL_DELETE,
		.csi = 0,
	};

	return nvme_ns_mgmt(&args);
}

/**
 * nvme_ns_attach() - Attach or detach namespace to controller(s)
 * @args:	&struct nvme_ns_attach_args Argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_ns_attach(struct nvme_ns_attach_args *args);

/**
 * nvme_ns_attach_ctrls() - Attach namespace to controllers
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace ID to attach
 * @ctrlist:	Controller list to modify attachment state of nsid
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_ns_attach_ctrls(int fd, __u32 nsid,
			struct nvme_ctrl_list *ctrlist)
{
	struct nvme_ns_attach_args args = {
		.result = NULL,
		.ctrlist = ctrlist,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.nsid = nsid,
		.sel = NVME_NS_ATTACH_SEL_CTRL_ATTACH,
	};

	return nvme_ns_attach(&args);
}

/**
 * nvme_ns_detach_ctrls() - Detach namespace from controllers
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace ID to detach
 * @ctrlist:	Controller list to modify attachment state of nsid
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_ns_detach_ctrls(int fd, __u32 nsid,
			struct nvme_ctrl_list *ctrlist)
{
	struct nvme_ns_attach_args args = {
		.result = NULL,
		.ctrlist = ctrlist,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.nsid = nsid,
		.sel = NVME_NS_ATTACH_SEL_CTRL_DEATTACH,
	};

	return nvme_ns_attach(&args);
}

/**
 * nvme_fw_download() - Download part or all of a firmware image to the
 *			controller
 * @args:	&struct nvme_fw_download_args argument structure
 *
 * The Firmware Image Download command downloads all or a portion of an image
 * for a future update to the controller. The Firmware Image Download command
 * downloads a new image (in whole or in part) to the controller.
 *
 * The image may be constructed of multiple pieces that are individually
 * downloaded with separate Firmware Image Download commands. Each Firmware
 * Image Download command includes a Dword Offset and Number of Dwords that
 * specify a dword range.
 *
 * The new firmware image is not activated as part of the Firmware Image
 * Download command. Use the nvme_fw_commit() to activate a newly downloaded
 * image.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_fw_download(struct nvme_fw_download_args *args);

/**
 * nvme_fw_commit() - Commit firmware using the specified action
 * @args:	&struct nvme_fw_commit_args argument structure
 *
 * The Firmware Commit command modifies the firmware image or Boot Partitions.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise. The command
 * status response may specify additional reset actions required to complete
 * the commit process.
 */
int nvme_fw_commit(struct nvme_fw_commit_args *args);

/**
 * nvme_security_send() - Security Send command
 * @args:	&struct nvme_security_send argument structure
 *
 * The Security Send command transfers security protocol data to the
 * controller. The data structure transferred to the controller as part of this
 * command contains security protocol specific commands to be performed by the
 * controller. The data structure transferred may also contain data or
 * parameters associated with the security protocol commands.
 *
 * The security data is protocol specific and is not defined by the NVMe
 * specification.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_security_send(struct nvme_security_send_args *args);

/**
 * nvme_security_receive() - Security Receive command
 * @args:	&struct nvme_security_receive argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_security_receive(struct nvme_security_receive_args *args);

/**
 * nvme_get_lba_status() - Retrieve information on possibly unrecoverable LBAs
 * @args:	&struct nvme_get_lba_status_args argument structure
 *
 * The Get LBA Status command requests information about Potentially
 * Unrecoverable LBAs. Refer to the specification for action type descriptions.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_lba_status(struct nvme_get_lba_status_args *args);

/**
 * nvme_directive_send() - Send directive command
 * @args:	&struct nvme_directive_send_args argument structure
 *
 * Directives is a mechanism to enable host and NVM subsystem or controller
 * information exchange. The Directive Send command transfers data related to a
 * specific Directive Type from the host to the controller.
 *
 * See the NVMe specification for more information.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_directive_send(struct nvme_directive_send_args *args);

/**
 * nvme_directive_send_id_endir() - Directive Send Enable Directive
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace Identifier
 * @endir:	Enable Directive
 * @dtype:	Directive Type
 * @id:		Pointer to structure nvme_id_directives
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_directive_send_id_endir(int fd, __u32 nsid, bool endir,
				 enum nvme_directive_dtype dtype,
				 struct nvme_id_directives *id);

/**
 * nvme_directive_send_stream_release_identifier() - Directive Send Stream release
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace ID
 * @stream_id:	Stream identifier
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_directive_send_stream_release_identifier(int fd,
			__u32 nsid, __u16 stream_id)
{
	struct nvme_directive_send_args args = {
		.result = NULL,
		.data = NULL,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.nsid = nsid,
		.doper = NVME_DIRECTIVE_SEND_STREAMS_DOPER_RELEASE_IDENTIFIER,
		.dtype = NVME_DIRECTIVE_DTYPE_STREAMS,
		.cdw12 = 0,
		.data_len = 0,
		.dspec = stream_id,
	};

	return nvme_directive_send(&args);
}

/**
 * nvme_directive_send_stream_release_resource() - Directive Send Stream release resources
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace ID
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_directive_send_stream_release_resource(int fd, __u32 nsid)
{
	struct nvme_directive_send_args args = {
		.result = NULL,
		.data = NULL,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.nsid = nsid,
		.doper = NVME_DIRECTIVE_SEND_STREAMS_DOPER_RELEASE_RESOURCE,
		.dtype = NVME_DIRECTIVE_DTYPE_STREAMS,
		.cdw12 = 0,
		.data_len = 0,
		.dspec = 0,
	};

	return nvme_directive_send(&args);
}

/**
 * nvme_directive_recv() - Receive directive specific data
 * @args:	&struct nvme_directive_recv_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_directive_recv(struct nvme_directive_recv_args *args);

/**
 * nvme_directive_recv_identify_parameters() - Directive receive identifier parameters
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace ID
 * @id:		Identify parameters buffer
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_directive_recv_identify_parameters(int fd, __u32 nsid,
			struct nvme_id_directives *id)
{
	struct nvme_directive_recv_args args = {
		.result = NULL,
		.data = id,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.nsid = nsid,
		.doper = NVME_DIRECTIVE_RECEIVE_IDENTIFY_DOPER_PARAM,
		.dtype = NVME_DIRECTIVE_DTYPE_IDENTIFY,
		.cdw12 = 0,
		.data_len = sizeof(*id),
		.dspec = 0,
	};

	return nvme_directive_recv(&args);
}

/**
 * nvme_directive_recv_stream_parameters() - Directive receive stream parameters
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace ID
 * @parms:	Streams directive parameters buffer
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_directive_recv_stream_parameters(int fd, __u32 nsid,
			struct nvme_streams_directive_params *parms)
{
	struct nvme_directive_recv_args args = {
		.result = NULL,
		.data = parms,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.nsid = nsid,
		.doper = NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_PARAM,
		.dtype = NVME_DIRECTIVE_DTYPE_STREAMS,
		.cdw12 = 0,
		.data_len = sizeof(*parms),
		.dspec = 0,
	};

	return nvme_directive_recv(&args);
}

/**
 * nvme_directive_recv_stream_status() - Directive receive stream status
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace ID
 * @nr_entries: Number of streams to receive
 * @id:		Stream status buffer
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_directive_recv_stream_status(int fd, __u32 nsid,
			unsigned int nr_entries,
			struct nvme_streams_directive_status *id)
{
	struct nvme_directive_recv_args args = {
		.result = NULL,
		.data = id,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.nsid = nsid,
		.doper = NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_STATUS,
		.dtype = NVME_DIRECTIVE_DTYPE_STREAMS,
		.cdw12 = 0,
		.data_len = sizeof(*id),
		.dspec = 0,
	};

	return nvme_directive_recv(&args);
}

/**
 * nvme_directive_recv_stream_allocate() - Directive receive stream allocate
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace ID
 * @nsr:	Namespace Streams Requested
 * @result:	If successful, the CQE dword0 value
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_directive_recv_stream_allocate(int fd, __u32 nsid,
			__u16 nsr, __u32 *result)
{
	struct nvme_directive_recv_args args = {
		.result = result,
		.data = NULL,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.nsid = nsid,
		.doper = NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_RESOURCE,
		.dtype = NVME_DIRECTIVE_DTYPE_STREAMS,
		.cdw12 = nsr,
		.data_len = 0,
		.dspec = 0,
	};

	return nvme_directive_recv(&args);
}

/**
 * nvme_capacity_mgmt() - Capacity management command
 * @args:	&struct nvme_capacity_mgmt_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_capacity_mgmt(struct nvme_capacity_mgmt_args *args);

/**
 * nvme_lockdown() - Issue lockdown command
 * @args:	&struct nvme_lockdown_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_lockdown(struct nvme_lockdown_args *args);

/**
 * nvme_set_property() - Set controller property
 * @args:	&struct nvme_set_property_args argument structure
 *
 * This is an NVMe-over-Fabrics specific command, not applicable to PCIe. These
 * properties align to the PCI MMIO controller registers.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_set_property(struct nvme_set_property_args *args);

/**
 * nvme_get_property() - Get a controller property
 * @args:	&struct nvme_get_propert_args argument structure
 *
 * This is an NVMe-over-Fabrics specific command, not applicable to PCIe. These
 * properties align to the PCI MMIO controller registers.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_get_property(struct nvme_get_property_args *args);

/**
 * nvme_sanitize_nvm() - Start a sanitize operation
 * @args:	&struct nvme_sanitize_nvm_args argument structure
 *
 * A sanitize operation alters all user data in the NVM subsystem such that
 * recovery of any previous user data from any cache, the non-volatile media,
 * or any Controller Memory Buffer is not possible.
 *
 * The Sanitize command starts a sanitize operation or to recover from a
 * previously failed sanitize operation. The sanitize operation types that may
 * be supported are Block Erase, Crypto Erase, and Overwrite. All sanitize
 * operations are processed in the background, i.e., completion of the sanitize
 * command does not indicate completion of the sanitize operation.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_sanitize_nvm(struct nvme_sanitize_nvm_args *args);

/**
 * nvme_dev_self_test() - Start or abort a self test
 * @args:	&struct nvme_dev_self_test argument structure
 *
 * The Device Self-test command starts a device self-test operation or abort a
 * device self-test operation. A device self-test operation is a diagnostic
 * testing sequence that tests the integrity and functionality of the
 * controller and may include testing of the media associated with namespaces.
 * The controller may return a response to this command immediately while
 * running the self-test in the background.
 *
 * Set the 'nsid' field to 0 to not include namepsaces in the test. Set to
 * 0xffffffff to test all namespaces. All other values tests a specific
 * namespace, if present.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_dev_self_test(struct nvme_dev_self_test_args *args);

/**
 * nvme_virtual_mgmt() - Virtualization resource management
 * @args:	&struct nvme_virtual_mgmt_args argument structure
 *
 * The Virtualization Management command is supported by primary controllers
 * that support the Virtualization Enhancements capability. This command is
 * used for several functions:
 *
 *	- Modifying Flexible Resource allocation for the primary controller
 *	- Assigning Flexible Resources for secondary controllers
 *	- Setting the Online and Offline state for secondary controllers
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_virtual_mgmt(struct nvme_virtual_mgmt_args *args);

/**
 * nvme_flush() - Send an nvme flush command
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace identifier
 *
 * The Flush command requests that the contents of volatile write cache be made
 * non-volatile.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_flush(int fd, __u32 nsid)
{
	struct nvme_passthru_cmd cmd = {};

	cmd.opcode = nvme_cmd_flush;
	cmd.nsid = nsid;

	return nvme_submit_io_passthru(fd, &cmd, NULL);
}

/**
 * nvme_io() - Submit an nvme user I/O command
 * @args:	&struct nvme_io_args argument structure
 * @opcode:	Opcode to execute
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_io(struct nvme_io_args *args, __u8 opcode);

/**
 * nvme_read() - Submit an nvme user read command
 * @args:	&struct nvme_io_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_read(struct nvme_io_args *args)
{
	return nvme_io(args, nvme_cmd_read);
}

/**
 * nvme_write() - Submit an nvme user write command
 * @args:	&struct nvme_io_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_write(struct nvme_io_args *args)
{
	return nvme_io(args, nvme_cmd_write);
}

/**
 * nvme_compare() - Submit an nvme user compare command
 * @args:	&struct nvme_io_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_compare(struct nvme_io_args *args)
{
	return nvme_io(args, nvme_cmd_compare);
}

/**
 * nvme_write_zeros() - Submit an nvme write zeroes command
 * @args:	&struct nvme_io_args argument structure
 *
 * The Write Zeroes command sets a range of logical blocks to zero.  After
 * successful completion of this command, the value returned by subsequent
 * reads of logical blocks in this range shall be all bytes cleared to 0h until
 * a write occurs to this LBA range.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_write_zeros(struct nvme_io_args *args)
{
	return nvme_io(args, nvme_cmd_write_zeroes);
}

/**
 * nvme_write_uncorrectable() - Submit an nvme write uncorrectable command
 * @args:	&struct nvme_io_args argument structure
 *
 * The Write Uncorrectable command marks a range of logical blocks as invalid.
 * When the specified logical block(s) are read after this operation, a failure
 * is returned with Unrecovered Read Error status. To clear the invalid logical
 * block status, a write operation on those logical blocks is required.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_write_uncorrectable(struct nvme_io_args *args)
{
	return nvme_io(args, nvme_cmd_write_uncor);
}

/**
 * nvme_verify() - Send an nvme verify command
 * @args:	&struct nvme_io_args argument structure
 *
 * The Verify command verifies integrity of stored information by reading data
 * and metadata, if applicable, for the LBAs indicated without transferring any
 * data or metadata to the host.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_verify(struct nvme_io_args *args)
{
	return nvme_io(args, nvme_cmd_verify);
}

/**
 * nvme_dsm() - Send an nvme data set management command
 * @args:	&struct nvme_dsm_args argument structure
 *
 * The Dataset Management command is used by the host to indicate attributes
 * for ranges of logical blocks. This includes attributes like frequency that
 * data is read or written, access size, and other information that may be used
 * to optimize performance and reliability, and may be used to
 * deallocate/unmap/trim those logical blocks.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_dsm(struct nvme_dsm_args *args);

/**
 * nvme_copy() - Copy command
 *
 * @args:	&struct nvme_copy_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_copy(struct nvme_copy_args *args);

/**
 * nvme_resv_acquire() - Send an nvme reservation acquire
 * @args:	&struct nvme_resv_acquire argument structure
 *
 * The Reservation Acquire command acquires a reservation on a namespace,
 * preempt a reservation held on a namespace, and abort a reservation held on a
 * namespace.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_resv_acquire(struct nvme_resv_acquire_args *args);

/**
 * nvme_resv_register() - Send an nvme reservation register
 * @args:	&struct nvme_resv_register_args argument structure
 *
 * The Reservation Register command registers, unregisters, or replaces a
 * reservation key.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_resv_register(struct nvme_resv_register_args *args);

/**
 * nvme_resv_release() - Send an nvme reservation release
 * @args:	&struct nvme_resv_release_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_resv_release(struct nvme_resv_release_args *args);

/**
 * nvme_resv_report() - Send an nvme reservation report
 * @args:	struct nvme_resv_report_args argument structure
 *
 * Returns a Reservation Status data structure to memory that describes the
 * registration and reservation status of a namespace. See the definition for
 * the returned structure, &struct nvme_reservation_status, for more details.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_resv_report(struct nvme_resv_report_args *args);

/**
 * nvme_zns_mgmt_send() - ZNS management send command
 * @args:	&struct nvme_zns_mgmt_send_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_zns_mgmt_send(struct nvme_zns_mgmt_send_args *args);


/**
 * nvme_zns_mgmt_recv() - ZNS management receive command
 * @args:	&struct nvme_zns_mgmt_recv_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_zns_mgmt_recv(struct nvme_zns_mgmt_recv_args *args);

/**
 * nvme_zns_report_zones() - Return the list of zones
 * @fd:		File descriptor of nvme device
 * @nsid:	Namespace ID
 * @slba:	Starting LBA
 * @opts:	Reporting options
 * @extended:	Extended report
 * @partial:	Partial report requested
 * @data_len:	Length of the data buffer
 * @data:	Userspace address of the report zones data
 * @timeout:	timeout in ms
 * @result:	The command completion result from CQE dword0
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
static inline int nvme_zns_report_zones(int fd, __u32 nsid, __u64 slba,
			  enum nvme_zns_report_options opts,
			  bool extended, bool partial,
			  __u32 data_len, void *data,
			  __u32 timeout, __u32 *result)
{
	struct nvme_zns_mgmt_recv_args args = {
		.slba = slba,
		.result = result,
		.data = data,
		.args_size = sizeof(args),
		.fd = fd,
		.timeout = timeout,
		.nsid = nsid,
		.zra = extended ? NVME_ZNS_ZRA_EXTENDED_REPORT_ZONES :
		NVME_ZNS_ZRA_REPORT_ZONES,
		.data_len = data_len,
		.zrasf = (__u16)opts,
		.zras_feat = partial,
	};

	return nvme_zns_mgmt_recv(&args);
}

/**
 * nvme_zns_append() - Append data to a zone
 * @args:	&struct nvme_zns_append_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_zns_append(struct nvme_zns_append_args *args);

/**
 * nvme_dim_send - Send a Discovery Information Management (DIM) command
 * @args:	&struct nvme_dim_args argument structure
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field) or -1 with errno set otherwise.
 */
int nvme_dim_send(struct nvme_dim_args *args);

#endif /* _LIBNVME_IOCTL_H */
