|
|
@@ -16,6 +16,78 @@
|
|
|
#define _LINUX_NVME_H
|
|
|
|
|
|
#include <linux/types.h>
|
|
|
+#include <linux/uuid.h>
|
|
|
+
|
|
|
+/* NQN names in commands fields specified one size */
|
|
|
+#define NVMF_NQN_FIELD_LEN 256
|
|
|
+
|
|
|
+/* However the max length of a qualified name is another size */
|
|
|
+#define NVMF_NQN_SIZE 223
|
|
|
+
|
|
|
+#define NVMF_TRSVCID_SIZE 32
|
|
|
+#define NVMF_TRADDR_SIZE 256
|
|
|
+#define NVMF_TSAS_SIZE 256
|
|
|
+
|
|
|
+#define NVME_DISC_SUBSYS_NAME "nqn.2014-08.org.nvmexpress.discovery"
|
|
|
+
|
|
|
+#define NVME_RDMA_IP_PORT 4420
|
|
|
+
|
|
|
+enum nvme_subsys_type {
|
|
|
+ NVME_NQN_DISC = 1, /* Discovery type target subsystem */
|
|
|
+ NVME_NQN_NVME = 2, /* NVME type target subsystem */
|
|
|
+};
|
|
|
+
|
|
|
+/* Address Family codes for Discovery Log Page entry ADRFAM field */
|
|
|
+enum {
|
|
|
+ NVMF_ADDR_FAMILY_PCI = 0, /* PCIe */
|
|
|
+ NVMF_ADDR_FAMILY_IP4 = 1, /* IP4 */
|
|
|
+ NVMF_ADDR_FAMILY_IP6 = 2, /* IP6 */
|
|
|
+ NVMF_ADDR_FAMILY_IB = 3, /* InfiniBand */
|
|
|
+ NVMF_ADDR_FAMILY_FC = 4, /* Fibre Channel */
|
|
|
+};
|
|
|
+
|
|
|
+/* Transport Type codes for Discovery Log Page entry TRTYPE field */
|
|
|
+enum {
|
|
|
+ NVMF_TRTYPE_RDMA = 1, /* RDMA */
|
|
|
+ NVMF_TRTYPE_FC = 2, /* Fibre Channel */
|
|
|
+ NVMF_TRTYPE_LOOP = 254, /* Reserved for host usage */
|
|
|
+ NVMF_TRTYPE_MAX,
|
|
|
+};
|
|
|
+
|
|
|
+/* Transport Requirements codes for Discovery Log Page entry TREQ field */
|
|
|
+enum {
|
|
|
+ NVMF_TREQ_NOT_SPECIFIED = 0, /* Not specified */
|
|
|
+ NVMF_TREQ_REQUIRED = 1, /* Required */
|
|
|
+ NVMF_TREQ_NOT_REQUIRED = 2, /* Not Required */
|
|
|
+};
|
|
|
+
|
|
|
+/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
|
|
|
+ * RDMA_QPTYPE field
|
|
|
+ */
|
|
|
+enum {
|
|
|
+ NVMF_RDMA_QPTYPE_CONNECTED = 0, /* Reliable Connected */
|
|
|
+ NVMF_RDMA_QPTYPE_DATAGRAM = 1, /* Reliable Datagram */
|
|
|
+};
|
|
|
+
|
|
|
+/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
|
|
|
+ * RDMA_QPTYPE field
|
|
|
+ */
|
|
|
+enum {
|
|
|
+ NVMF_RDMA_PRTYPE_NOT_SPECIFIED = 0, /* No Provider Specified */
|
|
|
+ NVMF_RDMA_PRTYPE_IB = 1, /* InfiniBand */
|
|
|
+ NVMF_RDMA_PRTYPE_ROCE = 2, /* InfiniBand RoCE */
|
|
|
+ NVMF_RDMA_PRTYPE_ROCEV2 = 3, /* InfiniBand RoCEV2 */
|
|
|
+ NVMF_RDMA_PRTYPE_IWARP = 4, /* IWARP */
|
|
|
+};
|
|
|
+
|
|
|
+/* RDMA Connection Management Service Type codes for Discovery Log Page
|
|
|
+ * entry TSAS RDMA_CMS field
|
|
|
+ */
|
|
|
+enum {
|
|
|
+ NVMF_RDMA_CMS_RDMA_CM = 0, /* Sockets based enpoint addressing */
|
|
|
+};
|
|
|
+
|
|
|
+#define NVMF_AQ_DEPTH 32
|
|
|
|
|
|
enum {
|
|
|
NVME_REG_CAP = 0x0000, /* Controller Capabilities */
|
|
|
@@ -117,7 +189,8 @@ struct nvme_id_ctrl {
|
|
|
__le32 rtd3r;
|
|
|
__le32 rtd3e;
|
|
|
__le32 oaes;
|
|
|
- __u8 rsvd96[160];
|
|
|
+ __le32 ctratt;
|
|
|
+ __u8 rsvd100[156];
|
|
|
__le16 oacs;
|
|
|
__u8 acl;
|
|
|
__u8 aerl;
|
|
|
@@ -132,7 +205,7 @@ struct nvme_id_ctrl {
|
|
|
__u8 rsvd270[242];
|
|
|
__u8 sqes;
|
|
|
__u8 cqes;
|
|
|
- __u8 rsvd514[2];
|
|
|
+ __le16 maxcmd;
|
|
|
__le32 nn;
|
|
|
__le16 oncs;
|
|
|
__le16 fuses;
|
|
|
@@ -145,7 +218,15 @@ struct nvme_id_ctrl {
|
|
|
__le16 acwu;
|
|
|
__u8 rsvd534[2];
|
|
|
__le32 sgls;
|
|
|
- __u8 rsvd540[1508];
|
|
|
+ __u8 rsvd540[228];
|
|
|
+ char subnqn[256];
|
|
|
+ __u8 rsvd1024[768];
|
|
|
+ __le32 ioccsz;
|
|
|
+ __le32 iorcsz;
|
|
|
+ __le16 icdoff;
|
|
|
+ __u8 ctrattr;
|
|
|
+ __u8 msdbd;
|
|
|
+ __u8 rsvd1804[244];
|
|
|
struct nvme_id_power_state psd[32];
|
|
|
__u8 vs[1024];
|
|
|
};
|
|
|
@@ -306,6 +387,61 @@ enum nvme_opcode {
|
|
|
nvme_cmd_resv_release = 0x15,
|
|
|
};
|
|
|
|
|
|
+/*
|
|
|
+ * Descriptor subtype - lower 4 bits of nvme_(keyed_)sgl_desc identifier
|
|
|
+ *
|
|
|
+ * @NVME_SGL_FMT_ADDRESS: absolute address of the data block
|
|
|
+ * @NVME_SGL_FMT_OFFSET: relative offset of the in-capsule data block
|
|
|
+ * @NVME_SGL_FMT_INVALIDATE: RDMA transport specific remote invalidation
|
|
|
+ * request subtype
|
|
|
+ */
|
|
|
+enum {
|
|
|
+ NVME_SGL_FMT_ADDRESS = 0x00,
|
|
|
+ NVME_SGL_FMT_OFFSET = 0x01,
|
|
|
+ NVME_SGL_FMT_INVALIDATE = 0x0f,
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * Descriptor type - upper 4 bits of nvme_(keyed_)sgl_desc identifier
|
|
|
+ *
|
|
|
+ * For struct nvme_sgl_desc:
|
|
|
+ * @NVME_SGL_FMT_DATA_DESC: data block descriptor
|
|
|
+ * @NVME_SGL_FMT_SEG_DESC: sgl segment descriptor
|
|
|
+ * @NVME_SGL_FMT_LAST_SEG_DESC: last sgl segment descriptor
|
|
|
+ *
|
|
|
+ * For struct nvme_keyed_sgl_desc:
|
|
|
+ * @NVME_KEY_SGL_FMT_DATA_DESC: keyed data block descriptor
|
|
|
+ */
|
|
|
+enum {
|
|
|
+ NVME_SGL_FMT_DATA_DESC = 0x00,
|
|
|
+ NVME_SGL_FMT_SEG_DESC = 0x02,
|
|
|
+ NVME_SGL_FMT_LAST_SEG_DESC = 0x03,
|
|
|
+ NVME_KEY_SGL_FMT_DATA_DESC = 0x04,
|
|
|
+};
|
|
|
+
|
|
|
+struct nvme_sgl_desc {
|
|
|
+ __le64 addr;
|
|
|
+ __le32 length;
|
|
|
+ __u8 rsvd[3];
|
|
|
+ __u8 type;
|
|
|
+};
|
|
|
+
|
|
|
+struct nvme_keyed_sgl_desc {
|
|
|
+ __le64 addr;
|
|
|
+ __u8 length[3];
|
|
|
+ __u8 key[4];
|
|
|
+ __u8 type;
|
|
|
+};
|
|
|
+
|
|
|
+union nvme_data_ptr {
|
|
|
+ struct {
|
|
|
+ __le64 prp1;
|
|
|
+ __le64 prp2;
|
|
|
+ };
|
|
|
+ struct nvme_sgl_desc sgl;
|
|
|
+ struct nvme_keyed_sgl_desc ksgl;
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* Lowest two bits of our flags field (FUSE field in the spec):
|
|
|
*
|
|
|
@@ -336,8 +472,7 @@ struct nvme_common_command {
|
|
|
__le32 nsid;
|
|
|
__le32 cdw2[2];
|
|
|
__le64 metadata;
|
|
|
- __le64 prp1;
|
|
|
- __le64 prp2;
|
|
|
+ union nvme_data_ptr dptr;
|
|
|
__le32 cdw10[6];
|
|
|
};
|
|
|
|
|
|
@@ -348,8 +483,7 @@ struct nvme_rw_command {
|
|
|
__le32 nsid;
|
|
|
__u64 rsvd2;
|
|
|
__le64 metadata;
|
|
|
- __le64 prp1;
|
|
|
- __le64 prp2;
|
|
|
+ union nvme_data_ptr dptr;
|
|
|
__le64 slba;
|
|
|
__le16 length;
|
|
|
__le16 control;
|
|
|
@@ -389,8 +523,7 @@ struct nvme_dsm_cmd {
|
|
|
__u16 command_id;
|
|
|
__le32 nsid;
|
|
|
__u64 rsvd2[2];
|
|
|
- __le64 prp1;
|
|
|
- __le64 prp2;
|
|
|
+ union nvme_data_ptr dptr;
|
|
|
__le32 nr;
|
|
|
__le32 attributes;
|
|
|
__u32 rsvd12[4];
|
|
|
@@ -454,6 +587,7 @@ enum {
|
|
|
NVME_LOG_ERROR = 0x01,
|
|
|
NVME_LOG_SMART = 0x02,
|
|
|
NVME_LOG_FW_SLOT = 0x03,
|
|
|
+ NVME_LOG_DISC = 0x70,
|
|
|
NVME_LOG_RESERVATION = 0x80,
|
|
|
NVME_FWACT_REPL = (0 << 3),
|
|
|
NVME_FWACT_REPL_ACTV = (1 << 3),
|
|
|
@@ -466,8 +600,7 @@ struct nvme_identify {
|
|
|
__u16 command_id;
|
|
|
__le32 nsid;
|
|
|
__u64 rsvd2[2];
|
|
|
- __le64 prp1;
|
|
|
- __le64 prp2;
|
|
|
+ union nvme_data_ptr dptr;
|
|
|
__le32 cns;
|
|
|
__u32 rsvd11[5];
|
|
|
};
|
|
|
@@ -478,8 +611,7 @@ struct nvme_features {
|
|
|
__u16 command_id;
|
|
|
__le32 nsid;
|
|
|
__u64 rsvd2[2];
|
|
|
- __le64 prp1;
|
|
|
- __le64 prp2;
|
|
|
+ union nvme_data_ptr dptr;
|
|
|
__le32 fid;
|
|
|
__le32 dword11;
|
|
|
__u32 rsvd12[4];
|
|
|
@@ -538,8 +670,7 @@ struct nvme_download_firmware {
|
|
|
__u8 flags;
|
|
|
__u16 command_id;
|
|
|
__u32 rsvd1[5];
|
|
|
- __le64 prp1;
|
|
|
- __le64 prp2;
|
|
|
+ union nvme_data_ptr dptr;
|
|
|
__le32 numd;
|
|
|
__le32 offset;
|
|
|
__u32 rsvd12[4];
|
|
|
@@ -561,8 +692,7 @@ struct nvme_get_log_page_command {
|
|
|
__u16 command_id;
|
|
|
__le32 nsid;
|
|
|
__u64 rsvd2[2];
|
|
|
- __le64 prp1;
|
|
|
- __le64 prp2;
|
|
|
+ union nvme_data_ptr dptr;
|
|
|
__u8 lid;
|
|
|
__u8 rsvd10;
|
|
|
__le16 numdl;
|
|
|
@@ -573,6 +703,126 @@ struct nvme_get_log_page_command {
|
|
|
__u32 rsvd14[2];
|
|
|
};
|
|
|
|
|
|
+/*
|
|
|
+ * Fabrics subcommands.
|
|
|
+ */
|
|
|
+enum nvmf_fabrics_opcode {
|
|
|
+ nvme_fabrics_command = 0x7f,
|
|
|
+};
|
|
|
+
|
|
|
+enum nvmf_capsule_command {
|
|
|
+ nvme_fabrics_type_property_set = 0x00,
|
|
|
+ nvme_fabrics_type_connect = 0x01,
|
|
|
+ nvme_fabrics_type_property_get = 0x04,
|
|
|
+};
|
|
|
+
|
|
|
+struct nvmf_common_command {
|
|
|
+ __u8 opcode;
|
|
|
+ __u8 resv1;
|
|
|
+ __u16 command_id;
|
|
|
+ __u8 fctype;
|
|
|
+ __u8 resv2[35];
|
|
|
+ __u8 ts[24];
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * The legal cntlid range a NVMe Target will provide.
|
|
|
+ * Note that cntlid of value 0 is considered illegal in the fabrics world.
|
|
|
+ * Devices based on earlier specs did not have the subsystem concept;
|
|
|
+ * therefore, those devices had their cntlid value set to 0 as a result.
|
|
|
+ */
|
|
|
+#define NVME_CNTLID_MIN 1
|
|
|
+#define NVME_CNTLID_MAX 0xffef
|
|
|
+#define NVME_CNTLID_DYNAMIC 0xffff
|
|
|
+
|
|
|
+#define MAX_DISC_LOGS 255
|
|
|
+
|
|
|
+/* Discovery log page entry */
|
|
|
+struct nvmf_disc_rsp_page_entry {
|
|
|
+ __u8 trtype;
|
|
|
+ __u8 adrfam;
|
|
|
+ __u8 nqntype;
|
|
|
+ __u8 treq;
|
|
|
+ __le16 portid;
|
|
|
+ __le16 cntlid;
|
|
|
+ __le16 asqsz;
|
|
|
+ __u8 resv8[22];
|
|
|
+ char trsvcid[NVMF_TRSVCID_SIZE];
|
|
|
+ __u8 resv64[192];
|
|
|
+ char subnqn[NVMF_NQN_FIELD_LEN];
|
|
|
+ char traddr[NVMF_TRADDR_SIZE];
|
|
|
+ union tsas {
|
|
|
+ char common[NVMF_TSAS_SIZE];
|
|
|
+ struct rdma {
|
|
|
+ __u8 qptype;
|
|
|
+ __u8 prtype;
|
|
|
+ __u8 cms;
|
|
|
+ __u8 resv3[5];
|
|
|
+ __u16 pkey;
|
|
|
+ __u8 resv10[246];
|
|
|
+ } rdma;
|
|
|
+ } tsas;
|
|
|
+};
|
|
|
+
|
|
|
+/* Discovery log page header */
|
|
|
+struct nvmf_disc_rsp_page_hdr {
|
|
|
+ __le64 genctr;
|
|
|
+ __le64 numrec;
|
|
|
+ __le16 recfmt;
|
|
|
+ __u8 resv14[1006];
|
|
|
+ struct nvmf_disc_rsp_page_entry entries[0];
|
|
|
+};
|
|
|
+
|
|
|
+struct nvmf_connect_command {
|
|
|
+ __u8 opcode;
|
|
|
+ __u8 resv1;
|
|
|
+ __u16 command_id;
|
|
|
+ __u8 fctype;
|
|
|
+ __u8 resv2[19];
|
|
|
+ union nvme_data_ptr dptr;
|
|
|
+ __le16 recfmt;
|
|
|
+ __le16 qid;
|
|
|
+ __le16 sqsize;
|
|
|
+ __u8 cattr;
|
|
|
+ __u8 resv3;
|
|
|
+ __le32 kato;
|
|
|
+ __u8 resv4[12];
|
|
|
+};
|
|
|
+
|
|
|
+struct nvmf_connect_data {
|
|
|
+ uuid_le hostid;
|
|
|
+ __le16 cntlid;
|
|
|
+ char resv4[238];
|
|
|
+ char subsysnqn[NVMF_NQN_FIELD_LEN];
|
|
|
+ char hostnqn[NVMF_NQN_FIELD_LEN];
|
|
|
+ char resv5[256];
|
|
|
+};
|
|
|
+
|
|
|
+struct nvmf_property_set_command {
|
|
|
+ __u8 opcode;
|
|
|
+ __u8 resv1;
|
|
|
+ __u16 command_id;
|
|
|
+ __u8 fctype;
|
|
|
+ __u8 resv2[35];
|
|
|
+ __u8 attrib;
|
|
|
+ __u8 resv3[3];
|
|
|
+ __le32 offset;
|
|
|
+ __le64 value;
|
|
|
+ __u8 resv4[8];
|
|
|
+};
|
|
|
+
|
|
|
+struct nvmf_property_get_command {
|
|
|
+ __u8 opcode;
|
|
|
+ __u8 resv1;
|
|
|
+ __u16 command_id;
|
|
|
+ __u8 fctype;
|
|
|
+ __u8 resv2[35];
|
|
|
+ __u8 attrib;
|
|
|
+ __u8 resv3[3];
|
|
|
+ __le32 offset;
|
|
|
+ __u8 resv4[16];
|
|
|
+};
|
|
|
+
|
|
|
struct nvme_command {
|
|
|
union {
|
|
|
struct nvme_common_command common;
|
|
|
@@ -587,15 +837,29 @@ struct nvme_command {
|
|
|
struct nvme_dsm_cmd dsm;
|
|
|
struct nvme_abort_cmd abort;
|
|
|
struct nvme_get_log_page_command get_log_page;
|
|
|
+ struct nvmf_common_command fabrics;
|
|
|
+ struct nvmf_connect_command connect;
|
|
|
+ struct nvmf_property_set_command prop_set;
|
|
|
+ struct nvmf_property_get_command prop_get;
|
|
|
};
|
|
|
};
|
|
|
|
|
|
static inline bool nvme_is_write(struct nvme_command *cmd)
|
|
|
{
|
|
|
+ /*
|
|
|
+ * What a mess...
|
|
|
+ *
|
|
|
+ * Why can't we simply have a Fabrics In and Fabrics out command?
|
|
|
+ */
|
|
|
+ if (unlikely(cmd->common.opcode == nvme_fabrics_command))
|
|
|
+ return cmd->fabrics.opcode & 1;
|
|
|
return cmd->common.opcode & 1;
|
|
|
}
|
|
|
|
|
|
enum {
|
|
|
+ /*
|
|
|
+ * Generic Command Status:
|
|
|
+ */
|
|
|
NVME_SC_SUCCESS = 0x0,
|
|
|
NVME_SC_INVALID_OPCODE = 0x1,
|
|
|
NVME_SC_INVALID_FIELD = 0x2,
|
|
|
@@ -614,10 +878,18 @@ enum {
|
|
|
NVME_SC_SGL_INVALID_DATA = 0xf,
|
|
|
NVME_SC_SGL_INVALID_METADATA = 0x10,
|
|
|
NVME_SC_SGL_INVALID_TYPE = 0x11,
|
|
|
+
|
|
|
+ NVME_SC_SGL_INVALID_OFFSET = 0x16,
|
|
|
+ NVME_SC_SGL_INVALID_SUBTYPE = 0x17,
|
|
|
+
|
|
|
NVME_SC_LBA_RANGE = 0x80,
|
|
|
NVME_SC_CAP_EXCEEDED = 0x81,
|
|
|
NVME_SC_NS_NOT_READY = 0x82,
|
|
|
NVME_SC_RESERVATION_CONFLICT = 0x83,
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Command Specific Status:
|
|
|
+ */
|
|
|
NVME_SC_CQ_INVALID = 0x100,
|
|
|
NVME_SC_QID_INVALID = 0x101,
|
|
|
NVME_SC_QUEUE_SIZE = 0x102,
|
|
|
@@ -635,9 +907,29 @@ enum {
|
|
|
NVME_SC_FEATURE_NOT_CHANGEABLE = 0x10e,
|
|
|
NVME_SC_FEATURE_NOT_PER_NS = 0x10f,
|
|
|
NVME_SC_FW_NEEDS_RESET_SUBSYS = 0x110,
|
|
|
+
|
|
|
+ /*
|
|
|
+ * I/O Command Set Specific - NVM commands:
|
|
|
+ */
|
|
|
NVME_SC_BAD_ATTRIBUTES = 0x180,
|
|
|
NVME_SC_INVALID_PI = 0x181,
|
|
|
NVME_SC_READ_ONLY = 0x182,
|
|
|
+
|
|
|
+ /*
|
|
|
+ * I/O Command Set Specific - Fabrics commands:
|
|
|
+ */
|
|
|
+ NVME_SC_CONNECT_FORMAT = 0x180,
|
|
|
+ NVME_SC_CONNECT_CTRL_BUSY = 0x181,
|
|
|
+ NVME_SC_CONNECT_INVALID_PARAM = 0x182,
|
|
|
+ NVME_SC_CONNECT_RESTART_DISC = 0x183,
|
|
|
+ NVME_SC_CONNECT_INVALID_HOST = 0x184,
|
|
|
+
|
|
|
+ NVME_SC_DISCOVERY_RESTART = 0x190,
|
|
|
+ NVME_SC_AUTH_REQUIRED = 0x191,
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Media and Data Integrity Errors:
|
|
|
+ */
|
|
|
NVME_SC_WRITE_FAULT = 0x280,
|
|
|
NVME_SC_READ_ERROR = 0x281,
|
|
|
NVME_SC_GUARD_CHECK = 0x282,
|
|
|
@@ -645,12 +937,19 @@ enum {
|
|
|
NVME_SC_REFTAG_CHECK = 0x284,
|
|
|
NVME_SC_COMPARE_FAILED = 0x285,
|
|
|
NVME_SC_ACCESS_DENIED = 0x286,
|
|
|
+
|
|
|
NVME_SC_DNR = 0x4000,
|
|
|
};
|
|
|
|
|
|
struct nvme_completion {
|
|
|
- __le32 result; /* Used by admin commands to return data */
|
|
|
- __u32 rsvd;
|
|
|
+ /*
|
|
|
+ * Used by Admin and Fabrics commands to return data:
|
|
|
+ */
|
|
|
+ union {
|
|
|
+ __le16 result16;
|
|
|
+ __le32 result;
|
|
|
+ __le64 result64;
|
|
|
+ };
|
|
|
__le16 sq_head; /* how much of this queue may be reclaimed */
|
|
|
__le16 sq_id; /* submission queue that generated this entry */
|
|
|
__u16 command_id; /* of the command which completed */
|