git: f2e737683eef - main - nvmf_proto.h: NVMe over Fabrics protocol definitions

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Fri, 03 May 2024 00:15:37 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=f2e737683eef00469722265a2f957e867de6e354

commit f2e737683eef00469722265a2f957e867de6e354
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2024-05-02 23:26:16 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2024-05-02 23:26:16 +0000

    nvmf_proto.h: NVMe over Fabrics protocol definitions
    
    This is a copy of spdk/include/spdk/nvmf_spec.h as of commit
    470e851852bb948334a272c9f8de495020fa082f from Intel's SPDK.
    Subsequent commits will modify it to be suitable header for the
    kernel, but importing the stock file first makes it easier to see
    how the resulting header is derived from the original.
    
    Reviewed by:    imp
    Obtained from:  SPDK (https://github.com/spdk/spdk.git)
    Sponsored by:   Chelsio Communications
    Differential Revision:  https://reviews.freebsd.org/D44703
---
 sys/dev/nvmf/nvmf_proto.h | 721 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 721 insertions(+)

diff --git a/sys/dev/nvmf/nvmf_proto.h b/sys/dev/nvmf/nvmf_proto.h
new file mode 100644
index 000000000000..75f6db2f8b15
--- /dev/null
+++ b/sys/dev/nvmf/nvmf_proto.h
@@ -0,0 +1,721 @@
+/*   SPDX-License-Identifier: BSD-3-Clause
+ *   Copyright (C) 2016 Intel Corporation.
+ *   All rights reserved.
+ */
+
+#ifndef SPDK_NVMF_SPEC_H
+#define SPDK_NVMF_SPEC_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/assert.h"
+#include "spdk/nvme_spec.h"
+
+/**
+ * \file
+ * NVMe over Fabrics specification definitions
+ */
+
+#pragma pack(push, 1)
+
+struct spdk_nvmf_capsule_cmd {
+	uint8_t		opcode;
+	uint8_t		reserved1;
+	uint16_t	cid;
+	uint8_t		fctype;
+	uint8_t		reserved2[35];
+	uint8_t		fabric_specific[24];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_capsule_cmd) == 64, "Incorrect size");
+
+/* Fabric Command Set */
+#define SPDK_NVME_OPC_FABRIC 0x7f
+
+enum spdk_nvmf_fabric_cmd_types {
+	SPDK_NVMF_FABRIC_COMMAND_PROPERTY_SET			= 0x00,
+	SPDK_NVMF_FABRIC_COMMAND_CONNECT			= 0x01,
+	SPDK_NVMF_FABRIC_COMMAND_PROPERTY_GET			= 0x04,
+	SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND		= 0x05,
+	SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV		= 0x06,
+	SPDK_NVMF_FABRIC_COMMAND_START_VENDOR_SPECIFIC		= 0xC0,
+};
+
+enum spdk_nvmf_fabric_cmd_status_code {
+	SPDK_NVMF_FABRIC_SC_INCOMPATIBLE_FORMAT		= 0x80,
+	SPDK_NVMF_FABRIC_SC_CONTROLLER_BUSY		= 0x81,
+	SPDK_NVMF_FABRIC_SC_INVALID_PARAM		= 0x82,
+	SPDK_NVMF_FABRIC_SC_RESTART_DISCOVERY		= 0x83,
+	SPDK_NVMF_FABRIC_SC_INVALID_HOST		= 0x84,
+	SPDK_NVMF_FABRIC_SC_LOG_RESTART_DISCOVERY	= 0x90,
+	SPDK_NVMF_FABRIC_SC_AUTH_REQUIRED		= 0x91,
+};
+
+/**
+ * RDMA Queue Pair service types
+ */
+enum spdk_nvmf_rdma_qptype {
+	/** Reliable connected */
+	SPDK_NVMF_RDMA_QPTYPE_RELIABLE_CONNECTED	= 0x1,
+
+	/** Reliable datagram */
+	SPDK_NVMF_RDMA_QPTYPE_RELIABLE_DATAGRAM		= 0x2,
+};
+
+/**
+ * RDMA provider types
+ */
+enum spdk_nvmf_rdma_prtype {
+	/** No provider specified */
+	SPDK_NVMF_RDMA_PRTYPE_NONE	= 0x1,
+
+	/** InfiniBand */
+	SPDK_NVMF_RDMA_PRTYPE_IB	= 0x2,
+
+	/** RoCE v1 */
+	SPDK_NVMF_RDMA_PRTYPE_ROCE	= 0x3,
+
+	/** RoCE v2 */
+	SPDK_NVMF_RDMA_PRTYPE_ROCE2	= 0x4,
+
+	/** iWARP */
+	SPDK_NVMF_RDMA_PRTYPE_IWARP	= 0x5,
+};
+
+/**
+ * RDMA connection management service types
+ */
+enum spdk_nvmf_rdma_cms {
+	/** Sockets based endpoint addressing */
+	SPDK_NVMF_RDMA_CMS_RDMA_CM	= 0x1,
+};
+
+/**
+ * NVMe over Fabrics transport types
+ */
+enum spdk_nvmf_trtype {
+	/** RDMA */
+	SPDK_NVMF_TRTYPE_RDMA		= 0x1,
+
+	/** Fibre Channel */
+	SPDK_NVMF_TRTYPE_FC		= 0x2,
+
+	/** TCP */
+	SPDK_NVMF_TRTYPE_TCP		= 0x3,
+
+	/** Intra-host transport (loopback) */
+	SPDK_NVMF_TRTYPE_INTRA_HOST	= 0xfe,
+};
+
+/**
+ * Address family types
+ */
+enum spdk_nvmf_adrfam {
+	/** IPv4 (AF_INET) */
+	SPDK_NVMF_ADRFAM_IPV4		= 0x1,
+
+	/** IPv6 (AF_INET6) */
+	SPDK_NVMF_ADRFAM_IPV6		= 0x2,
+
+	/** InfiniBand (AF_IB) */
+	SPDK_NVMF_ADRFAM_IB		= 0x3,
+
+	/** Fibre Channel address family */
+	SPDK_NVMF_ADRFAM_FC		= 0x4,
+
+	/** Intra-host transport (loopback) */
+	SPDK_NVMF_ADRFAM_INTRA_HOST	= 0xfe,
+};
+
+/**
+ * NVM subsystem types
+ */
+enum spdk_nvmf_subtype {
+	/** Referral to a discovery service */
+	SPDK_NVMF_SUBTYPE_DISCOVERY		= 0x1,
+
+	/** NVM Subsystem */
+	SPDK_NVMF_SUBTYPE_NVME			= 0x2,
+
+	/** Current Discovery Subsystem */
+	SPDK_NVMF_SUBTYPE_DISCOVERY_CURRENT	= 0x3
+};
+
+/* Discovery Log Entry Flags - Duplicate Returned Information */
+#define SPDK_NVMF_DISCOVERY_LOG_EFLAGS_DUPRETINFO (1u << 0u)
+
+/* Discovery Log Entry Flags - Explicit Persistent Connection Support for Discovery */
+#define SPDK_NVMF_DISCOVERY_LOG_EFLAGS_EPCSD (1u << 1u)
+
+/**
+ * Connections shall be made over a fabric secure channel
+ */
+enum spdk_nvmf_treq_secure_channel {
+	/** Not specified */
+	SPDK_NVMF_TREQ_SECURE_CHANNEL_NOT_SPECIFIED	= 0x0,
+
+	/** Required */
+	SPDK_NVMF_TREQ_SECURE_CHANNEL_REQUIRED		= 0x1,
+
+	/** Not required */
+	SPDK_NVMF_TREQ_SECURE_CHANNEL_NOT_REQUIRED	= 0x2,
+};
+
+struct spdk_nvmf_fabric_auth_recv_cmd {
+	uint8_t		opcode;
+	uint8_t		reserved1;
+	uint16_t	cid;
+	uint8_t		fctype; /* NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV (0x06) */
+	uint8_t		reserved2[19];
+	struct spdk_nvme_sgl_descriptor sgl1;
+	uint8_t		reserved3;
+	uint8_t		spsp0;
+	uint8_t		spsp1;
+	uint8_t		secp;
+	uint32_t	al;
+	uint8_t		reserved4[16];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fabric_auth_recv_cmd) == 64, "Incorrect size");
+
+struct spdk_nvmf_fabric_auth_send_cmd {
+	uint8_t		opcode;
+	uint8_t		reserved1;
+	uint16_t	cid;
+	uint8_t		fctype; /* NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND (0x05) */
+	uint8_t		reserved2[19];
+	struct spdk_nvme_sgl_descriptor sgl1;
+	uint8_t		reserved3;
+	uint8_t		spsp0;
+	uint8_t		spsp1;
+	uint8_t		secp;
+	uint32_t	tl;
+	uint8_t		reserved4[16];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fabric_auth_send_cmd) == 64, "Incorrect size");
+
+struct spdk_nvmf_fabric_connect_data {
+	uint8_t		hostid[16];
+	uint16_t	cntlid;
+	uint8_t		reserved5[238];
+	uint8_t		subnqn[SPDK_NVME_NQN_FIELD_SIZE];
+	uint8_t		hostnqn[SPDK_NVME_NQN_FIELD_SIZE];
+	uint8_t		reserved6[256];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fabric_connect_data) == 1024, "Incorrect size");
+
+struct spdk_nvmf_fabric_connect_cmd {
+	uint8_t		opcode;
+	uint8_t		reserved1;
+	uint16_t	cid;
+	uint8_t		fctype;
+	uint8_t		reserved2[19];
+	struct spdk_nvme_sgl_descriptor sgl1;
+	uint16_t	recfmt; /* Connect Record Format */
+	uint16_t	qid; /* Queue Identifier */
+	uint16_t	sqsize; /* Submission Queue Size */
+	uint8_t		cattr; /* queue attributes */
+	uint8_t		reserved3;
+	uint32_t	kato; /* keep alive timeout */
+	uint8_t		reserved4[12];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fabric_connect_cmd) == 64, "Incorrect size");
+
+struct spdk_nvmf_fabric_connect_rsp {
+	union {
+		struct {
+			uint16_t cntlid;
+			uint16_t authreq;
+		} success;
+
+		struct {
+			uint16_t	ipo;
+			uint8_t		iattr;
+			uint8_t		reserved;
+		} invalid;
+
+		uint32_t raw;
+	} status_code_specific;
+
+	uint32_t	reserved0;
+	uint16_t	sqhd;
+	uint16_t	reserved1;
+	uint16_t	cid;
+	struct spdk_nvme_status status;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fabric_connect_rsp) == 16, "Incorrect size");
+
+#define SPDK_NVMF_PROP_SIZE_4	0
+#define SPDK_NVMF_PROP_SIZE_8	1
+
+struct spdk_nvmf_fabric_prop_get_cmd {
+	uint8_t		opcode;
+	uint8_t		reserved1;
+	uint16_t	cid;
+	uint8_t		fctype;
+	uint8_t		reserved2[35];
+	struct {
+		uint8_t size		: 3;
+		uint8_t reserved	: 5;
+	} attrib;
+	uint8_t		reserved3[3];
+	uint32_t	ofst;
+	uint8_t		reserved4[16];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fabric_prop_get_cmd) == 64, "Incorrect size");
+
+struct spdk_nvmf_fabric_prop_get_rsp {
+	union {
+		uint64_t u64;
+		struct {
+			uint32_t low;
+			uint32_t high;
+		} u32;
+	} value;
+
+	uint16_t	sqhd;
+	uint16_t	reserved0;
+	uint16_t	cid;
+	struct spdk_nvme_status status;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fabric_prop_get_rsp) == 16, "Incorrect size");
+
+struct spdk_nvmf_fabric_prop_set_cmd {
+	uint8_t		opcode;
+	uint8_t		reserved0;
+	uint16_t	cid;
+	uint8_t		fctype;
+	uint8_t		reserved1[35];
+	struct {
+		uint8_t size		: 3;
+		uint8_t reserved	: 5;
+	} attrib;
+	uint8_t		reserved2[3];
+	uint32_t	ofst;
+
+	union {
+		uint64_t u64;
+		struct {
+			uint32_t low;
+			uint32_t high;
+		} u32;
+	} value;
+
+	uint8_t		reserved4[8];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fabric_prop_set_cmd) == 64, "Incorrect size");
+
+#define SPDK_NVMF_NQN_MIN_LEN 11 /* The prefix in the spec is 11 characters */
+#define SPDK_NVMF_NQN_MAX_LEN 223
+#define SPDK_NVMF_NQN_UUID_PRE_LEN 32
+#define SPDK_NVMF_UUID_STRING_LEN 36
+#define SPDK_NVMF_NQN_UUID_PRE "nqn.2014-08.org.nvmexpress:uuid:"
+#define SPDK_NVMF_DISCOVERY_NQN "nqn.2014-08.org.nvmexpress.discovery"
+
+#define SPDK_DOMAIN_LABEL_MAX_LEN 63 /* RFC 1034 max domain label length */
+
+#define SPDK_NVMF_TRSTRING_MAX_LEN 32
+#define SPDK_NVMF_TRADDR_MAX_LEN 256
+#define SPDK_NVMF_TRSVCID_MAX_LEN 32
+
+/** RDMA transport-specific address subtype */
+struct spdk_nvmf_rdma_transport_specific_address_subtype {
+	/** RDMA QP service type (\ref spdk_nvmf_rdma_qptype) */
+	uint8_t		rdma_qptype;
+
+	/** RDMA provider type (\ref spdk_nvmf_rdma_prtype) */
+	uint8_t		rdma_prtype;
+
+	/** RDMA connection management service (\ref spdk_nvmf_rdma_cms) */
+	uint8_t		rdma_cms;
+
+	uint8_t		reserved0[5];
+
+	/** RDMA partition key for AF_IB */
+	uint16_t	rdma_pkey;
+
+	uint8_t		reserved2[246];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_rdma_transport_specific_address_subtype) == 256,
+		   "Incorrect size");
+
+/** TCP Secure Socket Type */
+enum spdk_nvme_tcp_secure_socket_type {
+	/** No security */
+	SPDK_NVME_TCP_SECURITY_NONE			= 0,
+
+	/** TLS (Secure Sockets) version 1.2 */
+	SPDK_NVME_TCP_SECURITY_TLS_1_2			= 1,
+
+	/** TLS (Secure Sockets) version 1.3 */
+	SPDK_NVME_TCP_SECURITY_TLS_1_3			= 2,
+};
+
+/** TCP transport-specific address subtype */
+struct spdk_nvme_tcp_transport_specific_address_subtype {
+	/** Security type (\ref spdk_nvme_tcp_secure_socket_type) */
+	uint8_t		sectype;
+
+	uint8_t		reserved0[255];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_tcp_transport_specific_address_subtype) == 256,
+		   "Incorrect size");
+
+/** Transport-specific address subtype */
+union spdk_nvmf_transport_specific_address_subtype {
+	uint8_t raw[256];
+
+	/** RDMA */
+	struct spdk_nvmf_rdma_transport_specific_address_subtype rdma;
+
+	/** TCP */
+	struct spdk_nvme_tcp_transport_specific_address_subtype tcp;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvmf_transport_specific_address_subtype) == 256,
+		   "Incorrect size");
+
+#define SPDK_NVMF_MIN_ADMIN_MAX_SQ_SIZE 32
+
+/**
+ * Discovery Log Page entry
+ */
+struct spdk_nvmf_discovery_log_page_entry {
+	/** Transport type (\ref spdk_nvmf_trtype) */
+	uint8_t		trtype;
+
+	/** Address family (\ref spdk_nvmf_adrfam) */
+	uint8_t		adrfam;
+
+	/** Subsystem type (\ref spdk_nvmf_subtype) */
+	uint8_t		subtype;
+
+	/** Transport requirements */
+	struct {
+		/** Secure channel requirements (\ref spdk_nvmf_treq_secure_channel) */
+		uint8_t secure_channel : 2;
+
+		uint8_t reserved : 6;
+	} treq;
+
+	/** NVM subsystem port ID */
+	uint16_t	portid;
+
+	/** Controller ID */
+	uint16_t	cntlid;
+
+	/** Admin max SQ size */
+	uint16_t	asqsz;
+
+	/** Entry Flags */
+	uint16_t	eflags;
+
+	uint8_t		reserved0[20];
+
+	/** Transport service identifier */
+	uint8_t		trsvcid[SPDK_NVMF_TRSVCID_MAX_LEN];
+
+	uint8_t		reserved1[192];
+
+	/** NVM subsystem qualified name */
+	uint8_t		subnqn[256];
+
+	/** Transport address */
+	uint8_t		traddr[SPDK_NVMF_TRADDR_MAX_LEN];
+
+	/** Transport-specific address subtype */
+	union spdk_nvmf_transport_specific_address_subtype tsas;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_discovery_log_page_entry) == 1024, "Incorrect size");
+
+struct spdk_nvmf_discovery_log_page {
+	uint64_t	genctr;
+	uint64_t	numrec;
+	uint16_t	recfmt;
+	uint8_t		reserved0[1006];
+	struct spdk_nvmf_discovery_log_page_entry entries[0];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_discovery_log_page) == 1024, "Incorrect size");
+
+/* RDMA Fabric specific definitions below */
+
+#define SPDK_NVME_SGL_SUBTYPE_INVALIDATE_KEY	0xF
+
+struct spdk_nvmf_rdma_request_private_data {
+	uint16_t	recfmt; /* record format */
+	uint16_t	qid;	/* queue id */
+	uint16_t	hrqsize;	/* host receive queue size */
+	uint16_t	hsqsize;	/* host send queue size */
+	uint16_t	cntlid;		/* controller id */
+	uint8_t		reserved[22];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_rdma_request_private_data) == 32, "Incorrect size");
+
+struct spdk_nvmf_rdma_accept_private_data {
+	uint16_t	recfmt; /* record format */
+	uint16_t	crqsize;	/* controller receive queue size */
+	uint8_t		reserved[28];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_rdma_accept_private_data) == 32, "Incorrect size");
+
+struct spdk_nvmf_rdma_reject_private_data {
+	uint16_t	recfmt; /* record format */
+	uint16_t	sts; /* status */
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_rdma_reject_private_data) == 4, "Incorrect size");
+
+union spdk_nvmf_rdma_private_data {
+	struct spdk_nvmf_rdma_request_private_data	pd_request;
+	struct spdk_nvmf_rdma_accept_private_data	pd_accept;
+	struct spdk_nvmf_rdma_reject_private_data	pd_reject;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvmf_rdma_private_data) == 32, "Incorrect size");
+
+enum spdk_nvmf_rdma_transport_error {
+	SPDK_NVMF_RDMA_ERROR_INVALID_PRIVATE_DATA_LENGTH	= 0x1,
+	SPDK_NVMF_RDMA_ERROR_INVALID_RECFMT			= 0x2,
+	SPDK_NVMF_RDMA_ERROR_INVALID_QID			= 0x3,
+	SPDK_NVMF_RDMA_ERROR_INVALID_HSQSIZE			= 0x4,
+	SPDK_NVMF_RDMA_ERROR_INVALID_HRQSIZE			= 0x5,
+	SPDK_NVMF_RDMA_ERROR_NO_RESOURCES			= 0x6,
+	SPDK_NVMF_RDMA_ERROR_INVALID_IRD			= 0x7,
+	SPDK_NVMF_RDMA_ERROR_INVALID_ORD			= 0x8,
+};
+
+/* TCP transport specific definitions below */
+
+/** NVMe/TCP PDU type */
+enum spdk_nvme_tcp_pdu_type {
+	/** Initialize Connection Request (ICReq) */
+	SPDK_NVME_TCP_PDU_TYPE_IC_REQ			= 0x00,
+
+	/** Initialize Connection Response (ICResp) */
+	SPDK_NVME_TCP_PDU_TYPE_IC_RESP			= 0x01,
+
+	/** Terminate Connection Request (TermReq) */
+	SPDK_NVME_TCP_PDU_TYPE_H2C_TERM_REQ		= 0x02,
+
+	/** Terminate Connection Response (TermResp) */
+	SPDK_NVME_TCP_PDU_TYPE_C2H_TERM_REQ		= 0x03,
+
+	/** Command Capsule (CapsuleCmd) */
+	SPDK_NVME_TCP_PDU_TYPE_CAPSULE_CMD		= 0x04,
+
+	/** Response Capsule (CapsuleRsp) */
+	SPDK_NVME_TCP_PDU_TYPE_CAPSULE_RESP		= 0x05,
+
+	/** Host To Controller Data (H2CData) */
+	SPDK_NVME_TCP_PDU_TYPE_H2C_DATA			= 0x06,
+
+	/** Controller To Host Data (C2HData) */
+	SPDK_NVME_TCP_PDU_TYPE_C2H_DATA			= 0x07,
+
+	/** Ready to Transfer (R2T) */
+	SPDK_NVME_TCP_PDU_TYPE_R2T			= 0x09,
+};
+
+/** Common NVMe/TCP PDU header */
+struct spdk_nvme_tcp_common_pdu_hdr {
+	/** PDU type (\ref spdk_nvme_tcp_pdu_type) */
+	uint8_t				pdu_type;
+
+	/** pdu_type-specific flags */
+	uint8_t				flags;
+
+	/** Length of PDU header (not including the Header Digest) */
+	uint8_t				hlen;
+
+	/** PDU Data Offset from the start of the PDU */
+	uint8_t				pdo;
+
+	/** Total number of bytes in PDU, including pdu_hdr */
+	uint32_t			plen;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_tcp_common_pdu_hdr) == 8, "Incorrect size");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_common_pdu_hdr, pdu_type) == 0,
+		   "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_common_pdu_hdr, flags) == 1, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_common_pdu_hdr, hlen) == 2, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_common_pdu_hdr, pdo) == 3, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_common_pdu_hdr, plen) == 4, "Incorrect offset");
+
+#define SPDK_NVME_TCP_CH_FLAGS_HDGSTF		(1u << 0)
+#define SPDK_NVME_TCP_CH_FLAGS_DDGSTF		(1u << 1)
+
+/**
+ * ICReq
+ *
+ * common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_IC_REQ
+ */
+struct spdk_nvme_tcp_ic_req {
+	struct spdk_nvme_tcp_common_pdu_hdr	common;
+	uint16_t				pfv;
+	/** Specifies the data alignment for all PDUs transferred from the controller to the host that contain data */
+	uint8_t					hpda;
+	union {
+		uint8_t				raw;
+		struct {
+			uint8_t			hdgst_enable : 1;
+			uint8_t			ddgst_enable : 1;
+			uint8_t			reserved : 6;
+		} bits;
+	} dgst;
+	uint32_t				maxr2t;
+	uint8_t					reserved16[112];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_tcp_ic_req) == 128, "Incorrect size");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_ic_req, pfv) == 8, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_ic_req, hpda) == 10, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_ic_req, maxr2t) == 12, "Incorrect offset");
+
+#define SPDK_NVME_TCP_HPDA_MAX 31
+#define SPDK_NVME_TCP_CPDA_MAX 31
+#define SPDK_NVME_TCP_PDU_PDO_MAX_OFFSET     ((SPDK_NVME_TCP_CPDA_MAX + 1) << 2)
+
+/**
+ * ICResp
+ *
+ * common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_IC_RESP
+ */
+struct spdk_nvme_tcp_ic_resp {
+	struct spdk_nvme_tcp_common_pdu_hdr	common;
+	uint16_t				pfv;
+	/** Specifies the data alignment for all PDUs transferred from the host to the controller that contain data */
+	uint8_t					cpda;
+	union {
+		uint8_t				raw;
+		struct {
+			uint8_t			hdgst_enable : 1;
+			uint8_t			ddgst_enable : 1;
+			uint8_t			reserved : 6;
+		} bits;
+	} dgst;
+	/** Specifies the maximum number of PDU-Data bytes per H2C Data Transfer PDU */
+	uint32_t				maxh2cdata;
+	uint8_t					reserved16[112];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_tcp_ic_resp) == 128, "Incorrect size");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_ic_resp, pfv) == 8, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_ic_resp, cpda) == 10, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_ic_resp, maxh2cdata) == 12, "Incorrect offset");
+
+/**
+ * TermReq
+ *
+ * common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_TERM_REQ
+ */
+struct spdk_nvme_tcp_term_req_hdr {
+	struct spdk_nvme_tcp_common_pdu_hdr	common;
+	uint16_t				fes;
+	uint8_t					fei[4];
+	uint8_t					reserved14[10];
+};
+
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_tcp_term_req_hdr) == 24, "Incorrect size");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_term_req_hdr, fes) == 8, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_term_req_hdr, fei) == 10, "Incorrect offset");
+
+enum spdk_nvme_tcp_term_req_fes {
+	SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD				= 0x01,
+	SPDK_NVME_TCP_TERM_REQ_FES_PDU_SEQUENCE_ERROR				= 0x02,
+	SPDK_NVME_TCP_TERM_REQ_FES_HDGST_ERROR					= 0x03,
+	SPDK_NVME_TCP_TERM_REQ_FES_DATA_TRANSFER_OUT_OF_RANGE			= 0x04,
+	SPDK_NVME_TCP_TERM_REQ_FES_DATA_TRANSFER_LIMIT_EXCEEDED			= 0x05,
+	SPDK_NVME_TCP_TERM_REQ_FES_R2T_LIMIT_EXCEEDED				= 0x05,
+	SPDK_NVME_TCP_TERM_REQ_FES_INVALID_DATA_UNSUPPORTED_PARAMETER		= 0x06,
+};
+
+/* Total length of term req PDU (including PDU header and DATA) in bytes shall not exceed a limit of 152 bytes. */
+#define SPDK_NVME_TCP_TERM_REQ_ERROR_DATA_MAX_SIZE	128
+#define SPDK_NVME_TCP_TERM_REQ_PDU_MAX_SIZE		(SPDK_NVME_TCP_TERM_REQ_ERROR_DATA_MAX_SIZE + sizeof(struct spdk_nvme_tcp_term_req_hdr))
+
+/**
+ * CapsuleCmd
+ *
+ * common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_CAPSULE_CMD
+ */
+struct spdk_nvme_tcp_cmd {
+	struct spdk_nvme_tcp_common_pdu_hdr	common;
+	struct spdk_nvme_cmd			ccsqe;
+	/**< icdoff hdgst padding + in-capsule data + ddgst (if enabled) */
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_tcp_cmd) == 72, "Incorrect size");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_cmd, ccsqe) == 8, "Incorrect offset");
+
+/**
+ * CapsuleResp
+ *
+ * common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_CAPSULE_RESP
+ */
+struct spdk_nvme_tcp_rsp {
+	struct spdk_nvme_tcp_common_pdu_hdr	common;
+	struct spdk_nvme_cpl			rccqe;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_tcp_rsp) == 24, "incorrect size");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_rsp, rccqe) == 8, "Incorrect offset");
+
+
+/**
+ * H2CData
+ *
+ * hdr.pdu_type == SPDK_NVME_TCP_PDU_TYPE_H2C_DATA
+ */
+struct spdk_nvme_tcp_h2c_data_hdr {
+	struct spdk_nvme_tcp_common_pdu_hdr	common;
+	uint16_t				cccid;
+	uint16_t				ttag;
+	uint32_t				datao;
+	uint32_t				datal;
+	uint8_t					reserved20[4];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_tcp_h2c_data_hdr) == 24, "Incorrect size");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_h2c_data_hdr, cccid) == 8, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_h2c_data_hdr, ttag) == 10, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_h2c_data_hdr, datao) == 12, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_h2c_data_hdr, datal) == 16, "Incorrect offset");
+
+#define SPDK_NVME_TCP_H2C_DATA_FLAGS_LAST_PDU	(1u << 2)
+#define SPDK_NVME_TCP_H2C_DATA_FLAGS_SUCCESS	(1u << 3)
+#define SPDK_NVME_TCP_H2C_DATA_PDO_MULT		8u
+
+/**
+ * C2HData
+ *
+ * hdr.pdu_type == SPDK_NVME_TCP_PDU_TYPE_C2H_DATA
+ */
+struct spdk_nvme_tcp_c2h_data_hdr {
+	struct spdk_nvme_tcp_common_pdu_hdr	common;
+	uint16_t				cccid;
+	uint8_t					reserved10[2];
+	uint32_t				datao;
+	uint32_t				datal;
+	uint8_t					reserved20[4];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_tcp_c2h_data_hdr) == 24, "Incorrect size");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_c2h_data_hdr, cccid) == 8, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_c2h_data_hdr, datao) == 12, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_c2h_data_hdr, datal) == 16, "Incorrect offset");
+
+#define SPDK_NVME_TCP_C2H_DATA_FLAGS_SUCCESS	(1u << 3)
+#define SPDK_NVME_TCP_C2H_DATA_FLAGS_LAST_PDU	(1u << 2)
+#define SPDK_NVME_TCP_C2H_DATA_PDO_MULT		8u
+
+/**
+ * R2T
+ *
+ * common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_R2T
+ */
+struct spdk_nvme_tcp_r2t_hdr {
+	struct spdk_nvme_tcp_common_pdu_hdr	common;
+	uint16_t				cccid;
+	uint16_t				ttag;
+	uint32_t				r2to;
+	uint32_t				r2tl;
+	uint8_t					reserved20[4];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_tcp_r2t_hdr) == 24, "Incorrect size");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_r2t_hdr, cccid) == 8, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_r2t_hdr, ttag) == 10, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_r2t_hdr, r2to) == 12, "Incorrect offset");
+SPDK_STATIC_ASSERT(offsetof(struct spdk_nvme_tcp_r2t_hdr, r2tl) == 16, "Incorrect offset");
+
+#pragma pack(pop)
+
+#endif /* __NVMF_SPEC_H__ */