#ifndef __LIBNVME_SPEC_H__
#define __LIBNVME_SPEC_H__
#include <stdint.h>
#include <stddef.h>
#define NVME_GLOBAL_NS_TAG ((uint32_t)0xFFFFFFFF)
#define NVME_MAX_IO_QUEUES (65535)
#define NVME_ADMIN_QUEUE_MIN_ENTRIES 2
#define NVME_ADMIN_QUEUE_MAX_ENTRIES 4096
#define NVME_IO_QUEUE_MIN_ENTRIES 2
#define NVME_IO_QUEUE_MAX_ENTRIES 65536
#define NVME_MAX_NS 1024
#define NVME_SERIAL_NUMBER_CHARACTERS 20
#define NVME_MODEL_NUMBER_CHARACTERS 40
#define NVME_DATASET_MANAGEMENT_MAX_RANGES 256
#if __GNUC__ > 3
#ifdef __cplusplus
#define nvme_static_assert(cond, msg) static_assert(cond, msg)
#else
#define nvme_static_assert(cond, msg) _Static_assert(cond, msg)
#endif
#else
#define nvme_static_assert(cond, msg)
#endif
union nvme_cap_register {
uint64_t raw;
struct {
uint32_t mqes : 16;
uint32_t cqr : 1;
uint32_t ams : 2;
uint32_t reserved1 : 5;
uint32_t to : 8;
uint32_t dstrd : 4;
uint32_t nssrs : 1;
uint32_t css_nvm : 1;
uint32_t css_reserved : 3;
uint32_t reserved2 : 7;
uint32_t mpsmin : 4;
uint32_t mpsmax : 4;
uint32_t reserved3 : 8;
} bits;
};
nvme_static_assert(sizeof(union nvme_cap_register) == 8, "Incorrect size");
union nvme_cc_register {
uint32_t raw;
struct {
uint32_t en : 1;
uint32_t reserved1 : 3;
uint32_t css : 3;
uint32_t mps : 4;
uint32_t ams : 3;
uint32_t shn : 2;
uint32_t iosqes : 4;
uint32_t iocqes : 4;
uint32_t reserved2 : 8;
} bits;
};
nvme_static_assert(sizeof(union nvme_cc_register) == 4, "Incorrect size");
enum nvme_shn_value {
NVME_SHN_NORMAL = 0x1,
NVME_SHN_ABRUPT = 0x2,
};
union nvme_csts_register {
uint32_t raw;
struct {
uint32_t rdy : 1;
uint32_t cfs : 1;
uint32_t shst : 2;
uint32_t reserved1 : 28;
} bits;
};
nvme_static_assert(sizeof(union nvme_csts_register) == 4, "Incorrect size");
enum nvme_shst_value {
NVME_SHST_NORMAL = 0x0,
NVME_SHST_OCCURRING = 0x1,
NVME_SHST_COMPLETE = 0x2,
};
union nvme_aqa_register {
uint32_t raw;
struct {
uint32_t asqs : 12;
uint32_t reserved1 : 4;
uint32_t acqs : 12;
uint32_t reserved2 : 4;
} bits;
};
nvme_static_assert(sizeof(union nvme_aqa_register) == 4, "Incorrect size");
union nvme_vs_register {
uint32_t raw;
struct {
uint32_t ter : 8;
uint32_t mnr : 8;
uint32_t mjr : 16;
} bits;
};
nvme_static_assert(sizeof(union nvme_vs_register) == 4, "Incorrect size");
#define NVME_VERSION(mjr, mnr, ter) \
(((uint32_t)(mjr) << 16) | \
((uint32_t)(mnr) << 8) | \
(uint32_t)(ter))
nvme_static_assert(NVME_VERSION(1, 0, 0) == 0x00010000, "version macro error");
nvme_static_assert(NVME_VERSION(1, 2, 1) == 0x00010201, "version macro error");
union nvme_cmbloc_register {
uint32_t raw;
struct {
uint32_t bir : 3;
uint32_t reserved1 : 9;
uint32_t ofst : 20;
} bits;
};
nvme_static_assert(sizeof(union nvme_cmbloc_register) == 4, "Incorrect size");
union nvme_cmbsz_register {
uint32_t raw;
struct {
uint32_t sqs : 1;
uint32_t cqs : 1;
uint32_t lists : 1;
uint32_t rds : 1;
uint32_t wds : 1;
uint32_t reserved1 : 3;
uint32_t szu : 4;
uint32_t sz : 20;
} bits;
};
nvme_static_assert(sizeof(union nvme_cmbsz_register) == 4, "Incorrect size");
struct nvme_registers {
union nvme_cap_register cap;
union nvme_vs_register vs;
uint32_t intms;
uint32_t intmc;
union nvme_cc_register cc;
uint32_t reserved1;
union nvme_csts_register csts;
uint32_t nssr;
union nvme_aqa_register aqa;
uint64_t asq;
uint64_t acq;
union nvme_cmbloc_register cmbloc;
union nvme_cmbsz_register cmbsz;
uint32_t reserved3[0x3f0];
struct {
uint32_t sq_tdbl;
uint32_t cq_hdbl;
} doorbell[1];
};
#ifndef offsetof
#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
#endif
nvme_static_assert(0x00 == offsetof(struct nvme_registers, cap),
"Incorrect register offset");
nvme_static_assert(0x08 == offsetof(struct nvme_registers, vs),
"Incorrect register offset");
nvme_static_assert(0x0C == offsetof(struct nvme_registers, intms),
"Incorrect register offset");
nvme_static_assert(0x10 == offsetof(struct nvme_registers, intmc),
"Incorrect register offset");
nvme_static_assert(0x14 == offsetof(struct nvme_registers, cc),
"Incorrect register offset");
nvme_static_assert(0x1C == offsetof(struct nvme_registers, csts),
"Incorrect register offset");
nvme_static_assert(0x20 == offsetof(struct nvme_registers, nssr),
"Incorrect register offset");
nvme_static_assert(0x24 == offsetof(struct nvme_registers, aqa),
"Incorrect register offset");
nvme_static_assert(0x28 == offsetof(struct nvme_registers, asq),
"Incorrect register offset");
nvme_static_assert(0x30 == offsetof(struct nvme_registers, acq),
"Incorrect register offset");
nvme_static_assert(0x38 == offsetof(struct nvme_registers, cmbloc),
"Incorrect register offset");
nvme_static_assert(0x3C == offsetof(struct nvme_registers, cmbsz),
"Incorrect register offset");
enum nvme_sgl_descriptor_type {
NVME_SGL_TYPE_DATA_BLOCK = 0x0,
NVME_SGL_TYPE_BIT_BUCKET = 0x1,
NVME_SGL_TYPE_SEGMENT = 0x2,
NVME_SGL_TYPE_LAST_SEGMENT = 0x3,
NVME_SGL_TYPE_KEYED_DATA_BLOCK = 0x4,
NVME_SGL_TYPE_VENDOR_SPECIFIC = 0xF
};
enum nvme_sgl_descriptor_subtype {
NVME_SGL_SUBTYPE_ADDRESS = 0x0,
NVME_SGL_SUBTYPE_OFFSET = 0x1,
};
struct __attribute__((packed)) nvme_sgl_descriptor {
uint64_t address;
union {
struct {
uint8_t reserved[7];
uint8_t subtype : 4;
uint8_t type : 4;
} generic;
struct {
uint32_t length;
uint8_t reserved[3];
uint8_t subtype : 4;
uint8_t type : 4;
} unkeyed;
struct {
uint64_t length : 24;
uint64_t key : 32;
uint64_t subtype : 4;
uint64_t type : 4;
} keyed;
};
};
nvme_static_assert(sizeof(struct nvme_sgl_descriptor) == 16,
"Incorrect size");
enum nvme_psdt_value {
NVME_PSDT_PRP = 0x0,
NVME_PSDT_SGL_MPTR_CONTIG = 0x1,
NVME_PSDT_SGL_MPTR_SGL = 0x2,
NVME_PSDT_RESERVED = 0x3
};
enum nvme_qprio {
NVME_QPRIO_URGENT = 0x0,
NVME_QPRIO_HIGH = 0x1,
NVME_QPRIO_MEDIUM = 0x2,
NVME_QPRIO_LOW = 0x3
};
enum nvme_cap_ams {
NVME_CAP_AMS_WRR = 0x1,
NVME_CAP_AMS_VS = 0x2,
};
enum nvme_cc_ams {
NVME_CC_AMS_RR = 0x0,
NVME_CC_AMS_WRR = 0x1,
NVME_CC_AMS_VS = 0x7,
};
struct nvme_cmd {
uint16_t opc : 8;
uint16_t fuse : 2;
uint16_t rsvd1 : 4;
uint16_t psdt : 2;
uint16_t cid;
uint32_t nsid;
uint32_t rsvd2;
uint32_t rsvd3;
uint64_t mptr;
union {
struct {
uint64_t prp1;
uint64_t prp2;
} prp;
struct nvme_sgl_descriptor sgl1;
} dptr;
uint32_t cdw10;
uint32_t cdw11;
uint32_t cdw12;
uint32_t cdw13;
uint32_t cdw14;
uint32_t cdw15;
};
nvme_static_assert(sizeof(struct nvme_cmd) == 64, "Incorrect size");
struct nvme_status {
uint16_t p : 1;
uint16_t sc : 8;
uint16_t sct : 3;
uint16_t rsvd2 : 2;
uint16_t m : 1;
uint16_t dnr : 1;
};
nvme_static_assert(sizeof(struct nvme_status) == 2, "Incorrect size");
struct nvme_cpl {
uint32_t cdw0;
uint32_t rsvd1;
uint16_t sqhd;
uint16_t sqid;
uint16_t cid;
struct nvme_status status;
};
nvme_static_assert(sizeof(struct nvme_cpl) == 16, "Incorrect size");
struct nvme_dsm_range {
uint32_t attributes;
uint32_t length;
uint64_t starting_lba;
};
nvme_static_assert(sizeof(struct nvme_dsm_range) == 16, "Incorrect size");
enum nvme_status_code_type {
NVME_SCT_GENERIC = 0x0,
NVME_SCT_COMMAND_SPECIFIC = 0x1,
NVME_SCT_MEDIA_ERROR = 0x2,
NVME_SCT_VENDOR_SPECIFIC = 0x7,
};
enum nvme_generic_command_status_code {
NVME_SC_SUCCESS = 0x00,
NVME_SC_INVALID_OPCODE = 0x01,
NVME_SC_INVALID_FIELD = 0x02,
NVME_SC_COMMAND_ID_CONFLICT = 0x03,
NVME_SC_DATA_TRANSFER_ERROR = 0x04,
NVME_SC_ABORTED_POWER_LOSS = 0x05,
NVME_SC_INTERNAL_DEVICE_ERROR = 0x06,
NVME_SC_ABORTED_BY_REQUEST = 0x07,
NVME_SC_ABORTED_SQ_DELETION = 0x08,
NVME_SC_ABORTED_FAILED_FUSED = 0x09,
NVME_SC_ABORTED_MISSING_FUSED = 0x0a,
NVME_SC_INVALID_NAMESPACE_OR_FORMAT = 0x0b,
NVME_SC_COMMAND_SEQUENCE_ERROR = 0x0c,
NVME_SC_INVALID_SGL_SEG_DESCRIPTOR = 0x0d,
NVME_SC_INVALID_NUM_SGL_DESCIRPTORS = 0x0e,
NVME_SC_DATA_SGL_LENGTH_INVALID = 0x0f,
NVME_SC_METADATA_SGL_LENGTH_INVALID = 0x10,
NVME_SC_SGL_DESCRIPTOR_TYPE_INVALID = 0x11,
NVME_SC_INVALID_CONTROLLER_MEM_BUF = 0x12,
NVME_SC_INVALID_PRP_OFFSET = 0x13,
NVME_SC_ATOMIC_WRITE_UNIT_EXCEEDED = 0x14,
NVME_SC_INVALID_SGL_OFFSET = 0x16,
NVME_SC_INVALID_SGL_SUBTYPE = 0x17,
NVME_SC_HOSTID_INCONSISTENT_FORMAT = 0x18,
NVME_SC_KEEP_ALIVE_EXPIRED = 0x19,
NVME_SC_KEEP_ALIVE_INVALID = 0x1a,
NVME_SC_LBA_OUT_OF_RANGE = 0x80,
NVME_SC_CAPACITY_EXCEEDED = 0x81,
NVME_SC_NAMESPACE_NOT_READY = 0x82,
NVME_SC_RESERVATION_CONFLICT = 0x83,
NVME_SC_FORMAT_IN_PROGRESS = 0x84,
};
enum nvme_command_specific_status_code {
NVME_SC_COMPLETION_QUEUE_INVALID = 0x00,
NVME_SC_INVALID_QUEUE_IDENTIFIER = 0x01,
NVME_SC_MAXIMUM_QUEUE_SIZE_EXCEEDED = 0x02,
NVME_SC_ABORT_COMMAND_LIMIT_EXCEEDED = 0x03,
NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED = 0x05,
NVME_SC_INVALID_FIRMWARE_SLOT = 0x06,
NVME_SC_INVALID_FIRMWARE_IMAGE = 0x07,
NVME_SC_INVALID_INTERRUPT_VECTOR = 0x08,
NVME_SC_INVALID_LOG_PAGE = 0x09,
NVME_SC_INVALID_FORMAT = 0x0a,
NVME_SC_FIRMWARE_REQ_CONVENTIONAL_RESET = 0x0b,
NVME_SC_INVALID_QUEUE_DELETION = 0x0c,
NVME_SC_FEATURE_ID_NOT_SAVEABLE = 0x0d,
NVME_SC_FEATURE_NOT_CHANGEABLE = 0x0e,
NVME_SC_FEATURE_NOT_NAMESPACE_SPECIFIC = 0x0f,
NVME_SC_FIRMWARE_REQ_NVM_RESET = 0x10,
NVME_SC_FIRMWARE_REQ_RESET = 0x11,
NVME_SC_FIRMWARE_REQ_MAX_TIME_VIOLATION = 0x12,
NVME_SC_FIRMWARE_ACTIVATION_PROHIBITED = 0x13,
NVME_SC_OVERLAPPING_RANGE = 0x14,
NVME_SC_NAMESPACE_INSUFFICIENT_CAPACITY = 0x15,
NVME_SC_NAMESPACE_ID_UNAVAILABLE = 0x16,
NVME_SC_NAMESPACE_ALREADY_ATTACHED = 0x18,
NVME_SC_NAMESPACE_IS_PRIVATE = 0x19,
NVME_SC_NAMESPACE_NOT_ATTACHED = 0x1a,
NVME_SC_THINPROVISIONING_NOT_SUPPORTED = 0x1b,
NVME_SC_CONTROLLER_LIST_INVALID = 0x1c,
NVME_SC_CONFLICTING_ATTRIBUTES = 0x80,
NVME_SC_INVALID_PROTECTION_INFO = 0x81,
NVME_SC_ATTEMPTED_WRITE_TO_RO_PAGE = 0x82,
};
enum nvme_media_error_status_code {
NVME_SC_WRITE_FAULTS = 0x80,
NVME_SC_UNRECOVERED_READ_ERROR = 0x81,
NVME_SC_GUARD_CHECK_ERROR = 0x82,
NVME_SC_APPLICATION_TAG_CHECK_ERROR = 0x83,
NVME_SC_REFERENCE_TAG_CHECK_ERROR = 0x84,
NVME_SC_COMPARE_FAILURE = 0x85,
NVME_SC_ACCESS_DENIED = 0x86,
NVME_SC_DEALLOCATED_OR_UNWRITTEN_BLOCK = 0x87,
};
enum nvme_admin_opcode {
NVME_OPC_DELETE_IO_SQ = 0x00,
NVME_OPC_CREATE_IO_SQ = 0x01,
NVME_OPC_GET_LOG_PAGE = 0x02,
NVME_OPC_DELETE_IO_CQ = 0x04,
NVME_OPC_CREATE_IO_CQ = 0x05,
NVME_OPC_IDENTIFY = 0x06,
NVME_OPC_ABORT = 0x08,
NVME_OPC_SET_FEATURES = 0x09,
NVME_OPC_GET_FEATURES = 0x0a,
NVME_OPC_ASYNC_EVENT_REQUEST = 0x0c,
NVME_OPC_NS_MANAGEMENT = 0x0d,
NVME_OPC_FIRMWARE_COMMIT = 0x10,
NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD = 0x11,
NVME_OPC_NS_ATTACHMENT = 0x15,
NVME_OPC_KEEP_ALIVE = 0x18,
NVME_OPC_FORMAT_NVM = 0x80,
NVME_OPC_SECURITY_SEND = 0x81,
NVME_OPC_SECURITY_RECEIVE = 0x82,
};
enum nvme_nvm_opcode {
NVME_OPC_FLUSH = 0x00,
NVME_OPC_WRITE = 0x01,
NVME_OPC_READ = 0x02,
NVME_OPC_WRITE_UNCORRECTABLE = 0x04,
NVME_OPC_COMPARE = 0x05,
NVME_OPC_WRITE_ZEROES = 0x08,
NVME_OPC_DATASET_MANAGEMENT = 0x09,
NVME_OPC_RESERVATION_REGISTER = 0x0d,
NVME_OPC_RESERVATION_REPORT = 0x0e,
NVME_OPC_RESERVATION_ACQUIRE = 0x11,
NVME_OPC_RESERVATION_RELEASE = 0x15,
};
enum nvme_data_transfer {
NVME_DATA_NONE = 0,
NVME_DATA_HOST_TO_CONTROLLER = 1,
NVME_DATA_CONTROLLER_TO_HOST = 2,
NVME_DATA_BIDIRECTIONAL = 3
};
static inline enum nvme_data_transfer nvme_opc_get_data_transfer(uint8_t opc)
{
return (enum nvme_data_transfer)(opc & 3);
}
enum nvme_feat {
NVME_FEAT_ARBITRATION = 0x01,
NVME_FEAT_POWER_MANAGEMENT = 0x02,
NVME_FEAT_LBA_RANGE_TYPE = 0x03,
NVME_FEAT_TEMPERATURE_THRESHOLD = 0x04,
NVME_FEAT_ERROR_RECOVERY = 0x05,
NVME_FEAT_VOLATILE_WRITE_CACHE = 0x06,
NVME_FEAT_NUMBER_OF_QUEUES = 0x07,
NVME_FEAT_INTERRUPT_COALESCING = 0x08,
NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION = 0x09,
NVME_FEAT_WRITE_ATOMICITY = 0x0A,
NVME_FEAT_ASYNC_EVENT_CONFIGURATION = 0x0B,
NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION = 0x0C,
NVME_FEAT_HOST_MEM_BUFFER = 0x0D,
NVME_FEAT_KEEP_ALIVE_TIMER = 0x0F,
NVME_FEAT_SOFTWARE_PROGRESS_MARKER = 0x80,
NVME_FEAT_HOST_IDENTIFIER = 0x81,
NVME_FEAT_HOST_RESERVE_MASK = 0x82,
NVME_FEAT_HOST_RESERVE_PERSIST = 0x83,
};
enum nvme_feat_sel {
NVME_FEAT_CURRENT = 0x0,
NVME_FEAT_DEFAULT = 0x1,
NVME_FEAT_SAVED = 0x2,
NVME_FEAT_SUPPORTED = 0x3,
};
enum nvme_dsm_attribute {
NVME_DSM_ATTR_INTEGRAL_READ = 0x1,
NVME_DSM_ATTR_INTEGRAL_WRITE = 0x2,
NVME_DSM_ATTR_DEALLOCATE = 0x4,
};
struct nvme_power_state {
uint16_t mp;
uint8_t reserved1;
uint8_t mxps : 1;
uint8_t nops : 1;
uint8_t reserved2 : 6;
uint32_t enlat;
uint32_t exlat;
uint8_t rrt : 5;
uint8_t reserved3 : 3;
uint8_t rrl : 5;
uint8_t reserved4 : 3;
uint8_t rwt : 5;
uint8_t reserved5 : 3;
uint8_t rwl : 5;
uint8_t reserved6 : 3;
uint16_t idlp;
uint8_t reserved7 : 6;
uint8_t ips : 2;
uint8_t reserved8;
uint16_t actp;
uint8_t apw : 3;
uint8_t reserved9 : 3;
uint8_t aps : 2;
uint8_t reserved10[9];
};
nvme_static_assert(sizeof(struct nvme_power_state) == 32, "Incorrect size");
enum nvme_identify_cns {
NVME_IDENTIFY_NS = 0x00,
NVME_IDENTIFY_CTRLR = 0x01,
NVME_IDENTIFY_ACTIVE_NS_LIST = 0x02,
NVME_IDENTIFY_ALLOCATED_NS_LIST = 0x10,
NVME_IDENTIFY_NS_ALLOCATED = 0x11,
NVME_IDENTIFY_NS_ATTACHED_CTRLR_LIST = 0x12,
NVME_IDENTIFY_CTRLR_LIST = 0x13,
};
enum nvmf_ctrlr_model {
NVMF_CTRLR_MODEL_DYNAMIC = 0,
NVMF_CTRLR_MODEL_STATIC = 1,
};
struct __attribute__((packed)) nvme_ctrlr_data {
uint16_t vid;
uint16_t ssvid;
int8_t sn[NVME_SERIAL_NUMBER_CHARACTERS];
int8_t mn[NVME_MODEL_NUMBER_CHARACTERS];
uint8_t fr[8];
uint8_t rab;
uint8_t ieee[3];
struct {
uint8_t multi_port : 1;
uint8_t multi_host : 1;
uint8_t sr_iov : 1;
uint8_t reserved : 5;
} cmic;
uint8_t mdts;
uint16_t cntlid;
union nvme_vs_register ver;
uint32_t rtd3r;
uint32_t rtd3e;
uint32_t oaes;
struct {
uint32_t host_id_exhid_supported: 1;
uint32_t reserved: 31;
} ctratt;
uint8_t reserved1[156];
struct {
uint16_t security : 1;
uint16_t format : 1;
uint16_t firmware : 1;
uint16_t ns_manage : 1;
uint16_t oacs_rsvd : 12;
} oacs;
uint8_t acl;
uint8_t aerl;
struct {
uint8_t slot1_ro : 1;
uint8_t num_slots : 3;
uint8_t activation_without_reset : 1;
uint8_t frmw_rsvd : 3;
} frmw;
struct {
uint8_t ns_smart : 1;
uint8_t celp : 1;
uint8_t edlp : 1;
uint8_t lpa_rsvd : 5;
} lpa;
uint8_t elpe;
uint8_t npss;
struct {
uint8_t spec_format : 1;
uint8_t avscc_rsvd : 7;
} avscc;
struct {
uint8_t supported : 1;
uint8_t apsta_rsvd : 7;
} apsta;
uint16_t wctemp;
uint16_t cctemp;
uint16_t mtfa;
uint32_t hmpre;
uint32_t hmmin;
uint64_t tnvmcap[2];
uint64_t unvmcap[2];
struct {
uint8_t num_rpmb_units : 3;
uint8_t auth_method : 3;
uint8_t reserved1 : 2;
uint8_t reserved2;
uint8_t total_size;
uint8_t access_size;
} rpmbs;
uint8_t reserved2[4];
uint16_t kas;
uint8_t reserved3[190];
struct {
uint8_t min : 4;
uint8_t max : 4;
} sqes;
struct {
uint8_t min : 4;
uint8_t max : 4;
} cqes;
uint16_t maxcmd;
uint32_t nn;
struct {
uint16_t compare : 1;
uint16_t write_unc : 1;
uint16_t dsm : 1;
uint16_t write_zeroes : 1;
uint16_t set_features_save : 1;
uint16_t reservations : 1;
uint16_t reserved : 10;
} oncs;
uint16_t fuses;
struct {
uint8_t format_all_ns : 1;
uint8_t erase_all_ns : 1;
uint8_t crypto_erase_supported : 1;
uint8_t reserved : 5;
} fna;
struct {
uint8_t present : 1;
uint8_t reserved : 7;
} vwc;
uint16_t awun;
uint16_t awupf;
uint8_t nvscc;
uint8_t reserved531;
uint16_t acwu;
uint16_t reserved534;
struct {
uint32_t supported : 1;
uint32_t reserved0 : 1;
uint32_t keyed_sgl : 1;
uint32_t reserved1 : 13;
uint32_t bit_bucket_descriptor : 1;
uint32_t metadata_pointer : 1;
uint32_t oversized_sgl : 1;
uint32_t metadata_address : 1;
uint32_t sgl_offset : 1;
uint32_t reserved2 : 11;
} sgls;
uint8_t reserved4[228];
uint8_t subnqn[256];
uint8_t reserved5[768];
struct {
uint32_t ioccsz;
uint32_t iorcsz;
uint16_t icdoff;
struct {
uint8_t ctrlr_model : 1;
uint8_t reserved : 7;
} ctrattr;
uint8_t msdbd;
uint8_t reserved[244];
} nvmf_specific;
struct nvme_power_state psd[32];
uint8_t vs[1024];
};
nvme_static_assert(sizeof(struct nvme_ctrlr_data) == 4096, "Incorrect size");
struct nvme_ns_data {
uint64_t nsze;
uint64_t ncap;
uint64_t nuse;
struct {
uint8_t thin_prov : 1;
uint8_t reserved1 : 7;
} nsfeat;
uint8_t nlbaf;
struct {
uint8_t format : 4;
uint8_t extended : 1;
uint8_t msb_format: 2;
uint8_t reserved2 : 1;
} flbas;
struct {
uint8_t extended : 1;
uint8_t pointer : 1;
uint8_t reserved3 : 6;
} mc;
struct {
uint8_t pit1 : 1;
uint8_t pit2 : 1;
uint8_t pit3 : 1;
uint8_t md_start : 1;
uint8_t md_end : 1;
} dpc;
struct {
uint8_t pit : 3;
uint8_t md_start : 1;
uint8_t reserved4 : 4;
} dps;
struct {
uint8_t can_share : 1;
uint8_t reserved : 7;
} nmic;
union {
struct {
uint8_t persist : 1;
uint8_t write_exclusive : 1;
uint8_t exclusive_access : 1;
uint8_t write_exclusive_reg_only : 1;
uint8_t exclusive_access_reg_only : 1;
uint8_t write_exclusive_all_reg : 1;
uint8_t exclusive_access_all_reg : 1;
uint8_t reserved : 1;
} rescap;
uint8_t raw;
} nsrescap;
struct {
uint8_t percentage_remaining : 7;
uint8_t fpi_supported : 1;
} fpi;
uint8_t reserved33;
uint16_t nawun;
uint16_t nawupf;
uint16_t nacwu;
uint16_t nabsn;
uint16_t nabo;
uint16_t nabspf;
uint16_t reserved46;
uint64_t nvmcap[2];
uint8_t reserved64[40];
uint8_t nguid[16];
uint64_t eui64;
struct {
uint32_t ms : 16;
uint32_t lbads : 8;
uint32_t rp : 2;
uint32_t reserved6 : 6;
} lbaf[64];
uint8_t vendor_specific[3712];
};
nvme_static_assert(sizeof(struct nvme_ns_data) == 4096, "Incorrect size");
enum nvme_reservation_type {
NVME_RESERVE_WRITE_EXCLUSIVE = 0x1,
NVME_RESERVE_EXCLUSIVE_ACCESS = 0x2,
NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY = 0x3,
NVME_RESERVE_EXCLUSIVE_ACCESS_REG_ONLY = 0x4,
NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS = 0x5,
NVME_RESERVE_EXCLUSIVE_ACCESS_ALL_REGS = 0x6,
};
struct nvme_reservation_acquire_data {
uint64_t crkey;
uint64_t prkey;
};
nvme_static_assert(sizeof(struct nvme_reservation_acquire_data) == 16,
"Incorrect size");
enum nvme_reservation_acquire_action {
NVME_RESERVE_ACQUIRE = 0x0,
NVME_RESERVE_PREEMPT = 0x1,
NVME_RESERVE_PREEMPT_ABORT = 0x2,
};
struct __attribute__((packed)) nvme_reservation_status_data {
uint32_t generation;
uint8_t type;
uint16_t nr_regctl;
uint16_t reserved1;
uint8_t ptpl_state;
uint8_t reserved[14];
};
nvme_static_assert(sizeof(struct nvme_reservation_status_data) == 24,
"Incorrect size");
struct __attribute__((packed)) nvme_reservation_ctrlr_data {
uint16_t ctrlr_id;
struct {
uint8_t status : 1;
uint8_t reserved1 : 7;
} rcsts;
uint8_t reserved2[5];
uint64_t host_id;
uint64_t key;
};
nvme_static_assert(sizeof(struct nvme_reservation_ctrlr_data) == 24,
"Incorrect size");
enum nvme_reservation_register_cptpl {
NVME_RESERVE_PTPL_NO_CHANGES = 0x0,
NVME_RESERVE_PTPL_CLEAR_POWER_ON = 0x2,
NVME_RESERVE_PTPL_PERSIST_POWER_LOSS = 0x3,
};
enum nvme_reservation_register_action {
NVME_RESERVE_REGISTER_KEY = 0x0,
NVME_RESERVE_UNREGISTER_KEY = 0x1,
NVME_RESERVE_REPLACE_KEY = 0x2,
};
struct nvme_reservation_register_data {
uint64_t crkey;
uint64_t nrkey;
};
nvme_static_assert(sizeof(struct nvme_reservation_register_data) == 16,
"Incorrect size");
struct nvme_reservation_key_data {
uint64_t crkey;
};
nvme_static_assert(sizeof(struct nvme_reservation_key_data) == 8,
"Incorrect size");
enum nvme_reservation_release_action {
NVME_RESERVE_RELEASE = 0x0,
NVME_RESERVE_CLEAR = 0x1,
};
enum nvme_log_page {
NVME_LOG_ERROR = 0x01,
NVME_LOG_HEALTH_INFORMATION = 0x02,
NVME_LOG_FIRMWARE_SLOT = 0x03,
NVME_LOG_CHANGED_NS_LIST = 0x04,
NVME_LOG_COMMAND_EFFECTS_LOG = 0x05,
NVME_LOG_DISCOVERY = 0x70,
NVME_LOG_RESERVATION_NOTIFICATION = 0x80,
};
struct nvme_error_information_entry {
uint64_t error_count;
uint16_t sqid;
uint16_t cid;
struct nvme_status status;
uint16_t error_location;
uint64_t lba;
uint32_t nsid;
uint8_t vendor_specific;
uint8_t reserved[35];
};
nvme_static_assert(sizeof(struct nvme_error_information_entry) == 64,
"Incorrect size");
union nvme_critical_warning_state {
uint8_t raw;
struct {
uint8_t available_spare : 1;
uint8_t temperature : 1;
uint8_t device_reliability : 1;
uint8_t read_only : 1;
uint8_t volatile_memory_backup : 1;
uint8_t reserved : 3;
} bits;
};
nvme_static_assert(sizeof(union nvme_critical_warning_state) == 1,
"Incorrect size");
struct __attribute__((packed)) nvme_health_information_page {
union nvme_critical_warning_state critical_warning;
uint16_t temperature;
uint8_t available_spare;
uint8_t available_spare_threshold;
uint8_t percentage_used;
uint8_t reserved[26];
uint64_t data_units_read[2];
uint64_t data_units_written[2];
uint64_t host_read_commands[2];
uint64_t host_write_commands[2];
uint64_t controller_busy_time[2];
uint64_t power_cycles[2];
uint64_t power_on_hours[2];
uint64_t unsafe_shutdowns[2];
uint64_t media_errors[2];
uint64_t num_error_info_log_entries[2];
uint8_t reserved2[320];
};
nvme_static_assert(sizeof(struct nvme_health_information_page) == 512,
"Incorrect size");
struct nvme_firmware_page {
struct {
uint8_t slot : 3;
uint8_t reserved : 5;
} afi;
uint8_t reserved[7];
uint64_t revision[7];
uint8_t reserved2[448];
};
nvme_static_assert(sizeof(struct nvme_firmware_page) == 512,
"Incorrect size");
enum nvme_ns_attach_type {
NVME_NS_CTRLR_ATTACH = 0x0,
NVME_NS_CTRLR_DETACH = 0x1,
};
enum nvme_ns_management_type {
NVME_NS_MANAGEMENT_CREATE = 0x0,
NVME_NS_MANAGEMENT_DELETE = 0x1,
};
struct nvme_ns_list {
uint32_t ns_list[NVME_MAX_NS];
};
nvme_static_assert(sizeof(struct nvme_ns_list) == 4096, "Incorrect size");
struct nvme_ctrlr_list {
uint16_t ctrlr_count;
uint16_t ctrlr_list[2047];
};
nvme_static_assert(sizeof(struct nvme_ctrlr_list) == 4096, "Incorrect size");
enum nvme_secure_erase_setting {
NVME_FMT_NVM_SES_NO_SECURE_ERASE = 0x0,
NVME_FMT_NVM_SES_USER_DATA_ERASE = 0x1,
NVME_FMT_NVM_SES_CRYPTO_ERASE = 0x2,
};
enum nvme_pi_location {
NVME_FMT_NVM_PROTECTION_AT_TAIL = 0x0,
NVME_FMT_NVM_PROTECTION_AT_HEAD = 0x1,
};
enum nvme_pi_type {
NVME_FMT_NVM_PROTECTION_DISABLE = 0x0,
NVME_FMT_NVM_PROTECTION_TYPE1 = 0x1,
NVME_FMT_NVM_PROTECTION_TYPE2 = 0x2,
NVME_FMT_NVM_PROTECTION_TYPE3 = 0x3,
};
enum nvme_metadata_setting {
NVME_FMT_NVM_METADATA_TRANSFER_AS_BUFFER = 0x0,
NVME_FMT_NVM_METADATA_TRANSFER_AS_LBA = 0x1,
};
struct nvme_format {
uint32_t lbaf : 4;
uint32_t ms : 1;
uint32_t pi : 3;
uint32_t pil : 1;
uint32_t ses : 3;
uint32_t lbafu : 2;
uint32_t reserved : 18;
};
nvme_static_assert(sizeof(struct nvme_format) == 4, "Incorrect size");
struct nvme_protection_info {
uint16_t guard;
uint16_t app_tag;
uint32_t ref_tag;
};
nvme_static_assert(sizeof(struct nvme_protection_info) == 8, "Incorrect size");
enum nvme_fw_commit_action {
NVME_FW_COMMIT_REPLACE_IMG = 0x0,
NVME_FW_COMMIT_REPLACE_AND_ENABLE_IMG = 0x1,
NVME_FW_COMMIT_ENABLE_IMG = 0x2,
NVME_FW_COMMIT_RUN_IMG = 0x3,
};
struct nvme_fw_commit {
uint32_t fs : 3;
uint32_t ca : 3;
uint32_t reserved : 26;
};
nvme_static_assert(sizeof(struct nvme_fw_commit) == 4, "Incorrect size");
#define nvme_cpl_is_error(cpl) \
((cpl)->status.sc != 0 || (cpl)->status.sct != 0)
#define NVME_IO_FLAGS_PRCHK_REFTAG (1U << 26)
#define NVME_IO_FLAGS_PRCHK_APPTAG (1U << 27)
#define NVME_IO_FLAGS_PRCHK_GUARD (1U << 28)
#define NVME_IO_FLAGS_PRACT (1U << 29)
#define NVME_IO_FLAGS_FORCE_UNIT_ACCESS (1U << 30)
#define NVME_IO_FLAGS_LIMITED_RETRY (1U << 31)
#endif