summaryrefslogtreecommitdiffstats
path: root/src/spdk/include
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 18:24:20 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 18:24:20 +0000
commit483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch)
treee5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/spdk/include
parentInitial commit. (diff)
downloadceph-upstream.tar.xz
ceph-upstream.zip
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/spdk/include/Makefile51
-rw-r--r--src/spdk/include/linux/virtio_blk.h147
-rw-r--r--src/spdk/include/linux/virtio_config.h74
-rw-r--r--src/spdk/include/linux/virtio_pci.h199
-rw-r--r--src/spdk/include/linux/virtio_scsi.h172
-rw-r--r--src/spdk/include/linux/virtio_types.h46
-rw-r--r--src/spdk/include/spdk/assert.h65
-rw-r--r--src/spdk/include/spdk/barrier.h127
-rw-r--r--src/spdk/include/spdk/base64.h138
-rw-r--r--src/spdk/include/spdk/bdev.h1082
-rw-r--r--src/spdk/include/spdk/bdev_module.h977
-rw-r--r--src/spdk/include/spdk/bit_array.h180
-rw-r--r--src/spdk/include/spdk/blob.h854
-rw-r--r--src/spdk/include/spdk/blob_bdev.h78
-rw-r--r--src/spdk/include/spdk/blobfs.h406
-rw-r--r--src/spdk/include/spdk/conf.h208
-rw-r--r--src/spdk/include/spdk/copy_engine.h147
-rw-r--r--src/spdk/include/spdk/cpuset.h164
-rw-r--r--src/spdk/include/spdk/crc16.h66
-rw-r--r--src/spdk/include/spdk/crc32.h108
-rw-r--r--src/spdk/include/spdk/endian.h178
-rw-r--r--src/spdk/include/spdk/env.h1083
-rw-r--r--src/spdk/include/spdk/event.h302
-rw-r--r--src/spdk/include/spdk/fd.h69
-rw-r--r--src/spdk/include/spdk/gpt_spec.h144
-rw-r--r--src/spdk/include/spdk/histogram_data.h247
-rw-r--r--src/spdk/include/spdk/io_channel.h48
-rw-r--r--src/spdk/include/spdk/ioat.h174
-rw-r--r--src/spdk/include/spdk/ioat_spec.h330
-rw-r--r--src/spdk/include/spdk/iscsi_spec.h567
-rw-r--r--src/spdk/include/spdk/json.h337
-rw-r--r--src/spdk/include/spdk/jsonrpc.h265
-rw-r--r--src/spdk/include/spdk/likely.h46
-rw-r--r--src/spdk/include/spdk/log.h189
-rw-r--r--src/spdk/include/spdk/lvol.h282
-rw-r--r--src/spdk/include/spdk/mmio.h139
-rw-r--r--src/spdk/include/spdk/nbd.h91
-rw-r--r--src/spdk/include/spdk/net.h101
-rw-r--r--src/spdk/include/spdk/nvme.h2043
-rw-r--r--src/spdk/include/spdk/nvme_intel.h212
-rw-r--r--src/spdk/include/spdk/nvme_ocssd.h227
-rw-r--r--src/spdk/include/spdk/nvme_ocssd_spec.h414
-rw-r--r--src/spdk/include/spdk/nvme_spec.h2414
-rw-r--r--src/spdk/include/spdk/nvmf.h799
-rw-r--r--src/spdk/include/spdk/nvmf_fc_spec.h403
-rw-r--r--src/spdk/include/spdk/nvmf_spec.h472
-rw-r--r--src/spdk/include/spdk/pci_ids.h127
-rw-r--r--src/spdk/include/spdk/queue.h57
-rw-r--r--src/spdk/include/spdk/queue_extras.h341
-rw-r--r--src/spdk/include/spdk/rpc.h106
-rw-r--r--src/spdk/include/spdk/scsi.h517
-rw-r--r--src/spdk/include/spdk/scsi_spec.h508
-rw-r--r--src/spdk/include/spdk/sock.h248
-rw-r--r--src/spdk/include/spdk/stdinc.h96
-rw-r--r--src/spdk/include/spdk/string.h207
-rw-r--r--src/spdk/include/spdk/thread.h431
-rw-r--r--src/spdk/include/spdk/trace.h319
-rw-r--r--src/spdk/include/spdk/util.h89
-rw-r--r--src/spdk/include/spdk/uuid.h100
-rw-r--r--src/spdk/include/spdk/version.h110
-rw-r--r--src/spdk/include/spdk/vhost.h336
-rw-r--r--src/spdk/include/spdk_internal/assert.h55
-rw-r--r--src/spdk/include/spdk_internal/copy_engine.h95
-rw-r--r--src/spdk/include/spdk_internal/event.h133
-rw-r--r--src/spdk/include/spdk_internal/log.h101
-rw-r--r--src/spdk/include/spdk_internal/lvolstore.h124
-rw-r--r--src/spdk/include/spdk_internal/mock.h117
-rw-r--r--src/spdk/include/spdk_internal/sock.h109
-rw-r--r--src/spdk/include/spdk_internal/utf.h325
-rw-r--r--src/spdk/include/spdk_internal/virtio.h490
70 files changed, 22006 insertions, 0 deletions
diff --git a/src/spdk/include/Makefile b/src/spdk/include/Makefile
new file mode 100644
index 00000000..26082698
--- /dev/null
+++ b/src/spdk/include/Makefile
@@ -0,0 +1,51 @@
+#
+# BSD LICENSE
+#
+# Copyright (c) Intel Corporation.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+SPDK_ROOT_DIR := $(abspath $(CURDIR)/..)
+include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
+
+HEADERS := $(wildcard $(SPDK_ROOT_DIR)/include/spdk/*.h)
+INSTALLED_HEADERS := $(patsubst $(SPDK_ROOT_DIR)/include%,$(DESTDIR)$(includedir)%,$(HEADERS))
+
+$(DESTDIR)$(includedir)%.h:
+ $(INSTALL_HEADER)
+
+all:
+ @:
+
+clean:
+ @:
+
+install: $(INSTALLED_HEADERS)
+
+include $(SPDK_ROOT_DIR)/mk/spdk.deps.mk
diff --git a/src/spdk/include/linux/virtio_blk.h b/src/spdk/include/linux/virtio_blk.h
new file mode 100644
index 00000000..acab5ebb
--- /dev/null
+++ b/src/spdk/include/linux/virtio_blk.h
@@ -0,0 +1,147 @@
+#ifndef _LINUX_VIRTIO_BLK_H
+#define _LINUX_VIRTIO_BLK_H
+/* This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+#include <linux/types.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_types.h>
+
+/* Feature bits */
+#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */
+#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */
+#define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */
+#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
+#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available */
+#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */
+#define VIRTIO_BLK_F_MQ 12 /* support more than one vq */
+
+/* Legacy feature bits */
+#ifndef VIRTIO_BLK_NO_LEGACY
+#define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */
+#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
+#define VIRTIO_BLK_F_FLUSH 9 /* Flush command supported */
+#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */
+/* Old (deprecated) name for VIRTIO_BLK_F_FLUSH. */
+#define VIRTIO_BLK_F_WCE VIRTIO_BLK_F_FLUSH
+#endif /* !VIRTIO_BLK_NO_LEGACY */
+
+#define VIRTIO_BLK_ID_BYTES 20 /* ID string length */
+
+struct virtio_blk_config {
+ /* The capacity (in 512-byte sectors). */
+ __u64 capacity;
+ /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */
+ __u32 size_max;
+ /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
+ __u32 seg_max;
+ /* geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */
+ struct virtio_blk_geometry {
+ __u16 cylinders;
+ __u8 heads;
+ __u8 sectors;
+ } geometry;
+
+ /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
+ __u32 blk_size;
+
+ /* the next 4 entries are guarded by VIRTIO_BLK_F_TOPOLOGY */
+ /* exponent for physical block per logical block. */
+ __u8 physical_block_exp;
+ /* alignment offset in logical blocks. */
+ __u8 alignment_offset;
+ /* minimum I/O size without performance penalty in logical blocks. */
+ __u16 min_io_size;
+ /* optimal sustained I/O size in logical blocks. */
+ __u32 opt_io_size;
+
+ /* writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */
+ __u8 wce;
+ __u8 unused;
+
+ /* number of vqs, only available when VIRTIO_BLK_F_MQ is set */
+ __u16 num_queues;
+} __attribute__((packed));
+
+/*
+ * Command types
+ *
+ * Usage is a bit tricky as some bits are used as flags and some are not.
+ *
+ * Rules:
+ * VIRTIO_BLK_T_OUT may be combined with VIRTIO_BLK_T_SCSI_CMD or
+ * VIRTIO_BLK_T_BARRIER. VIRTIO_BLK_T_FLUSH is a command of its own
+ * and may not be combined with any of the other flags.
+ */
+
+/* These two define direction. */
+#define VIRTIO_BLK_T_IN 0
+#define VIRTIO_BLK_T_OUT 1
+
+#ifndef VIRTIO_BLK_NO_LEGACY
+/* This bit says it's a scsi command, not an actual read or write. */
+#define VIRTIO_BLK_T_SCSI_CMD 2
+#endif /* VIRTIO_BLK_NO_LEGACY */
+
+/* Cache flush command */
+#define VIRTIO_BLK_T_FLUSH 4
+
+/* Get device ID command */
+#define VIRTIO_BLK_T_GET_ID 8
+
+#ifndef VIRTIO_BLK_NO_LEGACY
+/* Barrier before this op. */
+#define VIRTIO_BLK_T_BARRIER 0x80000000
+#endif /* !VIRTIO_BLK_NO_LEGACY */
+
+/*
+ * This comes first in the read scatter-gather list.
+ * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated,
+ * this is the first element of the read scatter-gather list.
+ */
+struct virtio_blk_outhdr {
+ /* VIRTIO_BLK_T* */
+ __virtio32 type;
+ /* io priority. */
+ __virtio32 ioprio;
+ /* Sector (ie. 512 byte offset) */
+ __virtio64 sector;
+};
+
+#ifndef VIRTIO_BLK_NO_LEGACY
+struct virtio_scsi_inhdr {
+ __virtio32 errors;
+ __virtio32 data_len;
+ __virtio32 sense_len;
+ __virtio32 residual;
+};
+#endif /* !VIRTIO_BLK_NO_LEGACY */
+
+/* And this is the final byte of the write scatter-gather list. */
+#define VIRTIO_BLK_S_OK 0
+#define VIRTIO_BLK_S_IOERR 1
+#define VIRTIO_BLK_S_UNSUPP 2
+#endif /* _LINUX_VIRTIO_BLK_H */
diff --git a/src/spdk/include/linux/virtio_config.h b/src/spdk/include/linux/virtio_config.h
new file mode 100644
index 00000000..648b688f
--- /dev/null
+++ b/src/spdk/include/linux/virtio_config.h
@@ -0,0 +1,74 @@
+#ifndef _LINUX_VIRTIO_CONFIG_H
+#define _LINUX_VIRTIO_CONFIG_H
+/* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
+ * anyone can use the definitions to implement compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+
+/* Virtio devices use a standardized configuration space to define their
+ * features and pass configuration information, but each implementation can
+ * store and access that space differently. */
+#include <linux/types.h>
+
+/* Status byte for guest to report progress, and synchronize features. */
+/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
+/* We have found a driver for the device. */
+#define VIRTIO_CONFIG_S_DRIVER 2
+/* Driver has used its parts of the config, and is happy */
+#define VIRTIO_CONFIG_S_DRIVER_OK 4
+/* Driver has finished configuring features */
+#define VIRTIO_CONFIG_S_FEATURES_OK 8
+/* Device entered invalid state, driver must reset it */
+#define VIRTIO_CONFIG_S_NEEDS_RESET 0x40
+/* We've given up on this device. */
+#define VIRTIO_CONFIG_S_FAILED 0x80
+
+/* Some virtio feature bits (currently bits 28 through 32) are reserved for the
+ * transport being used (eg. virtio_ring), the rest are per-device feature
+ * bits. */
+#define VIRTIO_TRANSPORT_F_START 28
+#define VIRTIO_TRANSPORT_F_END 34
+
+#ifndef VIRTIO_CONFIG_NO_LEGACY
+/* Do we get callbacks when the ring is completely used, even if we've
+ * suppressed them? */
+#define VIRTIO_F_NOTIFY_ON_EMPTY 24
+
+/* Can the device handle any descriptor layout? */
+#define VIRTIO_F_ANY_LAYOUT 27
+#endif /* VIRTIO_CONFIG_NO_LEGACY */
+
+/* v1.0 compliant. */
+#define VIRTIO_F_VERSION_1 32
+
+/*
+ * If clear - device has the IOMMU bypass quirk feature.
+ * If set - use platform tools to detect the IOMMU.
+ *
+ * Note the reverse polarity (compared to most other features),
+ * this is for compatibility with legacy systems.
+ */
+#define VIRTIO_F_IOMMU_PLATFORM 33
+#endif /* _LINUX_VIRTIO_CONFIG_H */
diff --git a/src/spdk/include/linux/virtio_pci.h b/src/spdk/include/linux/virtio_pci.h
new file mode 100644
index 00000000..90007a1a
--- /dev/null
+++ b/src/spdk/include/linux/virtio_pci.h
@@ -0,0 +1,199 @@
+/*
+ * Virtio PCI driver
+ *
+ * This module allows virtio devices to be used over a virtual PCI device.
+ * This can be used with QEMU based VMMs like KVM or Xen.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_VIRTIO_PCI_H
+#define _LINUX_VIRTIO_PCI_H
+
+#include <linux/types.h>
+
+#ifndef VIRTIO_PCI_NO_LEGACY
+
+/* A 32-bit r/o bitmask of the features supported by the host */
+#define VIRTIO_PCI_HOST_FEATURES 0
+
+/* A 32-bit r/w bitmask of features activated by the guest */
+#define VIRTIO_PCI_GUEST_FEATURES 4
+
+/* A 32-bit r/w PFN for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_PFN 8
+
+/* A 16-bit r/o queue size for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_NUM 12
+
+/* A 16-bit r/w queue selector */
+#define VIRTIO_PCI_QUEUE_SEL 14
+
+/* A 16-bit r/w queue notifier */
+#define VIRTIO_PCI_QUEUE_NOTIFY 16
+
+/* An 8-bit device status register. */
+#define VIRTIO_PCI_STATUS 18
+
+/* An 8-bit r/o interrupt status register. Reading the value will return the
+ * current contents of the ISR and will also clear it. This is effectively
+ * a read-and-acknowledge. */
+#define VIRTIO_PCI_ISR 19
+
+/* MSI-X registers: only enabled if MSI-X is enabled. */
+/* A 16-bit vector for configuration changes. */
+#define VIRTIO_MSI_CONFIG_VECTOR 20
+/* A 16-bit vector for selected queue notifications. */
+#define VIRTIO_MSI_QUEUE_VECTOR 22
+
+/* The remaining space is defined by each driver as the per-driver
+ * configuration space */
+#define VIRTIO_PCI_CONFIG_OFF(msix_enabled) ((msix_enabled) ? 24 : 20)
+/* Deprecated: please use VIRTIO_PCI_CONFIG_OFF instead */
+#define VIRTIO_PCI_CONFIG(dev) VIRTIO_PCI_CONFIG_OFF((dev)->msix_enabled)
+
+/* Virtio ABI version, this must match exactly */
+#define VIRTIO_PCI_ABI_VERSION 0
+
+/* How many bits to shift physical queue address written to QUEUE_PFN.
+ * 12 is historical, and due to x86 page size. */
+#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12
+
+/* The alignment to use between consumer and producer parts of vring.
+ * x86 pagesize again. */
+#define VIRTIO_PCI_VRING_ALIGN 4096
+
+#endif /* VIRTIO_PCI_NO_LEGACY */
+
+/* The bit of the ISR which indicates a device configuration change. */
+#define VIRTIO_PCI_ISR_CONFIG 0x2
+/* Vector value used to disable MSI for queue */
+#define VIRTIO_MSI_NO_VECTOR 0xffff
+
+#ifndef VIRTIO_PCI_NO_MODERN
+
+/* IDs for different capabilities. Must all exist. */
+
+/* Common configuration */
+#define VIRTIO_PCI_CAP_COMMON_CFG 1
+/* Notifications */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
+/* ISR access */
+#define VIRTIO_PCI_CAP_ISR_CFG 3
+/* Device specific configuration */
+#define VIRTIO_PCI_CAP_DEVICE_CFG 4
+/* PCI configuration access */
+#define VIRTIO_PCI_CAP_PCI_CFG 5
+
+/* This is the PCI capability header: */
+struct virtio_pci_cap {
+ __u8 cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */
+ __u8 cap_next; /* Generic PCI field: next ptr. */
+ __u8 cap_len; /* Generic PCI field: capability length */
+ __u8 cfg_type; /* Identifies the structure. */
+ __u8 bar; /* Where to find it. */
+ __u8 padding[3]; /* Pad to full dword. */
+ __le32 offset; /* Offset within bar. */
+ __le32 length; /* Length of the structure, in bytes. */
+};
+
+struct virtio_pci_notify_cap {
+ struct virtio_pci_cap cap;
+ __le32 notify_off_multiplier; /* Multiplier for queue_notify_off. */
+};
+
+/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */
+struct virtio_pci_common_cfg {
+ /* About the whole device. */
+ __le32 device_feature_select; /* read-write */
+ __le32 device_feature; /* read-only */
+ __le32 guest_feature_select; /* read-write */
+ __le32 guest_feature; /* read-write */
+ __le16 msix_config; /* read-write */
+ __le16 num_queues; /* read-only */
+ __u8 device_status; /* read-write */
+ __u8 config_generation; /* read-only */
+
+ /* About a specific virtqueue. */
+ __le16 queue_select; /* read-write */
+ __le16 queue_size; /* read-write, power of 2. */
+ __le16 queue_msix_vector; /* read-write */
+ __le16 queue_enable; /* read-write */
+ __le16 queue_notify_off; /* read-only */
+ __le32 queue_desc_lo; /* read-write */
+ __le32 queue_desc_hi; /* read-write */
+ __le32 queue_avail_lo; /* read-write */
+ __le32 queue_avail_hi; /* read-write */
+ __le32 queue_used_lo; /* read-write */
+ __le32 queue_used_hi; /* read-write */
+};
+
+/* Fields in VIRTIO_PCI_CAP_PCI_CFG: */
+struct virtio_pci_cfg_cap {
+ struct virtio_pci_cap cap;
+ __u8 pci_cfg_data[4]; /* Data for BAR access. */
+};
+
+/* Macro versions of offsets for the Old Timers! */
+#define VIRTIO_PCI_CAP_VNDR 0
+#define VIRTIO_PCI_CAP_NEXT 1
+#define VIRTIO_PCI_CAP_LEN 2
+#define VIRTIO_PCI_CAP_CFG_TYPE 3
+#define VIRTIO_PCI_CAP_BAR 4
+#define VIRTIO_PCI_CAP_OFFSET 8
+#define VIRTIO_PCI_CAP_LENGTH 12
+
+#define VIRTIO_PCI_NOTIFY_CAP_MULT 16
+
+#define VIRTIO_PCI_COMMON_DFSELECT 0
+#define VIRTIO_PCI_COMMON_DF 4
+#define VIRTIO_PCI_COMMON_GFSELECT 8
+#define VIRTIO_PCI_COMMON_GF 12
+#define VIRTIO_PCI_COMMON_MSIX 16
+#define VIRTIO_PCI_COMMON_NUMQ 18
+#define VIRTIO_PCI_COMMON_STATUS 20
+#define VIRTIO_PCI_COMMON_CFGGENERATION 21
+#define VIRTIO_PCI_COMMON_Q_SELECT 22
+#define VIRTIO_PCI_COMMON_Q_SIZE 24
+#define VIRTIO_PCI_COMMON_Q_MSIX 26
+#define VIRTIO_PCI_COMMON_Q_ENABLE 28
+#define VIRTIO_PCI_COMMON_Q_NOFF 30
+#define VIRTIO_PCI_COMMON_Q_DESCLO 32
+#define VIRTIO_PCI_COMMON_Q_DESCHI 36
+#define VIRTIO_PCI_COMMON_Q_AVAILLO 40
+#define VIRTIO_PCI_COMMON_Q_AVAILHI 44
+#define VIRTIO_PCI_COMMON_Q_USEDLO 48
+#define VIRTIO_PCI_COMMON_Q_USEDHI 52
+
+#endif /* VIRTIO_PCI_NO_MODERN */
+
+#endif
diff --git a/src/spdk/include/linux/virtio_scsi.h b/src/spdk/include/linux/virtio_scsi.h
new file mode 100644
index 00000000..cc18ef88
--- /dev/null
+++ b/src/spdk/include/linux/virtio_scsi.h
@@ -0,0 +1,172 @@
+/*
+ * This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_VIRTIO_SCSI_H
+#define _LINUX_VIRTIO_SCSI_H
+
+#include <linux/virtio_types.h>
+
+/* Default values of the CDB and sense data size configuration fields */
+#define VIRTIO_SCSI_CDB_DEFAULT_SIZE 32
+#define VIRTIO_SCSI_SENSE_DEFAULT_SIZE 96
+
+#ifndef VIRTIO_SCSI_CDB_SIZE
+#define VIRTIO_SCSI_CDB_SIZE VIRTIO_SCSI_CDB_DEFAULT_SIZE
+#endif
+#ifndef VIRTIO_SCSI_SENSE_SIZE
+#define VIRTIO_SCSI_SENSE_SIZE VIRTIO_SCSI_SENSE_DEFAULT_SIZE
+#endif
+
+/* SCSI command request, followed by data-out */
+struct virtio_scsi_cmd_req {
+ __u8 lun[8]; /* Logical Unit Number */
+ __virtio64 tag; /* Command identifier */
+ __u8 task_attr; /* Task attribute */
+ __u8 prio; /* SAM command priority field */
+ __u8 crn;
+ __u8 cdb[VIRTIO_SCSI_CDB_SIZE];
+} __attribute__((packed));
+
+/* SCSI command request, followed by protection information */
+struct virtio_scsi_cmd_req_pi {
+ __u8 lun[8]; /* Logical Unit Number */
+ __virtio64 tag; /* Command identifier */
+ __u8 task_attr; /* Task attribute */
+ __u8 prio; /* SAM command priority field */
+ __u8 crn;
+ __virtio32 pi_bytesout; /* DataOUT PI Number of bytes */
+ __virtio32 pi_bytesin; /* DataIN PI Number of bytes */
+ __u8 cdb[VIRTIO_SCSI_CDB_SIZE];
+} __attribute__((packed));
+
+/* Response, followed by sense data and data-in */
+struct virtio_scsi_cmd_resp {
+ __virtio32 sense_len; /* Sense data length */
+ __virtio32 resid; /* Residual bytes in data buffer */
+ __virtio16 status_qualifier; /* Status qualifier */
+ __u8 status; /* Command completion status */
+ __u8 response; /* Response values */
+ __u8 sense[VIRTIO_SCSI_SENSE_SIZE];
+} __attribute__((packed));
+
+/* Task Management Request */
+struct virtio_scsi_ctrl_tmf_req {
+ __virtio32 type;
+ __virtio32 subtype;
+ __u8 lun[8];
+ __virtio64 tag;
+} __attribute__((packed));
+
+struct virtio_scsi_ctrl_tmf_resp {
+ __u8 response;
+} __attribute__((packed));
+
+/* Asynchronous notification query/subscription */
+struct virtio_scsi_ctrl_an_req {
+ __virtio32 type;
+ __u8 lun[8];
+ __virtio32 event_requested;
+} __attribute__((packed));
+
+struct virtio_scsi_ctrl_an_resp {
+ __virtio32 event_actual;
+ __u8 response;
+} __attribute__((packed));
+
+struct virtio_scsi_event {
+ __virtio32 event;
+ __u8 lun[8];
+ __virtio32 reason;
+} __attribute__((packed));
+
+struct virtio_scsi_config {
+ __u32 num_queues;
+ __u32 seg_max;
+ __u32 max_sectors;
+ __u32 cmd_per_lun;
+ __u32 event_info_size;
+ __u32 sense_size;
+ __u32 cdb_size;
+ __u16 max_channel;
+ __u16 max_target;
+ __u32 max_lun;
+} __attribute__((packed));
+
+/* Feature Bits */
+#define VIRTIO_SCSI_F_INOUT 0
+#define VIRTIO_SCSI_F_HOTPLUG 1
+#define VIRTIO_SCSI_F_CHANGE 2
+#define VIRTIO_SCSI_F_T10_PI 3
+
+/* Response codes */
+#define VIRTIO_SCSI_S_OK 0
+#define VIRTIO_SCSI_S_OVERRUN 1
+#define VIRTIO_SCSI_S_ABORTED 2
+#define VIRTIO_SCSI_S_BAD_TARGET 3
+#define VIRTIO_SCSI_S_RESET 4
+#define VIRTIO_SCSI_S_BUSY 5
+#define VIRTIO_SCSI_S_TRANSPORT_FAILURE 6
+#define VIRTIO_SCSI_S_TARGET_FAILURE 7
+#define VIRTIO_SCSI_S_NEXUS_FAILURE 8
+#define VIRTIO_SCSI_S_FAILURE 9
+#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED 10
+#define VIRTIO_SCSI_S_FUNCTION_REJECTED 11
+#define VIRTIO_SCSI_S_INCORRECT_LUN 12
+
+/* Controlq type codes. */
+#define VIRTIO_SCSI_T_TMF 0
+#define VIRTIO_SCSI_T_AN_QUERY 1
+#define VIRTIO_SCSI_T_AN_SUBSCRIBE 2
+
+/* Valid TMF subtypes. */
+#define VIRTIO_SCSI_T_TMF_ABORT_TASK 0
+#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET 1
+#define VIRTIO_SCSI_T_TMF_CLEAR_ACA 2
+#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET 3
+#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET 4
+#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET 5
+#define VIRTIO_SCSI_T_TMF_QUERY_TASK 6
+#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET 7
+
+/* Events. */
+#define VIRTIO_SCSI_T_EVENTS_MISSED 0x80000000
+#define VIRTIO_SCSI_T_NO_EVENT 0
+#define VIRTIO_SCSI_T_TRANSPORT_RESET 1
+#define VIRTIO_SCSI_T_ASYNC_NOTIFY 2
+#define VIRTIO_SCSI_T_PARAM_CHANGE 3
+
+/* Reasons of transport reset event */
+#define VIRTIO_SCSI_EVT_RESET_HARD 0
+#define VIRTIO_SCSI_EVT_RESET_RESCAN 1
+#define VIRTIO_SCSI_EVT_RESET_REMOVED 2
+
+#define VIRTIO_SCSI_S_SIMPLE 0
+#define VIRTIO_SCSI_S_ORDERED 1
+#define VIRTIO_SCSI_S_HEAD 2
+#define VIRTIO_SCSI_S_ACA 3
+
+
+#endif /* _LINUX_VIRTIO_SCSI_H */
diff --git a/src/spdk/include/linux/virtio_types.h b/src/spdk/include/linux/virtio_types.h
new file mode 100644
index 00000000..6162bdf0
--- /dev/null
+++ b/src/spdk/include/linux/virtio_types.h
@@ -0,0 +1,46 @@
+#ifndef _LINUX_VIRTIO_TYPES_H
+#define _LINUX_VIRTIO_TYPES_H
+/* Type definitions for virtio implementations.
+ *
+ * This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ */
+#include <linux/types.h>
+
+/*
+ * __virtio{16,32,64} have the following meaning:
+ * - __u{16,32,64} for virtio devices in legacy mode, accessed in native endian
+ * - __le{16,32,64} for standard-compliant virtio devices
+ */
+
+typedef __u16 __bitwise__ __virtio16;
+typedef __u32 __bitwise__ __virtio32;
+typedef __u64 __bitwise__ __virtio64;
+
+#endif /* _LINUX_VIRTIO_TYPES_H */
diff --git a/src/spdk/include/spdk/assert.h b/src/spdk/include/spdk/assert.h
new file mode 100644
index 00000000..67e674aa
--- /dev/null
+++ b/src/spdk/include/spdk/assert.h
@@ -0,0 +1,65 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Runtime and compile-time assert macros
+ */
+
+#ifndef SPDK_ASSERT_H
+#define SPDK_ASSERT_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef static_assert
+#define SPDK_STATIC_ASSERT(cond, msg) static_assert(cond, msg)
+#else
+/**
+ * Compatibility wrapper for static_assert.
+ *
+ * This won't actually enforce the condition when compiled with an environment that doesn't support
+ * C11 static_assert; it is only intended to allow end users with old compilers to build the package.
+ *
+ * Developers should use a recent compiler that provides static_assert.
+ */
+#define SPDK_STATIC_ASSERT(cond, msg)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_ASSERT_H */
diff --git a/src/spdk/include/spdk/barrier.h b/src/spdk/include/spdk/barrier.h
new file mode 100644
index 00000000..cd670abf
--- /dev/null
+++ b/src/spdk/include/spdk/barrier.h
@@ -0,0 +1,127 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * Copyright (c) 2017, IBM Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Memory barriers
+ */
+
+#ifndef SPDK_BARRIER_H
+#define SPDK_BARRIER_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Compiler memory barrier */
+#define spdk_compiler_barrier() __asm volatile("" ::: "memory")
+
+/** Write memory barrier */
+#ifdef __PPC64__
+#define spdk_wmb() __asm volatile("sync" ::: "memory")
+#elif defined(__aarch64__)
+#define spdk_wmb() __asm volatile("dsb st" ::: "memory")
+#elif defined(__i386__) || defined(__x86_64__)
+#define spdk_wmb() __asm volatile("sfence" ::: "memory")
+#else
+#define spdk_wmb()
+#error Unknown architecture
+#endif
+
+/** Read memory barrier */
+#ifdef __PPC64__
+#define spdk_rmb() __asm volatile("sync" ::: "memory")
+#elif defined(__aarch64__)
+#define spdk_rmb() __asm volatile("dsb ld" ::: "memory")
+#elif defined(__i386__) || defined(__x86_64__)
+#define spdk_rmb() __asm volatile("lfence" ::: "memory")
+#else
+#define spdk_rmb()
+#error Unknown architecture
+#endif
+
+/** Full read/write memory barrier */
+#ifdef __PPC64__
+#define spdk_mb() __asm volatile("sync" ::: "memory")
+#elif defined(__aarch64__)
+#define spdk_mb() __asm volatile("dsb sy" ::: "memory")
+#elif defined(__i386__) || defined(__x86_64__)
+#define spdk_mb() __asm volatile("mfence" ::: "memory")
+#else
+#define spdk_mb()
+#error Unknown architecture
+#endif
+
+/** SMP read memory barrier. */
+#ifdef __PPC64__
+#define spdk_smp_rmb() __asm volatile("lwsync" ::: "memory")
+#elif defined(__aarch64__)
+#define spdk_smp_rmb() __asm volatile("dmb ishld" ::: "memory")
+#elif defined(__i386__) || defined(__x86_64__)
+#define spdk_smp_rmb() spdk_compiler_barrier()
+#else
+#define spdk_smp_rmb()
+#error Unknown architecture
+#endif
+
+/** SMP write memory barrier. */
+#ifdef __PPC64__
+#define spdk_smp_wmb() __asm volatile("lwsync" ::: "memory")
+#elif defined(__aarch64__)
+#define spdk_smp_wmb() __asm volatile("dmb ishst" ::: "memory")
+#elif defined(__i386__) || defined(__x86_64__)
+#define spdk_smp_wmb() spdk_compiler_barrier()
+#else
+#define spdk_smp_wmb()
+#error Unknown architecture
+#endif
+
+/** SMP read/write memory barrier. */
+#ifdef __PPC64__
+#define spdk_smp_mb() spdk_mb()
+#elif defined(__aarch64__)
+#define spdk_smp_mb() __asm volatile("dmb ish" ::: "memory")
+#elif defined(__i386__) || defined(__x86_64__)
+#define spdk_smp_mb() spdk_mb()
+#else
+#define spdk_smp_mb()
+#error Unknown architecture
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/base64.h b/src/spdk/include/spdk/base64.h
new file mode 100644
index 00000000..c158c231
--- /dev/null
+++ b/src/spdk/include/spdk/base64.h
@@ -0,0 +1,138 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * Base64 utility functions
+ */
+
+#ifndef SPDK_BASE64_H
+#define SPDK_BASE64_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Following the Base64 part in RFC4648:
+ * https://tools.ietf.org/html/rfc4648.html
+ */
+
+/**
+ * Calculate strlen of encoded Base64 string based on raw buffer length.
+ *
+ * \param raw_len Length of raw buffer.
+ * \return Encoded Base64 string length, excluding the terminating null byte ('\0').
+ */
+static inline size_t spdk_base64_get_encoded_strlen(size_t raw_len)
+{
+ return (raw_len + 2) / 3 * 4;
+}
+
+/**
+ * Calculate length of raw buffer based on strlen of encoded Base64.
+ *
+ * \param encoded_strlen Length of enocded Base64 string, excluding terminating null byte ('\0').
+ * \return Length of raw buffer.
+ */
+static inline size_t spdk_base64_get_decoded_len(size_t encoded_strlen)
+{
+ /* text_strlen and raw_len should be (4n,3n), (4n+2, 3n+1) or (4n+3, 3n+2) */
+ return encoded_strlen / 4 * 3 + ((encoded_strlen % 4 + 1) / 2);
+}
+
+/**
+ * Base 64 Encoding with Standard Base64 Alphabet defined in RFC4684.
+ *
+ * \param dst Buffer address of encoded Base64 string. Its length should be enough
+ * to contain Base64 string and the terminating null byte ('\0'), so it needs to be at
+ * least as long as 1 + spdk_base64_get_encoded_strlen(src_len).
+ * \param src Raw data buffer to be encoded.
+ * \param src_len Length of raw data buffer.
+ *
+ * \return 0 on success.
+ * \return -EINVAL if dst or src is NULL, or binary_len <= 0.
+ */
+int spdk_base64_encode(char *dst, const void *src, size_t src_len);
+
+/**
+ * Base 64 Encoding with URL and Filename Safe Alphabet.
+ *
+ * \param dst Buffer address of encoded Base64 string. Its length should be enough
+ * to contain Base64 string and the terminating null byte ('\0'), so it needs to be at
+ * least as long as 1 + spdk_base64_get_encoded_strlen(src_len).
+ * \param src Raw data buffer to be encoded.
+ * \param src_len Length of raw data buffer.
+ *
+ * \return 0 on success.
+ * \return -EINVAL if dst or src is NULL, or binary_len <= 0.
+ */
+int spdk_base64_urlsafe_encode(char *dst, const void *src, size_t src_len);
+
+/**
+ * Base 64 Decoding with Standard Base64 Alphabet defined in RFC4684.
+ *
+ * \param dst Buffer address of decoded raw data. Its length should be enough
+ * to contain decoded raw data, so it needs to be at least as long as
+ * spdk_base64_get_decoded_len(encoded_strlen).
+ * \param dst_len Output parameter for the length of actual decoded raw data.
+ * If NULL, the actual decoded length won't be returned.
+ * \param src Data buffer for base64 string to be decoded.
+ *
+ * \return 0 on success.
+ * \return -EINVAL if dst or src is NULL, or content of src is illegal.
+ */
+int spdk_base64_decode(void *dst, size_t *dst_len, const char *src);
+
+/**
+ * Base 64 Decoding with URL and Filename Safe Alphabet.
+ *
+ * \param dst Buffer address of decoded raw data. Its length should be enough
+ * to contain decoded raw data, so it needs to be at least as long as
+ * spdk_base64_get_decoded_len(encoded_strlen).
+ * \param dst_len Output parameter for the length of actual decoded raw data.
+ * If NULL, the actual decoded length won't be returned.
+ * \param src Data buffer for base64 string to be decoded.
+ *
+ * \return 0 on success.
+ * \return -EINVAL if dst or src is NULL, or content of src is illegal.
+ */
+int spdk_base64_urlsafe_decode(void *dst, size_t *dst_len, const char *src);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_BASE64_H */
diff --git a/src/spdk/include/spdk/bdev.h b/src/spdk/include/spdk/bdev.h
new file mode 100644
index 00000000..097cca18
--- /dev/null
+++ b/src/spdk/include/spdk/bdev.h
@@ -0,0 +1,1082 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Block device abstraction layer
+ */
+
+#ifndef SPDK_BDEV_H_
+#define SPDK_BDEV_H_
+
+#include "spdk/stdinc.h"
+
+#include "spdk/scsi_spec.h"
+#include "spdk/nvme_spec.h"
+#include "spdk/json.h"
+#include "spdk/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPDK_BDEV_SMALL_BUF_MAX_SIZE 8192
+#define SPDK_BDEV_LARGE_BUF_MAX_SIZE (64 * 1024)
+
+/**
+ * Block device remove callback.
+ *
+ * \param remove_ctx Context for the removed block device.
+ */
+typedef void (*spdk_bdev_remove_cb_t)(void *remove_ctx);
+
+/**
+ * Block device I/O
+ *
+ * This is an I/O that is passed to an spdk_bdev.
+ */
+struct spdk_bdev_io;
+
+struct spdk_bdev_fn_table;
+struct spdk_io_channel;
+struct spdk_json_write_ctx;
+struct spdk_uuid;
+
+/** bdev status */
+enum spdk_bdev_status {
+ SPDK_BDEV_STATUS_INVALID,
+ SPDK_BDEV_STATUS_READY,
+ SPDK_BDEV_STATUS_REMOVING,
+};
+
+/**
+ * \brief SPDK block device.
+ *
+ * This is a virtual representation of a block device that is exported by the backend.
+ */
+struct spdk_bdev;
+
+/**
+ * \brief Handle to an opened SPDK block device.
+ */
+struct spdk_bdev_desc;
+
+/** bdev I/O type */
+enum spdk_bdev_io_type {
+ SPDK_BDEV_IO_TYPE_INVALID = 0,
+ SPDK_BDEV_IO_TYPE_READ,
+ SPDK_BDEV_IO_TYPE_WRITE,
+ SPDK_BDEV_IO_TYPE_UNMAP,
+ SPDK_BDEV_IO_TYPE_FLUSH,
+ SPDK_BDEV_IO_TYPE_RESET,
+ SPDK_BDEV_IO_TYPE_NVME_ADMIN,
+ SPDK_BDEV_IO_TYPE_NVME_IO,
+ SPDK_BDEV_IO_TYPE_NVME_IO_MD,
+ SPDK_BDEV_IO_TYPE_WRITE_ZEROES,
+ SPDK_BDEV_NUM_IO_TYPES /* Keep last */
+};
+
+/** bdev QoS rate limit type */
+enum spdk_bdev_qos_rate_limit_type {
+ /** IOPS rate limit for both read and write */
+ SPDK_BDEV_QOS_RW_IOPS_RATE_LIMIT = 0,
+ /** Byte per second rate limit for both read and write */
+ SPDK_BDEV_QOS_RW_BPS_RATE_LIMIT,
+ /** Keep last */
+ SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES
+};
+
+/**
+ * Block device completion callback.
+ *
+ * \param bdev_io Block device I/O that has completed.
+ * \param success True if I/O completed successfully or false if it failed;
+ * additional error information may be retrieved from bdev_io by calling
+ * spdk_bdev_io_get_nvme_status() or spdk_bdev_io_get_scsi_status().
+ * \param cb_arg Callback argument specified when bdev_io was submitted.
+ */
+typedef void (*spdk_bdev_io_completion_cb)(struct spdk_bdev_io *bdev_io,
+ bool success,
+ void *cb_arg);
+
+struct spdk_bdev_io_stat {
+ uint64_t bytes_read;
+ uint64_t num_read_ops;
+ uint64_t bytes_written;
+ uint64_t num_write_ops;
+ uint64_t read_latency_ticks;
+ uint64_t write_latency_ticks;
+ uint64_t ticks_rate;
+};
+
+struct spdk_bdev_opts {
+ uint32_t bdev_io_pool_size;
+ uint32_t bdev_io_cache_size;
+};
+
+void spdk_bdev_get_opts(struct spdk_bdev_opts *opts);
+
+int spdk_bdev_set_opts(struct spdk_bdev_opts *opts);
+
+/**
+ * Block device initialization callback.
+ *
+ * \param cb_arg Callback argument.
+ * \param rc 0 if block device initialized successfully or negative errno if it failed.
+ */
+typedef void (*spdk_bdev_init_cb)(void *cb_arg, int rc);
+
+/**
+ * Block device finish callback.
+ *
+ * \param cb_arg Callback argument.
+ */
+typedef void (*spdk_bdev_fini_cb)(void *cb_arg);
+typedef void (*spdk_bdev_get_device_stat_cb)(struct spdk_bdev *bdev,
+ struct spdk_bdev_io_stat *stat, void *cb_arg, int rc);
+
+/**
+ * Initialize block device modules.
+ *
+ * \param cb_fn Called when the initialization is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bdev_initialize(spdk_bdev_init_cb cb_fn, void *cb_arg);
+
+/**
+ * Perform cleanup work to remove the registered block device modules.
+ *
+ * \param cb_fn Called when the removal is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bdev_finish(spdk_bdev_fini_cb cb_fn, void *cb_arg);
+
+/**
+ * Get the configuration options for the registered block device modules.
+ *
+ * \param fp The pointer to a file that will be written to the configuration options.
+ */
+void spdk_bdev_config_text(FILE *fp);
+
+/**
+ * Get the full configuration options for the registered block device modules and created bdevs.
+ *
+ * \param w pointer to a JSON write context where the configuration will be written.
+ */
+void spdk_bdev_subsystem_config_json(struct spdk_json_write_ctx *w);
+
+/**
+ * Get block device by the block device name.
+ *
+ * \param bdev_name The name of the block device.
+ * \return Block device associated with the name or NULL if no block device with
+ * bdev_name is currently registered.
+ */
+struct spdk_bdev *spdk_bdev_get_by_name(const char *bdev_name);
+
+/**
+ * Get the first registered block device.
+ *
+ * \return The first registered block device.
+ */
+struct spdk_bdev *spdk_bdev_first(void);
+
+/**
+ * Get the next registered block device.
+ *
+ * \param prev The current block device.
+ * \return The next registered block device.
+ */
+struct spdk_bdev *spdk_bdev_next(struct spdk_bdev *prev);
+
+/**
+ * Get the first block device without virtual block devices on top.
+ *
+ * This function only traverses over block devices which have no virtual block
+ * devices on top of them, then get the first one.
+ *
+ * \return The first block device without virtual block devices on top.
+ */
+struct spdk_bdev *spdk_bdev_first_leaf(void);
+
+/**
+ * Get the next block device without virtual block devices on top.
+ *
+ * This function only traverses over block devices which have no virtual block
+ * devices on top of them, then get the next one.
+ *
+ * \param prev The current block device.
+ * \return The next block device without virtual block devices on top.
+ */
+struct spdk_bdev *spdk_bdev_next_leaf(struct spdk_bdev *prev);
+
+/**
+ * Open a block device for I/O operations.
+ *
+ * \param bdev Block device to open.
+ * \param write true is read/write access requested, false if read-only
+ * \param remove_cb callback function for hot remove the device. Will
+ * always be called on the same thread that spdk_bdev_open() was called on.
+ * \param remove_ctx param for hot removal callback function.
+ * \param desc output parameter for the descriptor when operation is successful
+ * \return 0 if operation is successful, suitable errno value otherwise
+ */
+int spdk_bdev_open(struct spdk_bdev *bdev, bool write, spdk_bdev_remove_cb_t remove_cb,
+ void *remove_ctx, struct spdk_bdev_desc **desc);
+
+/**
+ * Close a previously opened block device.
+ *
+ * Must be called on the same thread that the spdk_bdev_open()
+ * was performed on.
+ *
+ * \param desc Block device descriptor to close.
+ */
+void spdk_bdev_close(struct spdk_bdev_desc *desc);
+
+/**
+ * Get the bdev associated with a bdev descriptor.
+ *
+ * \param desc Open block device desciptor
+ * \return bdev associated with the descriptor
+ */
+struct spdk_bdev *spdk_bdev_desc_get_bdev(struct spdk_bdev_desc *desc);
+
+/**
+ * Check whether the block device supports the I/O type.
+ *
+ * \param bdev Block device to check.
+ * \param io_type The specific I/O type like read, write, flush, unmap.
+ * \return true if support, false otherwise.
+ */
+bool spdk_bdev_io_type_supported(struct spdk_bdev *bdev, enum spdk_bdev_io_type io_type);
+
+/**
+ * Output driver-specific information to a JSON stream.
+ *
+ * The JSON write context will be initialized with an open object, so the bdev
+ * driver should write a name(based on the driver name) followed by a JSON value
+ * (most likely another nested object).
+ *
+ * \param bdev Block device to query.
+ * \param w JSON write context. It will store the driver-specific configuration context.
+ * \return 0 on success, negated errno on failure.
+ */
+int spdk_bdev_dump_info_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w);
+
+/**
+ * Get block device name.
+ *
+ * \param bdev Block device to query.
+ * \return Name of bdev as a null-terminated string.
+ */
+const char *spdk_bdev_get_name(const struct spdk_bdev *bdev);
+
+/**
+ * Get block device product name.
+ *
+ * \param bdev Block device to query.
+ * \return Product name of bdev as a null-terminated string.
+ */
+const char *spdk_bdev_get_product_name(const struct spdk_bdev *bdev);
+
+/**
+ * Get block device logical block size.
+ *
+ * \param bdev Block device to query.
+ * \return Size of logical block for this bdev in bytes.
+ */
+uint32_t spdk_bdev_get_block_size(const struct spdk_bdev *bdev);
+
+/**
+ * Get size of block device in logical blocks.
+ *
+ * \param bdev Block device to query.
+ * \return Size of bdev in logical blocks.
+ *
+ * Logical blocks are numbered from 0 to spdk_bdev_get_num_blocks(bdev) - 1, inclusive.
+ */
+uint64_t spdk_bdev_get_num_blocks(const struct spdk_bdev *bdev);
+
+/**
+ * Get the string of quality of service rate limit.
+ *
+ * \param type Type of rate limit to query.
+ * \return String of QoS type.
+ */
+const char *spdk_bdev_get_qos_rpc_type(enum spdk_bdev_qos_rate_limit_type type);
+
+/**
+ * Get the quality of service rate limits on a bdev.
+ *
+ * \param bdev Block device to query.
+ * \param limits Pointer to the QoS rate limits array which holding the limits.
+ *
+ * The limits are ordered based on the @ref spdk_bdev_qos_rate_limit_type enum.
+ */
+void spdk_bdev_get_qos_rate_limits(struct spdk_bdev *bdev, uint64_t *limits);
+
+/**
+ * Set the quality of service rate limits on a bdev.
+ *
+ * \param bdev Block device.
+ * \param limits Pointer to the QoS rate limits array which holding the limits.
+ * \param cb_fn Callback function to be called when the QoS limit has been updated.
+ * \param cb_arg Argument to pass to cb_fn.
+ *
+ * The limits are ordered based on the @ref spdk_bdev_qos_rate_limit_type enum.
+ */
+void spdk_bdev_set_qos_rate_limits(struct spdk_bdev *bdev, uint64_t *limits,
+ void (*cb_fn)(void *cb_arg, int status), void *cb_arg);
+
+/**
+ * Get minimum I/O buffer address alignment for a bdev.
+ *
+ * \param bdev Block device to query.
+ * \return Required alignment of I/O buffers in bytes.
+ */
+size_t spdk_bdev_get_buf_align(const struct spdk_bdev *bdev);
+
+/**
+ * Get optimal I/O boundary for a bdev.
+ *
+ * \param bdev Block device to query.
+ * \return Optimal I/O boundary in blocks that should not be crossed for best performance, or 0 if
+ * no optimal boundary is reported.
+ */
+uint32_t spdk_bdev_get_optimal_io_boundary(const struct spdk_bdev *bdev);
+
+/**
+ * Query whether block device has an enabled write cache.
+ *
+ * \param bdev Block device to query.
+ * \return true if block device has a volatile write cache enabled.
+ *
+ * If this function returns true, written data may not be persistent until a flush command
+ * is issued.
+ */
+bool spdk_bdev_has_write_cache(const struct spdk_bdev *bdev);
+
+/**
+ * Get a bdev's UUID.
+ *
+ * \param bdev Block device to query.
+ * \return Pointer to UUID.
+ *
+ * Not all bdevs will have a UUID; in this case, the returned UUID will be
+ * the nil UUID (all bytes zero).
+ */
+const struct spdk_uuid *spdk_bdev_get_uuid(const struct spdk_bdev *bdev);
+
+/**
+ * Get the most recently measured queue depth from a bdev.
+ *
+ * The reported queue depth is the aggregate of outstanding I/O
+ * across all open channels associated with this bdev.
+ *
+ * \param bdev Block device to query.
+ *
+ * \return The most recent queue depth measurement for the bdev.
+ * If tracking is not enabled, the function will return UINT64_MAX
+ * It is also possible to receive UINT64_MAX after enabling tracking
+ * but before the first period has expired.
+ */
+uint64_t
+spdk_bdev_get_qd(const struct spdk_bdev *bdev);
+
+/**
+ * Get the queue depth polling period.
+ *
+ * The return value of this function is only valid if the bdev's
+ * queue depth tracking status is set to true.
+ *
+ * \param bdev Block device to query.
+ *
+ * \return The period at which this bdev's gueue depth is being refreshed.
+ */
+uint64_t
+spdk_bdev_get_qd_sampling_period(const struct spdk_bdev *bdev);
+
+/**
+ * Enable or disable queue depth sampling for this bdev.
+ *
+ * Enables queue depth sampling when period is greater than 0. Disables it when the period
+ * is equal to zero. The resulting queue depth is stored in the spdk_bdev object as
+ * measured_queue_depth.
+ *
+ * \param bdev Block device on which to enable queue depth tracking.
+ * \param period The period at which to poll this bdev's queue depth. If this is set
+ * to zero, polling will be disabled.
+ */
+void spdk_bdev_set_qd_sampling_period(struct spdk_bdev *bdev, uint64_t period);
+
+/**
+ * Get the time spent processing IO for this device.
+ *
+ * This value is dependent upon the queue depth sampling period and is
+ * incremented at sampling time by the sampling period only if the measured
+ * queue depth is greater than 0.
+ *
+ * The disk utilization can be calculated by the following formula:
+ * disk_util = (io_time_2 - io_time_1) / elapsed_time.
+ * The user is responsible for tracking the elapsed time between two measurements.
+ *
+ * \param bdev Block device to query.
+ *
+ * \return The io time for this device in microseconds.
+ */
+uint64_t spdk_bdev_get_io_time(const struct spdk_bdev *bdev);
+
+/**
+ * Get the weighted IO processing time for this bdev.
+ *
+ * This value is dependent upon the queue depth sampling period and is
+ * equal to the time spent reading from or writing to a device times
+ * the measured queue depth during each sampling period.
+ *
+ * The average queue depth can be calculated by the following formula:
+ * queue_depth = (weighted_io_time_2 - weighted_io_time_1) / elapsed_time.
+ * The user is responsible for tracking the elapsed time between two measurements.
+ *
+ * \param bdev Block device to query.
+ *
+ * \return The weighted io time for this device in microseconds.
+ */
+uint64_t spdk_bdev_get_weighted_io_time(const struct spdk_bdev *bdev);
+
+/**
+ * Obtain an I/O channel for the block device opened by the specified
+ * descriptor. I/O channels are bound to threads, so the resulting I/O
+ * channel may only be used from the thread it was originally obtained
+ * from.
+ *
+ * \param desc Block device descriptor.
+ *
+ * \return A handle to the I/O channel or NULL on failure.
+ */
+struct spdk_io_channel *spdk_bdev_get_io_channel(struct spdk_bdev_desc *desc);
+
+/**
+ * \defgroup bdev_io_submit_functions bdev I/O Submit Functions
+ *
+ * These functions submit a new I/O request to a bdev. The I/O request will
+ * be represented by an spdk_bdev_io structure allocated from a global pool.
+ * These functions will return -ENOMEM if the spdk_bdev_io pool is empty.
+ */
+
+/**
+ * Submit a read request to the bdev on the given channel.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param buf Data buffer to read into.
+ * \param offset The offset, in bytes, from the start of the block device.
+ * \param nbytes The number of bytes to read.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset and/or nbytes are not aligned or out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ */
+int spdk_bdev_read(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ void *buf, uint64_t offset, uint64_t nbytes,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit a read request to the bdev on the given channel.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param buf Data buffer to read into.
+ * \param offset_blocks The offset, in blocks, from the start of the block device.
+ * \param num_blocks The number of blocks to read.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset_blocks and/or num_blocks are out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ */
+int spdk_bdev_read_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ void *buf, uint64_t offset_blocks, uint64_t num_blocks,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit a read request to the bdev on the given channel. This differs from
+ * spdk_bdev_read by allowing the data buffer to be described in a scatter
+ * gather list. Some physical devices place memory alignment requirements on
+ * data and may not be able to directly transfer into the buffers provided. In
+ * this case, the request may fail.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param iov A scatter gather list of buffers to be read into.
+ * \param iovcnt The number of elements in iov.
+ * \param offset The offset, in bytes, from the start of the block device.
+ * \param nbytes The number of bytes to read.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset and/or nbytes are not aligned or out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ */
+int spdk_bdev_readv(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ struct iovec *iov, int iovcnt,
+ uint64_t offset, uint64_t nbytes,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit a read request to the bdev on the given channel. This differs from
+ * spdk_bdev_read by allowing the data buffer to be described in a scatter
+ * gather list. Some physical devices place memory alignment requirements on
+ * data and may not be able to directly transfer into the buffers provided. In
+ * this case, the request may fail.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param iov A scatter gather list of buffers to be read into.
+ * \param iovcnt The number of elements in iov.
+ * \param offset_blocks The offset, in blocks, from the start of the block device.
+ * \param num_blocks The number of blocks to read.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset_blocks and/or num_blocks are out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ */
+int spdk_bdev_readv_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ struct iovec *iov, int iovcnt,
+ uint64_t offset_blocks, uint64_t num_blocks,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit a write request to the bdev on the given channel.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param buf Data buffer to written from.
+ * \param offset The offset, in bytes, from the start of the block device.
+ * \param nbytes The number of bytes to write. buf must be greater than or equal to this size.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset and/or nbytes are not aligned or out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ * * -EBADF - desc not open for writing
+ */
+int spdk_bdev_write(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ void *buf, uint64_t offset, uint64_t nbytes,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit a write request to the bdev on the given channel.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param buf Data buffer to written from.
+ * \param offset_blocks The offset, in blocks, from the start of the block device.
+ * \param num_blocks The number of blocks to write. buf must be greater than or equal to this size.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset_blocks and/or num_blocks are out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ * * -EBADF - desc not open for writing
+ */
+int spdk_bdev_write_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ void *buf, uint64_t offset_blocks, uint64_t num_blocks,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit a write request to the bdev on the given channel. This differs from
+ * spdk_bdev_write by allowing the data buffer to be described in a scatter
+ * gather list. Some physical devices place memory alignment requirements on
+ * data and may not be able to directly transfer out of the buffers provided. In
+ * this case, the request may fail.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param iov A scatter gather list of buffers to be written from.
+ * \param iovcnt The number of elements in iov.
+ * \param offset The offset, in bytes, from the start of the block device.
+ * \param len The size of data to write.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset and/or nbytes are not aligned or out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ * * -EBADF - desc not open for writing
+ */
+int spdk_bdev_writev(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ struct iovec *iov, int iovcnt,
+ uint64_t offset, uint64_t len,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit a write request to the bdev on the given channel. This differs from
+ * spdk_bdev_write by allowing the data buffer to be described in a scatter
+ * gather list. Some physical devices place memory alignment requirements on
+ * data and may not be able to directly transfer out of the buffers provided. In
+ * this case, the request may fail.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param iov A scatter gather list of buffers to be written from.
+ * \param iovcnt The number of elements in iov.
+ * \param offset_blocks The offset, in blocks, from the start of the block device.
+ * \param num_blocks The number of blocks to write.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset_blocks and/or num_blocks are out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ * * -EBADF - desc not open for writing
+ */
+int spdk_bdev_writev_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ struct iovec *iov, int iovcnt,
+ uint64_t offset_blocks, uint64_t num_blocks,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit a write zeroes request to the bdev on the given channel. This command
+ * ensures that all bytes in the specified range are set to 00h
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param offset The offset, in bytes, from the start of the block device.
+ * \param len The size of data to zero.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset and/or nbytes are not aligned or out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ * * -EBADF - desc not open for writing
+ */
+int spdk_bdev_write_zeroes(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ uint64_t offset, uint64_t len,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit a write zeroes request to the bdev on the given channel. This command
+ * ensures that all bytes in the specified range are set to 00h
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param offset_blocks The offset, in blocks, from the start of the block device.
+ * \param num_blocks The number of blocks to zero.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset_blocks and/or num_blocks are out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ * * -EBADF - desc not open for writing
+ */
+int spdk_bdev_write_zeroes_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ uint64_t offset_blocks, uint64_t num_blocks,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit an unmap request to the block device. Unmap is sometimes also called trim or
+ * deallocate. This notifies the device that the data in the blocks described is no
+ * longer valid. Reading blocks that have been unmapped results in indeterminate data.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param offset The offset, in bytes, from the start of the block device.
+ * \param nbytes The number of bytes to unmap. Must be a multiple of the block size.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset and/or nbytes are not aligned or out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ * * -EBADF - desc not open for writing
+ */
+int spdk_bdev_unmap(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ uint64_t offset, uint64_t nbytes,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit an unmap request to the block device. Unmap is sometimes also called trim or
+ * deallocate. This notifies the device that the data in the blocks described is no
+ * longer valid. Reading blocks that have been unmapped results in indeterminate data.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param offset_blocks The offset, in blocks, from the start of the block device.
+ * \param num_blocks The number of blocks to unmap.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset_blocks and/or num_blocks are out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ * * -EBADF - desc not open for writing
+ */
+int spdk_bdev_unmap_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ uint64_t offset_blocks, uint64_t num_blocks,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit a flush request to the bdev on the given channel. For devices with volatile
+ * caches, data is not guaranteed to be persistent until the completion of a flush
+ * request. Call spdk_bdev_has_write_cache() to check if the bdev has a volatile cache.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param offset The offset, in bytes, from the start of the block device.
+ * \param length The number of bytes.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset and/or nbytes are not aligned or out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ * * -EBADF - desc not open for writing
+ */
+int spdk_bdev_flush(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ uint64_t offset, uint64_t length,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit a flush request to the bdev on the given channel. For devices with volatile
+ * caches, data is not guaranteed to be persistent until the completion of a flush
+ * request. Call spdk_bdev_has_write_cache() to check if the bdev has a volatile cache.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param offset_blocks The offset, in blocks, from the start of the block device.
+ * \param num_blocks The number of blocks.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -EINVAL - offset_blocks and/or num_blocks are out of range
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ * * -EBADF - desc not open for writing
+ */
+int spdk_bdev_flush_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ uint64_t offset_blocks, uint64_t num_blocks,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit a reset request to the bdev on the given channel.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ */
+int spdk_bdev_reset(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit an NVMe Admin command to the bdev. This passes directly through
+ * the block layer to the device. Support for NVMe passthru is optional,
+ * indicated by calling spdk_bdev_io_type_supported().
+ *
+ * The SGL/PRP will be automated generated based on the given buffer,
+ * so that portion of the command may be left empty.
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * \param desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param cmd The raw NVMe command. Must be an admin command.
+ * \param buf Data buffer to written from.
+ * \param nbytes The number of bytes to transfer. buf must be greater than or equal to this size.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ * * -EBADF - desc not open for writing
+ */
+int spdk_bdev_nvme_admin_passthru(struct spdk_bdev_desc *desc,
+ struct spdk_io_channel *ch,
+ const struct spdk_nvme_cmd *cmd,
+ void *buf, size_t nbytes,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit an NVMe I/O command to the bdev. This passes directly through
+ * the block layer to the device. Support for NVMe passthru is optional,
+ * indicated by calling spdk_bdev_io_type_supported().
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * The SGL/PRP will be automated generated based on the given buffer,
+ * so that portion of the command may be left empty. Also, the namespace
+ * id (nsid) will be populated automatically.
+ *
+ * \param bdev_desc Block device descriptor.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param cmd The raw NVMe command. Must be in the NVM command set.
+ * \param buf Data buffer to written from.
+ * \param nbytes The number of bytes to transfer. buf must be greater than or equal to this size.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ * * -EBADF - desc not open for writing
+ */
+int spdk_bdev_nvme_io_passthru(struct spdk_bdev_desc *bdev_desc,
+ struct spdk_io_channel *ch,
+ const struct spdk_nvme_cmd *cmd,
+ void *buf, size_t nbytes,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Submit an NVMe I/O command to the bdev. This passes directly through
+ * the block layer to the device. Support for NVMe passthru is optional,
+ * indicated by calling spdk_bdev_io_type_supported().
+ *
+ * \ingroup bdev_io_submit_functions
+ *
+ * The SGL/PRP will be automated generated based on the given buffer,
+ * so that portion of the command may be left empty. Also, the namespace
+ * id (nsid) will be populated automatically.
+ *
+ * \param bdev_desc Block device descriptor
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param cmd The raw NVMe command. Must be in the NVM command set.
+ * \param buf Data buffer to written from.
+ * \param nbytes The number of bytes to transfer. buf must be greater than or equal to this size.
+ * \param md_buf Meta data buffer to written from.
+ * \param md_len md_buf size to transfer. md_buf must be greater than or equal to this size.
+ * \param cb Called when the request is complete.
+ * \param cb_arg Argument passed to cb.
+ *
+ * \return 0 on success. On success, the callback will always
+ * be called (even if the request ultimately failed). Return
+ * negated errno on failure, in which case the callback will not be called.
+ * * -ENOMEM - spdk_bdev_io buffer cannot be allocated
+ * * -EBADF - desc not open for writing
+ */
+int spdk_bdev_nvme_io_passthru_md(struct spdk_bdev_desc *bdev_desc,
+ struct spdk_io_channel *ch,
+ const struct spdk_nvme_cmd *cmd,
+ void *buf, size_t nbytes, void *md_buf, size_t md_len,
+ spdk_bdev_io_completion_cb cb, void *cb_arg);
+
+/**
+ * Free an I/O request. This should only be called after the completion callback
+ * for the I/O has been called and notifies the bdev layer that memory may now
+ * be released.
+ *
+ * \param bdev_io I/O request.
+ */
+void spdk_bdev_free_io(struct spdk_bdev_io *bdev_io);
+
+/**
+ * Block device I/O wait callback
+ *
+ * Callback function to notify when an spdk_bdev_io structure is available
+ * to satisfy a call to one of the @ref bdev_io_submit_functions.
+ */
+typedef void (*spdk_bdev_io_wait_cb)(void *cb_arg);
+
+/**
+ * Structure to register a callback when an spdk_bdev_io becomes available.
+ */
+struct spdk_bdev_io_wait_entry {
+ struct spdk_bdev *bdev;
+ spdk_bdev_io_wait_cb cb_fn;
+ void *cb_arg;
+ TAILQ_ENTRY(spdk_bdev_io_wait_entry) link;
+};
+
+/**
+ * Add an entry into the calling thread's queue to be notified when an
+ * spdk_bdev_io becomes available.
+ *
+ * When one of the @ref bdev_io_submit_functions returns -ENOMEM, it means
+ * the spdk_bdev_io buffer pool has no available buffers. This function may
+ * be called to register a callback to be notified when a buffer becomes
+ * available on the calling thread.
+ *
+ * The callback function will always be called on the same thread as this
+ * function was called.
+ *
+ * This function must only be called immediately after one of the
+ * @ref bdev_io_submit_functions returns -ENOMEM.
+ *
+ * \param bdev Block device. The block device that the caller will submit
+ * an I/O to when the callback is invoked. Must match the bdev
+ * member in the entry parameter.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param entry Data structure allocated by the caller specifying the callback
+ * function and argument.
+ *
+ * \return 0 on success.
+ * -EINVAL if bdev parameter does not match bdev member in entry
+ * -EINVAL if an spdk_bdev_io structure was available on this thread.
+ */
+int spdk_bdev_queue_io_wait(struct spdk_bdev *bdev, struct spdk_io_channel *ch,
+ struct spdk_bdev_io_wait_entry *entry);
+
+/**
+ * Return I/O statistics for this channel.
+ *
+ * \param bdev Block device.
+ * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel().
+ * \param stat The per-channel statistics.
+ *
+ */
+void spdk_bdev_get_io_stat(struct spdk_bdev *bdev, struct spdk_io_channel *ch,
+ struct spdk_bdev_io_stat *stat);
+
+
+/**
+ * Return I/O statistics for this bdev. All the required information will be passed
+ * via the callback function.
+ *
+ * \param bdev Block device to query.
+ * \param stat Structure for aggregating collected statistics. Passed as argument to cb.
+ * \param cb Called when this operation completes.
+ * \param cb_arg Argument passed to callback function.
+ */
+void spdk_bdev_get_device_stat(struct spdk_bdev *bdev, struct spdk_bdev_io_stat *stat,
+ spdk_bdev_get_device_stat_cb cb, void *cb_arg);
+
+/**
+ * Get the status of bdev_io as an NVMe status code.
+ *
+ * \param bdev_io I/O to get the status from.
+ * \param sct Status Code Type return value, as defined by the NVMe specification.
+ * \param sc Status Code return value, as defined by the NVMe specification.
+ */
+void spdk_bdev_io_get_nvme_status(const struct spdk_bdev_io *bdev_io, int *sct, int *sc);
+
+/**
+ * Get the status of bdev_io as a SCSI status code.
+ *
+ * \param bdev_io I/O to get the status from.
+ * \param sc SCSI Status Code.
+ * \param sk SCSI Sense Key.
+ * \param asc SCSI Additional Sense Code.
+ * \param ascq SCSI Additional Sense Code Qualifier.
+ */
+void spdk_bdev_io_get_scsi_status(const struct spdk_bdev_io *bdev_io,
+ int *sc, int *sk, int *asc, int *ascq);
+
+/**
+ * Get the iovec describing the data buffer of a bdev_io.
+ *
+ * \param bdev_io I/O to describe with iovec.
+ * \param iovp Pointer to be filled with iovec.
+ * \param iovcntp Pointer to be filled with number of iovec entries.
+ */
+void spdk_bdev_io_get_iovec(struct spdk_bdev_io *bdev_io, struct iovec **iovp, int *iovcntp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_BDEV_H_ */
diff --git a/src/spdk/include/spdk/bdev_module.h b/src/spdk/include/spdk/bdev_module.h
new file mode 100644
index 00000000..d88be7ad
--- /dev/null
+++ b/src/spdk/include/spdk/bdev_module.h
@@ -0,0 +1,977 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Block Device Module Interface
+ *
+ * For information on how to write a bdev module, see @ref bdev_module.
+ */
+
+#ifndef SPDK_BDEV_MODULE_H
+#define SPDK_BDEV_MODULE_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/bdev.h"
+#include "spdk/queue.h"
+#include "spdk/scsi_spec.h"
+#include "spdk/thread.h"
+#include "spdk/util.h"
+#include "spdk/uuid.h"
+
+/** Block device module */
+struct spdk_bdev_module {
+ /**
+ * Initialization function for the module. Called by the spdk
+ * application during startup.
+ *
+ * Modules are required to define this function.
+ */
+ int (*module_init)(void);
+
+ /**
+ * Optional callback for modules that require notification of when
+ * the bdev subsystem has completed initialization.
+ *
+ * Modules are not required to define this function.
+ */
+ void (*init_complete)(void);
+
+ /**
+ * Optional callback for modules that require notification of when
+ * the bdev subsystem is starting the fini process.
+ *
+ * Modules are not required to define this function.
+ */
+ void (*fini_start)(void);
+
+ /**
+ * Finish function for the module. Called by the spdk application
+ * after all bdevs for all modules have been unregistered. This allows
+ * the module to do any final cleanup before the SPDK application exits.
+ *
+ * Modules are not required to define this function.
+ */
+ void (*module_fini)(void);
+
+ /**
+ * Function called to return a text string representing the
+ * module's configuration options for inclusion in a configuration file.
+ */
+ void (*config_text)(FILE *fp);
+
+ /**
+ * Function called to return a text string representing the module-level
+ * JSON RPCs required to regenerate the current configuration. This will
+ * include module-level configuration options, or methods to construct
+ * bdevs when one RPC may generate multiple bdevs (for example, an NVMe
+ * controller with multiple namespaces).
+ *
+ * Per-bdev JSON RPCs (where one "construct" RPC always creates one bdev)
+ * may be implemented here, or by the bdev's write_config_json function -
+ * but not both. Bdev module implementers may choose which mechanism to
+ * use based on the module's design.
+ *
+ * \return 0 on success or Bdev specific negative error code.
+ */
+ int (*config_json)(struct spdk_json_write_ctx *w);
+
+ /** Name for the modules being defined. */
+ const char *name;
+
+ /**
+ * Returns the allocation size required for the backend for uses such as local
+ * command structs, local SGL, iovecs, or other user context.
+ */
+ int (*get_ctx_size)(void);
+
+ /**
+ * First notification that a bdev should be examined by a virtual bdev module.
+ * Virtual bdev modules may use this to examine newly-added bdevs and automatically
+ * create their own vbdevs, but no I/O to device can be send to bdev at this point.
+ * Only vbdevs based on config files can be created here.
+ */
+ void (*examine_config)(struct spdk_bdev *bdev);
+
+ /**
+ * Second notification that a bdev should be examined by a virtual bdev module.
+ * Virtual bdev modules may use this to examine newly-added bdevs and automatically
+ * create their own vbdevs. This callback may use I/O operations end finish asynchronously.
+ */
+ void (*examine_disk)(struct spdk_bdev *bdev);
+
+ /**
+ * Denotes if the module_init function may complete asynchronously. If set to true,
+ * the module initialization has to be explicitly completed by calling
+ * spdk_bdev_module_init_done().
+ */
+ bool async_init;
+
+ /**
+ * Denotes if the module_fini function may complete asynchronously.
+ * If set to true finishing has to be explicitly completed by calling
+ * spdk_bdev_module_fini_done().
+ */
+ bool async_fini;
+
+ /**
+ * Fields that are used by the internal bdev subsystem. Bdev modules
+ * must not read or write to these fields.
+ */
+ struct __bdev_module_internal_fields {
+ /**
+ * Count of bdev inits/examinations in progress. Used by generic bdev
+ * layer and must not be modified by bdev modules.
+ *
+ * \note Used internally by bdev subsystem, don't change this value in bdev module.
+ */
+ uint32_t action_in_progress;
+
+ TAILQ_ENTRY(spdk_bdev_module) tailq;
+ } internal;
+};
+
+typedef void (*spdk_bdev_unregister_cb)(void *cb_arg, int rc);
+
+/**
+ * Function table for a block device backend.
+ *
+ * The backend block device function table provides a set of APIs to allow
+ * communication with a backend. The main commands are read/write API
+ * calls for I/O via submit_request.
+ */
+struct spdk_bdev_fn_table {
+ /** Destroy the backend block device object */
+ int (*destruct)(void *ctx);
+
+ /** Process the IO. */
+ void (*submit_request)(struct spdk_io_channel *ch, struct spdk_bdev_io *);
+
+ /** Check if the block device supports a specific I/O type. */
+ bool (*io_type_supported)(void *ctx, enum spdk_bdev_io_type);
+
+ /** Get an I/O channel for the specific bdev for the calling thread. */
+ struct spdk_io_channel *(*get_io_channel)(void *ctx);
+
+ /**
+ * Output driver-specific information to a JSON stream. Optional - may be NULL.
+ *
+ * The JSON write context will be initialized with an open object, so the bdev
+ * driver should write a name (based on the driver name) followed by a JSON value
+ * (most likely another nested object).
+ */
+ int (*dump_info_json)(void *ctx, struct spdk_json_write_ctx *w);
+
+ /**
+ * Output bdev-specific RPC configuration to a JSON stream. Optional - may be NULL.
+ *
+ * This function should only be implemented for bdevs which can be configured
+ * independently of other bdevs. For example, RPCs to create a bdev for an NVMe
+ * namespace may not be generated by this function, since enumerating an NVMe
+ * namespace requires attaching to an NVMe controller, and that controller may
+ * contain multiple namespaces. The spdk_bdev_module's config_json function should
+ * be used instead for these cases.
+ *
+ * The JSON write context will be initialized with an open object, so the bdev
+ * driver should write all data necessary to recreate this bdev by invoking
+ * constructor method. No other data should be written.
+ */
+ void (*write_config_json)(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w);
+
+ /** Get spin-time per I/O channel in microseconds.
+ * Optional - may be NULL.
+ */
+ uint64_t (*get_spin_time)(struct spdk_io_channel *ch);
+};
+
+/** bdev I/O completion status */
+enum spdk_bdev_io_status {
+ /*
+ * NOMEM should be returned when a bdev module cannot start an I/O because of
+ * some lack of resources. It may not be returned for RESET I/O. I/O completed
+ * with NOMEM status will be retried after some I/O from the same channel have
+ * completed.
+ */
+ SPDK_BDEV_IO_STATUS_NOMEM = -4,
+ SPDK_BDEV_IO_STATUS_SCSI_ERROR = -3,
+ SPDK_BDEV_IO_STATUS_NVME_ERROR = -2,
+ SPDK_BDEV_IO_STATUS_FAILED = -1,
+ SPDK_BDEV_IO_STATUS_PENDING = 0,
+ SPDK_BDEV_IO_STATUS_SUCCESS = 1,
+};
+
+struct spdk_bdev_alias {
+ char *alias;
+ TAILQ_ENTRY(spdk_bdev_alias) tailq;
+};
+
+typedef TAILQ_HEAD(, spdk_bdev_io) bdev_io_tailq_t;
+typedef STAILQ_HEAD(, spdk_bdev_io) bdev_io_stailq_t;
+
+struct spdk_bdev {
+ /** User context passed in by the backend */
+ void *ctxt;
+
+ /** Unique name for this block device. */
+ char *name;
+
+ /** Unique aliases for this block device. */
+ TAILQ_HEAD(spdk_bdev_aliases_list, spdk_bdev_alias) aliases;
+
+ /** Unique product name for this kind of block device. */
+ char *product_name;
+
+ /** write cache enabled, not used at the moment */
+ int write_cache;
+
+ /** Size in bytes of a logical block for the backend */
+ uint32_t blocklen;
+
+ /** Number of blocks */
+ uint64_t blockcnt;
+
+ /**
+ * This is used to make sure buffers are sector aligned.
+ * This causes double buffering on writes.
+ */
+ bool need_aligned_buffer;
+
+ /**
+ * Specifies whether the optimal_io_boundary is mandatory or
+ * only advisory. If set to true, the bdev layer will split
+ * READ and WRITE I/O that span the optimal_io_boundary before
+ * submitting them to the bdev module.
+ *
+ * Note that this field cannot be used to force splitting of
+ * UNMAP, WRITE_ZEROES or FLUSH I/O.
+ */
+ bool split_on_optimal_io_boundary;
+
+ /**
+ * Optimal I/O boundary in blocks, or 0 for no value reported.
+ */
+ uint32_t optimal_io_boundary;
+
+ /**
+ * UUID for this bdev.
+ *
+ * Fill with zeroes if no uuid is available.
+ */
+ struct spdk_uuid uuid;
+
+ /**
+ * Pointer to the bdev module that registered this bdev.
+ */
+ struct spdk_bdev_module *module;
+
+ /** function table for all LUN ops */
+ const struct spdk_bdev_fn_table *fn_table;
+
+ /** Fields that are used internally by the bdev subsystem. Bdev modules
+ * must not read or write to these fields.
+ */
+ struct __bdev_internal_fields {
+ /** Quality of service parameters */
+ struct spdk_bdev_qos *qos;
+
+ /** True if the state of the QoS is being modified */
+ bool qos_mod_in_progress;
+
+ /** Mutex protecting claimed */
+ pthread_mutex_t mutex;
+
+ /** The bdev status */
+ enum spdk_bdev_status status;
+
+ /**
+ * Pointer to the module that has claimed this bdev for purposes of creating virtual
+ * bdevs on top of it. Set to NULL if the bdev has not been claimed.
+ */
+ struct spdk_bdev_module *claim_module;
+
+ /** Callback function that will be called after bdev destruct is completed. */
+ spdk_bdev_unregister_cb unregister_cb;
+
+ /** Unregister call context */
+ void *unregister_ctx;
+
+ /** List of open descriptors for this block device. */
+ TAILQ_HEAD(, spdk_bdev_desc) open_descs;
+
+ TAILQ_ENTRY(spdk_bdev) link;
+
+ /** points to a reset bdev_io if one is in progress. */
+ struct spdk_bdev_io *reset_in_progress;
+
+ /** poller for tracking the queue_depth of a device, NULL if not tracking */
+ struct spdk_poller *qd_poller;
+
+ /** period at which we poll for queue depth information */
+ uint64_t period;
+
+ /** used to aggregate queue depth while iterating across the bdev's open channels */
+ uint64_t temporary_queue_depth;
+
+ /** queue depth as calculated the last time the telemetry poller checked. */
+ uint64_t measured_queue_depth;
+
+ /** most recent value of ticks spent performing I/O. Used to calculate the weighted time doing I/O */
+ uint64_t io_time;
+
+ /** weighted time performing I/O. Equal to measured_queue_depth * period */
+ uint64_t weighted_io_time;
+
+ /** accumulated I/O statistics for previously deleted channels of this bdev */
+ struct spdk_bdev_io_stat stat;
+ } internal;
+};
+
+typedef void (*spdk_bdev_io_get_buf_cb)(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io);
+
+#define BDEV_IO_NUM_CHILD_IOV 32
+
+struct spdk_bdev_io {
+ /** The block device that this I/O belongs to. */
+ struct spdk_bdev *bdev;
+
+ /** Enumerated value representing the I/O type. */
+ uint8_t type;
+
+ /** A single iovec element for use by this bdev_io. */
+ struct iovec iov;
+
+ /** Array of iovecs used for I/O splitting. */
+ struct iovec child_iov[BDEV_IO_NUM_CHILD_IOV];
+
+ union {
+ struct {
+ /** For SG buffer cases, array of iovecs to transfer. */
+ struct iovec *iovs;
+
+ /** For SG buffer cases, number of iovecs in iovec array. */
+ int iovcnt;
+
+ /** Total size of data to be transferred. */
+ uint64_t num_blocks;
+
+ /** Starting offset (in blocks) of the bdev for this I/O. */
+ uint64_t offset_blocks;
+
+ /** stored user callback in case we split the I/O and use a temporary callback */
+ spdk_bdev_io_completion_cb stored_user_cb;
+
+ /** number of blocks remaining in a split i/o */
+ uint64_t split_remaining_num_blocks;
+
+ /** current offset of the split I/O in the bdev */
+ uint64_t split_current_offset_blocks;
+
+ /** count of outstanding batched split I/Os */
+ uint32_t split_outstanding;
+ } bdev;
+ struct {
+ /** Channel reference held while messages for this reset are in progress. */
+ struct spdk_io_channel *ch_ref;
+ } reset;
+ struct {
+ /* The NVMe command to execute */
+ struct spdk_nvme_cmd cmd;
+
+ /* The data buffer to transfer */
+ void *buf;
+
+ /* The number of bytes to transfer */
+ size_t nbytes;
+
+ /* The meta data buffer to transfer */
+ void *md_buf;
+
+ /* meta data buffer size to transfer */
+ size_t md_len;
+ } nvme_passthru;
+ } u;
+
+ /** It may be used by modules to put the bdev_io into its own list. */
+ TAILQ_ENTRY(spdk_bdev_io) module_link;
+
+ /**
+ * Fields that are used internally by the bdev subsystem. Bdev modules
+ * must not read or write to these fields.
+ */
+ struct __bdev_io_internal_fields {
+ /** The bdev I/O channel that this was handled on. */
+ struct spdk_bdev_channel *ch;
+
+ /** The bdev I/O channel that this was submitted on. */
+ struct spdk_bdev_channel *io_submit_ch;
+
+ /** The bdev descriptor that was used when submitting this I/O. */
+ struct spdk_bdev_desc *desc;
+
+ /** User function that will be called when this completes */
+ spdk_bdev_io_completion_cb cb;
+
+ /** Context that will be passed to the completion callback */
+ void *caller_ctx;
+
+ /** Current tsc at submit time. Used to calculate latency at completion. */
+ uint64_t submit_tsc;
+
+ /** Error information from a device */
+ union {
+ /** Only valid when status is SPDK_BDEV_IO_STATUS_NVME_ERROR */
+ struct {
+ /** NVMe status code type */
+ uint8_t sct;
+ /** NVMe status code */
+ uint8_t sc;
+ } nvme;
+ /** Only valid when status is SPDK_BDEV_IO_STATUS_SCSI_ERROR */
+ struct {
+ /** SCSI status code */
+ uint8_t sc;
+ /** SCSI sense key */
+ uint8_t sk;
+ /** SCSI additional sense code */
+ uint8_t asc;
+ /** SCSI additional sense code qualifier */
+ uint8_t ascq;
+ } scsi;
+ } error;
+
+ /**
+ * Set to true while the bdev module submit_request function is in progress.
+ *
+ * This is used to decide whether spdk_bdev_io_complete() can complete the I/O directly
+ * or if completion must be deferred via an event.
+ */
+ bool in_submit_request;
+
+ /** Status for the IO */
+ int8_t status;
+
+ /** bdev allocated memory associated with this request */
+ void *buf;
+
+ /** requested size of the buffer associated with this I/O */
+ uint64_t buf_len;
+
+ /** Callback for when buf is allocated */
+ spdk_bdev_io_get_buf_cb get_buf_cb;
+
+ /** Member used for linking child I/Os together. */
+ TAILQ_ENTRY(spdk_bdev_io) link;
+
+ /** Entry to the list need_buf of struct spdk_bdev. */
+ STAILQ_ENTRY(spdk_bdev_io) buf_link;
+
+ /** Enables queuing parent I/O when no bdev_ios available for split children. */
+ struct spdk_bdev_io_wait_entry waitq_entry;
+ } internal;
+
+ /**
+ * Per I/O context for use by the bdev module.
+ */
+ uint8_t driver_ctx[0];
+
+ /* No members may be added after driver_ctx! */
+};
+
+/**
+ * Register a new bdev.
+ *
+ * \param bdev Block device to register.
+ *
+ * \return 0 on success.
+ * \return -EINVAL if the bdev name is NULL.
+ * \return -EEXIST if a bdev or bdev alias with the same name already exists.
+ */
+int spdk_bdev_register(struct spdk_bdev *bdev);
+
+/**
+ * Unregister a bdev
+ *
+ * \param bdev Block device to unregister.
+ * \param cb_fn Callback function to be called when the unregister is complete.
+ * \param cb_arg Argument to be supplied to cb_fn
+ */
+void spdk_bdev_unregister(struct spdk_bdev *bdev, spdk_bdev_unregister_cb cb_fn, void *cb_arg);
+
+/**
+ * Invokes the unregister callback of a bdev backing a virtual bdev.
+ *
+ * A Bdev with an asynchronous destruct path should return 1 from its
+ * destruct function and call this function at the conclusion of that path.
+ * Bdevs with synchronous destruct paths should return 0 from their destruct
+ * path.
+ *
+ * \param bdev Block device that was destroyed.
+ * \param bdeverrno Error code returned from bdev's destruct callback.
+ */
+void spdk_bdev_destruct_done(struct spdk_bdev *bdev, int bdeverrno);
+
+/**
+ * Register a virtual bdev.
+ *
+ * \param vbdev Virtual bdev to register.
+ * \param base_bdevs Array of bdevs upon which this vbdev is based.
+ * \param base_bdev_count Number of bdevs in base_bdevs.
+ *
+ * \return 0 on success
+ * \return -EINVAL if the bdev name is NULL.
+ * \return -EEXIST if the bdev already exists.
+ * \return -ENOMEM if allocation of the base_bdevs array or the base bdevs vbdevs array fails.
+ */
+int spdk_vbdev_register(struct spdk_bdev *vbdev, struct spdk_bdev **base_bdevs,
+ int base_bdev_count);
+
+/**
+ * Indicate to the bdev layer that the module is done examining a bdev.
+ *
+ * To be called synchronously or asynchronously in response to the
+ * module's examine function being called.
+ *
+ * \param module Pointer to the module completing the examination.
+ */
+void spdk_bdev_module_examine_done(struct spdk_bdev_module *module);
+
+/**
+ * Indicate to the bdev layer that the module is done initializing.
+ *
+ * To be called synchronously or asynchronously in response to the
+ * module_init function being called.
+ *
+ * \param module Pointer to the module completing the initialization.
+ */
+void spdk_bdev_module_init_done(struct spdk_bdev_module *module);
+
+/**
+ * Indicate to the bdev layer that the module is done cleaning up.
+ *
+ * To be called either synchronously or asynchronously
+ * in response to the module_fini function being called.
+ *
+ */
+void spdk_bdev_module_finish_done(void);
+
+/**
+ * Called by a bdev module to lay exclusive write claim to a bdev.
+ *
+ * Also upgrades that bdev's descriptor to have write access.
+ *
+ * \param bdev Block device to be claimed.
+ * \param desc Descriptor for the above block device.
+ * \param module Bdev module attempting to claim bdev.
+ *
+ * \return 0 on success
+ * \return -EPERM if the bdev is already claimed by another module.
+ */
+int spdk_bdev_module_claim_bdev(struct spdk_bdev *bdev, struct spdk_bdev_desc *desc,
+ struct spdk_bdev_module *module);
+
+/**
+ * Called to release a write claim on a block device.
+ *
+ * \param bdev Block device to be released.
+ */
+void spdk_bdev_module_release_bdev(struct spdk_bdev *bdev);
+
+/**
+ * Add alias to block device names list.
+ * Aliases can be add only to registered bdev.
+ *
+ * \param bdev Block device to query.
+ * \param alias Alias to be added to list.
+ *
+ * \return 0 on success
+ * \return -EEXIST if alias already exists as name or alias on any bdev
+ * \return -ENOMEM if memory cannot be allocated to store alias
+ * \return -EINVAL if passed alias is empty
+ */
+int spdk_bdev_alias_add(struct spdk_bdev *bdev, const char *alias);
+
+/**
+ * Removes name from block device names list.
+ *
+ * \param bdev Block device to query.
+ * \param alias Alias to be deleted from list.
+ * \return 0 on success
+ * \return -ENOENT if alias does not exists
+ */
+int spdk_bdev_alias_del(struct spdk_bdev *bdev, const char *alias);
+
+/**
+ * Removes all alias from block device alias list.
+ *
+ * \param bdev Block device to operate.
+ */
+void spdk_bdev_alias_del_all(struct spdk_bdev *bdev);
+
+/**
+ * Get pointer to block device aliases list.
+ *
+ * \param bdev Block device to query.
+ * \return Pointer to bdev aliases list.
+ */
+const struct spdk_bdev_aliases_list *spdk_bdev_get_aliases(const struct spdk_bdev *bdev);
+
+/**
+ * Allocate a buffer for given bdev_io. Allocation will happen
+ * only if the bdev_io has no assigned SGL yet. The buffer will be
+ * freed automatically on \c spdk_bdev_free_io() call. This call
+ * will never fail - in case of lack of memory given callback \c cb
+ * will be deferred until enough memory is freed.
+ *
+ * \param bdev_io I/O to allocate buffer for.
+ * \param cb callback to be called when the buffer is allocated
+ * or the bdev_io has an SGL assigned already.
+ * \param len size of the buffer to allocate. In case the bdev_io
+ * doesn't have an SGL assigned this field must be no bigger than
+ * \c SPDK_BDEV_LARGE_BUF_MAX_SIZE.
+ */
+void spdk_bdev_io_get_buf(struct spdk_bdev_io *bdev_io, spdk_bdev_io_get_buf_cb cb, uint64_t len);
+
+/**
+ * Set the given buffer as the data buffer described by this bdev_io.
+ *
+ * The portion of the buffer used may be adjusted for memory alignement
+ * purposes.
+ *
+ * \param bdev_io I/O to set the buffer on.
+ * \param buf The buffer to set as the active data buffer.
+ * \param len The length of the buffer.
+ *
+ */
+void spdk_bdev_io_set_buf(struct spdk_bdev_io *bdev_io, void *buf, size_t len);
+
+/**
+ * Complete a bdev_io
+ *
+ * \param bdev_io I/O to complete.
+ * \param status The I/O completion status.
+ */
+void spdk_bdev_io_complete(struct spdk_bdev_io *bdev_io,
+ enum spdk_bdev_io_status status);
+
+/**
+ * Complete a bdev_io with an NVMe status code.
+ *
+ * \param bdev_io I/O to complete.
+ * \param sct NVMe Status Code Type.
+ * \param sc NVMe Status Code.
+ */
+void spdk_bdev_io_complete_nvme_status(struct spdk_bdev_io *bdev_io, int sct, int sc);
+
+/**
+ * Complete a bdev_io with a SCSI status code.
+ *
+ * \param bdev_io I/O to complete.
+ * \param sc SCSI Status Code.
+ * \param sk SCSI Sense Key.
+ * \param asc SCSI Additional Sense Code.
+ * \param ascq SCSI Additional Sense Code Qualifier.
+ */
+void spdk_bdev_io_complete_scsi_status(struct spdk_bdev_io *bdev_io, enum spdk_scsi_status sc,
+ enum spdk_scsi_sense sk, uint8_t asc, uint8_t ascq);
+
+/**
+ * Get a thread that given bdev_io was submitted on.
+ *
+ * \param bdev_io I/O
+ * \return thread that submitted the I/O
+ */
+struct spdk_thread *spdk_bdev_io_get_thread(struct spdk_bdev_io *bdev_io);
+
+/**
+ * Resize for a bdev.
+ *
+ * Change number of blocks for provided block device.
+ * It can only be called on a registered bdev.
+ *
+ * \param bdev Block device to change.
+ * \param size New size of bdev.
+ * \return 0 on success, negated errno on failure.
+ */
+int spdk_bdev_notify_blockcnt_change(struct spdk_bdev *bdev, uint64_t size);
+
+/**
+ * Translates NVMe status codes to SCSI status information.
+ *
+ * The codes are stored in the user supplied integers.
+ *
+ * \param bdev_io I/O containing status codes to translate.
+ * \param sc SCSI Status Code will be stored here.
+ * \param sk SCSI Sense Key will be stored here.
+ * \param asc SCSI Additional Sense Code will be stored here.
+ * \param ascq SCSI Additional Sense Code Qualifier will be stored here.
+ */
+void spdk_scsi_nvme_translate(const struct spdk_bdev_io *bdev_io,
+ int *sc, int *sk, int *asc, int *ascq);
+
+/**
+ * Add the given module to the list of registered modules.
+ * This function should be invoked by referencing the macro
+ * SPDK_BDEV_MODULE_REGISTER in the module c file.
+ *
+ * \param bdev_module Module to be added.
+ */
+void spdk_bdev_module_list_add(struct spdk_bdev_module *bdev_module);
+
+/**
+ * Find registered module with name pointed by \c name.
+ *
+ * \param name name of module to be searched for.
+ * \return pointer to module or NULL if no module with \c name exist
+ */
+struct spdk_bdev_module *spdk_bdev_module_list_find(const char *name);
+
+static inline struct spdk_bdev_io *
+spdk_bdev_io_from_ctx(void *ctx)
+{
+ return SPDK_CONTAINEROF(ctx, struct spdk_bdev_io, driver_ctx);
+}
+
+struct spdk_bdev_part_base;
+
+/**
+ * Returns a pointer to the spdk_bdev associated with an spdk_bdev_part_base
+ *
+ * \param part_base A pointer to an spdk_bdev_part_base object.
+ *
+ * \return A pointer to the base's spdk_bdev struct.
+ */
+struct spdk_bdev *spdk_bdev_part_base_get_bdev(struct spdk_bdev_part_base *part_base);
+
+/**
+ * Returns a pointer to the spdk_bdev_descriptor associated with an spdk_bdev_part_base
+ *
+ * \param part_base A pointer to an spdk_bdev_part_base object.
+ *
+ * \return A pointer to the base's spdk_bdev_desc struct.
+ */
+struct spdk_bdev_desc *spdk_bdev_part_base_get_desc(struct spdk_bdev_part_base *part_base);
+
+/**
+ * Returns a pointer to the tailq associated with an spdk_bdev_part_base
+ *
+ * \param part_base A pointer to an spdk_bdev_part_base object.
+ *
+ * \return The head of a tailq of spdk_bdev_part structs registered to the base's module.
+ */
+struct bdev_part_tailq *spdk_bdev_part_base_get_tailq(struct spdk_bdev_part_base *part_base);
+
+/**
+ * Returns a pointer to the module level context associated with an spdk_bdev_part_base
+ *
+ * \param part_base A pointer to an spdk_bdev_part_base object.
+ *
+ * \return A pointer to the module level context registered with the base in spdk_bdev_part_base_construct.
+ */
+void *spdk_bdev_part_base_get_ctx(struct spdk_bdev_part_base *part_base);
+
+typedef void (*spdk_bdev_part_base_free_fn)(void *ctx);
+
+struct spdk_bdev_part {
+ /* Entry into the module's global list of bdev parts */
+ TAILQ_ENTRY(spdk_bdev_part) tailq;
+
+ /**
+ * Fields that are used internally by part.c These fields should only
+ * be accessed from a module using any pertinent get and set methods.
+ */
+ struct bdev_part_internal_fields {
+
+ /* This part's corresponding bdev object. Not to be confused with the base bdev */
+ struct spdk_bdev bdev;
+
+ /* The base to which this part belongs */
+ struct spdk_bdev_part_base *base;
+
+ /* number of blocks from the start of the base bdev to the start of this part */
+ uint64_t offset_blocks;
+ } internal;
+};
+
+struct spdk_bdev_part_channel {
+ struct spdk_bdev_part *part;
+ struct spdk_io_channel *base_ch;
+};
+
+typedef TAILQ_HEAD(bdev_part_tailq, spdk_bdev_part) SPDK_BDEV_PART_TAILQ;
+
+/**
+ * Free the base corresponding to one or more spdk_bdev_part.
+ *
+ * \param base The base to free.
+ */
+void spdk_bdev_part_base_free(struct spdk_bdev_part_base *base);
+
+/**
+ * Free an spdk_bdev_part context.
+ *
+ * \param part The part to free.
+ *
+ * \return 1 always. To indicate that the operation is asynchronous.
+ */
+int spdk_bdev_part_free(struct spdk_bdev_part *part);
+
+/**
+ * Calls spdk_bdev_unregister on the bdev for each part associated with base_bdev.
+ *
+ * \param base_bdev The spdk_bdev upon which an spdk_bdev-part_base is built
+ * \param tailq The list of spdk_bdev_part bdevs associated with this base bdev.
+ */
+void spdk_bdev_part_base_hotremove(struct spdk_bdev *base_bdev, struct bdev_part_tailq *tailq);
+
+/**
+ * Construct a new spdk_bdev_part_base on top of the provided bdev.
+ *
+ * \param bdev The spdk_bdev upon which this base will be built.
+ * \param remove_cb Function to be called upon hotremove of the bdev.
+ * \param module The module to which this bdev base belongs.
+ * \param fn_table Function table for communicating with the bdev backend.
+ * \param tailq The head of the list of all spdk_bdev_part structures registered to this base's module.
+ * \param free_fn User provided function to free base related context upon bdev removal or shutdown.
+ * \param ctx Module specific context for this bdev part base.
+ * \param channel_size Channel size in bytes.
+ * \param ch_create_cb Called after a new channel is allocated.
+ * \param ch_destroy_cb Called upon channel deletion.
+ *
+ * \return 0 on success
+ * \return -1 if the underlying bdev cannot be opened.
+ */
+struct spdk_bdev_part_base *spdk_bdev_part_base_construct(struct spdk_bdev *bdev,
+ spdk_bdev_remove_cb_t remove_cb,
+ struct spdk_bdev_module *module,
+ struct spdk_bdev_fn_table *fn_table,
+ struct bdev_part_tailq *tailq,
+ spdk_bdev_part_base_free_fn free_fn,
+ void *ctx,
+ uint32_t channel_size,
+ spdk_io_channel_create_cb ch_create_cb,
+ spdk_io_channel_destroy_cb ch_destroy_cb);
+
+/**
+ * Create a logical spdk_bdev_part on top of a base.
+ *
+ * \param part The part object allocated by the user.
+ * \param base The base from which to create the part.
+ * \param name The name of the new spdk_bdev_part.
+ * \param offset_blocks The offset into the base bdev at which this part begins.
+ * \param num_blocks The number of blocks that this part will span.
+ * \param product_name Unique name for this type of block device.
+ *
+ * \return 0 on success.
+ * \return -1 if the bases underlying bdev cannot be claimed by the current module.
+ */
+int spdk_bdev_part_construct(struct spdk_bdev_part *part, struct spdk_bdev_part_base *base,
+ char *name, uint64_t offset_blocks, uint64_t num_blocks,
+ char *product_name);
+
+/**
+ * Forwards I/O from an spdk_bdev_part to the underlying base bdev.
+ *
+ * This function will apply the offset_blocks the user provided to
+ * spdk_bdev_part_construct to the I/O. The user should not manually
+ * apply this offset before submitting any I/O through this function.
+ *
+ * \param ch The I/O channel associated with the spdk_bdev_part.
+ * \param bdev_io The I/O to be submitted to the underlying bdev.
+ * \return 0 on success or non-zero if submit request failed.
+ */
+int spdk_bdev_part_submit_request(struct spdk_bdev_part_channel *ch, struct spdk_bdev_io *bdev_io);
+
+/**
+ * Return a pointer to this part's spdk_bdev.
+ *
+ * \param part An spdk_bdev_part object.
+ *
+ * \return A pointer to this part's spdk_bdev object.
+ */
+struct spdk_bdev *spdk_bdev_part_get_bdev(struct spdk_bdev_part *part);
+
+/**
+ * Return a pointer to this part's base.
+ *
+ * \param part An spdk_bdev_part object.
+ *
+ * \return A pointer to this part's spdk_bdev_part_base object.
+ */
+struct spdk_bdev_part_base *spdk_bdev_part_get_base(struct spdk_bdev_part *part);
+
+/**
+ * Return a pointer to this part's base bdev.
+ *
+ * The return value of this function is equivalent to calling
+ * spdk_bdev_part_base_get_bdev on this part's base.
+ *
+ * \param part An spdk_bdev_part object.
+ *
+ * \return A pointer to the bdev belonging to this part's base.
+ */
+struct spdk_bdev *spdk_bdev_part_get_base_bdev(struct spdk_bdev_part *part);
+
+/**
+ * Return this part's offset from the beginning of the base bdev.
+ *
+ * This function should not be called in the I/O path. Any block
+ * translations to I/O will be handled in spdk_bdev_part_submit_request.
+ *
+ * \param part An spdk_bdev_part object.
+ *
+ * \return the block offset of this part from it's underlying bdev.
+ */
+uint64_t spdk_bdev_part_get_offset_blocks(struct spdk_bdev_part *part);
+
+/*
+ * Macro used to register module for later initialization.
+ */
+#define SPDK_BDEV_MODULE_REGISTER(_module) \
+ __attribute__((constructor)) static void \
+ SPDK_BDEV_MODULE_REGISTER_FN_NAME(__LINE__) (void) \
+ { \
+ spdk_bdev_module_list_add(_module); \
+ }
+
+/*
+ * This is helper macro for automatic function generation.
+ *
+ */
+#define SPDK_BDEV_MODULE_REGISTER_FN_NAME(line) SPDK_BDEV_MODULE_REGISTER_FN_NAME_(line)
+
+/*
+ * Second helper macro for "stringize" trick to work.
+ */
+#define SPDK_BDEV_MODULE_REGISTER_FN_NAME_(line) spdk_bdev_module_register_ ## line
+
+#endif /* SPDK_BDEV_MODULE_H */
diff --git a/src/spdk/include/spdk/bit_array.h b/src/spdk/include/spdk/bit_array.h
new file mode 100644
index 00000000..37279dfc
--- /dev/null
+++ b/src/spdk/include/spdk/bit_array.h
@@ -0,0 +1,180 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Bit array data structure
+ */
+
+#ifndef SPDK_BIT_ARRAY_H
+#define SPDK_BIT_ARRAY_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Variable-length bit array.
+ */
+struct spdk_bit_array;
+
+/**
+ * Return the number of bits that a bit array is currently sized to hold.
+ *
+ * \param ba Bit array to query.
+ *
+ * \return the number of bits.
+ */
+uint32_t spdk_bit_array_capacity(const struct spdk_bit_array *ba);
+
+/**
+ * Create a bit array.
+ *
+ * \param num_bits Number of bits that the bit array is sized to hold.
+ *
+ * All bits in the array will be cleared.
+ *
+ * \return a pointer to the new bit array.
+ */
+struct spdk_bit_array *spdk_bit_array_create(uint32_t num_bits);
+
+/**
+ * Free a bit array and set the pointer to NULL.
+ *
+ * \param bap Bit array to free.
+ */
+void spdk_bit_array_free(struct spdk_bit_array **bap);
+
+/**
+ * Create or resize a bit array.
+ *
+ * To create a new bit array, pass a pointer to a spdk_bit_array pointer that is
+ * NULL for bap.
+ *
+ * The bit array will be sized to hold at least num_bits.
+ *
+ * If num_bits is smaller than the previous size of the bit array,
+ * any data beyond the new num_bits size will be cleared.
+ *
+ * If num_bits is larger than the previous size of the bit array,
+ * any data beyond the old num_bits size will be cleared.
+ *
+ * \param bap Bit array to create/resize.
+ * \param num_bits Number of bits that the bit array is sized to hold.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_bit_array_resize(struct spdk_bit_array **bap, uint32_t num_bits);
+
+/**
+ * Get the value of a bit from the bit array.
+ *
+ * If bit_index is beyond the end of the current size of the bit array, this
+ * function will return false (i.e. bits beyond the end of the array are implicitly 0).
+ *
+ * \param ba Bit array to query.
+ * \param bit_index The index of a bit to query.
+ *
+ * \return the value of a bit from the bit array on success, or false on failure.
+ */
+bool spdk_bit_array_get(const struct spdk_bit_array *ba, uint32_t bit_index);
+
+/**
+ * Set (to 1) a bit in the bit array.
+ *
+ * If bit_index is beyond the end of the bit array, this function will return -EINVAL.
+ *
+ * \param ba Bit array to set a bit.
+ * \param bit_index The index of a bit to set.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_bit_array_set(struct spdk_bit_array *ba, uint32_t bit_index);
+
+/**
+ * Clear (to 0) a bit in the bit array.
+ *
+ * If bit_index is beyond the end of the bit array, no action is taken. Bits
+ * beyond the end of the bit array are implicitly 0.
+ *
+ * \param ba Bit array to clear a bit.
+ * \param bit_index The index of a bit to clear.
+ */
+void spdk_bit_array_clear(struct spdk_bit_array *ba, uint32_t bit_index);
+
+/**
+ * Find the index of the first set bit in the array.
+ *
+ * \param ba The bit array to search.
+ * \param start_bit_index The bit index from which to start searching (0 to start
+ * from the beginning of the array).
+ *
+ * \return the index of the first set bit. If no bits are set, returns UINT32_MAX.
+ */
+uint32_t spdk_bit_array_find_first_set(const struct spdk_bit_array *ba, uint32_t start_bit_index);
+
+/**
+ * Find the index of the first cleared bit in the array.
+ *
+ * \param ba The bit array to search.
+ * \param start_bit_index The bit index from which to start searching (0 to start
+ * from the beginning of the array).
+ *
+ * \return the index of the first cleared bit. If no bits are cleared, returns UINT32_MAX.
+ */
+uint32_t spdk_bit_array_find_first_clear(const struct spdk_bit_array *ba, uint32_t start_bit_index);
+
+/**
+ * Count the number of set bits in the array.
+ *
+ * \param ba The bit array to search.
+ *
+ * \return the number of bits set in the array.
+ */
+uint32_t spdk_bit_array_count_set(const struct spdk_bit_array *ba);
+
+/**
+ * Count the number of cleared bits in the array.
+ *
+ * \param ba The bit array to search.
+ *
+ * \return the number of bits cleared in the array.
+ */
+uint32_t spdk_bit_array_count_clear(const struct spdk_bit_array *ba);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/blob.h b/src/spdk/include/spdk/blob.h
new file mode 100644
index 00000000..5a895fef
--- /dev/null
+++ b/src/spdk/include/spdk/blob.h
@@ -0,0 +1,854 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Blob Storage System
+ *
+ * The blob storage system, or the blobstore for short, is a low level
+ * library for placing opaque blobs of data onto a storage device such
+ * that scattered physical blocks on the storage device appear as a
+ * single, contiguous storage region. These blobs are also persistent,
+ * which means they are rediscoverable after reboot or power loss.
+ *
+ * The blobstore is designed to be very high performance, and thus has
+ * a few general rules regarding thread safety to avoid taking locks
+ * in the I/O path. This is primarily done by only allowing most
+ * functions to be called on the metadata thread. The metadata thread is
+ * the thread which called spdk_bs_init() or spdk_bs_load().
+ *
+ * Functions starting with the prefix "spdk_blob_io" are passed a channel
+ * as an argument, and channels may only be used from the thread they were
+ * created on. See \ref spdk_bs_alloc_io_channel. These are the only
+ * functions that may be called from a thread other than the metadata
+ * thread.
+ *
+ * The blobstore returns errors using negated POSIX errno values, either
+ * returned in the callback or as a return value. An errno value of 0 means
+ * success.
+ */
+
+#ifndef SPDK_BLOB_H
+#define SPDK_BLOB_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint64_t spdk_blob_id;
+#define SPDK_BLOBID_INVALID (uint64_t)-1
+#define SPDK_BLOBSTORE_TYPE_LENGTH 16
+
+struct spdk_blob_store;
+struct spdk_io_channel;
+struct spdk_blob;
+struct spdk_xattr_names;
+
+/**
+ * Blobstore operation completion callback.
+ *
+ * \param cb_arg Callback argument.
+ * \param bserrno 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_bs_op_complete)(void *cb_arg, int bserrno);
+
+/**
+ * Blobstore operation completion callback with handle.
+ *
+ * \param cb_arg Callback argument.
+ * \param bs Handle to a blobstore.
+ * \param bserrno 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_bs_op_with_handle_complete)(void *cb_arg, struct spdk_blob_store *bs,
+ int bserrno);
+
+/**
+ * Blob operation completion callback.
+ *
+ * \param cb_arg Callback argument.
+ * \param bserrno 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_blob_op_complete)(void *cb_arg, int bserrno);
+
+/**
+ * Blob operation completion callback with blob ID.
+ *
+ * \param cb_arg Callback argument.
+ * \param blobid Blob ID.
+ * \param bserrno 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_blob_op_with_id_complete)(void *cb_arg, spdk_blob_id blobid, int bserrno);
+
+/**
+ * Blob operation completion callback with handle.
+ *
+ * \param cb_arg Callback argument.
+ * \param bs Handle to a blob.
+ * \param bserrno 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_blob_op_with_handle_complete)(void *cb_arg, struct spdk_blob *blb, int bserrno);
+
+/**
+ * Blobstore device completion callback.
+ *
+ * \param channel I/O channel the operation was initiated on.
+ * \param cb_arg Callback argument.
+ * \param bserrno 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_bs_dev_cpl)(struct spdk_io_channel *channel,
+ void *cb_arg, int bserrno);
+
+struct spdk_bs_dev_cb_args {
+ spdk_bs_dev_cpl cb_fn;
+ struct spdk_io_channel *channel;
+ void *cb_arg;
+};
+
+struct spdk_bs_dev {
+ /* Create a new channel which is a software construct that is used
+ * to submit I/O. */
+ struct spdk_io_channel *(*create_channel)(struct spdk_bs_dev *dev);
+
+ /* Destroy a previously created channel */
+ void (*destroy_channel)(struct spdk_bs_dev *dev, struct spdk_io_channel *channel);
+
+ /* Destroy this blobstore device. Applications must not destroy the blobstore device,
+ * rather the blobstore will destroy it using this function pointer once all
+ * references to it during unload callback context have been completed.
+ */
+ void (*destroy)(struct spdk_bs_dev *dev);
+
+ void (*read)(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, void *payload,
+ uint64_t lba, uint32_t lba_count,
+ struct spdk_bs_dev_cb_args *cb_args);
+
+ void (*write)(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, void *payload,
+ uint64_t lba, uint32_t lba_count,
+ struct spdk_bs_dev_cb_args *cb_args);
+
+ void (*readv)(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
+ struct iovec *iov, int iovcnt,
+ uint64_t lba, uint32_t lba_count,
+ struct spdk_bs_dev_cb_args *cb_args);
+
+ void (*writev)(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
+ struct iovec *iov, int iovcnt,
+ uint64_t lba, uint32_t lba_count,
+ struct spdk_bs_dev_cb_args *cb_args);
+
+ void (*flush)(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
+ struct spdk_bs_dev_cb_args *cb_args);
+
+ void (*write_zeroes)(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
+ uint64_t lba, uint32_t lba_count,
+ struct spdk_bs_dev_cb_args *cb_args);
+
+ void (*unmap)(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
+ uint64_t lba, uint32_t lba_count,
+ struct spdk_bs_dev_cb_args *cb_args);
+
+ uint64_t blockcnt;
+ uint32_t blocklen; /* In bytes */
+};
+
+struct spdk_bs_type {
+ char bstype[SPDK_BLOBSTORE_TYPE_LENGTH];
+};
+
+struct spdk_bs_opts {
+ /** Size of cluster in bytes. Must be multiple of 4KiB page size. */
+ uint32_t cluster_sz;
+
+ /** Count of the number of pages reserved for metadata */
+ uint32_t num_md_pages;
+
+ /** Maximum simultaneous metadata operations */
+ uint32_t max_md_ops;
+
+ /** Maximum simultaneous operations per channel */
+ uint32_t max_channel_ops;
+
+ /** Blobstore type */
+ struct spdk_bs_type bstype;
+
+ /** Callback function to invoke for each blob. */
+ spdk_blob_op_with_handle_complete iter_cb_fn;
+
+ /** Argument passed to iter_cb_fn for each blob. */
+ void *iter_cb_arg;
+};
+
+/**
+ * Initialize a spdk_bs_opts structure to the default blobstore option values.
+ *
+ * \param opts The spdk_bs_opts structure to be initialized.
+ */
+void spdk_bs_opts_init(struct spdk_bs_opts *opts);
+
+/**
+ * Load a blobstore from the given device.
+ *
+ * \param dev Blobstore block device.
+ * \param opts The structure which contains the option values for the blobstore.
+ * \param cb_fn Called when the loading is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_load(struct spdk_bs_dev *dev, struct spdk_bs_opts *opts,
+ spdk_bs_op_with_handle_complete cb_fn, void *cb_arg);
+
+/**
+ * Initialize a blobstore on the given device.
+ *
+ * \param dev Blobstore block device.
+ * \param opts The structure which contains the option values for the blobstore.
+ * \param cb_fn Called when the initialization is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_bs_opts *opts,
+ spdk_bs_op_with_handle_complete cb_fn, void *cb_arg);
+
+typedef void (*spdk_bs_dump_print_xattr)(FILE *fp, const char *bstype, const char *name,
+ const void *value, size_t value_length);
+
+/**
+ * Dump a blobstore's metadata to a given FILE in human-readable format.
+ *
+ * \param dev Blobstore block device.
+ * \param fp FILE pointer to dump the metadata contents.
+ * \param print_xattr_fn Callback function to interpret external xattrs.
+ * \param cb_fn Called when the dump is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_dump(struct spdk_bs_dev *dev, FILE *fp, spdk_bs_dump_print_xattr print_xattr_fn,
+ spdk_bs_op_complete cb_fn, void *cb_arg);
+/**
+ * Destroy the blobstore.
+ *
+ * It will destroy the blobstore by zeroing the super block.
+ *
+ * \param bs blobstore to destroy.
+ * \param cb_fn Called when the destruction is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_destroy(struct spdk_blob_store *bs, spdk_bs_op_complete cb_fn,
+ void *cb_arg);
+
+/**
+ * Unload the blobstore.
+ *
+ * It will flush all volatile data to disk.
+ *
+ * \param bs blobstore to unload.
+ * \param cb_fn Called when the unloading is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_unload(struct spdk_blob_store *bs, spdk_bs_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Set a super blob on the given blobstore.
+ *
+ * This will be retrievable immediately after spdk_bs_load() on the next initializaiton.
+ *
+ * \param bs blobstore.
+ * \param blobid The id of the blob which will be set as the super blob.
+ * \param cb_fn Called when the setting is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_set_super(struct spdk_blob_store *bs, spdk_blob_id blobid,
+ spdk_bs_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Get the super blob. The obtained blob id will be passed to the callback function.
+ *
+ * \param bs blobstore.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_get_super(struct spdk_blob_store *bs,
+ spdk_blob_op_with_id_complete cb_fn, void *cb_arg);
+
+/**
+ * Get the cluster size in bytes.
+ *
+ * \param bs blobstore to query.
+ *
+ * \return cluster size.
+ */
+uint64_t spdk_bs_get_cluster_size(struct spdk_blob_store *bs);
+
+/**
+ * Get the page size in bytes. This is the write and read granularity of blobs.
+ *
+ * \param bs blobstore to query.
+ *
+ * \return page size.
+ */
+uint64_t spdk_bs_get_page_size(struct spdk_blob_store *bs);
+
+/**
+ * Get the io unit size in bytes.
+ *
+ * \param bs blobstore to query.
+ *
+ * \return io unit size.
+ */
+uint64_t spdk_bs_get_io_unit_size(struct spdk_blob_store *bs);
+
+/**
+ * Get the number of free clusters.
+ *
+ * \param bs blobstore to query.
+ *
+ * \return the number of free clusters.
+ */
+uint64_t spdk_bs_free_cluster_count(struct spdk_blob_store *bs);
+
+/**
+ * Get the total number of clusters accessible by user.
+ *
+ * \param bs blobstore to query.
+ *
+ * \return the total number of clusters accessible by user.
+ */
+uint64_t spdk_bs_total_data_cluster_count(struct spdk_blob_store *bs);
+
+/**
+ * Get the blob id.
+ *
+ * \param blob Blob struct to query.
+ *
+ * \return blob id.
+ */
+spdk_blob_id spdk_blob_get_id(struct spdk_blob *blob);
+
+/**
+ * Get the number of pages allocated to the blob.
+ *
+ * \param blob Blob struct to query.
+ *
+ * \return the number of pages.
+ */
+uint64_t spdk_blob_get_num_pages(struct spdk_blob *blob);
+
+/**
+ * Get the number of io_units allocated to the blob.
+ *
+ * \param blob Blob struct to query.
+ *
+ * \return the number of io_units.
+ */
+uint64_t spdk_blob_get_num_io_units(struct spdk_blob *blob);
+
+/**
+ * Get the number of clusters allocated to the blob.
+ *
+ * \param blob Blob struct to query.
+ *
+ * \return the number of clusters.
+ */
+uint64_t spdk_blob_get_num_clusters(struct spdk_blob *blob);
+
+struct spdk_blob_xattr_opts {
+ /* Number of attributes */
+ size_t count;
+ /* Array of attribute names. Caller should free this array after use. */
+ char **names;
+ /* User context passed to get_xattr_value function */
+ void *ctx;
+ /* Callback that will return value for each attribute name. */
+ void (*get_value)(void *xattr_ctx, const char *name,
+ const void **value, size_t *value_len);
+};
+
+struct spdk_blob_opts {
+ uint64_t num_clusters;
+ bool thin_provision;
+ struct spdk_blob_xattr_opts xattrs;
+};
+
+/**
+ * Initialize a spdk_blob_opts structure to the default blob option values.
+ *
+ * \param opts spdk_blob_opts structure to initialize.
+ */
+void spdk_blob_opts_init(struct spdk_blob_opts *opts);
+
+/**
+ * Create a new blob with options on the given blobstore. The new blob id will
+ * be passed to the callback function.
+ *
+ * \param bs blobstore.
+ * \param opts The structure which contains the option values for the new blob.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to funcion cb_fn.
+ */
+void spdk_bs_create_blob_ext(struct spdk_blob_store *bs, const struct spdk_blob_opts *opts,
+ spdk_blob_op_with_id_complete cb_fn, void *cb_arg);
+
+/**
+ * Create a new blob with default option values on the given blobstore.
+ * The new blob id will be passed to the callback function.
+ *
+ * \param bs blobstore.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_create_blob(struct spdk_blob_store *bs,
+ spdk_blob_op_with_id_complete cb_fn, void *cb_arg);
+
+/**
+ * Create a read-only snapshot of specified blob with provided options.
+ * This will automatically sync specified blob.
+ *
+ * When operation is done, original blob is converted to the thin-provisioned
+ * blob with a newly created read-only snapshot set as a backing blob.
+ * Structure snapshot_xattrs as well as anything it references (like e.g. names
+ * array) must be valid until the completion is called.
+ *
+ * \param bs blobstore.
+ * \param blobid Id of the source blob used to create a snapshot.
+ * \param snapshot_xattrs xattrs specified for snapshot.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_create_snapshot(struct spdk_blob_store *bs, spdk_blob_id blobid,
+ const struct spdk_blob_xattr_opts *snapshot_xattrs,
+ spdk_blob_op_with_id_complete cb_fn, void *cb_arg);
+
+/**
+ * Create a clone of specified read-only blob.
+ *
+ * Structure clone_xattrs as well as anything it references (like e.g. names
+ * array) must be valid until the completion is called.
+ *
+ * \param bs blobstore.
+ * \param blobid Id of the read only blob used as a snapshot for new clone.
+ * \param clone_xattrs xattrs specified for clone.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_create_clone(struct spdk_blob_store *bs, spdk_blob_id blobid,
+ const struct spdk_blob_xattr_opts *clone_xattrs,
+ spdk_blob_op_with_id_complete cb_fn, void *cb_arg);
+
+/**
+ * Provide table with blob id's of clones are dependent on specified snapshot.
+ *
+ * Ids array should be allocated and the count parameter set to the number of
+ * id's it can store, before calling this function.
+ *
+ * If ids is NULL or count parameter is not sufficient to handle ids of all
+ * clones, -ENOMEM error is returned and count parameter is updated to the
+ * total number of clones.
+ *
+ * \param bs blobstore.
+ * \param blobid Snapshots blob id.
+ * \param ids Array of the clone ids or NULL to get required size in count.
+ * \param count Size of ids. After call it is updated to the number of clones.
+ *
+ * \return -ENOMEM if count is not sufficient to store all clones.
+ */
+int spdk_blob_get_clones(struct spdk_blob_store *bs, spdk_blob_id blobid, spdk_blob_id *ids,
+ size_t *count);
+
+/**
+ * Get the blob id for the parent snapshot of this blob.
+ *
+ * \param bs blobstore.
+ * \param blobid Blob id.
+ *
+ * \return blob id of parent blob or SPDK_BLOBID_INVALID if have no parent
+ */
+spdk_blob_id spdk_blob_get_parent_snapshot(struct spdk_blob_store *bs, spdk_blob_id blobid);
+
+/**
+ * Check if blob is read only.
+ *
+ * \param blob Blob.
+ *
+ * \return true if blob is read only.
+ */
+bool spdk_blob_is_read_only(struct spdk_blob *blob);
+
+/**
+ * Check if blob is a snapshot.
+ *
+ * \param blob Blob.
+ *
+ * \return true if blob is a snapshot.
+ */
+bool spdk_blob_is_snapshot(struct spdk_blob *blob);
+
+/**
+ * Check if blob is a clone.
+ *
+ * \param blob Blob.
+ *
+ * \return true if blob is a clone.
+ */
+bool spdk_blob_is_clone(struct spdk_blob *blob);
+
+/**
+ * Check if blob is thin-provisioned.
+ *
+ * \param blob Blob.
+ *
+ * \return true if blob is thin-provisioned.
+ */
+bool spdk_blob_is_thin_provisioned(struct spdk_blob *blob);
+
+/**
+ * Delete an existing blob from the given blobstore.
+ *
+ * \param bs blobstore.
+ * \param blobid The id of the blob to delete.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_delete_blob(struct spdk_blob_store *bs, spdk_blob_id blobid,
+ spdk_blob_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Allocate all clusters in this blob. Data for allocated clusters is copied
+ * from backing blob(s) if they exist.
+ *
+ * This call removes all dependencies on any backing blobs.
+ *
+ * \param bs blobstore.
+ * \param channel IO channel used to inflate blob.
+ * \param blobid The id of the blob to inflate.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_inflate_blob(struct spdk_blob_store *bs, struct spdk_io_channel *channel,
+ spdk_blob_id blobid, spdk_blob_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Remove dependency on parent blob.
+ *
+ * This call allocates and copies data for any clusters that are allocated in
+ * the parent blob, and decouples parent updating dependencies of blob to
+ * its ancestor.
+ *
+ * If blob have no parent -EINVAL error is reported.
+ *
+ * \param bs blobstore.
+ * \param channel IO channel used to inflate blob.
+ * \param blobid The id of the blob.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_blob_decouple_parent(struct spdk_blob_store *bs, struct spdk_io_channel *channel,
+ spdk_blob_id blobid, spdk_blob_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Open a blob from the given blobstore.
+ *
+ * \param bs blobstore.
+ * \param blobid The id of the blob to open.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_open_blob(struct spdk_blob_store *bs, spdk_blob_id blobid,
+ spdk_blob_op_with_handle_complete cb_fn, void *cb_arg);
+
+/**
+ * Resize a blob to 'sz' clusters. These changes are not persisted to disk until
+ * spdk_bs_md_sync_blob() is called.
+ * If called before previous resize finish, it will fail with errno -EBUSY
+ *
+ * \param blob Blob to resize.
+ * \param sz The new number of clusters.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ *
+ */
+void spdk_blob_resize(struct spdk_blob *blob, uint64_t sz, spdk_blob_op_complete cb_fn,
+ void *cb_arg);
+
+/**
+ * Set blob as read only.
+ *
+ * These changes do not take effect until spdk_blob_sync_md() is called.
+ *
+ * \param blob Blob to set.
+ */
+int spdk_blob_set_read_only(struct spdk_blob *blob);
+
+/**
+ * Sync a blob.
+ *
+ * Make a blob persistent. This applies to open, resize, set xattr, and remove
+ * xattr. These operations will not be persistent until the blob has been synced.
+ *
+ * \param blob Blob to sync.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_blob_sync_md(struct spdk_blob *blob, spdk_blob_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Close a blob. This will automatically sync.
+ *
+ * \param blob Blob to close.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_blob_close(struct spdk_blob *blob, spdk_blob_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Allocate an I/O channel for the given blobstore.
+ *
+ * \param bs blobstore.
+ * \return a pointer to the allocated I/O channel.
+ */
+struct spdk_io_channel *spdk_bs_alloc_io_channel(struct spdk_blob_store *bs);
+
+/**
+ * Free the I/O channel.
+ *
+ * \param channel I/O channel to free.
+ */
+void spdk_bs_free_io_channel(struct spdk_io_channel *channel);
+
+/**
+ * Write data to a blob.
+ *
+ * \param blob Blob to write.
+ * \param channel The I/O channel used to submit requests.
+ * \param payload The specified buffer which should contain the data to be written.
+ * \param offset Offset is in io units from the beginning of the blob.
+ * \param length Size of data in io units.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_blob_io_write(struct spdk_blob *blob, struct spdk_io_channel *channel,
+ void *payload, uint64_t offset, uint64_t length,
+ spdk_blob_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Read data from a blob.
+ *
+ * \param blob Blob to read.
+ * \param channel The I/O channel used to submit requests.
+ * \param payload The specified buffer which will store the obtained data.
+ * \param offset Offset is in io units from the beginning of the blob.
+ * \param length Size of data in io units.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_blob_io_read(struct spdk_blob *blob, struct spdk_io_channel *channel,
+ void *payload, uint64_t offset, uint64_t length,
+ spdk_blob_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Write the data described by 'iov' to 'length' pages beginning at 'offset' pages
+ * into the blob.
+ *
+ * \param blob Blob to write.
+ * \param channel I/O channel used to submit requests.
+ * \param iov The pointer points to an array of iovec structures.
+ * \param iovcnt The number of buffers.
+ * \param offset Offset is in io units from the beginning of the blob.
+ * \param length Size of data in io units.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_blob_io_writev(struct spdk_blob *blob, struct spdk_io_channel *channel,
+ struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
+ spdk_blob_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Read 'length' pages starting at 'offset' pages into the blob into the memory
+ * described by 'iov'.
+ *
+ * \param blob Blob to read.
+ * \param channel I/O channel used to submit requests.
+ * \param iov The pointer points to an array of iovec structures.
+ * \param iovcnt The number of buffers.
+ * \param offset Offset is in io units from the beginning of the blob.
+ * \param length Size of data in io units.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_blob_io_readv(struct spdk_blob *blob, struct spdk_io_channel *channel,
+ struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
+ spdk_blob_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Unmap 'length' pages beginning at 'offset' pages on the blob as unused. Unmapped
+ * pages may allow the underlying storage media to behave more effciently.
+ *
+ * \param blob Blob to unmap.
+ * \param channel I/O channel used to submit requests.
+ * \param offset Offset is in io units from the beginning of the blob.
+ * \param length Size of unmap area in pages.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_blob_io_unmap(struct spdk_blob *blob, struct spdk_io_channel *channel,
+ uint64_t offset, uint64_t length, spdk_blob_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Write zeros into area of a blob.
+ *
+ * \param blob Blob to write.
+ * \param channel I/O channel used to submit requests.
+ * \param offset Offset is in io units from the beginning of the blob.
+ * \param length Size of data in io units.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_blob_io_write_zeroes(struct spdk_blob *blob, struct spdk_io_channel *channel,
+ uint64_t offset, uint64_t length, spdk_blob_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Get the first blob of the blobstore. The obtained blob will be passed to
+ * the callback function.
+ *
+ * \param bs blobstore to traverse.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_iter_first(struct spdk_blob_store *bs,
+ spdk_blob_op_with_handle_complete cb_fn, void *cb_arg);
+
+/**
+ * Get the next blob by using the current blob. The obtained blob will be passed
+ * to the callback function.
+ *
+ * \param bs blobstore to traverse.
+ * \param blob The current blob.
+ * \param cb_fn Called when the operation is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_bs_iter_next(struct spdk_blob_store *bs, struct spdk_blob *blob,
+ spdk_blob_op_with_handle_complete cb_fn, void *cb_arg);
+
+/**
+ * Set an extended attribute for the given blob.
+ *
+ * \param blob Blob to set attribute.
+ * \param name Name of the extended attribute.
+ * \param value Value of the extended attribute.
+ * \param value_len Length of the value.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_blob_set_xattr(struct spdk_blob *blob, const char *name, const void *value,
+ uint16_t value_len);
+
+/**
+ * Remove the extended attribute from the given blob.
+ *
+ * \param blob Blob to remove attribute.
+ * \param name Name of the extended attribute.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_blob_remove_xattr(struct spdk_blob *blob, const char *name);
+
+/**
+ * Get the value of the specified extended attribute. The obtained value and its
+ * size will be stored in value and value_len.
+ *
+ * \param blob Blob to query.
+ * \param name Name of the extended attribute.
+ * \param value Parameter as output.
+ * \param value_len Parameter as output.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_blob_get_xattr_value(struct spdk_blob *blob, const char *name,
+ const void **value, size_t *value_len);
+
+/**
+ * Iterate through all extended attributes of the blob. Get the names of all extended
+ * attributes that will be stored in names.
+ *
+ * \param blob Blob to query.
+ * \param names Parameter as output.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_blob_get_xattr_names(struct spdk_blob *blob, struct spdk_xattr_names **names);
+
+/**
+ * Get the number of extended attributes.
+ *
+ * \param names Names of total extended attributes of the blob.
+ *
+ * \return the number of extended attributes.
+ */
+uint32_t spdk_xattr_names_get_count(struct spdk_xattr_names *names);
+
+/**
+ * Get the attribute name specified by the index.
+ *
+ * \param names Names of total extended attributes of the blob.
+ * \param index Index position of the specified attribute.
+ *
+ * \return attribute name.
+ */
+const char *spdk_xattr_names_get_name(struct spdk_xattr_names *names, uint32_t index);
+
+/**
+ * Free the attribute names.
+ *
+ * \param names Names of total extended attributes of the blob.
+ */
+void spdk_xattr_names_free(struct spdk_xattr_names *names);
+
+/**
+ * Get blobstore type of the given device.
+ *
+ * \param bs blobstore to query.
+ *
+ * \return blobstore type.
+ */
+struct spdk_bs_type spdk_bs_get_bstype(struct spdk_blob_store *bs);
+
+/**
+ * Set blobstore type to the given device.
+ *
+ * \param bs blobstore to set to.
+ * \param bstype Type label to set.
+ */
+void spdk_bs_set_bstype(struct spdk_blob_store *bs, struct spdk_bs_type bstype);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_BLOB_H_ */
diff --git a/src/spdk/include/spdk/blob_bdev.h b/src/spdk/include/spdk/blob_bdev.h
new file mode 100644
index 00000000..dcaa5b18
--- /dev/null
+++ b/src/spdk/include/spdk/blob_bdev.h
@@ -0,0 +1,78 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Helper library to use spdk_bdev as the backing device for a blobstore
+ */
+
+#ifndef SPDK_BLOB_BDEV_H
+#define SPDK_BLOB_BDEV_H
+
+#include "spdk/stdinc.h"
+#include "spdk/bdev.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct spdk_bs_dev;
+struct spdk_bdev;
+struct spdk_bdev_module;
+
+/**
+ * Create a blobstore block device from a bdev.
+ *
+ * \param bdev Bdev to use.
+ * \param remove_cb Called when the block device is removed.
+ * \param remove_ctx Argument passed to function remove_cb.
+ *
+ * \return a pointer to the blobstore block device on success or NULL otherwise.
+ */
+struct spdk_bs_dev *spdk_bdev_create_bs_dev(struct spdk_bdev *bdev, spdk_bdev_remove_cb_t remove_cb,
+ void *remove_ctx);
+
+/**
+ * Claim the bdev module for the given blobstore.
+ *
+ * \param bs_dev Blobstore block device.
+ * \param module Bdev module to claim.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_bs_bdev_claim(struct spdk_bs_dev *bs_dev, struct spdk_bdev_module *module);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/blobfs.h b/src/spdk/include/spdk/blobfs.h
new file mode 100644
index 00000000..05d5d999
--- /dev/null
+++ b/src/spdk/include/spdk/blobfs.h
@@ -0,0 +1,406 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * SPDK Filesystem
+ */
+
+#ifndef SPDK_FS_H
+#define SPDK_FS_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/blob.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPDK_FILE_NAME_MAX 255
+
+struct spdk_file;
+struct spdk_filesystem;
+
+typedef struct spdk_file *spdk_fs_iter;
+
+struct spdk_blobfs_opts {
+ uint32_t cluster_sz;
+};
+
+struct spdk_file_stat {
+ spdk_blob_id blobid;
+ uint64_t size;
+};
+
+/**
+ * Filesystem operation completion callback with handle.
+ *
+ * \param ctx Context for the operation.
+ * \param fs Handle to a blobfs.
+ * \param fserrno 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_fs_op_with_handle_complete)(void *ctx, struct spdk_filesystem *fs,
+ int fserrno);
+
+/**
+ * File operation completion callback with handle.
+ *
+ * \param ctx Context for the operation.
+ * \param f Handle to a file.
+ * \param fserrno 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_file_op_with_handle_complete)(void *ctx, struct spdk_file *f, int fserrno);
+typedef spdk_bs_op_complete spdk_fs_op_complete;
+
+/**
+ * File operation completion callback.
+ *
+ * \param ctx Context for the operation.
+ * \param fserrno 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_file_op_complete)(void *ctx, int fserrno);
+
+/**
+ * File stat operation completion callback.
+ *
+ * \param ctx Context for the operation.
+ * \param stat Handle to the stat about the file.
+ * \param fserrno 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_file_stat_op_complete)(void *ctx, struct spdk_file_stat *stat, int fserrno);
+
+/**
+ * Function for a request of file system.
+ *
+ * \param arg Argument to the request function.
+ */
+typedef void (*fs_request_fn)(void *arg);
+
+/**
+ * Function for sending request.
+ *
+ * This function will be invoked any time when the filesystem wants to pass a
+ * message to the main dispatch thread.
+ *
+ * \param fs_request_fn A pointer to the request function.
+ * \param arg Argument to the request function.
+ */
+typedef void (*fs_send_request_fn)(fs_request_fn, void *arg);
+
+/**
+ * Initialize a spdk_blobfs_opts structure to the default option values.
+ *
+ * \param opts spdk_blobf_opts struture to intialize.
+ */
+void spdk_fs_opts_init(struct spdk_blobfs_opts *opts);
+
+/**
+ * Initialize blobstore filesystem.
+ *
+ * Initialize the blobstore filesystem on the blobstore block device which has
+ * been created by the function spdk_bdev_create_bs_dev() in the blob_bdev.h.
+ * The obtained blobstore filesystem will be passed to the callback function.
+ *
+ * \param dev Blobstore block device used by this blobstore filesystem.
+ * \param opt Initialization options used for this blobstore filesystem.
+ * \param send_request_fn The function for sending request. This function will
+ * be invoked any time when the blobstore filesystem wants to pass a message to
+ * the main dispatch thread.
+ * \param cb_fn Called when the initialization is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_fs_init(struct spdk_bs_dev *dev, struct spdk_blobfs_opts *opt,
+ fs_send_request_fn send_request_fn,
+ spdk_fs_op_with_handle_complete cb_fn, void *cb_arg);
+
+/**
+ * Load blobstore filesystem from the given blobstore block device.
+ *
+ * The obtained blobstore filesystem will be passed to the callback function.
+ *
+ * \param dev Blobstore block device used by this blobstore filesystem.
+ * \param send_request_fn The function for sending request. This function will
+ * be invoked any time when the blobstore filesystem wants to pass a message to
+ * the main dispatch thread.
+ * \param cb_fn Called when the loading is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_fs_load(struct spdk_bs_dev *dev, fs_send_request_fn send_request_fn,
+ spdk_fs_op_with_handle_complete cb_fn, void *cb_arg);
+
+/**
+ * Unload blobstore filesystem.
+ *
+ * \param fs Blobstore filesystem to unload.
+ * \param cb_fn Called when the unloading is complete.
+ * \param cb_arg Argument passed to function cb_fn.
+ */
+void spdk_fs_unload(struct spdk_filesystem *fs, spdk_fs_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Allocate an I/O channel for asynchronous operations.
+ *
+ * \param fs Blobstore filesystem to allocate I/O channel.
+ *
+ * \return a pointer to the I/O channel on success or NULL otherwise.
+ */
+struct spdk_io_channel *spdk_fs_alloc_io_channel(struct spdk_filesystem *fs);
+
+/**
+ * Allocate an I/O channel for synchronous operations.
+ *
+ * \param fs Blobstore filesystem to allocate I/O channel.
+ *
+ * \return a pointer to the I/O channel on success or NULL otherwise.
+ */
+struct spdk_io_channel *spdk_fs_alloc_io_channel_sync(struct spdk_filesystem *fs);
+
+/**
+ * Free I/O channel.
+ *
+ * This function will decrease the references of this I/O channel. If the reference
+ * is reduced to 0, the I/O channel will be freed.
+ *
+ * \param channel I/O channel to free.
+ */
+void spdk_fs_free_io_channel(struct spdk_io_channel *channel);
+
+/**
+ * Get statistics about the file including the underlying blob id and the file size.
+ *
+ * \param fs Blobstore filesystem.
+ * \param channel The I/O channel used to allocate file request.
+ * \param name The file name used to look up the matched file in the blobstore filesystem.
+ * \param stat Caller allocated structure to store the obtained information about
+ * this file.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_fs_file_stat(struct spdk_filesystem *fs, struct spdk_io_channel *channel,
+ const char *name, struct spdk_file_stat *stat);
+
+#define SPDK_BLOBFS_OPEN_CREATE (1ULL << 0)
+
+/**
+ * Create a new file on the given blobstore filesystem.
+ *
+ * \param fs Blobstore filesystem.
+ * \param channel The I/O channel used to allocate file request.
+ * \param name The file name for this new file.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_fs_create_file(struct spdk_filesystem *fs, struct spdk_io_channel *channel,
+ const char *name);
+
+/**
+ * Open the file.
+ *
+ * \param fs Blobstore filesystem.
+ * \param channel The I/O channel used to allocate file request.
+ * \param name The file name used to look up the matched file in the blobstore filesystem.
+ * \param flags This flags will be used to control the open mode.
+ * \param file It will point to the open file if sccessful or NULL otherwirse.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_fs_open_file(struct spdk_filesystem *fs, struct spdk_io_channel *channel,
+ const char *name, uint32_t flags, struct spdk_file **file);
+
+/**
+ * Close the file.
+ *
+ * \param file File to close.
+ * \param channel The I/O channel used to allocate file request.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_file_close(struct spdk_file *file, struct spdk_io_channel *channel);
+
+/**
+ * Change the file name.
+ *
+ * This operation will overwrite an existing file if there is a file with the
+ * same name.
+ *
+ * \param fs Blobstore filesystem.
+ * \param channel The I/O channel used to allocate file request.
+ * \param old_name Old name of the file.
+ * \param new_name New name of the file.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_fs_rename_file(struct spdk_filesystem *fs, struct spdk_io_channel *channel,
+ const char *old_name, const char *new_name);
+
+/**
+ * Delete the file.
+ *
+ * \param fs Blobstore filesystem.
+ * \param channel The I/O channel used to allocate file request.
+ * \param name The name of the file to be deleted.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_fs_delete_file(struct spdk_filesystem *fs, struct spdk_io_channel *channel,
+ const char *name);
+
+/**
+ * Get the first file in the blobstore filesystem.
+ *
+ * \param fs Blobstore filesystem to traverse.
+ *
+ * \return an iterator which points to the first file in the blobstore filesystem.
+ */
+spdk_fs_iter spdk_fs_iter_first(struct spdk_filesystem *fs);
+
+/**
+ * Get the next file in the blobstore filesystem by using the input iterator.
+ *
+ * \param iter The iterator which points to the current file struct.
+ *
+ * \return an iterator which points to the next file in the blobstore filesystem.
+ */
+spdk_fs_iter spdk_fs_iter_next(spdk_fs_iter iter);
+
+#define spdk_fs_iter_get_file(iter) ((struct spdk_file *)(iter))
+
+/**
+ * Truncate the file.
+ *
+ * \param file File to truncate.
+ * \param channel The I/O channel used to allocate file request.
+ * \param length New size in bytes of the file.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_file_truncate(struct spdk_file *file, struct spdk_io_channel *channel,
+ uint64_t length);
+
+/**
+ * Get file name.
+ *
+ * \param file File to query.
+ *
+ * \return the name of the file.
+ */
+const char *spdk_file_get_name(struct spdk_file *file);
+
+/**
+ * Obtain the size of the file.
+ *
+ * \param file File to query.
+ *
+ * \return the size in bytes of the file.
+ */
+uint64_t spdk_file_get_length(struct spdk_file *file);
+
+/**
+ * Write data to the given file.
+ *
+ * \param file File to write.
+ * \param channel The I/O channel used to allocate file request.
+ * \param payload The specified buffer which should contain the data to be transmitted.
+ * \param offset The beginning position to write data.
+ * \param length The size in bytes of data to write.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_file_write(struct spdk_file *file, struct spdk_io_channel *channel,
+ void *payload, uint64_t offset, uint64_t length);
+
+/**
+ * Read data to user buffer from the given file.
+ *
+ * \param file File to read.
+ * \param channel The I/O channel used to allocate file request.
+ * \param payload The specified buffer which will store the obtained data.
+ * \param offset The beginning position to read.
+ * \param length The size in bytes of data to read.
+ *
+ * \return the end position of this read operation on success, negated errno on failure.
+ */
+int64_t spdk_file_read(struct spdk_file *file, struct spdk_io_channel *channel,
+ void *payload, uint64_t offset, uint64_t length);
+
+/**
+ * Set cache size for the blobstore filesystem.
+ *
+ * \param size_in_mb Cache size in megabytes.
+ */
+void spdk_fs_set_cache_size(uint64_t size_in_mb);
+
+/**
+ * Obtain the cache size.
+ *
+ * \return cache size in megabytes.
+ */
+uint64_t spdk_fs_get_cache_size(void);
+
+#define SPDK_FILE_PRIORITY_LOW 0 /* default */
+#define SPDK_FILE_PRIORITY_HIGH 1
+
+/**
+ * Set priority for the file.
+ *
+ * \param file File to set priority.
+ * \param priority Priority level (SPDK_FILE_PRIORITY_LOW or SPDK_FILE_PRIORITY_HIGH).
+ */
+void spdk_file_set_priority(struct spdk_file *file, uint32_t priority);
+
+/**
+ * Synchronize the data from the cache to the disk.
+ *
+ * \param file File to sync.
+ * \param channel The I/O channel used to allocate file request.
+ *
+ * \return 0 on success.
+ */
+int spdk_file_sync(struct spdk_file *file, struct spdk_io_channel *channel);
+
+/**
+ * Get the unique ID for the file.
+ *
+ * \param file File to get the ID.
+ * \param id ID buffer.
+ * \param size Size of the ID buffer.
+ *
+ * \return the length of ID on success.
+ */
+int spdk_file_get_id(struct spdk_file *file, void *id, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_FS_H_ */
diff --git a/src/spdk/include/spdk/conf.h b/src/spdk/include/spdk/conf.h
new file mode 100644
index 00000000..51cbd8d6
--- /dev/null
+++ b/src/spdk/include/spdk/conf.h
@@ -0,0 +1,208 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Configuration file parser
+ */
+
+#ifndef SPDK_CONF_H
+#define SPDK_CONF_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct spdk_conf_value;
+struct spdk_conf_item;
+struct spdk_conf_section;
+struct spdk_conf;
+
+/**
+ * Allocate a configuration struct used for the initialization of SPDK app.
+ *
+ * \return a pointer to the allocated configuration struct.
+ */
+struct spdk_conf *spdk_conf_allocate(void);
+
+/**
+ * Free the configuration struct.
+ *
+ * \param cp Configuration struct to free.
+ */
+void spdk_conf_free(struct spdk_conf *cp);
+
+/**
+ * Read configuration file for spdk_conf struct.
+ *
+ * \param cp Configuration struct used for the initialization of SPDK app.
+ * \param file File to read that is created by user to configure SPDK app.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_conf_read(struct spdk_conf *cp, const char *file);
+
+/**
+ * Find the specified section of the configuration.
+ *
+ * \param cp Configuration struct used for the initialization of SPDK app.
+ * \param name Name of section to find.
+ *
+ * \return a pointer to the requested section on success or NULL otherwise.
+ */
+struct spdk_conf_section *spdk_conf_find_section(struct spdk_conf *cp, const char *name);
+
+/**
+ * Get the first section of the configuration.
+ *
+ * \param cp Configuration struct used for the initialization of SPDK app.
+ *
+ * \return a pointer to the requested section on success or NULL otherwise.
+ */
+struct spdk_conf_section *spdk_conf_first_section(struct spdk_conf *cp);
+
+/**
+ * Get the next section of the configuration.
+ *
+ * \param sp The current section of the configuration.
+ *
+ * \return a pointer to the requested section on success or NULL otherwise.
+ */
+struct spdk_conf_section *spdk_conf_next_section(struct spdk_conf_section *sp);
+
+/**
+ * Match prefix of the name of section.
+ *
+ * \param sp The section of the configuration.
+ * \param name_prefix Prefix name to match.
+ *
+ * \return ture on success, false on failure.
+ */
+bool spdk_conf_section_match_prefix(const struct spdk_conf_section *sp, const char *name_prefix);
+
+/**
+ * Get the name of the section.
+ *
+ * \param sp The section of the configuration.
+ *
+ * \return the name of the section.
+ */
+const char *spdk_conf_section_get_name(const struct spdk_conf_section *sp);
+
+/**
+ * Get the number of the section.
+ *
+ * \param sp The section of the configuration.
+ *
+ * \return the number of the section.
+ */
+int spdk_conf_section_get_num(const struct spdk_conf_section *sp);
+
+/**
+ * Get the value of the item with name 'key' in the section.
+ *
+ * If key appears multiple times, idx1 will control which version to retrieve.
+ * Indices will start from the top of the configuration file at 0 and increment
+ * by one for each new apperarance. If the configuration key contains multiple
+ * whitespace delimited values, idx2 controls which value is returned. The index
+ * begins at 0.
+ *
+ *
+ * \param sp The section of the configuration.
+ * \param key Name of item.
+ * \param idx1 The index into the item list for the key.
+ * \param idx2 The index into the value list for the item.
+ *
+ * \return the requested value on success or NULL otherwise.
+ */
+char *spdk_conf_section_get_nmval(struct spdk_conf_section *sp, const char *key,
+ int idx1, int idx2);
+
+/**
+ * Get the first value of the item with name 'key' in the section.
+ *
+ * \param sp The section of the configuration.
+ * \param key Name of item.
+ * \param idx The index into the value list for the item.
+ *
+ * \return the requested value on success or NULL otherwise.
+ */
+char *spdk_conf_section_get_nval(struct spdk_conf_section *sp, const char *key, int idx);
+
+/**
+ * Get the first value of the first item with name 'key' in the section.
+ *
+ * \param sp The section of the configuration.
+ * \param key Name of item.
+ *
+ * \return the requested value on success or NULL otherwise.
+ */
+char *spdk_conf_section_get_val(struct spdk_conf_section *sp, const char *key);
+
+/**
+ * Get the first value of the first item with name 'key' in the section.
+ *
+ * \param sp The section of the configuration.
+ * \param key Name of item.
+ *
+ * \return the requested value on success or NULL otherwise.
+ */
+int spdk_conf_section_get_intval(struct spdk_conf_section *sp, const char *key);
+
+/**
+ * Get the bool value of the item with name 'key' in the section.
+ *
+ * This is used to check whether the service is enabled.
+ *
+ * \param sp The section of the configuration.
+ * \param key Name of item.
+ * \param default_val Default value.
+ *
+ * \return true if matching 'Yes/Y/True', false if matching 'No/N/False', default value otherwise.
+ */
+bool spdk_conf_section_get_boolval(struct spdk_conf_section *sp, const char *key, bool default_val);
+
+/**
+ * Set the configuration as the default.
+ *
+ * \param cp Configuration to set.
+ */
+void spdk_conf_set_as_default(struct spdk_conf *cp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/copy_engine.h b/src/spdk/include/spdk/copy_engine.h
new file mode 100644
index 00000000..06dc1560
--- /dev/null
+++ b/src/spdk/include/spdk/copy_engine.h
@@ -0,0 +1,147 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Memory copy offload engine abstraction layer
+ */
+
+#ifndef SPDK_COPY_ENGINE_H
+#define SPDK_COPY_ENGINE_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Copy operation callback.
+ *
+ * \param ref 'copy_req' passed to the corresponding spdk_copy_submit() call.
+ * \param status 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_copy_completion_cb)(void *ref, int status);
+
+/**
+ * Copy engine finish callback.
+ *
+ * \param cb_arg Callback argument.
+ */
+typedef void (*spdk_copy_fini_cb)(void *cb_arg);
+
+struct spdk_io_channel;
+
+struct spdk_copy_task;
+
+/**
+ * Initialize the copy engine.
+ *
+ * \return 0 on success.
+ */
+int spdk_copy_engine_initialize(void);
+
+/**
+ * Close the copy engine.
+ *
+ * \param cb_fn Called when the close operation completes.
+ * \param cb_arg Argument passed to the callback function.
+ */
+void spdk_copy_engine_finish(spdk_copy_fini_cb cb_fn, void *cb_arg);
+
+/**
+ * Get the configuration for the copy engine.
+ *
+ * \param fp The pointer to a file that will be written to the configuration.
+ */
+void spdk_copy_engine_config_text(FILE *fp);
+
+/**
+ * Close the copy engine module and perform any necessary cleanup.
+ */
+void spdk_copy_engine_module_finish(void);
+
+/**
+ * Get the I/O channel registered on the copy engine.
+ *
+ * This I/O channel is used to submit copy request.
+ *
+ * \return a pointer to the I/O channel on success, or NULL on failure.
+ */
+struct spdk_io_channel *spdk_copy_engine_get_io_channel(void);
+
+/**
+ * Submit a copy request.
+ *
+ * \param copy_req Copy request task.
+ * \param ch I/O channel to submit request to the copy engine. This channel can
+ * be obtained by the function spdk_copy_engine_get_io_channel().
+ * \param dst Destination to copy to.
+ * \param src Source to copy from.
+ * \param nbytes Length in bytes to copy.
+ * \param cb Called when this copy operation completes.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_copy_submit(struct spdk_copy_task *copy_req, struct spdk_io_channel *ch, void *dst,
+ void *src, uint64_t nbytes, spdk_copy_completion_cb cb);
+
+/**
+ * Submit a fill request.
+ *
+ * This operation will fill the destination buffer with the specified value.
+ *
+ * \param copy_req Copy request task.
+ * \param ch I/O channel to submit request to the copy engine. This channel can
+ * be obtained by the function spdk_copy_engine_get_io_channel().
+ * \param dst Destination to fill.
+ * \param fill Constant byte to fill to the destination.
+ * \param nbytes Length in bytes to fill.
+ * \param cb Called when this copy operation completes.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_copy_submit_fill(struct spdk_copy_task *copy_req, struct spdk_io_channel *ch,
+ void *dst, uint8_t fill, uint64_t nbytes, spdk_copy_completion_cb cb);
+
+/**
+ * Get the size of copy task.
+ *
+ * \return the size of copy task.
+ */
+size_t spdk_copy_task_size(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/cpuset.h b/src/spdk/include/spdk/cpuset.h
new file mode 100644
index 00000000..d5930571
--- /dev/null
+++ b/src/spdk/include/spdk/cpuset.h
@@ -0,0 +1,164 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * CPU set management functions
+ */
+
+#ifndef SPDK_CPUSET_H
+#define SPDK_CPUSET_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPDK_CPUSET_SIZE 1024
+
+/**
+ * List of CPUs.
+ */
+struct spdk_cpuset;
+
+/**
+ * Allocate CPU set object.
+ *
+ * \return a pointer to the allocated zeroed cpuset on success, or NULL on failure.
+ */
+struct spdk_cpuset *spdk_cpuset_alloc(void);
+
+/**
+ * Free allocated CPU set.
+ *
+ * \param set CPU set to be freed.
+ */
+void spdk_cpuset_free(struct spdk_cpuset *set);
+
+/**
+ * Compare two CPU sets.
+ *
+ * \param set1 CPU set1.
+ * \param set2 CPU set2.
+ *
+ * \return true if both CPU sets are equal.
+ */
+bool spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2);
+
+/**
+ * Copy the content of CPU set to another.
+ *
+ * \param dst Destination CPU set
+ * \param src Source CPU set
+ */
+void spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src);
+
+/**
+ * Perform AND operation on two CPU sets. The result is stored in dst.
+ *
+ * \param dst First argument of operation. This value also stores the result of operation.
+ * \param src Second argument of operation.
+ */
+void spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src);
+
+/**
+ * Perform OR operation on two CPU sets. The result is stored in dst.
+ *
+ * \param dst First argument of operation. This value also stores the result of operation.
+ * \param src Second argument of operation.
+ */
+void spdk_cpuset_or(struct spdk_cpuset *dst, const struct spdk_cpuset *src);
+
+/**
+ * Clear all CPUs in CPU set.
+ *
+ * \param set CPU set to be cleared.
+ */
+void spdk_cpuset_zero(struct spdk_cpuset *set);
+
+/**
+ * Set or clear CPU state in CPU set.
+ *
+ * \param set CPU set object.
+ * \param cpu CPU index to be set or cleared.
+ * \param state *true* to set cpu, *false* to clear.
+ */
+void spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state);
+
+/**
+ * Get the state of CPU in CPU set.
+ *
+ * \param set CPU set object.
+ * \param cpu CPU index.
+ *
+ * \return the state of selected CPU.
+ */
+bool spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu);
+
+/**
+ * Get the number of CPUs that are set in CPU set.
+ *
+ * \param set CPU set object.
+ *
+ * \return the number of CPUs.
+ */
+uint32_t spdk_cpuset_count(const struct spdk_cpuset *set);
+
+/**
+ * Convert a CPU set to hex string.
+ *
+ * \param set CPU set.
+ *
+ * \return a pointer to hexadecimal representation of CPU set. Buffer to store a
+ * string is dynamically allocated internally and freed with CPU set object.
+ * Memory returned by this function might be changed after subsequent calls to
+ * this function so string should be copied by user.
+ */
+const char *spdk_cpuset_fmt(struct spdk_cpuset *set);
+
+/**
+ * Convert a string containing a CPU core mask into a CPU set.
+ *
+ * \param set CPU set.
+ * \param mask String defining CPU set. By default hexadecimal value is used or
+ * as CPU list enclosed in square brackets defined as: 'c1[-c2][,c3[-c4],...]'.
+ *
+ * \return zero if success, non zero if fails.
+ */
+int spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* SPDK_CPUSET_H */
diff --git a/src/spdk/include/spdk/crc16.h b/src/spdk/include/spdk/crc16.h
new file mode 100644
index 00000000..ad79a41d
--- /dev/null
+++ b/src/spdk/include/spdk/crc16.h
@@ -0,0 +1,66 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * CRC-16 utility functions
+ */
+
+#ifndef SPDK_CRC16_H
+#define SPDK_CRC16_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * T10-DIF CRC-16 polynomial
+ */
+#define SPDK_T10DIF_CRC16_POLYNOMIAL 0x8bb7u
+
+/**
+ * Calculate T10-DIF CRC-16 checksum.
+ *
+ * \param buf Data buffer to checksum.
+ * \param len Length of buf in bytes.
+ * \return CRC-16 value.
+ */
+uint16_t spdk_crc16_t10dif(const void *buf, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_CRC16_H */
diff --git a/src/spdk/include/spdk/crc32.h b/src/spdk/include/spdk/crc32.h
new file mode 100644
index 00000000..85e0112d
--- /dev/null
+++ b/src/spdk/include/spdk/crc32.h
@@ -0,0 +1,108 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * CRC-32 utility functions
+ */
+
+#ifndef SPDK_CRC32_H
+#define SPDK_CRC32_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * IEEE CRC-32 polynomial (bit reflected)
+ */
+#define SPDK_CRC32_POLYNOMIAL_REFLECT 0xedb88320UL
+
+/**
+ * CRC-32C (Castagnoli) polynomial (bit reflected)
+ */
+#define SPDK_CRC32C_POLYNOMIAL_REFLECT 0x82f63b78UL
+
+struct spdk_crc32_table {
+ uint32_t table[256];
+};
+
+/**
+ * Initialize a CRC32 lookup table for a given polynomial.
+ *
+ * \param table Table to fill with precalculated CRC-32 data.
+ * \param polynomial_reflect Bit-reflected CRC-32 polynomial.
+ */
+void spdk_crc32_table_init(struct spdk_crc32_table *table,
+ uint32_t polynomial_reflect);
+
+/**
+ * Calculate a partial CRC-32 checksum.
+ *
+ * \param table CRC-32 table initialized with spdk_crc32_table_init().
+ * \param buf Data buffer to checksum.
+ * \param len Length of buf in bytes.
+ * \param crc Previous CRC-32 value.
+ * \return Updated CRC-32 value.
+ */
+uint32_t spdk_crc32_update(const struct spdk_crc32_table *table,
+ const void *buf, size_t len,
+ uint32_t crc);
+
+/**
+ * Calculate a partial CRC-32 IEEE checksum.
+ *
+ * \param buf Data buffer to checksum.
+ * \param len Length of buf in bytes.
+ * \param crc Previous CRC-32 value.
+ * \return Updated CRC-32 value.
+ */
+uint32_t spdk_crc32_ieee_update(const void *buf, size_t len, uint32_t crc);
+
+/**
+ * Calculate a partial CRC-32C checksum.
+ *
+ * \param buf Data buffer to checksum.
+ * \param len Length of buf in bytes.
+ * \param crc Previous CRC-32C value.
+ * \return Updated CRC-32C value.
+ */
+uint32_t spdk_crc32c_update(const void *buf, size_t len, uint32_t crc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_CRC32_H */
diff --git a/src/spdk/include/spdk/endian.h b/src/spdk/include/spdk/endian.h
new file mode 100644
index 00000000..116b7fb9
--- /dev/null
+++ b/src/spdk/include/spdk/endian.h
@@ -0,0 +1,178 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * Endian conversion functions
+ */
+
+#ifndef SPDK_ENDIAN_H
+#define SPDK_ENDIAN_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline uint16_t
+from_be16(const void *ptr)
+{
+ const uint8_t *tmp = (const uint8_t *)ptr;
+ return (((uint16_t)tmp[0] << 8) | tmp[1]);
+}
+
+static inline void
+to_be16(void *out, uint16_t in)
+{
+ uint8_t *tmp = (uint8_t *)out;
+ tmp[0] = (in >> 8) & 0xFF;
+ tmp[1] = in & 0xFF;
+}
+
+static inline uint32_t
+from_be32(const void *ptr)
+{
+ const uint8_t *tmp = (const uint8_t *)ptr;
+ return (((uint32_t)tmp[0] << 24) |
+ ((uint32_t)tmp[1] << 16) |
+ ((uint32_t)tmp[2] << 8) |
+ ((uint32_t)tmp[3]));
+}
+
+static inline void
+to_be32(void *out, uint32_t in)
+{
+ uint8_t *tmp = (uint8_t *)out;
+ tmp[0] = (in >> 24) & 0xFF;
+ tmp[1] = (in >> 16) & 0xFF;
+ tmp[2] = (in >> 8) & 0xFF;
+ tmp[3] = in & 0xFF;
+}
+
+static inline uint64_t
+from_be64(const void *ptr)
+{
+ const uint8_t *tmp = (const uint8_t *)ptr;
+ return (((uint64_t)tmp[0] << 56) |
+ ((uint64_t)tmp[1] << 48) |
+ ((uint64_t)tmp[2] << 40) |
+ ((uint64_t)tmp[3] << 32) |
+ ((uint64_t)tmp[4] << 24) |
+ ((uint64_t)tmp[5] << 16) |
+ ((uint64_t)tmp[6] << 8) |
+ ((uint64_t)tmp[7]));
+}
+
+static inline void
+to_be64(void *out, uint64_t in)
+{
+ uint8_t *tmp = (uint8_t *)out;
+ tmp[0] = (in >> 56) & 0xFF;
+ tmp[1] = (in >> 48) & 0xFF;
+ tmp[2] = (in >> 40) & 0xFF;
+ tmp[3] = (in >> 32) & 0xFF;
+ tmp[4] = (in >> 24) & 0xFF;
+ tmp[5] = (in >> 16) & 0xFF;
+ tmp[6] = (in >> 8) & 0xFF;
+ tmp[7] = in & 0xFF;
+}
+
+static inline uint16_t
+from_le16(const void *ptr)
+{
+ const uint8_t *tmp = (const uint8_t *)ptr;
+ return (((uint16_t)tmp[1] << 8) | tmp[0]);
+}
+
+static inline void
+to_le16(void *out, uint16_t in)
+{
+ uint8_t *tmp = (uint8_t *)out;
+ tmp[1] = (in >> 8) & 0xFF;
+ tmp[0] = in & 0xFF;
+}
+
+static inline uint32_t
+from_le32(const void *ptr)
+{
+ const uint8_t *tmp = (const uint8_t *)ptr;
+ return (((uint32_t)tmp[3] << 24) |
+ ((uint32_t)tmp[2] << 16) |
+ ((uint32_t)tmp[1] << 8) |
+ ((uint32_t)tmp[0]));
+}
+
+static inline void
+to_le32(void *out, uint32_t in)
+{
+ uint8_t *tmp = (uint8_t *)out;
+ tmp[3] = (in >> 24) & 0xFF;
+ tmp[2] = (in >> 16) & 0xFF;
+ tmp[1] = (in >> 8) & 0xFF;
+ tmp[0] = in & 0xFF;
+}
+
+static inline uint64_t
+from_le64(const void *ptr)
+{
+ const uint8_t *tmp = (const uint8_t *)ptr;
+ return (((uint64_t)tmp[7] << 56) |
+ ((uint64_t)tmp[6] << 48) |
+ ((uint64_t)tmp[5] << 40) |
+ ((uint64_t)tmp[4] << 32) |
+ ((uint64_t)tmp[3] << 24) |
+ ((uint64_t)tmp[2] << 16) |
+ ((uint64_t)tmp[1] << 8) |
+ ((uint64_t)tmp[0]));
+}
+
+static inline void
+to_le64(void *out, uint64_t in)
+{
+ uint8_t *tmp = (uint8_t *)out;
+ tmp[7] = (in >> 56) & 0xFF;
+ tmp[6] = (in >> 48) & 0xFF;
+ tmp[5] = (in >> 40) & 0xFF;
+ tmp[4] = (in >> 32) & 0xFF;
+ tmp[3] = (in >> 24) & 0xFF;
+ tmp[2] = (in >> 16) & 0xFF;
+ tmp[1] = (in >> 8) & 0xFF;
+ tmp[0] = in & 0xFF;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/env.h b/src/spdk/include/spdk/env.h
new file mode 100644
index 00000000..307499b7
--- /dev/null
+++ b/src/spdk/include/spdk/env.h
@@ -0,0 +1,1083 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * Copyright (c) NetApp, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Encapsulated third-party dependencies
+ */
+
+#ifndef SPDK_ENV_H
+#define SPDK_ENV_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPDK_ENV_SOCKET_ID_ANY (-1)
+#define SPDK_ENV_LCORE_ID_ANY (UINT32_MAX)
+
+/**
+ * Memory is dma-safe.
+ */
+#define SPDK_MALLOC_DMA 0x01
+
+/**
+ * Memory is sharable across process boundries.
+ */
+#define SPDK_MALLOC_SHARE 0x02
+
+#define SPDK_MAX_MEMZONE_NAME_LEN 32
+#define SPDK_MAX_MEMPOOL_NAME_LEN 29
+
+/**
+ * Memzone flags
+ */
+#define SPDK_MEMZONE_NO_IOVA_CONTIG 0x00100000 /**< no iova contiguity */
+
+struct spdk_pci_device;
+
+/**
+ * \brief Environment initialization options
+ */
+struct spdk_env_opts {
+ const char *name;
+ const char *core_mask;
+ int shm_id;
+ int mem_channel;
+ int master_core;
+ int mem_size;
+ bool no_pci;
+ bool hugepage_single_segments;
+ bool unlink_hugepage;
+ size_t num_pci_addr;
+ struct spdk_pci_addr *pci_blacklist;
+ struct spdk_pci_addr *pci_whitelist;
+
+ /** Opaque context for use of the env implementation. */
+ void *env_context;
+};
+
+/**
+ * Allocate dma/sharable memory based on a given dma_flg. It is a physically
+ * contiguous memory buffer with the given size, alignment and socket id.
+ *
+ * \param size Size in bytes.
+ * \param align Alignment value for the allocated memory. If '0', the allocated
+ * buffer is suitably aligned (in the same manner as malloc()). Otherwise, the
+ * allocated buffer is aligned to the multiple of align. In this case, it must
+ * be a power of two.
+ * \param phys_addr A pointer to the variable to hold the physical address of
+ * the allocated buffer is passed. If NULL, the physical address is not returned.
+ * \param socket_id Socket ID to allocate memory on, or SPDK_ENV_SOCKET_ID_ANY
+ * for any socket.
+ * \param flags Combination of SPDK_MALLOC flags (\ref SPDK_MALLOC_DMA, \ref SPDK_MALLOC_SHARE).
+ * At least one flag must be specified.
+ *
+ * \return a pointer to the allocated memory buffer.
+ */
+void *spdk_malloc(size_t size, size_t align, uint64_t *phys_addr, int socket_id, uint32_t flags);
+
+/**
+ * Allocate dma/sharable memory based on a given dma_flg. It is a physically
+ * contiguous memory buffer with the given size, alignment and socket id.
+ * Also, the buffer will be zeroed.
+ *
+ * \param size Size in bytes.
+ * \param align Alignment value for the allocated memory. If '0', the allocated
+ * buffer is suitably aligned (in the same manner as malloc()). Otherwise, the
+ * allocated buffer is aligned to the multiple of align. In this case, it must
+ * be a power of two.
+ * \param phys_addr A pointer to the variable to hold the physical address of
+ * the allocated buffer is passed. If NULL, the physical address is not returned.
+ * \param socket_id Socket ID to allocate memory on, or SPDK_ENV_SOCKET_ID_ANY
+ * for any socket.
+ * \param flags Combination of SPDK_MALLOC flags (\ref SPDK_MALLOC_DMA, \ref SPDK_MALLOC_SHARE).
+ *
+ * \return a pointer to the allocated memory buffer.
+ */
+void *spdk_zmalloc(size_t size, size_t align, uint64_t *phys_addr, int socket_id, uint32_t flags);
+
+/**
+ * Free buffer memory that was previously allocated with spdk_malloc() or spdk_zmalloc().
+ *
+ * \param buf Buffer to free.
+ */
+void spdk_free(void *buf);
+
+/**
+ * Initialize the default value of opts.
+ *
+ * \param opts Data structure where SPDK will initialize the default options.
+ */
+void spdk_env_opts_init(struct spdk_env_opts *opts);
+
+/**
+ * Initialize the environment library. This must be called prior to using
+ * any other functions in this library.
+ *
+ * \param opts Environment initialization options.
+ * \return 0 on success, or negative errno on failure.
+ */
+int spdk_env_init(const struct spdk_env_opts *opts);
+
+/**
+ * Allocate a pinned, physically contiguous memory buffer with the given size
+ * and alignment.
+ *
+ * \param size Size in bytes.
+ * \param align Alignment value for the allocated memory. If '0', the allocated
+ * buffer is suitably aligned (in the same manner as malloc()). Otherwise, the
+ * allocated buffer is aligned to the multiple of align. In this case, it must
+ * be a power of two.
+ * \param phys_addr A pointer to the variable to hold the physical address of
+ * the allocated buffer is passed. If NULL, the physical address is not returned.
+ *
+ * \return a pointer to the allocated memory buffer.
+ */
+void *spdk_dma_malloc(size_t size, size_t align, uint64_t *phys_addr);
+
+/**
+ * Allocate a pinned, physically contiguous memory buffer with the given size,
+ * alignment and socket id.
+ *
+ * \param size Size in bytes.
+ * \param align Alignment value for the allocated memory. If '0', the allocated
+ * buffer is suitably aligned (in the same manner as malloc()). Otherwise, the
+ * allocated buffer is aligned to the multiple of align. In this case, it must
+ * be a power of two.
+ * \param phys_addr A pointer to the variable to hold the physical address of
+ * the allocated buffer is passed. If NULL, the physical address is not returned.
+ * \param socket_id Socket ID to allocate memory on, or SPDK_ENV_SOCKET_ID_ANY
+ * for any socket.
+ *
+ * \return a pointer to the allocated memory buffer.
+ */
+void *spdk_dma_malloc_socket(size_t size, size_t align, uint64_t *phys_addr, int socket_id);
+
+/**
+ * Allocate a pinned, physically contiguous memory buffer with the given size
+ * and alignment. The buffer will be zeroed.
+ *
+ * \param size Size in bytes.
+ * \param align Alignment value for the allocated memory. If '0', the allocated
+ * buffer is suitably aligned (in the same manner as malloc()). Otherwise, the
+ * allocated buffer is aligned to the multiple of align. In this case, it must
+ * be a power of two.
+ * \param phys_addr A pointer to the variable to hold the physical address of
+ * the allocated buffer is passed. If NULL, the physical address is not returned.
+ *
+ * \return a pointer to the allocated memory buffer.
+ */
+void *spdk_dma_zmalloc(size_t size, size_t align, uint64_t *phys_addr);
+
+/**
+ * Allocate a pinned, physically contiguous memory buffer with the given size,
+ * alignment and socket id. The buffer will be zeroed.
+ *
+ * \param size Size in bytes.
+ * \param align Alignment value for the allocated memory. If '0', the allocated
+ * buffer is suitably aligned (in the same manner as malloc()). Otherwise, the
+ * allocated buffer is aligned to the multiple of align. In this case, it must
+ * be a power of two.
+ * \param phys_addr A pointer to the variable to hold the physical address of
+ * the allocated buffer is passed. If NULL, the physical address is not returned.
+ * \param socket_id Socket ID to allocate memory on, or SPDK_ENV_SOCKET_ID_ANY
+ * for any socket.
+ *
+ * \return a pointer to the allocated memory buffer.
+ */
+void *spdk_dma_zmalloc_socket(size_t size, size_t align, uint64_t *phys_addr, int socket_id);
+
+/**
+ * Resize the allocated and pinned memory buffer with the given new size and
+ * alignment. Existing contents are preserved.
+ *
+ * \param buf Buffer to resize.
+ * \param size Size in bytes.
+ * \param align Alignment value for the allocated memory. If '0', the allocated
+ * buffer is suitably aligned (in the same manner as malloc()). Otherwise, the
+ * allocated buffer is aligned to the multiple of align. In this case, it must
+ * be a power of two.
+ * \param phys_addr A pointer to the variable to hold the physical address of
+ * the allocated buffer is passed. If NULL, the physical address is not returned.
+ *
+ * \return a pointer to the resized memory buffer.
+ */
+void *spdk_dma_realloc(void *buf, size_t size, size_t align, uint64_t *phys_addr);
+
+/**
+ * Free a memory buffer previously allocated, for example from spdk_dma_zmalloc().
+ * This call is never made from the performance path.
+ *
+ * \param buf Buffer to free.
+ */
+void spdk_dma_free(void *buf);
+
+/**
+ * Reserve a named, process shared memory zone with the given size, socket_id
+ * and flags.
+ *
+ * \param name Name to set for this memory zone.
+ * \param len Length in bytes.
+ * \param socket_id Socket ID to allocate memory on, or SPDK_ENV_SOCKET_ID_ANY
+ * for any socket.
+ * \param flags Flags to set for this memory zone.
+ *
+ * \return a pointer to the allocated memory address on success, or NULL on failure.
+ */
+void *spdk_memzone_reserve(const char *name, size_t len, int socket_id, unsigned flags);
+
+/**
+ * Reserve a named, process shared memory zone with the given size, socket_id,
+ * flags and alignment.
+ *
+ * \param name Name to set for this memory zone.
+ * \param len Length in bytes.
+ * \param socket_id Socket ID to allocate memory on, or SPDK_ENV_SOCKET_ID_ANY
+ * for any socket.
+ * \param flags Flags to set for this memory zone.
+ * \param align Alignment for resulting memzone. Must be a power of 2.
+ *
+ * \return a pointer to the allocated memory address on success, or NULL on failure.
+ */
+void *spdk_memzone_reserve_aligned(const char *name, size_t len, int socket_id,
+ unsigned flags, unsigned align);
+
+/**
+ * Lookup the memory zone identified by the given name.
+ *
+ * \param name Name of the memory zone.
+ *
+ * \return a pointer to the reserved memory address on success, or NULL on failure.
+ */
+void *spdk_memzone_lookup(const char *name);
+
+/**
+ * Free the memory zone identified by the given name.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_memzone_free(const char *name);
+
+/**
+ * Dump debug information about all memzones.
+ *
+ * \param f File to write debug information to.
+ */
+void spdk_memzone_dump(FILE *f);
+
+struct spdk_mempool;
+
+#define SPDK_MEMPOOL_DEFAULT_CACHE_SIZE SIZE_MAX
+
+/**
+ * Create a thread-safe memory pool.
+ *
+ * \param name Name for the memory pool.
+ * \param count Count of elements.
+ * \param ele_size Element size in bytes.
+ * \param cache_size How many elements may be cached in per-core caches. Use
+ * SPDK_MEMPOOL_DEFAULT_CACHE_SIZE for a reasonable default, or 0 for no per-core cache.
+ * \param socket_id Socket ID to allocate memory on, or SPDK_ENV_SOCKET_ID_ANY
+ * for any socket.
+ *
+ * \return a pointer to the created memory pool.
+ */
+struct spdk_mempool *spdk_mempool_create(const char *name, size_t count,
+ size_t ele_size, size_t cache_size, int socket_id);
+
+/**
+ * An object callback function for memory pool.
+ *
+ * Used by spdk_mempool_create_ctor().
+ */
+typedef void (spdk_mempool_obj_cb_t)(struct spdk_mempool *mp,
+ void *opaque, void *obj, unsigned obj_idx);
+
+/**
+ * Create a thread-safe memory pool with user provided initialization function
+ * and argument.
+ *
+ * \param name Name for the memory pool.
+ * \param count Count of elements.
+ * \param ele_size Element size in bytes.
+ * \param cache_size How many elements may be cached in per-core caches. Use
+ * SPDK_MEMPOOL_DEFAULT_CACHE_SIZE for a reasonable default, or 0 for no per-core cache.
+ * \param socket_id Socket ID to allocate memory on, or SPDK_ENV_SOCKET_ID_ANY
+ * for any socket.
+ * \param obj_init User provided object calllback initialization function.
+ * \param obj_init_arg User provided callback initialization function argument.
+ *
+ * \return a pointer to the created memory pool.
+ */
+struct spdk_mempool *spdk_mempool_create_ctor(const char *name, size_t count,
+ size_t ele_size, size_t cache_size, int socket_id,
+ spdk_mempool_obj_cb_t *obj_init, void *obj_init_arg);
+
+/**
+ * Get the name of a memory pool.
+ *
+ * \param mp Memory pool to query.
+ *
+ * \return the name of the memory pool.
+ */
+char *spdk_mempool_get_name(struct spdk_mempool *mp);
+
+/**
+ * Free a memory pool.
+ */
+void spdk_mempool_free(struct spdk_mempool *mp);
+
+/**
+ * Get an element from a memory pool. If no elements remain, return NULL.
+ *
+ * \param mp Memory pool to query.
+ *
+ * \return a pointer to the element.
+ */
+void *spdk_mempool_get(struct spdk_mempool *mp);
+
+/**
+ * Get multiple elements from a memory pool.
+ *
+ * \param mp Memory pool to get multiple elements from.
+ * \param ele_arr Array of the elements to fill.
+ * \param count Count of elements to get.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_mempool_get_bulk(struct spdk_mempool *mp, void **ele_arr, size_t count);
+
+/**
+ * Put an element back into the memory pool.
+ *
+ * \param mp Memory pool to put element back into.
+ * \param ele Element to put.
+ */
+void spdk_mempool_put(struct spdk_mempool *mp, void *ele);
+
+/**
+ * Put multiple elements back into the memory pool.
+ *
+ * \param mp Memory pool to put multiple elements back into.
+ * \param ele_arr Array of the elements to put.
+ * \param count Count of elements to put.
+ */
+void spdk_mempool_put_bulk(struct spdk_mempool *mp, void **ele_arr, size_t count);
+
+/**
+ * Get the number of entries in the memory pool.
+ *
+ * \param pool Memory pool to query.
+ *
+ * \return the number of entries in the memory pool.
+ */
+size_t spdk_mempool_count(const struct spdk_mempool *pool);
+
+/**
+ * Get the number of dedicated CPU cores utilized by this env abstraction.
+ *
+ * \return the number of dedicated CPU cores.
+ */
+uint32_t spdk_env_get_core_count(void);
+
+/**
+ * Get the CPU core index of the current thread.
+ *
+ * This will only function when called from threads set up by
+ * this environment abstraction. For any other threads \c SPDK_ENV_LCORE_ID_ANY
+ * will be returned.
+ *
+ * \return the CPU core index of the current thread.
+ */
+uint32_t spdk_env_get_current_core(void);
+
+/**
+ * Get the index of the first dedicated CPU core for this application.
+ *
+ * \return the index of the first dedicated CPU core.
+ */
+uint32_t spdk_env_get_first_core(void);
+
+/**
+ * Get the index of the last dedicated CPU core for this application.
+ *
+ * \return the index of the last dedicated CPU core.
+ */
+uint32_t spdk_env_get_last_core(void);
+
+/**
+ * Get the index of the next dedicated CPU core for this application.
+ *
+ * If there is no next core, return UINT32_MAX.
+ *
+ * \param prev_core Index of previous core.
+ *
+ * \return the index of the next dedicated CPU core.
+ */
+uint32_t spdk_env_get_next_core(uint32_t prev_core);
+
+#define SPDK_ENV_FOREACH_CORE(i) \
+ for (i = spdk_env_get_first_core(); \
+ i < UINT32_MAX; \
+ i = spdk_env_get_next_core(i))
+
+/**
+ * Get the socket ID for the given core.
+ *
+ * \param core CPU core to query.
+ *
+ * \return the socket ID for the given core.
+ */
+uint32_t spdk_env_get_socket_id(uint32_t core);
+
+typedef int (*thread_start_fn)(void *);
+
+/**
+ * Launch a thread pinned to the given core. Only a single pinned thread may be
+ * launched per core. Subsequent attempts to launch pinned threads on that core
+ * will fail.
+ *
+ * \param core The core to pin the thread to.
+ * \param fn Entry point on the new thread.
+ * \param arg Argument apssed to thread_start_fn
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_env_thread_launch_pinned(uint32_t core, thread_start_fn fn, void *arg);
+
+/**
+ * Wait for all threads to exit before returning.
+ */
+void spdk_env_thread_wait_all(void);
+
+/**
+ * Check whether the calling process is primary process.
+ *
+ * \return true if the calling process is primary process, or false otherwise.
+ */
+bool spdk_process_is_primary(void);
+
+/**
+ * Get a monotonic timestamp counter.
+ *
+ * \return the monotonic timestamp counter.
+ */
+uint64_t spdk_get_ticks(void);
+
+/**
+ * Get the tick rate of spdk_get_ticks() per second.
+ *
+ * \return the tick rate of spdk_get_ticks() per second.
+ */
+uint64_t spdk_get_ticks_hz(void);
+
+/**
+ * Delay the given number of microseconds.
+ *
+ * \param us Number of microseconds.
+ */
+void spdk_delay_us(unsigned int us);
+
+struct spdk_ring;
+
+enum spdk_ring_type {
+ SPDK_RING_TYPE_SP_SC, /* Single-producer, single-consumer */
+ SPDK_RING_TYPE_MP_SC, /* Multi-producer, single-consumer */
+ SPDK_RING_TYPE_MP_MC, /* Multi-producer, multi-consumer */
+};
+
+/**
+ * Create a ring.
+ *
+ * \param type Type for the ring. (SPDK_RING_TYPE_SP_SC or SPDK_RING_TYPE_MP_SC).
+ * \param count Size of the ring in elements.
+ * \param socket_id Socket ID to allocate memory on, or SPDK_ENV_SOCKET_ID_ANY
+ * for any socket.
+ *
+ * \return a pointer to the created ring.
+ */
+struct spdk_ring *spdk_ring_create(enum spdk_ring_type type, size_t count, int socket_id);
+
+/**
+ * Free the ring.
+ *
+ * \param ring Ring to free.
+ */
+void spdk_ring_free(struct spdk_ring *ring);
+
+/**
+ * Get the number of objects in the ring.
+ *
+ * \param ring the ring.
+ *
+ * \return the number of objects in the ring.
+ */
+size_t spdk_ring_count(struct spdk_ring *ring);
+
+/**
+ * Queue the array of objects (with length count) on the ring.
+ *
+ * \param ring A pointer to the ring.
+ * \param objs A pointer to the array to be queued.
+ * \param count Length count of the array of objects.
+ *
+ * \return the number of objects enqueued.
+ */
+size_t spdk_ring_enqueue(struct spdk_ring *ring, void **objs, size_t count);
+
+/**
+ * Dequeue count objects from the ring into the array objs.
+ *
+ * \param ring A pointer to the ring.
+ * \param objs A pointer to the array to be dequeued.
+ * \param count Maximum number of elements to be dequeued.
+ *
+ * \return the number of objects dequeued which is less than 'count'.
+ */
+size_t spdk_ring_dequeue(struct spdk_ring *ring, void **objs, size_t count);
+
+#define SPDK_VTOPHYS_ERROR (0xFFFFFFFFFFFFFFFFULL)
+
+/**
+ * Get the physical address of a buffer.
+ *
+ * \param buf A pointer to a buffer.
+ *
+ * \return the physical address of this buffer on success, or SPDK_VTOPHYS_ERROR
+ * on failure.
+ */
+uint64_t spdk_vtophys(void *buf);
+
+struct spdk_pci_addr {
+ uint32_t domain;
+ uint8_t bus;
+ uint8_t dev;
+ uint8_t func;
+};
+
+struct spdk_pci_id {
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint16_t subvendor_id;
+ uint16_t subdevice_id;
+};
+
+typedef int (*spdk_pci_enum_cb)(void *enum_ctx, struct spdk_pci_device *pci_dev);
+
+/**
+ * Enumerate NVMe devices.
+ *
+ * \param enum_cb Called when the enumerate operation completes.
+ * \param enum_ctx Argument passed to the callback function.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_nvme_enumerate(spdk_pci_enum_cb enum_cb, void *enum_ctx);
+
+/**
+ * Enumerate I/OAT device.
+ *
+ * \param enum_cb Called when the enumerate operation completes.
+ * \param enum_ctx Argument passed to the callback function.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_ioat_enumerate(spdk_pci_enum_cb enum_cb, void *enum_ctx);
+
+/**
+ * Enumerate virtio device.
+ *
+ * \param enum_cb Called when the enumerate operation completes.
+ * \param enum_ctx Argument passed to the callback function.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_virtio_enumerate(spdk_pci_enum_cb enum_cb, void *enum_ctx);
+
+/**
+ * Get a mapping of the virtual address to the BAR of the PCI device.
+ *
+ * \param dev PCI device.
+ * \param bar Index to the BAR.
+ * \param mapped_addr A pointer to the pointer to hold the virtual address of
+ * the mapping.
+ * \param phys_addr A pointer to the variable to hold the physical address of
+ * the mapping.
+ * \param size A pointer to the variable to hold the mapped size in bytes.
+ *
+ * \return 0 on success.
+ */
+int spdk_pci_device_map_bar(struct spdk_pci_device *dev, uint32_t bar,
+ void **mapped_addr, uint64_t *phys_addr, uint64_t *size);
+
+/**
+ * Remove the mapping of the virtual address to the BAR of the PCI device.
+ *
+ * \param dev PCI device.
+ * \param bar Index to the BAR.
+ * \param addr Virtual address to remove that must be the mapped_addr returned
+ * by a previous call to spdk_pci_device_map_bar().
+ *
+ * \return 0 on success.
+ */
+int spdk_pci_device_unmap_bar(struct spdk_pci_device *dev, uint32_t bar, void *addr);
+
+/**
+ * Get the domain address of a PCI device.
+ *
+ * \param dev A pointer to the PCI device.
+ *
+ * \return the domain address of PCI device.
+ */
+uint32_t spdk_pci_device_get_domain(struct spdk_pci_device *dev);
+
+/**
+ * Get the bus address of a PCI device.
+ *
+ * \param dev A pointer to the PCI device.
+ *
+ * \return the bus address of PCI device.
+ */
+uint8_t spdk_pci_device_get_bus(struct spdk_pci_device *dev);
+
+/**
+ * Get the device address of a PCI device.
+ *
+ * \param dev A pointer to the PCI device.
+ *
+ * \return the device address of PCI device.
+ */
+uint8_t spdk_pci_device_get_dev(struct spdk_pci_device *dev);
+
+/**
+ * Get the function address of a PCI device.
+ *
+ * \param dev A pointer to the PCI device.
+ *
+ * \return the function address of PCI device.
+ */
+uint8_t spdk_pci_device_get_func(struct spdk_pci_device *dev);
+
+/**
+ * Get the PCI address of a PCI device.
+ *
+ * \param dev A pointer to the PCI device.
+ *
+ * \return the PCI address structure.
+ */
+struct spdk_pci_addr spdk_pci_device_get_addr(struct spdk_pci_device *dev);
+
+/**
+ * Get the vendor ID of a PCI device.
+ *
+ * \param dev A pointer to the PCI device.
+ *
+ * \return the vendor ID of PCI device.
+ */
+uint16_t spdk_pci_device_get_vendor_id(struct spdk_pci_device *dev);
+
+/**
+ * Get the device ID of a PCI device.
+ *
+ * \param dev A pointer to the PCI device.
+ *
+ * \return the device ID of PCI device.
+ */
+uint16_t spdk_pci_device_get_device_id(struct spdk_pci_device *dev);
+
+/**
+ * Get the subvendor ID of a PCI device.
+ *
+ * \param dev A pointer to the PCI device.
+ *
+ * \return the subvendor ID of PCI device.
+ */
+uint16_t spdk_pci_device_get_subvendor_id(struct spdk_pci_device *dev);
+
+/**
+ * Get the subdevice ID of a PCI device.
+ *
+ * \param dev A pointer to the PCI device.
+ *
+ * \return the subdevice ID of PCI device.
+ */
+uint16_t spdk_pci_device_get_subdevice_id(struct spdk_pci_device *dev);
+
+/**
+ * Allocate a PCI ID struct for the PCI device.
+ *
+ * \param dev A pointer to the PCI device.
+ *
+ * \return a PCI ID struct.
+ */
+struct spdk_pci_id spdk_pci_device_get_id(struct spdk_pci_device *dev);
+
+/**
+ * Get the NUMA socket ID of a PCI device.
+ *
+ * \param dev PCI device to get the socket ID of.
+ *
+ * \return the socket ID (>= 0) of PCI device.
+ */
+int spdk_pci_device_get_socket_id(struct spdk_pci_device *dev);
+
+/**
+ * Get the serial number of a PCI device.
+ *
+ * \param dev A pointer to the PCI device.
+ * \param sn String to store the serial number.
+ * \param len Length of the 'sn'.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_device_get_serial_number(struct spdk_pci_device *dev, char *sn, size_t len);
+
+/**
+ * Claim a PCI device for exclusive SPDK userspace access.
+ *
+ * Uses F_SETLK on a shared memory file with the PCI address embedded in its name.
+ * As long as this file remains open with the lock acquired, other processes will
+ * not be able to successfully call this function on the same PCI device.
+ *
+ * \param pci_addr PCI address of the device to claim
+ *
+ * \return -1 if the device has already been claimed, an fd otherwise. This fd
+ * should be closed when the application no longer needs access to the PCI device
+ * (including when it is hot removed).
+ */
+int spdk_pci_device_claim(const struct spdk_pci_addr *pci_addr);
+
+/**
+ * Detach a PCI device.
+ *
+ * \param device PCI device to detach.
+ */
+void spdk_pci_device_detach(struct spdk_pci_device *device);
+
+/**
+ * Attach a NVMe device.
+ *
+ * \param enum_cb Called when the attach operation completes.
+ * \param enum_ctx Argument passed to the callback function.
+ * \param pci_address PCI address of the NVMe device.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_nvme_device_attach(spdk_pci_enum_cb enum_cb, void *enum_ctx,
+ struct spdk_pci_addr *pci_address);
+
+/**
+ * Attach a I/OAT device.
+ *
+ * \param enum_cb Called when the attach operation completes.
+ * \param enum_ctx Argument passed to the callback function.
+ * \param pci_address PCI address of the I/OAT device.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_ioat_device_attach(spdk_pci_enum_cb enum_cb, void *enum_ctx,
+ struct spdk_pci_addr *pci_address);
+
+/**
+ * Attach a virtio device.
+ *
+ * \param enum_cb Called when the attach operation completes.
+ * \param enum_ctx Argument passed to the callback function.
+ * \param pci_address PCI address of the virtio device.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_virtio_device_attach(spdk_pci_enum_cb enum_cb, void *enum_ctx,
+ struct spdk_pci_addr *pci_address);
+
+/**
+ * Read PCI configuration space in any specified size.
+ *
+ * \param dev PCI device.
+ * \param value A pointer to the buffer to hold the value.
+ * \param len Length in bytes to read.
+ * \param offset Offset in bytes.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_device_cfg_read(struct spdk_pci_device *dev, void *value, uint32_t len,
+ uint32_t offset);
+
+/**
+ * Write PCI configuration space in any specified size.
+ *
+ * \param dev PCI device.
+ * \param value A pointer to the value to write.
+ * \param len Length in bytes to write.
+ * \param offset Offset in bytes.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_device_cfg_write(struct spdk_pci_device *dev, void *value, uint32_t len,
+ uint32_t offset);
+/**
+ * Read 1 byte from PCI configuration space.
+ *
+ * \param dev PCI device.
+ * \param value A pointer to the buffer to hold the value.
+ * \param offset Offset in bytes.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_device_cfg_read8(struct spdk_pci_device *dev, uint8_t *value, uint32_t offset);
+
+/**
+ * Write 1 byte to PCI configuration space.
+ *
+ * \param dev PCI device.
+ * \param value A value to write.
+ * \param offset Offset in bytes.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_device_cfg_write8(struct spdk_pci_device *dev, uint8_t value, uint32_t offset);
+
+/**
+ * Read 2 bytes from PCI configuration space.
+ *
+ * \param dev PCI device.
+ * \param value A pointer to the buffer to hold the value.
+ * \param offset Offset in bytes.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_device_cfg_read16(struct spdk_pci_device *dev, uint16_t *value, uint32_t offset);
+
+/**
+ * Write 2 bytes to PCI configuration space.
+ *
+ * \param dev PCI device.
+ * \param value A value to write.
+ * \param offset Offset in bytes.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_device_cfg_write16(struct spdk_pci_device *dev, uint16_t value, uint32_t offset);
+
+/**
+ * Read 4 bytes from PCI configuration space.
+ *
+ * \param dev PCI device.
+ * \param value A pointer to the buffer to hold the value.
+ * \param offset Offset in bytes.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_device_cfg_read32(struct spdk_pci_device *dev, uint32_t *value, uint32_t offset);
+
+/**
+ * Write 4 bytes to PCI configuration space.
+ *
+ * \param dev PCI device.
+ * \param value A value to write.
+ * \param offset Offset in bytes.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_pci_device_cfg_write32(struct spdk_pci_device *dev, uint32_t value, uint32_t offset);
+
+/**
+ * Compare two PCI addresses.
+ *
+ * \param a1 PCI address 1.
+ * \param a2 PCI address 2.
+ *
+ * \return 0 if a1 == a2, less than 0 if a1 < a2, greater than 0 if a1 > a2
+ */
+int spdk_pci_addr_compare(const struct spdk_pci_addr *a1, const struct spdk_pci_addr *a2);
+
+/**
+ * Convert a string representation of a PCI address into a struct spdk_pci_addr.
+ *
+ * \param addr PCI adddress output on success.
+ * \param bdf PCI address in domain:bus:device.function format or
+ * domain.bus.device.function format.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_pci_addr_parse(struct spdk_pci_addr *addr, const char *bdf);
+
+/**
+ * Convert a struct spdk_pci_addr to a string.
+ *
+ * \param bdf String into which a string will be output in the format
+ * domain:bus:device.function. The string must be at least 14 characters in size.
+ * \param sz Size of bdf in bytes. Must be at least 14.
+ * \param addr PCI address.
+ *
+ * \return 0 on success, or a negated errno on failure.
+ */
+int spdk_pci_addr_fmt(char *bdf, size_t sz, const struct spdk_pci_addr *addr);
+
+/**
+ * Remove any CPU affinity from the current thread.
+ */
+void spdk_unaffinitize_thread(void);
+
+/**
+ * Call a function with CPU affinity unset.
+ *
+ * This can be used to run a function that creates other threads without inheriting the calling
+ * thread's CPU affinity.
+ *
+ * \param cb Function to call
+ * \param arg Parameter to the function cb().
+ *
+ * \return the return value of cb().
+ */
+void *spdk_call_unaffinitized(void *cb(void *arg), void *arg);
+
+/**
+ * Page-granularity memory address translation table.
+ */
+struct spdk_mem_map;
+
+enum spdk_mem_map_notify_action {
+ SPDK_MEM_MAP_NOTIFY_REGISTER,
+ SPDK_MEM_MAP_NOTIFY_UNREGISTER,
+};
+
+typedef int (*spdk_mem_map_notify_cb)(void *cb_ctx, struct spdk_mem_map *map,
+ enum spdk_mem_map_notify_action action,
+ void *vaddr, size_t size);
+
+typedef int (*spdk_mem_map_contiguous_translations)(uint64_t addr_1, uint64_t addr_2);
+
+/**
+ * A function table to be implemented by each memory map.
+ */
+struct spdk_mem_map_ops {
+ spdk_mem_map_notify_cb notify_cb;
+ spdk_mem_map_contiguous_translations are_contiguous;
+};
+
+/**
+ * Allocate a virtual memory address translation map.
+ *
+ * \param default_translation Default translation for the map.
+ * \param ops Table of callback functions for map operations.
+ * \param cb_ctx Argument passed to the callback function.
+ *
+ * \return a pointer to the allocated virtual memory address translation map.
+ */
+struct spdk_mem_map *spdk_mem_map_alloc(uint64_t default_translation,
+ const struct spdk_mem_map_ops *ops, void *cb_ctx);
+
+/**
+ * Free a memory map previously allocated by spdk_mem_map_alloc().
+ *
+ * \param pmap Memory map to free.
+ */
+void spdk_mem_map_free(struct spdk_mem_map **pmap);
+
+/**
+ * Register an address translation for a range of virtual memory.
+ *
+ * \param map Memory map.
+ * \param vaddr Virtual address of the region to register - must be 2 MB aligned.
+ * \param size Size of the region in bytes - must be multiple of 2 MB in the
+ * current implementation.
+ * \param translation Translation to store in the map for this address range.
+ *
+ * \sa spdk_mem_map_clear_translation().
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_mem_map_set_translation(struct spdk_mem_map *map, uint64_t vaddr, uint64_t size,
+ uint64_t translation);
+
+/**
+ * Unregister an address translation.
+ *
+ * \param map Memory map.
+ * \param vaddr Virtual address of the region to unregister - must be 2 MB aligned.
+ * \param size Size of the region in bytes - must be multiple of 2 MB in the
+ * current implementation.
+ *
+ * \sa spdk_mem_map_set_translation().
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_mem_map_clear_translation(struct spdk_mem_map *map, uint64_t vaddr, uint64_t size);
+
+/**
+ * Look up the translation of a virtual address in a memory map.
+ *
+ * \param map Memory map.
+ * \param vaddr Virtual address.
+ * \param size Contains the size of the memory region pointed to by vaddr.
+ * Updated with the size of the memory region for which the translation is valid.
+ *
+ * \return the translation of vaddr stored in the map, or default_translation
+ * as specified in spdk_mem_map_alloc() if vaddr is not present in the map.
+ */
+uint64_t spdk_mem_map_translate(const struct spdk_mem_map *map, uint64_t vaddr, uint64_t *size);
+
+/**
+ * Register the specified memory region for address translation.
+ *
+ * The memory region must map to pinned huge pages (2MB or greater).
+ *
+ * \param vaddr Virtual address to register.
+ * \param len Length in bytes of the vaddr.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_mem_register(void *vaddr, size_t len);
+
+/**
+ * Unregister the specified memory region from vtophys address translation.
+ *
+ * The caller must ensure all in-flight DMA operations to this memory region
+ * are completed or cancelled before calling this function.
+ *
+ * \param vaddr Virtual address to unregister.
+ * \param len Length in bytes of the vaddr.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_mem_unregister(void *vaddr, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/event.h b/src/spdk/include/spdk/event.h
new file mode 100644
index 00000000..2fa3f92e
--- /dev/null
+++ b/src/spdk/include/spdk/event.h
@@ -0,0 +1,302 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * Event framework public API.
+ *
+ * See @ref event_components for an overview of the SPDK event framework API.
+ */
+
+#ifndef SPDK_EVENT_H
+#define SPDK_EVENT_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/cpuset.h"
+#include "spdk/queue.h"
+#include "spdk/log.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Event handler function.
+ *
+ * \param arg1 Argument 1.
+ * \param arg2 Argument 2.
+ */
+typedef void (*spdk_event_fn)(void *arg1, void *arg2);
+
+/**
+ * \brief An event is a function that is passed to and called on an lcore.
+ */
+struct spdk_event;
+
+/**
+ * \brief A poller is a function that is repeatedly called on an lcore.
+ */
+struct spdk_poller;
+
+/**
+ * Callback function for customized shutdown handling of application.
+ */
+typedef void (*spdk_app_shutdown_cb)(void);
+
+/**
+ * Signal handler fucntion.
+ *
+ * \param signal Signal number.
+ */
+typedef void (*spdk_sighandler_t)(int signal);
+
+#define SPDK_DEFAULT_RPC_ADDR "/var/tmp/spdk.sock"
+
+/**
+ * \brief Event framework initialization options
+ */
+struct spdk_app_opts {
+ const char *name;
+ const char *config_file;
+ const char *rpc_addr; /* Can be UNIX domain socket path or IP address + TCP port */
+ const char *reactor_mask;
+ const char *tpoint_group_mask;
+
+ int shm_id;
+
+ spdk_app_shutdown_cb shutdown_cb;
+ spdk_sighandler_t usr1_handler;
+
+ bool enable_coredump;
+ int mem_channel;
+ int master_core;
+ int mem_size;
+ bool no_pci;
+ bool hugepage_single_segments;
+ bool unlink_hugepage;
+ enum spdk_log_level print_level;
+ size_t num_pci_addr;
+ struct spdk_pci_addr *pci_blacklist;
+ struct spdk_pci_addr *pci_whitelist;
+
+ /* The maximum latency allowed when passing an event
+ * from one core to another. A value of 0
+ * means all cores continually poll. This is
+ * specified in microseconds.
+ */
+ uint64_t max_delay_us;
+
+ /* Wait for the associated RPC before initializing subsystems
+ * when this flag is enabled.
+ */
+ bool delay_subsystem_init;
+};
+
+struct spdk_reactor_tsc_stats {
+ uint64_t busy_tsc;
+ uint64_t idle_tsc;
+ uint64_t unknown_tsc;
+};
+
+/**
+ * Initialize the default value of opts
+ *
+ * \param opts Data structure where SPDK will initialize the default options.
+ */
+void spdk_app_opts_init(struct spdk_app_opts *opts);
+
+/**
+ * Start the framework.
+ *
+ * Before calling this function, the fields of opts must be initialized by
+ * spdk_app_opts_init(). Once started, the framework will call start_fn on the
+ * master core with the arguments provided. This call will block until spdk_app_stop()
+ * is called, or if an error condition occurs during the intialization
+ * code within spdk_app_start(), itself, before invoking the caller's
+ * supplied function.
+ *
+ * \param opts Initialization options used for this application.
+ * \param start_fn Event function that is called when the framework starts.
+ * \param arg1 Argument passed to function start_fn.
+ * \param arg2 Argument passed to function start_fn.
+ *
+ * \return 0 on success or non-zero on failure.
+ */
+int spdk_app_start(struct spdk_app_opts *opts, spdk_event_fn start_fn,
+ void *arg1, void *arg2);
+
+/**
+ * Perform final shutdown operations on an application using the event framework.
+ */
+void spdk_app_fini(void);
+
+/**
+ * Start shutting down the framework.
+ *
+ * Typically this function is not called directly, and the shutdown process is
+ * started implicitly by a process signal. But in applications that are using
+ * SPDK for a subset of its process threads, this function can be called in lieu
+ * of a signal.
+ */
+void spdk_app_start_shutdown(void);
+
+/**
+ * Stop the framework.
+ *
+ * This does not wait for all threads to exit. Instead, it kicks off the shutdown
+ * process and returns. Once the shutdown process is complete, spdk_app_start()
+ * will return.
+ *
+ * \param rc The rc value specified here will be returned to caller of spdk_app_start().
+ */
+void spdk_app_stop(int rc);
+
+/**
+ * Generate a configuration file that corresponds to the current running state.
+ *
+ * \param config_str Values obtained from the generated configuration file.
+ * \param name Prefix for name of temporary configuration file to save the current config.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_app_get_running_config(char **config_str, char *name);
+
+/**
+ * Return the shared memory id for this application.
+ *
+ * \return shared memory id.
+ */
+int spdk_app_get_shm_id(void);
+
+/**
+ * Convert a string containing a CPU core mask into a bitmask
+ *
+ * \param mask String containing a CPU core mask.
+ * \param cpumask Bitmask of CPU cores.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_app_parse_core_mask(const char *mask, struct spdk_cpuset *cpumask);
+
+/**
+ * Get the mask of the CPU cores active for this application
+ *
+ * \return the bitmask of the active CPU cores.
+ */
+struct spdk_cpuset *spdk_app_get_core_mask(void);
+
+#define SPDK_APP_GETOPT_STRING "c:de:ghi:m:n:p:r:s:uB:L:RW:"
+
+enum spdk_app_parse_args_rvals {
+ SPDK_APP_PARSE_ARGS_HELP = 0,
+ SPDK_APP_PARSE_ARGS_SUCCESS = 1,
+ SPDK_APP_PARSE_ARGS_FAIL = 2
+};
+typedef enum spdk_app_parse_args_rvals spdk_app_parse_args_rvals_t;
+
+/**
+ * Helper function for parsing arguments and printing usage messages.
+ *
+ * \param argc Count of arguments in argv parameter array.
+ * \param argv Array of command line arguments.
+ * \param opts Default options for the application.
+ * \param getopt_str String representing the app-specific command line parameters.
+ * Characters in this string must not conflict with characters in SPDK_APP_GETOPT_STRING.
+ * \param app_long_opts Array of full-name parameters. Can be NULL.
+ * \param parse Function pointer to call if an argument in getopt_str is found.
+ * \param usage Function pointer to print usage messages for app-specific command
+ * line parameters.
+ *\return SPDK_APP_PARSE_ARGS_FAIL on failure, SPDK_APP_PARSE_ARGS_SUCCESS on
+ * success, SPDK_APP_PARSE_ARGS_HELP if '-h' passed as an option.
+ */
+spdk_app_parse_args_rvals_t spdk_app_parse_args(int argc, char **argv,
+ struct spdk_app_opts *opts, const char *getopt_str,
+ struct option *app_long_opts, void (*parse)(int ch, char *arg),
+ void (*usage)(void));
+
+/**
+ * Print usage strings for common SPDK command line options.
+ *
+ * May only be called after spdk_app_parse_args().
+ */
+void spdk_app_usage(void);
+
+/**
+ * Allocate an event to be passed to spdk_event_call().
+ *
+ * \param lcore Lcore to run this event.
+ * \param fn Function used to execute event.
+ * \param arg1 Argument passed to function fn.
+ * \param arg2 Argument passed to function fn.
+ *
+ * \return a pointer to the allocated event.
+ */
+struct spdk_event *spdk_event_allocate(uint32_t lcore, spdk_event_fn fn,
+ void *arg1, void *arg2);
+
+/**
+ * Pass the given event to the associated lcore and call the function.
+ *
+ * \param event Event to execute.
+ */
+void spdk_event_call(struct spdk_event *event);
+
+/**
+ * Enable or disable monitoring of context switches.
+ *
+ * \param enabled True to enable, false to disable.
+ */
+void spdk_reactor_enable_context_switch_monitor(bool enabled);
+
+/**
+ * Return whether context switch monitoring is enabled.
+ *
+ * \return true if enabled or false otherwise.
+ */
+bool spdk_reactor_context_switch_monitor_enabled(void);
+
+/**
+ * Get tsc stats from a given reactor
+ * Copy cumulative reactor tsc values to user's tsc_stats structure.
+ *
+ * \param tsc_stats User's tsc_stats structure.
+ * \param core_id Get tsc data on this Reactor core id.
+ */
+int spdk_reactor_get_tsc_stats(struct spdk_reactor_tsc_stats *tsc_stats, uint32_t core_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/fd.h b/src/spdk/include/spdk/fd.h
new file mode 100644
index 00000000..8da7f2cd
--- /dev/null
+++ b/src/spdk/include/spdk/fd.h
@@ -0,0 +1,69 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * OS filesystem utility functions
+ */
+
+#ifndef SPDK_FD_H
+#define SPDK_FD_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Get the file size.
+ *
+ * \param fd File descriptor.
+ *
+ * \return File size.
+ */
+uint64_t spdk_fd_get_size(int fd);
+
+/**
+ * Get the block size of the file.
+ *
+ * \param fd File descriptor.
+ *
+ * \return Block size.
+ */
+uint32_t spdk_fd_get_blocklen(int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/gpt_spec.h b/src/spdk/include/spdk/gpt_spec.h
new file mode 100644
index 00000000..c67eb572
--- /dev/null
+++ b/src/spdk/include/spdk/gpt_spec.h
@@ -0,0 +1,144 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * GUID Partition Table (GPT) specification definitions
+ */
+
+#ifndef SPDK_GPT_SPEC_H
+#define SPDK_GPT_SPEC_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/assert.h"
+
+#pragma pack(push, 1)
+
+#define SPDK_MBR_SIGNATURE 0xAA55
+
+#define SPDK_MBR_OS_TYPE_GPT_PROTECTIVE 0xEE
+#define SPDK_MBR_OS_TYPE_EFI_SYSTEM_PARTITION 0xEF
+
+struct spdk_mbr_chs {
+ uint8_t head;
+ uint16_t sector : 6;
+ uint16_t cylinder : 10;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_mbr_chs) == 3, "size incorrect");
+
+struct spdk_mbr_partition_entry {
+ uint8_t reserved : 7;
+ uint8_t bootable : 1;
+
+ struct spdk_mbr_chs start_chs;
+
+ uint8_t os_type;
+
+ struct spdk_mbr_chs end_chs;
+
+ uint32_t start_lba;
+ uint32_t size_lba;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_mbr_partition_entry) == 16, "size incorrect");
+
+struct spdk_mbr {
+ uint8_t boot_code[440];
+ uint32_t disk_signature;
+ uint16_t reserved_444;
+ struct spdk_mbr_partition_entry partitions[4];
+ uint16_t mbr_signature;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_mbr) == 512, "size incorrect");
+
+#define SPDK_GPT_SIGNATURE "EFI PART"
+
+#define SPDK_GPT_REVISION_1_0 0x00010000u
+
+struct spdk_gpt_guid {
+ uint8_t raw[16];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_gpt_guid) == 16, "size incorrect");
+
+#define SPDK_GPT_GUID(a, b, c, d, e) \
+ (struct spdk_gpt_guid){{ \
+ (uint8_t)(a), (uint8_t)(((uint32_t)a) >> 8), \
+ (uint8_t)(((uint32_t)a) >> 16), (uint8_t)(((uint32_t)a >> 24)), \
+ (uint8_t)(b), (uint8_t)(((uint16_t)b) >> 8), \
+ (uint8_t)(c), (uint8_t)(((uint16_t)c) >> 8), \
+ (uint8_t)(((uint16_t)d) >> 8), (uint8_t)(d), \
+ (uint8_t)(((uint64_t)e) >> 40), (uint8_t)(((uint64_t)e) >> 32), (uint8_t)(((uint64_t)e) >> 24), \
+ (uint8_t)(((uint64_t)e) >> 16), (uint8_t)(((uint64_t)e) >> 8), (uint8_t)(e) \
+ }}
+
+#define SPDK_GPT_PART_TYPE_UNUSED SPDK_GPT_GUID(0x00000000, 0x0000, 0x0000, 0x0000, 0x000000000000)
+#define SPDK_GPT_PART_TYPE_EFI_SYSTEM_PARTITION SPDK_GPT_GUID(0xC12A7328, 0xF81F, 0x11D2, 0xBA4B, 0x00A0C93EC93B)
+#define SPDK_GPT_PART_TYPE_LEGACY_MBR SPDK_GPT_GUID(0x024DEE41, 0x33E7, 0x11D3, 0x9D69, 0x0008C781F39F)
+
+struct spdk_gpt_header {
+ char gpt_signature[8];
+ uint32_t revision;
+ uint32_t header_size;
+ uint32_t header_crc32;
+ uint32_t reserved;
+ uint64_t my_lba;
+ uint64_t alternate_lba;
+ uint64_t first_usable_lba;
+ uint64_t last_usable_lba;
+ struct spdk_gpt_guid disk_guid;
+ uint64_t partition_entry_lba;
+ uint32_t num_partition_entries;
+ uint32_t size_of_partition_entry;
+ uint32_t partition_entry_array_crc32;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_gpt_header) == 92, "size incorrect");
+
+struct spdk_gpt_partition_entry {
+ struct spdk_gpt_guid part_type_guid;
+ struct spdk_gpt_guid unique_partition_guid;
+ uint64_t starting_lba;
+ uint64_t ending_lba;
+ struct {
+ uint64_t required : 1;
+ uint64_t no_block_io_proto : 1;
+ uint64_t legacy_bios_bootable : 1;
+ uint64_t reserved_uefi : 45;
+ uint64_t guid_specific : 16;
+ } attr;
+ uint16_t partition_name[36];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_gpt_partition_entry) == 128, "size incorrect");
+
+#pragma pack(pop)
+
+#endif
diff --git a/src/spdk/include/spdk/histogram_data.h b/src/spdk/include/spdk/histogram_data.h
new file mode 100644
index 00000000..25649397
--- /dev/null
+++ b/src/spdk/include/spdk/histogram_data.h
@@ -0,0 +1,247 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * Generic histogram library
+ */
+
+#ifndef _SPDK_HISTOGRAM_DATA_H_
+#define _SPDK_HISTOGRAM_DATA_H_
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPDK_HISTOGRAM_BUCKET_SHIFT_DEFAULT 7
+#define SPDK_HISTOGRAM_BUCKET_SHIFT(h) h->bucket_shift
+#define SPDK_HISTOGRAM_BUCKET_LSB(h) (64 - SPDK_HISTOGRAM_BUCKET_SHIFT(h))
+#define SPDK_HISTOGRAM_NUM_BUCKETS_PER_RANGE(h) (1ULL << SPDK_HISTOGRAM_BUCKET_SHIFT(h))
+#define SPDK_HISTOGRAM_BUCKET_MASK(h) (SPDK_HISTOGRAM_NUM_BUCKETS_PER_RANGE(h) - 1)
+#define SPDK_HISTOGRAM_NUM_BUCKET_RANGES(h) (SPDK_HISTOGRAM_BUCKET_LSB(h) + 1)
+#define SPDK_HISTOGRAM_NUM_BUCKETS(h) (SPDK_HISTOGRAM_NUM_BUCKETS_PER_RANGE(h) * \
+ SPDK_HISTOGRAM_NUM_BUCKET_RANGES(h))
+
+/*
+ * SPDK histograms are implemented using ranges of bucket arrays. The most common usage
+ * model is using TSC datapoints to capture an I/O latency histogram. For this usage model,
+ * the histogram tracks only TSC deltas - any translation to microseconds is done by the
+ * histogram user calling spdk_histogram_data_iterate() to iterate over the buckets to perform
+ * the translations.
+ *
+ * Each range has a number of buckets determined by SPDK_HISTOGRAM_NUM_BUCKETS_PER_RANGE
+ * which is 128. The buckets in ranges 0 and 1 each map to one specific datapoint value.
+ * The buckets in subsequent ranges each map to twice as many datapoint values as buckets
+ * in the range before it:
+ *
+ * Range 0: 1 value each - 128 buckets cover 0 to 127 (2^7-1)
+ * Range 1: 1 value each - 128 buckets cover 128 to 255 (2^8-1)
+ * Range 2: 2 values each - 128 buckets cover 256 to 511 (2^9-1)
+ * Range 3: 4 values each - 128 buckets cover 512 to 1023 (2^10-1)
+ * Range 4: 8 values each - 128 buckets cover 1024 to 2047 (2^11-1)
+ * Range 5: 16 values each - 128 buckets cover 2048 to 4095 (2^12-1)
+ * ...
+ * Range 55: 2^54 values each - 128 buckets cover 2^61 to 2^62-1
+ * Range 56: 2^55 values each - 128 buckets cover 2^62 to 2^63-1
+ * Range 57: 2^56 values each - 128 buckets cover 2^63 to 2^64-1
+ *
+ * On a 2.3GHz processor, this strategy results in 50ns buckets in the 7-14us range (sweet
+ * spot for Intel Optane SSD latency testing).
+ *
+ * Buckets can be made more granular by increasing SPDK_HISTOGRAM_BUCKET_SHIFT. This
+ * comes at the cost of additional storage per namespace context to store the bucket data.
+ */
+
+struct spdk_histogram_data {
+
+ uint32_t bucket_shift;
+ uint64_t *bucket;
+
+};
+
+static inline void
+__spdk_histogram_increment(struct spdk_histogram_data *h, uint32_t range, uint32_t index)
+{
+ uint64_t *count;
+
+ count = &h->bucket[(range << SPDK_HISTOGRAM_BUCKET_SHIFT(h)) + index];
+ (*count)++;
+}
+
+static inline uint64_t
+__spdk_histogram_get_count(const struct spdk_histogram_data *h, uint32_t range, uint32_t index)
+{
+ return h->bucket[(range << SPDK_HISTOGRAM_BUCKET_SHIFT(h)) + index];
+}
+
+static inline void
+spdk_histogram_data_reset(struct spdk_histogram_data *histogram)
+{
+ memset(histogram->bucket, 0, SPDK_HISTOGRAM_NUM_BUCKETS(histogram) * sizeof(uint64_t));
+}
+
+static inline uint32_t
+__spdk_histogram_data_get_bucket_range(struct spdk_histogram_data *h, uint64_t datapoint)
+{
+ uint32_t clz, range;
+
+ assert(datapoint != 0);
+
+ clz = __builtin_clzll(datapoint);
+
+ if (clz <= SPDK_HISTOGRAM_BUCKET_LSB(h)) {
+ range = SPDK_HISTOGRAM_BUCKET_LSB(h) - clz;
+ } else {
+ range = 0;
+ }
+
+ return range;
+}
+
+static inline uint32_t
+__spdk_histogram_data_get_bucket_index(struct spdk_histogram_data *h, uint64_t datapoint,
+ uint32_t range)
+{
+ uint32_t shift;
+
+ if (range == 0) {
+ shift = 0;
+ } else {
+ shift = range - 1;
+ }
+
+ return (datapoint >> shift) & SPDK_HISTOGRAM_BUCKET_MASK(h);
+}
+
+static inline void
+spdk_histogram_data_tally(struct spdk_histogram_data *histogram, uint64_t datapoint)
+{
+ uint32_t range = __spdk_histogram_data_get_bucket_range(histogram, datapoint);
+ uint32_t index = __spdk_histogram_data_get_bucket_index(histogram, datapoint, range);
+
+ __spdk_histogram_increment(histogram, range, index);
+}
+
+static inline uint64_t
+__spdk_histogram_data_get_bucket_start(const struct spdk_histogram_data *h, uint32_t range,
+ uint32_t index)
+{
+ uint64_t bucket;
+
+ index += 1;
+ if (range > 0) {
+ bucket = 1ULL << (range + SPDK_HISTOGRAM_BUCKET_SHIFT(h) - 1);
+ bucket += (uint64_t)index << (range - 1);
+ } else {
+ bucket = index;
+ }
+
+ return bucket;
+}
+
+typedef void (*spdk_histogram_data_fn)(void *ctx, uint64_t start, uint64_t end, uint64_t count,
+ uint64_t total, uint64_t so_far);
+
+static inline void
+spdk_histogram_data_iterate(const struct spdk_histogram_data *histogram,
+ spdk_histogram_data_fn fn, void *ctx)
+{
+ uint64_t i, j, count, so_far, total;
+ uint64_t bucket, last_bucket;
+
+ total = 0;
+
+ for (i = 0; i < SPDK_HISTOGRAM_NUM_BUCKET_RANGES(histogram); i++) {
+ for (j = 0; j < SPDK_HISTOGRAM_NUM_BUCKETS_PER_RANGE(histogram); j++) {
+ total += __spdk_histogram_get_count(histogram, i, j);
+ }
+ }
+
+ so_far = 0;
+ bucket = 0;
+
+ for (i = 0; i < SPDK_HISTOGRAM_NUM_BUCKET_RANGES(histogram); i++) {
+ for (j = 0; j < SPDK_HISTOGRAM_NUM_BUCKETS_PER_RANGE(histogram); j++) {
+ count = __spdk_histogram_get_count(histogram, i, j);
+ so_far += count;
+ last_bucket = bucket;
+ bucket = __spdk_histogram_data_get_bucket_start(histogram, i, j);
+ fn(ctx, last_bucket, bucket, count, total, so_far);
+ }
+ }
+}
+
+static inline struct spdk_histogram_data *
+spdk_histogram_data_alloc_sized(uint32_t bucket_shift)
+{
+ struct spdk_histogram_data *h;
+
+ h = (struct spdk_histogram_data *)calloc(1, sizeof(*h));
+ if (h == NULL) {
+ return NULL;
+ }
+
+ h->bucket_shift = bucket_shift;
+ h->bucket = (uint64_t *)calloc(SPDK_HISTOGRAM_NUM_BUCKETS(h), sizeof(uint64_t));
+ if (h->bucket == NULL) {
+ free(h);
+ return NULL;
+ }
+
+ return h;
+}
+
+static inline struct spdk_histogram_data *
+spdk_histogram_data_alloc(void)
+{
+ return spdk_histogram_data_alloc_sized(SPDK_HISTOGRAM_BUCKET_SHIFT_DEFAULT);
+}
+
+static inline void
+spdk_histogram_data_free(struct spdk_histogram_data *h)
+{
+ if (h == NULL) {
+ return;
+ }
+
+ free(h->bucket);
+ free(h);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/io_channel.h b/src/spdk/include/spdk/io_channel.h
new file mode 100644
index 00000000..71ddb90a
--- /dev/null
+++ b/src/spdk/include/spdk/io_channel.h
@@ -0,0 +1,48 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * IO channel
+ */
+
+#ifndef SPDK_IO_CHANNEL_H_
+#define SPDK_IO_CHANNEL_H_
+
+/*
+ * This file has been renamed to thread.h. Please update
+ * include paths.
+ */
+
+#include "spdk/thread.h"
+
+#endif /* SPDK_IO_CHANNEL_H_ */
diff --git a/src/spdk/include/spdk/ioat.h b/src/spdk/include/spdk/ioat.h
new file mode 100644
index 00000000..c323a0b4
--- /dev/null
+++ b/src/spdk/include/spdk/ioat.h
@@ -0,0 +1,174 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * I/OAT DMA engine driver public interface
+ */
+
+#ifndef SPDK_IOAT_H
+#define SPDK_IOAT_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "spdk/env.h"
+
+/**
+ * Opaque handle for a single I/OAT channel returned by \ref spdk_ioat_probe().
+ */
+struct spdk_ioat_chan;
+
+/**
+ * Signature for callback function invoked when a request is completed.
+ *
+ * \param arg User-specified opaque value corresponding to cb_arg from the
+ * request submission.
+ */
+typedef void (*spdk_ioat_req_cb)(void *arg);
+
+/**
+ * Callback for spdk_ioat_probe() enumeration.
+ *
+ * \param cb_ctx User-specified opaque value corresponding to cb_ctx from spdk_ioat_probe().
+ * \param pci_dev PCI device that is being probed.
+ *
+ * \return true to attach to this device.
+ */
+typedef bool (*spdk_ioat_probe_cb)(void *cb_ctx, struct spdk_pci_device *pci_dev);
+
+/**
+ * Callback for spdk_ioat_probe() to report a device that has been attached to
+ * the userspace I/OAT driver.
+ *
+ * \param cb_ctx User-specified opaque value corresponding to cb_ctx from spdk_ioat_probe().
+ * \param pci_dev PCI device that was attached to the driver.
+ * \param ioat I/OAT channel that was attached to the driver.
+ */
+typedef void (*spdk_ioat_attach_cb)(void *cb_ctx, struct spdk_pci_device *pci_dev,
+ struct spdk_ioat_chan *ioat);
+
+/**
+ * Enumerate the I/OAT devices attached to the system and attach the userspace
+ * I/OAT driver to them if desired.
+ *
+ * If called more than once, only devices that are not already attached to the
+ * SPDK I/OAT driver will be reported.
+ *
+ * To stop using the controller and release its associated resources, call
+ * spdk_ioat_detach() with the ioat_channel instance returned by this function.
+ *
+ * \param cb_ctx Opaque value which will be passed back in cb_ctx parameter of
+ * the callbacks.
+ * \param probe_cb will be called once per I/OAT device found in the system.
+ * \param attach_cb will be called for devices for which probe_cb returned true
+ * once the I/OAT controller has been attached to the userspace driver.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_ioat_probe(void *cb_ctx, spdk_ioat_probe_cb probe_cb, spdk_ioat_attach_cb attach_cb);
+
+/**
+ * Detach specified device returned by spdk_ioat_probe() from the I/OAT driver.
+ *
+ * \param ioat I/OAT channel to detach from the driver.
+ */
+void spdk_ioat_detach(struct spdk_ioat_chan *ioat);
+
+/**
+ * Submit a DMA engine memory copy request.
+ *
+ * \param chan I/OAT channel to submit request.
+ * \param cb_arg Opaque value which will be passed back as the arg parameter in
+ * the completion callback.
+ * \param cb_fn Callback function which will be called when the request is complete.
+ * \param dst Destination virtual address.
+ * \param src Source virtual address.
+ * \param nbytes Number of bytes to copy.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_ioat_submit_copy(struct spdk_ioat_chan *chan,
+ void *cb_arg, spdk_ioat_req_cb cb_fn,
+ void *dst, const void *src, uint64_t nbytes);
+
+/**
+ * Submit a DMA engine memory fill request.
+ *
+ * \param chan I/OAT channel to submit request.
+ * \param cb_arg Opaque value which will be passed back as the cb_arg parameter
+ * in the completion callback.
+ * \param cb_fn Callback function which will be called when the request is complete.
+ * \param dst Destination virtual address.
+ * \param fill_pattern Repeating eight-byte pattern to use for memory fill.
+ * \param nbytes Number of bytes to fill.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_ioat_submit_fill(struct spdk_ioat_chan *chan,
+ void *cb_arg, spdk_ioat_req_cb cb_fn,
+ void *dst, uint64_t fill_pattern, uint64_t nbytes);
+
+/**
+ * Check for completed requests on an I/OAT channel.
+ *
+ * \param chan I/OAT channel to check for completions.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_ioat_process_events(struct spdk_ioat_chan *chan);
+
+/**
+ * DMA engine capability flags
+ */
+enum spdk_ioat_dma_capability_flags {
+ SPDK_IOAT_ENGINE_COPY_SUPPORTED = 0x1, /**< The memory copy is supported */
+ SPDK_IOAT_ENGINE_FILL_SUPPORTED = 0x2, /**< The memory fill is supported */
+};
+
+/**
+ * Get the DMA engine capabilities.
+ *
+ * \param chan I/OAT channel to query.
+ *
+ * \return a combination of flags from spdk_ioat_dma_capability_flags().
+ */
+uint32_t spdk_ioat_get_dma_capabilities(struct spdk_ioat_chan *chan);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/ioat_spec.h b/src/spdk/include/spdk/ioat_spec.h
new file mode 100644
index 00000000..0c49405e
--- /dev/null
+++ b/src/spdk/include/spdk/ioat_spec.h
@@ -0,0 +1,330 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * I/OAT specification definitions
+ */
+
+#ifndef SPDK_IOAT_SPEC_H
+#define SPDK_IOAT_SPEC_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "spdk/assert.h"
+
+#define SPDK_IOAT_PCI_CHANERR_INT_OFFSET 0x180
+
+#define SPDK_IOAT_INTRCTRL_MASTER_INT_EN 0x01
+
+#define SPDK_IOAT_VER_3_0 0x30
+#define SPDK_IOAT_VER_3_3 0x33
+
+/* DMA Channel Registers */
+#define SPDK_IOAT_CHANCTRL_CHANNEL_PRIORITY_MASK 0xF000
+#define SPDK_IOAT_CHANCTRL_COMPL_DCA_EN 0x0200
+#define SPDK_IOAT_CHANCTRL_CHANNEL_IN_USE 0x0100
+#define SPDK_IOAT_CHANCTRL_DESCRIPTOR_ADDR_SNOOP_CONTROL 0x0020
+#define SPDK_IOAT_CHANCTRL_ERR_INT_EN 0x0010
+#define SPDK_IOAT_CHANCTRL_ANY_ERR_ABORT_EN 0x0008
+#define SPDK_IOAT_CHANCTRL_ERR_COMPLETION_EN 0x0004
+#define SPDK_IOAT_CHANCTRL_INT_REARM 0x0001
+
+/* DMA Channel Capabilities */
+#define SPDK_IOAT_DMACAP_PB (1 << 0)
+#define SPDK_IOAT_DMACAP_DCA (1 << 4)
+#define SPDK_IOAT_DMACAP_BFILL (1 << 6)
+#define SPDK_IOAT_DMACAP_XOR (1 << 8)
+#define SPDK_IOAT_DMACAP_PQ (1 << 9)
+#define SPDK_IOAT_DMACAP_DMA_DIF (1 << 10)
+
+struct spdk_ioat_registers {
+ uint8_t chancnt;
+ uint8_t xfercap;
+ uint8_t genctrl;
+ uint8_t intrctrl;
+ uint32_t attnstatus;
+ uint8_t cbver; /* 0x08 */
+ uint8_t reserved4[0x3]; /* 0x09 */
+ uint16_t intrdelay; /* 0x0C */
+ uint16_t cs_status; /* 0x0E */
+ uint32_t dmacapability; /* 0x10 */
+ uint8_t reserved5[0x6C]; /* 0x14 */
+ uint16_t chanctrl; /* 0x80 */
+ uint8_t reserved6[0x2]; /* 0x82 */
+ uint8_t chancmd; /* 0x84 */
+ uint8_t reserved3[1]; /* 0x85 */
+ uint16_t dmacount; /* 0x86 */
+ uint64_t chansts; /* 0x88 */
+ uint64_t chainaddr; /* 0x90 */
+ uint64_t chancmp; /* 0x98 */
+ uint8_t reserved2[0x8]; /* 0xA0 */
+ uint32_t chanerr; /* 0xA8 */
+ uint32_t chanerrmask; /* 0xAC */
+} __attribute__((packed));
+
+#define SPDK_IOAT_CHANCMD_RESET 0x20
+#define SPDK_IOAT_CHANCMD_SUSPEND 0x04
+
+#define SPDK_IOAT_CHANSTS_STATUS 0x7ULL
+#define SPDK_IOAT_CHANSTS_ACTIVE 0x0
+#define SPDK_IOAT_CHANSTS_IDLE 0x1
+#define SPDK_IOAT_CHANSTS_SUSPENDED 0x2
+#define SPDK_IOAT_CHANSTS_HALTED 0x3
+#define SPDK_IOAT_CHANSTS_ARMED 0x4
+
+#define SPDK_IOAT_CHANSTS_UNAFFILIATED_ERROR 0x8ULL
+#define SPDK_IOAT_CHANSTS_SOFT_ERROR 0x10ULL
+
+#define SPDK_IOAT_CHANSTS_COMPLETED_DESCRIPTOR_MASK (~0x3FULL)
+
+#define SPDK_IOAT_CHANCMP_ALIGN 8 /* CHANCMP address must be 64-bit aligned */
+
+struct spdk_ioat_generic_hw_desc {
+ uint32_t size;
+ union {
+ uint32_t control_raw;
+ struct {
+ uint32_t int_enable: 1;
+ uint32_t src_snoop_disable: 1;
+ uint32_t dest_snoop_disable: 1;
+ uint32_t completion_update: 1;
+ uint32_t fence: 1;
+ uint32_t reserved2: 1;
+ uint32_t src_page_break: 1;
+ uint32_t dest_page_break: 1;
+ uint32_t bundle: 1;
+ uint32_t dest_dca: 1;
+ uint32_t hint: 1;
+ uint32_t reserved: 13;
+ uint32_t op: 8;
+ } control;
+ } u;
+ uint64_t src_addr;
+ uint64_t dest_addr;
+ uint64_t next;
+ uint64_t op_specific[4];
+};
+
+struct spdk_ioat_dma_hw_desc {
+ uint32_t size;
+ union {
+ uint32_t control_raw;
+ struct {
+ uint32_t int_enable: 1;
+ uint32_t src_snoop_disable: 1;
+ uint32_t dest_snoop_disable: 1;
+ uint32_t completion_update: 1;
+ uint32_t fence: 1;
+ uint32_t null: 1;
+ uint32_t src_page_break: 1;
+ uint32_t dest_page_break: 1;
+ uint32_t bundle: 1;
+ uint32_t dest_dca: 1;
+ uint32_t hint: 1;
+ uint32_t reserved: 13;
+#define SPDK_IOAT_OP_COPY 0x00
+ uint32_t op: 8;
+ } control;
+ } u;
+ uint64_t src_addr;
+ uint64_t dest_addr;
+ uint64_t next;
+ uint64_t reserved;
+ uint64_t reserved2;
+ uint64_t user1;
+ uint64_t user2;
+};
+
+struct spdk_ioat_fill_hw_desc {
+ uint32_t size;
+ union {
+ uint32_t control_raw;
+ struct {
+ uint32_t int_enable: 1;
+ uint32_t reserved: 1;
+ uint32_t dest_snoop_disable: 1;
+ uint32_t completion_update: 1;
+ uint32_t fence: 1;
+ uint32_t reserved2: 2;
+ uint32_t dest_page_break: 1;
+ uint32_t bundle: 1;
+ uint32_t reserved3: 15;
+#define SPDK_IOAT_OP_FILL 0x01
+ uint32_t op: 8;
+ } control;
+ } u;
+ uint64_t src_data;
+ uint64_t dest_addr;
+ uint64_t next;
+ uint64_t reserved;
+ uint64_t next_dest_addr;
+ uint64_t user1;
+ uint64_t user2;
+};
+
+struct spdk_ioat_xor_hw_desc {
+ uint32_t size;
+ union {
+ uint32_t control_raw;
+ struct {
+ uint32_t int_enable: 1;
+ uint32_t src_snoop_disable: 1;
+ uint32_t dest_snoop_disable: 1;
+ uint32_t completion_update: 1;
+ uint32_t fence: 1;
+ uint32_t src_count: 3;
+ uint32_t bundle: 1;
+ uint32_t dest_dca: 1;
+ uint32_t hint: 1;
+ uint32_t reserved: 13;
+#define SPDK_IOAT_OP_XOR 0x87
+#define SPDK_IOAT_OP_XOR_VAL 0x88
+ uint32_t op: 8;
+ } control;
+ } u;
+ uint64_t src_addr;
+ uint64_t dest_addr;
+ uint64_t next;
+ uint64_t src_addr2;
+ uint64_t src_addr3;
+ uint64_t src_addr4;
+ uint64_t src_addr5;
+};
+
+struct spdk_ioat_xor_ext_hw_desc {
+ uint64_t src_addr6;
+ uint64_t src_addr7;
+ uint64_t src_addr8;
+ uint64_t next;
+ uint64_t reserved[4];
+};
+
+struct spdk_ioat_pq_hw_desc {
+ uint32_t size;
+ union {
+ uint32_t control_raw;
+ struct {
+ uint32_t int_enable: 1;
+ uint32_t src_snoop_disable: 1;
+ uint32_t dest_snoop_disable: 1;
+ uint32_t completion_update: 1;
+ uint32_t fence: 1;
+ uint32_t src_count: 3;
+ uint32_t bundle: 1;
+ uint32_t dest_dca: 1;
+ uint32_t hint: 1;
+ uint32_t p_disable: 1;
+ uint32_t q_disable: 1;
+ uint32_t reserved: 11;
+#define SPDK_IOAT_OP_PQ 0x89
+#define SPDK_IOAT_OP_PQ_VAL 0x8a
+ uint32_t op: 8;
+ } control;
+ } u;
+ uint64_t src_addr;
+ uint64_t p_addr;
+ uint64_t next;
+ uint64_t src_addr2;
+ uint64_t src_addr3;
+ uint8_t coef[8];
+ uint64_t q_addr;
+};
+
+struct spdk_ioat_pq_ext_hw_desc {
+ uint64_t src_addr4;
+ uint64_t src_addr5;
+ uint64_t src_addr6;
+ uint64_t next;
+ uint64_t src_addr7;
+ uint64_t src_addr8;
+ uint64_t reserved[2];
+};
+
+struct spdk_ioat_pq_update_hw_desc {
+ uint32_t size;
+ union {
+ uint32_t control_raw;
+ struct {
+ uint32_t int_enable: 1;
+ uint32_t src_snoop_disable: 1;
+ uint32_t dest_snoop_disable: 1;
+ uint32_t completion_update: 1;
+ uint32_t fence: 1;
+ uint32_t src_cnt: 3;
+ uint32_t bundle: 1;
+ uint32_t dest_dca: 1;
+ uint32_t hint: 1;
+ uint32_t p_disable: 1;
+ uint32_t q_disable: 1;
+ uint32_t reserved: 3;
+ uint32_t coef: 8;
+#define SPDK_IOAT_OP_PQ_UP 0x8b
+ uint32_t op: 8;
+ } control;
+ } u;
+ uint64_t src_addr;
+ uint64_t p_addr;
+ uint64_t next;
+ uint64_t src_addr2;
+ uint64_t p_src;
+ uint64_t q_src;
+ uint64_t q_addr;
+};
+
+struct spdk_ioat_raw_hw_desc {
+ uint64_t field[8];
+};
+
+union spdk_ioat_hw_desc {
+ struct spdk_ioat_raw_hw_desc raw;
+ struct spdk_ioat_generic_hw_desc generic;
+ struct spdk_ioat_dma_hw_desc dma;
+ struct spdk_ioat_fill_hw_desc fill;
+ struct spdk_ioat_xor_hw_desc xor_desc;
+ struct spdk_ioat_xor_ext_hw_desc xor_ext;
+ struct spdk_ioat_pq_hw_desc pq;
+ struct spdk_ioat_pq_ext_hw_desc pq_ext;
+ struct spdk_ioat_pq_update_hw_desc pq_update;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_ioat_hw_desc) == 64, "incorrect spdk_ioat_hw_desc layout");
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_IOAT_SPEC_H */
diff --git a/src/spdk/include/spdk/iscsi_spec.h b/src/spdk/include/spdk/iscsi_spec.h
new file mode 100644
index 00000000..06e56786
--- /dev/null
+++ b/src/spdk/include/spdk/iscsi_spec.h
@@ -0,0 +1,567 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * iSCSI specification definitions
+ */
+
+#ifndef SPDK_ISCSI_SPEC_H
+#define SPDK_ISCSI_SPEC_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/assert.h"
+
+#define ISCSI_BHS_LEN 48
+#define ISCSI_DIGEST_LEN 4
+#define ISCSI_ALIGNMENT 4
+
+/** support version - RFC3720(10.12.4) */
+#define ISCSI_VERSION 0x00
+
+#define ISCSI_ALIGN(SIZE) \
+ (((SIZE) + (ISCSI_ALIGNMENT - 1)) & ~(ISCSI_ALIGNMENT - 1))
+
+/** for authentication key (non encoded 1024bytes) RFC3720(5.1/11.1.4) */
+#define ISCSI_TEXT_MAX_VAL_LEN 8192
+
+/**
+ * RFC 3720 5.1
+ * If not otherwise specified, the maximum length of a simple-value
+ * (not its encoded representation) is 255 bytes, not including the delimiter
+ * (comma or zero byte).
+ */
+#define ISCSI_TEXT_MAX_SIMPLE_VAL_LEN 255
+
+#define ISCSI_TEXT_MAX_KEY_LEN 63
+
+enum iscsi_op {
+ /* Initiator opcodes */
+ ISCSI_OP_NOPOUT = 0x00,
+ ISCSI_OP_SCSI = 0x01,
+ ISCSI_OP_TASK = 0x02,
+ ISCSI_OP_LOGIN = 0x03,
+ ISCSI_OP_TEXT = 0x04,
+ ISCSI_OP_SCSI_DATAOUT = 0x05,
+ ISCSI_OP_LOGOUT = 0x06,
+ ISCSI_OP_SNACK = 0x10,
+ ISCSI_OP_VENDOR_1C = 0x1c,
+ ISCSI_OP_VENDOR_1D = 0x1d,
+ ISCSI_OP_VENDOR_1E = 0x1e,
+
+ /* Target opcodes */
+ ISCSI_OP_NOPIN = 0x20,
+ ISCSI_OP_SCSI_RSP = 0x21,
+ ISCSI_OP_TASK_RSP = 0x22,
+ ISCSI_OP_LOGIN_RSP = 0x23,
+ ISCSI_OP_TEXT_RSP = 0x24,
+ ISCSI_OP_SCSI_DATAIN = 0x25,
+ ISCSI_OP_LOGOUT_RSP = 0x26,
+ ISCSI_OP_R2T = 0x31,
+ ISCSI_OP_ASYNC = 0x32,
+ ISCSI_OP_VENDOR_3C = 0x3c,
+ ISCSI_OP_VENDOR_3D = 0x3d,
+ ISCSI_OP_VENDOR_3E = 0x3e,
+ ISCSI_OP_REJECT = 0x3f,
+};
+
+enum iscsi_task_func {
+ ISCSI_TASK_FUNC_ABORT_TASK = 1,
+ ISCSI_TASK_FUNC_ABORT_TASK_SET = 2,
+ ISCSI_TASK_FUNC_CLEAR_ACA = 3,
+ ISCSI_TASK_FUNC_CLEAR_TASK_SET = 4,
+ ISCSI_TASK_FUNC_LOGICAL_UNIT_RESET = 5,
+ ISCSI_TASK_FUNC_TARGET_WARM_RESET = 6,
+ ISCSI_TASK_FUNC_TARGET_COLD_RESET = 7,
+ ISCSI_TASK_FUNC_TASK_REASSIGN = 8,
+};
+
+enum iscsi_task_func_resp {
+ ISCSI_TASK_FUNC_RESP_COMPLETE = 0,
+ ISCSI_TASK_FUNC_RESP_TASK_NOT_EXIST = 1,
+ ISCSI_TASK_FUNC_RESP_LUN_NOT_EXIST = 2,
+ ISCSI_TASK_FUNC_RESP_TASK_STILL_ALLEGIANT = 3,
+ ISCSI_TASK_FUNC_RESP_REASSIGNMENT_NOT_SUPPORTED = 4,
+ ISCSI_TASK_FUNC_RESP_FUNC_NOT_SUPPORTED = 5,
+ ISCSI_TASK_FUNC_RESP_AUTHORIZATION_FAILED = 6,
+ ISCSI_TASK_FUNC_REJECTED = 255
+};
+
+struct iscsi_bhs {
+ uint8_t opcode : 6;
+ uint8_t immediate : 1;
+ uint8_t reserved : 1;
+ uint8_t flags;
+ uint8_t rsv[2];
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint64_t lun;
+ uint32_t itt;
+ uint32_t ttt;
+ uint32_t stat_sn;
+ uint32_t exp_stat_sn;
+ uint32_t max_stat_sn;
+ uint8_t res3[12];
+};
+SPDK_STATIC_ASSERT(sizeof(struct iscsi_bhs) == ISCSI_BHS_LEN, "ISCSI_BHS_LEN mismatch");
+
+struct iscsi_bhs_async {
+ uint8_t opcode : 6; /* opcode = 0x32 */
+ uint8_t reserved : 2;
+ uint8_t flags;
+ uint8_t res[2];
+
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+
+ uint64_t lun;
+ uint32_t ffffffff;
+ uint32_t res3;
+ uint32_t stat_sn;
+ uint32_t exp_cmd_sn;
+ uint32_t max_cmd_sn;
+ uint8_t async_event;
+ uint8_t async_vcode;
+ uint16_t param1;
+ uint16_t param2;
+ uint16_t param3;
+ uint8_t res4[4];
+};
+
+struct iscsi_bhs_login_req {
+ uint8_t opcode : 6; /* opcode = 0x03 */
+ uint8_t immediate : 1;
+ uint8_t reserved : 1;
+ uint8_t flags;
+ uint8_t version_max;
+ uint8_t version_min;
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint8_t isid[6];
+ uint16_t tsih;
+ uint32_t itt;
+ uint16_t cid;
+ uint16_t res2;
+ uint32_t cmd_sn;
+ uint32_t exp_stat_sn;
+ uint8_t res3[16];
+};
+
+struct iscsi_bhs_login_rsp {
+ uint8_t opcode : 6; /* opcode = 0x23 */
+ uint8_t reserved : 2;
+ uint8_t flags;
+ uint8_t version_max;
+ uint8_t version_act;
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint8_t isid[6];
+ uint16_t tsih;
+ uint32_t itt;
+ uint32_t res2;
+ uint32_t stat_sn;
+ uint32_t exp_cmd_sn;
+ uint32_t max_cmd_sn;
+ uint8_t status_class;
+ uint8_t status_detail;
+ uint8_t res3[10];
+};
+
+struct iscsi_bhs_logout_req {
+ uint8_t opcode : 6; /* opcode = 0x06 */
+ uint8_t immediate : 1;
+ uint8_t reserved : 1;
+ uint8_t reason : 7;
+ uint8_t reason_1 : 1;
+ uint8_t res[2];
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint8_t res2[8];
+ uint32_t itt;
+ uint16_t cid;
+ uint16_t res3;
+ uint32_t cmd_sn;
+ uint32_t exp_stat_sn;
+ uint8_t res4[16];
+};
+
+struct iscsi_bhs_logout_resp {
+ uint8_t opcode : 6; /* opcode = 0x26 */
+ uint8_t reserved : 2;
+ uint8_t flags;
+ uint8_t response;
+ uint8_t res;
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint8_t res2[8];
+ uint32_t itt;
+ uint32_t res3;
+ uint32_t stat_sn;
+ uint32_t exp_cmd_sn;
+ uint32_t max_cmd_sn;
+ uint32_t res4;
+ uint16_t time_2_wait;
+ uint16_t time_2_retain;
+ uint32_t res5;
+};
+
+struct iscsi_bhs_nop_in {
+ uint8_t opcode : 6; /* opcode = 0x20 */
+ uint8_t reserved : 2;
+ uint8_t flags;
+ uint8_t res[2];
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint64_t lun;
+ uint32_t itt;
+ uint32_t ttt;
+ uint32_t stat_sn;
+ uint32_t exp_cmd_sn;
+ uint32_t max_cmd_sn;
+ uint8_t res3[12];
+};
+
+struct iscsi_bhs_nop_out {
+ uint8_t opcode : 6; /* opcode = 0x00 */
+ uint8_t immediate : 1;
+ uint8_t reserved : 1;
+ uint8_t flags;
+ uint8_t res[2];
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint64_t lun;
+ uint32_t itt;
+ uint32_t ttt;
+ uint32_t cmd_sn;
+ uint32_t exp_stat_sn;
+ uint8_t res4[16];
+};
+
+struct iscsi_bhs_r2t {
+ uint8_t opcode : 6; /* opcode = 0x31 */
+ uint8_t reserved : 2;
+ uint8_t flags;
+ uint8_t rsv[2];
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint64_t lun;
+ uint32_t itt;
+ uint32_t ttt;
+ uint32_t stat_sn;
+ uint32_t exp_cmd_sn;
+ uint32_t max_cmd_sn;
+ uint32_t r2t_sn;
+ uint32_t buffer_offset;
+ uint32_t desired_xfer_len;
+};
+
+struct iscsi_bhs_reject {
+ uint8_t opcode : 6; /* opcode = 0x3f */
+ uint8_t reserved : 2;
+ uint8_t flags;
+ uint8_t reason;
+ uint8_t res;
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint8_t res2[8];
+ uint32_t ffffffff;
+ uint32_t res3;
+ uint32_t stat_sn;
+ uint32_t exp_cmd_sn;
+ uint32_t max_cmd_sn;
+ uint32_t data_sn;
+ uint8_t res4[8];
+};
+
+struct iscsi_bhs_scsi_req {
+ uint8_t opcode : 6; /* opcode = 0x01 */
+ uint8_t immediate : 1;
+ uint8_t reserved : 1;
+ uint8_t attribute : 3;
+ uint8_t reserved2 : 2;
+ uint8_t write_bit : 1;
+ uint8_t read_bit : 1;
+ uint8_t final_bit : 1;
+ uint8_t res[2];
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint64_t lun;
+ uint32_t itt;
+ uint32_t expected_data_xfer_len;
+ uint32_t cmd_sn;
+ uint32_t exp_stat_sn;
+ uint8_t cdb[16];
+};
+
+struct iscsi_bhs_scsi_resp {
+ uint8_t opcode : 6; /* opcode = 0x21 */
+ uint8_t reserved : 2;
+ uint8_t flags;
+ uint8_t response;
+ uint8_t status;
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint8_t res4[8];
+ uint32_t itt;
+ uint32_t snacktag;
+ uint32_t stat_sn;
+ uint32_t exp_cmd_sn;
+ uint32_t max_cmd_sn;
+ uint32_t exp_data_sn;
+ uint32_t bi_read_res_cnt;
+ uint32_t res_cnt;
+};
+
+struct iscsi_bhs_data_in {
+ uint8_t opcode : 6; /* opcode = 0x05 */
+ uint8_t reserved : 2;
+ uint8_t flags;
+ uint8_t res;
+ uint8_t status;
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint64_t lun;
+ uint32_t itt;
+ uint32_t ttt;
+ uint32_t stat_sn;
+ uint32_t exp_cmd_sn;
+ uint32_t max_cmd_sn;
+ uint32_t data_sn;
+ uint32_t buffer_offset;
+ uint32_t res_cnt;
+};
+
+struct iscsi_bhs_data_out {
+ uint8_t opcode : 6; /* opcode = 0x25 */
+ uint8_t reserved : 2;
+ uint8_t flags;
+ uint8_t res[2];
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint64_t lun;
+ uint32_t itt;
+ uint32_t ttt;
+ uint32_t res3;
+ uint32_t exp_stat_sn;
+ uint32_t res4;
+ uint32_t data_sn;
+ uint32_t buffer_offset;
+ uint32_t res5;
+};
+
+struct iscsi_bhs_snack_req {
+ uint8_t opcode : 6; /* opcode = 0x10 */
+ uint8_t reserved : 2;
+ uint8_t flags;
+ uint8_t res[2];
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint64_t lun;
+ uint32_t itt;
+ uint32_t ttt;
+ uint32_t res5;
+ uint32_t exp_stat_sn;
+ uint8_t res6[8];
+ uint32_t beg_run;
+ uint32_t run_len;
+};
+
+struct iscsi_bhs_task_req {
+ uint8_t opcode : 6; /* opcode = 0x02 */
+ uint8_t immediate : 1;
+ uint8_t reserved : 1;
+ uint8_t flags;
+ uint8_t res[2];
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint64_t lun;
+ uint32_t itt;
+ uint32_t ref_task_tag;
+ uint32_t cmd_sn;
+ uint32_t exp_stat_sn;
+ uint32_t ref_cmd_sn;
+ uint32_t exp_data_sn;
+ uint8_t res5[8];
+};
+
+struct iscsi_bhs_task_resp {
+ uint8_t opcode : 6; /* opcode = 0x22 */
+ uint8_t reserved : 2;
+ uint8_t flags;
+ uint8_t response;
+ uint8_t res;
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint8_t res2[8];
+ uint32_t itt;
+ uint32_t res3;
+ uint32_t stat_sn;
+ uint32_t exp_cmd_sn;
+ uint32_t max_cmd_sn;
+ uint8_t res4[12];
+};
+
+struct iscsi_bhs_text_req {
+ uint8_t opcode : 6; /* opcode = 0x04 */
+ uint8_t immediate : 1;
+ uint8_t reserved : 1;
+ uint8_t flags;
+ uint8_t res[2];
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint64_t lun;
+ uint32_t itt;
+ uint32_t ttt;
+ uint32_t cmd_sn;
+ uint32_t exp_stat_sn;
+ uint8_t res3[16];
+};
+
+struct iscsi_bhs_text_resp {
+ uint8_t opcode : 6; /* opcode = 0x24 */
+ uint8_t reserved : 2;
+ uint8_t flags;
+ uint8_t res[2];
+ uint8_t total_ahs_len;
+ uint8_t data_segment_len[3];
+ uint64_t lun;
+ uint32_t itt;
+ uint32_t ttt;
+ uint32_t stat_sn;
+ uint32_t exp_cmd_sn;
+ uint32_t max_cmd_sn;
+ uint8_t res4[12];
+};
+
+/* generic flags */
+#define ISCSI_FLAG_FINAL 0x80
+
+/* login flags */
+#define ISCSI_LOGIN_TRANSIT 0x80
+#define ISCSI_LOGIN_CONTINUE 0x40
+#define ISCSI_LOGIN_CURRENT_STAGE_MASK 0x0c
+#define ISCSI_LOGIN_CURRENT_STAGE_0 0x04
+#define ISCSI_LOGIN_CURRENT_STAGE_1 0x08
+#define ISCSI_LOGIN_CURRENT_STAGE_3 0x0c
+#define ISCSI_LOGIN_NEXT_STAGE_MASK 0x03
+#define ISCSI_LOGIN_NEXT_STAGE_0 0x01
+#define ISCSI_LOGIN_NEXT_STAGE_1 0x02
+#define ISCSI_LOGIN_NEXT_STAGE_3 0x03
+
+/* text flags */
+#define ISCSI_TEXT_CONTINUE 0x40
+
+/* datain flags */
+#define ISCSI_DATAIN_ACKNOLWEDGE 0x40
+#define ISCSI_DATAIN_OVERFLOW 0x04
+#define ISCSI_DATAIN_UNDERFLOW 0x02
+#define ISCSI_DATAIN_STATUS 0x01
+
+/* SCSI resp flags */
+#define ISCSI_SCSI_BIDI_OVERFLOW 0x10
+#define ISCSI_SCSI_BIDI_UNDERFLOW 0x08
+#define ISCSI_SCSI_OVERFLOW 0x04
+#define ISCSI_SCSI_UNDERFLOW 0x02
+
+/* SCSI task flags */
+#define ISCSI_TASK_FUNCTION_MASK 0x7f
+
+/* Reason for Reject */
+#define ISCSI_REASON_RESERVED 0x1
+#define ISCSI_REASON_DATA_DIGEST_ERROR 0x2
+#define ISCSI_REASON_DATA_SNACK_REJECT 0x3
+#define ISCSI_REASON_PROTOCOL_ERROR 0x4
+#define ISCSI_REASON_CMD_NOT_SUPPORTED 0x5
+#define ISCSI_REASON_IMM_CMD_REJECT 0x6
+#define ISCSI_REASON_TASK_IN_PROGRESS 0x7
+#define ISCSI_REASON_INVALID_SNACK 0x8
+#define ISCSI_REASON_INVALID_PDU_FIELD 0x9
+#define ISCSI_REASON_LONG_OPERATION_REJECT 0xa
+#define ISCSI_REASON_NEGOTIATION_RESET 0xb
+#define ISCSI_REASON_WAIT_FOR_RESET 0xc
+
+#define ISCSI_FLAG_SNACK_TYPE_DATA 0
+#define ISCSI_FLAG_SNACK_TYPE_R2T 0
+#define ISCSI_FLAG_SNACK_TYPE_STATUS 1
+#define ISCSI_FLAG_SNACK_TYPE_DATA_ACK 2
+#define ISCSI_FLAG_SNACK_TYPE_RDATA 3
+#define ISCSI_FLAG_SNACK_TYPE_MASK 0x0F /* 4 bits */
+
+struct iscsi_ahs {
+ /* 0-3 */
+ uint8_t ahs_len[2];
+ uint8_t ahs_type;
+ uint8_t ahs_specific1;
+ /* 4-x */
+ uint8_t ahs_specific2[];
+};
+
+#define ISCSI_BHS_LOGIN_GET_TBIT(X) (!!(X & ISCSI_LOGIN_TRANSIT))
+#define ISCSI_BHS_LOGIN_GET_CBIT(X) (!!(X & ISCSI_LOGIN_CONTINUE))
+#define ISCSI_BHS_LOGIN_GET_CSG(X) ((X & ISCSI_LOGIN_CURRENT_STAGE_MASK) >> 2)
+#define ISCSI_BHS_LOGIN_GET_NSG(X) (X & ISCSI_LOGIN_NEXT_STAGE_MASK)
+
+#define ISCSI_CLASS_SUCCESS 0x00
+#define ISCSI_CLASS_REDIRECT 0x01
+#define ISCSI_CLASS_INITIATOR_ERROR 0x02
+#define ISCSI_CLASS_TARGET_ERROR 0x03
+
+/* Class (Success) detailed info: 0 */
+#define ISCSI_LOGIN_ACCEPT 0x00
+
+/* Class (Redirection) detailed info: 1 */
+#define ISCSI_LOGIN_TARGET_TEMPORARILY_MOVED 0x01
+#define ISCSI_LOGIN_TARGET_PERMANENTLY_MOVED 0x02
+
+/* Class (Initiator Error) detailed info: 2 */
+#define ISCSI_LOGIN_INITIATOR_ERROR 0x00
+#define ISCSI_LOGIN_AUTHENT_FAIL 0x01
+#define ISCSI_LOGIN_AUTHORIZATION_FAIL 0x02
+#define ISCSI_LOGIN_TARGET_NOT_FOUND 0x03
+#define ISCSI_LOGIN_TARGET_REMOVED 0x04
+#define ISCSI_LOGIN_UNSUPPORTED_VERSION 0x05
+#define ISCSI_LOGIN_TOO_MANY_CONNECTIONS 0x06
+#define ISCSI_LOGIN_MISSING_PARMS 0x07
+#define ISCSI_LOGIN_CONN_ADD_FAIL 0x08
+#define ISCSI_LOGIN_NOT_SUPPORTED_SESSION_TYPE 0x09
+#define ISCSI_LOGIN_NO_SESSION 0x0a
+#define ISCSI_LOGIN_INVALID_LOGIN_REQUEST 0x0b
+
+/* Class (Target Error) detailed info: 3 */
+#define ISCSI_LOGIN_STATUS_TARGET_ERROR 0x00
+#define ISCSI_LOGIN_STATUS_SERVICE_UNAVAILABLE 0x01
+#define ISCSI_LOGIN_STATUS_NO_RESOURCES 0x02
+
+#endif /* SPDK_ISCSI_SPEC_H */
diff --git a/src/spdk/include/spdk/json.h b/src/spdk/include/spdk/json.h
new file mode 100644
index 00000000..8109e518
--- /dev/null
+++ b/src/spdk/include/spdk/json.h
@@ -0,0 +1,337 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * JSON parsing and encoding
+ */
+
+#ifndef SPDK_JSON_H_
+#define SPDK_JSON_H_
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum spdk_json_val_type {
+ SPDK_JSON_VAL_INVALID = 0,
+#define SPDK_JSON_VAL_ANY SPDK_JSON_VAL_INVALID
+ SPDK_JSON_VAL_NULL = 1U << 1,
+ SPDK_JSON_VAL_TRUE = 1U << 2,
+ SPDK_JSON_VAL_FALSE = 1U << 3,
+ SPDK_JSON_VAL_NUMBER = 1U << 4,
+ SPDK_JSON_VAL_STRING = 1U << 5,
+ SPDK_JSON_VAL_ARRAY_BEGIN = 1U << 6,
+ SPDK_JSON_VAL_ARRAY_END = 1U << 7,
+ SPDK_JSON_VAL_OBJECT_BEGIN = 1U << 8,
+ SPDK_JSON_VAL_OBJECT_END = 1U << 9,
+ SPDK_JSON_VAL_NAME = 1U << 10,
+};
+
+struct spdk_json_val {
+ /**
+ * Pointer to the location of the value within the parsed JSON input.
+ *
+ * For SPDK_JSON_VAL_STRING and SPDK_JSON_VAL_NAME,
+ * this points to the beginning of the decoded UTF-8 string without quotes.
+ *
+ * For SPDK_JSON_VAL_NUMBER, this points to the beginning of the number as represented in
+ * the original JSON (text representation, not converted to a numeric value).
+ */
+ void *start;
+
+ /**
+ * Length of value.
+ *
+ * For SPDK_JSON_VAL_STRING, SPDK_JSON_VAL_NUMBER, and SPDK_JSON_VAL_NAME,
+ * this is the length in bytes of the value starting at \ref start.
+ *
+ * For SPDK_JSON_VAL_ARRAY_BEGIN and SPDK_JSON_VAL_OBJECT_BEGIN,
+ * this is the number of values contained within the array or object (including
+ * nested objects and arrays, but not including the _END value). The array or object _END
+ * value can be found by advancing len values from the _BEGIN value.
+ */
+ uint32_t len;
+
+ /**
+ * Type of value.
+ */
+ enum spdk_json_val_type type;
+};
+
+/**
+ * Invalid JSON syntax.
+ */
+#define SPDK_JSON_PARSE_INVALID -1
+
+/**
+ * JSON was valid up to the end of the current buffer, but did not represent a complete JSON value.
+ */
+#define SPDK_JSON_PARSE_INCOMPLETE -2
+
+#define SPDK_JSON_PARSE_MAX_DEPTH_EXCEEDED -3
+
+/**
+ * Decode JSON strings and names in place (modify the input buffer).
+ */
+#define SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE 0x000000001
+
+/**
+ * Allow parsing of comments.
+ *
+ * Comments are not allowed by the JSON RFC, so this is not enabled by default.
+ */
+#define SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS 0x000000002
+
+/*
+ * Parse JSON data.
+ *
+ * \param data Raw JSON data; must be encoded in UTF-8.
+ * Note that the data may be modified to perform in-place string decoding.
+ *
+ * \param size Size of data in bytes.
+ *
+ * \param end If non-NULL, this will be filled a pointer to the byte just beyond the end
+ * of the valid JSON.
+ *
+ * \return Number of values parsed, or negative on failure:
+ * SPDK_JSON_PARSE_INVALID if the provided data was not valid JSON, or
+ * SPDK_JSON_PARSE_INCOMPLETE if the provided data was not a complete JSON value.
+ */
+ssize_t spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t num_values,
+ void **end, uint32_t flags);
+
+typedef int (*spdk_json_decode_fn)(const struct spdk_json_val *val, void *out);
+
+struct spdk_json_object_decoder {
+ const char *name;
+ size_t offset;
+ spdk_json_decode_fn decode_func;
+ bool optional;
+};
+
+int spdk_json_decode_object(const struct spdk_json_val *values,
+ const struct spdk_json_object_decoder *decoders, size_t num_decoders, void *out);
+int spdk_json_decode_array(const struct spdk_json_val *values, spdk_json_decode_fn decode_func,
+ void *out, size_t max_size, size_t *out_size, size_t stride);
+
+int spdk_json_decode_bool(const struct spdk_json_val *val, void *out);
+int spdk_json_decode_uint16(const struct spdk_json_val *val, void *out);
+int spdk_json_decode_int32(const struct spdk_json_val *val, void *out);
+int spdk_json_decode_uint32(const struct spdk_json_val *val, void *out);
+int spdk_json_decode_uint64(const struct spdk_json_val *val, void *out);
+int spdk_json_decode_string(const struct spdk_json_val *val, void *out);
+
+/**
+ * Get length of a value in number of values.
+ *
+ * This can be used to skip over a value while interpreting parse results.
+ *
+ * For SPDK_JSON_VAL_ARRAY_BEGIN and SPDK_JSON_VAL_OBJECT_BEGIN,
+ * this returns the number of values contained within this value, plus the _BEGIN and _END values.
+ *
+ * For all other values, this returns 1.
+ */
+size_t spdk_json_val_len(const struct spdk_json_val *val);
+
+/**
+ * Compare JSON string with null terminated C string.
+ *
+ * \return true if strings are equal or false if not
+ */
+bool spdk_json_strequal(const struct spdk_json_val *val, const char *str);
+
+/**
+ * Equivalent of strdup() for JSON string values.
+ *
+ * If val is not representable as a C string (contains embedded '\0' characters),
+ * returns NULL.
+ *
+ * Caller is responsible for passing the result to free() when it is no longer needed.
+ */
+char *spdk_json_strdup(const struct spdk_json_val *val);
+
+int spdk_json_number_to_uint16(const struct spdk_json_val *val, uint16_t *num);
+int spdk_json_number_to_int32(const struct spdk_json_val *val, int32_t *num);
+int spdk_json_number_to_uint32(const struct spdk_json_val *val, uint32_t *num);
+int spdk_json_number_to_uint64(const struct spdk_json_val *val, uint64_t *num);
+
+struct spdk_json_write_ctx;
+
+#define SPDK_JSON_WRITE_FLAG_FORMATTED 0x00000001
+
+typedef int (*spdk_json_write_cb)(void *cb_ctx, const void *data, size_t size);
+
+struct spdk_json_write_ctx *spdk_json_write_begin(spdk_json_write_cb write_cb, void *cb_ctx,
+ uint32_t flags);
+int spdk_json_write_end(struct spdk_json_write_ctx *w);
+int spdk_json_write_null(struct spdk_json_write_ctx *w);
+int spdk_json_write_bool(struct spdk_json_write_ctx *w, bool val);
+int spdk_json_write_int32(struct spdk_json_write_ctx *w, int32_t val);
+int spdk_json_write_uint32(struct spdk_json_write_ctx *w, uint32_t val);
+int spdk_json_write_int64(struct spdk_json_write_ctx *w, int64_t val);
+int spdk_json_write_uint64(struct spdk_json_write_ctx *w, uint64_t val);
+int spdk_json_write_string(struct spdk_json_write_ctx *w, const char *val);
+int spdk_json_write_string_raw(struct spdk_json_write_ctx *w, const char *val, size_t len);
+
+/**
+ * Write null-terminated UTF-16LE string.
+ *
+ * \param w JSON write context.
+ * \param val UTF-16LE string; must be null terminated.
+ * \return 0 on success or negative on failure.
+ */
+int spdk_json_write_string_utf16le(struct spdk_json_write_ctx *w, const uint16_t *val);
+
+/**
+ * Write UTF-16LE string.
+ *
+ * \param w JSON write context.
+ * \param val UTF-16LE string; may contain embedded null characters.
+ * \param len Length of val in 16-bit code units (i.e. size of string in bytes divided by 2).
+ * \return 0 on success or negative on failure.
+ */
+int spdk_json_write_string_utf16le_raw(struct spdk_json_write_ctx *w, const uint16_t *val,
+ size_t len);
+
+int spdk_json_write_string_fmt(struct spdk_json_write_ctx *w, const char *fmt,
+ ...) __attribute__((__format__(__printf__, 2, 3)));
+int spdk_json_write_string_fmt_v(struct spdk_json_write_ctx *w, const char *fmt, va_list args);
+
+int spdk_json_write_array_begin(struct spdk_json_write_ctx *w);
+int spdk_json_write_array_end(struct spdk_json_write_ctx *w);
+int spdk_json_write_object_begin(struct spdk_json_write_ctx *w);
+int spdk_json_write_object_end(struct spdk_json_write_ctx *w);
+int spdk_json_write_name(struct spdk_json_write_ctx *w, const char *name);
+int spdk_json_write_name_raw(struct spdk_json_write_ctx *w, const char *name, size_t len);
+
+int spdk_json_write_val(struct spdk_json_write_ctx *w, const struct spdk_json_val *val);
+
+/*
+ * Append bytes directly to the output stream without validation.
+ *
+ * Can be used to write values with specific encodings that differ from the JSON writer output.
+ */
+int spdk_json_write_val_raw(struct spdk_json_write_ctx *w, const void *data, size_t len);
+
+/* Utility functions */
+int spdk_json_write_named_null(struct spdk_json_write_ctx *w, const char *name);
+int spdk_json_write_named_bool(struct spdk_json_write_ctx *w, const char *name, bool val);
+int spdk_json_write_named_int32(struct spdk_json_write_ctx *w, const char *name, int32_t val);
+int spdk_json_write_named_uint32(struct spdk_json_write_ctx *w, const char *name, uint32_t val);
+int spdk_json_write_named_uint64(struct spdk_json_write_ctx *w, const char *name, uint64_t val);
+int spdk_json_write_named_int64(struct spdk_json_write_ctx *w, const char *name, int64_t val);
+int spdk_json_write_named_string(struct spdk_json_write_ctx *w, const char *name, const char *val);
+int spdk_json_write_named_string_fmt(struct spdk_json_write_ctx *w, const char *name,
+ const char *fmt, ...) __attribute__((__format__(__printf__, 3, 4)));
+int spdk_json_write_named_string_fmt_v(struct spdk_json_write_ctx *w, const char *name,
+ const char *fmt, va_list args);
+
+int spdk_json_write_named_array_begin(struct spdk_json_write_ctx *w, const char *name);
+int spdk_json_write_named_object_begin(struct spdk_json_write_ctx *w, const char *name);
+
+/**
+ * Return JSON value asociated with key \c key_name. Subobjects won't be searched.
+ *
+ * \param object JSON object to be examined
+ * \param key_name name of the key
+ * \param key optional, will be set with found key
+ * \param val optional, will be set with value of the key
+ * \param type search for specific value type. Pass SPDK_JSON_VAL_ANY to match any type.
+ * \return 0 if found or negative error code:
+ * -EINVAL - json object is invalid
+ * -ENOENT - key not found
+ * -EDOM - key exists but value type mismatch.
+ */
+int spdk_json_find(struct spdk_json_val *object, const char *key_name, struct spdk_json_val **key,
+ struct spdk_json_val **val, enum spdk_json_val_type type);
+
+/**
+ * The same as calling \c spdk_json_find() function with \c type set to \c SPDK_JSON_VAL_STRING
+ *
+ * \param object JSON object to be examined
+ * \param key_name name of the key
+ * \param key optional, will be set with found key
+ * \param val optional, will be set with value of the key
+ * \return See \c spdk_json_find
+ */
+
+int spdk_json_find_string(struct spdk_json_val *object, const char *key_name,
+ struct spdk_json_val **key, struct spdk_json_val **val);
+
+/**
+ * The same as calling \c spdk_json_key() function with \c type set to \c SPDK_JSON_VAL_ARRAY_BEGIN
+ *
+ * \param object JSON object to be examined
+ * \param key_name name of the key
+ * \param key optional, will be set with found key
+ * \param value optional, will be set with key value
+ * \return See \c spdk_json_find
+ */
+int spdk_json_find_array(struct spdk_json_val *object, const char *key_name,
+ struct spdk_json_val **key, struct spdk_json_val **value);
+
+/**
+ * Return first JSON value in given JSON object.
+ *
+ * \param object pointer to JSON object begin
+ * \return Pointer to first object or NULL if object is empty or is not an JSON object
+ */
+struct spdk_json_val *spdk_json_object_first(struct spdk_json_val *object);
+
+/**
+ * Return first JSON value in array.
+ *
+ * \param array_begin pointer to JSON array begin
+ * \return Pointer to first JSON value or NULL if array is empty or is not an JSON array.
+ */
+
+struct spdk_json_val *spdk_json_array_first(struct spdk_json_val *array_begin);
+
+/**
+ * Advance to the next JSON value in JSON object or array.
+ *
+ * \warning if \c pos is not JSON key or JSON array element behaviour is undefined.
+ *
+ * \param pos pointer to JSON key if iterating over JSON object or array element
+ * \return next JSON value or NULL if there is no more objects or array elements
+ */
+struct spdk_json_val *spdk_json_next(struct spdk_json_val *pos);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/jsonrpc.h b/src/spdk/include/spdk/jsonrpc.h
new file mode 100644
index 00000000..ff9438a7
--- /dev/null
+++ b/src/spdk/include/spdk/jsonrpc.h
@@ -0,0 +1,265 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * JSON-RPC 2.0 server implementation
+ */
+
+#ifndef SPDK_JSONRPC_H_
+#define SPDK_JSONRPC_H_
+
+#include "spdk/stdinc.h"
+
+#include "spdk/json.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Defined error codes in JSON-RPC specification 2.0 */
+#define SPDK_JSONRPC_ERROR_PARSE_ERROR -32700
+#define SPDK_JSONRPC_ERROR_INVALID_REQUEST -32600
+#define SPDK_JSONRPC_ERROR_METHOD_NOT_FOUND -32601
+#define SPDK_JSONRPC_ERROR_INVALID_PARAMS -32602
+#define SPDK_JSONRPC_ERROR_INTERNAL_ERROR -32603
+
+/* Custom error codes in SPDK
+
+ * Error codes from and including -32768 to -32000 are reserved for
+ * predefined errors, hence custom error codes must be outside of the range.
+ */
+#define SPDK_JSONRPC_ERROR_INVALID_STATE -1
+
+struct spdk_jsonrpc_server;
+struct spdk_jsonrpc_request;
+
+struct spdk_jsonrpc_client;
+struct spdk_jsonrpc_client_request;
+
+/**
+ * User callback to handle a single JSON-RPC request.
+ *
+ * The user should respond by calling one of spdk_jsonrpc_begin_result() or
+ * spdk_jsonrpc_send_error_response().
+ *
+ * \param request JSON-RPC request to handle.
+ * \param method Function to handle the request.
+ * \param param Parameters passed to the function 'method'.
+ */
+typedef void (*spdk_jsonrpc_handle_request_fn)(
+ struct spdk_jsonrpc_request *request,
+ const struct spdk_json_val *method,
+ const struct spdk_json_val *params);
+
+/**
+ * Function for specific RPC method response parsing handlers.
+ *
+ * \param parser_ctx context where analysis are put.
+ * \param result json values responsed to this method.
+ *
+ * \return 0 on success.
+ * SPDK_JSON_PARSE_INVALID on failure.
+ */
+typedef int (*spdk_jsonrpc_client_response_parser)(
+ void *parser_ctx,
+ const struct spdk_json_val *result);
+
+/**
+ * Create a JSON-RPC server listening on the required address.
+ *
+ * \param domain Socket family.
+ * \param protocol Protocol.
+ * \param listen_addr Listening address.
+ * \param addrlen Length of address.
+ * \param handle_request User callback to handle a JSON-RPC request.
+ *
+ * \return a pointer to the JSON-RPC server.
+ */
+struct spdk_jsonrpc_server *spdk_jsonrpc_server_listen(int domain, int protocol,
+ struct sockaddr *listen_addr, socklen_t addrlen, spdk_jsonrpc_handle_request_fn handle_request);
+
+/**
+ * Poll the requests to the JSON-RPC server.
+ *
+ * This function does accept, receive, handle the requests and reply to them.
+ *
+ * \param server JSON-RPC server.
+ *
+ * \return 0 on success.
+ */
+int spdk_jsonrpc_server_poll(struct spdk_jsonrpc_server *server);
+
+/**
+ * Shutdown the JSON-RPC server.
+ *
+ * \param server JSON-RPC server.
+ */
+void spdk_jsonrpc_server_shutdown(struct spdk_jsonrpc_server *server);
+
+/**
+ * Begin building a response to a JSON-RPC request.
+ *
+ * If this function returns non-NULL, the user must call spdk_jsonrpc_end_result()
+ * on the request after writing the desired response object to the spdk_json_write_ctx.
+ *
+ * \param request JSON-RPC request to respond to.
+
+ * \return JSON write context to write the response object to, or NULL if no
+ * response is necessary.
+ */
+struct spdk_json_write_ctx *spdk_jsonrpc_begin_result(struct spdk_jsonrpc_request *request);
+
+/**
+ * Complete and send a JSON-RPC response.
+ *
+ * \param request Request to complete the response for.
+ * \param w JSON write context returned from spdk_jsonrpc_begin_result().
+ */
+void spdk_jsonrpc_end_result(struct spdk_jsonrpc_request *request, struct spdk_json_write_ctx *w);
+
+/**
+ * Send an error response to a JSON-RPC request.
+ *
+ * This is shorthand for spdk_jsonrpc_begin_result() + spdk_jsonrpc_end_result()
+ * with an error object.
+ *
+ * \param request JSON-RPC request to respond to.
+ * \param error_code Integer error code to return (may be one of the
+ * SPDK_JSONRPC_ERROR_ errors, or a custom error code).
+ * \param msg String error message to return.
+ */
+void spdk_jsonrpc_send_error_response(struct spdk_jsonrpc_request *request,
+ int error_code, const char *msg);
+
+/**
+ * Send an error response to a JSON-RPC request.
+ *
+ * This is shorthand for printf() + spdk_jsonrpc_send_error_response().
+ *
+ * \param request JSON-RPC request to respond to.
+ * \param error_code Integer error code to return (may be one of the
+ * SPDK_JSONRPC_ERROR_ errors, or a custom error code).
+ * \param fmt Printf-like format string.
+ */
+void spdk_jsonrpc_send_error_response_fmt(struct spdk_jsonrpc_request *request,
+ int error_code, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
+
+/**
+ * Begin building a JSON-RPC request.
+ *
+ * If this function returns non-NULL, the user must call spdk_jsonrpc_end_request()
+ * on the request after writing the desired request object to the spdk_json_write_ctx.
+ *
+ * \param request JSON-RPC request.
+ * \param id ID index for the request. If < 0 skip ID.
+ * \param method Name of the RPC method. If NULL caller will have to create "method" key.
+ *
+ * \return JSON write context to write the parameter object to, or NULL if no
+ * parameter is necessary.
+ */
+struct spdk_json_write_ctx *
+spdk_jsonrpc_begin_request(struct spdk_jsonrpc_client_request *request, int32_t id,
+ const char *method);
+
+/**
+ * Complete a JSON-RPC request.
+ *
+ * \param request JSON-RPC request.
+ * \param w JSON write context returned from spdk_jsonrpc_begin_request().
+ */
+void spdk_jsonrpc_end_request(struct spdk_jsonrpc_client_request *request,
+ struct spdk_json_write_ctx *w);
+
+/**
+ * Connect to the specified RPC server.
+ *
+ * \param rpc_sock_addr RPC socket address.
+ * \param addr_family Protocol families of address.
+ *
+ * \return JSON-RPC client on success, NULL on failure.
+ */
+struct spdk_jsonrpc_client *spdk_jsonrpc_client_connect(const char *rpc_sock_addr,
+ int addr_family);
+
+/**
+ * Close the JSON-RPC client.
+ *
+ * \param client JSON-RPC client.
+ */
+void spdk_jsonrpc_client_close(struct spdk_jsonrpc_client *client);
+
+/**
+ * Create one JSON-RPC request
+ *
+ * \return Created JSON-RPC request.
+ */
+struct spdk_jsonrpc_client_request *spdk_jsonrpc_client_create_request(void);
+
+/**
+ * free one JSON-RPC request
+ *
+ * \param req Created JSON-RPC request.
+ */
+void spdk_jsonrpc_client_free_request(
+ struct spdk_jsonrpc_client_request *req);
+
+/**
+ * Send the JSON-RPC request in JSON-RPC client.
+ *
+ * \param client JSON-RPC client.
+ * \param req JSON-RPC request.
+ *
+ * \return 0 on success.
+ */
+int spdk_jsonrpc_client_send_request(struct spdk_jsonrpc_client *client,
+ struct spdk_jsonrpc_client_request *req);
+
+/**
+ * Receive the JSON-RPC response in JSON-RPC client.
+ *
+ * \param client JSON-RPC client.
+ * \param parser_fn Specific function used to parse the result inside response.
+ * \param parser_ctx Parameter for parser_fn.
+ *
+ * \return 0 on success.
+ */
+int spdk_jsonrpc_client_recv_response(struct spdk_jsonrpc_client *client,
+ spdk_jsonrpc_client_response_parser parser_fn,
+ void *parser_ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/likely.h b/src/spdk/include/spdk/likely.h
new file mode 100644
index 00000000..034a9b98
--- /dev/null
+++ b/src/spdk/include/spdk/likely.h
@@ -0,0 +1,46 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Likely/unlikely branch prediction macros
+ */
+
+#ifndef SPDK_LIKELY_H
+#define SPDK_LIKELY_H
+
+#include "spdk/stdinc.h"
+
+#define spdk_unlikely(cond) __builtin_expect((cond), 0)
+#define spdk_likely(cond) __builtin_expect(!!(cond), 1)
+
+#endif
diff --git a/src/spdk/include/spdk/log.h b/src/spdk/include/spdk/log.h
new file mode 100644
index 00000000..b6f0dd62
--- /dev/null
+++ b/src/spdk/include/spdk/log.h
@@ -0,0 +1,189 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * Logging interfaces
+ */
+
+#ifndef SPDK_LOG_H
+#define SPDK_LOG_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the logging module. Messages prior
+ * to this call will be dropped.
+ */
+void spdk_log_open(void);
+
+/**
+ * Close the currently active log. Messages after this call
+ * will be dropped.
+ */
+void spdk_log_close(void);
+
+enum spdk_log_level {
+ /** All messages will be suppressed. */
+ SPDK_LOG_DISABLED = -1,
+ SPDK_LOG_ERROR,
+ SPDK_LOG_WARN,
+ SPDK_LOG_NOTICE,
+ SPDK_LOG_INFO,
+ SPDK_LOG_DEBUG,
+};
+
+/**
+ * Set the log level threshold to log messages. Messages with a higher
+ * level than this are ignored.
+ *
+ * \param level Log level threshold to set to log messages.
+ */
+void spdk_log_set_level(enum spdk_log_level level);
+
+/**
+ * Get the current log level threshold.
+ *
+ * \return the current log level threshold.
+ */
+enum spdk_log_level spdk_log_get_level(void);
+
+/**
+ * Set the log level threshold to include stack trace in log messages.
+ * Messages with a higher level than this will not contain stack trace. You
+ * can use \c SPDK_LOG_DISABLED to completely disable stack trace printing
+ * even if it is supported.
+ *
+ * \note This function has no effect if SPDK is built without stack trace
+ * printing support.
+ *
+ * \param level Log level threshold for stacktrace.
+ */
+void spdk_log_set_backtrace_level(enum spdk_log_level level);
+
+/**
+ * Get the current log level threshold for showing stack trace in log message.
+ *
+ * \return the current log level threshold for stack trace.
+ */
+enum spdk_log_level spdk_log_get_backtrace_level(void);
+
+/**
+ * Set the current log level threshold for printing to stderr.
+ * Messages with a level less than or equal to this level
+ * are also printed to stderr. You can use \c SPDK_LOG_DISABLED to completely
+ * suppress log printing.
+ *
+ * \param level Log level threshold for printing to stderr.
+ */
+void spdk_log_set_print_level(enum spdk_log_level level);
+
+/**
+ * Get the current log level print threshold.
+ *
+ * \return the current log level print threshold.
+ */
+enum spdk_log_level spdk_log_get_print_level(void);
+
+#define SPDK_NOTICELOG(...) \
+ spdk_log(SPDK_LOG_NOTICE, __FILE__, __LINE__, __func__, __VA_ARGS__)
+#define SPDK_WARNLOG(...) \
+ spdk_log(SPDK_LOG_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__)
+#define SPDK_ERRLOG(...) \
+ spdk_log(SPDK_LOG_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__)
+
+/**
+ * Write messages to the log file. If \c level is set to \c SPDK_LOG_DISABLED,
+ * this log message won't be written.
+ *
+ * \param level Log level threshold.
+ * \param file Name of the current source file.
+ * \param line Current source line number.
+ * \param func Current source function name.
+ * \param format Format string to the message.
+ */
+void spdk_log(enum spdk_log_level level, const char *file, const int line, const char *func,
+ const char *format, ...) __attribute__((__format__(__printf__, 5, 6)));
+
+/**
+ * Dump the trace to a file.
+ *
+ * \param fp File to hold the trace.
+ * \param label Label to print to the file.
+ * \param buf Buffer that holds the trace information.
+ * \param len Length of trace to dump.
+ */
+void spdk_trace_dump(FILE *fp, const char *label, const void *buf, size_t len);
+
+/**
+ * Check whether the trace flag exists and is enabled.
+ *
+ * \return true if enabled, or false otherwise.
+ */
+bool spdk_log_get_trace_flag(const char *flag);
+
+/**
+ * Enable the trace flag.
+ *
+ * \param flag Trace flag to be enabled.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_log_set_trace_flag(const char *flag);
+
+/**
+ * Clear a trace flag.
+ *
+ * \param flag Trace flag to clear.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_log_clear_trace_flag(const char *flag);
+
+/**
+ * Show all the log trace flags and their usage.
+ *
+ * \param f File to hold all the flags' information.
+ * \param trace_arg Command line option to set/enable the trace flag.
+ */
+void spdk_tracelog_usage(FILE *f, const char *trace_arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_LOG_H */
diff --git a/src/spdk/include/spdk/lvol.h b/src/spdk/include/spdk/lvol.h
new file mode 100644
index 00000000..279b4dfd
--- /dev/null
+++ b/src/spdk/include/spdk/lvol.h
@@ -0,0 +1,282 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Logical Volume Interface
+ */
+
+#ifndef SPDK_LVOL_H
+#define SPDK_LVOL_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct spdk_bs_dev;
+struct spdk_lvol_store;
+struct spdk_lvol;
+
+/* Must include null terminator. */
+#define SPDK_LVS_NAME_MAX 64
+#define SPDK_LVOL_NAME_MAX 64
+
+/**
+ * Parameters for lvolstore initialization.
+ */
+struct spdk_lvs_opts {
+ uint32_t cluster_sz;
+ char name[SPDK_LVS_NAME_MAX];
+};
+
+/**
+ * Initialize an spdk_lvs_opts structure to the defaults.
+ *
+ * \param opts Pointer to the spdk_lvs_opts structure to initialize.
+ */
+void spdk_lvs_opts_init(struct spdk_lvs_opts *opts);
+
+/**
+ * Callback definition for lvolstore operations, including handle to lvs.
+ *
+ * \param cb_arg Custom arguments
+ * \param lvol_store Handle to lvol_store or NULL when lvserrno is set
+ * \param lvserrno Error
+ */
+typedef void (*spdk_lvs_op_with_handle_complete)(void *cb_arg, struct spdk_lvol_store *lvol_store,
+ int lvserrno);
+
+/**
+ * Callback definition for lvolstore operations without handle.
+ *
+ * \param cb_arg Custom arguments
+ * \param lvserrno Error
+ */
+typedef void (*spdk_lvs_op_complete)(void *cb_arg, int lvserrno);
+
+
+/**
+ * Callback definition for lvol operations with handle to lvol.
+ *
+ * \param cb_arg Custom arguments
+ * \param lvol Handle to lvol or NULL when lvserrno is set
+ * \param lvolerrno Error
+ */
+typedef void (*spdk_lvol_op_with_handle_complete)(void *cb_arg, struct spdk_lvol *lvol,
+ int lvolerrno);
+
+/**
+ * Callback definition for lvol operations without handle to lvol.
+ *
+ * \param cb_arg Custom arguments
+ * \param lvolerrno Error
+ */
+typedef void (*spdk_lvol_op_complete)(void *cb_arg, int lvolerrno);
+
+/**
+ * Initialize lvolstore on given bs_bdev.
+ *
+ * \param bs_dev This is created on the given bdev by using spdk_bdev_create_bs_dev()
+ * beforehand.
+ * \param o Options for lvolstore.
+ * \param cb_fn Completion callback.
+ * \param cb_arg Completion callback custom arguments.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_lvs_init(struct spdk_bs_dev *bs_dev, struct spdk_lvs_opts *o,
+ spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg);
+
+/**
+ * Rename the given lvolstore.
+ *
+ * \param lvs Pointer to lvolstore.
+ * \param new_name New name of lvs.
+ * \param cb_fn Completion callback.
+ * \param cb_arg Completion callback custom arguments.
+ */
+void spdk_lvs_rename(struct spdk_lvol_store *lvs, const char *new_name,
+ spdk_lvs_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Unload lvolstore.
+ *
+ * All lvols have to be closed beforehand, when doing unload.
+ *
+ * \param lvol_store Handle to lvolstore.
+ * \param cb_fn Completion callback.
+ * \param cb_arg Completion callback custom arguments.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_lvs_unload(struct spdk_lvol_store *lvol_store,
+ spdk_lvs_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Destroy lvolstore.
+ *
+ * All lvols have to be closed beforehand, when doing destroy.
+ *
+ * \param lvol_store Handle to lvolstore.
+ * \param cb_fn Completion callback.
+ * \param cb_arg Completion callback custom arguments.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_lvs_destroy(struct spdk_lvol_store *lvol_store,
+ spdk_lvs_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Create lvol on given lvolstore with specified size.
+ *
+ * \param lvs Handle to lvolstore.
+ * \param name Name of lvol.
+ * \param sz size of lvol in bytes.
+ * \param thin_provisioned Enables thin provisioning.
+ * \param cb_fn Completion callback.
+ * \param cb_arg Completion callback custom arguments.
+ *
+ * \return 0 on success, negative errno on failure.
+ */
+int spdk_lvol_create(struct spdk_lvol_store *lvs, const char *name, uint64_t sz,
+ bool thin_provisioned, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
+/**
+ * Create snapshot of given lvol.
+ *
+ * \param lvol Handle to lvol.
+ * \param snapshot_name Name of created snapshot.
+ * \param cb_fn Completion callback.
+ * \param cb_arg Completion callback custom arguments.
+ */
+void spdk_lvol_create_snapshot(struct spdk_lvol *lvol, const char *snapshot_name,
+ spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
+
+/**
+ * Create clone of given snapshot.
+ *
+ * \param lvol Handle to lvol snapshot.
+ * \param clone_name Name of created clone.
+ * \param cb_fn Completion callback.
+ * \param cb_arg Completion callback custom arguments.
+ */
+void spdk_lvol_create_clone(struct spdk_lvol *lvol, const char *clone_name,
+ spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
+
+/**
+ * Rename lvol with new_name.
+ *
+ * \param lvol Handle to lvol.
+ * \param new_name new name for lvol.
+ * \param cb_fn Completion callback.
+ * \param cb_arg Completion callback custom arguments.
+ */
+void
+spdk_lvol_rename(struct spdk_lvol *lvol, const char *new_name,
+ spdk_lvol_op_complete cb_fn, void *cb_arg);
+
+/**
+ * \brief Returns if it is possible to delete an lvol (i.e. lvol is not a snapshot that have at least one clone).
+ * \param lvol Handle to lvol
+ */
+bool spdk_lvol_deletable(struct spdk_lvol *lvol);
+
+/**
+ * Close lvol and remove information about lvol from its lvolstore.
+ *
+ * \param lvol Handle to lvol.
+ * \param cb_fn Completion callback.
+ * \param cb_arg Completion callback custom arguments.
+ */
+void spdk_lvol_destroy(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Close lvol, but information is kept on lvolstore.
+ *
+ * \param lvol Handle to lvol.
+ * \param cb_fn Completion callback.
+ * \param cb_arg Completion callback custom arguments.
+ */
+void spdk_lvol_close(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Get I/O channel of bdev associated with specified lvol.
+ *
+ * \param lvol Handle to lvol.
+ *
+ * \return a pointer to the I/O channel.
+ */
+struct spdk_io_channel *spdk_lvol_get_io_channel(struct spdk_lvol *lvol);
+
+/**
+ * Load lvolstore from the given blobstore device.
+ *
+ * \param bs_dev Pointer to the blobstore device.
+ * \param cb_fn Completion callback.
+ * \param cb_arg Completion callback custom arguments.
+ */
+void spdk_lvs_load(struct spdk_bs_dev *bs_dev, spdk_lvs_op_with_handle_complete cb_fn,
+ void *cb_arg);
+
+/**
+ * Open a lvol.
+ *
+ * \param lvol Handle to lvol.
+ * \param cb_fn Completion callback.
+ * \param cb_arg Completion callback custom arguments.
+ */
+void spdk_lvol_open(struct spdk_lvol *lvol, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
+
+/**
+ * Inflate lvol
+ *
+ * \param lvol Handle to lvol
+ * \param cb_fn Completion callback
+ * \param cb_arg Completion callback custom arguments
+ */
+void spdk_lvol_inflate(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg);
+
+/**
+ * Decouple parent of lvol
+ *
+ * \param lvol Handle to lvol
+ * \param cb_fn Completion callback
+ * \param cb_arg Completion callback custom arguments
+ */
+void spdk_lvol_decouple_parent(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_LVOL_H */
diff --git a/src/spdk/include/spdk/mmio.h b/src/spdk/include/spdk/mmio.h
new file mode 100644
index 00000000..68b16605
--- /dev/null
+++ b/src/spdk/include/spdk/mmio.h
@@ -0,0 +1,139 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Memory-mapped I/O utility functions
+ */
+
+#ifndef SPDK_MMIO_H
+#define SPDK_MMIO_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "spdk/barrier.h"
+
+#ifdef __x86_64__
+#define SPDK_MMIO_64BIT 1 /* Can do atomic 64-bit memory read/write (over PCIe) */
+#else
+#define SPDK_MMIO_64BIT 0
+#endif
+
+static inline uint8_t
+spdk_mmio_read_1(const volatile uint8_t *addr)
+{
+ spdk_compiler_barrier();
+ return *addr;
+}
+
+static inline void
+spdk_mmio_write_1(volatile uint8_t *addr, uint8_t val)
+{
+ spdk_compiler_barrier();
+ *addr = val;
+}
+
+static inline uint16_t
+spdk_mmio_read_2(const volatile uint16_t *addr)
+{
+ spdk_compiler_barrier();
+ return *addr;
+}
+
+static inline void
+spdk_mmio_write_2(volatile uint16_t *addr, uint16_t val)
+{
+ spdk_compiler_barrier();
+ *addr = val;
+}
+
+static inline uint32_t
+spdk_mmio_read_4(const volatile uint32_t *addr)
+{
+ spdk_compiler_barrier();
+ return *addr;
+}
+
+static inline void
+spdk_mmio_write_4(volatile uint32_t *addr, uint32_t val)
+{
+ spdk_compiler_barrier();
+ *addr = val;
+}
+
+static inline uint64_t
+spdk_mmio_read_8(volatile uint64_t *addr)
+{
+ uint64_t val;
+ volatile uint32_t *addr32 = (volatile uint32_t *)addr;
+
+ spdk_compiler_barrier();
+
+ if (SPDK_MMIO_64BIT) {
+ val = *addr;
+ } else {
+ /*
+ * Read lower 4 bytes before upper 4 bytes.
+ * This particular order is required by I/OAT.
+ * If the other order is required, use a pair of spdk_mmio_read_4() calls.
+ */
+ val = addr32[0];
+ val |= (uint64_t)addr32[1] << 32;
+ }
+
+ return val;
+}
+
+static inline void
+spdk_mmio_write_8(volatile uint64_t *addr, uint64_t val)
+{
+ volatile uint32_t *addr32 = (volatile uint32_t *)addr;
+
+ spdk_compiler_barrier();
+
+ if (SPDK_MMIO_64BIT) {
+ *addr = val;
+ } else {
+ addr32[0] = (uint32_t)val;
+ addr32[1] = (uint32_t)(val >> 32);
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/nbd.h b/src/spdk/include/spdk/nbd.h
new file mode 100644
index 00000000..d987c1c4
--- /dev/null
+++ b/src/spdk/include/spdk/nbd.h
@@ -0,0 +1,91 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Network block device layer
+ */
+
+#ifndef SPDK_NBD_H_
+#define SPDK_NBD_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct spdk_bdev;
+struct spdk_nbd_disk;
+struct spdk_json_write_ctx;
+struct spdk_event;
+
+/**
+ * Initialize the network block device layer.
+ *
+ * \return 0 on success.
+ */
+int spdk_nbd_init(void);
+
+/**
+ * Stop and close all the running network block devices.
+ */
+void spdk_nbd_fini(void);
+
+/**
+ * Start a network block device backed by the bdev.
+ *
+ * \param bdev_name Name of bdev exposed as a network block device.
+ * \param nbd_path Path to the registered network block device.
+ *
+ * \return a pointer to the configuration of the registered network block device
+ * on success, or NULL on failure.
+ */
+struct spdk_nbd_disk *spdk_nbd_start(const char *bdev_name, const char *nbd_path);
+
+/**
+ * Stop the running network block device safely.
+ *
+ * \param nbd A pointer to the network block device to stop.
+ */
+void spdk_nbd_stop(struct spdk_nbd_disk *nbd);
+
+/**
+ * Write NBD subsystem configuration into provided JSON context.
+ *
+ * \param w JSON write context
+ */
+void spdk_nbd_write_config_json(struct spdk_json_write_ctx *w);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/net.h b/src/spdk/include/spdk/net.h
new file mode 100644
index 00000000..ef58dd6d
--- /dev/null
+++ b/src/spdk/include/spdk/net.h
@@ -0,0 +1,101 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Net framework abstraction layer
+ */
+
+#ifndef SPDK_NET_H
+#define SPDK_NET_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct spdk_sock;
+
+struct spdk_net_framework {
+ const char *name;
+
+ int (*init)(void);
+ void (*fini)(void);
+
+ STAILQ_ENTRY(spdk_net_framework) link;
+};
+
+/**
+ * Register a net framework.
+ *
+ * \param frame Net framework to register.
+ */
+void spdk_net_framework_register(struct spdk_net_framework *frame);
+
+#define SPDK_NET_FRAMEWORK_REGISTER(name, frame) \
+static void __attribute__((constructor)) net_framework_register_##name(void) \
+{ \
+ spdk_net_framework_register(frame); \
+}
+
+/**
+ * Initialize the network interfaces by getting information through netlink socket.
+ *
+ * \return 0 on success, 1 on failure.
+ */
+int spdk_interface_init(void);
+
+/**
+ * Destroy the network interfaces.
+ */
+void spdk_interface_destroy(void);
+
+/**
+ * Start all registered frameworks.
+ *
+ * \return 0 on success.
+ */
+int spdk_net_framework_start(void);
+
+/**
+ * Stop all registered frameworks.
+ */
+void spdk_net_framework_fini(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_NET_H */
diff --git a/src/spdk/include/spdk/nvme.h b/src/spdk/include/spdk/nvme.h
new file mode 100644
index 00000000..89ae2061
--- /dev/null
+++ b/src/spdk/include/spdk/nvme.h
@@ -0,0 +1,2043 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * NVMe driver public API
+ */
+
+#ifndef SPDK_NVME_H
+#define SPDK_NVME_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "spdk/env.h"
+#include "spdk/nvme_spec.h"
+#include "spdk/nvmf_spec.h"
+
+#define SPDK_NVME_DEFAULT_RETRY_COUNT (4)
+extern int32_t spdk_nvme_retry_count;
+
+
+
+/**
+ * Opaque handle to a controller. Returned by spdk_nvme_probe()'s attach_cb.
+ */
+struct spdk_nvme_ctrlr;
+
+/**
+ * NVMe controller initialization options.
+ *
+ * A pointer to this structure will be provided for each probe callback from spdk_nvme_probe() to
+ * allow the user to request non-default options, and the actual options enabled on the controller
+ * will be provided during the attach callback.
+ */
+struct spdk_nvme_ctrlr_opts {
+ /**
+ * Number of I/O queues to request (used to set Number of Queues feature)
+ */
+ uint32_t num_io_queues;
+
+ /**
+ * Enable submission queue in controller memory buffer
+ */
+ bool use_cmb_sqs;
+
+ /**
+ * Type of arbitration mechanism
+ */
+ enum spdk_nvme_cc_ams arb_mechanism;
+
+ /**
+ * Keep alive timeout in milliseconds (0 = disabled).
+ *
+ * The NVMe library will set the Keep Alive Timer feature to this value and automatically
+ * send Keep Alive commands as needed. The library user must call
+ * spdk_nvme_ctrlr_process_admin_completions() periodically to ensure Keep Alive commands
+ * are sent.
+ */
+ uint32_t keep_alive_timeout_ms;
+
+ /**
+ * Specify the retry number when there is issue with the transport
+ */
+ int transport_retry_count;
+
+ /**
+ * The queue depth of each NVMe I/O queue.
+ */
+ uint32_t io_queue_size;
+
+ /**
+ * The host NQN to use when connecting to NVMe over Fabrics controllers.
+ *
+ * Unused for local PCIe-attached NVMe devices.
+ */
+ char hostnqn[SPDK_NVMF_NQN_MAX_LEN + 1];
+
+ /**
+ * The number of requests to allocate for each NVMe I/O queue.
+ *
+ * This should be at least as large as io_queue_size.
+ *
+ * A single I/O may allocate more than one request, since splitting may be necessary to
+ * conform to the device's maximum transfer size, PRP list compatibility requirements,
+ * or driver-assisted striping.
+ */
+ uint32_t io_queue_requests;
+
+ /**
+ * Source address for NVMe-oF connections.
+ * Set src_addr and src_svcid to empty strings if no source address should be
+ * specified.
+ */
+ char src_addr[SPDK_NVMF_TRADDR_MAX_LEN + 1];
+
+ /**
+ * Source service ID (port) for NVMe-oF connections.
+ * Set src_addr and src_svcid to empty strings if no source address should be
+ * specified.
+ */
+ char src_svcid[SPDK_NVMF_TRSVCID_MAX_LEN + 1];
+
+ /**
+ * The host identifier to use when connecting to controllers with 64-bit host ID support.
+ *
+ * Set to all zeroes to specify that no host ID should be provided to the controller.
+ */
+ uint8_t host_id[8];
+
+ /**
+ * The host identifier to use when connecting to controllers with extended (128-bit) host ID support.
+ *
+ * Set to all zeroes to specify that no host ID should be provided to the controller.
+ */
+ uint8_t extended_host_id[16];
+
+ /**
+ * The I/O command set to select.
+ *
+ * If the requested command set is not supported, the controller
+ * initialization process will not proceed. By default, the NVM
+ * command set is used.
+ */
+ enum spdk_nvme_cc_css command_set;
+};
+
+/**
+ * Get the default options for the creation of a specific NVMe controller.
+ *
+ * \param[out] opts Will be filled with the default option.
+ * \param opts_size Must be set to sizeof(struct spdk_nvme_ctrlr_opts).
+ */
+void spdk_nvme_ctrlr_get_default_ctrlr_opts(struct spdk_nvme_ctrlr_opts *opts,
+ size_t opts_size);
+
+/**
+ * NVMe library transports
+ *
+ * NOTE: These are mapped directly to the NVMe over Fabrics TRTYPE values, except for PCIe,
+ * which is a special case since NVMe over Fabrics does not define a TRTYPE for local PCIe.
+ *
+ * Currently, this uses 256 for PCIe which is intentionally outside of the 8-bit range of TRTYPE.
+ * If the NVMe-oF specification ever defines a PCIe TRTYPE, this should be updated.
+ */
+enum spdk_nvme_transport_type {
+ /**
+ * PCIe Transport (locally attached devices)
+ */
+ SPDK_NVME_TRANSPORT_PCIE = 256,
+
+ /**
+ * RDMA Transport (RoCE, iWARP, etc.)
+ */
+ SPDK_NVME_TRANSPORT_RDMA = SPDK_NVMF_TRTYPE_RDMA,
+
+ /**
+ * Fibre Channel (FC) Transport
+ */
+ SPDK_NVME_TRANSPORT_FC = SPDK_NVMF_TRTYPE_FC,
+};
+
+/**
+ * NVMe transport identifier.
+ *
+ * This identifies a unique endpoint on an NVMe fabric.
+ *
+ * A string representation of a transport ID may be converted to this type using
+ * spdk_nvme_transport_id_parse().
+ */
+struct spdk_nvme_transport_id {
+ /**
+ * NVMe transport type.
+ */
+ enum spdk_nvme_transport_type trtype;
+
+ /**
+ * Address family of the transport address.
+ *
+ * For PCIe, this value is ignored.
+ */
+ enum spdk_nvmf_adrfam adrfam;
+
+ /**
+ * Transport address of the NVMe-oF endpoint. For transports which use IP
+ * addressing (e.g. RDMA), this should be an IP address. For PCIe, this
+ * can either be a zero length string (the whole bus) or a PCI address
+ * in the format DDDD:BB:DD.FF or DDDD.BB.DD.FF. For FC the string is
+ * formatted as: nn-0xWWNN:pn-0xWWPN” where WWNN is the Node_Name of the
+ * target NVMe_Port and WWPN is the N_Port_Name of the target NVMe_Port.
+ */
+ char traddr[SPDK_NVMF_TRADDR_MAX_LEN + 1];
+
+ /**
+ * Transport service id of the NVMe-oF endpoint. For transports which use
+ * IP addressing (e.g. RDMA), this field shoud be the port number. For PCIe,
+ * and FC this is always a zero length string.
+ */
+ char trsvcid[SPDK_NVMF_TRSVCID_MAX_LEN + 1];
+
+ /**
+ * Subsystem NQN of the NVMe over Fabrics endpoint. May be a zero length string.
+ */
+ char subnqn[SPDK_NVMF_NQN_MAX_LEN + 1];
+};
+
+/**
+ * Parse the string representation of a transport ID.
+ *
+ * \param trid Output transport ID structure (must be allocated and initialized by caller).
+ * \param str Input string representation of a transport ID to parse.
+ *
+ * str must be a zero-terminated C string containing one or more key:value pairs
+ * separated by whitespace.
+ *
+ * Key | Value
+ * ------------ | -----
+ * trtype | Transport type (e.g. PCIe, RDMA)
+ * adrfam | Address family (e.g. IPv4, IPv6)
+ * traddr | Transport address (e.g. 0000:04:00.0 for PCIe, 192.168.100.8 for RDMA, or WWN for FC)
+ * trsvcid | Transport service identifier (e.g. 4420)
+ * subnqn | Subsystem NQN
+ *
+ * Unspecified fields of trid are left unmodified, so the caller must initialize
+ * trid (for example, memset() to 0) before calling this function.
+ *
+ * \return 0 if parsing was successful and trid is filled out, or negated errno
+ * values on failure.
+ */
+int spdk_nvme_transport_id_parse(struct spdk_nvme_transport_id *trid, const char *str);
+
+/**
+ * Parse the string representation of a transport ID tranport type.
+ *
+ * \param trtype Output transport type (allocated by caller).
+ * \param str Input string representation of transport type (e.g. "PCIe", "RDMA").
+ *
+ * \return 0 if parsing was successful and trtype is filled out, or negated errno
+ * values on failure.
+ */
+int spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str);
+
+/**
+ * Look up the string representation of a transport ID transport type.
+ *
+ * \param trtype Transport type to convert.
+ *
+ * \return static string constant describing trtype, or NULL if trtype not found.
+ */
+const char *spdk_nvme_transport_id_trtype_str(enum spdk_nvme_transport_type trtype);
+
+/**
+ * Look up the string representation of a transport ID address family.
+ *
+ * \param adrfam Address family to convert.
+ *
+ * \return static string constant describing adrfam, or NULL if adrmfam not found.
+ */
+const char *spdk_nvme_transport_id_adrfam_str(enum spdk_nvmf_adrfam adrfam);
+
+/**
+ * Parse the string representation of a tranport ID address family.
+ *
+ * \param adrfam Output address family (allocated by caller).
+ * \param str Input string representation of address family (e.g. "IPv4", "IPv6").
+ *
+ * \return 0 if parsing was successful and adrfam is filled out, or negated errno
+ * values on failure.
+ */
+int spdk_nvme_transport_id_parse_adrfam(enum spdk_nvmf_adrfam *adrfam, const char *str);
+
+/**
+ * Compare two transport IDs.
+ *
+ * The result of this function may be used to sort transport IDs in a consistent
+ * order; however, the comparison result is not guaranteed to be consistent across
+ * library versions.
+ *
+ * This function uses a case-insensitive comparison for string fields, but it does
+ * not otherwise normalize the transport ID. It is the caller's responsibility to
+ * provide the transport IDs in a consistent format.
+ *
+ * \param trid1 First transport ID to compare.
+ * \param trid2 Second transport ID to compare.
+ *
+ * \return 0 if trid1 == trid2, less than 0 if trid1 < trid2, greater than 0 if
+ * trid1 > trid2.
+ */
+int spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1,
+ const struct spdk_nvme_transport_id *trid2);
+
+/**
+ * Determine whether the NVMe library can handle a specific NVMe over Fabrics
+ * transport type.
+ *
+ * \param trtype NVMe over Fabrics transport type to check.
+ *
+ * \return true if trtype is supported or false if it is not supported.
+ */
+bool spdk_nvme_transport_available(enum spdk_nvme_transport_type trtype);
+
+/**
+ * Callback for spdk_nvme_probe() enumeration.
+ *
+ * \param cb_ctx Opaque value passed to spdk_nvme_probe().
+ * \param trid NVMe transport identifier.
+ * \param opts NVMe controller initialization options. This structure will be
+ * populated with the default values on entry, and the user callback may update
+ * any options to request a different value. The controller may not support all
+ * requested parameters, so the final values will be provided during the attach
+ * callback.
+ *
+ * \return true to attach to this device.
+ */
+typedef bool (*spdk_nvme_probe_cb)(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
+ struct spdk_nvme_ctrlr_opts *opts);
+
+/**
+ * Callback for spdk_nvme_attach() to report a device that has been attached to
+ * the userspace NVMe driver.
+ *
+ * \param cb_ctx Opaque value passed to spdk_nvme_attach_cb().
+ * \param trid NVMe transport identifier.
+ * \param ctrlr Opaque handle to NVMe controller.
+ * \param opts NVMe controller initialization options that were actually used.
+ * Options may differ from the requested options from the attach call depending
+ * on what the controller supports.
+ */
+typedef void (*spdk_nvme_attach_cb)(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
+ struct spdk_nvme_ctrlr *ctrlr,
+ const struct spdk_nvme_ctrlr_opts *opts);
+
+/**
+ * Callback for spdk_nvme_remove() to report that a device attached to the userspace
+ * NVMe driver has been removed from the system.
+ *
+ * The controller will remain in a failed state (any new I/O submitted will fail).
+ *
+ * The controller must be detached from the userspace driver by calling spdk_nvme_detach()
+ * once the controller is no longer in use. It is up to the library user to ensure
+ * that no other threads are using the controller before calling spdk_nvme_detach().
+ *
+ * \param cb_ctx Opaque value passed to spdk_nvme_remove_cb().
+ * \param ctrlr NVMe controller instance that was removed.
+ */
+typedef void (*spdk_nvme_remove_cb)(void *cb_ctx, struct spdk_nvme_ctrlr *ctrlr);
+
+/**
+ * Enumerate the bus indicated by the transport ID and attach the userspace NVMe
+ * driver to each device found if desired.
+ *
+ * This function is not thread safe and should only be called from one thread at
+ * a time while no other threads are actively using any NVMe devices.
+ *
+ * If called from a secondary process, only devices that have been attached to
+ * the userspace driver in the primary process will be probed.
+ *
+ * If called more than once, only devices that are not already attached to the
+ * SPDK NVMe driver will be reported.
+ *
+ * To stop using the the controller and release its associated resources,
+ * call spdk_nvme_detach() with the spdk_nvme_ctrlr instance from the attach_cb()
+ * function.
+ *
+ * \param trid The transport ID indicating which bus to enumerate. If the trtype
+ * is PCIe or trid is NULL, this will scan the local PCIe bus. If the trtype is
+ * RDMA, the traddr and trsvcid must point at the location of an NVMe-oF discovery
+ * service.
+ * \param cb_ctx Opaque value which will be passed back in cb_ctx parameter of
+ * the callbacks.
+ * \param probe_cb will be called once per NVMe device found in the system.
+ * \param attach_cb will be called for devices for which probe_cb returned true
+ * once that NVMe controller has been attached to the userspace driver.
+ * \param remove_cb will be called for devices that were attached in a previous
+ * spdk_nvme_probe() call but are no longer attached to the system. Optional;
+ * specify NULL if removal notices are not desired.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_nvme_probe(const struct spdk_nvme_transport_id *trid,
+ void *cb_ctx,
+ spdk_nvme_probe_cb probe_cb,
+ spdk_nvme_attach_cb attach_cb,
+ spdk_nvme_remove_cb remove_cb);
+
+/**
+ * Connect the NVMe driver to the device located at the given transport ID.
+ *
+ * This function is not thread safe and should only be called from one thread at
+ * a time while no other threads are actively using this NVMe device.
+ *
+ * If called from a secondary process, only the device that has been attached to
+ * the userspace driver in the primary process will be connected.
+ *
+ * If connecting to multiple controllers, it is suggested to use spdk_nvme_probe()
+ * and filter the requested controllers with the probe callback. For PCIe controllers,
+ * spdk_nvme_probe() will be more efficient since the controller resets will happen
+ * in parallel.
+ *
+ * To stop using the the controller and release its associated resources, call
+ * spdk_nvme_detach() with the spdk_nvme_ctrlr instance returned by this function.
+ *
+ * \param trid The transport ID indicating which device to connect. If the trtype
+ * is PCIe, this will connect the local PCIe bus. If the trtype is RDMA, the traddr
+ * and trsvcid must point at the location of an NVMe-oF service.
+ * \param opts NVMe controller initialization options. Default values will be used
+ * if the user does not specify the options. The controller may not support all
+ * requested parameters.
+ * \param opts_size Must be set to sizeof(struct spdk_nvme_ctrlr_opts), or 0 if
+ * opts is NULL.
+ *
+ * \return pointer to the connected NVMe controller or NULL if there is any failure.
+ *
+ */
+struct spdk_nvme_ctrlr *spdk_nvme_connect(const struct spdk_nvme_transport_id *trid,
+ const struct spdk_nvme_ctrlr_opts *opts,
+ size_t opts_size);
+
+/**
+ * Detach specified device returned by spdk_nvme_probe()'s attach_cb from the
+ * NVMe driver.
+ *
+ * On success, the spdk_nvme_ctrlr handle is no longer valid.
+ *
+ * This function should be called from a single thread while no other threads
+ * are actively using the NVMe device.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr);
+
+/**
+ * Perform a full hardware reset of the NVMe controller.
+ *
+ * This function should be called from a single thread while no other threads
+ * are actively using the NVMe device.
+ *
+ * Any pointers returned from spdk_nvme_ctrlr_get_ns() and spdk_nvme_ns_get_data()
+ * may be invalidated by calling this function. The number of namespaces as returned
+ * by spdk_nvme_ctrlr_get_num_ns() may also change.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_nvme_ctrlr_reset(struct spdk_nvme_ctrlr *ctrlr);
+
+/**
+ * Get the identify controller data as defined by the NVMe specification.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ *
+ * \return pointer to the identify controller data.
+ */
+const struct spdk_nvme_ctrlr_data *spdk_nvme_ctrlr_get_data(struct spdk_nvme_ctrlr *ctrlr);
+
+/**
+ * Get the NVMe controller CSTS (Status) register.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ *
+ * \return the NVMe controller CSTS (Status) register.
+ */
+union spdk_nvme_csts_register spdk_nvme_ctrlr_get_regs_csts(struct spdk_nvme_ctrlr *ctrlr);
+
+/**
+ * Get the NVMe controller CAP (Capabilities) register.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ *
+ * \return the NVMe controller CAP (Capabilities) register.
+ */
+union spdk_nvme_cap_register spdk_nvme_ctrlr_get_regs_cap(struct spdk_nvme_ctrlr *ctrlr);
+
+/**
+ * Get the NVMe controller VS (Version) register.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ *
+ * \return the NVMe controller VS (Version) register.
+ */
+union spdk_nvme_vs_register spdk_nvme_ctrlr_get_regs_vs(struct spdk_nvme_ctrlr *ctrlr);
+
+/**
+ * Get the number of namespaces for the given NVMe controller.
+ *
+ * This function is thread safe and can be called at any point while the
+ * controller is attached to the SPDK NVMe driver.
+ *
+ * This is equivalent to calling spdk_nvme_ctrlr_get_data() to get the
+ * spdk_nvme_ctrlr_data and then reading the nn field.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ *
+ * \return the number of namespaces.
+ */
+uint32_t spdk_nvme_ctrlr_get_num_ns(struct spdk_nvme_ctrlr *ctrlr);
+
+/**
+ * Get the PCI device of a given NVMe controller.
+ *
+ * This only works for local (PCIe-attached) NVMe controllers; other transports
+ * will return NULL.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ *
+ * \return PCI device of the NVMe controller, or NULL if not available.
+ */
+struct spdk_pci_device *spdk_nvme_ctrlr_get_pci_device(struct spdk_nvme_ctrlr *ctrlr);
+
+/**
+ * Get the maximum data transfer size of a given NVMe controller.
+ *
+ * \return Maximum data transfer size of the NVMe controller in bytes.
+ *
+ * The I/O command helper functions, such as spdk_nvme_ns_cmd_read(), will split
+ * large I/Os automatically; however, it is up to the user to obey this limit for
+ * commands submitted with the raw command functions, such as spdk_nvme_ctrlr_cmd_io_raw().
+ */
+uint32_t spdk_nvme_ctrlr_get_max_xfer_size(const struct spdk_nvme_ctrlr *ctrlr);
+
+/**
+ * Check whether the nsid is an active nv for the given NVMe controller.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ * \param nsid Namespace id.
+ *
+ * \return true if nsid is an active ns, or false otherwise.
+ */
+bool spdk_nvme_ctrlr_is_active_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid);
+
+/**
+ * Get the nsid of the first active namespace.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ *
+ * \return the nsid of the first active namespace, 0 if there are no active namespaces.
+ */
+uint32_t spdk_nvme_ctrlr_get_first_active_ns(struct spdk_nvme_ctrlr *ctrlr);
+
+/**
+ * Get next active namespace given the previous nsid.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ * \param prev_nsid Namespace id.
+ *
+ * \return a next active namespace given the previous nsid, 0 when there are no
+ * more active namespaces.
+ */
+uint32_t spdk_nvme_ctrlr_get_next_active_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t prev_nsid);
+
+/**
+ * Determine if a particular log page is supported by the given NVMe controller.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \sa spdk_nvme_ctrlr_cmd_get_log_page().
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ * \param log_page Log page to query.
+ *
+ * \return true if supported, or false otherwise.
+ */
+bool spdk_nvme_ctrlr_is_log_page_supported(struct spdk_nvme_ctrlr *ctrlr, uint8_t log_page);
+
+/**
+ * Determine if a particular feature is supported by the given NVMe controller.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \sa spdk_nvme_ctrlr_cmd_get_feature().
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ * \param feature_code Feature to query.
+ *
+ * \return true if supported, or false otherwise.
+ */
+bool spdk_nvme_ctrlr_is_feature_supported(struct spdk_nvme_ctrlr *ctrlr, uint8_t feature_code);
+
+/**
+ * Signature for callback function invoked when a command is completed.
+ *
+ * \param spdk_nvme_cpl Completion queue entry that coontains the completion status.
+ */
+typedef void (*spdk_nvme_cmd_cb)(void *, const struct spdk_nvme_cpl *);
+
+/**
+ * Signature for callback function invoked when an asynchronous error request
+ * command is completed.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ * \param aer_cb_arg Context specified by spdk_nvme_register_aer_callback().
+ * \param spdk_nvme_cpl Completion queue entry that contains the completion status
+ * of the asynchronous event request that was completed.
+ */
+typedef void (*spdk_nvme_aer_cb)(void *aer_cb_arg,
+ const struct spdk_nvme_cpl *);
+
+/**
+ * Register callback function invoked when an AER command is completed for the
+ * given NVMe controller.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ * \param aer_cb_fn Callback function invoked when an asynchronous error request
+ * command is completed.
+ * \param aer_cb_arg Argument passed to callback function.
+ */
+void spdk_nvme_ctrlr_register_aer_callback(struct spdk_nvme_ctrlr *ctrlr,
+ spdk_nvme_aer_cb aer_cb_fn,
+ void *aer_cb_arg);
+
+/**
+ * Opaque handle to a queue pair.
+ *
+ * I/O queue pairs may be allocated using spdk_nvme_ctrlr_alloc_io_qpair().
+ */
+struct spdk_nvme_qpair;
+
+/**
+ * Signature for the callback function invoked when a timeout is detected on a
+ * request.
+ *
+ * For timeouts detected on the admin queue pair, the qpair returned here will
+ * be NULL. If the controller has a serious error condition and is unable to
+ * communicate with driver via completion queue, the controller can set Controller
+ * Fatal Status field to 1, then reset is required to recover from such error.
+ * Users may detect Controller Fatal Status when timeout happens.
+ *
+ * \param cb_arg Argument passed to callback funciton.
+ * \param ctrlr Opaque handle to NVMe controller.
+ * \param qpair Opaque handle to a queue pair.
+ * \param cid Command ID.
+ */
+typedef void (*spdk_nvme_timeout_cb)(void *cb_arg,
+ struct spdk_nvme_ctrlr *ctrlr,
+ struct spdk_nvme_qpair *qpair,
+ uint16_t cid);
+
+/**
+ * Register for timeout callback on a controller.
+ *
+ * The application can choose to register for timeout callback or not register
+ * for timeout callback.
+ *
+ * \param ctrlr NVMe controller on which to monitor for timeout.
+ * \param timeout_us Timeout value in microseconds.
+ * \param cb_fn A function pointer that points to the callback function.
+ * \param cb_arg Argument to the callback function.
+ */
+void spdk_nvme_ctrlr_register_timeout_callback(struct spdk_nvme_ctrlr *ctrlr,
+ uint64_t timeout_us, spdk_nvme_timeout_cb cb_fn, void *cb_arg);
+
+/**
+ * NVMe I/O queue pair initialization options.
+ *
+ * These options may be passed to spdk_nvme_ctrlr_alloc_io_qpair() to configure queue pair
+ * options at queue creation time.
+ *
+ * The user may retrieve the default I/O queue pair creation options for a controller using
+ * spdk_nvme_ctrlr_get_default_io_qpair_opts().
+ */
+struct spdk_nvme_io_qpair_opts {
+ /**
+ * Queue priority for weighted round robin arbitration. If a different arbitration
+ * method is in use, pass 0.
+ */
+ enum spdk_nvme_qprio qprio;
+
+ /**
+ * The queue depth of this NVMe I/O queue. Overrides spdk_nvme_ctrlr_opts::io_queue_size.
+ */
+ uint32_t io_queue_size;
+
+ /**
+ * The number of requests to allocate for this NVMe I/O queue.
+ *
+ * Overrides spdk_nvme_ctrlr_opts::io_queue_requests.
+ *
+ * This should be at least as large as io_queue_size.
+ *
+ * A single I/O may allocate more than one request, since splitting may be
+ * necessary to conform to the device's maximum transfer size, PRP list
+ * compatibility requirements, or driver-assisted striping.
+ */
+ uint32_t io_queue_requests;
+};
+
+/**
+ * Get the default options for I/O qpair creation for a specific NVMe controller.
+ *
+ * \param ctrlr NVMe controller to retrieve the defaults from.
+ * \param[out] opts Will be filled with the default options for
+ * spdk_nvme_ctrlr_alloc_io_qpair().
+ * \param opts_size Must be set to sizeof(struct spdk_nvme_io_qpair_opts).
+ */
+void spdk_nvme_ctrlr_get_default_io_qpair_opts(struct spdk_nvme_ctrlr *ctrlr,
+ struct spdk_nvme_io_qpair_opts *opts,
+ size_t opts_size);
+
+/**
+ * Allocate an I/O queue pair (submission and completion queue).
+ *
+ * Each queue pair should only be used from a single thread at a time (mutual
+ * exclusion must be enforced by the user).
+ *
+ * \param ctrlr NVMe controller for which to allocate the I/O queue pair.
+ * \param opts I/O qpair creation options, or NULL to use the defaults as returned
+ * by spdk_nvme_ctrlr_alloc_io_qpair().
+ * \param opts_size Must be set to sizeof(struct spdk_nvme_io_qpair_opts), or 0
+ * if opts is NULL.
+ *
+ * \return a pointer to the allocated I/O queue pair.
+ */
+struct spdk_nvme_qpair *spdk_nvme_ctrlr_alloc_io_qpair(struct spdk_nvme_ctrlr *ctrlr,
+ const struct spdk_nvme_io_qpair_opts *opts,
+ size_t opts_size);
+
+/**
+ * Free an I/O queue pair that was allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ *
+ * \param qpair I/O queue pair to free.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_nvme_ctrlr_free_io_qpair(struct spdk_nvme_qpair *qpair);
+
+/**
+ * Send the given NVM I/O command to the NVMe controller.
+ *
+ * This is a low level interface for submitting I/O commands directly. Prefer
+ * the spdk_nvme_ns_cmd_* functions instead. The validity of the command will
+ * not be checked!
+ *
+ * When constructing the nvme_command it is not necessary to fill out the PRP
+ * list/SGL or the CID. The driver will handle both of those for you.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ * \param qpair I/O qpair to submit command.
+ * \param cmd NVM I/O command to submit.
+ * \param buf Virtual memory address of a single physically contiguous buffer.
+ * \param len Size of buffer.
+ * \param cb_fn Callback function invoked when the I/O command completes.
+ * \param cb_arg Argument passed to callback function.
+ *
+ * \return 0 on success, negated errno on failure.
+ */
+int spdk_nvme_ctrlr_cmd_io_raw(struct spdk_nvme_ctrlr *ctrlr,
+ struct spdk_nvme_qpair *qpair,
+ struct spdk_nvme_cmd *cmd,
+ void *buf, uint32_t len,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * Send the given NVM I/O command with metadata to the NVMe controller.
+ *
+ * This is a low level interface for submitting I/O commands directly. Prefer
+ * the spdk_nvme_ns_cmd_* functions instead. The validity of the command will
+ * not be checked!
+ *
+ * When constructing the nvme_command it is not necessary to fill out the PRP
+ * list/SGL or the CID. The driver will handle both of those for you.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ * \param qpair I/O qpair to submit command.
+ * \param cmd NVM I/O command to submit.
+ * \param buf Virtual memory address of a single physically contiguous buffer.
+ * \param len Size of buffer.
+ * \param md_buf Virtual memory address of a single physically contiguous metadata
+ * buffer.
+ * \param cb_fn Callback function invoked when the I/O command completes.
+ * \param cb_arg Argument passed to callback function.
+ *
+ * \return 0 on success, negated errno on failure.
+ */
+int spdk_nvme_ctrlr_cmd_io_raw_with_md(struct spdk_nvme_ctrlr *ctrlr,
+ struct spdk_nvme_qpair *qpair,
+ struct spdk_nvme_cmd *cmd,
+ void *buf, uint32_t len, void *md_buf,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * Process any outstanding completions for I/O submitted on a queue pair.
+ *
+ * This call is non-blocking, i.e. it only processes completions that are ready
+ * at the time of this function call. It does not wait for outstanding commands
+ * to finish.
+ *
+ * For each completed command, the request's callback function will be called if
+ * specified as non-NULL when the request was submitted.
+ *
+ * The caller must ensure that each queue pair is only used from one thread at a
+ * time.
+ *
+ * This function may be called at any point while the controller is attached to
+ * the SPDK NVMe driver.
+ *
+ * \sa spdk_nvme_cmd_cb
+ *
+ * \param qpair Queue pair to check for completions.
+ * \param max_completions Limit the number of completions to be processed in one
+ * call, or 0 for unlimited.
+ *
+ * \return number of completions processed (may be 0) or negated on error.
+ */
+int32_t spdk_nvme_qpair_process_completions(struct spdk_nvme_qpair *qpair,
+ uint32_t max_completions);
+
+/**
+ * Send the given admin command to the NVMe controller.
+ *
+ * This is a low level interface for submitting admin commands directly. Prefer
+ * the spdk_nvme_ctrlr_cmd_* functions instead. The validity of the command will
+ * not be checked!
+ *
+ * When constructing the nvme_command it is not necessary to fill out the PRP
+ * list/SGL or the CID. The driver will handle both of those for you.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * Call spdk_nvme_ctrlr_process_admin_completions() to poll for completion
+ * of commands submitted through this function.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ * \param cmd NVM admin command to submit.
+ * \param buf Virtual memory address of a single physically contiguous buffer.
+ * \param len Size of buffer.
+ * \param cb_fn Callback function invoked when the admin command completes.
+ * \param cb_arg Argument passed to callback function.
+ *
+ * \return 0 on success, negated errno on failure.
+ */
+int spdk_nvme_ctrlr_cmd_admin_raw(struct spdk_nvme_ctrlr *ctrlr,
+ struct spdk_nvme_cmd *cmd,
+ void *buf, uint32_t len,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * Process any outstanding completions for admin commands.
+ *
+ * This will process completions for admin commands submitted on any thread.
+ *
+ * This call is non-blocking, i.e. it only processes completions that are ready
+ * at the time of this function call. It does not wait for outstanding commands
+ * to finish.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ *
+ * \return number of completions processed (may be 0) or negated on error.
+ */
+int32_t spdk_nvme_ctrlr_process_admin_completions(struct spdk_nvme_ctrlr *ctrlr);
+
+
+/**
+ * Opaque handle to a namespace. Obtained by calling spdk_nvme_ctrlr_get_ns().
+ */
+struct spdk_nvme_ns;
+
+/**
+ * Get a handle to a namespace for the given controller.
+ *
+ * Namespaces are numbered from 1 to the total number of namespaces. There will
+ * never be any gaps in the numbering. The number of namespaces is obtained by
+ * calling spdk_nvme_ctrlr_get_num_ns().
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ * \param ns_id Namespace id.
+ *
+ * \return a pointer to the namespace.
+ */
+struct spdk_nvme_ns *spdk_nvme_ctrlr_get_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t ns_id);
+
+/**
+ * Get a specific log page from the NVMe controller.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * Call spdk_nvme_ctrlr_process_admin_completions() to poll for completion of
+ * commands submitted through this function.
+ *
+ * \sa spdk_nvme_ctrlr_is_log_page_supported()
+ *
+ * \param ctrlr Opaque handle to NVMe controller.
+ * \param log_page The log page identifier.
+ * \param nsid Depending on the log page, this may be 0, a namespace identifier,
+ * or SPDK_NVME_GLOBAL_NS_TAG.
+ * \param payload The pointer to the payload buffer.
+ * \param payload_size The size of payload buffer.
+ * \param offset Offset in bytes within the log page to start retrieving log page
+ * data. May only be non-zero if the controller supports extended data for Get Log
+ * Page as reported in the controller data log page attributes.
+ * \param cb_fn Callback function to invoke when the log page has been retrieved.
+ * \param cb_arg Argument to pass to the callback function.
+ *
+ * \return 0 if successfully submitted, negated errno if resources could not be
+ * allocated for this request.
+ */
+int spdk_nvme_ctrlr_cmd_get_log_page(struct spdk_nvme_ctrlr *ctrlr,
+ uint8_t log_page, uint32_t nsid,
+ void *payload, uint32_t payload_size,
+ uint64_t offset,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * Abort a specific previously-submitted NVMe command.
+ *
+ * \sa spdk_nvme_ctrlr_register_timeout_callback()
+ *
+ * \param ctrlr NVMe controller to which the command was submitted.
+ * \param qpair NVMe queue pair to which the command was submitted. For admin
+ * commands, pass NULL for the qpair.
+ * \param cid Command ID of the command to abort.
+ * \param cb_fn Callback function to invoke when the abort has completed.
+ * \param cb_arg Argument to pass to the callback function.
+ *
+ * \return 0 if successfully submitted, negated errno value otherwise.
+ */
+int spdk_nvme_ctrlr_cmd_abort(struct spdk_nvme_ctrlr *ctrlr,
+ struct spdk_nvme_qpair *qpair,
+ uint16_t cid,
+ spdk_nvme_cmd_cb cb_fn,
+ void *cb_arg);
+
+/**
+ * Set specific feature for the given NVMe controller.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * Call spdk_nvme_ctrlr_process_admin_completions() to poll for completion of
+ * commands submitted through this function.
+ *
+ * \sa spdk_nvme_ctrlr_cmd_get_feature().
+ *
+ * \param ctrlr NVMe controller to manipulate.
+ * \param feature The feature identifier.
+ * \param cdw11 as defined by the specification for this command.
+ * \param cdw12 as defined by the specification for this command.
+ * \param payload The pointer to the payload buffer.
+ * \param payload_size The size of payload buffer.
+ * \param cb_fn Callback function to invoke when the feature has been set.
+ * \param cb_arg Argument to pass to the callback function.
+ *
+ * \return 0 if successfully submitted, negated errno if resources could not be
+ * allocated for this request.
+ */
+int spdk_nvme_ctrlr_cmd_set_feature(struct spdk_nvme_ctrlr *ctrlr,
+ uint8_t feature, uint32_t cdw11, uint32_t cdw12,
+ void *payload, uint32_t payload_size,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * Get specific feature from given NVMe controller.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * Call spdk_nvme_ctrlr_process_admin_completions() to poll for completion of
+ * commands submitted through this function.
+ *
+ * \sa spdk_nvme_ctrlr_cmd_set_feature()
+ *
+ * \param ctrlr NVMe controller to query.
+ * \param feature The feature identifier.
+ * \param cdw11 as defined by the specification for this command.
+ * \param payload The pointer to the payload buffer.
+ * \param payload_size The size of payload buffer.
+ * \param cb_fn Callback function to invoke when the feature has been retrieved.
+ * \param cb_arg Argument to pass to the callback function.
+ *
+ * \return 0 if successfully submitted, ENOMEM if resources could not be allocated
+ * for this request.
+ */
+int spdk_nvme_ctrlr_cmd_get_feature(struct spdk_nvme_ctrlr *ctrlr,
+ uint8_t feature, uint32_t cdw11,
+ void *payload, uint32_t payload_size,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * Get specific feature from given NVMe controller.
+ *
+ * \param ctrlr NVMe controller to query.
+ * \param feature The feature identifier.
+ * \param cdw11 as defined by the specification for this command.
+ * \param payload The pointer to the payload buffer.
+ * \param payload_size The size of payload buffer.
+ * \param cb_fn Callback function to invoke when the feature has been retrieved.
+ * \param cb_arg Argument to pass to the callback function.
+ * \param ns_id The namespace identifier.
+ *
+ * \return 0 if successfully submitted, ENOMEM if resources could not be allocated
+ * for this request
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * Call \ref spdk_nvme_ctrlr_process_admin_completions() to poll for completion
+ * of commands submitted through this function.
+ *
+ * \sa spdk_nvme_ctrlr_cmd_set_feature_ns()
+ */
+int spdk_nvme_ctrlr_cmd_get_feature_ns(struct spdk_nvme_ctrlr *ctrlr, uint8_t feature,
+ uint32_t cdw11, void *payload, uint32_t payload_size,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t ns_id);
+
+/**
+ * Set specific feature for the given NVMe controller and namespace ID.
+ *
+ * \param ctrlr NVMe controller to manipulate.
+ * \param feature The feature identifier.
+ * \param cdw11 as defined by the specification for this command.
+ * \param cdw12 as defined by the specification for this command.
+ * \param payload The pointer to the payload buffer.
+ * \param payload_size The size of payload buffer.
+ * \param cb_fn Callback function to invoke when the feature has been set.
+ * \param cb_arg Argument to pass to the callback function.
+ * \param ns_id The namespace identifier.
+ *
+ * \return 0 if successfully submitted, ENOMEM if resources could not be allocated
+ * for this request.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * Call \ref spdk_nvme_ctrlr_process_admin_completions() to poll for completion
+ * of commands submitted through this function.
+ *
+ * \sa spdk_nvme_ctrlr_cmd_get_feature_ns()
+ */
+int spdk_nvme_ctrlr_cmd_set_feature_ns(struct spdk_nvme_ctrlr *ctrlr, uint8_t feature,
+ uint32_t cdw11, uint32_t cdw12, void *payload,
+ uint32_t payload_size, spdk_nvme_cmd_cb cb_fn,
+ void *cb_arg, uint32_t ns_id);
+
+/**
+ * Receive security protocol data from controller.
+ *
+ * This function is thread safe and can be called at any point after spdk_nvme_probe().
+ *
+ * Call spdk_nvme_ctrlr_process_admin_completions() to poll for completion of
+ * commands submitted through this function.
+ *
+ * \param ctrlr NVMe controller to use for security receive command submission.
+ * \param secp Security Protocol that is used.
+ * \param spsp Security Protocol Specific field.
+ * \param nssf NVMe Security Specific field. Indicate RPMB target when using Security
+ * Protocol EAh.
+ * \param payload The pointer to the payload buffer.
+ * \param payload_size The size of payload buffer.
+ * \param cb_fn Callback function to invoke when the security receive has completed.
+ * \param cb_arg Argument to pass to the callback function.
+ *
+ * \return 0 if successfully submitted, negated errno if resources could not be allocated
+ * for this request.
+ */
+int spdk_nvme_ctrlr_cmd_security_receive(struct spdk_nvme_ctrlr *ctrlr, uint8_t secp, uint16_t spsp,
+ uint8_t nssf, void *payload, uint32_t payload_size,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * Send security protocol data to controller.
+ *
+ * This function is thread safe and can be called at any point after spdk_nvme_probe().
+ *
+ * Call spdk_nvme_ctrlr_process_admin_completions() to poll for completion of
+ * commands submitted through this function.
+ *
+ * \param ctrlr NVMe controller to use for security send command submission.
+ * \param secp Security Protocol that is used.
+ * \param spsp Security Protocol Specific field.
+ * \param nssf NVMe Security Specific field. Indicate RPMB target when using Security
+ * Protocol EAh.
+ * \param payload The pointer to the payload buffer.
+ * \param payload_size The size of payload buffer.
+ * \param cb_fn Callback function to invoke when the security send has completed.
+ * \param cb_arg Argument to pass to the callback function.
+ *
+ * \return 0 if successfully submitted, negated errno if resources could not be allocated
+ * for this request.
+ */
+int spdk_nvme_ctrlr_cmd_security_send(struct spdk_nvme_ctrlr *ctrlr, uint8_t secp, uint16_t spsp,
+ uint8_t nssf, void *payload, uint32_t payload_size,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * Attach the specified namespace to controllers.
+ *
+ * This function is thread safe and can be called at any point after spdk_nvme_probe().
+ *
+ * Call spdk_nvme_ctrlr_process_admin_completions() to poll for completion of
+ * commands submitted through this function.
+ *
+ * \param ctrlr NVMe controller to use for command submission.
+ * \param nsid Namespace identifier for namespace to attach.
+ * \param payload The pointer to the controller list.
+ *
+ * \return 0 if successfully submitted, ENOMEM if resources could not be allocated
+ * for this request.
+ */
+int spdk_nvme_ctrlr_attach_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid,
+ struct spdk_nvme_ctrlr_list *payload);
+
+/**
+ * Detach the specified namespace from controllers.
+ *
+ * This function is thread safe and can be called at any point after spdk_nvme_probe().
+ *
+ * Call spdk_nvme_ctrlr_process_admin_completions() to poll for completion of
+ * commands submitted through this function.
+ *
+ * \param ctrlr NVMe controller to use for command submission.
+ * \param nsid Namespace ID to detach.
+ * \param payload The pointer to the controller list.
+ *
+ * \return 0 if successfully submitted, ENOMEM if resources could not be allocated
+ * for this request
+ */
+int spdk_nvme_ctrlr_detach_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid,
+ struct spdk_nvme_ctrlr_list *payload);
+
+/**
+ * Create a namespace.
+ *
+ * This function is thread safe and can be called at any point after spdk_nvme_probe().
+ *
+ * \param ctrlr NVMe controller to create namespace on.
+ * \param payload The pointer to the NVMe namespace data.
+ *
+ * \return Namespace ID (>= 1) if successfully created, or 0 if the request failed.
+ */
+uint32_t spdk_nvme_ctrlr_create_ns(struct spdk_nvme_ctrlr *ctrlr,
+ struct spdk_nvme_ns_data *payload);
+
+/**
+ * Delete a namespace.
+ *
+ * This function is thread safe and can be called at any point after spdk_nvme_probe().
+ *
+ * Call spdk_nvme_ctrlr_process_admin_completions() to poll for completion of
+ * commands submitted through this function.
+ *
+ * \param ctrlr NVMe controller to delete namespace from.
+ * \param nsid The namespace identifier.
+ *
+ * \return 0 if successfully submitted, negated errno if resources could not be
+ * allocated
+ * for this request
+ */
+int spdk_nvme_ctrlr_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid);
+
+/**
+ * Format NVM.
+ *
+ * This function requests a low-level format of the media.
+ *
+ * This function is thread safe and can be called at any point after spdk_nvme_probe().
+ *
+ * \param ctrlr NVMe controller to format.
+ * \param nsid The namespace identifier. May be SPDK_NVME_GLOBAL_NS_TAG to format
+ * all namespaces.
+ * \param format The format information for the command.
+ *
+ * \return 0 if successfully submitted, negated errno if resources could not be
+ * allocated for this request
+ */
+int spdk_nvme_ctrlr_format(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid,
+ struct spdk_nvme_format *format);
+
+/**
+ * Download a new firmware image.
+ *
+ * This function is thread safe and can be called at any point after spdk_nvme_probe().
+ *
+ * \param ctrlr NVMe controller to perform firmware operation on.
+ * \param payload The data buffer for the firmware image.
+ * \param size The data size will be downloaded.
+ * \param slot The slot that the firmware image will be committed to.
+ * \param commit_action The action to perform when firmware is committed.
+ * \param completion_status output parameter. Contains the completion status of
+ * the firmware commit operation.
+ *
+ * \return 0 if successfully submitted, ENOMEM if resources could not be allocated
+ * for this request, -1 if the size is not multiple of 4.
+ */
+int spdk_nvme_ctrlr_update_firmware(struct spdk_nvme_ctrlr *ctrlr, void *payload, uint32_t size,
+ int slot, enum spdk_nvme_fw_commit_action commit_action,
+ struct spdk_nvme_status *completion_status);
+
+/**
+ * Allocate an I/O buffer from the controller memory buffer (Experimental).
+ *
+ * This function allocates registered memory which belongs to the Controller
+ * Memory Buffer (CMB) of the specified NVMe controller. Note that the CMB has
+ * to support the WDS and RDS capabilities for the allocation to be successful.
+ * Also, due to vtophys contraints the CMB must be at least 4MiB in size. Free
+ * memory allocated with this function using spdk_nvme_ctrlr_free_cmb_io_buffer().
+ *
+ * \param ctrlr Controller from which to allocate memory buffer.
+ * \param size Size of buffer to allocate in bytes.
+ *
+ * \return Pointer to controller memory buffer allocation, or NULL if allocation
+ * was not possible.
+ */
+void *spdk_nvme_ctrlr_alloc_cmb_io_buffer(struct spdk_nvme_ctrlr *ctrlr, size_t size);
+
+/**
+ * Free a controller memory I/O buffer (Experimental).
+ *
+ * Note this function is currently a NOP which is one reason why this and
+ * spdk_nvme_ctrlr_alloc_cmb_io_buffer() are currently marked as experimental.
+ *
+ * \param ctrlr Controller from which the buffer was allocated.
+ * \param buf Buffer previously allocated by spdk_nvme_ctrlr_alloc_cmb_io_buffer().
+ * \param size Size of buf in bytes.
+ */
+void spdk_nvme_ctrlr_free_cmb_io_buffer(struct spdk_nvme_ctrlr *ctrlr, void *buf, size_t size);
+
+/**
+ * Get the identify namespace data as defined by the NVMe specification.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ns Namespace.
+ *
+ * \return a pointer to the namespace data.
+ */
+const struct spdk_nvme_ns_data *spdk_nvme_ns_get_data(struct spdk_nvme_ns *ns);
+
+/**
+ * Get the namespace id (index number) from the given namespace handle.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ns Namespace.
+ *
+ * \return namespace id.
+ */
+uint32_t spdk_nvme_ns_get_id(struct spdk_nvme_ns *ns);
+
+/**
+ * Get the controller with which this namespace is associated.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ns Namespace.
+ *
+ * \return a pointer to the controller.
+ */
+struct spdk_nvme_ctrlr *spdk_nvme_ns_get_ctrlr(struct spdk_nvme_ns *ns);
+
+/**
+ * Determine whether a namespace is active.
+ *
+ * Inactive namespaces cannot be the target of I/O commands.
+ *
+ * \param ns Namespace to query.
+ *
+ * \return true if active, or false if inactive.
+ */
+bool spdk_nvme_ns_is_active(struct spdk_nvme_ns *ns);
+
+/**
+ * Get the maximum transfer size, in bytes, for an I/O sent to the given namespace.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ns Namespace to query.
+ *
+ * \return the maximum transfer size in bytes.
+ */
+uint32_t spdk_nvme_ns_get_max_io_xfer_size(struct spdk_nvme_ns *ns);
+
+/**
+ * Get the sector size, in bytes, of the given namespace.
+ *
+ * This function returns the size of the data sector only. It does not
+ * include metadata size.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ns Namespace to query.
+ *
+ * /return the sector size in bytes.
+ */
+uint32_t spdk_nvme_ns_get_sector_size(struct spdk_nvme_ns *ns);
+
+/**
+ * Get the extended sector size, in bytes, of the given namespace.
+ *
+ * This function returns the size of the data sector plus metadata.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ns Namespace to query.
+ *
+ * /return the extended sector size in bytes.
+ */
+uint32_t spdk_nvme_ns_get_extended_sector_size(struct spdk_nvme_ns *ns);
+
+/**
+ * Get the number of sectors for the given namespace.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ns Namespace to query.
+ *
+ * \return the number of sectors.
+ */
+uint64_t spdk_nvme_ns_get_num_sectors(struct spdk_nvme_ns *ns);
+
+/**
+ * Get the size, in bytes, of the given namespace.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ns Namespace to query.
+ *
+ * \return the size of the given namespace in bytes.
+ */
+uint64_t spdk_nvme_ns_get_size(struct spdk_nvme_ns *ns);
+
+/**
+ * Get the end-to-end data protection information type of the given namespace.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ns Namespace to query.
+ *
+ * \return the end-to-end data protection information type.
+ */
+enum spdk_nvme_pi_type spdk_nvme_ns_get_pi_type(struct spdk_nvme_ns *ns);
+
+/**
+ * Get the metadata size, in bytes, of the given namespace.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ns Namespace to query.
+ *
+ * \return the metadata size of the given namespace in bytes.
+ */
+uint32_t spdk_nvme_ns_get_md_size(struct spdk_nvme_ns *ns);
+
+/**
+ * Check whether if the namespace can support extended LBA when end-to-end data
+ * protection enabled.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ns Namespace to query.
+ *
+ * \return true if the namespace can support extended LBA when end-to-end data
+ * protection enabled, or false otherwise.
+ */
+bool spdk_nvme_ns_supports_extended_lba(struct spdk_nvme_ns *ns);
+
+/**
+ * Determine the value returned when reading deallocated blocks.
+ *
+ * If deallocated blocks return 0, the deallocate command can be used as a more
+ * efficient alternative to the write_zeroes command, especially for large requests.
+ *
+ * \param ns Namespace.
+ *
+ * \return the logical block read value.
+ */
+enum spdk_nvme_dealloc_logical_block_read_value spdk_nvme_ns_get_dealloc_logical_block_read_value(
+ struct spdk_nvme_ns *ns);
+
+/**
+ * Get the optimal I/O boundary, in blocks, for the given namespace.
+ *
+ * Read and write commands should not cross the optimal I/O boundary for best
+ * performance.
+ *
+ * \param ns Namespace to query.
+ *
+ * \return Optimal granularity of I/O commands, in blocks, or 0 if no optimal
+ * granularity is reported.
+ */
+uint32_t spdk_nvme_ns_get_optimal_io_boundary(struct spdk_nvme_ns *ns);
+
+/**
+ * Get the UUID for the given namespace.
+ *
+ * \param ns Namespace to query.
+ *
+ * \return a pointer to namespace UUID, or NULL if ns does not have a UUID.
+ */
+const struct spdk_uuid *spdk_nvme_ns_get_uuid(const struct spdk_nvme_ns *ns);
+
+/**
+ * \brief Namespace command support flags.
+ */
+enum spdk_nvme_ns_flags {
+ SPDK_NVME_NS_DEALLOCATE_SUPPORTED = 0x1, /**< The deallocate command is supported */
+ SPDK_NVME_NS_FLUSH_SUPPORTED = 0x2, /**< The flush command is supported */
+ SPDK_NVME_NS_RESERVATION_SUPPORTED = 0x4, /**< The reservation command is supported */
+ SPDK_NVME_NS_WRITE_ZEROES_SUPPORTED = 0x8, /**< The write zeroes command is supported */
+ SPDK_NVME_NS_DPS_PI_SUPPORTED = 0x10, /**< The end-to-end data protection is supported */
+ SPDK_NVME_NS_EXTENDED_LBA_SUPPORTED = 0x20, /**< The extended lba format is supported,
+ metadata is transferred as a contiguous
+ part of the logical block that it is associated with */
+};
+
+/**
+ * Get the flags for the given namespace.
+ *
+ * See spdk_nvme_ns_flags for the possible flags returned.
+ *
+ * This function is thread safe and can be called at any point while the controller
+ * is attached to the SPDK NVMe driver.
+ *
+ * \param ns Namespace to query.
+ *
+ * \return the flags for the given namespace.
+ */
+uint32_t spdk_nvme_ns_get_flags(struct spdk_nvme_ns *ns);
+
+/**
+ * Restart the SGL walk to the specified offset when the command has scattered payloads.
+ *
+ * \param cb_arg Argument passed to readv/writev.
+ * \param offset Offset for SGL.
+ */
+typedef void (*spdk_nvme_req_reset_sgl_cb)(void *cb_arg, uint32_t offset);
+
+/**
+ * Fill out *address and *length with the current SGL entry and advance to the next
+ * entry for the next time the callback is invoked.
+ *
+ * The described segment must be physically contiguous.
+ *
+ * \param cb_arg Argument passed to readv/writev.
+ * \param address Virtual address of this segment.
+ * \param length Length of this physical segment.
+ */
+typedef int (*spdk_nvme_req_next_sge_cb)(void *cb_arg, void **address, uint32_t *length);
+
+/**
+ * Submit a write I/O to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the write I/O.
+ * \param qpair I/O queue pair to submit the request.
+ * \param payload Virtual address pointer to the data payload.
+ * \param lba Starting LBA to write the data.
+ * \param lba_count Length (in sectors) for the write operation.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ * \param io_flags Set flags, defined by the SPDK_NVME_IO_FLAGS_* entries in
+ * spdk/nvme_spec.h, for this I/O.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request
+ */
+int spdk_nvme_ns_cmd_write(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, void *payload,
+ uint64_t lba, uint32_t lba_count, spdk_nvme_cmd_cb cb_fn,
+ void *cb_arg, uint32_t io_flags);
+
+/**
+ * Submit a write I/O to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the write I/O.
+ * \param qpair I/O queue pair to submit the request.
+ * \param lba Starting LBA to write the data.
+ * \param lba_count Length (in sectors) for the write operation.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ * \param io_flags Set flags, defined in nvme_spec.h, for this I/O.
+ * \param reset_sgl_fn Callback function to reset scattered payload.
+ * \param next_sge_fn Callback function to iterate each scattered payload memory
+ * segment.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_writev(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
+ uint64_t lba, uint32_t lba_count,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
+ spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
+ spdk_nvme_req_next_sge_cb next_sge_fn);
+
+/**
+ * Submit a write I/O to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the write I/O
+ * \param qpair I/O queue pair to submit the request
+ * \param lba starting LBA to write the data
+ * \param lba_count length (in sectors) for the write operation
+ * \param cb_fn callback function to invoke when the I/O is completed
+ * \param cb_arg argument to pass to the callback function
+ * \param io_flags set flags, defined in nvme_spec.h, for this I/O
+ * \param reset_sgl_fn callback function to reset scattered payload
+ * \param next_sge_fn callback function to iterate each scattered
+ * payload memory segment
+ * \param metadata virtual address pointer to the metadata payload, the length
+ * of metadata is specified by spdk_nvme_ns_get_md_size()
+ * \param apptag_mask application tag mask.
+ * \param apptag application tag to use end-to-end protection information.
+ *
+ * \return 0 if successfully submitted, ENOMEM if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_writev_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
+ uint64_t lba, uint32_t lba_count,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
+ spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
+ spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata,
+ uint16_t apptag_mask, uint16_t apptag);
+
+/**
+ * Submit a write I/O to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the write I/O.
+ * \param qpair I/O queue pair to submit the request.
+ * \param payload Virtual address pointer to the data payload.
+ * \param metadata Virtual address pointer to the metadata payload, the length
+ * of metadata is specified by spdk_nvme_ns_get_md_size().
+ * \param lba Starting LBA to write the data.
+ * \param lba_count Length (in sectors) for the write operation.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ * \param io_flags Set flags, defined by the SPDK_NVME_IO_FLAGS_* entries in
+ * spdk/nvme_spec.h, for this I/O.
+ * \param apptag_mask Application tag mask.
+ * \param apptag Application tag to use end-to-end protection information.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_write_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
+ void *payload, void *metadata,
+ uint64_t lba, uint32_t lba_count, spdk_nvme_cmd_cb cb_fn,
+ void *cb_arg, uint32_t io_flags,
+ uint16_t apptag_mask, uint16_t apptag);
+
+/**
+ * Submit a write zeroes I/O to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the write zeroes I/O.
+ * \param qpair I/O queue pair to submit the request.
+ * \param lba Starting LBA for this command.
+ * \param lba_count Length (in sectors) for the write zero operation.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ * \param io_flags Set flags, defined by the SPDK_NVME_IO_FLAGS_* entries in
+ * spdk/nvme_spec.h, for this I/O.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_write_zeroes(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
+ uint64_t lba, uint32_t lba_count,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg,
+ uint32_t io_flags);
+
+/**
+ * \brief Submits a read I/O to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the read I/O.
+ * \param qpair I/O queue pair to submit the request.
+ * \param payload Virtual address pointer to the data payload.
+ * \param lba Starting LBA to read the data.
+ * \param lba_count Length (in sectors) for the read operation.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ * \param io_flags Set flags, defined in nvme_spec.h, for this I/O.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_read(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, void *payload,
+ uint64_t lba, uint32_t lba_count, spdk_nvme_cmd_cb cb_fn,
+ void *cb_arg, uint32_t io_flags);
+
+/**
+ * Submit a read I/O to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the read I/O.
+ * \param qpair I/O queue pair to submit the request.
+ * \param lba Starting LBA to read the data.
+ * \param lba_count Length (in sectors) for the read operation.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ * \param io_flags Set flags, defined in nvme_spec.h, for this I/O.
+ * \param reset_sgl_fn Callback function to reset scattered payload.
+ * \param next_sge_fn Callback function to iterate each scattered payload memory
+ * segment.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_readv(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
+ uint64_t lba, uint32_t lba_count,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
+ spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
+ spdk_nvme_req_next_sge_cb next_sge_fn);
+
+/**
+ * Submit a read I/O to the specified NVMe namespace.
+ *
+ * \param ns NVMe namespace to submit the read I/O
+ * \param qpair I/O queue pair to submit the request
+ * \param lba starting LBA to read the data
+ * \param lba_count length (in sectors) for the read operation
+ * \param cb_fn callback function to invoke when the I/O is completed
+ * \param cb_arg argument to pass to the callback function
+ * \param io_flags set flags, defined in nvme_spec.h, for this I/O
+ * \param reset_sgl_fn callback function to reset scattered payload
+ * \param next_sge_fn callback function to iterate each scattered
+ * payload memory segment
+ * \param metadata virtual address pointer to the metadata payload, the length
+ * of metadata is specified by spdk_nvme_ns_get_md_size()
+ * \param apptag_mask application tag mask.
+ * \param apptag application tag to use end-to-end protection information.
+ *
+ * \return 0 if successfully submitted, ENOMEM if an nvme_request
+ * structure cannot be allocated for the I/O request
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any given time.
+ */
+int spdk_nvme_ns_cmd_readv_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
+ uint64_t lba, uint32_t lba_count,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
+ spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
+ spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata,
+ uint16_t apptag_mask, uint16_t apptag);
+
+/**
+ * Submits a read I/O to the specified NVMe namespace.
+ *
+ * \param ns NVMe namespace to submit the read I/O
+ * \param qpair I/O queue pair to submit the request
+ * \param payload virtual address pointer to the data payload
+ * \param metadata virtual address pointer to the metadata payload, the length
+ * of metadata is specified by spdk_nvme_ns_get_md_size().
+ * \param lba starting LBA to read the data.
+ * \param lba_count Length (in sectors) for the read operation.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ * \param io_flags Set flags, defined in nvme_spec.h, for this I/O.
+ * \param apptag_mask Application tag mask.
+ * \param apptag Application tag to use end-to-end protection information.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_read_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
+ void *payload, void *metadata,
+ uint64_t lba, uint32_t lba_count, spdk_nvme_cmd_cb cb_fn,
+ void *cb_arg, uint32_t io_flags,
+ uint16_t apptag_mask, uint16_t apptag);
+
+/**
+ * Submit a data set management request to the specified NVMe namespace. Data set
+ * management operations are designed to optimize interaction with the block
+ * translation layer inside the device. The most common type of operation is
+ * deallocate, which is often referred to as TRIM or UNMAP.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * This is a convenience wrapper that will automatically allocate and construct
+ * the correct data buffers. Therefore, ranges does not need to be allocated from
+ * pinned memory and can be placed on the stack. If a higher performance, zero-copy
+ * version of DSM is required, simply build and submit a raw command using
+ * spdk_nvme_ctrlr_cmd_io_raw().
+ *
+ * \param ns NVMe namespace to submit the DSM request
+ * \param type A bit field constructed from \ref spdk_nvme_dsm_attribute.
+ * \param qpair I/O queue pair to submit the request
+ * \param ranges An array of \ref spdk_nvme_dsm_range elements describing the LBAs
+ * to operate on.
+ * \param num_ranges The number of elements in the ranges array.
+ * \param cb_fn Callback function to invoke when the I/O is completed
+ * \param cb_arg Argument to pass to the callback function
+ *
+ * \return 0 if successfully submitted, negated POSIX errno values otherwise.
+ */
+int spdk_nvme_ns_cmd_dataset_management(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
+ uint32_t type,
+ const struct spdk_nvme_dsm_range *ranges,
+ uint16_t num_ranges,
+ spdk_nvme_cmd_cb cb_fn,
+ void *cb_arg);
+
+/**
+ * Submit a flush request to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the flush request.
+ * \param qpair I/O queue pair to submit the request.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_flush(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * Submit a reservation register to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the reservation register request.
+ * \param qpair I/O queue pair to submit the request.
+ * \param payload Virtual address pointer to the reservation register data.
+ * \param ignore_key '1' the current reservation key check is disabled.
+ * \param action Specifies the registration action.
+ * \param cptpl Change the Persist Through Power Loss state.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_reservation_register(struct spdk_nvme_ns *ns,
+ struct spdk_nvme_qpair *qpair,
+ struct spdk_nvme_reservation_register_data *payload,
+ bool ignore_key,
+ enum spdk_nvme_reservation_register_action action,
+ enum spdk_nvme_reservation_register_cptpl cptpl,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * Submits a reservation release to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the reservation release request.
+ * \param qpair I/O queue pair to submit the request.
+ * \param payload Virtual address pointer to current reservation key.
+ * \param ignore_key '1' the current reservation key check is disabled.
+ * \param action Specifies the reservation release action.
+ * \param type Reservation type for the namespace.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_reservation_release(struct spdk_nvme_ns *ns,
+ struct spdk_nvme_qpair *qpair,
+ struct spdk_nvme_reservation_key_data *payload,
+ bool ignore_key,
+ enum spdk_nvme_reservation_release_action action,
+ enum spdk_nvme_reservation_type type,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * Submits a reservation acquire to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the reservation acquire request.
+ * \param qpair I/O queue pair to submit the request.
+ * \param payload Virtual address pointer to reservation acquire data.
+ * \param ignore_key '1' the current reservation key check is disabled.
+ * \param action Specifies the reservation acquire action.
+ * \param type Reservation type for the namespace.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_reservation_acquire(struct spdk_nvme_ns *ns,
+ struct spdk_nvme_qpair *qpair,
+ struct spdk_nvme_reservation_acquire_data *payload,
+ bool ignore_key,
+ enum spdk_nvme_reservation_acquire_action action,
+ enum spdk_nvme_reservation_type type,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * Submit a reservation report to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the reservation report request.
+ * \param qpair I/O queue pair to submit the request.
+ * \param payload Virtual address pointer for reservation status data.
+ * \param len Length bytes for reservation status data structure.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_reservation_report(struct spdk_nvme_ns *ns,
+ struct spdk_nvme_qpair *qpair,
+ void *payload, uint32_t len,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * Submit a compare I/O to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the compare I/O.
+ * \param qpair I/O queue pair to submit the request.
+ * \param payload Virtual address pointer to the data payload.
+ * \param lba Starting LBA to compare the data.
+ * \param lba_count Length (in sectors) for the compare operation.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ * \param io_flags Set flags, defined in nvme_spec.h, for this I/O.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_compare(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, void *payload,
+ uint64_t lba, uint32_t lba_count, spdk_nvme_cmd_cb cb_fn,
+ void *cb_arg, uint32_t io_flags);
+
+/**
+ * Submit a compare I/O to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the compare I/O.
+ * \param qpair I/O queue pair to submit the request.
+ * \param lba Starting LBA to compare the data.
+ * \param lba_count Length (in sectors) for the compare operation.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ * \param io_flags Set flags, defined in nvme_spec.h, for this I/O.
+ * \param reset_sgl_fn Callback function to reset scattered payload.
+ * \param next_sge_fn Callback function to iterate each scattered payload memory
+ * segment.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_comparev(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
+ uint64_t lba, uint32_t lba_count,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
+ spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
+ spdk_nvme_req_next_sge_cb next_sge_fn);
+
+/**
+ * Submit a compare I/O to the specified NVMe namespace.
+ *
+ * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
+ * The user must ensure that only one thread submits I/O on a given qpair at any
+ * given time.
+ *
+ * \param ns NVMe namespace to submit the compare I/O.
+ * \param qpair I/O queue pair to submit the request.
+ * \param payload Virtual address pointer to the data payload.
+ * \param metadata Virtual address pointer to the metadata payload, the length
+ * of metadata is specified by spdk_nvme_ns_get_md_size().
+ * \param lba Starting LBA to compare the data.
+ * \param lba_count Length (in sectors) for the compare operation.
+ * \param cb_fn Callback function to invoke when the I/O is completed.
+ * \param cb_arg Argument to pass to the callback function.
+ * \param io_flags Set flags, defined in nvme_spec.h, for this I/O.
+ * \param apptag_mask Application tag mask.
+ * \param apptag Application tag to use end-to-end protection information.
+ *
+ * \return 0 if successfully submitted, negated errno if an nvme_request structure
+ * cannot be allocated for the I/O request.
+ */
+int spdk_nvme_ns_cmd_compare_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
+ void *payload, void *metadata,
+ uint64_t lba, uint32_t lba_count, spdk_nvme_cmd_cb cb_fn,
+ void *cb_arg, uint32_t io_flags,
+ uint16_t apptag_mask, uint16_t apptag);
+
+/**
+ * \brief Inject an error for the next request with a given opcode.
+ *
+ * \param ctrlr NVMe controller.
+ * \param qpair I/O queue pair to add the error command,
+ * NULL for Admin queue pair.
+ * \param opc Opcode for Admin or I/O commands.
+ * \param do_not_submit True if matching requests should not be submitted
+ * to the controller, but instead completed manually
+ * after timeout_in_us has expired. False if matching
+ * requests should be submitted to the controller and
+ * have their completion status modified after the
+ * controller completes the request.
+ * \param timeout_in_us Wait specified microseconds when do_not_submit is true.
+ * \param err_count Number of matching requests to inject errors.
+ * \param sct Status code type.
+ * \param sc Status code.
+ *
+ * \return 0 if successfully enabled, ENOMEM if an error command
+ * structure cannot be allocated.
+ *
+ * The function can be called multiple times to inject errors for different
+ * commands. If the opcode matches an existing entry, the existing entry
+ * will be updated with the values specified.
+ */
+int spdk_nvme_qpair_add_cmd_error_injection(struct spdk_nvme_ctrlr *ctrlr,
+ struct spdk_nvme_qpair *qpair,
+ uint8_t opc,
+ bool do_not_submit,
+ uint64_t timeout_in_us,
+ uint32_t err_count,
+ uint8_t sct, uint8_t sc);
+
+/**
+ * \brief Clear the specified NVMe command with error status.
+ *
+ * \param ctrlr NVMe controller.
+ * \param qpair I/O queue pair to remove the error command,
+ * \ NULL for Admin queue pair.
+ * \param opc Opcode for Admin or I/O commands.
+ *
+ * The function will remove specified command in the error list.
+ */
+void spdk_nvme_qpair_remove_cmd_error_injection(struct spdk_nvme_ctrlr *ctrlr,
+ struct spdk_nvme_qpair *qpair,
+ uint8_t opc);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/nvme_intel.h b/src/spdk/include/spdk/nvme_intel.h
new file mode 100644
index 00000000..fc4cd0cd
--- /dev/null
+++ b/src/spdk/include/spdk/nvme_intel.h
@@ -0,0 +1,212 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * Intel NVMe vendor-specific definitions
+ *
+ * Reference:
+ * http://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/ssd-dc-p3700-spec.pdf
+ */
+
+#ifndef SPDK_NVME_INTEL_H
+#define SPDK_NVME_INTEL_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "spdk/assert.h"
+
+enum spdk_nvme_intel_feat {
+ SPDK_NVME_INTEL_FEAT_MAX_LBA = 0xC1,
+ SPDK_NVME_INTEL_FEAT_NATIVE_MAX_LBA = 0xC2,
+ SPDK_NVME_INTEL_FEAT_POWER_GOVERNOR_SETTING = 0xC6,
+ SPDK_NVME_INTEL_FEAT_SMBUS_ADDRESS = 0xC8,
+ SPDK_NVME_INTEL_FEAT_LED_PATTERN = 0xC9,
+ SPDK_NVME_INTEL_FEAT_RESET_TIMED_WORKLOAD_COUNTERS = 0xD5,
+ SPDK_NVME_INTEL_FEAT_LATENCY_TRACKING = 0xE2,
+};
+
+enum spdk_nvme_intel_set_max_lba_command_status_code {
+ SPDK_NVME_INTEL_EXCEEDS_AVAILABLE_CAPACITY = 0xC0,
+ SPDK_NVME_INTEL_SMALLER_THAN_MIN_LIMIT = 0xC1,
+ SPDK_NVME_INTEL_SMALLER_THAN_NS_REQUIREMENTS = 0xC2,
+};
+
+enum spdk_nvme_intel_log_page {
+ SPDK_NVME_INTEL_LOG_PAGE_DIRECTORY = 0xC0,
+ SPDK_NVME_INTEL_LOG_READ_CMD_LATENCY = 0xC1,
+ SPDK_NVME_INTEL_LOG_WRITE_CMD_LATENCY = 0xC2,
+ SPDK_NVME_INTEL_LOG_TEMPERATURE = 0xC5,
+ SPDK_NVME_INTEL_LOG_SMART = 0xCA,
+ SPDK_NVME_INTEL_MARKETING_DESCRIPTION = 0xDD,
+};
+
+enum spdk_nvme_intel_smart_attribute_code {
+ SPDK_NVME_INTEL_SMART_PROGRAM_FAIL_COUNT = 0xAB,
+ SPDK_NVME_INTEL_SMART_ERASE_FAIL_COUNT = 0xAC,
+ SPDK_NVME_INTEL_SMART_WEAR_LEVELING_COUNT = 0xAD,
+ SPDK_NVME_INTEL_SMART_E2E_ERROR_COUNT = 0xB8,
+ SPDK_NVME_INTEL_SMART_CRC_ERROR_COUNT = 0xC7,
+ SPDK_NVME_INTEL_SMART_MEDIA_WEAR = 0xE2,
+ SPDK_NVME_INTEL_SMART_HOST_READ_PERCENTAGE = 0xE3,
+ SPDK_NVME_INTEL_SMART_TIMER = 0xE4,
+ SPDK_NVME_INTEL_SMART_THERMAL_THROTTLE_STATUS = 0xEA,
+ SPDK_NVME_INTEL_SMART_RETRY_BUFFER_OVERFLOW_COUNTER = 0xF0,
+ SPDK_NVME_INTEL_SMART_PLL_LOCK_LOSS_COUNT = 0xF3,
+ SPDK_NVME_INTEL_SMART_NAND_BYTES_WRITTEN = 0xF4,
+ SPDK_NVME_INTEL_SMART_HOST_BYTES_WRITTEN = 0xF5,
+};
+
+struct spdk_nvme_intel_log_page_directory {
+ uint8_t version[2];
+ uint8_t reserved[384];
+ uint8_t read_latency_log_len;
+ uint8_t reserved2;
+ uint8_t write_latency_log_len;
+ uint8_t reserved3[5];
+ uint8_t temperature_statistics_log_len;
+ uint8_t reserved4[9];
+ uint8_t smart_log_len;
+ uint8_t reserved5[37];
+ uint8_t marketing_description_log_len;
+ uint8_t reserved6[69];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_intel_log_page_directory) == 512, "Incorrect size");
+
+struct spdk_nvme_intel_rw_latency_page {
+ uint16_t major_revison;
+ uint16_t minor_revison;
+ uint32_t buckets_32us[32];
+ uint32_t buckets_1ms[31];
+ uint32_t buckets_32ms[31];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_intel_rw_latency_page) == 380, "Incorrect size");
+
+struct spdk_nvme_intel_temperature_page {
+ uint64_t current_temperature;
+ uint64_t shutdown_flag_last;
+ uint64_t shutdown_flag_life;
+ uint64_t highest_temperature;
+ uint64_t lowest_temperature;
+ uint64_t reserved[5];
+ uint64_t specified_max_op_temperature;
+ uint64_t reserved2;
+ uint64_t specified_min_op_temperature;
+ uint64_t estimated_offset;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_intel_temperature_page) == 112, "Incorrect size");
+
+struct spdk_nvme_intel_smart_attribute {
+ uint8_t code;
+ uint8_t reserved[2];
+ uint8_t normalized_value;
+ uint8_t reserved2;
+ uint8_t raw_value[6];
+ uint8_t reserved3;
+};
+
+struct __attribute__((packed)) spdk_nvme_intel_smart_information_page {
+ struct spdk_nvme_intel_smart_attribute attributes[13];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_intel_smart_information_page) == 156, "Incorrect size");
+
+union spdk_nvme_intel_feat_power_governor {
+ uint32_t raw;
+ struct {
+ /** power governor setting : 00h = 25W 01h = 20W 02h = 10W */
+ uint32_t power_governor_setting : 8;
+ uint32_t reserved : 24;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_intel_feat_power_governor) == 4, "Incorrect size");
+
+union spdk_nvme_intel_feat_smbus_address {
+ uint32_t raw;
+ struct {
+ uint32_t reserved : 1;
+ uint32_t smbus_controller_address : 8;
+ uint32_t reserved2 : 23;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_intel_feat_smbus_address) == 4, "Incorrect size");
+
+union spdk_nvme_intel_feat_led_pattern {
+ uint32_t raw;
+ struct {
+ uint32_t feature_options : 24;
+ uint32_t value : 8;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_intel_feat_led_pattern) == 4, "Incorrect size");
+
+union spdk_nvme_intel_feat_reset_timed_workload_counters {
+ uint32_t raw;
+ struct {
+ /**
+ * Write Usage: 00 = NOP, 1 = Reset E2, E3,E4 counters;
+ * Read Usage: Not Supported
+ */
+ uint32_t reset : 1;
+ uint32_t reserved : 31;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_intel_feat_reset_timed_workload_counters) == 4,
+ "Incorrect size");
+
+union spdk_nvme_intel_feat_latency_tracking {
+ uint32_t raw;
+ struct {
+ /**
+ * Write Usage:
+ * 00h = Disable Latency Tracking (Default)
+ * 01h = Enable Latency Tracking
+ */
+ uint32_t enable : 32;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_intel_feat_latency_tracking) == 4, "Incorrect size");
+
+struct spdk_nvme_intel_marketing_description_page {
+ uint8_t marketing_product[512];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_intel_marketing_description_page) == 512,
+ "Incorrect size");
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/nvme_ocssd.h b/src/spdk/include/spdk/nvme_ocssd.h
new file mode 100644
index 00000000..7ebb0799
--- /dev/null
+++ b/src/spdk/include/spdk/nvme_ocssd.h
@@ -0,0 +1,227 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * NVMe driver public API extension for Open-Channel
+ */
+
+#ifndef SPDK_NVME_OCSSD_H
+#define SPDK_NVME_OCSSD_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "spdk/nvme.h"
+#include "spdk/nvme_ocssd_spec.h"
+
+/**
+ * \brief Determine if OpenChannel is supported by the given NVMe controller.
+ * \param ctrlr NVMe controller to check.
+ *
+ * \return true if support OpenChannel
+ */
+bool spdk_nvme_ctrlr_is_ocssd_supported(struct spdk_nvme_ctrlr *ctrlr);
+
+/**
+ * \brief Identify geometry of the given namespace.
+ * \param ctrlr NVMe controller to query.
+ * \param nsid Id of the given namesapce.
+ * \param payload The pointer to the payload buffer.
+ * \param payload_size The size of payload buffer. Shall be multiple of 4K.
+ * \param cb_fn Callback function to invoke when the feature has been retrieved.
+ * \param cb_arg Argument to pass to the callback function.
+ *
+ * \return 0 if successfully submitted, ENOMEM if resources could not be
+ * allocated for this request, EINVAL if wrong payload size.
+ *
+ */
+int spdk_nvme_ocssd_ctrlr_cmd_geometry(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid,
+ void *payload, uint32_t payload_size,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * \brief Submits a vector reset command to the specified NVMe namespace.
+ *
+ * \param ns NVMe namespace to submit the command
+ * \param qpair I/O queue pair to submit the request
+ * \param lba_list an array of LBAs for processing.
+ * LBAs must correspond to the start of chunks to reset.
+ * Must be allocated through spdk_dma_malloc() or its variants
+ * \param num_lbas number of LBAs stored in lba_list
+ * \param chunk_info an array of chunk info on DMA-able memory
+ * \param cb_fn callback function to invoke when the I/O is completed
+ * \param cb_arg argument to pass to the callback function
+ *
+ * \return 0 if successfully submitted, ENOMEM if an nvme_request
+ * structure cannot be allocated for the I/O request
+ */
+int spdk_nvme_ocssd_ns_cmd_vector_reset(struct spdk_nvme_ns *ns,
+ struct spdk_nvme_qpair *qpair,
+ uint64_t *lba_list, uint32_t num_lbas,
+ struct spdk_ocssd_chunk_information_entry *chunk_info,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg);
+
+/**
+ * \brief Submits a vector write command to the specified NVMe namespace.
+ *
+ * \param ns NVMe namespace to submit the command
+ * \param qpair I/O queue pair to submit the request
+ * \param buffer virtual address pointer to the data payload
+ * \param lba_list an array of LBAs for processing.
+ * Must be allocated through spdk_dma_malloc() or its variants
+ * \param num_lbas number of LBAs stored in lba_list
+ * \param cb_fn callback function to invoke when the I/O is completed
+ * \param cb_arg argument to pass to the callback function
+ * \param io_flags set flags, defined by the SPDK_OCSSD_IO_FLAGS_* entries
+ * in spdk/nvme_ocssd_spec.h, for this I/O.
+ *
+ * \return 0 if successfully submitted, ENOMEM if an nvme_request
+ * structure cannot be allocated for the I/O request
+ */
+int spdk_nvme_ocssd_ns_cmd_vector_write(struct spdk_nvme_ns *ns,
+ struct spdk_nvme_qpair *qpair,
+ void *buffer,
+ uint64_t *lba_list, uint32_t num_lbas,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg,
+ uint32_t io_flags);
+
+/**
+ * \brief Submits a vector write command to the specified NVMe namespace.
+ *
+ * \param ns NVMe namespace to submit the command
+ * \param qpair I/O queue pair to submit the request
+ * \param buffer virtual address pointer to the data payload
+ * \param metadata virtual address pointer to the metadata payload, the length
+ * of metadata is specified by spdk_nvme_ns_get_md_size()
+ * \param lba_list an array of LBAs for processing.
+ * Must be allocated through spdk_dma_malloc() or its variants
+ * \param num_lbas number of LBAs stored in lba_list
+ * \param cb_fn callback function to invoke when the I/O is completed
+ * \param cb_arg argument to pass to the callback function
+ * \param io_flags set flags, defined by the SPDK_OCSSD_IO_FLAGS_* entries
+ * in spdk/nvme_ocssd_spec.h, for this I/O.
+ *
+ * \return 0 if successfully submitted, ENOMEM if an nvme_request
+ * structure cannot be allocated for the I/O request
+ */
+int spdk_nvme_ocssd_ns_cmd_vector_write_with_md(struct spdk_nvme_ns *ns,
+ struct spdk_nvme_qpair *qpair,
+ void *buffer, void *metadata,
+ uint64_t *lba_list, uint32_t num_lbas,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg,
+ uint32_t io_flags);
+
+/**
+ * \brief Submits a vector read command to the specified NVMe namespace.
+ *
+ * \param ns NVMe namespace to submit the command
+ * \param qpair I/O queue pair to submit the request
+ * \param buffer virtual address pointer to the data payload
+ * \param lba_list an array of LBAs for processing.
+ * Must be allocated through spdk_dma_malloc() or its variants
+ * \param num_lbas number of LBAs stored in lba_list
+ * \param cb_fn callback function to invoke when the I/O is completed
+ * \param cb_arg argument to pass to the callback function
+ * \param io_flags set flags, defined by the SPDK_OCSSD_IO_FLAGS_* entries
+ * in spdk/nvme_ocssd_spec.h, for this I/O.
+ *
+ * \return 0 if successfully submitted, ENOMEM if an nvme_request
+ * structure cannot be allocated for the I/O request
+ */
+int spdk_nvme_ocssd_ns_cmd_vector_read(struct spdk_nvme_ns *ns,
+ struct spdk_nvme_qpair *qpair,
+ void *buffer,
+ uint64_t *lba_list, uint32_t num_lbas,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg,
+ uint32_t io_flags);
+
+/**
+ * \brief Submits a vector read command to the specified NVMe namespace.
+ *
+ * \param ns NVMe namespace to submit the command
+ * \param qpair I/O queue pair to submit the request
+ * \param buffer virtual address pointer to the data payload
+ * \param metadata virtual address pointer to the metadata payload, the length
+ * of metadata is specified by spdk_nvme_ns_get_md_size()
+ * \param lba_list an array of LBAs for processing.
+ * Must be allocated through spdk_dma_malloc() or its variants
+ * \param num_lbas number of LBAs stored in lba_list
+ * \param cb_fn callback function to invoke when the I/O is completed
+ * \param cb_arg argument to pass to the callback function
+ * \param io_flags set flags, defined by the SPDK_OCSSD_IO_FLAGS_* entries
+ * in spdk/nvme_ocssd_spec.h, for this I/O.
+ *
+ * \return 0 if successfully submitted, ENOMEM if an nvme_request
+ * structure cannot be allocated for the I/O request
+ */
+int spdk_nvme_ocssd_ns_cmd_vector_read_with_md(struct spdk_nvme_ns *ns,
+ struct spdk_nvme_qpair *qpair,
+ void *buffer, void *metadata,
+ uint64_t *lba_list, uint32_t num_lbas,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg,
+ uint32_t io_flags);
+
+/**
+ * \brief Submits a vector copy command to the specified NVMe namespace.
+ *
+ * \param ns NVMe namespace to submit the command
+ * \param qpair I/O queue pair to submit the request
+ * \param dst_lba_list an array of destination LBAs for processing.
+ * Must be allocated through spdk_dma_malloc() or its variants
+ * \param src_lba_list an array of source LBAs for processing.
+ * Must be allocated through spdk_dma_malloc() or its variants
+ * \param num_lbas number of LBAs stored in src_lba_list and dst_lba_list
+ * \param cb_fn callback function to invoke when the I/O is completed
+ * \param cb_arg argument to pass to the callback function
+ * \param io_flags set flags, defined by the SPDK_OCSSD_IO_FLAGS_* entries
+ * in spdk/nvme_ocssd_spec.h, for this I/O.
+ *
+ * \return 0 if successfully submitted, ENOMEM if an nvme_request
+ * structure cannot be allocated for the I/O request
+ */
+int spdk_nvme_ocssd_ns_cmd_vector_copy(struct spdk_nvme_ns *ns,
+ struct spdk_nvme_qpair *qpair,
+ uint64_t *dst_lba_list, uint64_t *src_lba_list,
+ uint32_t num_lbas,
+ spdk_nvme_cmd_cb cb_fn, void *cb_arg,
+ uint32_t io_flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/nvme_ocssd_spec.h b/src/spdk/include/spdk/nvme_ocssd_spec.h
new file mode 100644
index 00000000..21e9bcef
--- /dev/null
+++ b/src/spdk/include/spdk/nvme_ocssd_spec.h
@@ -0,0 +1,414 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * Open-Channel specification definitions
+ */
+
+#ifndef SPDK_NVME_OCSSD_SPEC_H
+#define SPDK_NVME_OCSSD_SPEC_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "spdk/assert.h"
+#include "spdk/nvme_spec.h"
+
+/** A maximum number of LBAs that can be issued by vector I/O commands */
+#define SPDK_NVME_OCSSD_MAX_LBAL_ENTRIES 64
+
+struct spdk_ocssd_dev_lba_fmt {
+ /** Contiguous number of bits assigned to Group addressing */
+ uint8_t grp_len;
+
+ /** Contiguous number of bits assigned to PU addressing */
+ uint8_t pu_len;
+
+ /** Contiguous number of bits assigned to Chunk addressing */
+ uint8_t chk_len;
+
+ /** Contiguous number of bits assigned to logical blocks within Chunk */
+ uint8_t lbk_len;
+
+ uint8_t reserved[4];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_ocssd_dev_lba_fmt) == 8, "Incorrect size");
+
+struct spdk_ocssd_geometry_data {
+ /** Major Version Number */
+ uint8_t mjr;
+
+ /** Minor Version Number */
+ uint8_t mnr;
+
+ uint8_t reserved1[6];
+
+ /** LBA format */
+ struct spdk_ocssd_dev_lba_fmt lbaf;
+
+ /** Media and Controller Capabilities */
+ struct {
+ /* Supports the Vector Chunk Copy I/O Command */
+ uint32_t vec_chk_cpy : 1;
+
+ /* Supports multiple resets when a chunk is in its free state */
+ uint32_t multi_reset : 1;
+
+ uint32_t reserved : 30;
+ } mccap;
+
+ uint8_t reserved2[12];
+
+ /** Wear-level Index Delta Threshold */
+ uint8_t wit;
+
+ uint8_t reserved3[31];
+
+ /** Number of Groups */
+ uint16_t num_grp;
+
+ /** Number of parallel units per group */
+ uint16_t num_pu;
+
+ /** Number of chunks per parallel unit */
+ uint32_t num_chk;
+
+ /** Chunk Size */
+ uint32_t clba;
+
+ uint8_t reserved4[52];
+
+ /** Minimum Write Size */
+ uint32_t ws_min;
+
+ /** Optimal Write Size */
+ uint32_t ws_opt;
+
+ /** Cache Minimum Write Size Units */
+ uint32_t mw_cunits;
+
+ /** Maximum Open Chunks */
+ uint32_t maxoc;
+
+ /** Maximum Open Chunks per PU */
+ uint32_t maxocpu;
+
+ uint8_t reserved5[44];
+
+ /** tRD Typical */
+ uint32_t trdt;
+
+ /** tRD Max */
+ uint32_t trdm;
+
+ /** tWR Typical */
+ uint32_t twrt;
+
+ /** tWR Max */
+ uint32_t twrm;
+
+ /** tCRS Typical */
+ uint32_t tcrst;
+
+ /** tCRS Max */
+ uint32_t tcrsm;
+
+ /** bytes 216-255: reserved for performance related metrics */
+ uint8_t reserved6[40];
+
+ uint8_t reserved7[3071 - 255];
+
+ /** bytes 3072-4095: Vendor Specific */
+ uint8_t vs[4095 - 3071];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_ocssd_geometry_data) == 4096, "Incorrect size");
+
+struct spdk_ocssd_chunk_information_entry {
+ /** Chunk State */
+ struct {
+ /** if set to 1 chunk is free */
+ uint8_t free : 1;
+
+ /** if set to 1 chunk is closed */
+ uint8_t closed : 1;
+
+ /** if set to 1 chunk is open */
+ uint8_t open : 1;
+
+ /** if set to 1 chunk is offline */
+ uint8_t offline : 1;
+
+ uint8_t reserved : 4;
+ } cs;
+
+ /** Chunk Type */
+ struct {
+ /** If set to 1 chunk must be written sequentially */
+ uint8_t seq_write : 1;
+
+ /** If set to 1 chunk allows random writes */
+ uint8_t rnd_write : 1;
+
+ uint8_t reserved1 : 2;
+
+ /**
+ * If set to 1 chunk deviates from the chunk size reported
+ * in identify geometry command.
+ */
+ uint8_t size_deviate : 1;
+
+ uint8_t reserved2 : 3;
+ } ct;
+
+ /** Wear-level Index */
+ uint8_t wli;
+
+ uint8_t reserved[5];
+
+ /** Starting LBA */
+ uint64_t slba;
+
+ /** Number of blocks in chunk */
+ uint64_t cnlb;
+
+ /** Write Pointer */
+ uint64_t wp;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_ocssd_chunk_information_entry) == 32, "Incorrect size");
+
+struct spdk_ocssd_chunk_notification_entry {
+
+ /**
+ * This is a 64-bit incrementing notification count, indicating a
+ * unique identifier for this notification. The counter begins at 1h
+ * and is incremented for each unique event
+ */
+ uint64_t nc;
+
+ /** This field points to the chunk that has its state updated */
+ uint64_t lba;
+
+ /**
+ * This field indicates the namespace id that the event is associated
+ * with
+ */
+ uint32_t nsid;
+
+ /** Field that indicate the state of the block */
+ struct {
+
+ /**
+ * If set to 1, then the error rate of the chunk has been
+ * changed to low
+ */
+ uint8_t error_rate_low : 1;
+
+ /**
+ * If set to 1, then the error rate of the chunk has been
+ * changed to medium
+ */
+ uint8_t error_rate_medium : 1;
+
+ /**
+ * If set to 1, then the error rate of the chunk has been
+ * changed to high
+ */
+ uint8_t error_rate_high : 1;
+
+ /**
+ * If set to 1, then the error rate of the chunk has been
+ * changed to unrecoverable
+ */
+ uint8_t unrecoverable : 1;
+
+ /**
+ * If set to 1, then the chunk has been refreshed by the
+ * device
+ */
+ uint8_t refreshed : 1;
+
+ uint8_t rsvd : 3;
+
+ /**
+ * If set to 1 then the chunk's wear-level index is outside
+ * the average wear-level index threshold defined by the
+ * controller
+ */
+ uint8_t wit_exceeded : 1;
+
+ uint8_t rsvd2 : 7;
+ } state;
+
+ /**
+ * The address provided is covering either logical block, chunk, or
+ * parallel unit
+ */
+ struct {
+
+ /** If set to 1, the LBA covers the logical block */
+ uint8_t lblk : 1;
+
+ /** If set to 1, the LBA covers the respecting chunk */
+ uint8_t chunk : 1;
+
+ /**
+ * If set to 1, the LBA covers the respecting parallel unit
+ * including all chunks
+ */
+ uint8_t pu : 1;
+
+ uint8_t rsvd : 5;
+ } mask;
+
+ uint8_t rsvd[9];
+
+ /**
+ * This field indicates the number of logical chunks to be written.
+ * This is a 0's based value. This field is only valid if mask bit 0 is
+ * set. The number of blocks addressed shall not be outside the boundary
+ * of the specified chunk.
+ */
+ uint16_t nlb;
+
+ uint8_t rsvd2[30];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_ocssd_chunk_notification_entry) == 64, "Incorrect size");
+
+/**
+ * Vector completion queue entry
+ */
+struct spdk_ocssd_vector_cpl {
+ /* dword 0,1 */
+ uint64_t lba_status; /* completion status bit array */
+
+ /* dword 2 */
+ uint16_t sqhd; /* submission queue head pointer */
+ uint16_t sqid; /* submission queue identifier */
+
+ /* dword 3 */
+ uint16_t cid; /* command identifier */
+ struct spdk_nvme_status status;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_ocssd_vector_cpl) == 16, "Incorrect size");
+
+/**
+ * OCSSD admin command set opcodes
+ */
+enum spdk_ocssd_admin_opcode {
+ SPDK_OCSSD_OPC_GEOMETRY = 0xE2
+};
+
+/**
+ * OCSSD I/O command set opcodes
+ */
+enum spdk_ocssd_io_opcode {
+ SPDK_OCSSD_OPC_VECTOR_RESET = 0x90,
+ SPDK_OCSSD_OPC_VECTOR_WRITE = 0x91,
+ SPDK_OCSSD_OPC_VECTOR_READ = 0x92,
+ SPDK_OCSSD_OPC_VECTOR_COPY = 0x93
+};
+
+/**
+ * Log page identifiers for SPDK_NVME_OPC_GET_LOG_PAGE
+ */
+enum spdk_ocssd_log_page {
+ /** Chunk Information */
+ SPDK_OCSSD_LOG_CHUNK_INFO = 0xCA,
+
+ /** Chunk Notification Log */
+ SPDK_OCSSD_LOG_CHUNK_NOTIFICATION = 0xD0,
+};
+
+/**
+ * OCSSD feature identifiers
+ * Defines OCSSD specific features that may be configured with Set Features and
+ * retrieved with Get Features.
+ */
+enum spdk_ocssd_feat {
+ /** Media Feedback feature identifier */
+ SPDK_OCSSD_FEAT_MEDIA_FEEDBACK = 0xCA
+};
+
+/**
+ * OCSSD media error status codes extension.
+ * Additional error codes for status code type “2h” (media errors)
+ */
+enum spdk_ocssd_media_error_status_code {
+ /**
+ * The chunk was either marked offline by the reset or the state
+ * of the chunk is already offline.
+ */
+ SPDK_OCSSD_SC_OFFLINE_CHUNK = 0xC0,
+
+ /**
+ * Invalid reset if chunk state is either “Free” or “Open”
+ */
+ SPDK_OCSSD_SC_INVALID_RESET = 0xC1,
+
+ /**
+ * Write failed, chunk remains open.
+ * Host should proceed to write to next write unit.
+ */
+ SPDK_OCSSD_SC_WRITE_FAIL_WRITE_NEXT_UNIT = 0xF0,
+
+ /**
+ * The writes ended prematurely. The chunk state is set to closed.
+ * The host can read up to the value of the write pointer.
+ */
+ SPDK_OCSSD_SC_WRITE_FAIL_CHUNK_EARLY_CLOSE = 0xF1,
+
+ /**
+ * The write corresponds to a write out of order within an open
+ * chunk or the write is to a closed or offline chunk.
+ */
+ SPDK_OCSSD_SC_OUT_OF_ORDER_WRITE = 0xF2,
+
+ /**
+ * The data retrieved is nearing its limit for reading.
+ * The limit is vendor specific, and only provides a hint
+ * to the host that should refresh its data in the future.
+ */
+ SPDK_OCSSD_SC_READ_HIGH_ECC = 0xD0,
+};
+
+#define SPDK_OCSSD_IO_FLAGS_LIMITED_RETRY (1U << 31)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/nvme_spec.h b/src/spdk/include/spdk/nvme_spec.h
new file mode 100644
index 00000000..6b180b3f
--- /dev/null
+++ b/src/spdk/include/spdk/nvme_spec.h
@@ -0,0 +1,2414 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * NVMe specification definitions
+ */
+
+#ifndef SPDK_NVME_SPEC_H
+#define SPDK_NVME_SPEC_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "spdk/assert.h"
+
+/**
+ * Use to mark a command to apply to all namespaces, or to retrieve global
+ * log pages.
+ */
+#define SPDK_NVME_GLOBAL_NS_TAG ((uint32_t)0xFFFFFFFF)
+
+#define SPDK_NVME_MAX_IO_QUEUES (65535)
+
+#define SPDK_NVME_ADMIN_QUEUE_MIN_ENTRIES 2
+#define SPDK_NVME_ADMIN_QUEUE_MAX_ENTRIES 4096
+
+#define SPDK_NVME_IO_QUEUE_MIN_ENTRIES 2
+#define SPDK_NVME_IO_QUEUE_MAX_ENTRIES 65536
+
+/**
+ * Indicates the maximum number of range sets that may be specified
+ * in the dataset mangement command.
+ */
+#define SPDK_NVME_DATASET_MANAGEMENT_MAX_RANGES 256
+
+/**
+ * Maximum number of blocks that may be specified in a single dataset management range.
+ */
+#define SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS 0xFFFFFFFFu
+
+union spdk_nvme_cap_register {
+ uint64_t raw;
+ struct {
+ /** maximum queue entries supported */
+ uint32_t mqes : 16;
+
+ /** contiguous queues required */
+ uint32_t cqr : 1;
+
+ /** arbitration mechanism supported */
+ uint32_t ams : 2;
+
+ uint32_t reserved1 : 5;
+
+ /** timeout */
+ uint32_t to : 8;
+
+ /** doorbell stride */
+ uint32_t dstrd : 4;
+
+ /** NVM subsystem reset supported */
+ uint32_t nssrs : 1;
+
+ /** command sets supported */
+ uint32_t css : 8;
+
+ /** boot partition support */
+ uint32_t bps : 1;
+
+ uint32_t reserved2 : 2;
+
+ /** memory page size minimum */
+ uint32_t mpsmin : 4;
+
+ /** memory page size maximum */
+ uint32_t mpsmax : 4;
+
+ uint32_t reserved3 : 8;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_cap_register) == 8, "Incorrect size");
+
+/**
+ * I/O Command Set Selected
+ *
+ * Only a single command set is defined as of NVMe 1.3 (NVM).
+ */
+enum spdk_nvme_cc_css {
+ SPDK_NVME_CC_CSS_NVM = 0x0, /**< NVM command set */
+};
+
+#define SPDK_NVME_CAP_CSS_NVM (1u << SPDK_NVME_CC_CSS_NVM) /**< NVM command set supported */
+
+union spdk_nvme_cc_register {
+ uint32_t raw;
+ struct {
+ /** enable */
+ uint32_t en : 1;
+
+ uint32_t reserved1 : 3;
+
+ /** i/o command set selected */
+ uint32_t css : 3;
+
+ /** memory page size */
+ uint32_t mps : 4;
+
+ /** arbitration mechanism selected */
+ uint32_t ams : 3;
+
+ /** shutdown notification */
+ uint32_t shn : 2;
+
+ /** i/o submission queue entry size */
+ uint32_t iosqes : 4;
+
+ /** i/o completion queue entry size */
+ uint32_t iocqes : 4;
+
+ uint32_t reserved2 : 8;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_cc_register) == 4, "Incorrect size");
+
+enum spdk_nvme_shn_value {
+ SPDK_NVME_SHN_NORMAL = 0x1,
+ SPDK_NVME_SHN_ABRUPT = 0x2,
+};
+
+union spdk_nvme_csts_register {
+ uint32_t raw;
+ struct {
+ /** ready */
+ uint32_t rdy : 1;
+
+ /** controller fatal status */
+ uint32_t cfs : 1;
+
+ /** shutdown status */
+ uint32_t shst : 2;
+
+ /** NVM subsystem reset occurred */
+ uint32_t nssro : 1;
+
+ /** Processing paused */
+ uint32_t pp : 1;
+
+ uint32_t reserved1 : 26;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_csts_register) == 4, "Incorrect size");
+
+enum spdk_nvme_shst_value {
+ SPDK_NVME_SHST_NORMAL = 0x0,
+ SPDK_NVME_SHST_OCCURRING = 0x1,
+ SPDK_NVME_SHST_COMPLETE = 0x2,
+};
+
+union spdk_nvme_aqa_register {
+ uint32_t raw;
+ struct {
+ /** admin submission queue size */
+ uint32_t asqs : 12;
+
+ uint32_t reserved1 : 4;
+
+ /** admin completion queue size */
+ uint32_t acqs : 12;
+
+ uint32_t reserved2 : 4;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_aqa_register) == 4, "Incorrect size");
+
+union spdk_nvme_vs_register {
+ uint32_t raw;
+ struct {
+ /** indicates the tertiary version */
+ uint32_t ter : 8;
+ /** indicates the minor version */
+ uint32_t mnr : 8;
+ /** indicates the major version */
+ uint32_t mjr : 16;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_vs_register) == 4, "Incorrect size");
+
+/** Generate raw version in the same format as \ref spdk_nvme_vs_register for comparison. */
+#define SPDK_NVME_VERSION(mjr, mnr, ter) \
+ (((uint32_t)(mjr) << 16) | \
+ ((uint32_t)(mnr) << 8) | \
+ (uint32_t)(ter))
+
+/* Test that the shifts are correct */
+SPDK_STATIC_ASSERT(SPDK_NVME_VERSION(1, 0, 0) == 0x00010000, "version macro error");
+SPDK_STATIC_ASSERT(SPDK_NVME_VERSION(1, 2, 1) == 0x00010201, "version macro error");
+
+union spdk_nvme_cmbloc_register {
+ uint32_t raw;
+ struct {
+ /** indicator of BAR which contains controller memory buffer(CMB) */
+ uint32_t bir : 3;
+ uint32_t reserved1 : 9;
+ /** offset of CMB in multiples of the size unit */
+ uint32_t ofst : 20;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_cmbloc_register) == 4, "Incorrect size");
+
+union spdk_nvme_cmbsz_register {
+ uint32_t raw;
+ struct {
+ /** support submission queues in CMB */
+ uint32_t sqs : 1;
+ /** support completion queues in CMB */
+ uint32_t cqs : 1;
+ /** support PRP and SGLs lists in CMB */
+ uint32_t lists : 1;
+ /** support read data and metadata in CMB */
+ uint32_t rds : 1;
+ /** support write data and metadata in CMB */
+ uint32_t wds : 1;
+ uint32_t reserved1 : 3;
+ /** indicates the granularity of the size unit */
+ uint32_t szu : 4;
+ /** size of CMB in multiples of the size unit */
+ uint32_t sz : 20;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_cmbsz_register) == 4, "Incorrect size");
+
+/** Boot partition information */
+union spdk_nvme_bpinfo_register {
+ uint32_t raw;
+ struct {
+ /** Boot partition size in 128KB multiples */
+ uint32_t bpsz : 15;
+
+ uint32_t reserved1 : 9;
+
+ /**
+ * Boot read status
+ * 00b: No Boot Partition read operation requested
+ * 01b: Boot Partition read in progress
+ * 10b: Boot Partition read completed successfully
+ * 11b: Error completing Boot Partition read
+ */
+ uint32_t brs : 2;
+
+ uint32_t reserved2 : 5;
+
+ /** Active Boot Partition ID */
+ uint32_t abpid : 1;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_bpinfo_register) == 4, "Incorrect size");
+
+/** Boot partition read select */
+union spdk_nvme_bprsel_register {
+ uint32_t raw;
+ struct {
+ /** Boot partition read size in multiples of 4KB */
+ uint32_t bprsz : 10;
+
+ /** Boot partition read offset in multiples of 4KB */
+ uint32_t bprof : 20;
+
+ uint32_t reserved : 1;
+
+ /** Boot Partition Identifier */
+ uint32_t bpid : 1;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_bprsel_register) == 4, "Incorrect size");
+
+/** Value to write to NSSR to indicate a NVM subsystem reset ("NVMe") */
+#define SPDK_NVME_NSSR_VALUE 0x4E564D65
+
+struct spdk_nvme_registers {
+ /** controller capabilities */
+ union spdk_nvme_cap_register cap;
+
+ /** version of NVMe specification */
+ union spdk_nvme_vs_register vs;
+ uint32_t intms; /* interrupt mask set */
+ uint32_t intmc; /* interrupt mask clear */
+
+ /** controller configuration */
+ union spdk_nvme_cc_register cc;
+
+ uint32_t reserved1;
+ union spdk_nvme_csts_register csts; /* controller status */
+ uint32_t nssr; /* NVM subsystem reset */
+
+ /** admin queue attributes */
+ union spdk_nvme_aqa_register aqa;
+
+ uint64_t asq; /* admin submission queue base addr */
+ uint64_t acq; /* admin completion queue base addr */
+ /** controller memory buffer location */
+ union spdk_nvme_cmbloc_register cmbloc;
+ /** controller memory buffer size */
+ union spdk_nvme_cmbsz_register cmbsz;
+
+ /** boot partition information */
+ union spdk_nvme_bpinfo_register bpinfo;
+
+ /** boot partition read select */
+ union spdk_nvme_bprsel_register bprsel;
+
+ /** boot partition memory buffer location (must be 4KB aligned) */
+ uint64_t bpmbl;
+
+ uint32_t reserved3[0x3ec];
+
+ struct {
+ uint32_t sq_tdbl; /* submission queue tail doorbell */
+ uint32_t cq_hdbl; /* completion queue head doorbell */
+ } doorbell[1];
+};
+
+/* NVMe controller register space offsets */
+SPDK_STATIC_ASSERT(0x00 == offsetof(struct spdk_nvme_registers, cap),
+ "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x08 == offsetof(struct spdk_nvme_registers, vs), "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x0C == offsetof(struct spdk_nvme_registers, intms),
+ "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x10 == offsetof(struct spdk_nvme_registers, intmc),
+ "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x14 == offsetof(struct spdk_nvme_registers, cc), "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x1C == offsetof(struct spdk_nvme_registers, csts), "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x20 == offsetof(struct spdk_nvme_registers, nssr), "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x24 == offsetof(struct spdk_nvme_registers, aqa), "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x28 == offsetof(struct spdk_nvme_registers, asq), "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x30 == offsetof(struct spdk_nvme_registers, acq), "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x38 == offsetof(struct spdk_nvme_registers, cmbloc),
+ "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x3C == offsetof(struct spdk_nvme_registers, cmbsz),
+ "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x40 == offsetof(struct spdk_nvme_registers, bpinfo),
+ "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x44 == offsetof(struct spdk_nvme_registers, bprsel),
+ "Incorrect register offset");
+SPDK_STATIC_ASSERT(0x48 == offsetof(struct spdk_nvme_registers, bpmbl),
+ "Incorrect register offset");
+
+enum spdk_nvme_sgl_descriptor_type {
+ SPDK_NVME_SGL_TYPE_DATA_BLOCK = 0x0,
+ SPDK_NVME_SGL_TYPE_BIT_BUCKET = 0x1,
+ SPDK_NVME_SGL_TYPE_SEGMENT = 0x2,
+ SPDK_NVME_SGL_TYPE_LAST_SEGMENT = 0x3,
+ SPDK_NVME_SGL_TYPE_KEYED_DATA_BLOCK = 0x4,
+ SPDK_NVME_SGL_TYPE_TRANSPORT_DATA_BLOCK = 0x5,
+ /* 0x6 - 0xE reserved */
+ SPDK_NVME_SGL_TYPE_VENDOR_SPECIFIC = 0xF
+};
+
+enum spdk_nvme_sgl_descriptor_subtype {
+ SPDK_NVME_SGL_SUBTYPE_ADDRESS = 0x0,
+ SPDK_NVME_SGL_SUBTYPE_OFFSET = 0x1,
+};
+
+struct __attribute__((packed)) spdk_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;
+ };
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_sgl_descriptor) == 16, "Incorrect size");
+
+enum spdk_nvme_psdt_value {
+ SPDK_NVME_PSDT_PRP = 0x0,
+ SPDK_NVME_PSDT_SGL_MPTR_CONTIG = 0x1,
+ SPDK_NVME_PSDT_SGL_MPTR_SGL = 0x2,
+ SPDK_NVME_PSDT_RESERVED = 0x3
+};
+
+/**
+ * Submission queue priority values for Create I/O Submission Queue Command.
+ *
+ * Only valid for weighted round robin arbitration method.
+ */
+enum spdk_nvme_qprio {
+ SPDK_NVME_QPRIO_URGENT = 0x0,
+ SPDK_NVME_QPRIO_HIGH = 0x1,
+ SPDK_NVME_QPRIO_MEDIUM = 0x2,
+ SPDK_NVME_QPRIO_LOW = 0x3
+};
+
+/**
+ * Optional Arbitration Mechanism Supported by the controller.
+ *
+ * Two bits for CAP.AMS (18:17) field are set to '1' when the controller supports.
+ * There is no bit for AMS_RR where all controllers support and set to 0x0 by default.
+ */
+enum spdk_nvme_cap_ams {
+ SPDK_NVME_CAP_AMS_WRR = 0x1, /**< weighted round robin */
+ SPDK_NVME_CAP_AMS_VS = 0x2, /**< vendor specific */
+};
+
+/**
+ * Arbitration Mechanism Selected to the controller.
+ *
+ * Value 0x2 to 0x6 is reserved.
+ */
+enum spdk_nvme_cc_ams {
+ SPDK_NVME_CC_AMS_RR = 0x0, /**< default round robin */
+ SPDK_NVME_CC_AMS_WRR = 0x1, /**< weighted round robin */
+ SPDK_NVME_CC_AMS_VS = 0x7, /**< vendor specific */
+};
+
+struct spdk_nvme_cmd {
+ /* dword 0 */
+ uint16_t opc : 8; /* opcode */
+ uint16_t fuse : 2; /* fused operation */
+ uint16_t rsvd1 : 4;
+ uint16_t psdt : 2;
+ uint16_t cid; /* command identifier */
+
+ /* dword 1 */
+ uint32_t nsid; /* namespace identifier */
+
+ /* dword 2-3 */
+ uint32_t rsvd2;
+ uint32_t rsvd3;
+
+ /* dword 4-5 */
+ uint64_t mptr; /* metadata pointer */
+
+ /* dword 6-9: data pointer */
+ union {
+ struct {
+ uint64_t prp1; /* prp entry 1 */
+ uint64_t prp2; /* prp entry 2 */
+ } prp;
+
+ struct spdk_nvme_sgl_descriptor sgl1;
+ } dptr;
+
+ /* dword 10-15 */
+ uint32_t cdw10; /* command-specific */
+ uint32_t cdw11; /* command-specific */
+ uint32_t cdw12; /* command-specific */
+ uint32_t cdw13; /* command-specific */
+ uint32_t cdw14; /* command-specific */
+ uint32_t cdw15; /* command-specific */
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_cmd) == 64, "Incorrect size");
+
+struct spdk_nvme_status {
+ uint16_t p : 1; /* phase tag */
+ uint16_t sc : 8; /* status code */
+ uint16_t sct : 3; /* status code type */
+ uint16_t rsvd2 : 2;
+ uint16_t m : 1; /* more */
+ uint16_t dnr : 1; /* do not retry */
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_status) == 2, "Incorrect size");
+
+/**
+ * Completion queue entry
+ */
+struct spdk_nvme_cpl {
+ /* dword 0 */
+ uint32_t cdw0; /* command-specific */
+
+ /* dword 1 */
+ uint32_t rsvd1;
+
+ /* dword 2 */
+ uint16_t sqhd; /* submission queue head pointer */
+ uint16_t sqid; /* submission queue identifier */
+
+ /* dword 3 */
+ uint16_t cid; /* command identifier */
+ struct spdk_nvme_status status;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_cpl) == 16, "Incorrect size");
+
+/**
+ * Dataset Management range
+ */
+struct spdk_nvme_dsm_range {
+ union {
+ struct {
+ uint32_t af : 4; /**< access frequencey */
+ uint32_t al : 2; /**< access latency */
+ uint32_t reserved0 : 2;
+
+ uint32_t sr : 1; /**< sequential read range */
+ uint32_t sw : 1; /**< sequential write range */
+ uint32_t wp : 1; /**< write prepare */
+ uint32_t reserved1 : 13;
+
+ uint32_t access_size : 8; /**< command access size */
+ } bits;
+
+ uint32_t raw;
+ } attributes;
+
+ uint32_t length;
+ uint64_t starting_lba;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_dsm_range) == 16, "Incorrect size");
+
+/**
+ * Status code types
+ */
+enum spdk_nvme_status_code_type {
+ SPDK_NVME_SCT_GENERIC = 0x0,
+ SPDK_NVME_SCT_COMMAND_SPECIFIC = 0x1,
+ SPDK_NVME_SCT_MEDIA_ERROR = 0x2,
+ SPDK_NVME_SCT_PATH = 0x3,
+ /* 0x4-0x6 - reserved */
+ SPDK_NVME_SCT_VENDOR_SPECIFIC = 0x7,
+};
+
+/**
+ * Generic command status codes
+ */
+enum spdk_nvme_generic_command_status_code {
+ SPDK_NVME_SC_SUCCESS = 0x00,
+ SPDK_NVME_SC_INVALID_OPCODE = 0x01,
+ SPDK_NVME_SC_INVALID_FIELD = 0x02,
+ SPDK_NVME_SC_COMMAND_ID_CONFLICT = 0x03,
+ SPDK_NVME_SC_DATA_TRANSFER_ERROR = 0x04,
+ SPDK_NVME_SC_ABORTED_POWER_LOSS = 0x05,
+ SPDK_NVME_SC_INTERNAL_DEVICE_ERROR = 0x06,
+ SPDK_NVME_SC_ABORTED_BY_REQUEST = 0x07,
+ SPDK_NVME_SC_ABORTED_SQ_DELETION = 0x08,
+ SPDK_NVME_SC_ABORTED_FAILED_FUSED = 0x09,
+ SPDK_NVME_SC_ABORTED_MISSING_FUSED = 0x0a,
+ SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT = 0x0b,
+ SPDK_NVME_SC_COMMAND_SEQUENCE_ERROR = 0x0c,
+ SPDK_NVME_SC_INVALID_SGL_SEG_DESCRIPTOR = 0x0d,
+ SPDK_NVME_SC_INVALID_NUM_SGL_DESCIRPTORS = 0x0e,
+ SPDK_NVME_SC_DATA_SGL_LENGTH_INVALID = 0x0f,
+ SPDK_NVME_SC_METADATA_SGL_LENGTH_INVALID = 0x10,
+ SPDK_NVME_SC_SGL_DESCRIPTOR_TYPE_INVALID = 0x11,
+ SPDK_NVME_SC_INVALID_CONTROLLER_MEM_BUF = 0x12,
+ SPDK_NVME_SC_INVALID_PRP_OFFSET = 0x13,
+ SPDK_NVME_SC_ATOMIC_WRITE_UNIT_EXCEEDED = 0x14,
+ SPDK_NVME_SC_OPERATION_DENIED = 0x15,
+ SPDK_NVME_SC_INVALID_SGL_OFFSET = 0x16,
+ /* 0x17 - reserved */
+ SPDK_NVME_SC_HOSTID_INCONSISTENT_FORMAT = 0x18,
+ SPDK_NVME_SC_KEEP_ALIVE_EXPIRED = 0x19,
+ SPDK_NVME_SC_KEEP_ALIVE_INVALID = 0x1a,
+ SPDK_NVME_SC_ABORTED_PREEMPT = 0x1b,
+ SPDK_NVME_SC_SANITIZE_FAILED = 0x1c,
+ SPDK_NVME_SC_SANITIZE_IN_PROGRESS = 0x1d,
+ SPDK_NVME_SC_SGL_DATA_BLOCK_GRANULARITY_INVALID = 0x1e,
+ SPDK_NVME_SC_COMMAND_INVALID_IN_CMB = 0x1f,
+
+ SPDK_NVME_SC_LBA_OUT_OF_RANGE = 0x80,
+ SPDK_NVME_SC_CAPACITY_EXCEEDED = 0x81,
+ SPDK_NVME_SC_NAMESPACE_NOT_READY = 0x82,
+ SPDK_NVME_SC_RESERVATION_CONFLICT = 0x83,
+ SPDK_NVME_SC_FORMAT_IN_PROGRESS = 0x84,
+};
+
+/**
+ * Command specific status codes
+ */
+enum spdk_nvme_command_specific_status_code {
+ SPDK_NVME_SC_COMPLETION_QUEUE_INVALID = 0x00,
+ SPDK_NVME_SC_INVALID_QUEUE_IDENTIFIER = 0x01,
+ SPDK_NVME_SC_MAXIMUM_QUEUE_SIZE_EXCEEDED = 0x02,
+ SPDK_NVME_SC_ABORT_COMMAND_LIMIT_EXCEEDED = 0x03,
+ /* 0x04 - reserved */
+ SPDK_NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED = 0x05,
+ SPDK_NVME_SC_INVALID_FIRMWARE_SLOT = 0x06,
+ SPDK_NVME_SC_INVALID_FIRMWARE_IMAGE = 0x07,
+ SPDK_NVME_SC_INVALID_INTERRUPT_VECTOR = 0x08,
+ SPDK_NVME_SC_INVALID_LOG_PAGE = 0x09,
+ SPDK_NVME_SC_INVALID_FORMAT = 0x0a,
+ SPDK_NVME_SC_FIRMWARE_REQ_CONVENTIONAL_RESET = 0x0b,
+ SPDK_NVME_SC_INVALID_QUEUE_DELETION = 0x0c,
+ SPDK_NVME_SC_FEATURE_ID_NOT_SAVEABLE = 0x0d,
+ SPDK_NVME_SC_FEATURE_NOT_CHANGEABLE = 0x0e,
+ SPDK_NVME_SC_FEATURE_NOT_NAMESPACE_SPECIFIC = 0x0f,
+ SPDK_NVME_SC_FIRMWARE_REQ_NVM_RESET = 0x10,
+ SPDK_NVME_SC_FIRMWARE_REQ_RESET = 0x11,
+ SPDK_NVME_SC_FIRMWARE_REQ_MAX_TIME_VIOLATION = 0x12,
+ SPDK_NVME_SC_FIRMWARE_ACTIVATION_PROHIBITED = 0x13,
+ SPDK_NVME_SC_OVERLAPPING_RANGE = 0x14,
+ SPDK_NVME_SC_NAMESPACE_INSUFFICIENT_CAPACITY = 0x15,
+ SPDK_NVME_SC_NAMESPACE_ID_UNAVAILABLE = 0x16,
+ /* 0x17 - reserved */
+ SPDK_NVME_SC_NAMESPACE_ALREADY_ATTACHED = 0x18,
+ SPDK_NVME_SC_NAMESPACE_IS_PRIVATE = 0x19,
+ SPDK_NVME_SC_NAMESPACE_NOT_ATTACHED = 0x1a,
+ SPDK_NVME_SC_THINPROVISIONING_NOT_SUPPORTED = 0x1b,
+ SPDK_NVME_SC_CONTROLLER_LIST_INVALID = 0x1c,
+ SPDK_NVME_SC_DEVICE_SELF_TEST_IN_PROGRESS = 0x1d,
+ SPDK_NVME_SC_BOOT_PARTITION_WRITE_PROHIBITED = 0x1e,
+ SPDK_NVME_SC_INVALID_CTRLR_ID = 0x1f,
+ SPDK_NVME_SC_INVALID_SECONDARY_CTRLR_STATE = 0x20,
+ SPDK_NVME_SC_INVALID_NUM_CTRLR_RESOURCES = 0x21,
+ SPDK_NVME_SC_INVALID_RESOURCE_ID = 0x22,
+
+ SPDK_NVME_SC_CONFLICTING_ATTRIBUTES = 0x80,
+ SPDK_NVME_SC_INVALID_PROTECTION_INFO = 0x81,
+ SPDK_NVME_SC_ATTEMPTED_WRITE_TO_RO_PAGE = 0x82,
+};
+
+/**
+ * Media error status codes
+ */
+enum spdk_nvme_media_error_status_code {
+ SPDK_NVME_SC_WRITE_FAULTS = 0x80,
+ SPDK_NVME_SC_UNRECOVERED_READ_ERROR = 0x81,
+ SPDK_NVME_SC_GUARD_CHECK_ERROR = 0x82,
+ SPDK_NVME_SC_APPLICATION_TAG_CHECK_ERROR = 0x83,
+ SPDK_NVME_SC_REFERENCE_TAG_CHECK_ERROR = 0x84,
+ SPDK_NVME_SC_COMPARE_FAILURE = 0x85,
+ SPDK_NVME_SC_ACCESS_DENIED = 0x86,
+ SPDK_NVME_SC_DEALLOCATED_OR_UNWRITTEN_BLOCK = 0x87,
+};
+
+/**
+ * Path related status codes
+ */
+enum spdk_nvme_path_status_code {
+ SPDK_NVME_SC_INTERNAL_PATH_ERROR = 0x00,
+
+ SPDK_NVME_SC_CONTROLLER_PATH_ERROR = 0x60,
+
+ SPDK_NVME_SC_HOST_PATH_ERROR = 0x70,
+ SPDK_NVME_SC_ABORTED_BY_HOST = 0x71,
+};
+
+/**
+ * Admin opcodes
+ */
+enum spdk_nvme_admin_opcode {
+ SPDK_NVME_OPC_DELETE_IO_SQ = 0x00,
+ SPDK_NVME_OPC_CREATE_IO_SQ = 0x01,
+ SPDK_NVME_OPC_GET_LOG_PAGE = 0x02,
+ /* 0x03 - reserved */
+ SPDK_NVME_OPC_DELETE_IO_CQ = 0x04,
+ SPDK_NVME_OPC_CREATE_IO_CQ = 0x05,
+ SPDK_NVME_OPC_IDENTIFY = 0x06,
+ /* 0x07 - reserved */
+ SPDK_NVME_OPC_ABORT = 0x08,
+ SPDK_NVME_OPC_SET_FEATURES = 0x09,
+ SPDK_NVME_OPC_GET_FEATURES = 0x0a,
+ /* 0x0b - reserved */
+ SPDK_NVME_OPC_ASYNC_EVENT_REQUEST = 0x0c,
+ SPDK_NVME_OPC_NS_MANAGEMENT = 0x0d,
+ /* 0x0e-0x0f - reserved */
+ SPDK_NVME_OPC_FIRMWARE_COMMIT = 0x10,
+ SPDK_NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD = 0x11,
+
+ SPDK_NVME_OPC_DEVICE_SELF_TEST = 0x14,
+ SPDK_NVME_OPC_NS_ATTACHMENT = 0x15,
+
+ SPDK_NVME_OPC_KEEP_ALIVE = 0x18,
+ SPDK_NVME_OPC_DIRECTIVE_SEND = 0x19,
+ SPDK_NVME_OPC_DIRECTIVE_RECEIVE = 0x1a,
+
+ SPDK_NVME_OPC_VIRTUALIZATION_MANAGEMENT = 0x1c,
+ SPDK_NVME_OPC_NVME_MI_SEND = 0x1d,
+ SPDK_NVME_OPC_NVME_MI_RECEIVE = 0x1e,
+
+ SPDK_NVME_OPC_DOORBELL_BUFFER_CONFIG = 0x7c,
+
+ SPDK_NVME_OPC_FORMAT_NVM = 0x80,
+ SPDK_NVME_OPC_SECURITY_SEND = 0x81,
+ SPDK_NVME_OPC_SECURITY_RECEIVE = 0x82,
+
+ SPDK_NVME_OPC_SANITIZE = 0x84,
+};
+
+/**
+ * NVM command set opcodes
+ */
+enum spdk_nvme_nvm_opcode {
+ SPDK_NVME_OPC_FLUSH = 0x00,
+ SPDK_NVME_OPC_WRITE = 0x01,
+ SPDK_NVME_OPC_READ = 0x02,
+ /* 0x03 - reserved */
+ SPDK_NVME_OPC_WRITE_UNCORRECTABLE = 0x04,
+ SPDK_NVME_OPC_COMPARE = 0x05,
+ /* 0x06-0x07 - reserved */
+ SPDK_NVME_OPC_WRITE_ZEROES = 0x08,
+ SPDK_NVME_OPC_DATASET_MANAGEMENT = 0x09,
+
+ SPDK_NVME_OPC_RESERVATION_REGISTER = 0x0d,
+ SPDK_NVME_OPC_RESERVATION_REPORT = 0x0e,
+
+ SPDK_NVME_OPC_RESERVATION_ACQUIRE = 0x11,
+ SPDK_NVME_OPC_RESERVATION_RELEASE = 0x15,
+};
+
+/**
+ * Data transfer (bits 1:0) of an NVMe opcode.
+ *
+ * \sa spdk_nvme_opc_get_data_transfer
+ */
+enum spdk_nvme_data_transfer {
+ /** Opcode does not transfer data */
+ SPDK_NVME_DATA_NONE = 0,
+ /** Opcode transfers data from host to controller (e.g. Write) */
+ SPDK_NVME_DATA_HOST_TO_CONTROLLER = 1,
+ /** Opcode transfers data from controller to host (e.g. Read) */
+ SPDK_NVME_DATA_CONTROLLER_TO_HOST = 2,
+ /** Opcode transfers data both directions */
+ SPDK_NVME_DATA_BIDIRECTIONAL = 3
+};
+
+/**
+ * Extract the Data Transfer bits from an NVMe opcode.
+ *
+ * This determines whether a command requires a data buffer and
+ * which direction (host to controller or controller to host) it is
+ * transferred.
+ */
+static inline enum spdk_nvme_data_transfer spdk_nvme_opc_get_data_transfer(uint8_t opc)
+{
+ return (enum spdk_nvme_data_transfer)(opc & 3);
+}
+
+enum spdk_nvme_feat {
+ /* 0x00 - reserved */
+
+ /** cdw11 layout defined by \ref spdk_nvme_feat_arbitration */
+ SPDK_NVME_FEAT_ARBITRATION = 0x01,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_power_management */
+ SPDK_NVME_FEAT_POWER_MANAGEMENT = 0x02,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_lba_range_type */
+ SPDK_NVME_FEAT_LBA_RANGE_TYPE = 0x03,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_temperature_threshold */
+ SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD = 0x04,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_error_recovery */
+ SPDK_NVME_FEAT_ERROR_RECOVERY = 0x05,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_volatile_write_cache */
+ SPDK_NVME_FEAT_VOLATILE_WRITE_CACHE = 0x06,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_number_of_queues */
+ SPDK_NVME_FEAT_NUMBER_OF_QUEUES = 0x07,
+ SPDK_NVME_FEAT_INTERRUPT_COALESCING = 0x08,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_interrupt_vector_configuration */
+ SPDK_NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION = 0x09,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_write_atomicity */
+ SPDK_NVME_FEAT_WRITE_ATOMICITY = 0x0A,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_async_event_configuration */
+ SPDK_NVME_FEAT_ASYNC_EVENT_CONFIGURATION = 0x0B,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_autonomous_power_state_transition */
+ SPDK_NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION = 0x0C,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_host_mem_buffer */
+ SPDK_NVME_FEAT_HOST_MEM_BUFFER = 0x0D,
+ SPDK_NVME_FEAT_TIMESTAMP = 0x0E,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_keep_alive_timer */
+ SPDK_NVME_FEAT_KEEP_ALIVE_TIMER = 0x0F,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_host_controlled_thermal_management */
+ SPDK_NVME_FEAT_HOST_CONTROLLED_THERMAL_MANAGEMENT = 0x10,
+ /** cdw11 layout defined by \ref spdk_nvme_feat_non_operational_power_state_config */
+ SPDK_NVME_FEAT_NON_OPERATIONAL_POWER_STATE_CONFIG = 0x11,
+
+ /* 0x12-0x77 - reserved */
+
+ /* 0x78-0x7F - NVMe-MI features */
+
+ /** cdw11 layout defined by \ref spdk_nvme_feat_software_progress_marker */
+ SPDK_NVME_FEAT_SOFTWARE_PROGRESS_MARKER = 0x80,
+
+ /** cdw11 layout defined by \ref spdk_nvme_feat_host_identifier */
+ SPDK_NVME_FEAT_HOST_IDENTIFIER = 0x81,
+ SPDK_NVME_FEAT_HOST_RESERVE_MASK = 0x82,
+ SPDK_NVME_FEAT_HOST_RESERVE_PERSIST = 0x83,
+
+ /* 0x84-0xBF - command set specific (reserved) */
+
+ /* 0xC0-0xFF - vendor specific */
+};
+
+/** Bit set of attributes for DATASET MANAGEMENT commands. */
+enum spdk_nvme_dsm_attribute {
+ SPDK_NVME_DSM_ATTR_INTEGRAL_READ = 0x1,
+ SPDK_NVME_DSM_ATTR_INTEGRAL_WRITE = 0x2,
+ SPDK_NVME_DSM_ATTR_DEALLOCATE = 0x4,
+};
+
+struct spdk_nvme_power_state {
+ uint16_t mp; /* bits 15:00: maximum power */
+
+ uint8_t reserved1;
+
+ uint8_t mps : 1; /* bit 24: max power scale */
+ uint8_t nops : 1; /* bit 25: non-operational state */
+ uint8_t reserved2 : 6;
+
+ uint32_t enlat; /* bits 63:32: entry latency in microseconds */
+ uint32_t exlat; /* bits 95:64: exit latency in microseconds */
+
+ uint8_t rrt : 5; /* bits 100:96: relative read throughput */
+ uint8_t reserved3 : 3;
+
+ uint8_t rrl : 5; /* bits 108:104: relative read latency */
+ uint8_t reserved4 : 3;
+
+ uint8_t rwt : 5; /* bits 116:112: relative write throughput */
+ uint8_t reserved5 : 3;
+
+ uint8_t rwl : 5; /* bits 124:120: relative write latency */
+ uint8_t reserved6 : 3;
+
+ uint8_t reserved7[16];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_power_state) == 32, "Incorrect size");
+
+/** Identify command CNS value */
+enum spdk_nvme_identify_cns {
+ /** Identify namespace indicated in CDW1.NSID */
+ SPDK_NVME_IDENTIFY_NS = 0x00,
+
+ /** Identify controller */
+ SPDK_NVME_IDENTIFY_CTRLR = 0x01,
+
+ /** List active NSIDs greater than CDW1.NSID */
+ SPDK_NVME_IDENTIFY_ACTIVE_NS_LIST = 0x02,
+
+ /** List namespace identification descriptors */
+ SPDK_NVME_IDENTIFY_NS_ID_DESCRIPTOR_LIST = 0x03,
+
+ /** List allocated NSIDs greater than CDW1.NSID */
+ SPDK_NVME_IDENTIFY_ALLOCATED_NS_LIST = 0x10,
+
+ /** Identify namespace if CDW1.NSID is allocated */
+ SPDK_NVME_IDENTIFY_NS_ALLOCATED = 0x11,
+
+ /** Get list of controllers starting at CDW10.CNTID that are attached to CDW1.NSID */
+ SPDK_NVME_IDENTIFY_NS_ATTACHED_CTRLR_LIST = 0x12,
+
+ /** Get list of controllers starting at CDW10.CNTID */
+ SPDK_NVME_IDENTIFY_CTRLR_LIST = 0x13,
+
+ /** Get primary controller capabilities structure */
+ SPDK_NVME_IDENTIFY_PRIMARY_CTRLR_CAP = 0x14,
+
+ /** Get secondary controller list */
+ SPDK_NVME_IDENTIFY_SECONDARY_CTRLR_LIST = 0x15,
+};
+
+/** NVMe over Fabrics controller model */
+enum spdk_nvmf_ctrlr_model {
+ /** NVM subsystem uses dynamic controller model */
+ SPDK_NVMF_CTRLR_MODEL_DYNAMIC = 0,
+
+ /** NVM subsystem uses static controller model */
+ SPDK_NVMF_CTRLR_MODEL_STATIC = 1,
+};
+
+#define SPDK_NVME_CTRLR_SN_LEN 20
+#define SPDK_NVME_CTRLR_MN_LEN 40
+#define SPDK_NVME_CTRLR_FR_LEN 8
+
+/** Identify Controller data sgls.supported values */
+enum spdk_nvme_sgls_supported {
+ /** SGLs are not supported */
+ SPDK_NVME_SGLS_NOT_SUPPORTED = 0,
+
+ /** SGLs are supported with no alignment or granularity requirement. */
+ SPDK_NVME_SGLS_SUPPORTED = 1,
+
+ /** SGLs are supported with a DWORD alignment and granularity requirement. */
+ SPDK_NVME_SGLS_SUPPORTED_DWORD_ALIGNED = 2,
+};
+
+/** Identify Controller data vwc.flush_broadcast values */
+enum spdk_nvme_flush_broadcast {
+ /** Support for NSID=FFFFFFFFh with Flush is not indicated. */
+ SPDK_NVME_FLUSH_BROADCAST_NOT_INDICATED = 0,
+
+ /* 01b: Reserved */
+
+ /** Flush does not support NSID set to FFFFFFFFh. */
+ SPDK_NVME_FLUSH_BROADCAST_NOT_SUPPORTED = 2,
+
+ /** Flush supports NSID set to FFFFFFFFh. */
+ SPDK_NVME_FLUSH_BROADCAST_SUPPORTED = 3
+};
+
+struct __attribute__((packed)) spdk_nvme_ctrlr_data {
+ /* bytes 0-255: controller capabilities and features */
+
+ /** pci vendor id */
+ uint16_t vid;
+
+ /** pci subsystem vendor id */
+ uint16_t ssvid;
+
+ /** serial number */
+ int8_t sn[SPDK_NVME_CTRLR_SN_LEN];
+
+ /** model number */
+ int8_t mn[SPDK_NVME_CTRLR_MN_LEN];
+
+ /** firmware revision */
+ uint8_t fr[SPDK_NVME_CTRLR_FR_LEN];
+
+ /** recommended arbitration burst */
+ uint8_t rab;
+
+ /** ieee oui identifier */
+ uint8_t ieee[3];
+
+ /** controller multi-path I/O and namespace sharing capabilities */
+ struct {
+ uint8_t multi_port : 1;
+ uint8_t multi_host : 1;
+ uint8_t sr_iov : 1;
+ uint8_t reserved : 5;
+ } cmic;
+
+ /** maximum data transfer size */
+ uint8_t mdts;
+
+ /** controller id */
+ uint16_t cntlid;
+
+ /** version */
+ union spdk_nvme_vs_register ver;
+
+ /** RTD3 resume latency */
+ uint32_t rtd3r;
+
+ /** RTD3 entry latency */
+ uint32_t rtd3e;
+
+ /** optional asynchronous events supported */
+ struct {
+ uint32_t reserved1 : 8;
+
+ /** Supports sending Namespace Attribute Notices. */
+ uint32_t ns_attribute_notices : 1;
+
+ /** Supports sending Firmware Activation Notices. */
+ uint32_t fw_activation_notices : 1;
+
+ uint32_t reserved2 : 22;
+ } oaes;
+
+ /** controller attributes */
+ struct {
+ /** Supports 128-bit host identifier */
+ uint32_t host_id_exhid_supported: 1;
+
+ /** Supports non-operational power state permissive mode */
+ uint32_t non_operational_power_state_permissive_mode: 1;
+
+ uint32_t reserved: 30;
+ } ctratt;
+
+ uint8_t reserved_100[12];
+
+ /** FRU globally unique identifier */
+ uint8_t fguid[16];
+
+ uint8_t reserved_128[128];
+
+ /* bytes 256-511: admin command set attributes */
+
+ /** optional admin command support */
+ struct {
+ /* supports security send/receive commands */
+ uint16_t security : 1;
+
+ /* supports format nvm command */
+ uint16_t format : 1;
+
+ /* supports firmware activate/download commands */
+ uint16_t firmware : 1;
+
+ /* supports ns manage/ns attach commands */
+ uint16_t ns_manage : 1;
+
+ /** Supports device self-test command (SPDK_NVME_OPC_DEVICE_SELF_TEST) */
+ uint16_t device_self_test : 1;
+
+ /** Supports SPDK_NVME_OPC_DIRECTIVE_SEND and SPDK_NVME_OPC_DIRECTIVE_RECEIVE */
+ uint16_t directives : 1;
+
+ /** Supports NVMe-MI (SPDK_NVME_OPC_NVME_MI_SEND, SPDK_NVME_OPC_NVME_MI_RECEIVE) */
+ uint16_t nvme_mi : 1;
+
+ /** Supports SPDK_NVME_OPC_VIRTUALIZATION_MANAGEMENT */
+ uint16_t virtualization_management : 1;
+
+ /** Supports SPDK_NVME_OPC_DOORBELL_BUFFER_CONFIG */
+ uint16_t doorbell_buffer_config : 1;
+
+ uint16_t oacs_rsvd : 7;
+ } oacs;
+
+ /** abort command limit */
+ uint8_t acl;
+
+ /** asynchronous event request limit */
+ uint8_t aerl;
+
+ /** firmware updates */
+ struct {
+ /* first slot is read-only */
+ uint8_t slot1_ro : 1;
+
+ /* number of firmware slots */
+ uint8_t num_slots : 3;
+
+ /* support activation without reset */
+ uint8_t activation_without_reset : 1;
+
+ uint8_t frmw_rsvd : 3;
+ } frmw;
+
+ /** log page attributes */
+ struct {
+ /* per namespace smart/health log page */
+ uint8_t ns_smart : 1;
+ /* command effects log page */
+ uint8_t celp : 1;
+ /* extended data for get log page */
+ uint8_t edlp: 1;
+ /** telemetry log pages and notices */
+ uint8_t telemetry : 1;
+ uint8_t lpa_rsvd : 4;
+ } lpa;
+
+ /** error log page entries */
+ uint8_t elpe;
+
+ /** number of power states supported */
+ uint8_t npss;
+
+ /** admin vendor specific command configuration */
+ struct {
+ /* admin vendor specific commands use disk format */
+ uint8_t spec_format : 1;
+
+ uint8_t avscc_rsvd : 7;
+ } avscc;
+
+ /** autonomous power state transition attributes */
+ struct {
+ /** controller supports autonomous power state transitions */
+ uint8_t supported : 1;
+
+ uint8_t apsta_rsvd : 7;
+ } apsta;
+
+ /** warning composite temperature threshold */
+ uint16_t wctemp;
+
+ /** critical composite temperature threshold */
+ uint16_t cctemp;
+
+ /** maximum time for firmware activation */
+ uint16_t mtfa;
+
+ /** host memory buffer preferred size */
+ uint32_t hmpre;
+
+ /** host memory buffer minimum size */
+ uint32_t hmmin;
+
+ /** total NVM capacity */
+ uint64_t tnvmcap[2];
+
+ /** unallocated NVM capacity */
+ uint64_t unvmcap[2];
+
+ /** replay protected memory block support */
+ 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;
+
+ /** extended device self-test time (in minutes) */
+ uint16_t edstt;
+
+ /** device self-test options */
+ union {
+ uint8_t raw;
+ struct {
+ /** Device supports only one device self-test operation at a time */
+ uint8_t one_only : 1;
+
+ uint8_t reserved : 7;
+ } bits;
+ } dsto;
+
+ /**
+ * Firmware update granularity
+ *
+ * 4KB units
+ * 0x00 = no information provided
+ * 0xFF = no restriction
+ */
+ uint8_t fwug;
+
+ /**
+ * Keep Alive Support
+ *
+ * Granularity of keep alive timer in 100 ms units
+ * 0 = keep alive not supported
+ */
+ uint16_t kas;
+
+ /** Host controlled thermal management attributes */
+ union {
+ uint16_t raw;
+ struct {
+ uint16_t supported : 1;
+ uint16_t reserved : 15;
+ } bits;
+ } hctma;
+
+ /** Minimum thermal management temperature */
+ uint16_t mntmt;
+
+ /** Maximum thermal management temperature */
+ uint16_t mxtmt;
+
+ /** Sanitize capabilities */
+ union {
+ uint32_t raw;
+ struct {
+ uint32_t crypto_erase : 1;
+ uint32_t block_erase : 1;
+ uint32_t overwrite : 1;
+ uint32_t reserved : 29;
+ } bits;
+ } sanicap;
+
+ uint8_t reserved3[180];
+
+ /* bytes 512-703: nvm command set attributes */
+
+ /** submission queue entry size */
+ struct {
+ uint8_t min : 4;
+ uint8_t max : 4;
+ } sqes;
+
+ /** completion queue entry size */
+ struct {
+ uint8_t min : 4;
+ uint8_t max : 4;
+ } cqes;
+
+ uint16_t maxcmd;
+
+ /** number of namespaces */
+ uint32_t nn;
+
+ /** optional nvm command support */
+ 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 timestamp: 1;
+ uint16_t reserved: 9;
+ } oncs;
+
+ /** fused operation support */
+ uint16_t fuses;
+
+ /** format nvm attributes */
+ struct {
+ uint8_t format_all_ns: 1;
+ uint8_t erase_all_ns: 1;
+ uint8_t crypto_erase_supported: 1;
+ uint8_t reserved: 5;
+ } fna;
+
+ /** volatile write cache */
+ struct {
+ uint8_t present : 1;
+ uint8_t flush_broadcast : 2;
+ uint8_t reserved : 5;
+ } vwc;
+
+ /** atomic write unit normal */
+ uint16_t awun;
+
+ /** atomic write unit power fail */
+ uint16_t awupf;
+
+ /** NVM vendor specific command configuration */
+ uint8_t nvscc;
+
+ uint8_t reserved531;
+
+ /** atomic compare & write unit */
+ uint16_t acwu;
+
+ uint16_t reserved534;
+
+ /** SGL support */
+ struct {
+ uint32_t supported : 2;
+ 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 transport_sgl : 1;
+ uint32_t reserved2 : 10;
+ } sgls;
+
+ uint8_t reserved4[228];
+
+ uint8_t subnqn[256];
+
+ uint8_t reserved5[768];
+
+ /** NVMe over Fabrics-specific fields */
+ struct {
+ /** I/O queue command capsule supported size (16-byte units) */
+ uint32_t ioccsz;
+
+ /** I/O queue response capsule supported size (16-byte units) */
+ uint32_t iorcsz;
+
+ /** In-capsule data offset (16-byte units) */
+ uint16_t icdoff;
+
+ /** Controller attributes */
+ struct {
+ /** Controller model: \ref spdk_nvmf_ctrlr_model */
+ uint8_t ctrlr_model : 1;
+ uint8_t reserved : 7;
+ } ctrattr;
+
+ /** Maximum SGL block descriptors (0 = no limit) */
+ uint8_t msdbd;
+
+ uint8_t reserved[244];
+ } nvmf_specific;
+
+ /* bytes 2048-3071: power state descriptors */
+ struct spdk_nvme_power_state psd[32];
+
+ /* bytes 3072-4095: vendor specific */
+ uint8_t vs[1024];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_ctrlr_data) == 4096, "Incorrect size");
+
+struct __attribute__((packed)) spdk_nvme_primary_ctrl_capabilities {
+ /** controller id */
+ uint16_t cntlid;
+ /** port identifier */
+ uint16_t portid;
+ /** controller resource types */
+ struct {
+ uint8_t vq_supported : 1;
+ uint8_t vi_supported : 1;
+ uint8_t reserved : 6;
+ } crt;
+ uint8_t reserved[27];
+ /** total number of VQ flexible resources */
+ uint32_t vqfrt;
+ /** total number of VQ flexible resources assigned to secondary controllers */
+ uint32_t vqrfa;
+ /** total number of VQ flexible resources allocated to primary controller */
+ uint16_t vqrfap;
+ /** total number of VQ Private resources for the primary controller */
+ uint16_t vqprt;
+ /** max number of VQ flexible Resources that may be assigned to a secondary controller */
+ uint16_t vqfrsm;
+ /** preferred granularity of assigning and removing VQ Flexible Resources */
+ uint16_t vqgran;
+ uint8_t reserved1[16];
+ /** total number of VI flexible resources for the primary and its secondary controllers */
+ uint32_t vifrt;
+ /** total number of VI flexible resources assigned to the secondary controllers */
+ uint32_t virfa;
+ /** total number of VI flexible resources currently allocated to the primary controller */
+ uint16_t virfap;
+ /** total number of VI private resources for the primary controller */
+ uint16_t viprt;
+ /** max number of VI flexible resources that may be assigned to a secondary controller */
+ uint16_t vifrsm;
+ /** preferred granularity of assigning and removing VI flexible resources */
+ uint16_t vigran;
+ uint8_t reserved2[4016];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_primary_ctrl_capabilities) == 4096, "Incorrect size");
+
+struct __attribute__((packed)) spdk_nvme_secondary_ctrl_entry {
+ /** controller identifier of the secondary controller */
+ uint16_t scid;
+ /** controller identifier of the associated primary controller */
+ uint16_t pcid;
+ /** indicates the state of the secondary controller */
+ struct {
+ uint8_t is_online : 1;
+ uint8_t reserved : 7;
+ } scs;
+ uint8_t reserved[3];
+ /** VF number if the secondary controller is an SR-IOV VF */
+ uint16_t vfn;
+ /** number of VQ flexible resources assigned to the indicated secondary controller */
+ uint16_t nvq;
+ /** number of VI flexible resources assigned to the indicated secondary controller */
+ uint16_t nvi;
+ uint8_t reserved1[18];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_secondary_ctrl_entry) == 32, "Incorrect size");
+
+struct __attribute__((packed)) spdk_nvme_secondary_ctrl_list {
+ /** number of Secondary controller entries in the list */
+ uint8_t number;
+ uint8_t reserved[31];
+ struct spdk_nvme_secondary_ctrl_entry entries[127];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_secondary_ctrl_list) == 4096, "Incorrect size");
+
+struct spdk_nvme_ns_data {
+ /** namespace size */
+ uint64_t nsze;
+
+ /** namespace capacity */
+ uint64_t ncap;
+
+ /** namespace utilization */
+ uint64_t nuse;
+
+ /** namespace features */
+ struct {
+ /** thin provisioning */
+ uint8_t thin_prov : 1;
+
+ /** NAWUN, NAWUPF, and NACWU are defined for this namespace */
+ uint8_t ns_atomic_write_unit : 1;
+
+ /** Supports Deallocated or Unwritten LBA error for this namespace */
+ uint8_t dealloc_or_unwritten_error : 1;
+
+ /** Non-zero NGUID and EUI64 for namespace are never reused */
+ uint8_t guid_never_reused : 1;
+
+ uint8_t reserved1 : 4;
+ } nsfeat;
+
+ /** number of lba formats */
+ uint8_t nlbaf;
+
+ /** formatted lba size */
+ struct {
+ uint8_t format : 4;
+ uint8_t extended : 1;
+ uint8_t reserved2 : 3;
+ } flbas;
+
+ /** metadata capabilities */
+ struct {
+ /** metadata can be transferred as part of data prp list */
+ uint8_t extended : 1;
+
+ /** metadata can be transferred with separate metadata pointer */
+ uint8_t pointer : 1;
+
+ /** reserved */
+ uint8_t reserved3 : 6;
+ } mc;
+
+ /** end-to-end data protection capabilities */
+ struct {
+ /** protection information type 1 */
+ uint8_t pit1 : 1;
+
+ /** protection information type 2 */
+ uint8_t pit2 : 1;
+
+ /** protection information type 3 */
+ uint8_t pit3 : 1;
+
+ /** first eight bytes of metadata */
+ uint8_t md_start : 1;
+
+ /** last eight bytes of metadata */
+ uint8_t md_end : 1;
+ } dpc;
+
+ /** end-to-end data protection type settings */
+ struct {
+ /** protection information type */
+ uint8_t pit : 3;
+
+ /** 1 == protection info transferred at start of metadata */
+ /** 0 == protection info transferred at end of metadata */
+ uint8_t md_start : 1;
+
+ uint8_t reserved4 : 4;
+ } dps;
+
+ /** namespace multi-path I/O and namespace sharing capabilities */
+ struct {
+ uint8_t can_share : 1;
+ uint8_t reserved : 7;
+ } nmic;
+
+ /** reservation capabilities */
+ union {
+ struct {
+ /** supports persist through power loss */
+ uint8_t persist : 1;
+
+ /** supports write exclusive */
+ uint8_t write_exclusive : 1;
+
+ /** supports exclusive access */
+ uint8_t exclusive_access : 1;
+
+ /** supports write exclusive - registrants only */
+ uint8_t write_exclusive_reg_only : 1;
+
+ /** supports exclusive access - registrants only */
+ uint8_t exclusive_access_reg_only : 1;
+
+ /** supports write exclusive - all registrants */
+ uint8_t write_exclusive_all_reg : 1;
+
+ /** supports exclusive access - all registrants */
+ uint8_t exclusive_access_all_reg : 1;
+
+ /** supports ignore existing key */
+ uint8_t ignore_existing_key : 1;
+ } rescap;
+ uint8_t raw;
+ } nsrescap;
+ /** format progress indicator */
+ struct {
+ uint8_t percentage_remaining : 7;
+ uint8_t fpi_supported : 1;
+ } fpi;
+
+ /** deallocate logical features */
+ union {
+ uint8_t raw;
+ struct {
+ /**
+ * Value read from deallocated blocks
+ *
+ * 000b = not reported
+ * 001b = all bytes 0x00
+ * 010b = all bytes 0xFF
+ *
+ * \ref spdk_nvme_dealloc_logical_block_read_value
+ */
+ uint8_t read_value : 3;
+
+ /** Supports Deallocate bit in Write Zeroes */
+ uint8_t write_zero_deallocate : 1;
+
+ /**
+ * Guard field behavior for deallocated logical blocks
+ * 0: contains 0xFFFF
+ * 1: contains CRC for read value
+ */
+ uint8_t guard_value : 1;
+
+ uint8_t reserved : 3;
+ } bits;
+ } dlfeat;
+
+ /** namespace atomic write unit normal */
+ uint16_t nawun;
+
+ /** namespace atomic write unit power fail */
+ uint16_t nawupf;
+
+ /** namespace atomic compare & write unit */
+ uint16_t nacwu;
+
+ /** namespace atomic boundary size normal */
+ uint16_t nabsn;
+
+ /** namespace atomic boundary offset */
+ uint16_t nabo;
+
+ /** namespace atomic boundary size power fail */
+ uint16_t nabspf;
+
+ /** namespace optimal I/O boundary in logical blocks */
+ uint16_t noiob;
+
+ /** NVM capacity */
+ uint64_t nvmcap[2];
+
+ uint8_t reserved64[40];
+
+ /** namespace globally unique identifier */
+ uint8_t nguid[16];
+
+ /** IEEE extended unique identifier */
+ uint64_t eui64;
+
+ /** lba format support */
+ struct {
+ /** metadata size */
+ uint32_t ms : 16;
+
+ /** lba data size */
+ uint32_t lbads : 8;
+
+ /** relative performance */
+ uint32_t rp : 2;
+
+ uint32_t reserved6 : 6;
+ } lbaf[16];
+
+ uint8_t reserved6[192];
+
+ uint8_t vendor_specific[3712];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_ns_data) == 4096, "Incorrect size");
+
+/**
+ * Deallocated logical block features - read value
+ */
+enum spdk_nvme_dealloc_logical_block_read_value {
+ /** Not reported */
+ SPDK_NVME_DEALLOC_NOT_REPORTED = 0,
+
+ /** Deallocated blocks read 0x00 */
+ SPDK_NVME_DEALLOC_READ_00 = 1,
+
+ /** Deallocated blocks read 0xFF */
+ SPDK_NVME_DEALLOC_READ_FF = 2,
+};
+
+/**
+ * Reservation Type Encoding
+ */
+enum spdk_nvme_reservation_type {
+ /* 0x00 - reserved */
+
+ /* Write Exclusive Reservation */
+ SPDK_NVME_RESERVE_WRITE_EXCLUSIVE = 0x1,
+
+ /* Exclusive Access Reservation */
+ SPDK_NVME_RESERVE_EXCLUSIVE_ACCESS = 0x2,
+
+ /* Write Exclusive - Registrants Only Reservation */
+ SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY = 0x3,
+
+ /* Exclusive Access - Registrants Only Reservation */
+ SPDK_NVME_RESERVE_EXCLUSIVE_ACCESS_REG_ONLY = 0x4,
+
+ /* Write Exclusive - All Registrants Reservation */
+ SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS = 0x5,
+
+ /* Exclusive Access - All Registrants Reservation */
+ SPDK_NVME_RESERVE_EXCLUSIVE_ACCESS_ALL_REGS = 0x6,
+
+ /* 0x7-0xFF - Reserved */
+};
+
+struct spdk_nvme_reservation_acquire_data {
+ /** current reservation key */
+ uint64_t crkey;
+ /** preempt reservation key */
+ uint64_t prkey;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_reservation_acquire_data) == 16, "Incorrect size");
+
+/**
+ * Reservation Acquire action
+ */
+enum spdk_nvme_reservation_acquire_action {
+ SPDK_NVME_RESERVE_ACQUIRE = 0x0,
+ SPDK_NVME_RESERVE_PREEMPT = 0x1,
+ SPDK_NVME_RESERVE_PREEMPT_ABORT = 0x2,
+};
+
+struct __attribute__((packed)) spdk_nvme_reservation_status_data {
+ /** reservation action generation counter */
+ uint32_t generation;
+ /** reservation type */
+ uint8_t type;
+ /** number of registered controllers */
+ uint16_t nr_regctl;
+ uint16_t reserved1;
+ /** persist through power loss state */
+ uint8_t ptpl_state;
+ uint8_t reserved[14];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_reservation_status_data) == 24, "Incorrect size");
+
+struct __attribute__((packed)) spdk_nvme_reservation_ctrlr_data {
+ uint16_t ctrlr_id;
+ /** reservation status */
+ struct {
+ uint8_t status : 1;
+ uint8_t reserved1 : 7;
+ } rcsts;
+ uint8_t reserved2[5];
+ /** host identifier */
+ uint64_t host_id;
+ /** reservation key */
+ uint64_t key;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_reservation_ctrlr_data) == 24, "Incorrect size");
+
+/**
+ * Change persist through power loss state for
+ * Reservation Register command
+ */
+enum spdk_nvme_reservation_register_cptpl {
+ SPDK_NVME_RESERVE_PTPL_NO_CHANGES = 0x0,
+ SPDK_NVME_RESERVE_PTPL_CLEAR_POWER_ON = 0x2,
+ SPDK_NVME_RESERVE_PTPL_PERSIST_POWER_LOSS = 0x3,
+};
+
+/**
+ * Registration action for Reservation Register command
+ */
+enum spdk_nvme_reservation_register_action {
+ SPDK_NVME_RESERVE_REGISTER_KEY = 0x0,
+ SPDK_NVME_RESERVE_UNREGISTER_KEY = 0x1,
+ SPDK_NVME_RESERVE_REPLACE_KEY = 0x2,
+};
+
+struct spdk_nvme_reservation_register_data {
+ /** current reservation key */
+ uint64_t crkey;
+ /** new reservation key */
+ uint64_t nrkey;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_reservation_register_data) == 16, "Incorrect size");
+
+struct spdk_nvme_reservation_key_data {
+ /** current reservation key */
+ uint64_t crkey;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_reservation_key_data) == 8, "Incorrect size");
+
+/**
+ * Reservation Release action
+ */
+enum spdk_nvme_reservation_release_action {
+ SPDK_NVME_RESERVE_RELEASE = 0x0,
+ SPDK_NVME_RESERVE_CLEAR = 0x1,
+};
+
+/**
+ * Log page identifiers for SPDK_NVME_OPC_GET_LOG_PAGE
+ */
+enum spdk_nvme_log_page {
+ /* 0x00 - reserved */
+
+ /** Error information (mandatory) - \ref spdk_nvme_error_information_entry */
+ SPDK_NVME_LOG_ERROR = 0x01,
+
+ /** SMART / health information (mandatory) - \ref spdk_nvme_health_information_page */
+ SPDK_NVME_LOG_HEALTH_INFORMATION = 0x02,
+
+ /** Firmware slot information (mandatory) - \ref spdk_nvme_firmware_page */
+ SPDK_NVME_LOG_FIRMWARE_SLOT = 0x03,
+
+ /** Changed namespace list (optional) */
+ SPDK_NVME_LOG_CHANGED_NS_LIST = 0x04,
+
+ /** Command effects log (optional) */
+ SPDK_NVME_LOG_COMMAND_EFFECTS_LOG = 0x05,
+
+ /* 0x06-0x6F - reserved */
+
+ /** Discovery(refer to the NVMe over Fabrics specification) */
+ SPDK_NVME_LOG_DISCOVERY = 0x70,
+
+ /* 0x71-0x7f - reserved for NVMe over Fabrics */
+
+ /** Reservation notification (optional) */
+ SPDK_NVME_LOG_RESERVATION_NOTIFICATION = 0x80,
+
+ /* 0x81-0xBF - I/O command set specific */
+
+ /* 0xC0-0xFF - vendor specific */
+};
+
+/**
+ * Error information log page (\ref SPDK_NVME_LOG_ERROR)
+ */
+struct spdk_nvme_error_information_entry {
+ uint64_t error_count;
+ uint16_t sqid;
+ uint16_t cid;
+ struct spdk_nvme_status status;
+ uint16_t error_location;
+ uint64_t lba;
+ uint32_t nsid;
+ uint8_t vendor_specific;
+ uint8_t trtype;
+ uint8_t reserved30[2];
+ uint64_t command_specific;
+ uint16_t trtype_specific;
+ uint8_t reserved42[22];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_error_information_entry) == 64, "Incorrect size");
+
+union spdk_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;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_critical_warning_state) == 1, "Incorrect size");
+
+/**
+ * SMART / health information page (\ref SPDK_NVME_LOG_HEALTH_INFORMATION)
+ */
+struct __attribute__((packed)) spdk_nvme_health_information_page {
+ union spdk_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];
+
+ /*
+ * Note that the following are 128-bit values, but are
+ * defined as an array of 2 64-bit values.
+ */
+ /* Data Units Read is always in 512-byte units. */
+ uint64_t data_units_read[2];
+ /* Data Units Written is always in 512-byte units. */
+ uint64_t data_units_written[2];
+ /* For NVM command set, this includes Compare commands. */
+ uint64_t host_read_commands[2];
+ uint64_t host_write_commands[2];
+ /* Controller Busy Time is reported in minutes. */
+ 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];
+ /* Controller temperature related. */
+ uint32_t warning_temp_time;
+ uint32_t critical_temp_time;
+ uint16_t temp_sensor[8];
+
+ uint8_t reserved2[296];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_health_information_page) == 512, "Incorrect size");
+
+/* Commands Supported and Effects Data Structure */
+struct spdk_nvme_cmds_and_effect_entry {
+ /** Command Supported */
+ uint16_t csupp : 1;
+
+ /** Logic Block Content Change */
+ uint16_t lbcc : 1;
+
+ /** Namespace Capability Change */
+ uint16_t ncc : 1;
+
+ /** Namespace Inventory Change */
+ uint16_t nic : 1;
+
+ /** Controller Capability Change */
+ uint16_t ccc : 1;
+
+ uint16_t reserved1 : 11;
+
+ /* Command Submission and Execution recommendation
+ * 000 - No command submission or execution restriction
+ * 001 - Submitted when there is no outstanding command to same NS
+ * 010 - Submitted when there is no outstanding command to any NS
+ * others - Reserved
+ * \ref command_submission_and_execution in section 5.14.1.5 NVMe Revision 1.3
+ */
+ uint16_t cse : 3;
+
+ uint16_t reserved2 : 13;
+};
+
+/* Commands Supported and Effects Log Page */
+struct spdk_nvme_cmds_and_effect_log_page {
+ /** Commands Supported and Effects Data Structure for the Admin Commands */
+ struct spdk_nvme_cmds_and_effect_entry admin_cmds_supported[256];
+
+ /** Commands Supported and Effects Data Structure for the IO Commands */
+ struct spdk_nvme_cmds_and_effect_entry io_cmds_supported[256];
+
+ uint8_t reserved0[2048];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_cmds_and_effect_log_page) == 4096, "Incorrect size");
+
+/**
+ * Asynchronous Event Type
+ */
+enum spdk_nvme_async_event_type {
+ /* Error Status */
+ SPDK_NVME_ASYNC_EVENT_TYPE_ERROR = 0x0,
+ /* SMART/Health Status */
+ SPDK_NVME_ASYNC_EVENT_TYPE_SMART = 0x1,
+ /* Notice */
+ SPDK_NVME_ASYNC_EVENT_TYPE_NOTICE = 0x2,
+ /* 0x3 - 0x5 Reserved */
+
+ /* I/O Command Set Specific Status */
+ SPDK_NVME_ASYNC_EVENT_TYPE_IO = 0x6,
+ /* Vendor Specific */
+ SPDK_NVME_ASYNC_EVENT_TYPE_VENDOR = 0x7,
+};
+
+/**
+ * Asynchronous Event Information for Error Status
+ */
+enum spdk_nvme_async_event_info_error {
+ /* Write to Invalid Doorbell Register */
+ SPDK_NVME_ASYNC_EVENT_WRITE_INVALID_DB = 0x0,
+ /* Invalid Doorbell Register Write Value */
+ SPDK_NVME_ASYNC_EVENT_INVALID_DB_WRITE = 0x1,
+ /* Diagnostic Failure */
+ SPDK_NVME_ASYNC_EVENT_DIAGNOSTIC_FAILURE = 0x2,
+ /* Persistent Internal Error */
+ SPDK_NVME_ASYNC_EVENT_PERSISTENT_INTERNAL = 0x3,
+ /* Transient Internal Error */
+ SPDK_NVME_ASYNC_EVENT_TRANSIENT_INTERNAL = 0x4,
+ /* Firmware Image Load Error */
+ SPDK_NVME_ASYNC_EVENT_FW_IMAGE_LOAD = 0x5,
+
+ /* 0x6 - 0xFF Reserved */
+};
+
+/**
+ * Asynchronous Event Information for SMART/Health Status
+ */
+enum spdk_nvme_async_event_info_smart {
+ /* NVM Subsystem Reliability */
+ SPDK_NVME_ASYNC_EVENT_SUBSYSTEM_RELIABILITY = 0x0,
+ /* Temperature Threshold */
+ SPDK_NVME_ASYNC_EVENT_TEMPERATURE_THRESHOLD = 0x1,
+ /* Spare Below Threshold */
+ SPDK_NVME_ASYNC_EVENT_SPARE_BELOW_THRESHOLD = 0x2,
+
+ /* 0x3 - 0xFF Reserved */
+};
+
+/**
+ * Asynchronous Event Information for Notice
+ */
+enum spdk_nvme_async_event_info_notice {
+ /* Namespace Attribute Changed */
+ SPDK_NVME_ASYNC_EVENT_NS_ATTR_CHANGED = 0x0,
+ /* Firmware Activation Starting */
+ SPDK_NVME_ASYNC_EVENT_FW_ACTIVATION_START = 0x1,
+ /* Telemetry Log Changed */
+ SPDK_NVME_ASYNC_EVENT_TELEMETRY_LOG_CHANGED = 0x2,
+
+ /* 0x3 - 0xFF Reserved */
+};
+
+/**
+ * Asynchronous Event Information for NVM Command Set Specific Status
+ */
+enum spdk_nvme_async_event_info_nvm_command_set {
+ /* Reservation Log Page Avaiable */
+ SPDK_NVME_ASYNC_EVENT_RESERVATION_LOG_AVAIL = 0x0,
+ /* Sanitize Operation Completed */
+ SPDK_NVME_ASYNC_EVENT_SANITIZE_COMPLETED = 0x1,
+
+ /* 0x2 - 0xFF Reserved */
+};
+
+/**
+ * Asynchronous Event Request Completion
+ */
+union spdk_nvme_async_event_completion {
+ uint32_t raw;
+ struct {
+ uint32_t async_event_type : 3;
+ uint32_t reserved1 : 5;
+ uint32_t async_event_info : 8;
+ uint32_t log_page_identifier : 8;
+ uint32_t reserved2 : 8;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_async_event_completion) == 4, "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_ARBITRATION
+ */
+union spdk_nvme_feat_arbitration {
+ uint32_t raw;
+ struct {
+ /** Arbitration Burst */
+ uint32_t ab : 3;
+
+ uint32_t reserved : 5;
+
+ /** Low Priority Weight */
+ uint32_t lpw : 8;
+
+ /** Medium Priority Weight */
+ uint32_t mpw : 8;
+
+ /** High Priority Weight */
+ uint32_t hpw : 8;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_arbitration) == 4, "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_POWER_MANAGEMENT
+ */
+union spdk_nvme_feat_power_management {
+ uint32_t raw;
+ struct {
+ /** Power State */
+ uint32_t ps : 5;
+
+ /** Workload Hint */
+ uint32_t wh : 3;
+
+ uint32_t reserved : 24;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_power_management) == 4, "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_LBA_RANGE_TYPE
+ */
+union spdk_nvme_feat_lba_range_type {
+ uint32_t raw;
+ struct {
+ /** Number of LBA Ranges */
+ uint32_t num : 6;
+
+ uint32_t reserved : 26;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_lba_range_type) == 4, "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD
+ */
+union spdk_nvme_feat_temperature_threshold {
+ uint32_t raw;
+ struct {
+ /** Temperature Threshold */
+ uint32_t tmpth : 16;
+
+ /** Threshold Temperature Select */
+ uint32_t tmpsel : 4;
+
+ /** Threshold Type Select */
+ uint32_t thsel : 2;
+
+ uint32_t reserved : 10;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_temperature_threshold) == 4, "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_ERROR_RECOVERY
+ */
+union spdk_nvme_feat_error_recovery {
+ uint32_t raw;
+ struct {
+ /** Time Limited Error Recovery */
+ uint32_t tler : 16;
+
+ /** Deallocated or Unwritten Logical Block Error Enable */
+ uint32_t dulbe : 1;
+
+ uint32_t reserved : 15;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_error_recovery) == 4, "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_VOLATILE_WRITE_CACHE
+ */
+union spdk_nvme_feat_volatile_write_cache {
+ uint32_t raw;
+ struct {
+ /** Volatile Write Cache Enable */
+ uint32_t wce : 1;
+
+ uint32_t reserved : 31;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_volatile_write_cache) == 4, "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_NUMBER_OF_QUEUES
+ */
+union spdk_nvme_feat_number_of_queues {
+ uint32_t raw;
+ struct {
+ /** Number of I/O Submission Queues Requested */
+ uint32_t nsqr : 16;
+
+ /** Number of I/O Completion Queues Requested */
+ uint32_t ncqr : 16;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_number_of_queues) == 4, "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION
+ */
+union spdk_nvme_feat_interrupt_vector_configuration {
+ uint32_t raw;
+ struct {
+ /** Interrupt Vector */
+ uint32_t iv : 16;
+
+ /** Coalescing Disable */
+ uint32_t cd : 1;
+
+ uint32_t reserved : 15;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_interrupt_vector_configuration) == 4,
+ "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_WRITE_ATOMICITY
+ */
+union spdk_nvme_feat_write_atomicity {
+ uint32_t raw;
+ struct {
+ /** Disable Normal */
+ uint32_t dn : 1;
+
+ uint32_t reserved : 31;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_write_atomicity) == 4, "Incorrect size");
+
+/**
+ * Data used by Set Features / Get Features \ref SPDK_NVME_FEAT_ASYNC_EVENT_CONFIGURATION
+ */
+union spdk_nvme_feat_async_event_configuration {
+ uint32_t raw;
+ struct {
+ union spdk_nvme_critical_warning_state crit_warn;
+ uint32_t ns_attr_notice : 1;
+ uint32_t fw_activation_notice : 1;
+ uint32_t telemetry_log_notice : 1;
+ uint32_t reserved : 21;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_async_event_configuration) == 4, "Incorrect size");
+/* Old name defined for compatibility */
+#define spdk_nvme_async_event_config spdk_nvme_feat_async_event_configuration
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION
+ */
+union spdk_nvme_feat_autonomous_power_state_transition {
+ uint32_t raw;
+ struct {
+ /** Autonomous Power State Transition Enable */
+ uint32_t apste : 1;
+
+ uint32_t reserved : 31;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_autonomous_power_state_transition) == 4,
+ "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_HOST_MEM_BUFFER
+ */
+union spdk_nvme_feat_host_mem_buffer {
+ uint32_t raw;
+ struct {
+ /** Enable Host Memory */
+ uint32_t ehm : 1;
+
+ /** Memory Return */
+ uint32_t mr : 1;
+
+ uint32_t reserved : 30;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_host_mem_buffer) == 4, "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_KEEP_ALIVE_TIMER
+ */
+union spdk_nvme_feat_keep_alive_timer {
+ uint32_t raw;
+ struct {
+ /** Keep Alive Timeout */
+ uint32_t kato : 32;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_keep_alive_timer) == 4, "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_HOST_CONTROLLED_THERMAL_MANAGEMENT
+ */
+union spdk_nvme_feat_host_controlled_thermal_management {
+ uint32_t raw;
+ struct {
+ /** Thermal Management Temperature 2 */
+ uint32_t tmt2 : 16;
+
+ /** Thermal Management Temperature 1 */
+ uint32_t tmt1 : 16;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_host_controlled_thermal_management) == 4,
+ "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_NON_OPERATIONAL_POWER_STATE_CONFIG
+ */
+union spdk_nvme_feat_non_operational_power_state_config {
+ uint32_t raw;
+ struct {
+ /** Non-Operational Power State Permissive Mode Enable */
+ uint32_t noppme : 1;
+
+ uint32_t reserved : 31;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_non_operational_power_state_config) == 4,
+ "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_SOFTWARE_PROGRESS_MARKER
+ */
+union spdk_nvme_feat_software_progress_marker {
+ uint32_t raw;
+ struct {
+ /** Pre-boot Software Load Count */
+ uint32_t pbslc : 8;
+
+ uint32_t reserved : 24;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_software_progress_marker) == 4, "Incorrect size");
+
+/**
+ * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_HOST_IDENTIFIER
+ */
+union spdk_nvme_feat_host_identifier {
+ uint32_t raw;
+ struct {
+ /** Enable Extended Host Identifier */
+ uint32_t exhid : 1;
+
+ uint32_t reserved : 31;
+ } bits;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_feat_host_identifier) == 4, "Incorrect size");
+
+/**
+ * Firmware slot information page (\ref SPDK_NVME_LOG_FIRMWARE_SLOT)
+ */
+struct spdk_nvme_firmware_page {
+ struct {
+ uint8_t active_slot : 3; /**< Slot for current FW */
+ uint8_t reserved3 : 1;
+ uint8_t next_reset_slot : 3; /**< Slot that will be active at next controller reset */
+ uint8_t reserved7 : 1;
+ } afi;
+
+ uint8_t reserved[7];
+ uint8_t revision[7][8]; /** Revisions for 7 slots (ASCII strings) */
+ uint8_t reserved2[448];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_firmware_page) == 512, "Incorrect size");
+
+/**
+ * Namespace attachment Type Encoding
+ */
+enum spdk_nvme_ns_attach_type {
+ /* Controller attach */
+ SPDK_NVME_NS_CTRLR_ATTACH = 0x0,
+
+ /* Controller detach */
+ SPDK_NVME_NS_CTRLR_DETACH = 0x1,
+
+ /* 0x2-0xF - Reserved */
+};
+
+/**
+ * Namespace management Type Encoding
+ */
+enum spdk_nvme_ns_management_type {
+ /* Create */
+ SPDK_NVME_NS_MANAGEMENT_CREATE = 0x0,
+
+ /* Delete */
+ SPDK_NVME_NS_MANAGEMENT_DELETE = 0x1,
+
+ /* 0x2-0xF - Reserved */
+};
+
+struct spdk_nvme_ns_list {
+ uint32_t ns_list[1024];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_ns_list) == 4096, "Incorrect size");
+
+/**
+ * Namespace identification descriptor type
+ *
+ * \sa spdk_nvme_ns_id_desc
+ */
+enum spdk_nvme_nidt {
+ /** IEEE Extended Unique Identifier */
+ SPDK_NVME_NIDT_EUI64 = 0x01,
+
+ /** Namespace GUID */
+ SPDK_NVME_NIDT_NGUID = 0x02,
+
+ /** Namespace UUID */
+ SPDK_NVME_NIDT_UUID = 0x03,
+};
+
+struct spdk_nvme_ns_id_desc {
+ /** Namespace identifier type */
+ uint8_t nidt;
+
+ /** Namespace identifier length (length of nid field) */
+ uint8_t nidl;
+
+ uint8_t reserved2;
+ uint8_t reserved3;
+
+ /** Namespace identifier */
+ uint8_t nid[];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_ns_id_desc) == 4, "Incorrect size");
+
+struct spdk_nvme_ctrlr_list {
+ uint16_t ctrlr_count;
+ uint16_t ctrlr_list[2047];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_ctrlr_list) == 4096, "Incorrect size");
+
+enum spdk_nvme_secure_erase_setting {
+ SPDK_NVME_FMT_NVM_SES_NO_SECURE_ERASE = 0x0,
+ SPDK_NVME_FMT_NVM_SES_USER_DATA_ERASE = 0x1,
+ SPDK_NVME_FMT_NVM_SES_CRYPTO_ERASE = 0x2,
+};
+
+enum spdk_nvme_pi_location {
+ SPDK_NVME_FMT_NVM_PROTECTION_AT_TAIL = 0x0,
+ SPDK_NVME_FMT_NVM_PROTECTION_AT_HEAD = 0x1,
+};
+
+enum spdk_nvme_pi_type {
+ SPDK_NVME_FMT_NVM_PROTECTION_DISABLE = 0x0,
+ SPDK_NVME_FMT_NVM_PROTECTION_TYPE1 = 0x1,
+ SPDK_NVME_FMT_NVM_PROTECTION_TYPE2 = 0x2,
+ SPDK_NVME_FMT_NVM_PROTECTION_TYPE3 = 0x3,
+};
+
+enum spdk_nvme_metadata_setting {
+ SPDK_NVME_FMT_NVM_METADATA_TRANSFER_AS_BUFFER = 0x0,
+ SPDK_NVME_FMT_NVM_METADATA_TRANSFER_AS_LBA = 0x1,
+};
+
+struct spdk_nvme_format {
+ uint32_t lbaf : 4;
+ uint32_t ms : 1;
+ uint32_t pi : 3;
+ uint32_t pil : 1;
+ uint32_t ses : 3;
+ uint32_t reserved : 20;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_format) == 4, "Incorrect size");
+
+struct spdk_nvme_protection_info {
+ uint16_t guard;
+ uint16_t app_tag;
+ uint32_t ref_tag;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_protection_info) == 8, "Incorrect size");
+
+/** Parameters for SPDK_NVME_OPC_FIRMWARE_COMMIT cdw10: commit action */
+enum spdk_nvme_fw_commit_action {
+ /**
+ * Downloaded image replaces the image specified by
+ * the Firmware Slot field. This image is not activated.
+ */
+ SPDK_NVME_FW_COMMIT_REPLACE_IMG = 0x0,
+ /**
+ * Downloaded image replaces the image specified by
+ * the Firmware Slot field. This image is activated at the next reset.
+ */
+ SPDK_NVME_FW_COMMIT_REPLACE_AND_ENABLE_IMG = 0x1,
+ /**
+ * The image specified by the Firmware Slot field is
+ * activated at the next reset.
+ */
+ SPDK_NVME_FW_COMMIT_ENABLE_IMG = 0x2,
+ /**
+ * The image specified by the Firmware Slot field is
+ * requested to be activated immediately without reset.
+ */
+ SPDK_NVME_FW_COMMIT_RUN_IMG = 0x3,
+};
+
+/** Parameters for SPDK_NVME_OPC_FIRMWARE_COMMIT cdw10 */
+struct spdk_nvme_fw_commit {
+ /**
+ * Firmware Slot. Specifies the firmware slot that shall be used for the
+ * Commit Action. The controller shall choose the firmware slot (slot 1 - 7)
+ * to use for the operation if the value specified is 0h.
+ */
+ uint32_t fs : 3;
+ /**
+ * Commit Action. Specifies the action that is taken on the image downloaded
+ * with the Firmware Image Download command or on a previously downloaded and
+ * placed image.
+ */
+ uint32_t ca : 3;
+ uint32_t reserved : 26;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_fw_commit) == 4, "Incorrect size");
+
+#define spdk_nvme_cpl_is_error(cpl) \
+ ((cpl)->status.sc != 0 || (cpl)->status.sct != 0)
+
+/** Enable protection information checking of the Logical Block Reference Tag field */
+#define SPDK_NVME_IO_FLAGS_PRCHK_REFTAG (1U << 26)
+/** Enable protection information checking of the Application Tag field */
+#define SPDK_NVME_IO_FLAGS_PRCHK_APPTAG (1U << 27)
+/** Enable protection information checking of the Guard field */
+#define SPDK_NVME_IO_FLAGS_PRCHK_GUARD (1U << 28)
+/** The protection information is stripped or inserted when set this bit */
+#define SPDK_NVME_IO_FLAGS_PRACT (1U << 29)
+#define SPDK_NVME_IO_FLAGS_FORCE_UNIT_ACCESS (1U << 30)
+#define SPDK_NVME_IO_FLAGS_LIMITED_RETRY (1U << 31)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/nvmf.h b/src/spdk/include/spdk/nvmf.h
new file mode 100644
index 00000000..17fa347a
--- /dev/null
+++ b/src/spdk/include/spdk/nvmf.h
@@ -0,0 +1,799 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * NVMe over Fabrics target public API
+ */
+
+#ifndef SPDK_NVMF_H
+#define SPDK_NVMF_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/env.h"
+#include "spdk/nvme.h"
+#include "spdk/nvmf_spec.h"
+#include "spdk/queue.h"
+#include "spdk/uuid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct spdk_nvmf_tgt;
+struct spdk_nvmf_subsystem;
+struct spdk_nvmf_ctrlr;
+struct spdk_nvmf_qpair;
+struct spdk_nvmf_request;
+struct spdk_bdev;
+struct spdk_nvmf_request;
+struct spdk_nvmf_host;
+struct spdk_nvmf_listener;
+struct spdk_nvmf_poll_group;
+struct spdk_json_write_ctx;
+struct spdk_nvmf_transport;
+
+struct spdk_nvmf_tgt_opts {
+ uint16_t max_queue_depth;
+ uint16_t max_qpairs_per_ctrlr;
+ uint32_t in_capsule_data_size;
+ uint32_t max_io_size;
+ uint32_t max_subsystems;
+ uint32_t io_unit_size;
+};
+
+struct spdk_nvmf_transport_opts {
+ uint16_t max_queue_depth;
+ uint16_t max_qpairs_per_ctrlr;
+ uint32_t in_capsule_data_size;
+ uint32_t max_io_size;
+ uint32_t io_unit_size;
+ uint32_t max_aq_depth;
+};
+
+/**
+ * Initialize the default value of opts.
+ *
+ * \param opts Data structure where SPDK will initialize the default options.
+ */
+void spdk_nvmf_tgt_opts_init(struct spdk_nvmf_tgt_opts *opts);
+
+/**
+ * Construct an NVMe-oF target.
+ *
+ * \param opts Options.
+ *
+ * \return a pointer to a NVMe-oF target on success, or NULL on failure.
+ */
+struct spdk_nvmf_tgt *spdk_nvmf_tgt_create(struct spdk_nvmf_tgt_opts *opts);
+
+typedef void (spdk_nvmf_tgt_destroy_done_fn)(void *ctx, int status);
+
+/**
+ * Destroy an NVMe-oF target.
+ *
+ * \param tgt The target to destroy. This releases all resources.
+ * \param cb_fn A callback that will be called once the target is destroyed
+ * \param cb_arg A context argument passed to cb_fn.
+ */
+void spdk_nvmf_tgt_destroy(struct spdk_nvmf_tgt *tgt,
+ spdk_nvmf_tgt_destroy_done_fn cb_fn,
+ void *cb_arg);
+
+/**
+ * Write NVMe-oF target configuration into provided JSON context.
+ * \param w JSON write context
+ * \param tgt The NVMe-oF target
+ */
+void spdk_nvmf_tgt_write_config_json(struct spdk_json_write_ctx *w, struct spdk_nvmf_tgt *tgt);
+
+/**
+ * Function to be called once the target is listening.
+ *
+ * \param ctx Context argument passed to this function.
+ * \param status 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_nvmf_tgt_listen_done_fn)(void *ctx, int status);
+
+/**
+ * Begin accepting new connections at the address provided.
+ *
+ * The connections will be matched with a subsystem, which may or may not allow
+ * the connection based on a subsystem-specific whitelist. See
+ * spdk_nvmf_subsystem_add_host() and spdk_nvmf_subsystem_add_listener()
+ *
+ * \param tgt The target associated with this listen address.
+ * \param trid The address to listen at.
+ * \param cb_fn A callback that will be called once the target is listening
+ * \param cb_arg A context argument passed to cb_fn.
+ *
+ * \return void. The callback status argument will be 0 on success
+ * or a negated errno on failure.
+ */
+void spdk_nvmf_tgt_listen(struct spdk_nvmf_tgt *tgt,
+ struct spdk_nvme_transport_id *trid,
+ spdk_nvmf_tgt_listen_done_fn cb_fn,
+ void *cb_arg);
+
+/**
+ * Function to be called for each newly discovered qpair.
+ *
+ * \param qpair The newly discovered qpair.
+ */
+typedef void (*new_qpair_fn)(struct spdk_nvmf_qpair *qpair);
+
+/**
+ * Poll the target for incoming connections.
+ *
+ * The new_qpair_fn cb_fn will be called for each newly discovered
+ * qpair. The user is expected to add that qpair to a poll group
+ * to establish the connection.
+ *
+ * \param tgt The target associated with the listen address.
+ * \param cb_fn Called for each newly discovered qpair.
+ */
+void spdk_nvmf_tgt_accept(struct spdk_nvmf_tgt *tgt, new_qpair_fn cb_fn);
+
+/**
+ * Create a poll group.
+ *
+ * \param tgt The target to create a poll group.
+ *
+ * \return a poll group on success, or NULL on failure.
+ */
+struct spdk_nvmf_poll_group *spdk_nvmf_poll_group_create(struct spdk_nvmf_tgt *tgt);
+
+/**
+ * Destroy a poll group.
+ *
+ * \param group The poll group to destroy.
+ */
+void spdk_nvmf_poll_group_destroy(struct spdk_nvmf_poll_group *group);
+
+/**
+ * Add the given qpair to the poll group.
+ *
+ * \param group The group to add qpair to.
+ * \param qpair The qpair to add.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_nvmf_poll_group_add(struct spdk_nvmf_poll_group *group,
+ struct spdk_nvmf_qpair *qpair);
+
+typedef void (*nvmf_qpair_disconnect_cb)(void *ctx);
+
+/**
+ * Disconnect an NVMe-oF qpair
+ *
+ * \param qpair The NVMe-oF qpair to disconnect.
+ * \param cb_fn The function to call upon completion of the disconnect.
+ * \param ctx The context to pass to the callback function.
+ *
+ * \return 0 upon success.
+ * \return -ENOMEM if the function specific context could not be allocated.
+ */
+int spdk_nvmf_qpair_disconnect(struct spdk_nvmf_qpair *qpair, nvmf_qpair_disconnect_cb cb_fn,
+ void *ctx);
+
+/**
+ * Get the peer's transport ID for this queue pair.
+ *
+ * \param qpair The NVMe-oF qpair
+ * \param trid Output parameter that will contain the transport id.
+ *
+ * \return 0 for success.
+ * \return -EINVAL if the qpair is not connected.
+ */
+int spdk_nvmf_qpair_get_peer_trid(struct spdk_nvmf_qpair *qpair,
+ struct spdk_nvme_transport_id *trid);
+
+/**
+ * Get the local transport ID for this queue pair.
+ *
+ * \param qpair The NVMe-oF qpair
+ * \param trid Output parameter that will contain the transport id.
+ *
+ * \return 0 for success.
+ * \return -EINVAL if the qpair is not connected.
+ */
+int spdk_nvmf_qpair_get_local_trid(struct spdk_nvmf_qpair *qpair,
+ struct spdk_nvme_transport_id *trid);
+
+/**
+ * Get the associated listener transport ID for this queue pair.
+ *
+ * \param qpair The NVMe-oF qpair
+ * \param trid Output parameter that will contain the transport id.
+ *
+ * \return 0 for success.
+ * \return -EINVAL if the qpair is not connected.
+ */
+int spdk_nvmf_qpair_get_listen_trid(struct spdk_nvmf_qpair *qpair,
+ struct spdk_nvme_transport_id *trid);
+
+/**
+ * Create an NVMe-oF subsystem.
+ *
+ * Subsystems are in one of three states: Inactive, Active, Paused. This
+ * state affects which operations may be performed on the subsystem. Upon
+ * creation, the subsystem will be in the Inactive state and may be activated
+ * by calling spdk_nvmf_subsystem_start(). No I/O will be processed in the Inactive
+ * or Paused states, but changes to the state of the subsystem may be made.
+ *
+ * \param tgt The NVMe-oF target that will own this subsystem.
+ * \param nqn The NVMe qualified name of this subsystem.
+ * \param type Whether this subsystem is an I/O subsystem or a Discovery subsystem.
+ * \param num_ns The number of namespaces this subsystem contains.
+ *
+ * \return a pointer to a NVMe-oF subsystem on success, or NULL on failure.
+ */
+struct spdk_nvmf_subsystem *spdk_nvmf_subsystem_create(struct spdk_nvmf_tgt *tgt,
+ const char *nqn,
+ enum spdk_nvmf_subtype type,
+ uint32_t num_ns);
+
+/**
+ * Destroy an NVMe-oF subsystem. A subsystem may only be destroyed when in
+ * the Inactive state. See spdk_nvmf_subsystem_stop().
+ *
+ * \param subsystem The NVMe-oF subsystem to destroy.
+ */
+void spdk_nvmf_subsystem_destroy(struct spdk_nvmf_subsystem *subsystem);
+
+/**
+ * Function to be called once the subsystem has changed state.
+ *
+ * \param subsytem NVMe-oF subsystem that has changed state.
+ * \param cb_arg Argument passed to callback function.
+ * \param status 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_nvmf_subsystem_state_change_done)(struct spdk_nvmf_subsystem *subsystem,
+ void *cb_arg, int status);
+
+/**
+ * Transition an NVMe-oF subsystem from Inactive to Active state.
+ *
+ * \param subsystem The NVMe-oF subsystem.
+ * \param cb_fn A function that will be called once the subsystem has changed state.
+ * \param cb_arg Argument passed to cb_fn.
+ *
+ * \return 0 on success, or negated errno on failure. The callback provided will only
+ * be called on success.
+ */
+int spdk_nvmf_subsystem_start(struct spdk_nvmf_subsystem *subsystem,
+ spdk_nvmf_subsystem_state_change_done cb_fn,
+ void *cb_arg);
+
+/**
+ * Transition an NVMe-oF subsystem from Active to Inactive state.
+ *
+ * \param subsystem The NVMe-oF subsystem.
+ * \param cb_fn A function that will be called once the subsystem has changed state.
+ * \param cb_arg Argument passed to cb_fn.
+ *
+ * \return 0 on success, or negated errno on failure. The callback provided will only
+ * be called on success.
+ */
+int spdk_nvmf_subsystem_stop(struct spdk_nvmf_subsystem *subsystem,
+ spdk_nvmf_subsystem_state_change_done cb_fn,
+ void *cb_arg);
+
+/**
+ * Transition an NVMe-oF subsystem from Active to Paused state.
+ *
+ * \param subsystem The NVMe-oF subsystem.
+ * \param cb_fn A function that will be called once the subsystem has changed state.
+ * \param cb_arg Argument passed to cb_fn.
+ *
+ * \return 0 on success, or negated errno on failure. The callback provided will only
+ * be called on success.
+ */
+int spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem,
+ spdk_nvmf_subsystem_state_change_done cb_fn,
+ void *cb_arg);
+
+/**
+ * Transition an NVMe-oF subsystem from Paused to Active state.
+ *
+ * \param subsystem The NVMe-oF subsystem.
+ * \param cb_fn A function that will be called once the subsystem has changed state.
+ * \param cb_arg Argument passed to cb_fn.
+ *
+ * \return 0 on success, or negated errno on failure. The callback provided will only
+ * be called on success.
+ */
+int spdk_nvmf_subsystem_resume(struct spdk_nvmf_subsystem *subsystem,
+ spdk_nvmf_subsystem_state_change_done cb_fn,
+ void *cb_arg);
+
+/**
+ * Search the target for a subsystem with the given NQN.
+ *
+ * \param tgt The NVMe-oF target to search from.
+ * \param subnqn NQN of the subsystem.
+ *
+ * \return a pointer to the NVMe-oF subsystem on success, or NULL on failure.
+ */
+struct spdk_nvmf_subsystem *spdk_nvmf_tgt_find_subsystem(struct spdk_nvmf_tgt *tgt,
+ const char *subnqn);
+
+/**
+ * Begin iterating over all known subsystems. If no subsystems are present, return NULL.
+ *
+ * \param tgt The NVMe-oF target to iterate.
+ *
+ * \return a pointer to the first NVMe-oF subsystem on success, or NULL on failure.
+ */
+struct spdk_nvmf_subsystem *spdk_nvmf_subsystem_get_first(struct spdk_nvmf_tgt *tgt);
+
+/**
+ * Continue iterating over all known subsystems. If no additional subsystems, return NULL.
+ *
+ * \param subsystem Previous subsystem returned from \ref spdk_nvmf_subsystem_get_first or
+ * \ref spdk_nvmf_subsystem_get_next.
+ *
+ * \return a pointer to the next NVMe-oF subsystem on success, or NULL on failure.
+ */
+struct spdk_nvmf_subsystem *spdk_nvmf_subsystem_get_next(struct spdk_nvmf_subsystem *subsystem);
+
+/**
+ * Allow the given host NQN to connect to the given subsystem.
+ *
+ * May only be performed on subsystems in the PAUSED or INACTIVE states.
+ *
+ * \param subsystem Subsystem to add host to.
+ * \param hostnqn The NQN for the host.
+ *
+ * \return 0 on success, or negated errno value on failure.
+ */
+int spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem,
+ const char *hostnqn);
+
+/**
+ * Remove the given host NQN from the allowed hosts whitelist.
+ *
+ * May only be performed on subsystems in the PAUSED or INACTIVE states.
+ *
+ * \param subsystem Subsystem to remove host from.
+ * \param hostnqn The NQN for the host.
+ *
+ * \return 0 on success, or negated errno value on failure.
+ */
+int spdk_nvmf_subsystem_remove_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn);
+
+/**
+ * Set whether a subsystem should allow any host or only hosts in the allowed list.
+ *
+ * May only be performed on subsystems in the PAUSED or INACTIVE states.
+ *
+ * \param subsystem Subsystem to modify.
+ * \param allow_any_host true to allow any host to connect to this subsystem,
+ * or false to enforce the whitelist configured with spdk_nvmf_subsystem_add_host().
+ *
+ * \return 0 on success, or negated errno value on failure.
+ */
+int spdk_nvmf_subsystem_set_allow_any_host(struct spdk_nvmf_subsystem *subsystem,
+ bool allow_any_host);
+
+/**
+ * Check whether a subsystem should allow any host or only hosts in the allowed list.
+ *
+ * \param subsystem Subsystem to modify.
+ *
+ * \return true if any host is allowed to connect to this subsystem, or false if
+ * connecting hosts must be in the whitelist configured with spdk_nvmf_subsystem_add_host().
+ */
+bool spdk_nvmf_subsystem_get_allow_any_host(const struct spdk_nvmf_subsystem *subsystem);
+
+/**
+ * Check if the given host is allowed to connect to the subsystem.
+ *
+ * \param subsystem The subsystem to query.
+ * \param hostnqn The NQN of the host.
+ *
+ * \return true if allowed, false if not.
+ */
+bool spdk_nvmf_subsystem_host_allowed(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn);
+
+/**
+ * Get the first allowed host in a subsystem.
+ *
+ * \param subsystem Subsystem to query.
+ *
+ * \return first allowed host in this subsystem, or NULL if none allowed.
+ */
+struct spdk_nvmf_host *spdk_nvmf_subsystem_get_first_host(struct spdk_nvmf_subsystem *subsystem);
+
+/**
+ * Get the next allowed host in a subsystem.
+ *
+ * \param subsystem Subsystem to query.
+ * \param prev_host Previous host returned from this function.
+ *
+ * \return next allowed host in this subsystem, or NULL if prev_host was the last host.
+ */
+struct spdk_nvmf_host *spdk_nvmf_subsystem_get_next_host(struct spdk_nvmf_subsystem *subsystem,
+ struct spdk_nvmf_host *prev_host);
+
+/**
+ * Get a host's NQN.
+ *
+ * \param host Host to query.
+ *
+ * \return NQN of host.
+ */
+const char *spdk_nvmf_host_get_nqn(struct spdk_nvmf_host *host);
+
+/**
+ * Accept new connections on the address provided.
+ *
+ * May only be performed on subsystems in the PAUSED or INACTIVE states.
+ *
+ * \param subsystem Subsystem to add listener to.
+ * \param trid The address to accept connections from.
+ *
+ * \return 0 on success, or negated errno value on failure.
+ */
+int spdk_nvmf_subsystem_add_listener(struct spdk_nvmf_subsystem *subsystem,
+ struct spdk_nvme_transport_id *trid);
+
+/**
+ * Stop accepting new connections on the address provided
+ *
+ * May only be performed on subsystems in the PAUSED or INACTIVE states.
+ *
+ * \param subsystem Subsystem to remove listener from.
+ * \param trid The address to no longer accept connections from.
+ *
+ * \return 0 on success, or negated errno value on failure.
+ */
+int spdk_nvmf_subsystem_remove_listener(struct spdk_nvmf_subsystem *subsystem,
+ const struct spdk_nvme_transport_id *trid);
+
+/**
+ * Check if connections originated from the given address are allowed to connect
+ * to the subsystem.
+ *
+ * \param subsystem The subsystem to query.
+ * \param trid The listen address.
+ *
+ * \return true if allowed, or false if not.
+ */
+bool spdk_nvmf_subsystem_listener_allowed(struct spdk_nvmf_subsystem *subsystem,
+ struct spdk_nvme_transport_id *trid);
+
+/**
+ * Get the first allowed listen address in the subsystem.
+ *
+ * \param subsystem Subsystem to query.
+ *
+ * \return first allowed listen address in this subsystem, or NULL if none allowed.
+ */
+struct spdk_nvmf_listener *spdk_nvmf_subsystem_get_first_listener(
+ struct spdk_nvmf_subsystem *subsystem);
+
+/**
+ * Get the next allowed listen address in a subsystem.
+ *
+ * \param subsystem Subsystem to query.
+ * \param prev_listener Previous listen address for this subsystem.
+ *
+ * \return next allowed listen address in this subsystem, or NULL if prev_listener
+ * was the last address.
+ */
+struct spdk_nvmf_listener *spdk_nvmf_subsystem_get_next_listener(
+ struct spdk_nvmf_subsystem *subsystem,
+ struct spdk_nvmf_listener *prev_listener);
+
+/**
+ * Get a listen address' transport ID
+ *
+ * \param listener This listener.
+ *
+ * \return the transport ID for this listener.
+ */
+const struct spdk_nvme_transport_id *spdk_nvmf_listener_get_trid(
+ struct spdk_nvmf_listener *listener);
+
+/** NVMe-oF target namespace creation options */
+struct spdk_nvmf_ns_opts {
+ /**
+ * Namespace ID
+ *
+ * Set to 0 to automatically assign a free NSID.
+ */
+ uint32_t nsid;
+
+ /**
+ * Namespace Globally Unique Identifier
+ *
+ * Fill with 0s if not specified.
+ */
+ uint8_t nguid[16];
+
+ /**
+ * IEEE Extended Unique Identifier
+ *
+ * Fill with 0s if not specified.
+ */
+ uint8_t eui64[8];
+
+ /**
+ * Namespace UUID
+ *
+ * Fill with 0s if not specified.
+ */
+ struct spdk_uuid uuid;
+};
+
+/**
+ * Get default namespace creation options.
+ *
+ * \param opts Namespace options to fill with defaults.
+ * \param opts_size sizeof(struct spdk_nvmf_ns_opts)
+ */
+void spdk_nvmf_ns_opts_get_defaults(struct spdk_nvmf_ns_opts *opts, size_t opts_size);
+
+/**
+ * Add a namespace to a subsytem.
+ *
+ * May only be performed on subsystems in the PAUSED or INACTIVE states.
+ *
+ * \param subsystem Subsystem to add namespace to.
+ * \param bdev Block device to add as a namespace.
+ * \param opts Namespace options, or NULL to use defaults.
+ * \param opts_size sizeof(*opts)
+ *
+ * \return newly added NSID on success, or 0 on failure.
+ */
+uint32_t spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bdev *bdev,
+ const struct spdk_nvmf_ns_opts *opts, size_t opts_size);
+
+/**
+ * Remove a namespace from a subsytem.
+ *
+ * May only be performed on subsystems in the PAUSED or INACTIVE states.
+ *
+ * \param subsystem Subsystem the namespace belong to.
+ * \param nsid Namespace ID to be removed.
+ * \param cb_fn Function to call when all thread local ns information has been updated
+ * \param cb_arg Context for the above cb_fn
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid,
+ spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg);
+
+/**
+ * Get the first allocated namespace in a subsystem.
+ *
+ * \param subsystem Subsystem to query.
+ *
+ * \return first allocated namespace in this subsystem, or NULL if this subsystem
+ * has no namespaces.
+ */
+struct spdk_nvmf_ns *spdk_nvmf_subsystem_get_first_ns(struct spdk_nvmf_subsystem *subsystem);
+
+/**
+ * Get the next allocated namespace in a subsystem.
+ *
+ * \param subsystem Subsystem to query.
+ * \param prev_ns Previous ns returned from this function.
+ *
+ * \return next allocated namespace in this subsystem, or NULL if prev_ns was the
+ * last namespace.
+ */
+struct spdk_nvmf_ns *spdk_nvmf_subsystem_get_next_ns(struct spdk_nvmf_subsystem *subsystem,
+ struct spdk_nvmf_ns *prev_ns);
+
+/**
+ * Get a namespace in a subsystem by NSID.
+ *
+ * \param subsystem Subsystem to search.
+ * \param nsid Namespace ID to find.
+ *
+ * \return namespace matching nsid, or NULL if nsid was not found.
+ */
+struct spdk_nvmf_ns *spdk_nvmf_subsystem_get_ns(struct spdk_nvmf_subsystem *subsystem,
+ uint32_t nsid);
+
+/**
+ * Get the maximum number of namespaces allowed in a subsystem.
+ *
+ * \param subsystem Subsystem to query.
+ *
+ * \return Maximum number of namespaces allowed in the subsystem, or 0 for unlimited.
+ */
+uint32_t spdk_nvmf_subsystem_get_max_namespaces(const struct spdk_nvmf_subsystem *subsystem);
+
+/**
+ * Get a namespace's NSID.
+ *
+ * \param ns Namespace to query.
+ *
+ * \return NSID of ns.
+ */
+uint32_t spdk_nvmf_ns_get_id(const struct spdk_nvmf_ns *ns);
+
+/**
+ * Get a namespace's associated bdev.
+ *
+ * \param ns Namespace to query.
+ *
+ * \return backing bdev of ns.
+ */
+struct spdk_bdev *spdk_nvmf_ns_get_bdev(struct spdk_nvmf_ns *ns);
+
+/**
+ * Get the options specified for a namespace.
+ *
+ * \param ns Namespace to query.
+ * \param opts Output parameter for options.
+ * \param opts_size sizeof(*opts)
+ */
+void spdk_nvmf_ns_get_opts(const struct spdk_nvmf_ns *ns, struct spdk_nvmf_ns_opts *opts,
+ size_t opts_size);
+
+/**
+ * Get the serial number of the specified subsystem.
+ *
+ * \param subsystem Subsystem to query.
+ *
+ * \return serial number of the specified subsystem.
+ */
+const char *spdk_nvmf_subsystem_get_sn(const struct spdk_nvmf_subsystem *subsystem);
+
+
+/**
+ * Set the serial number for the specified subsystem.
+ *
+ * \param subsystem Subsystem to set for.
+ * \param sn serial number to set.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_nvmf_subsystem_set_sn(struct spdk_nvmf_subsystem *subsystem, const char *sn);
+
+/**
+ * Get the NQN of the specified subsystem.
+ *
+ * \param subsystem Subsystem to query.
+ *
+ * \return NQN of the specified subsystem.
+ */
+const char *spdk_nvmf_subsystem_get_nqn(struct spdk_nvmf_subsystem *subsystem);
+
+/**
+ * Get the type of the specified subsystem.
+ *
+ * \param subsystem Subsystem to query.
+ *
+ * \return the type of the specified subsystem.
+ */
+enum spdk_nvmf_subtype spdk_nvmf_subsystem_get_type(struct spdk_nvmf_subsystem *subsystem);
+
+/**
+ * Initialize transport options
+ *
+ * \param type The transport type to create
+ * \param opts The transport options (e.g. max_io_size)
+ *
+ * \return bool. true if successful, false if transport type
+ * not found.
+ */
+bool
+spdk_nvmf_transport_opts_init(enum spdk_nvme_transport_type type,
+ struct spdk_nvmf_transport_opts *opts);
+
+/**
+ * Create a protocol transport
+ *
+ * \param type The transport type to create
+ * \param opts The transport options (e.g. max_io_size)
+ *
+ * \return new transport or NULL if create fails
+ */
+struct spdk_nvmf_transport *spdk_nvmf_transport_create(enum spdk_nvme_transport_type type,
+ struct spdk_nvmf_transport_opts *opts);
+
+/**
+ * Destroy a protocol transport
+ *
+ * \param transport The transport to destory
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_nvmf_transport_destroy(struct spdk_nvmf_transport *transport);
+
+/**
+ * Get an existing transport from the target
+ *
+ * \param tgt The NVMe-oF target
+ * \param type The transport type to get
+ *
+ * \return the transport or NULL if not found
+ */
+struct spdk_nvmf_transport *spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt *tgt,
+ enum spdk_nvme_transport_type type);
+
+/**
+ * Function to be called once transport add is complete
+ *
+ * \param cb_arg Callback argument passed to this function.
+ * \param status 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_nvmf_tgt_add_transport_done_fn)(void *cb_arg, int status);
+
+/**
+ * Add a transport to a target
+ *
+ * \param tgt The NVMe-oF target
+ * \param transport The transport to add
+ * \param cb_fn A callback that will be called once the transport is created
+ * \param cb_arg A context argument passed to cb_fn.
+ *
+ * \return void. The callback status argument will be 0 on success
+ * or a negated errno on failure.
+ */
+void spdk_nvmf_tgt_add_transport(struct spdk_nvmf_tgt *tgt,
+ struct spdk_nvmf_transport *transport,
+ spdk_nvmf_tgt_add_transport_done_fn cb_fn,
+ void *cb_arg);
+
+/**
+ *
+ * Add listener to transport and begin accepting new connections.
+ *
+ * \param transport The transport to add listener to
+ * \param trid Address to listen at
+ *
+ * \return int. 0 if it completed successfully, or negative errno if it failed.
+ */
+
+int spdk_nvmf_transport_listen(struct spdk_nvmf_transport *transport,
+ const struct spdk_nvme_transport_id *trid);
+
+/**
+ * Write NVMe-oF target's transport configurations into provided JSON context.
+ * \param w JSON write context
+ * \param tgt The NVMe-oF target
+ */
+void
+spdk_nvmf_tgt_transport_write_config_json(struct spdk_json_write_ctx *w, struct spdk_nvmf_tgt *tgt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/nvmf_fc_spec.h b/src/spdk/include/spdk/nvmf_fc_spec.h
new file mode 100644
index 00000000..2a3435a7
--- /dev/null
+++ b/src/spdk/include/spdk/nvmf_fc_spec.h
@@ -0,0 +1,403 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright (c) 2018 Broadcom. All Rights Reserved.
+ * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __NVMF_FC_SPEC_H__
+#define __NVMF_FC_SPEC_H__
+
+#include "spdk/env.h"
+#include "spdk/nvme.h"
+
+/*
+ * FC-NVMe Spec. Definitions
+ */
+
+#define FCNVME_R_CTL_CMD_REQ 0x06
+#define FCNVME_R_CTL_DATA_OUT 0x01
+#define FCNVME_R_CTL_CONFIRM 0x03
+#define FCNVME_R_CTL_STATUS 0x07
+#define FCNVME_R_CTL_ERSP_STATUS 0x08
+#define FCNVME_R_CTL_LS_REQUEST 0x32
+#define FCNVME_R_CTL_LS_RESPONSE 0x33
+#define FCNVME_R_CTL_BA_ABTS 0x81
+
+#define FCNVME_F_CTL_END_SEQ 0x080000
+#define FCNVME_F_CTL_SEQ_INIT 0x010000
+
+/* END_SEQ | LAST_SEQ | Exchange Responder | SEQ init */
+#define FCNVME_F_CTL_RSP 0x990000
+
+#define FCNVME_TYPE_BLS 0x0
+#define FCNVME_TYPE_FC_EXCHANGE 0x08
+#define FCNVME_TYPE_NVMF_DATA 0x28
+
+#define FCNVME_CMND_IU_FC_ID 0x28
+#define FCNVME_CMND_IU_SCSI_ID 0xFD
+
+#define FCNVME_CMND_IU_NODATA 0x00
+#define FCNVME_CMND_IU_READ 0x10
+#define FCNVME_CMND_IU_WRITE 0x01
+
+/* BLS reject error codes */
+#define FCNVME_BLS_REJECT_UNABLE_TO_PERFORM 0x09
+#define FCNVME_BLS_REJECT_EXP_NOINFO 0x00
+#define FCNVME_BLS_REJECT_EXP_INVALID_OXID 0x03
+
+/*
+ * FC NVMe Link Services (LS) constants
+ */
+#define FCNVME_MAX_LS_REQ_SIZE 1536
+#define FCNVME_MAX_LS_RSP_SIZE 64
+
+#define FCNVME_LS_CA_CMD_MIN_LEN 592
+#define FCNVME_LS_CA_DESC_LIST_MIN_LEN 584
+#define FCNVME_LS_CA_DESC_MIN_LEN 576
+
+/* this value needs to be in sync with low level driver buffer size */
+#define FCNVME_MAX_LS_BUFFER_SIZE 2048
+
+#define FCNVME_GOOD_RSP_LEN 12
+#define FCNVME_ASSOC_HOSTID_LEN 16
+#define FCNVME_ASSOC_HOSTNQN_LEN 256
+#define FCNVME_ASSOC_SUBNQN_LEN 256
+
+
+typedef uint64_t FCNVME_BE64;
+typedef uint32_t FCNVME_BE32;
+typedef uint16_t FCNVME_BE16;
+
+/*
+ * FC-NVME LS Commands
+ */
+enum {
+ FCNVME_LS_RSVD = 0,
+ FCNVME_LS_RJT = 1,
+ FCNVME_LS_ACC = 2,
+ FCNVME_LS_CREATE_ASSOCIATION = 3,
+ FCNVME_LS_CREATE_CONNECTION = 4,
+ FCNVME_LS_DISCONNECT = 5,
+};
+
+/*
+ * FC-NVME Link Service Descriptors
+ */
+enum {
+ FCNVME_LSDESC_RSVD = 0x0,
+ FCNVME_LSDESC_RQST = 0x1,
+ FCNVME_LSDESC_RJT = 0x2,
+ FCNVME_LSDESC_CREATE_ASSOC_CMD = 0x3,
+ FCNVME_LSDESC_CREATE_CONN_CMD = 0x4,
+ FCNVME_LSDESC_DISCONN_CMD = 0x5,
+ FCNVME_LSDESC_CONN_ID = 0x6,
+ FCNVME_LSDESC_ASSOC_ID = 0x7,
+};
+
+/*
+ * LS Reject reason_codes
+ */
+enum fcnvme_ls_rjt_reason {
+ FCNVME_RJT_RC_NONE = 0, /* no reason - not to be sent */
+ FCNVME_RJT_RC_INVAL = 0x01, /* invalid NVMe_LS command code */
+ FCNVME_RJT_RC_LOGIC = 0x03, /* logical error */
+ FCNVME_RJT_RC_UNAB = 0x09, /* unable to perform request */
+ FCNVME_RJT_RC_UNSUP = 0x0b, /* command not supported */
+ FCNVME_RJT_RC_INPROG = 0x0e, /* command already in progress */
+ FCNVME_RJT_RC_INV_ASSOC = 0x40, /* invalid Association ID */
+ FCNVME_RJT_RC_INV_CONN = 0x41, /* invalid Connection ID */
+ FCNVME_RJT_RC_INV_PARAM = 0x42, /* invalid parameters */
+ FCNVME_RJT_RC_INSUFF_RES = 0x43, /* insufficient resources */
+ FCNVME_RJT_RC_INV_HOST = 0x44, /* invalid or rejected host */
+ FCNVME_RJT_RC_VENDOR = 0xff, /* vendor specific error */
+};
+
+/*
+ * LS Reject reason_explanation codes
+ */
+enum fcnvme_ls_rjt_explan {
+ FCNVME_RJT_EXP_NONE = 0x00, /* No additional explanation */
+ FCNVME_RJT_EXP_OXID_RXID = 0x17, /* invalid OX_ID-RX_ID combo */
+ FCNVME_RJT_EXP_UNAB_DATA = 0x2a, /* unable to supply data */
+ FCNVME_RJT_EXP_INV_LEN = 0x2d, /* invalid payload length */
+ FCNVME_RJT_EXP_INV_ESRP = 0x40, /* invalid ESRP ratio */
+ FCNVME_RJT_EXP_INV_CTL_ID = 0x41, /* invalid controller ID */
+ FCNVME_RJT_EXP_INV_Q_ID = 0x42, /* invalid queue ID */
+ FCNVME_RJT_EXP_SQ_SIZE = 0x43, /* invalid submission queue size */
+ FCNVME_RJT_EXP_INV_HOST_ID = 0x44, /* invalid or rejected host ID */
+ FCNVME_RJT_EXP_INV_HOSTNQN = 0x45, /* invalid or rejected host NQN */
+ FCNVME_RJT_EXP_INV_SUBNQN = 0x46, /* invalid or rejected subsys nqn */
+};
+
+/*
+ * NVMe over FC CMD IU
+ */
+struct spdk_nvmf_fc_cmnd_iu {
+ uint32_t scsi_id: 8,
+ fc_id: 8,
+ cmnd_iu_len: 16;
+ uint32_t rsvd0: 24,
+ flags: 8;
+ uint64_t conn_id;
+ uint32_t cmnd_seq_num;
+ uint32_t data_len;
+ struct spdk_nvme_cmd cmd;
+ uint32_t rsvd1[2];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_cmnd_iu) == 96, "size_mismatch");
+
+/*
+ * NVMe over Extended Response IU
+ */
+struct spdk_nvmf_fc_ersp_iu {
+ uint32_t status_code: 8,
+ rsvd0: 8,
+ ersp_len: 16;
+ uint32_t response_seq_no;
+ uint32_t transferred_data_len;
+ uint32_t rsvd1;
+ struct spdk_nvme_cpl rsp;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_ersp_iu) == 32, "size_mismatch");
+
+/*
+ * Transfer ready IU
+ */
+struct spdk_nvmf_fc_xfer_rdy_iu {
+ uint32_t relative_offset;
+ uint32_t burst_len;
+ uint32_t rsvd;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_xfer_rdy_iu) == 12, "size_mismatch");
+
+/*
+ * FC NVME Frame Header
+ */
+struct spdk_nvmf_fc_frame_hdr {
+ FCNVME_BE32 r_ctl: 8,
+ d_id: 24;
+ FCNVME_BE32 cs_ctl: 8,
+ s_id: 24;
+ FCNVME_BE32 type: 8,
+ f_ctl: 24;
+ FCNVME_BE32 seq_id: 8,
+ df_ctl: 8,
+ seq_cnt: 16;
+ FCNVME_BE32 ox_id: 16,
+ rx_id: 16;
+ FCNVME_BE32 parameter;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_frame_hdr) == 24, "size_mismatch");
+
+/*
+ * Request payload word 0
+ */
+struct spdk_nvmf_fc_ls_rqst_w0 {
+ uint8_t ls_cmd; /* FCNVME_LS_xxx */
+ uint8_t zeros[3];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_ls_rqst_w0) == 4, "size_mismatch");
+
+/*
+ * LS request information descriptor
+ */
+struct spdk_nvmf_fc_lsdesc_rqst {
+ FCNVME_BE32 desc_tag; /* FCNVME_LSDESC_xxx */
+ FCNVME_BE32 desc_len;
+ struct spdk_nvmf_fc_ls_rqst_w0 w0;
+ FCNVME_BE32 rsvd12;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_lsdesc_rqst) == 16, "size_mismatch");
+
+/*
+ * LS accept header
+ */
+struct spdk_nvmf_fc_ls_acc_hdr {
+ struct spdk_nvmf_fc_ls_rqst_w0 w0;
+ FCNVME_BE32 desc_list_len;
+ struct spdk_nvmf_fc_lsdesc_rqst rqst;
+ /* Followed by cmd-specific ACC descriptors, see next definitions */
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_ls_acc_hdr) == 24, "size_mismatch");
+
+/*
+ * LS descriptor connection id
+ */
+struct spdk_nvmf_fc_lsdesc_conn_id {
+ FCNVME_BE32 desc_tag;
+ FCNVME_BE32 desc_len;
+ FCNVME_BE64 connection_id;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_lsdesc_conn_id) == 16, "size_mismatch");
+
+/*
+ * LS decriptor association id
+ */
+struct spdk_nvmf_fc_lsdesc_assoc_id {
+ FCNVME_BE32 desc_tag;
+ FCNVME_BE32 desc_len;
+ FCNVME_BE64 association_id;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_lsdesc_assoc_id) == 16, "size_mismatch");
+
+/*
+ * LS Create Association descriptor
+ */
+struct spdk_nvmf_fc_lsdesc_cr_assoc_cmd {
+ FCNVME_BE32 desc_tag;
+ FCNVME_BE32 desc_len;
+ FCNVME_BE16 ersp_ratio;
+ FCNVME_BE16 rsvd10;
+ FCNVME_BE32 rsvd12[9];
+ FCNVME_BE16 cntlid;
+ FCNVME_BE16 sqsize;
+ FCNVME_BE32 rsvd52;
+ uint8_t hostid[FCNVME_ASSOC_HOSTID_LEN];
+ uint8_t hostnqn[FCNVME_ASSOC_HOSTNQN_LEN];
+ uint8_t subnqn[FCNVME_ASSOC_SUBNQN_LEN];
+ uint8_t rsvd584[432];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_lsdesc_cr_assoc_cmd) == 1016, "size_mismatch");
+
+/*
+ * LS Create Association reqeust payload
+ */
+struct spdk_nvmf_fc_ls_cr_assoc_rqst {
+ struct spdk_nvmf_fc_ls_rqst_w0 w0;
+ FCNVME_BE32 desc_list_len;
+ struct spdk_nvmf_fc_lsdesc_cr_assoc_cmd assoc_cmd;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_ls_cr_assoc_rqst) == 1024, "size_mismatch");
+
+/*
+ * LS Create Association accept payload
+ */
+struct spdk_nvmf_fc_ls_cr_assoc_acc {
+ struct spdk_nvmf_fc_ls_acc_hdr hdr;
+ struct spdk_nvmf_fc_lsdesc_assoc_id assoc_id;
+ struct spdk_nvmf_fc_lsdesc_conn_id conn_id;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_ls_cr_assoc_acc) == 56, "size_mismatch");
+
+/*
+ * LS Create IO Connection descriptor
+ */
+struct spdk_nvmf_fc_lsdesc_cr_conn_cmd {
+ FCNVME_BE32 desc_tag;
+ FCNVME_BE32 desc_len;
+ FCNVME_BE16 ersp_ratio;
+ FCNVME_BE16 rsvd10;
+ FCNVME_BE32 rsvd12[9];
+ FCNVME_BE16 qid;
+ FCNVME_BE16 sqsize;
+ FCNVME_BE32 rsvd52;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_ls_cr_assoc_acc) == 56, "size_mismatch");
+
+/*
+ * LS Create IO Connection payload
+ */
+struct spdk_nvmf_fc_ls_cr_conn_rqst {
+ struct spdk_nvmf_fc_ls_rqst_w0 w0;
+ FCNVME_BE32 desc_list_len;
+ struct spdk_nvmf_fc_lsdesc_assoc_id assoc_id;
+ struct spdk_nvmf_fc_lsdesc_cr_conn_cmd connect_cmd;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_ls_cr_conn_rqst) == 80, "size_mismatch");
+
+/*
+ * LS Create IO Connection accept payload
+ */
+struct spdk_nvmf_fc_ls_cr_conn_acc {
+ struct spdk_nvmf_fc_ls_acc_hdr hdr;
+ struct spdk_nvmf_fc_lsdesc_conn_id conn_id;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_ls_cr_conn_acc) == 40, "size_mismatch");
+
+/*
+ * LS Disconnect descriptor
+ */
+struct spdk_nvmf_fc_lsdesc_disconn_cmd {
+ FCNVME_BE32 desc_tag;
+ FCNVME_BE32 desc_len;
+ FCNVME_BE32 rsvd8;
+ FCNVME_BE32 rsvd12;
+ FCNVME_BE32 rsvd16;
+ FCNVME_BE32 rsvd20;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_lsdesc_disconn_cmd) == 24, "size_mismatch");
+
+/*
+ * LS Disconnect payload
+ */
+struct spdk_nvmf_fc_ls_disconnect_rqst {
+ struct spdk_nvmf_fc_ls_rqst_w0 w0;
+ FCNVME_BE32 desc_list_len;
+ struct spdk_nvmf_fc_lsdesc_assoc_id assoc_id;
+ struct spdk_nvmf_fc_lsdesc_disconn_cmd disconn_cmd;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst) == 48, "size_mismatch");
+
+/*
+ * LS Disconnect accept payload
+ */
+struct spdk_nvmf_fc_ls_disconnect_acc {
+ struct spdk_nvmf_fc_ls_acc_hdr hdr;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_ls_disconnect_acc) == 24, "size_mismatch");
+
+/*
+ * LS Reject descriptor
+ */
+struct spdk_nvmf_fc_lsdesc_rjt {
+ FCNVME_BE32 desc_tag;
+ FCNVME_BE32 desc_len;
+ uint8_t rsvd8;
+
+ uint8_t reason_code;
+ uint8_t reason_explanation;
+
+ uint8_t vendor;
+ FCNVME_BE32 rsvd12;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_lsdesc_rjt) == 16, "size_mismatch");
+
+/*
+ * LS Reject payload
+ */
+struct spdk_nvmf_fc_ls_rjt {
+ struct spdk_nvmf_fc_ls_rqst_w0 w0;
+ FCNVME_BE32 desc_list_len;
+ struct spdk_nvmf_fc_lsdesc_rqst rqst;
+ struct spdk_nvmf_fc_lsdesc_rjt rjt;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fc_ls_rjt) == 40, "size_mismatch");
+
+#endif
diff --git a/src/spdk/include/spdk/nvmf_spec.h b/src/spdk/include/spdk/nvmf_spec.h
new file mode 100644
index 00000000..d19a90ec
--- /dev/null
+++ b/src/spdk/include/spdk/nvmf_spec.h
@@ -0,0 +1,472 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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)
+
+/* Minimum number of admin queue entries defined by NVMe over Fabrics spec */
+#define SPDK_NVMF_MIN_ADMIN_QUEUE_ENTRIES 32
+
+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,
+
+ /** 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 {
+ /** Discovery type for NVM subsystem */
+ SPDK_NVMF_SUBTYPE_DISCOVERY = 0x1,
+
+ /** NVMe type for NVM subsystem */
+ SPDK_NVMF_SUBTYPE_NVME = 0x2,
+};
+
+/**
+ * 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[256];
+ uint8_t hostnqn[256];
+ 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_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");
+
+/** 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;
+};
+SPDK_STATIC_ASSERT(sizeof(union spdk_nvmf_transport_specific_address_subtype) == 256,
+ "Incorrect size");
+
+/**
+ * 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;
+
+ uint8_t reserved0[22];
+
+ /** 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,
+};
+
+#pragma pack(pop)
+
+#endif /* __NVMF_SPEC_H__ */
diff --git a/src/spdk/include/spdk/pci_ids.h b/src/spdk/include/spdk/pci_ids.h
new file mode 100644
index 00000000..6b3e7b5f
--- /dev/null
+++ b/src/spdk/include/spdk/pci_ids.h
@@ -0,0 +1,127 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * PCI device ID list
+ */
+
+#ifndef SPDK_PCI_IDS
+#define SPDK_PCI_IDS
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPDK_PCI_ANY_ID 0xffff
+#define SPDK_PCI_VID_INTEL 0x8086
+#define SPDK_PCI_VID_MEMBLAZE 0x1c5f
+#define SPDK_PCI_VID_SAMSUNG 0x144d
+#define SPDK_PCI_VID_VIRTUALBOX 0x80ee
+#define SPDK_PCI_VID_VIRTIO 0x1af4
+#define SPDK_PCI_VID_CNEXLABS 0x1d1d
+
+/**
+ * PCI class code for NVMe devices.
+ *
+ * Base class code 01h: mass storage
+ * Subclass code 08h: non-volatile memory
+ * Programming interface 02h: NVM Express
+ */
+#define SPDK_PCI_CLASS_NVME 0x010802
+
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB0 0x3c20
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB1 0x3c21
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB2 0x3c22
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB3 0x3c23
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB4 0x3c24
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB5 0x3c25
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB6 0x3c26
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f
+
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB0 0x0e20
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB1 0x0e21
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB2 0x0e22
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB3 0x0e23
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB4 0x0e24
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB5 0x0e25
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB6 0x0e26
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB7 0x0e27
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB8 0x0e2e
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB9 0x0e2f
+
+#define PCI_DEVICE_ID_INTEL_IOAT_HSW0 0x2f20
+#define PCI_DEVICE_ID_INTEL_IOAT_HSW1 0x2f21
+#define PCI_DEVICE_ID_INTEL_IOAT_HSW2 0x2f22
+#define PCI_DEVICE_ID_INTEL_IOAT_HSW3 0x2f23
+#define PCI_DEVICE_ID_INTEL_IOAT_HSW4 0x2f24
+#define PCI_DEVICE_ID_INTEL_IOAT_HSW5 0x2f25
+#define PCI_DEVICE_ID_INTEL_IOAT_HSW6 0x2f26
+#define PCI_DEVICE_ID_INTEL_IOAT_HSW7 0x2f27
+#define PCI_DEVICE_ID_INTEL_IOAT_HSW8 0x2f2e
+#define PCI_DEVICE_ID_INTEL_IOAT_HSW9 0x2f2f
+
+#define PCI_DEVICE_ID_INTEL_IOAT_BWD0 0x0C50
+#define PCI_DEVICE_ID_INTEL_IOAT_BWD1 0x0C51
+#define PCI_DEVICE_ID_INTEL_IOAT_BWD2 0x0C52
+#define PCI_DEVICE_ID_INTEL_IOAT_BWD3 0x0C53
+
+#define PCI_DEVICE_ID_INTEL_IOAT_BDXDE0 0x6f50
+#define PCI_DEVICE_ID_INTEL_IOAT_BDXDE1 0x6f51
+#define PCI_DEVICE_ID_INTEL_IOAT_BDXDE2 0x6f52
+#define PCI_DEVICE_ID_INTEL_IOAT_BDXDE3 0x6f53
+
+#define PCI_DEVICE_ID_INTEL_IOAT_BDX0 0x6f20
+#define PCI_DEVICE_ID_INTEL_IOAT_BDX1 0x6f21
+#define PCI_DEVICE_ID_INTEL_IOAT_BDX2 0x6f22
+#define PCI_DEVICE_ID_INTEL_IOAT_BDX3 0x6f23
+#define PCI_DEVICE_ID_INTEL_IOAT_BDX4 0x6f24
+#define PCI_DEVICE_ID_INTEL_IOAT_BDX5 0x6f25
+#define PCI_DEVICE_ID_INTEL_IOAT_BDX6 0x6f26
+#define PCI_DEVICE_ID_INTEL_IOAT_BDX7 0x6f27
+#define PCI_DEVICE_ID_INTEL_IOAT_BDX8 0x6f2e
+#define PCI_DEVICE_ID_INTEL_IOAT_BDX9 0x6f2f
+
+#define PCI_DEVICE_ID_INTEL_IOAT_SKX 0x2021
+
+#define PCI_DEVICE_ID_VIRTIO_BLK_MODERN 0x1001
+#define PCI_DEVICE_ID_VIRTIO_SCSI_MODERN 0x1004
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_PCI_IDS */
diff --git a/src/spdk/include/spdk/queue.h b/src/spdk/include/spdk/queue.h
new file mode 100644
index 00000000..d3d8615d
--- /dev/null
+++ b/src/spdk/include/spdk/queue.h
@@ -0,0 +1,57 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SPDK_QUEUE_H
+#define SPDK_QUEUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/cdefs.h>
+#include <sys/queue.h>
+
+/*
+ * The SPDK NVMe driver was originally ported from FreeBSD, which makes
+ * use of features in FreeBSD's queue.h that do not exist on Linux.
+ * Include a header with these additional features on Linux only.
+ */
+#ifndef __FreeBSD__
+#include <spdk/queue_extras.h>
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/queue_extras.h b/src/spdk/include/spdk/queue_extras.h
new file mode 100644
index 00000000..3ad31f6e
--- /dev/null
+++ b/src/spdk/include/spdk/queue_extras.h
@@ -0,0 +1,341 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ * $FreeBSD$
+ */
+
+#ifndef SPDK_QUEUE_EXTRAS_H
+#define SPDK_QUEUE_EXTRAS_H
+
+/*
+ * This file defines four types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists and tail queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may be traversed in either direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ * SLIST LIST STAILQ TAILQ
+ * _HEAD + + + +
+ * _HEAD_INITIALIZER + + + +
+ * _ENTRY + + + +
+ * _INIT + + + +
+ * _EMPTY + + + +
+ * _FIRST + + + +
+ * _NEXT + + + +
+ * _PREV - + - +
+ * _LAST - - + +
+ * _FOREACH + + + +
+ * _FOREACH_FROM + + + +
+ * _FOREACH_SAFE + + + +
+ * _FOREACH_FROM_SAFE + + + +
+ * _FOREACH_REVERSE - - - +
+ * _FOREACH_REVERSE_FROM - - - +
+ * _FOREACH_REVERSE_SAFE - - - +
+ * _FOREACH_REVERSE_FROM_SAFE - - - +
+ * _INSERT_HEAD + + + +
+ * _INSERT_BEFORE - + - +
+ * _INSERT_AFTER + + + +
+ * _INSERT_TAIL - - + +
+ * _CONCAT - - + +
+ * _REMOVE_AFTER + - + -
+ * _REMOVE_HEAD + - + -
+ * _REMOVE + + + +
+ * _SWAP + + + +
+ *
+ */
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define STAILQ_HEAD(name, type) \
+struct name { \
+ struct type *stqh_first;/* first element */ \
+ struct type **stqh_last;/* addr of last next element */ \
+}
+
+#define STAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).stqh_first }
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
+
+#define STAILQ_FIRST(head) ((head)->stqh_first)
+
+#define STAILQ_FOREACH_FROM(var, head, field) \
+ for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
+ (var); \
+ (var) = STAILQ_NEXT((var), field))
+
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = STAILQ_FIRST((head)); \
+ (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
+ for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
+ (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define STAILQ_LAST(head, type, field) \
+ (STAILQ_EMPTY((head)) ? NULL : \
+ __containerof((head)->stqh_last, struct type, field.stqe_next))
+
+#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
+
+#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
+ if ((STAILQ_NEXT(elm, field) = \
+ STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+} while (0)
+
+#define STAILQ_SWAP(head1, head2, type) do { \
+ struct type *swap_first = STAILQ_FIRST(head1); \
+ struct type **swap_last = (head1)->stqh_last; \
+ STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
+ (head1)->stqh_last = (head2)->stqh_last; \
+ STAILQ_FIRST(head2) = swap_first; \
+ (head2)->stqh_last = swap_last; \
+ if (STAILQ_EMPTY(head1)) \
+ (head1)->stqh_last = &STAILQ_FIRST(head1); \
+ if (STAILQ_EMPTY(head2)) \
+ (head2)->stqh_last = &STAILQ_FIRST(head2); \
+} while (0)
+
+/*
+ * List declarations.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List functions.
+ */
+
+#if (defined(_KERNEL) && defined(INVARIANTS))
+#define QMD_LIST_CHECK_HEAD(head, field) do { \
+ if (LIST_FIRST((head)) != NULL && \
+ LIST_FIRST((head))->field.le_prev != \
+ &LIST_FIRST((head))) \
+ panic("Bad list head %p first->prev != head", (head)); \
+} while (0)
+
+#define QMD_LIST_CHECK_NEXT(elm, field) do { \
+ if (LIST_NEXT((elm), field) != NULL && \
+ LIST_NEXT((elm), field)->field.le_prev != \
+ &((elm)->field.le_next)) \
+ panic("Bad link elm %p next->prev != elm", (elm)); \
+} while (0)
+
+#define QMD_LIST_CHECK_PREV(elm, field) do { \
+ if (*(elm)->field.le_prev != (elm)) \
+ panic("Bad link elm %p prev->next != elm", (elm)); \
+} while (0)
+#else
+#define QMD_LIST_CHECK_HEAD(head, field)
+#define QMD_LIST_CHECK_NEXT(elm, field)
+#define QMD_LIST_CHECK_PREV(elm, field)
+#endif /* (_KERNEL && INVARIANTS) */
+
+#define LIST_EMPTY(head) ((head)->lh_first == NULL)
+
+#define LIST_FIRST(head) ((head)->lh_first)
+
+#define LIST_FOREACH_FROM(var, head, field) \
+ for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
+ (var); \
+ (var) = LIST_NEXT((var), field))
+
+#define LIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = LIST_FIRST((head)); \
+ (var) && ((tvar) = LIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
+ for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
+ (var) && ((tvar) = LIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_PREV(elm, head, type, field) \
+ ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \
+ __containerof((elm)->field.le_prev, struct type, field.le_next))
+
+#define LIST_SWAP(head1, head2, type, field) do { \
+ struct type *swap_tmp = LIST_FIRST((head1)); \
+ LIST_FIRST((head1)) = LIST_FIRST((head2)); \
+ LIST_FIRST((head2)) = swap_tmp; \
+ if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
+ swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
+ if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
+ swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
+} while (0)
+
+/*
+ * Tail queue functions.
+ */
+#if (defined(_KERNEL) && defined(INVARIANTS))
+#define QMD_TAILQ_CHECK_HEAD(head, field) do { \
+ if (!TAILQ_EMPTY(head) && \
+ TAILQ_FIRST((head))->field.tqe_prev != \
+ &TAILQ_FIRST((head))) \
+ panic("Bad tailq head %p first->prev != head", (head)); \
+} while (0)
+
+#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
+ if (*(head)->tqh_last != NULL) \
+ panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
+} while (0)
+
+#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
+ if (TAILQ_NEXT((elm), field) != NULL && \
+ TAILQ_NEXT((elm), field)->field.tqe_prev != \
+ &((elm)->field.tqe_next)) \
+ panic("Bad link elm %p next->prev != elm", (elm)); \
+} while (0)
+
+#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
+ if (*(elm)->field.tqe_prev != (elm)) \
+ panic("Bad link elm %p prev->next != elm", (elm)); \
+} while (0)
+#else
+#define QMD_TAILQ_CHECK_HEAD(head, field)
+#define QMD_TAILQ_CHECK_TAIL(head, headname)
+#define QMD_TAILQ_CHECK_NEXT(elm, field)
+#define QMD_TAILQ_CHECK_PREV(elm, field)
+#endif /* (_KERNEL && INVARIANTS) */
+
+#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
+
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+
+#define TAILQ_FOREACH_FROM(var, head, field) \
+ for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
+ (var); \
+ (var) = TAILQ_NEXT((var), field))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TAILQ_FIRST((head)); \
+ (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
+ for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
+ (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \
+ for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
+ (var); \
+ (var) = TAILQ_PREV((var), headname, field))
+
+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
+ for ((var) = TAILQ_LAST((head), headname); \
+ (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
+ (var) = (tvar))
+
+#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \
+ for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
+ (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
+ (var) = (tvar))
+
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define TAILQ_SWAP(head1, head2, type, field) do { \
+ struct type *swap_first = (head1)->tqh_first; \
+ struct type **swap_last = (head1)->tqh_last; \
+ (head1)->tqh_first = (head2)->tqh_first; \
+ (head1)->tqh_last = (head2)->tqh_last; \
+ (head2)->tqh_first = swap_first; \
+ (head2)->tqh_last = swap_last; \
+ if ((swap_first = (head1)->tqh_first) != NULL) \
+ swap_first->field.tqe_prev = &(head1)->tqh_first; \
+ else \
+ (head1)->tqh_last = &(head1)->tqh_first; \
+ if ((swap_first = (head2)->tqh_first) != NULL) \
+ swap_first->field.tqe_prev = &(head2)->tqh_first; \
+ else \
+ (head2)->tqh_last = &(head2)->tqh_first; \
+} while (0)
+
+#endif
diff --git a/src/spdk/include/spdk/rpc.h b/src/spdk/include/spdk/rpc.h
new file mode 100644
index 00000000..ab1fa61b
--- /dev/null
+++ b/src/spdk/include/spdk/rpc.h
@@ -0,0 +1,106 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SPDK_RPC_CONFIG_H_
+#define SPDK_RPC_CONFIG_H_
+
+#include "spdk/stdinc.h"
+
+#include "spdk/jsonrpc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Start listening for RPC connections.
+ *
+ * \param listen_addr Listening address.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_rpc_listen(const char *listen_addr);
+
+/**
+ * Poll the RPC server.
+ */
+void spdk_rpc_accept(void);
+
+/**
+ * Stop listening for RPC connections.
+ */
+void spdk_rpc_close(void);
+
+/**
+ * Function signature for RPC request handlers.
+ *
+ * \param request RPC request to handle.
+ * \param params Parameters associated with the RPC request.
+ */
+typedef void (*spdk_rpc_method_handler)(struct spdk_jsonrpc_request *request,
+ const struct spdk_json_val *params);
+
+/**
+ * Register an RPC method.
+ *
+ * \param method Name for the registered method.
+ * \param func Function registered for this method to handle the RPC request.
+ * \param state_mask State mask of the registered method. If the bit of the state of
+ * the RPC server is set in the state_mask, the method is allowed. Otherwise, it is rejected.
+ */
+void spdk_rpc_register_method(const char *method, spdk_rpc_method_handler func,
+ uint32_t state_mask);
+
+#define SPDK_RPC_STARTUP 0x1
+#define SPDK_RPC_RUNTIME 0x2
+
+#define SPDK_RPC_REGISTER(method, func, state_mask) \
+static void __attribute__((constructor)) rpc_register_##func(void) \
+{ \
+ spdk_rpc_register_method(method, func, state_mask); \
+}
+
+/**
+ * Set the state mask of the RPC server. Any RPC method whose state mask is
+ * equal to the state of the RPC server is allowed.
+ *
+ * \param state_mask New state mask of the RPC server.
+ */
+void spdk_rpc_set_state(uint32_t state_mask);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/scsi.h b/src/spdk/include/spdk/scsi.h
new file mode 100644
index 00000000..6ecea307
--- /dev/null
+++ b/src/spdk/include/spdk/scsi.h
@@ -0,0 +1,517 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * SCSI to bdev translation layer
+ */
+
+#ifndef SPDK_SCSI_H
+#define SPDK_SCSI_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/bdev.h"
+#include "spdk/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Defines for SPDK tracing framework */
+#define OWNER_SCSI_DEV 0x10
+#define OBJECT_SCSI_TASK 0x10
+#define TRACE_GROUP_SCSI 0x2
+#define TRACE_SCSI_TASK_DONE SPDK_TPOINT_ID(TRACE_GROUP_SCSI, 0x0)
+#define TRACE_SCSI_TASK_START SPDK_TPOINT_ID(TRACE_GROUP_SCSI, 0x1)
+
+#define SPDK_SCSI_MAX_DEVS 1024
+#define SPDK_SCSI_DEV_MAX_LUN 64
+#define SPDK_SCSI_DEV_MAX_PORTS 4
+#define SPDK_SCSI_DEV_MAX_NAME 255
+
+#define SPDK_SCSI_PORT_MAX_NAME_LENGTH 255
+
+enum spdk_scsi_data_dir {
+ SPDK_SCSI_DIR_NONE = 0,
+ SPDK_SCSI_DIR_TO_DEV = 1,
+ SPDK_SCSI_DIR_FROM_DEV = 2,
+};
+
+enum spdk_scsi_task_func {
+ SPDK_SCSI_TASK_FUNC_ABORT_TASK = 0,
+ SPDK_SCSI_TASK_FUNC_ABORT_TASK_SET,
+ SPDK_SCSI_TASK_FUNC_CLEAR_TASK_SET,
+ SPDK_SCSI_TASK_FUNC_LUN_RESET,
+};
+
+/*
+ * SAM does not define the value for these service responses. Each transport
+ * (i.e. SAS, FC, iSCSI) will map these value to transport-specific codes,
+ * and may add their own.
+ */
+enum spdk_scsi_task_mgmt_resp {
+ SPDK_SCSI_TASK_MGMT_RESP_COMPLETE,
+ SPDK_SCSI_TASK_MGMT_RESP_SUCCESS,
+ SPDK_SCSI_TASK_MGMT_RESP_REJECT,
+ SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN,
+ SPDK_SCSI_TASK_MGMT_RESP_TARGET_FAILURE,
+ SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED
+};
+
+struct spdk_scsi_task;
+typedef void (*spdk_scsi_task_cpl)(struct spdk_scsi_task *task);
+typedef void (*spdk_scsi_task_free)(struct spdk_scsi_task *task);
+
+struct spdk_scsi_task {
+ uint8_t status;
+ uint8_t function; /* task mgmt function */
+ uint8_t response; /* task mgmt response */
+
+ struct spdk_scsi_lun *lun;
+ struct spdk_scsi_port *target_port;
+ struct spdk_scsi_port *initiator_port;
+
+ spdk_scsi_task_cpl cpl_fn;
+ spdk_scsi_task_free free_fn;
+
+ uint32_t ref;
+ uint32_t transfer_len;
+ uint32_t dxfer_dir;
+ uint32_t length;
+
+ /**
+ * Amount of data actually transferred. Can be less than requested
+ * transfer_len - i.e. SCSI INQUIRY.
+ */
+ uint32_t data_transferred;
+
+ uint64_t offset;
+
+ uint8_t *cdb;
+
+ /**
+ * \internal
+ * Size of internal buffer or zero when iov.iov_base is not internally managed.
+ */
+ uint32_t alloc_len;
+ /**
+ * \internal
+ * iov is internal buffer. Use iovs to access elements of IO.
+ */
+ struct iovec iov;
+ struct iovec *iovs;
+ uint16_t iovcnt;
+
+ uint8_t sense_data[32];
+ size_t sense_data_len;
+
+ void *bdev_io;
+
+ TAILQ_ENTRY(spdk_scsi_task) scsi_link;
+
+ uint32_t abort_id;
+ struct spdk_bdev_io_wait_entry bdev_io_wait;
+};
+
+struct spdk_scsi_port;
+struct spdk_scsi_dev;
+struct spdk_scsi_lun;
+struct spdk_scsi_desc;
+
+typedef void (*spdk_scsi_remove_cb_t)(struct spdk_scsi_lun *, void *);
+
+/**
+ * Initialize SCSI layer.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_scsi_init(void);
+
+/**
+ * Stop and clean the SCSI layer.
+ */
+void spdk_scsi_fini(void);
+
+/**
+ * Get the LUN id of the given logical unit.
+ *
+ * \param lun Logical unit.
+ *
+ * \return LUN id of the logical unit.
+ */
+int spdk_scsi_lun_get_id(const struct spdk_scsi_lun *lun);
+
+/**
+ * Get the name of the bdev associated with the given logical unit.
+ *
+ * \param lun Logical unit.
+ *
+ * \return the name of the bdev associated with the logical unit.
+ */
+const char *spdk_scsi_lun_get_bdev_name(const struct spdk_scsi_lun *lun);
+
+/**
+ * Get the SCSI device associated with the given logical unit.
+ *
+ * \param lun Logical unit.
+ *
+ * \return the SCSI device associated with the logical unit.
+ */
+const struct spdk_scsi_dev *spdk_scsi_lun_get_dev(const struct spdk_scsi_lun *lun);
+
+/**
+ * Check if the logical unit is hot removing.
+ *
+ * \param lun Logical unit
+ *
+ * \return true if removing, false otherwise.
+ */
+bool spdk_scsi_lun_is_removing(const struct spdk_scsi_lun *lun);
+
+/**
+ * Get the name of the given SCSI device.
+ *
+ * \param dev SCSI device.
+ *
+ * \return the name of the SCSI device on success, or NULL on failure.
+ */
+const char *spdk_scsi_dev_get_name(const struct spdk_scsi_dev *dev);
+
+/**
+ * Get the id of the given SCSI device.
+ *
+ * \param dev SCSI device.
+ *
+ * \return the id of the SCSI device.
+ */
+int spdk_scsi_dev_get_id(const struct spdk_scsi_dev *dev);
+
+/**
+ * Get the logical unit of the given SCSI device whose id is lun_id.
+ *
+ * \param dev SCSI device.
+ * \param lun_id Id of the logical unit.
+ *
+ * \return the logical unit on success, or NULL on failure.
+ */
+struct spdk_scsi_lun *spdk_scsi_dev_get_lun(struct spdk_scsi_dev *dev, int lun_id);
+
+/**
+ * Check whether the SCSI device has any pending task.
+ *
+ * \param dev SCSI device.
+ *
+ * \return true if the SCSI device has any pending task, or false otherwise.
+ */
+bool spdk_scsi_dev_has_pending_tasks(const struct spdk_scsi_dev *dev);
+
+/**
+ * Destruct the SCSI decice.
+ *
+ * \param dev SCSI device.
+ */
+void spdk_scsi_dev_destruct(struct spdk_scsi_dev *dev);
+
+/**
+ * Execute the SCSI management task.
+ *
+ * The task can be constructed by the function spdk_scsi_task_construct().
+ *
+ * \param dev SCSI device.
+ * \param task SCSI task to be executed.
+ * \param func Task management function to be executed.
+ */
+void spdk_scsi_dev_queue_mgmt_task(struct spdk_scsi_dev *dev, struct spdk_scsi_task *task,
+ enum spdk_scsi_task_func func);
+/**
+ * Execute the SCSI task.
+ *
+ * The task can be constructed by the function spdk_scsi_task_construct().
+ *
+ * \param dev SCSI device.
+ * \param task Task to be executed.
+ */
+void spdk_scsi_dev_queue_task(struct spdk_scsi_dev *dev, struct spdk_scsi_task *task);
+
+/**
+ * Add a new port to the given SCSI device.
+ *
+ * \param dev SCSI device.
+ * \param id Port id.
+ * \param name Port name.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_scsi_dev_add_port(struct spdk_scsi_dev *dev, uint64_t id, const char *name);
+
+/**
+ * Delete a specified port of the given SCSI device.
+ *
+ * \param dev SCSI device.
+ * \param id Port id.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_scsi_dev_delete_port(struct spdk_scsi_dev *dev, uint64_t id);
+
+/**
+ * Get the port of the given SCSI device whose port ID is id.
+ *
+ * \param dev SCSI device.
+ * \param id Port id.
+ *
+ * \return the port of the SCSI device on success, or NULL on failure.
+ */
+struct spdk_scsi_port *spdk_scsi_dev_find_port_by_id(struct spdk_scsi_dev *dev, uint64_t id);
+
+/**
+ * Allocate I/O channels for all LUNs of the given SCSI device.
+ *
+ * \param dev SCSI device.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_scsi_dev_allocate_io_channels(struct spdk_scsi_dev *dev);
+
+/**
+ * Free I/O channels from all LUNs of the given SCSI device.
+ */
+void spdk_scsi_dev_free_io_channels(struct spdk_scsi_dev *dev);
+
+/**
+ * Construct a SCSI device object using the given parameters.
+ *
+ * \param name Name for the SCSI device.
+ * \param bdev_name_list List of bdev names to attach to the LUNs for this SCSI
+ * device.
+ * \param lun_id_list List of LUN IDs for the LUN in this SCSI device. Caller is
+ * responsible for managing the memory containing this list. lun_id_list[x] is
+ * the LUN ID for lun_list[x].
+ * \param num_luns Number of entries in lun_list and lun_id_list.
+ * \param protocol_id SCSI SPC protocol identifier to report in INQUIRY data
+ * \param hotremove_cb Callback to lun hotremoval. Will be called once hotremove
+ * is first triggered.
+ * \param hotremove_ctx Additional argument to hotremove_cb.
+ *
+ * \return the constructed spdk_scsi_dev object.
+ */
+struct spdk_scsi_dev *spdk_scsi_dev_construct(const char *name,
+ const char *bdev_name_list[],
+ int *lun_id_list,
+ int num_luns,
+ uint8_t protocol_id,
+ void (*hotremove_cb)(const struct spdk_scsi_lun *, void *),
+ void *hotremove_ctx);
+
+/**
+ * Delete a logical unit of the given SCSI device.
+ *
+ * \param dev SCSI device.
+ * \param lun Logical unit to delete.
+ */
+void spdk_scsi_dev_delete_lun(struct spdk_scsi_dev *dev, struct spdk_scsi_lun *lun);
+
+/**
+ * Add a new logical unit to the given SCSI device.
+ *
+ * \param dev SCSI device.
+ * \param bdev_name Name of the bdev attached to the logical unit.
+ * \param lun_id LUN id for the new logical unit.
+ * \param hotremove_cb Callback to lun hotremoval. Will be called once hotremove
+ * is first triggered.
+ * \param hotremove_ctx Additional argument to hotremove_cb.
+ */
+int spdk_scsi_dev_add_lun(struct spdk_scsi_dev *dev, const char *bdev_name, int lun_id,
+ void (*hotremove_cb)(const struct spdk_scsi_lun *, void *),
+ void *hotremove_ctx);
+
+/**
+ * Create a new SCSI port.
+ *
+ * \param id Port id.
+ * \param index Port index.
+ * \param name Port Name.
+ *
+ * \return a pointer to the created SCSI port on success, or NULL on failure.
+ */
+struct spdk_scsi_port *spdk_scsi_port_create(uint64_t id, uint16_t index, const char *name);
+
+/**
+ * Free the SCSI port.
+ *
+ * \param pport SCSI port to free.
+ */
+void spdk_scsi_port_free(struct spdk_scsi_port **pport);
+
+/**
+ * Get the name of the SCSI port.
+ *
+ * \param port SCSI port to query.
+ *
+ * \return the name of the SCSI port.
+ */
+const char *spdk_scsi_port_get_name(const struct spdk_scsi_port *port);
+
+/**
+ * Construct a new SCSI task.
+ *
+ * \param task SCSI task to consturct.
+ * \param cpl_fn Called when the task is completed.
+ * \param free_fn Called when the task is freed
+ */
+void spdk_scsi_task_construct(struct spdk_scsi_task *task,
+ spdk_scsi_task_cpl cpl_fn,
+ spdk_scsi_task_free free_fn);
+
+/**
+ * Put the SCSI task.
+ *
+ * \param task SCSI task to put.
+ */
+void spdk_scsi_task_put(struct spdk_scsi_task *task);
+
+/**
+ * Set internal buffer to given one. Caller is owner of that buffer.
+ *
+ * \param task SCSI task.
+ * \param data Pointer to buffer.
+ * \param len Buffer length.
+ */
+void spdk_scsi_task_set_data(struct spdk_scsi_task *task, void *data, uint32_t len);
+
+/**
+ * Single buffer -> vector of buffers.
+ *
+ * \param task SCSI task.
+ * \param src A pointer to the data buffer read from.
+ * \param len Length of the data buffer read from.
+ *
+ * \return the total length of the vector of buffers written into on success, or
+ * -1 on failure.
+ */
+int spdk_scsi_task_scatter_data(struct spdk_scsi_task *task, const void *src, size_t len);
+
+/**
+ * Vector of buffers -> single buffer.
+ *
+ * \param task SCSI task,
+ * \param len Length of the buffer allocated and written into.
+ *
+ * \return a pointer to the buffer allocated and written into.
+ */
+void *spdk_scsi_task_gather_data(struct spdk_scsi_task *task, int *len);
+
+/**
+ * Build sense data for the SCSI task.
+ *
+ * \param task SCSI task.
+ * \param sk Sense key.
+ * \param asc Additional sense code.
+ * \param ascq Additional sense code qualifier.
+ */
+void spdk_scsi_task_build_sense_data(struct spdk_scsi_task *task, int sk, int asc,
+ int ascq);
+
+/**
+ * Set SCSI status code to the SCSI task. When the status code is CHECK CONDITION,
+ * sense data is build too.
+ *
+ * \param task SCSI task.
+ * \param sc Sense code
+ * \param sk Sense key.
+ * \param asc Additional sense code.
+ * \param ascq Additional sense code qualifier.
+ */
+void spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk, int asc,
+ int ascq);
+
+/**
+ * Copy SCSI status.
+ *
+ * \param dst SCSI task whose status is written to.
+ * \param src SCSI task whose status is read from.
+ */
+void spdk_scsi_task_copy_status(struct spdk_scsi_task *dst, struct spdk_scsi_task *src);
+
+/**
+ * Process the SCSI task when no LUN is attached.
+ *
+ * \param task SCSI task.
+ */
+void spdk_scsi_task_process_null_lun(struct spdk_scsi_task *task);
+
+/**
+ * Open a logical unit for I/O operations.
+ *
+ * The registered callback function must get all tasks from the upper layer
+ * (e.g. iSCSI) to the LUN done, free the IO channel of the LUN if allocated,
+ * and then close the LUN.
+ *
+ * \param lun Logical unit to open.
+ * \param hotremove_cb Callback function for hot removal of the logical unit.
+ * \param hotremove_ctx Param for hot removal callback function.
+ * \param desc Output parameter for the descriptor when operation is successful.
+ * \return 0 if operation is successful, suitable errno value otherwise
+ */
+int spdk_scsi_lun_open(struct spdk_scsi_lun *lun, spdk_scsi_remove_cb_t hotremove_cb,
+ void *hotremove_ctx, struct spdk_scsi_desc **desc);
+
+/**
+ * Close an opened logical unit.
+ *
+ * \param desc Descriptor of the logical unit.
+ */
+void spdk_scsi_lun_close(struct spdk_scsi_desc *desc);
+
+/**
+ * Allocate I/O channel for the LUN
+ *
+ * \param desc Descriptor of the logical unit.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_desc *desc);
+
+/**
+ * Free I/O channel from the logical unit
+ *
+ * \param desc Descriptor of the logical unit.
+ */
+void spdk_scsi_lun_free_io_channel(struct spdk_scsi_desc *desc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_SCSI_H */
diff --git a/src/spdk/include/spdk/scsi_spec.h b/src/spdk/include/spdk/scsi_spec.h
new file mode 100644
index 00000000..22723f32
--- /dev/null
+++ b/src/spdk/include/spdk/scsi_spec.h
@@ -0,0 +1,508 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * SCSI specification definitions
+ */
+
+#ifndef SPDK_SCSI_SPEC_H
+#define SPDK_SCSI_SPEC_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/assert.h"
+
+enum spdk_scsi_group_code {
+ SPDK_SCSI_6BYTE_CMD = 0x00,
+ SPDK_SCSI_10BYTE_CMD = 0x20,
+ SPDK_SCSI_10BYTE_CMD2 = 0x40,
+ SPDK_SCSI_16BYTE_CMD = 0x80,
+ SPDK_SCSI_12BYTE_CMD = 0xa0,
+};
+
+#define SPDK_SCSI_GROUP_MASK 0xe0
+#define SPDK_SCSI_OPCODE_MASK 0x1f
+
+enum spdk_scsi_status {
+ SPDK_SCSI_STATUS_GOOD = 0x00,
+ SPDK_SCSI_STATUS_CHECK_CONDITION = 0x02,
+ SPDK_SCSI_STATUS_CONDITION_MET = 0x04,
+ SPDK_SCSI_STATUS_BUSY = 0x08,
+ SPDK_SCSI_STATUS_INTERMEDIATE = 0x10,
+ SPDK_SCSI_STATUS_INTERMEDIATE_CONDITION_MET = 0x14,
+ SPDK_SCSI_STATUS_RESERVATION_CONFLICT = 0x18,
+ SPDK_SCSI_STATUS_Obsolete = 0x22,
+ SPDK_SCSI_STATUS_TASK_SET_FULL = 0x28,
+ SPDK_SCSI_STATUS_ACA_ACTIVE = 0x30,
+ SPDK_SCSI_STATUS_TASK_ABORTED = 0x40,
+};
+
+enum spdk_scsi_sense {
+ SPDK_SCSI_SENSE_NO_SENSE = 0x00,
+ SPDK_SCSI_SENSE_RECOVERED_ERROR = 0x01,
+ SPDK_SCSI_SENSE_NOT_READY = 0x02,
+ SPDK_SCSI_SENSE_MEDIUM_ERROR = 0x03,
+ SPDK_SCSI_SENSE_HARDWARE_ERROR = 0x04,
+ SPDK_SCSI_SENSE_ILLEGAL_REQUEST = 0x05,
+ SPDK_SCSI_SENSE_UNIT_ATTENTION = 0x06,
+ SPDK_SCSI_SENSE_DATA_PROTECT = 0x07,
+ SPDK_SCSI_SENSE_BLANK_CHECK = 0x08,
+ SPDK_SCSI_SENSE_VENDOR_SPECIFIC = 0x09,
+ SPDK_SCSI_SENSE_COPY_ABORTED = 0x0a,
+ SPDK_SCSI_SENSE_ABORTED_COMMAND = 0x0b,
+ SPDK_SCSI_SENSE_VOLUME_OVERFLOW = 0x0d,
+ SPDK_SCSI_SENSE_MISCOMPARE = 0x0e,
+};
+
+enum spdk_scsi_asc {
+ SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE = 0x00,
+ SPDK_SCSI_ASC_PERIPHERAL_DEVICE_WRITE_FAULT = 0x03,
+ SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_READY = 0x04,
+ SPDK_SCSI_ASC_WARNING = 0x0b,
+ SPDK_SCSI_ASC_LOGICAL_BLOCK_GUARD_CHECK_FAILED = 0x10,
+ SPDK_SCSI_ASC_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED = 0x10,
+ SPDK_SCSI_ASC_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED = 0x10,
+ SPDK_SCSI_ASC_UNRECOVERED_READ_ERROR = 0x11,
+ SPDK_SCSI_ASC_MISCOMPARE_DURING_VERIFY_OPERATION = 0x1d,
+ SPDK_SCSI_ASC_INVALID_COMMAND_OPERATION_CODE = 0x20,
+ SPDK_SCSI_ASC_ACCESS_DENIED = 0x20,
+ SPDK_SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE = 0x21,
+ SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB = 0x24,
+ SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED = 0x25,
+ SPDK_SCSI_ASC_WRITE_PROTECTED = 0x27,
+ SPDK_SCSI_ASC_FORMAT_COMMAND_FAILED = 0x31,
+ SPDK_SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED = 0x39,
+ SPDK_SCSI_ASC_INTERNAL_TARGET_FAILURE = 0x44,
+};
+
+enum spdk_scsi_ascq {
+ SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE = 0x00,
+ SPDK_SCSI_ASCQ_BECOMING_READY = 0x01,
+ SPDK_SCSI_ASCQ_FORMAT_COMMAND_FAILED = 0x01,
+ SPDK_SCSI_ASCQ_LOGICAL_BLOCK_GUARD_CHECK_FAILED = 0x01,
+ SPDK_SCSI_ASCQ_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED = 0x02,
+ SPDK_SCSI_ASCQ_NO_ACCESS_RIGHTS = 0x02,
+ SPDK_SCSI_ASCQ_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED = 0x03,
+ SPDK_SCSI_ASCQ_POWER_LOSS_EXPECTED = 0x08,
+ SPDK_SCSI_ASCQ_INVALID_LU_IDENTIFIER = 0x09,
+};
+
+enum spdk_spc_opcode {
+ /* SPC3 related */
+ SPDK_SPC_ACCESS_CONTROL_IN = 0x86,
+ SPDK_SPC_ACCESS_CONTROL_OUT = 0x87,
+ SPDK_SPC_EXTENDED_COPY = 0x83,
+ SPDK_SPC_INQUIRY = 0x12,
+ SPDK_SPC_LOG_SELECT = 0x4c,
+ SPDK_SPC_LOG_SENSE = 0x4d,
+ SPDK_SPC_MODE_SELECT_6 = 0x15,
+ SPDK_SPC_MODE_SELECT_10 = 0x55,
+ SPDK_SPC_MODE_SENSE_6 = 0x1a,
+ SPDK_SPC_MODE_SENSE_10 = 0x5a,
+ SPDK_SPC_PERSISTENT_RESERVE_IN = 0x5e,
+ SPDK_SPC_PERSISTENT_RESERVE_OUT = 0x5f,
+ SPDK_SPC_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1e,
+ SPDK_SPC_READ_ATTRIBUTE = 0x8c,
+ SPDK_SPC_READ_BUFFER = 0x3c,
+ SPDK_SPC_RECEIVE_COPY_RESULTS = 0x84,
+ SPDK_SPC_RECEIVE_DIAGNOSTIC_RESULTS = 0x1c,
+ SPDK_SPC_REPORT_LUNS = 0xa0,
+ SPDK_SPC_REQUEST_SENSE = 0x03,
+ SPDK_SPC_SEND_DIAGNOSTIC = 0x1d,
+ SPDK_SPC_TEST_UNIT_READY = 0x00,
+ SPDK_SPC_WRITE_ATTRIBUTE = 0x8d,
+ SPDK_SPC_WRITE_BUFFER = 0x3b,
+
+ SPDK_SPC_SERVICE_ACTION_IN_12 = 0xab,
+ SPDK_SPC_SERVICE_ACTION_OUT_12 = 0xa9,
+ SPDK_SPC_SERVICE_ACTION_IN_16 = 0x9e,
+ SPDK_SPC_SERVICE_ACTION_OUT_16 = 0x9f,
+
+ SPDK_SPC_VARIABLE_LENGTH = 0x7f,
+
+ SPDK_SPC_MO_CHANGE_ALIASES = 0x0b,
+ SPDK_SPC_MO_SET_DEVICE_IDENTIFIER = 0x06,
+ SPDK_SPC_MO_SET_PRIORITY = 0x0e,
+ SPDK_SPC_MO_SET_TARGET_PORT_GROUPS = 0x0a,
+ SPDK_SPC_MO_SET_TIMESTAMP = 0x0f,
+ SPDK_SPC_MI_REPORT_ALIASES = 0x0b,
+ SPDK_SPC_MI_REPORT_DEVICE_IDENTIFIER = 0x05,
+ SPDK_SPC_MI_REPORT_PRIORITY = 0x0e,
+ SPDK_SPC_MI_REPORT_SUPPORTED_OPERATION_CODES = 0x0c,
+ SPDK_SPC_MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS = 0x0d,
+ SPDK_SPC_MI_REPORT_TARGET_PORT_GROUPS = 0x0a,
+ SPDK_SPC_MI_REPORT_TIMESTAMP = 0x0f,
+
+ /* SPC2 related (Obsolete) */
+ SPDK_SPC2_RELEASE_6 = 0x17,
+ SPDK_SPC2_RELEASE_10 = 0x57,
+ SPDK_SPC2_RESERVE_6 = 0x16,
+ SPDK_SPC2_RESERVE_10 = 0x56,
+};
+
+enum spdk_scc_opcode {
+ SPDK_SCC_MAINTENANCE_IN = 0xa3,
+ SPDK_SCC_MAINTENANCE_OUT = 0xa4,
+};
+
+enum spdk_sbc_opcode {
+ SPDK_SBC_COMPARE_AND_WRITE = 0x89,
+ SPDK_SBC_FORMAT_UNIT = 0x04,
+ SPDK_SBC_GET_LBA_STATUS = 0x0012009e,
+ SPDK_SBC_ORWRITE_16 = 0x8b,
+ SPDK_SBC_PRE_FETCH_10 = 0x34,
+ SPDK_SBC_PRE_FETCH_16 = 0x90,
+ SPDK_SBC_READ_6 = 0x08,
+ SPDK_SBC_READ_10 = 0x28,
+ SPDK_SBC_READ_12 = 0xa8,
+ SPDK_SBC_READ_16 = 0x88,
+ SPDK_SBC_READ_ATTRIBUTE = 0x8c,
+ SPDK_SBC_READ_BUFFER = 0x3c,
+ SPDK_SBC_READ_CAPACITY_10 = 0x25,
+ SPDK_SBC_READ_DEFECT_DATA_10 = 0x37,
+ SPDK_SBC_READ_DEFECT_DATA_12 = 0xb7,
+ SPDK_SBC_READ_LONG_10 = 0x3e,
+ SPDK_SBC_REASSIGN_BLOCKS = 0x07,
+ SPDK_SBC_SANITIZE = 0x48,
+ SPDK_SBC_START_STOP_UNIT = 0x1b,
+ SPDK_SBC_SYNCHRONIZE_CACHE_10 = 0x35,
+ SPDK_SBC_SYNCHRONIZE_CACHE_16 = 0x91,
+ SPDK_SBC_UNMAP = 0x42,
+ SPDK_SBC_VERIFY_10 = 0x2f,
+ SPDK_SBC_VERIFY_12 = 0xaf,
+ SPDK_SBC_VERIFY_16 = 0x8f,
+ SPDK_SBC_WRITE_6 = 0x0a,
+ SPDK_SBC_WRITE_10 = 0x2a,
+ SPDK_SBC_WRITE_12 = 0xaa,
+ SPDK_SBC_WRITE_16 = 0x8a,
+ SPDK_SBC_WRITE_AND_VERIFY_10 = 0x2e,
+ SPDK_SBC_WRITE_AND_VERIFY_12 = 0xae,
+ SPDK_SBC_WRITE_AND_VERIFY_16 = 0x8e,
+ SPDK_SBC_WRITE_LONG_10 = 0x3f,
+ SPDK_SBC_WRITE_SAME_10 = 0x41,
+ SPDK_SBC_WRITE_SAME_16 = 0x93,
+ SPDK_SBC_XDREAD_10 = 0x52,
+ SPDK_SBC_XDWRITE_10 = 0x50,
+ SPDK_SBC_XDWRITEREAD_10 = 0x53,
+ SPDK_SBC_XPWRITE_10 = 0x51,
+
+ SPDK_SBC_SAI_READ_CAPACITY_16 = 0x10,
+ SPDK_SBC_SAI_READ_LONG_16 = 0x11,
+ SPDK_SBC_SAO_WRITE_LONG_16 = 0x11,
+
+ SPDK_SBC_VL_READ_32 = 0x0009,
+ SPDK_SBC_VL_VERIFY_32 = 0x000a,
+ SPDK_SBC_VL_WRITE_32 = 0x000b,
+ SPDK_SBC_VL_WRITE_AND_VERIFY_32 = 0x000c,
+ SPDK_SBC_VL_WRITE_SAME_32 = 0x000d,
+ SPDK_SBC_VL_XDREAD_32 = 0x0003,
+ SPDK_SBC_VL_XDWRITE_32 = 0x0004,
+ SPDK_SBC_VL_XDWRITEREAD_32 = 0x0007,
+ SPDK_SBC_VL_XPWRITE_32 = 0x0006,
+};
+
+#define SPDK_SBC_START_STOP_UNIT_START_BIT (1 << 0)
+
+enum spdk_mmc_opcode {
+ /* MMC6 */
+ SPDK_MMC_READ_DISC_STRUCTURE = 0xad,
+
+ /* MMC4 */
+ SPDK_MMC_BLANK = 0xa1,
+ SPDK_MMC_CLOSE_TRACK_SESSION = 0x5b,
+ SPDK_MMC_ERASE_10 = 0x2c,
+ SPDK_MMC_FORMAT_UNIT = 0x04,
+ SPDK_MMC_GET_CONFIGURATION = 0x46,
+ SPDK_MMC_GET_EVENT_STATUS_NOTIFICATION = 0x4a,
+ SPDK_MMC_GET_PERFORMANCE = 0xac,
+ SPDK_MMC_INQUIRY = 0x12,
+ SPDK_MMC_LOAD_UNLOAD_MEDIUM = 0xa6,
+ SPDK_MMC_MECHANISM_STATUS = 0xbd,
+ SPDK_MMC_MODE_SELECT_10 = 0x55,
+ SPDK_MMC_MODE_SENSE_10 = 0x5a,
+ SPDK_MMC_PAUSE_RESUME = 0x4b,
+ SPDK_MMC_PLAY_AUDIO_10 = 0x45,
+ SPDK_MMC_PLAY_AUDIO_12 = 0xa5,
+ SPDK_MMC_PLAY_AUDIO_MSF = 0x47,
+ SPDK_MMC_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1e,
+ SPDK_MMC_READ_10 = 0x28,
+ SPDK_MMC_READ_12 = 0xa8,
+ SPDK_MMC_READ_BUFFER = 0x3c,
+ SPDK_MMC_READ_BUFFER_CAPACITY = 0x5c,
+ SPDK_MMC_READ_CAPACITY = 0x25,
+ SPDK_MMC_READ_CD = 0xbe,
+ SPDK_MMC_READ_CD_MSF = 0xb9,
+ SPDK_MMC_READ_DISC_INFORMATION = 0x51,
+ SPDK_MMC_READ_DVD_STRUCTURE = 0xad,
+ SPDK_MMC_READ_FORMAT_CAPACITIES = 0x23,
+ SPDK_MMC_READ_SUB_CHANNEL = 0x42,
+ SPDK_MMC_READ_TOC_PMA_ATIP = 0x43,
+ SPDK_MMC_READ_TRACK_INFORMATION = 0x52,
+ SPDK_MMC_REPAIR_TRACK = 0x58,
+ SPDK_MMC_REPORT_KEY = 0xa4,
+ SPDK_MMC_REQUEST_SENSE = 0x03,
+ SPDK_MMC_RESERVE_TRACK = 0x53,
+ SPDK_MMC_SCAN = 0xba,
+ SPDK_MMC_SEEK_10 = 0x2b,
+ SPDK_MMC_SEND_CUE_SHEET = 0x5d,
+ SPDK_MMC_SEND_DVD_STRUCTURE = 0xbf,
+ SPDK_MMC_SEND_KEY = 0xa3,
+ SPDK_MMC_SEND_OPC_INFORMATION = 0x54,
+ SPDK_MMC_SET_CD_SPEED = 0xbb,
+ SPDK_MMC_SET_READ_AHEAD = 0xa7,
+ SPDK_MMC_SET_STREAMING = 0xb6,
+ SPDK_MMC_START_STOP_UNIT = 0x1b,
+ SPDK_MMC_STOP_PLAY_SCAN = 0x4e,
+ SPDK_MMC_SYNCHRONIZE_CACHE = 0x35,
+ SPDK_MMC_TEST_UNIT_READY = 0x00,
+ SPDK_MMC_VERIFY_10 = 0x2f,
+ SPDK_MMC_WRITE_10 = 0xa2,
+ SPDK_MMC_WRITE_12 = 0xaa,
+ SPDK_MMC_WRITE_AND_VERIFY_10 = 0x2e,
+ SPDK_MMC_WRITE_BUFFER = 0x3b,
+};
+
+enum spdk_ssc_opcode {
+ SPDK_SSC_ERASE_6 = 0x19,
+ SPDK_SSC_FORMAT_MEDIUM = 0x04,
+ SPDK_SSC_LOAD_UNLOAD = 0x1b,
+ SPDK_SSC_LOCATE_10 = 0x2b,
+ SPDK_SSC_LOCATE_16 = 0x92,
+ SPDK_SSC_MOVE_MEDIUM_ATTACHED = 0xa7,
+ SPDK_SSC_READ_6 = 0x08,
+ SPDK_SSC_READ_BLOCK_LIMITS = 0x05,
+ SPDK_SSC_READ_ELEMENT_STATUS_ATTACHED = 0xb4,
+ SPDK_SSC_READ_POSITION = 0x34,
+ SPDK_SSC_READ_REVERSE_6 = 0x0f,
+ SPDK_SSC_RECOVER_BUFFERED_DATA = 0x14,
+ SPDK_SSC_REPORT_DENSITY_SUPPORT = 0x44,
+ SPDK_SSC_REWIND = 0x01,
+ SPDK_SSC_SET_CAPACITY = 0x0b,
+ SPDK_SSC_SPACE_6 = 0x11,
+ SPDK_SSC_SPACE_16 = 0x91,
+ SPDK_SSC_VERIFY_6 = 0x13,
+ SPDK_SSC_WRITE_6 = 0x0a,
+ SPDK_SSC_WRITE_FILEMARKS_6 = 0x10,
+};
+
+enum spdk_spc_vpd {
+ SPDK_SPC_VPD_DEVICE_IDENTIFICATION = 0x83,
+ SPDK_SPC_VPD_EXTENDED_INQUIRY_DATA = 0x86,
+ SPDK_SPC_VPD_MANAGEMENT_NETWORK_ADDRESSES = 0x85,
+ SPDK_SPC_VPD_MODE_PAGE_POLICY = 0x87,
+ SPDK_SPC_VPD_SCSI_PORTS = 0x88,
+ SPDK_SPC_VPD_SOFTWARE_INTERFACE_IDENTIFICATION = 0x84,
+ SPDK_SPC_VPD_SUPPORTED_VPD_PAGES = 0x00,
+ SPDK_SPC_VPD_UNIT_SERIAL_NUMBER = 0x80,
+ SPDK_SPC_VPD_BLOCK_LIMITS = 0xb0,
+ SPDK_SPC_VPD_BLOCK_DEV_CHARS = 0xb1,
+ SPDK_SPC_VPD_BLOCK_THIN_PROVISION = 0xb2,
+};
+
+enum spdk_spc_peripheral_qualifier {
+ SPDK_SPC_PERIPHERAL_QUALIFIER_CONNECTED = 0,
+ SPDK_SPC_PERIPHERAL_QUALIFIER_NOT_CONNECTED = 1,
+ SPDK_SPC_PERIPHERAL_QUALIFIER_NOT_CAPABLE = 3,
+};
+
+enum {
+ SPDK_SPC_PERIPHERAL_DEVICE_TYPE_DISK = 0x00,
+ SPDK_SPC_PERIPHERAL_DEVICE_TYPE_TAPE = 0x01,
+ SPDK_SPC_PERIPHERAL_DEVICE_TYPE_DVD = 0x05,
+ SPDK_SPC_PERIPHERAL_DEVICE_TYPE_CHANGER = 0x08,
+
+ SPDK_SPC_VERSION_NONE = 0x00,
+ SPDK_SPC_VERSION_SPC = 0x03,
+ SPDK_SPC_VERSION_SPC2 = 0x04,
+ SPDK_SPC_VERSION_SPC3 = 0x05,
+ SPDK_SPC_VERSION_SPC4 = 0x06,
+
+ SPDK_SPC_PROTOCOL_IDENTIFIER_FC = 0x00,
+ SPDK_SPC_PROTOCOL_IDENTIFIER_PSCSI = 0x01,
+ SPDK_SPC_PROTOCOL_IDENTIFIER_SSA = 0x02,
+ SPDK_SPC_PROTOCOL_IDENTIFIER_IEEE1394 = 0x03,
+ SPDK_SPC_PROTOCOL_IDENTIFIER_RDMA = 0x04,
+ SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI = 0x05,
+ SPDK_SPC_PROTOCOL_IDENTIFIER_SAS = 0x06,
+ SPDK_SPC_PROTOCOL_IDENTIFIER_ADT = 0x07,
+ SPDK_SPC_PROTOCOL_IDENTIFIER_ATA = 0x08,
+
+ SPDK_SPC_VPD_CODE_SET_BINARY = 0x01,
+ SPDK_SPC_VPD_CODE_SET_ASCII = 0x02,
+ SPDK_SPC_VPD_CODE_SET_UTF8 = 0x03,
+
+ SPDK_SPC_VPD_ASSOCIATION_LOGICAL_UNIT = 0x00,
+ SPDK_SPC_VPD_ASSOCIATION_TARGET_PORT = 0x01,
+ SPDK_SPC_VPD_ASSOCIATION_TARGET_DEVICE = 0x02,
+
+ SPDK_SPC_VPD_IDENTIFIER_TYPE_VENDOR_SPECIFIC = 0x00,
+ SPDK_SPC_VPD_IDENTIFIER_TYPE_T10_VENDOR_ID = 0x01,
+ SPDK_SPC_VPD_IDENTIFIER_TYPE_EUI64 = 0x02,
+ SPDK_SPC_VPD_IDENTIFIER_TYPE_NAA = 0x03,
+ SPDK_SPC_VPD_IDENTIFIER_TYPE_RELATIVE_TARGET_PORT = 0x04,
+ SPDK_SPC_VPD_IDENTIFIER_TYPE_TARGET_PORT_GROUP = 0x05,
+ SPDK_SPC_VPD_IDENTIFIER_TYPE_LOGICAL_UNIT_GROUP = 0x06,
+ SPDK_SPC_VPD_IDENTIFIER_TYPE_MD5_LOGICAL_UNIT = 0x07,
+ SPDK_SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME = 0x08,
+};
+
+struct spdk_scsi_cdb_inquiry {
+ uint8_t opcode;
+ uint8_t evpd;
+ uint8_t page_code;
+ uint8_t alloc_len[2];
+ uint8_t control;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_scsi_cdb_inquiry) == 6, "incorrect CDB size");
+
+struct spdk_scsi_cdb_inquiry_data {
+ uint8_t peripheral_device_type : 5;
+ uint8_t peripheral_qualifier : 3;
+ uint8_t rmb;
+ uint8_t version;
+ uint8_t response;
+ uint8_t add_len;
+ uint8_t flags;
+ uint8_t flags2;
+ uint8_t flags3;
+ uint8_t t10_vendor_id[8];
+ uint8_t product_id[16];
+ uint8_t product_rev[4];
+ uint8_t vendor[20];
+ uint8_t ius;
+ uint8_t reserved;
+ uint8_t desc[];
+};
+
+struct spdk_scsi_vpd_page {
+ uint8_t peripheral_device_type : 5;
+ uint8_t peripheral_qualifier : 3;
+ uint8_t page_code;
+ uint8_t alloc_len[2];
+ uint8_t params[];
+};
+
+#define SPDK_SCSI_VEXT_REF_CHK 0x01
+#define SPDK_SCSI_VEXT_APP_CHK 0x02
+#define SPDK_SCSI_VEXT_GRD_CHK 0x04
+#define SPDK_SCSI_VEXT_SIMPSUP 0x01
+#define SPDK_SCSI_VEXT_ORDSUP 0x02
+#define SPDK_SCSI_VEXT_HEADSUP 0x04
+#define SPDK_SCSI_VEXT_PRIOR_SUP 0x08
+#define SPDK_SCSI_VEXT_GROUP_SUP 0x10
+#define SPDK_SCSI_VEXT_UASK_SUP 0x20
+#define SPDK_SCSI_VEXT_V_SUP 0x01
+#define SPDK_SCSI_VEXT_NV_SUP 0x02
+#define SPDK_SCSI_VEXT_CRD_SUP 0x04
+#define SPDK_SCSI_VEXT_WU_SUP 0x08
+
+struct spdk_scsi_vpd_ext_inquiry {
+ uint8_t peripheral;
+ uint8_t page_code;
+ uint8_t alloc_len[2];
+ uint8_t check;
+ uint8_t sup;
+ uint8_t sup2;
+ uint8_t luiclr;
+ uint8_t cbcs;
+ uint8_t micro_dl;
+ uint8_t reserved[54];
+};
+
+#define SPDK_SPC_VPD_DESIG_PIV 0x80
+
+/* designation descriptor */
+struct spdk_scsi_desig_desc {
+ uint8_t code_set : 4;
+ uint8_t protocol_id : 4;
+ uint8_t type : 4;
+ uint8_t association : 2;
+ uint8_t reserved0 : 1;
+ uint8_t piv : 1;
+ uint8_t reserved1;
+ uint8_t len;
+ uint8_t desig[];
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_scsi_desig_desc) == 4, "Invalid size");
+
+/* mode page policy descriptor */
+struct spdk_scsi_mpage_policy_desc {
+ uint8_t page_code;
+ uint8_t sub_page_code;
+ uint8_t policy;
+ uint8_t reserved;
+};
+
+/* target port descriptor */
+struct spdk_scsi_tgt_port_desc {
+ uint8_t code_set;
+ uint8_t desig_type;
+ uint8_t reserved;
+ uint8_t len;
+ uint8_t designator[];
+};
+
+/* SCSI port designation descriptor */
+struct spdk_scsi_port_desc {
+ uint16_t reserved;
+ uint16_t rel_port_id;
+ uint16_t reserved2;
+ uint16_t init_port_len;
+ uint16_t init_port_id;
+ uint16_t reserved3;
+ uint16_t tgt_desc_len;
+ uint8_t tgt_desc[];
+};
+
+/* SCSI UNMAP block descriptor */
+struct spdk_scsi_unmap_bdesc {
+ /* UNMAP LOGICAL BLOCK ADDRESS */
+ uint64_t lba;
+
+ /* NUMBER OF LOGICAL BLOCKS */
+ uint32_t block_count;
+
+ /* RESERVED */
+ uint32_t reserved;
+};
+
+#define SPDK_SCSI_UNMAP_LBPU 1 << 7
+#define SPDK_SCSI_UNMAP_LBPWS 1 << 6
+#define SPDK_SCSI_UNMAP_LBPWS10 1 << 5
+
+#define SPDK_SCSI_UNMAP_FULL_PROVISIONING 0x00
+#define SPDK_SCSI_UNMAP_RESOURCE_PROVISIONING 0x01
+#define SPDK_SCSI_UNMAP_THIN_PROVISIONING 0x02
+
+#endif /* SPDK_SCSI_SPEC_H */
diff --git a/src/spdk/include/spdk/sock.h b/src/spdk/include/spdk/sock.h
new file mode 100644
index 00000000..8d5c6a74
--- /dev/null
+++ b/src/spdk/include/spdk/sock.h
@@ -0,0 +1,248 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * TCP socket abstraction layer
+ */
+
+#ifndef SPDK_SOCK_H
+#define SPDK_SOCK_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct spdk_sock;
+struct spdk_sock_group;
+
+/**
+ * Get client and server addresses of the given socket.
+ *
+ * \param sock Socket to get address.
+ * \param saddr A pointer to the buffer to hold the address of server.
+ * \param slen Length of the buffer 'saddr'.
+ * \param sport A pointer(May be NULL) to the buffer to hold the port info of server.
+ * \param caddr A pointer to the buffer to hold the address of client.
+ * \param clen Length of the buffer 'caddr'.
+ * \param cport A pointer(May be NULL) to the buffer to hold the port info of server.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_sock_getaddr(struct spdk_sock *sock, char *saddr, int slen, uint16_t *sport,
+ char *caddr, int clen, uint16_t *cport);
+
+/**
+ * Create a socket, connect the socket to the specified address and port (of the
+ * server), and then return the socket. This function is used by client.
+ *
+ * \param ip IP address of the server.
+ * \param port Port number of the server.
+ *
+ * \return a pointer to the connected socket on success, or NULL on failure.
+ */
+struct spdk_sock *spdk_sock_connect(const char *ip, int port);
+
+/**
+ * Create a socket, bind the socket to the specified address and port and listen
+ * on the socket, and then return the socket. This function is used by server.
+ *
+ * \param ip IP address to listen on.
+ * \param port Port number.
+ *
+ * \return a pointer to the listened socket on success, or NULL on failure.
+ */
+struct spdk_sock *spdk_sock_listen(const char *ip, int port);
+
+/**
+ * Accept a new connection from a client on the specified socket and return a
+ * socket structure which holds the connection.
+ *
+ * \param sock Listening socket.
+ *
+ * \return a pointer to the accepted socket on success, or NULL on failure.
+ */
+struct spdk_sock *spdk_sock_accept(struct spdk_sock *sock);
+
+/**
+ * Close a socket.
+ *
+ * \param sock Socket to close.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_sock_close(struct spdk_sock **sock);
+
+/**
+ * Receive a message from the given socket.
+ *
+ * \param sock Socket to receive message.
+ * \param buf Pointer to a buffer to hold the data.
+ * \param len Length of the buffer.
+ *
+ * \return the length of the received message on success, -1 on failure.
+ */
+ssize_t spdk_sock_recv(struct spdk_sock *sock, void *buf, size_t len);
+
+/**
+ * Write message to the given socket from the I/O vector array.
+ *
+ * \param sock Socket to write to.
+ * \param iov I/O vector.
+ * \param iovcnt Number of I/O vectors in the array.
+ *
+ * \return the length of written message on success, -1 on failure.
+ */
+ssize_t spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt);
+
+/**
+ * Set the value used to specify the low water mark (in bytes) for this socket.
+ *
+ * \param sock Socket to set for.
+ * \param nbytes Value for recvlowat.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes);
+
+/**
+ * Set receive buffer size for the given socket.
+ *
+ * \param sock Socket to set buffer size for.
+ * \param sz Buffer size in bytes.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_sock_set_recvbuf(struct spdk_sock *sock, int sz);
+
+/**
+ * Set send buffer size for the given socket.
+ *
+ * \param sock Socket to set buffer size for.
+ * \param sz Buffer size in bytes.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_sock_set_sendbuf(struct spdk_sock *sock, int sz);
+
+/**
+ * Check whether the address of socket is ipv6.
+ *
+ * \param sock Socket to check.
+ *
+ * \return true if the address of socket is ipv6, or false otherwise.
+ */
+bool spdk_sock_is_ipv6(struct spdk_sock *sock);
+
+/**
+ * Check whether the address of socket is ipv4.
+ *
+ * \param sock Socket to check.
+ *
+ * \return true if the address of socket is ipv4, or false otherwise.
+ */
+bool spdk_sock_is_ipv4(struct spdk_sock *sock);
+
+/**
+ * Callback function for spdk_sock_group_add_sock().
+ *
+ * \param arg Argument for the callback function.
+ * \param group Socket group.
+ * \param sock Socket.
+ */
+typedef void (*spdk_sock_cb)(void *arg, struct spdk_sock_group *group, struct spdk_sock *sock);
+
+/**
+ * Create a new socket group.
+ *
+ * \return a pointer to the created group on success, or NULL on failure.
+ */
+struct spdk_sock_group *spdk_sock_group_create(void);
+
+/**
+ * Add a socket to the group.
+ *
+ * \param group Socket group.
+ * \param sock Socket to add.
+ * \param cb_fn Called when the operation completes.
+ * \param cb_arg Argument passed to the callback function.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock,
+ spdk_sock_cb cb_fn, void *cb_arg);
+
+/**
+ * Remove a socket from the group.
+ *
+ * \param group Socket group.
+ * \param sock Socket to remove.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock);
+
+/**
+ * Poll incoming events for each registered socket.
+ *
+ * \param group Group to poll.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_sock_group_poll(struct spdk_sock_group *group);
+
+/**
+ * Poll incoming events up to max_events for each registered socket.
+ *
+ * \param group Group to poll.
+ * \param max_events Number of maximum events to poll for each socket.
+ *
+ * \return the number of events on success, -1 on failure.
+ */
+int spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events);
+
+/**
+ * Close all registered sockets of the group and then remove the group.
+ *
+ * \param group Group to close.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_sock_group_close(struct spdk_sock_group **group);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_SOCK_H */
diff --git a/src/spdk/include/spdk/stdinc.h b/src/spdk/include/spdk/stdinc.h
new file mode 100644
index 00000000..f13cc29c
--- /dev/null
+++ b/src/spdk/include/spdk/stdinc.h
@@ -0,0 +1,96 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Standard C headers
+ *
+ * This file is intended to be included first by all other SPDK files.
+ */
+
+#ifndef SPDK_STDINC_H
+#define SPDK_STDINC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Standard C */
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+/* POSIX */
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <poll.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <syslog.h>
+#include <termios.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+
+/* GNU extension */
+#include <getopt.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_STDINC_H */
diff --git a/src/spdk/include/spdk/string.h b/src/spdk/include/spdk/string.h
new file mode 100644
index 00000000..b31762b8
--- /dev/null
+++ b/src/spdk/include/spdk/string.h
@@ -0,0 +1,207 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * String utility functions
+ */
+
+#ifndef SPDK_STRING_H
+#define SPDK_STRING_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * sprintf with automatic buffer allocation.
+ *
+ * The return value is the formatted string, which should be passed to free()
+ * when no longer needed.
+ *
+ * \param format Format for the string to print.
+ *
+ * \return the formatted string on success, or NULL on failure.
+ */
+char *spdk_sprintf_alloc(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+/**
+ * vsprintf with automatic buffer allocation.
+ *
+ * The return value is the formatted string, which should be passed to free()
+ * when no longer needed.
+ *
+ * \param format Format for the string to print.
+ * \param args A value that identifies a variable arguments list.
+ *
+ * \return the formatted string on success, or NULL on failure.
+ */
+char *spdk_vsprintf_alloc(const char *format, va_list args);
+
+/**
+ * Convert string to lowercase in place.
+ *
+ * \param s String to convert to lowercase.
+ *
+ * \return the converted string.
+ */
+char *spdk_strlwr(char *s);
+
+/**
+ * Parse a delimited string with quote handling.
+ *
+ * Note that the string will be modified in place to add the string terminator
+ * to each field.
+ *
+ * \param stringp Pointer to starting location in string. *stringp will be updated
+ * to point to the start of the next field, or NULL if the end of the string has
+ * been reached.
+ * \param delim Null-terminated string containing the list of accepted delimiters.
+ *
+ * \return a pointer to beginning of the current field.
+ */
+char *spdk_strsepq(char **stringp, const char *delim);
+
+/**
+ * Trim whitespace from a string in place.
+ *
+ * \param s String to trim.
+ *
+ * \return the trimmed string.
+ */
+char *spdk_str_trim(char *s);
+
+/**
+ * Copy the string version of an error into the user supplied buffer
+ *
+ * \param errnum Error code.
+ * \param buf Pointer to a buffer in which to place the error message.
+ * \param buflen The size of the buffer in bytes.
+ */
+void spdk_strerror_r(int errnum, char *buf, size_t buflen);
+
+/**
+ * Return the string version of an error from a static, thread-local buffer. This
+ * function is thread safe.
+ *
+ * \param errnum Error code.
+ *
+ * \return a pointer to buffer upon success.
+ */
+const char *spdk_strerror(int errnum);
+
+/**
+ * Remove trailing newlines from the end of a string in place.
+ *
+ * Any sequence of trailing \\r and \\n characters is removed from the end of the
+ * string.
+ *
+ * \param s String to remove newline from.
+ *
+ * \return the number of characters removed.
+ */
+size_t spdk_str_chomp(char *s);
+
+/**
+ * Copy a string into a fixed-size buffer, padding extra bytes with a specific
+ * character.
+ *
+ * If src is longer than size, only size bytes will be copied.
+ *
+ * \param dst Pointer to destination fixed-size buffer to fill.
+ * \param src Pointer to source null-terminated string to copy into dst.
+ * \param size Number of bytes to fill in dst.
+ * \param pad Character to pad extra space in dst beyond the size of src.
+ */
+void spdk_strcpy_pad(void *dst, const char *src, size_t size, int pad);
+
+/**
+ * Find the length of a string that has been padded with a specific byte.
+ *
+ * \param str Right-padded string to find the length of.
+ * \param size Size of the full string pointed to by str, including padding.
+ * \param pad Character that was used to pad str up to size.
+ *
+ * \return the length of the non-padded portion of str.
+ */
+size_t spdk_strlen_pad(const void *str, size_t size, int pad);
+
+/**
+ * Parse an IP address into its hostname and port components. This modifies the
+ * IP address in place.
+ *
+ * \param ip A null terminated IP address, including port. Both IPv4 and IPv6
+ * are supported.
+ * \param host Will point to the start of the hostname within ip. The string will
+ * be null terminated.
+ * \param port Will point to the start of the port within ip. The string will be
+ * null terminated.
+ *
+ * \return 0 on success. -EINVAL on failure.
+ */
+int spdk_parse_ip_addr(char *ip, char **host, char **port);
+
+/**
+ * Parse a string representing a number possibly followed by a binary prefix.
+ *
+ * The string can contain a trailing "B" (KB,MB,GB) but it's not necessary.
+ * "128K" = 128 * 1024; "2G" = 2 * 1024 * 1024; "2GB" = 2 * 1024 * 1024;
+ * Additionally, lowercase "k", "m", "g" are parsed as well. They are processed
+ * the same as their uppercase equivalents.
+ *
+ * \param cap_str Null terminated string.
+ * \param cap Pointer where the parsed capacity (in bytes) will be put.
+ * \param has_prefix Pointer to a flag that will be set to describe whether given
+ * string contains a binary prefix.
+ *
+ * \return 0 on success, or negative errno on failure.
+ */
+int spdk_parse_capacity(const char *cap_str, uint64_t *cap, bool *has_prefix);
+
+/**
+ * Check if a buffer is all zero (0x00) bytes or not.
+ *
+ * \param data Buffer to check.
+ * \param size Size of data in bytes.
+ *
+ * \return true if data consists entirely of zeroes, or false if any byte in data
+ * is not zero.
+ */
+bool spdk_mem_all_zero(const void *data, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/thread.h b/src/spdk/include/spdk/thread.h
new file mode 100644
index 00000000..63cb7b31
--- /dev/null
+++ b/src/spdk/include/spdk/thread.h
@@ -0,0 +1,431 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * Thread
+ */
+
+#ifndef SPDK_THREAD_H_
+#define SPDK_THREAD_H_
+
+#include "spdk/stdinc.h"
+
+#include "spdk/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct spdk_thread;
+struct spdk_io_channel_iter;
+struct spdk_poller;
+
+/**
+ * Callback function for a thread.
+ *
+ * \param ctx Context passed as arg to spdk_thread_pass_msg().
+ */
+typedef void (*spdk_thread_fn)(void *ctx);
+
+/**
+ * Function to be called to pass a message to a thread.
+ *
+ * \param fn Callback function for a thread.
+ * \param ctx Context passed to fn.
+ * \param thread_ctx Context for the thread.
+ */
+typedef void (*spdk_thread_pass_msg)(spdk_thread_fn fn, void *ctx,
+ void *thread_ctx);
+
+/**
+ * Callback function for a poller.
+ *
+ * \param ctx Context passed as arg to spdk_poller_register().
+ * \return 0 to indicate that polling took place but no events were found;
+ * positive to indicate that polling took place and some events were processed;
+ * negative if the poller does not provide spin-wait information.
+ */
+typedef int (*spdk_poller_fn)(void *ctx);
+
+/**
+ * Function to be called to start a poller for the thread.
+ *
+ * \param thread_ctx Context for the thread.
+ * \param fn Callback function for a poller.
+ * \param arg Argument passed to callback.
+ * \param period Polling period in microseconds.
+ *
+ * \return a pointer to the poller on success, or NULL on failure.
+ */
+typedef struct spdk_poller *(*spdk_start_poller)(void *thread_ctx,
+ spdk_poller_fn fn,
+ void *arg,
+ uint64_t period_microseconds);
+
+/**
+ * Function to be called to stop a poller.
+ *
+ * \param poller Poller to stop.
+ * \param thread_ctx Context for the thread.
+ */
+typedef void (*spdk_stop_poller)(struct spdk_poller *poller, void *thread_ctx);
+
+/**
+ * I/O channel creation callback.
+ *
+ * \param io_device I/O device associated with this channel.
+ * \param ctx_buf Context for the I/O device.
+ */
+typedef int (*spdk_io_channel_create_cb)(void *io_device, void *ctx_buf);
+
+/**
+ * I/O channel destruction callback.
+ *
+ * \param io_device I/O device associated with this channel.
+ * \param ctx_buf Context for the I/O device.
+ */
+typedef void (*spdk_io_channel_destroy_cb)(void *io_device, void *ctx_buf);
+
+/**
+ * I/O device unregister callback.
+ *
+ * \param io_device Unregistered I/O device.
+ */
+typedef void (*spdk_io_device_unregister_cb)(void *io_device);
+
+/**
+ * Called on the appropriate thread for each channel associated with io_device.
+ *
+ * \param i I/O channel iterator.
+ */
+typedef void (*spdk_channel_msg)(struct spdk_io_channel_iter *i);
+
+/**
+ * spdk_for_each_channel() callback.
+ *
+ * \param i I/O channel iterator.
+ * \param status 0 if it completed successfully, or negative errno if it failed.
+ */
+typedef void (*spdk_channel_for_each_cpl)(struct spdk_io_channel_iter *i, int status);
+
+/**
+ * \brief Represents a per-thread channel for accessing an I/O device.
+ *
+ * An I/O device may be a physical entity (i.e. NVMe controller) or a software
+ * entity (i.e. a blobstore).
+ *
+ * This structure is not part of the API - all accesses should be done through
+ * spdk_io_channel function calls.
+ */
+struct spdk_io_channel {
+ struct spdk_thread *thread;
+ struct io_device *dev;
+ uint32_t ref;
+ uint32_t destroy_ref;
+ TAILQ_ENTRY(spdk_io_channel) tailq;
+ spdk_io_channel_destroy_cb destroy_cb;
+
+ /*
+ * Modules will allocate extra memory off the end of this structure
+ * to store references to hardware-specific references (i.e. NVMe queue
+ * pairs, or references to child device spdk_io_channels (i.e.
+ * virtual bdevs).
+ */
+};
+
+/**
+ * Initialize the threading library. Must be called once prior to allocating any threads.
+ *
+ * \return 0 on success. Negated errno on failure.
+ */
+int spdk_thread_lib_init(void);
+
+/**
+ * Release all resources associated with this library.
+ */
+void spdk_thread_lib_fini(void);
+
+/**
+ * Initializes the calling thread for I/O channel allocation.
+ *
+ * \param msg_fn A function that may be called from any thread and is passed a function
+ * pointer (spdk_thread_fn) that must be called on the same thread that spdk_allocate_thread
+ * was called from.
+ * \param start_poller_fn Function to be called to start a poller for the thread.
+ * \param stop_poller_fn Function to be called to stop a poller for the thread.
+ * \param thread_ctx Context that will be passed to fn, start_poller_fn and spdk_stop_poller.
+ * \param name Human-readable name for the thread; can be retrieved with spdk_thread_get_name().
+ * The string is copied, so the pointed-to data only needs to be valid during the
+ * spdk_allocate_thread() call. May be NULL to specify no name.
+ *
+ * \return a pointer to the allocated thread on success or NULL on failure..
+ */
+struct spdk_thread *spdk_allocate_thread(spdk_thread_pass_msg msg_fn,
+ spdk_start_poller start_poller_fn,
+ spdk_stop_poller stop_poller_fn,
+ void *thread_ctx,
+ const char *name);
+
+/**
+ * Release any resources related to the calling thread for I/O channel allocation.
+ *
+ * All I/O channel references related to the calling thread must be released using
+ * spdk_put_io_channel() prior to calling this function.
+ */
+void spdk_free_thread(void);
+
+/**
+ * Get count of allocated threads.
+ */
+uint32_t spdk_thread_get_count(void);
+
+/**
+ * Get a handle to the current thread.
+ *
+ * This handle may be passed to other threads and used as the target of
+ * spdk_thread_send_msg().
+ *
+ * \sa spdk_io_channel_get_thread()
+ *
+ * \return a pointer to the current thread on success or NULL on failure.
+ */
+struct spdk_thread *spdk_get_thread(void);
+
+/**
+ * Get a thread's name.
+ *
+ * \param thread Thread to query.
+ *
+ * \return the name of the thread.
+ */
+const char *spdk_thread_get_name(const struct spdk_thread *thread);
+
+/**
+ * Send a message to the given thread.
+ *
+ * The message may be sent asynchronously - i.e. spdk_thread_send_msg may return
+ * prior to `fn` being called.
+ *
+ * \param thread The target thread.
+ * \param fn This function will be called on the given thread.
+ * \param ctx This context will be passed to fn when called.
+ */
+void spdk_thread_send_msg(const struct spdk_thread *thread, spdk_thread_fn fn, void *ctx);
+
+/**
+ * Send a message to each thread, serially.
+ *
+ * The message is sent asynchronously - i.e. spdk_for_each_thread will return
+ * prior to `fn` being called on each thread.
+ *
+ * \param fn This is the function that will be called on each thread.
+ * \param ctx This context will be passed to fn when called.
+ * \param cpl This will be called on the originating thread after `fn` has been
+ * called on each thread.
+ */
+void spdk_for_each_thread(spdk_thread_fn fn, void *ctx, spdk_thread_fn cpl);
+
+/**
+ * Register a poller on the current thread.
+ *
+ * The poller can be unregistered by calling spdk_poller_unregister().
+ *
+ * \param fn This function will be called every `period_microseconds`.
+ * \param arg Argument passed to fn.
+ * \param period_microseconds How often to call `fn`. If 0, call `fn` as often
+ * as possible.
+ *
+ * \return a pointer to the poller registered on the current thread on success
+ * or NULL on failure.
+ */
+struct spdk_poller *spdk_poller_register(spdk_poller_fn fn,
+ void *arg,
+ uint64_t period_microseconds);
+
+/**
+ * Unregister a poller on the current thread.
+ *
+ * \param ppoller The poller to unregister.
+ */
+void spdk_poller_unregister(struct spdk_poller **ppoller);
+
+/**
+ * Register the opaque io_device context as an I/O device.
+ *
+ * After an I/O device is registered, it can return I/O channels using the
+ * spdk_get_io_channel() function.
+ *
+ * \param io_device The pointer to io_device context.
+ * \param create_cb Callback function invoked to allocate any resources required
+ * for a new I/O channel.
+ * \param destroy_cb Callback function invoked to release the resources for an
+ * I/O channel.
+ * \param ctx_size The size of the context buffer allocated to store references
+ * to allocated I/O channel resources.
+ * \param name A string name for the device used only for debugging. Optional -
+ * may be NULL.
+ */
+void spdk_io_device_register(void *io_device, spdk_io_channel_create_cb create_cb,
+ spdk_io_channel_destroy_cb destroy_cb, uint32_t ctx_size,
+ const char *name);
+
+/**
+ * Unregister the opaque io_device context as an I/O device.
+ *
+ * The actual unregistration might be deferred until all active I/O channels are
+ * destroyed.
+ *
+ * \param io_device The pointer to io_device context.
+ * \param unregister_cb An optional callback function invoked to release any
+ * references to this I/O device.
+ */
+void spdk_io_device_unregister(void *io_device, spdk_io_device_unregister_cb unregister_cb);
+
+/**
+ * Get an I/O channel for the specified io_device to be used by the calling thread.
+ *
+ * The io_device context pointer specified must have previously been registered
+ * using spdk_io_device_register(). If an existing I/O channel does not exist
+ * yet for the given io_device on the calling thread, it will allocate an I/O
+ * channel and invoke the create_cb function pointer specified in spdk_io_device_register().
+ * If an I/O channel already exists for the given io_device on the calling thread,
+ * its reference is returned rather than creating a new I/O channel.
+ *
+ * \param io_device The pointer to io_device context.
+ *
+ * \return a pointer to the I/O channel for this device on success or NULL on failure.
+ */
+struct spdk_io_channel *spdk_get_io_channel(void *io_device);
+
+/**
+ * Release a reference to an I/O channel. This happens asynchronously.
+ *
+ * Actual release will happen on the same thread that called spdk_get_io_channel()
+ * for the specified I/O channel. If this releases the last reference to the
+ * I/O channel, The destroy_cb function specified in spdk_io_device_register()
+ * will be invoked to release any associated resources.
+ *
+ * \param ch I/O channel to release a reference.
+ */
+void spdk_put_io_channel(struct spdk_io_channel *ch);
+
+/**
+ * Get the context buffer associated with an I/O channel.
+ *
+ * \param ch I/O channel.
+ *
+ * \return a pointer to the context buffer.
+ */
+static inline void *
+spdk_io_channel_get_ctx(struct spdk_io_channel *ch)
+{
+ return (uint8_t *)ch + sizeof(*ch);
+}
+
+/**
+ * Get I/O channel from the context buffer. This is the inverse of
+ * spdk_io_channel_get_ctx().
+ *
+ * \param ctx The pointer to the context buffer.
+ *
+ * \return a pointer to the I/O channel associated with the context buffer.
+ */
+struct spdk_io_channel *spdk_io_channel_from_ctx(void *ctx);
+
+/**
+ * Get the thread associated with an I/O channel.
+ *
+ * \param ch I/O channel.
+ *
+ * \return a pointer to the thread associated with the I/O channel
+ */
+struct spdk_thread *spdk_io_channel_get_thread(struct spdk_io_channel *ch);
+
+/**
+ * Call 'fn' on each channel associated with io_device.
+ *
+ * This happens asynchronously, so fn may be called after spdk_for_each_channel
+ * returns. 'fn' will be called for each channel serially, such that two calls
+ * to 'fn' will not overlap in time. After 'fn' has been called, call
+ * spdk_for_each_channel_continue() to continue iterating.
+ *
+ * \param io_device 'fn' will be called on each channel associated with this io_device.
+ * \param fn Called on the appropriate thread for each channel associated with io_device.
+ * \param ctx Context buffer registered to spdk_io_channel_iter that can be obatined
+ * form the function spdk_io_channel_iter_get_ctx().
+ * \param cpl Called on the thread that spdk_for_each_channel was initially called
+ * from when 'fn' has been called on each channel.
+ */
+void spdk_for_each_channel(void *io_device, spdk_channel_msg fn, void *ctx,
+ spdk_channel_for_each_cpl cpl);
+
+/**
+ * Get io_device from the I/O channel iterator.
+ *
+ * \param i I/O channel iterator.
+ *
+ * \return a pointer to the io_device.
+ */
+void *spdk_io_channel_iter_get_io_device(struct spdk_io_channel_iter *i);
+
+/**
+ * Get I/O channel from the I/O channel iterator.
+ *
+ * \param i I/O channel iterator.
+ *
+ * \return a pointer to the I/O channel.
+ */
+struct spdk_io_channel *spdk_io_channel_iter_get_channel(struct spdk_io_channel_iter *i);
+
+/**
+ * Get context buffer from the I/O channel iterator.
+ *
+ * \param i I/O channel iterator.
+ *
+ * \return a pointer to the context buffer.
+ */
+void *spdk_io_channel_iter_get_ctx(struct spdk_io_channel_iter *i);
+
+/**
+ * Helper function to iterate all channels for spdk_for_each_channel().
+ *
+ * \param i I/O channel iterator.
+ * \param status Status for the I/O channel iterator.
+ */
+void spdk_for_each_channel_continue(struct spdk_io_channel_iter *i, int status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_THREAD_H_ */
diff --git a/src/spdk/include/spdk/trace.h b/src/spdk/include/spdk/trace.h
new file mode 100644
index 00000000..94cae175
--- /dev/null
+++ b/src/spdk/include/spdk/trace.h
@@ -0,0 +1,319 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * Tracepoint library
+ */
+
+#ifndef _SPDK_TRACE_H_
+#define _SPDK_TRACE_H_
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPDK_TRACE_SIZE (32 * 1024)
+
+struct spdk_trace_entry {
+ uint64_t tsc;
+ uint16_t tpoint_id;
+ uint16_t poller_id;
+ uint32_t size;
+ uint64_t object_id;
+ uint64_t arg1;
+};
+
+/* If type changes from a uint8_t, change this value. */
+#define SPDK_TRACE_MAX_OWNER (UCHAR_MAX + 1)
+
+struct spdk_trace_owner {
+ uint8_t type;
+ char id_prefix;
+};
+
+/* If type changes from a uint8_t, change this value. */
+#define SPDK_TRACE_MAX_OBJECT (UCHAR_MAX + 1)
+
+struct spdk_trace_object {
+ uint8_t type;
+ char id_prefix;
+};
+
+#define SPDK_TRACE_MAX_GROUP_ID 16
+#define SPDK_TRACE_MAX_TPOINT_ID (SPDK_TRACE_MAX_GROUP_ID * 64)
+#define SPDK_TPOINT_ID(group, tpoint) ((group * 64) + tpoint)
+
+struct spdk_trace_tpoint {
+ char name[44];
+ char short_name[4];
+ uint16_t tpoint_id;
+ uint8_t owner_type;
+ uint8_t object_type;
+ uint8_t new_object;
+ uint8_t arg1_is_ptr;
+ uint8_t reserved;
+ char arg1_name[8];
+};
+
+struct spdk_trace_history {
+ /** Logical core number associated with this structure instance. */
+ int lcore;
+
+ /**
+ * Circular buffer of spdk_trace_entry structures for tracing
+ * tpoints on this core. Debug tool spdk_trace reads this
+ * buffer from shared memory to post-process the tpoint entries and
+ * display in a human-readable format.
+ */
+ struct spdk_trace_entry entries[SPDK_TRACE_SIZE];
+
+ /**
+ * Running count of number of occurrences of each tracepoint on this
+ * lcore. Debug tools can use this to easily count tracepoints such as
+ * number of SCSI tasks completed or PDUs read.
+ */
+ uint64_t tpoint_count[SPDK_TRACE_MAX_TPOINT_ID];
+
+ /** Index to next spdk_trace_entry to fill in the circular buffer. */
+ uint32_t next_entry;
+
+};
+
+#define SPDK_TRACE_MAX_LCORE 128
+
+struct spdk_trace_flags {
+ uint64_t tsc_rate;
+ uint64_t tpoint_mask[SPDK_TRACE_MAX_GROUP_ID];
+ struct spdk_trace_owner owner[UCHAR_MAX + 1];
+ struct spdk_trace_object object[UCHAR_MAX + 1];
+ struct spdk_trace_tpoint tpoint[SPDK_TRACE_MAX_TPOINT_ID];
+};
+extern struct spdk_trace_flags *g_trace_flags;
+extern struct spdk_trace_histories *g_trace_histories;
+
+
+struct spdk_trace_histories {
+ struct spdk_trace_flags flags;
+ struct spdk_trace_history per_lcore_history[SPDK_TRACE_MAX_LCORE];
+};
+
+void _spdk_trace_record(uint64_t tsc, uint16_t tpoint_id, uint16_t poller_id,
+ uint32_t size, uint64_t object_id, uint64_t arg1);
+
+/**
+ * Record the current trace state for tracing tpoints. Debug tool can read the
+ * information from shared memory to post-process the tpoint entries and display
+ * in a human-readable format. This function will call spdk_get_ticks() to get
+ * the current tsc to save in the tracepoint.
+ *
+ * \param tpoint_id Tracepoint id to record.
+ * \param poller_id Poller id to record.
+ * \param size Size to record.
+ * \param object_id Object id to record.
+ * \param arg1 Argument to record.
+ */
+static inline
+void spdk_trace_record(uint16_t tpoint_id, uint16_t poller_id, uint32_t size,
+ uint64_t object_id, uint64_t arg1)
+{
+ /*
+ * Tracepoint group ID is encoded in the tpoint_id. Lower 6 bits determine the tracepoint
+ * within the group, the remaining upper bits determine the tracepoint group. Each
+ * tracepoint group has its own tracepoint mask.
+ */
+ if (g_trace_histories == NULL ||
+ !((1ULL << (tpoint_id & 0x3F)) & g_trace_histories->flags.tpoint_mask[tpoint_id >> 6])) {
+ return;
+ }
+
+ _spdk_trace_record(0, tpoint_id, poller_id, size, object_id, arg1);
+}
+
+/**
+ * Record the current trace state for tracing tpoints. Debug tool can read the
+ * information from shared memory to post-process the tpoint entries and display
+ * in a human-readable format.
+ *
+ * \param tsc Current tsc.
+ * \param tpoint_id Tracepoint id to record.
+ * \param poller_id Poller id to record.
+ * \param size Size to record.
+ * \param object_id Object id to record.
+ * \param arg1 Argument to record.
+ */
+static inline
+void spdk_trace_record_tsc(uint64_t tsc, uint16_t tpoint_id, uint16_t poller_id,
+ uint32_t size, uint64_t object_id, uint64_t arg1)
+{
+ /*
+ * Tracepoint group ID is encoded in the tpoint_id. Lower 6 bits determine the tracepoint
+ * within the group, the remaining upper bits determine the tracepoint group. Each
+ * tracepoint group has its own tracepoint mask.
+ */
+ if (g_trace_histories == NULL ||
+ !((1ULL << (tpoint_id & 0x3F)) & g_trace_histories->flags.tpoint_mask[tpoint_id >> 6])) {
+ return;
+ }
+
+ _spdk_trace_record(tsc, tpoint_id, poller_id, size, object_id, arg1);
+}
+
+/**
+ * Get the current tpoint mask of the given tpoint group.
+ *
+ * \param group_id Tpoint group id associated with the tpoint mask.
+ *
+ * \return current tpoint mask.
+ */
+uint64_t spdk_trace_get_tpoint_mask(uint32_t group_id);
+
+/**
+ * Add the specified tpoints to the current tpoint mask for the given tpoint group.
+ *
+ * \param group_id Tpoint group id associated with the tpoint mask.
+ * \param tpoint_mask Tpoint mask which indicates which tpoints to add to the
+ * current tpoint mask.
+ */
+void spdk_trace_set_tpoints(uint32_t group_id, uint64_t tpoint_mask);
+
+/**
+ * Clear the specified tpoints from the current tpoint mask for the given tpoint group.
+ *
+ * \param group_id Tpoint group id associated with the tpoint mask.
+ * \param tpoint_mask Tpoint mask which indicates which tpoints to clear from
+ * the current tpoint mask.
+ */
+void spdk_trace_clear_tpoints(uint32_t group_id, uint64_t tpoint_mask);
+
+/**
+ * Get a mask of all tracepoint groups which have at least one tracepoint enabled.
+ *
+ * \return a mask of all tracepoint groups.
+ */
+uint64_t spdk_trace_get_tpoint_group_mask(void);
+
+/**
+ * For each tpoint group specified in the group mask, enable all of its tpoints.
+ *
+ * \param tpoint_group_mask Tpoint group mask that indicates which tpoints to enable.
+ */
+void spdk_trace_set_tpoint_group_mask(uint64_t tpoint_group_mask);
+
+/**
+ * Initialize the trace environment. Debug tool can read the information from
+ * the given shared memory to post-process the tpoint entries and display in a
+ * human-readable format.
+ *
+ * \param shm_name Name of shared memory.
+ * \return 0 on success, else non-zero indicates a failure.
+ */
+int spdk_trace_init(const char *shm_name);
+
+/**
+ * Unmap global trace memory structs.
+ */
+void spdk_trace_cleanup(void);
+
+/**
+ * Initialize trace flags.
+ */
+void spdk_trace_flags_init(void);
+
+#define OWNER_NONE 0
+#define OBJECT_NONE 0
+
+/**
+ * Register the trace owner.
+ *
+ * \param type Type of the trace owner.
+ * \param id_prefix Prefix of id for the trace owner.
+ */
+void spdk_trace_register_owner(uint8_t type, char id_prefix);
+
+/**
+ * Register the trace object.
+ *
+ * \param type Type of the trace object.
+ * \param id_prefix Prefix of id for the trace object.
+ */
+void spdk_trace_register_object(uint8_t type, char id_prefix);
+
+/**
+ * Register the description for the tpoint.
+ *
+ * \param name Name for the tpoint.
+ * \param short_name Short name for the tpoint.
+ * \param tpoint_id Id for the tpoint.
+ * \param owner_type Owner type for the tpoint.
+ * \param object_type Object type for the tpoint.
+ * \param new_object New object for the tpoint.
+ * \param arg1_is_ptr This argument indicates whether argument1 is a pointer.
+ * \param arg1_name Name of argument.
+ */
+void spdk_trace_register_description(const char *name, const char *short_name,
+ uint16_t tpoint_id, uint8_t owner_type,
+ uint8_t object_type, uint8_t new_object,
+ uint8_t arg1_is_ptr, const char *arg1_name);
+
+struct spdk_trace_register_fn {
+ void (*reg_fn)(void);
+ struct spdk_trace_register_fn *next;
+};
+
+/**
+ * Add new trace register function.
+ *
+ * \param reg_fn Trace register function to add.
+ */
+void spdk_trace_add_register_fn(struct spdk_trace_register_fn *reg_fn);
+
+#define SPDK_TRACE_REGISTER_FN(fn) \
+ static void fn(void); \
+ struct spdk_trace_register_fn reg_ ## fn = { \
+ .reg_fn = fn, \
+ .next = NULL, \
+ }; \
+ __attribute__((constructor)) static void _ ## fn(void) \
+ { \
+ spdk_trace_add_register_fn(&reg_ ## fn); \
+ } \
+ static void fn(void)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/util.h b/src/spdk/include/spdk/util.h
new file mode 100644
index 00000000..43d3b8d5
--- /dev/null
+++ b/src/spdk/include/spdk/util.h
@@ -0,0 +1,89 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * General utility functions
+ */
+
+#ifndef SPDK_UTIL_H
+#define SPDK_UTIL_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define spdk_min(a,b) (((a)<(b))?(a):(b))
+#define spdk_max(a,b) (((a)>(b))?(a):(b))
+
+#define SPDK_COUNTOF(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#define SPDK_CONTAINEROF(ptr, type, member) ((type *)((uintptr_t)ptr - offsetof(type, member)))
+
+#define SPDK_SEC_TO_USEC 1000000ULL
+
+static inline uint32_t
+spdk_u32log2(uint32_t x)
+{
+ if (x == 0) {
+ /* log(0) is undefined */
+ return 0;
+ }
+ return 31u - __builtin_clz(x);
+}
+
+static inline uint32_t
+spdk_align32pow2(uint32_t x)
+{
+ return 1u << (1 + spdk_u32log2(x - 1));
+}
+
+/**
+ * Check if a uint32_t is a power of 2.
+ */
+static inline bool
+spdk_u32_is_pow2(uint32_t x)
+{
+ if (x == 0) {
+ return false;
+ }
+
+ return (x & (x - 1)) == 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/uuid.h b/src/spdk/include/spdk/uuid.h
new file mode 100644
index 00000000..61a58744
--- /dev/null
+++ b/src/spdk/include/spdk/uuid.h
@@ -0,0 +1,100 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * UUID types and functions
+ */
+
+#ifndef SPDK_UUID_H
+#define SPDK_UUID_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/assert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct spdk_uuid {
+ union {
+ uint8_t raw[16];
+ } u;
+};
+SPDK_STATIC_ASSERT(sizeof(struct spdk_uuid) == 16, "Incorrect size");
+
+#define SPDK_UUID_STRING_LEN 37 /* 36 characters + null terminator */
+
+/**
+ * Convert UUID in textual format into a spdk_uuid.
+ *
+ * \param[out] uuid User-provided UUID buffer.
+ * \param uuid_str UUID in textual format in C string.
+ *
+ * \return 0 on success, or negative errno on failure.
+ */
+int spdk_uuid_parse(struct spdk_uuid *uuid, const char *uuid_str);
+
+/**
+ * Convert UUID in spdk_uuid into lowercase textual format.
+ *
+ * \param uuid_str User-provided string buffer to write the textual format into.
+ * \param uuid_str_size Size of uuid_str buffer. Must be at least SPDK_UUID_STRING_LEN.
+ * \param uuid UUID to convert to textual format.
+ *
+ * \return 0 on success, or negative errno on failure.
+ */
+int spdk_uuid_fmt_lower(char *uuid_str, size_t uuid_str_size, const struct spdk_uuid *uuid);
+
+/**
+ * Compare two UUIDs.
+ *
+ * \param u1 UUID 1.
+ * \param u2 UUID 2.
+ *
+ * \return 0 if u1 == u2, less than 0 if u1 < u2, greater than 0 if u1 > u2.
+ */
+int spdk_uuid_compare(const struct spdk_uuid *u1, const struct spdk_uuid *u2);
+
+/**
+ * Generate a new UUID.
+ *
+ * \param[out] uuid User-provided UUID buffer to fill.
+ */
+void spdk_uuid_generate(struct spdk_uuid *uuid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/spdk/include/spdk/version.h b/src/spdk/include/spdk/version.h
new file mode 100644
index 00000000..7ff4c119
--- /dev/null
+++ b/src/spdk/include/spdk/version.h
@@ -0,0 +1,110 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * SPDK version number definitions
+ */
+
+#ifndef SPDK_VERSION_H
+#define SPDK_VERSION_H
+
+/**
+ * Major version number (year of original release minus 2000).
+ */
+#define SPDK_VERSION_MAJOR 18
+
+/**
+ * Minor version number (month of original release).
+ */
+#define SPDK_VERSION_MINOR 10
+
+/**
+ * Patch level.
+ *
+ * Patch level is incremented on maintenance branch releases and reset to 0 for each
+ * new major.minor release.
+ */
+#define SPDK_VERSION_PATCH 0
+
+/**
+ * Version string suffix.
+ */
+#define SPDK_VERSION_SUFFIX "-pre"
+
+/**
+ * Single numeric value representing a version number for compile-time comparisons.
+ *
+ * Example usage:
+ *
+ * \code
+ * #if SPDK_VERSION >= SPDK_VERSION_NUM(17, 7, 0)
+ * // Use feature from SPDK v17.07
+ * #endif
+ * \endcode
+ */
+#define SPDK_VERSION_NUM(major, minor, patch) \
+ (((major) * 100 + (minor)) * 100 + (patch))
+
+/**
+ * Current version as a SPDK_VERSION_NUM.
+ */
+#define SPDK_VERSION SPDK_VERSION_NUM(SPDK_VERSION_MAJOR, SPDK_VERSION_MINOR, SPDK_VERSION_PATCH)
+
+#define SPDK_VERSION_STRINGIFY_x(x) #x
+#define SPDK_VERSION_STRINGIFY(x) SPDK_VERSION_STRINGIFY_x(x)
+
+#define SPDK_VERSION_MAJOR_STRING SPDK_VERSION_STRINGIFY(SPDK_VERSION_MAJOR)
+
+#if SPDK_VERSION_MINOR < 10
+#define SPDK_VERSION_MINOR_STRING ".0" SPDK_VERSION_STRINGIFY(SPDK_VERSION_MINOR)
+#else
+#define SPDK_VERSION_MINOR_STRING "." SPDK_VERSION_STRINGIFY(SPDK_VERSION_MINOR)
+#endif
+
+#if SPDK_VERSION_PATCH != 0
+#define SPDK_VERSION_PATCH_STRING "." SPDK_VERSION_STRINGIFY(SPDK_VERSION_PATCH)
+#else
+#define SPDK_VERSION_PATCH_STRING ""
+#endif
+
+/**
+ * Human-readable version string.
+ */
+#define SPDK_VERSION_STRING \
+ "SPDK v" \
+ SPDK_VERSION_MAJOR_STRING \
+ SPDK_VERSION_MINOR_STRING \
+ SPDK_VERSION_PATCH_STRING \
+ SPDK_VERSION_SUFFIX
+
+#endif
diff --git a/src/spdk/include/spdk/vhost.h b/src/spdk/include/spdk/vhost.h
new file mode 100644
index 00000000..1b0e8079
--- /dev/null
+++ b/src/spdk/include/spdk/vhost.h
@@ -0,0 +1,336 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * SPDK vhost
+ */
+
+#ifndef SPDK_VHOST_H
+#define SPDK_VHOST_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/event.h"
+#include "spdk/json.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Callback funcion for spdk_vhost_fini().
+ */
+typedef void (*spdk_vhost_fini_cb)(void);
+
+/**
+ * Set the path to the directory where vhost sockets will be created.
+ *
+ * This function must be called before spdk_vhost_init().
+ *
+ * \param basename Path to vhost socket directory
+ *
+ * \return 0 on success, negative errno on error.
+ */
+int spdk_vhost_set_socket_path(const char *basename);
+
+/**
+ * Init vhost environment.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+int spdk_vhost_init(void);
+
+/**
+ * Clean up the environment of vhost after finishing the vhost application.
+ *
+ * \param fini_cb Called when the cleanup operation completes.
+ */
+void spdk_vhost_fini(spdk_vhost_fini_cb fini_cb);
+
+
+/**
+ * Write vhost subsystem configuration into provided JSON context.
+ *
+ * \param w JSON write context
+ * \param done_ev call this event when done.
+ */
+void spdk_vhost_config_json(struct spdk_json_write_ctx *w, struct spdk_event *done_ev);
+
+/**
+ * Deinit vhost application. This is called once by SPDK app layer.
+ */
+void spdk_vhost_shutdown_cb(void);
+
+/**
+ * SPDK vhost device (vdev). An equivalent of Virtio device.
+ * Both virtio-blk and virtio-scsi devices are represented by this
+ * struct. For virtio-scsi a single vhost device (also called SCSI
+ * controller) may contain multiple SCSI targets (devices), each of
+ * which may contain multiple logical units (SCSI LUNs). For now
+ * only one LUN per target is available.
+ *
+ * All vdev-changing functions operate directly on this object.
+ * Note that \c spdk_vhost_dev cannot be acquired. This object is
+ * only accessible as a callback parameter via \c
+ * spdk_vhost_call_external_event and it's derivatives. This ensures
+ * that all access to the vdev is piped through a single,
+ * thread-safe API.
+ */
+struct spdk_vhost_dev;
+
+/**
+ * Synchronized vhost event used for user callbacks.
+ *
+ * \param vdev vhost device.
+ * \param arg user-provided parameter.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+typedef int (*spdk_vhost_event_fn)(struct spdk_vhost_dev *vdev, void *arg);
+
+/**
+ * Get the name of the vhost device. This is equal to the filename
+ * of socket file. The name is constant throughout the lifetime of
+ * a vdev.
+ *
+ * \param vdev vhost device.
+ *
+ * \return name of the vdev.
+ */
+const char *spdk_vhost_dev_get_name(struct spdk_vhost_dev *vdev);
+
+/**
+ * Get cpuset of the vhost device. The cpuset is constant throughout the lifetime
+ * of a vdev. It is a subset of SPDK app cpuset vhost was started with.
+ *
+ * \param vdev vhost device.
+ *
+ * \return cpuset of the vdev.
+ */
+const struct spdk_cpuset *spdk_vhost_dev_get_cpumask(struct spdk_vhost_dev *vdev);
+
+/**
+ * By default, events are generated when asked, but for high queue depth and
+ * high IOPS this prove to be inefficient both for guest kernel that have to
+ * handle a lot more IO completions and for SPDK vhost that need to make more
+ * syscalls. If enabled, limit amount of events (IRQs) sent to initiator by SPDK
+ * vhost effectively coalescing couple of completions. This of cource introduce
+ * IO latency penalty proportional to event delay time.
+ *
+ * Actual events delay time when is calculated according to below formula:
+ * if (delay_base == 0 || IOPS < iops_threshold) {
+ * delay = 0;
+ * } else if (IOPS < iops_threshold) {
+ * delay = delay_base * (iops - iops_threshold) / iops_threshold;
+ * }
+ *
+ * \param vdev vhost device.
+ * \param delay_base_us Base delay time in microseconds. If 0, coalescing is disabled.
+ * \param iops_threshold IOPS threshold when coalescing is activated.
+ */
+int spdk_vhost_set_coalescing(struct spdk_vhost_dev *vdev, uint32_t delay_base_us,
+ uint32_t iops_threshold);
+
+/**
+ * Get coalescing parameters.
+ *
+ * \see spdk_vhost_set_coalescing
+ *
+ * \param vdev vhost device.
+ * \param delay_base_us Optional pointer to store base delay time.
+ * \param iops_threshold Optional pointer to store IOPS threshold.
+ */
+void spdk_vhost_get_coalescing(struct spdk_vhost_dev *vdev, uint32_t *delay_base_us,
+ uint32_t *iops_threshold);
+
+/**
+ * Construct an empty vhost SCSI device. This will create a
+ * Unix domain socket together with a vhost-user slave server waiting
+ * for a connection on this socket. Creating the vdev does not
+ * start any I/O pollers and does not hog the CPU. I/O processing
+ * starts after receiving proper message on the created socket.
+ * See QEMU's vhost-user documentation for details.
+ * All physical devices have to be separately attached to this
+ * vdev via \c spdk_vhost_scsi_dev_add_tgt().
+ *
+ * This function is thread-safe.
+ *
+ * \param name name of the vhost device. The name will also be used
+ * for socket name, which is exactly \c socket_base_dir/name
+ * \param cpumask string containing cpumask in hex. The leading *0x*
+ * is allowed but not required. The mask itself can be constructed as:
+ * ((1 << cpu0) | (1 << cpu1) | ... | (1 << cpuN)).
+ *
+ * \return 0 on success, negative errno on error.
+ */
+int spdk_vhost_scsi_dev_construct(const char *name, const char *cpumask);
+
+/**
+ * Construct and attach new SCSI target to the vhost SCSI device
+ * on given (unoccupied) slot. The device will be created with a single
+ * LUN0 associated with given SPDK bdev. Currently only one LUN per
+ * device is supported.
+ *
+ * If the vhost SCSI device has an active connection and has negotiated
+ * \c VIRTIO_SCSI_F_HOTPLUG feature, the new SCSI target should be
+ * automatically detected by the other side.
+ *
+ * \param vdev vhost SCSI device.
+ * \param scsi_tgt_num slot to attach to.
+ * \param bdev_name name of the SPDK bdev to associate with SCSI LUN0.
+ *
+ * \return 0 on success, negative errno on error.
+ */
+int spdk_vhost_scsi_dev_add_tgt(struct spdk_vhost_dev *vdev, unsigned scsi_tgt_num,
+ const char *bdev_name);
+
+/**
+ * Get SCSI target from vhost SCSI device on given slot. Max
+ * number of available slots is defined by.
+ * \c SPDK_VHOST_SCSI_CTRLR_MAX_DEVS.
+ *
+ * \param vdev vhost SCSI device.
+ * \param num slot id.
+ *
+ * \return SCSI device on given slot or NULL.
+ */
+struct spdk_scsi_dev *spdk_vhost_scsi_dev_get_tgt(struct spdk_vhost_dev *vdev, uint8_t num);
+
+/**
+ * Detach and destruct SCSI target from a vhost SCSI device.
+ *
+ * If vhost SCSI device has an active socket connection, it is
+ * required that it has negotiated \c VIRTIO_SCSI_F_HOTPLUG feature
+ * flag.Otherwise an -ENOTSUP error code is returned. If the flag has
+ * been negotiated, the device will be marked to be deleted. Actual
+ * deletion is deferred until after all pending I/O to this device
+ * has finished.
+ *
+ * Once the target has been deleted (whether or not vhost SCSI
+ * device is in use) given callback will be called.
+ *
+ * \param vdev vhost SCSI device
+ * \param scsi_tgt_num slot id to delete target from
+ * \param cb_fn callback to be fired once target has been successfully
+ * deleted. The first parameter of callback function is the vhost SCSI
+ * device, the second is user provided argument *cb_arg*.
+ * \param cb_arg parameter to be passed to *cb_fn*.
+ *
+ * \return 0 on success, negative errno on error.
+ */
+int spdk_vhost_scsi_dev_remove_tgt(struct spdk_vhost_dev *vdev, unsigned scsi_tgt_num,
+ spdk_vhost_event_fn cb_fn, void *cb_arg);
+
+/**
+ * Construct a vhost blk device. This will create a Unix domain
+ * socket together with a vhost-user slave server waiting for a
+ * connection on this socket. Creating the vdev does not start
+ * any I/O pollers and does not hog the CPU. I/O processing starts
+ * after receiving proper message on the created socket.
+ * See QEMU's vhost-user documentation for details. Vhost blk
+ * device is tightly associated with given SPDK bdev. Given
+ * bdev can not be changed, unless it has been hotremoved. This
+ * would result in all I/O failing with virtio \c VIRTIO_BLK_S_IOERR
+ * error code.
+ *
+ * This function is thread-safe.
+ *
+ * \param name name of the vhost blk device. The name will also be
+ * used for socket name, which is exactly \c socket_base_dir/name
+ * \param cpumask string containing cpumask in hex. The leading *0x*
+ * is allowed but not required. The mask itself can be constructed as:
+ * ((1 << cpu0) | (1 << cpu1) | ... | (1 << cpuN)).
+ * \param dev_name bdev name to associate with this vhost device
+ * \param readonly if set, all writes to the device will fail with
+ * \c VIRTIO_BLK_S_IOERR error code.
+ *
+ * \return 0 on success, negative errno on error.
+ */
+int spdk_vhost_blk_construct(const char *name, const char *cpumask, const char *dev_name,
+ bool readonly);
+
+/**
+ * Remove a vhost device. The device must not have any open connections on it's socket.
+ *
+ * \param vdev vhost blk device.
+ *
+ * \return 0 on success, negative errno on error.
+ */
+int spdk_vhost_dev_remove(struct spdk_vhost_dev *vdev);
+
+/**
+ * Get underlying SPDK bdev from vhost blk device. The bdev might be NULL, as it
+ * could have been hotremoved.
+ *
+ * \param ctrlr vhost blk device.
+ *
+ * \return SPDK bdev associated with given vdev.
+ */
+struct spdk_bdev *spdk_vhost_blk_get_dev(struct spdk_vhost_dev *ctrlr);
+
+/**
+ * Call function on reactor of given vhost device. If device is not in use, the
+ * event will be called right away on the caller's thread.
+ *
+ * This function is thread safe.
+ *
+ * \param vdev_name name of the vhost device to run this event on.
+ * \param fn function to be called. The first parameter of callback function is
+ * either actual spdk_vhost_dev pointer or NULL in case vdev with given name doesn't
+ * exist. The second param is user provided argument *arg*.
+ * \param arg parameter to be passed to *fn*.
+ */
+void spdk_vhost_call_external_event(const char *vdev_name, spdk_vhost_event_fn fn, void *arg);
+
+/**
+ * Call function for each available vhost device on
+ * it's reactor. This will call given function in a chain,
+ * meaning that each callback will be called after the
+ * previous one has finished. After given function has
+ * been called for all vdevs, it will be called once
+ * again with first param - vhost device- set to NULL.
+ *
+ * This function is thread safe.
+ *
+ * \param fn function to be called for each vdev. The first param will be
+ * either vdev pointer or NULL. The second param is user provided argument *arg*.
+ * \param arg parameter to be passed to *fn*.
+ */
+void spdk_vhost_call_external_event_foreach(spdk_vhost_event_fn fn, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_VHOST_H */
diff --git a/src/spdk/include/spdk_internal/assert.h b/src/spdk/include/spdk_internal/assert.h
new file mode 100644
index 00000000..7e4c4507
--- /dev/null
+++ b/src/spdk/include/spdk_internal/assert.h
@@ -0,0 +1,55 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SPDK_INTERNAL_ASSERT_H
+#define SPDK_INTERNAL_ASSERT_H
+
+#include "spdk/stdinc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "spdk/assert.h"
+
+#if !defined(DEBUG) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
+#define SPDK_UNREACHABLE() __builtin_unreachable()
+#else
+#define SPDK_UNREACHABLE() abort()
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_INTERNAL_ASSERT_H */
diff --git a/src/spdk/include/spdk_internal/copy_engine.h b/src/spdk/include/spdk_internal/copy_engine.h
new file mode 100644
index 00000000..6b8a13c4
--- /dev/null
+++ b/src/spdk/include/spdk_internal/copy_engine.h
@@ -0,0 +1,95 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SPDK_INTERNAL_COPY_ENGINE_H
+#define SPDK_INTERNAL_COPY_ENGINE_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/copy_engine.h"
+#include "spdk/queue.h"
+
+struct spdk_copy_task {
+ spdk_copy_completion_cb cb;
+ uint8_t offload_ctx[0];
+};
+
+struct spdk_copy_engine {
+ int (*copy)(void *cb_arg, struct spdk_io_channel *ch, void *dst, void *src,
+ uint64_t nbytes, spdk_copy_completion_cb cb);
+ int (*fill)(void *cb_arg, struct spdk_io_channel *ch, void *dst, uint8_t fill,
+ uint64_t nbytes, spdk_copy_completion_cb cb);
+ struct spdk_io_channel *(*get_io_channel)(void);
+};
+
+struct spdk_copy_module_if {
+ /** Initialization function for the module. Called by the spdk
+ * application during startup.
+ *
+ * Modules are required to define this function.
+ */
+ int (*module_init)(void);
+
+ /** Finish function for the module. Called by the spdk application
+ * before the spdk application exits to perform any necessary cleanup.
+ *
+ * Modules are not required to define this function.
+ */
+ void (*module_fini)(void *ctx);
+
+ /** Function called to return a text string representing the
+ * module's configuration options for inclusion in an
+ * spdk configuration file.
+ */
+ void (*config_text)(FILE *fp);
+
+ size_t (*get_ctx_size)(void);
+ TAILQ_ENTRY(spdk_copy_module_if) tailq;
+};
+
+void spdk_copy_engine_register(struct spdk_copy_engine *copy_engine);
+void spdk_copy_module_list_add(struct spdk_copy_module_if *copy_module);
+
+#define SPDK_COPY_MODULE_REGISTER(init_fn, fini_fn, config_fn, ctx_size_fn) \
+ static struct spdk_copy_module_if init_fn ## _if = { \
+ .module_init = init_fn, \
+ .module_fini = fini_fn, \
+ .config_text = config_fn, \
+ .get_ctx_size = ctx_size_fn, \
+ }; \
+ __attribute__((constructor)) static void init_fn ## _init(void) \
+ { \
+ spdk_copy_module_list_add(&init_fn ## _if); \
+ }
+
+#endif
diff --git a/src/spdk/include/spdk_internal/event.h b/src/spdk/include/spdk_internal/event.h
new file mode 100644
index 00000000..25bdc04e
--- /dev/null
+++ b/src/spdk/include/spdk_internal/event.h
@@ -0,0 +1,133 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SPDK_INTERNAL_EVENT_H
+#define SPDK_INTERNAL_EVENT_H
+
+#include "spdk/stdinc.h"
+
+#include "spdk/event.h"
+#include "spdk/json.h"
+
+struct spdk_event {
+ uint32_t lcore;
+ spdk_event_fn fn;
+ void *arg1;
+ void *arg2;
+};
+
+int spdk_reactors_init(unsigned int max_delay_us);
+void spdk_reactors_fini(void);
+
+void spdk_reactors_start(void);
+void spdk_reactors_stop(void *arg1, void *arg2);
+
+struct spdk_subsystem {
+ const char *name;
+ /* User must call spdk_subsystem_init_next() when they are done with their initialization. */
+ void (*init)(void);
+ void (*fini)(void);
+ void (*config)(FILE *fp);
+
+ /**
+ * Write JSON configuration handler.
+ *
+ * \param w JSON write context
+ * \param done_ev Done event to be called when writing is done.
+ */
+ void (*write_config_json)(struct spdk_json_write_ctx *w, struct spdk_event *done_ev);
+ TAILQ_ENTRY(spdk_subsystem) tailq;
+};
+
+TAILQ_HEAD(spdk_subsystem_list, spdk_subsystem);
+extern struct spdk_subsystem_list g_subsystems;
+
+struct spdk_subsystem *spdk_subsystem_find(struct spdk_subsystem_list *list, const char *name);
+
+struct spdk_subsystem_depend {
+ const char *name;
+ const char *depends_on;
+ TAILQ_ENTRY(spdk_subsystem_depend) tailq;
+};
+
+TAILQ_HEAD(spdk_subsystem_depend_list, spdk_subsystem_depend);
+extern struct spdk_subsystem_depend_list g_subsystems_deps;
+
+void spdk_add_subsystem(struct spdk_subsystem *subsystem);
+void spdk_add_subsystem_depend(struct spdk_subsystem_depend *depend);
+
+void spdk_subsystem_init(struct spdk_event *app_start_event);
+void spdk_subsystem_fini(struct spdk_event *app_finish_event);
+void spdk_subsystem_init_next(int rc);
+void spdk_subsystem_fini_next(void);
+void spdk_subsystem_config(FILE *fp);
+
+/**
+ * Save pointed \c subsystem configuration to the JSON write context \c w. In case of
+ * error \c null is written to the JSON context. Writing might be done in async way
+ * so caller need to pass event that subsystem will call when it finish writing
+ * configuration.
+ *
+ * \param w JSON write context
+ * \param subsystem the subsystem to query
+ * \param done_ev event to be called when writing is done
+ */
+void spdk_subsystem_config_json(struct spdk_json_write_ctx *w, struct spdk_subsystem *subsystem,
+ struct spdk_event *done_ev);
+
+void spdk_rpc_initialize(const char *listen_addr);
+void spdk_rpc_finish(void);
+
+/**
+ * \brief Register a new subsystem
+ */
+#define SPDK_SUBSYSTEM_REGISTER(_name) \
+ __attribute__((constructor)) static void _name ## _register(void) \
+ { \
+ spdk_add_subsystem(&_name); \
+ }
+
+/**
+ * \brief Declare that a subsystem depends on another subsystem.
+ */
+#define SPDK_SUBSYSTEM_DEPEND(_name, _depends_on) \
+ static struct spdk_subsystem_depend __subsystem_ ## _name ## _depend_on ## _depends_on = { \
+ .name = #_name, \
+ .depends_on = #_depends_on, \
+ }; \
+ __attribute__((constructor)) static void _name ## _depend_on ## _depends_on(void) \
+ { \
+ spdk_add_subsystem_depend(&__subsystem_ ## _name ## _depend_on ## _depends_on); \
+ }
+
+#endif /* SPDK_INTERNAL_EVENT_H */
diff --git a/src/spdk/include/spdk_internal/log.h b/src/spdk/include/spdk_internal/log.h
new file mode 100644
index 00000000..c91116bb
--- /dev/null
+++ b/src/spdk/include/spdk_internal/log.h
@@ -0,0 +1,101 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * Logging interfaces
+ */
+
+#ifndef SPDK_INTERNAL_LOG_H
+#define SPDK_INTERNAL_LOG_H
+
+#include "spdk/log.h"
+#include "spdk/queue.h"
+
+extern enum spdk_log_level g_spdk_log_level;
+extern enum spdk_log_level g_spdk_log_print_level;
+extern enum spdk_log_level g_spdk_log_backtrace_level;
+
+struct spdk_trace_flag {
+ TAILQ_ENTRY(spdk_trace_flag) tailq;
+ const char *name;
+ bool enabled;
+};
+
+void spdk_log_register_trace_flag(const char *name, struct spdk_trace_flag *flag);
+
+struct spdk_trace_flag *spdk_log_get_first_trace_flag(void);
+struct spdk_trace_flag *spdk_log_get_next_trace_flag(struct spdk_trace_flag *flag);
+
+#define SPDK_LOG_REGISTER_COMPONENT(str, flag) \
+struct spdk_trace_flag flag = { \
+ .enabled = false, \
+ .name = str, \
+}; \
+__attribute__((constructor)) static void register_trace_flag_##flag(void) \
+{ \
+ spdk_log_register_trace_flag(str, &flag); \
+}
+
+#define SPDK_INFOLOG(FLAG, ...) \
+ do { \
+ extern struct spdk_trace_flag FLAG; \
+ if (FLAG.enabled) { \
+ spdk_log(SPDK_LOG_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__); \
+ } \
+ } while (0)
+
+#ifdef DEBUG
+
+#define SPDK_DEBUGLOG(FLAG, ...) \
+ do { \
+ extern struct spdk_trace_flag FLAG; \
+ if (FLAG.enabled) { \
+ spdk_log(SPDK_LOG_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__); \
+ } \
+ } while (0)
+
+#define SPDK_TRACEDUMP(FLAG, LABEL, BUF, LEN) \
+ do { \
+ extern struct spdk_trace_flag FLAG; \
+ if ((FLAG.enabled) && (LEN)) { \
+ spdk_trace_dump(stderr, (LABEL), (BUF), (LEN)); \
+ } \
+ } while (0)
+
+#else
+#define SPDK_DEBUGLOG(...) do { } while (0)
+#define SPDK_TRACEDUMP(...) do { } while (0)
+#endif
+
+#endif /* SPDK_INTERNAL_LOG_H */
diff --git a/src/spdk/include/spdk_internal/lvolstore.h b/src/spdk/include/spdk_internal/lvolstore.h
new file mode 100644
index 00000000..064bad5d
--- /dev/null
+++ b/src/spdk/include/spdk_internal/lvolstore.h
@@ -0,0 +1,124 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SPDK_INTERNAL_LVOLSTORE_H
+#define SPDK_INTERNAL_LVOLSTORE_H
+
+#include "spdk/blob.h"
+#include "spdk/lvol.h"
+#include "spdk/uuid.h"
+#include "spdk/bdev_module.h"
+
+/* Default size of blobstore cluster */
+#define SPDK_LVS_OPTS_CLUSTER_SZ (4 * 1024 * 1024)
+
+struct spdk_lvs_req {
+ spdk_lvs_op_complete cb_fn;
+ void *cb_arg;
+ struct spdk_lvol_store *lvol_store;
+ int lvserrno;
+};
+
+struct spdk_lvol_req {
+ spdk_lvol_op_complete cb_fn;
+ void *cb_arg;
+ struct spdk_lvol *lvol;
+ size_t sz;
+ struct spdk_io_channel *channel;
+ char name[SPDK_LVOL_NAME_MAX];
+};
+
+struct spdk_lvs_with_handle_req {
+ spdk_lvs_op_with_handle_complete cb_fn;
+ void *cb_arg;
+ struct spdk_lvol_store *lvol_store;
+ struct spdk_bs_dev *bs_dev;
+ struct spdk_bdev *base_bdev;
+ int lvserrno;
+};
+
+struct spdk_lvs_destroy_req {
+ spdk_lvs_op_complete cb_fn;
+ void *cb_arg;
+ struct spdk_lvol_store *lvs;
+};
+
+struct spdk_lvol_with_handle_req {
+ spdk_lvol_op_with_handle_complete cb_fn;
+ void *cb_arg;
+ struct spdk_lvol *lvol;
+};
+
+struct spdk_lvol_store {
+ struct spdk_bs_dev *bs_dev;
+ struct spdk_blob_store *blobstore;
+ struct spdk_blob *super_blob;
+ spdk_blob_id super_blob_id;
+ struct spdk_uuid uuid;
+ int lvol_count;
+ int lvols_opened;
+ bool destruct;
+ TAILQ_HEAD(, spdk_lvol) lvols;
+ TAILQ_HEAD(, spdk_lvol) pending_lvols;
+ bool on_list;
+ TAILQ_ENTRY(spdk_lvol_store) link;
+ char name[SPDK_LVS_NAME_MAX];
+ char new_name[SPDK_LVS_NAME_MAX];
+};
+
+struct spdk_lvol {
+ struct spdk_lvol_store *lvol_store;
+ struct spdk_blob *blob;
+ spdk_blob_id blob_id;
+ char *unique_id;
+ char name[SPDK_LVOL_NAME_MAX];
+ struct spdk_uuid uuid;
+ char uuid_str[SPDK_UUID_STRING_LEN];
+ bool thin_provision;
+ struct spdk_bdev *bdev;
+ int ref_count;
+ bool action_in_progress;
+ TAILQ_ENTRY(spdk_lvol) link;
+};
+
+struct lvol_task {
+ enum spdk_bdev_io_status status;
+};
+
+struct lvol_store_bdev *vbdev_lvol_store_first(void);
+struct lvol_store_bdev *vbdev_lvol_store_next(struct lvol_store_bdev *prev);
+
+void spdk_lvol_resize(struct spdk_lvol *lvol, uint64_t sz, spdk_lvol_op_complete cb_fn,
+ void *cb_arg);
+
+#endif /* SPDK_INTERNAL_LVOLSTORE_H */
diff --git a/src/spdk/include/spdk_internal/mock.h b/src/spdk/include/spdk_internal/mock.h
new file mode 100644
index 00000000..f5a366dd
--- /dev/null
+++ b/src/spdk/include/spdk_internal/mock.h
@@ -0,0 +1,117 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SPDK_INTERNAL_MOCK_H
+#define SPDK_INTERNAL_MOCK_H
+
+#include "spdk/stdinc.h"
+
+#define MOCK_STRUCT_INIT(...) \
+ { __VA_ARGS__ }
+
+#define DEFINE_RETURN_MOCK(fn, ret) \
+ bool ut_ ## fn ## _mocked = false; \
+ ret ut_ ## fn
+
+/*
+ * For controlling mocked function behavior, setting
+ * and getting values from the stub, the _P macros are
+ * for mocking functions that return pointer values.
+ */
+#define MOCK_SET(fn, val) \
+ ut_ ## fn ## _mocked = true; \
+ ut_ ## fn = val
+
+#define MOCK_GET(fn) \
+ ut_ ## fn
+
+#define MOCK_CLEAR(fn) \
+ ut_ ## fn ## _mocked = false;
+
+#define MOCK_CLEAR_P(fn) \
+ ut_ ## fn ## _mocked = false; \
+ ut_ ## fn = NULL;
+
+/* for declaring function protoypes for wrappers */
+#define DECLARE_WRAPPER(fn, ret, args) \
+ extern bool ut_ ## fn ## _mocked; \
+ extern ret ut_ ## fn; \
+ ret __wrap_ ## fn args; ret __real_ ## fn args;
+
+/* for defining the implmentation of wrappers for syscalls */
+#define DEFINE_WRAPPER(fn, ret, dargs, pargs) \
+ DEFINE_RETURN_MOCK(fn, ret); \
+ __attribute__((used)) ret __wrap_ ## fn dargs \
+ { \
+ if (!ut_ ## fn ## _mocked) { \
+ return __real_ ## fn pargs; \
+ } else { \
+ return MOCK_GET(fn); \
+ } \
+ }
+
+/* DEFINE_STUB is for defining the implmentation of stubs for SPDK funcs. */
+#define DEFINE_STUB(fn, ret, dargs, val) \
+ bool ut_ ## fn ## _mocked = true; \
+ ret ut_ ## fn = val; \
+ ret fn dargs; \
+ ret fn dargs \
+ { \
+ return MOCK_GET(fn); \
+ }
+
+/* DEFINE_STUB_V macro is for stubs that don't have a return value */
+#define DEFINE_STUB_V(fn, dargs) \
+ void fn dargs; \
+ void fn dargs \
+ { \
+ }
+
+#define HANDLE_RETURN_MOCK(fn) \
+ if (ut_ ## fn ## _mocked) { \
+ return ut_ ## fn; \
+ }
+
+
+/* declare wrapper protos (alphabetically please) here */
+DECLARE_WRAPPER(calloc, void *, (size_t nmemb, size_t size));
+
+DECLARE_WRAPPER(pthread_mutex_init, int,
+ (pthread_mutex_t *mtx, const pthread_mutexattr_t *attr));
+
+DECLARE_WRAPPER(pthread_mutexattr_init, int,
+ (pthread_mutexattr_t *attr));
+
+DECLARE_WRAPPER(pthread_self, pthread_t, (void));
+
+#endif /* SPDK_INTERNAL_MOCK_H */
diff --git a/src/spdk/include/spdk_internal/sock.h b/src/spdk/include/spdk_internal/sock.h
new file mode 100644
index 00000000..d5542bf3
--- /dev/null
+++ b/src/spdk/include/spdk_internal/sock.h
@@ -0,0 +1,109 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * TCP network implementation abstraction layer
+ */
+
+#ifndef SPDK_INTERNAL_SOCK_H
+#define SPDK_INTERNAL_SOCK_H
+
+#include "spdk/stdinc.h"
+#include "spdk/sock.h"
+#include "spdk/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_EVENTS_PER_POLL 32
+
+struct spdk_sock {
+ struct spdk_net_impl *net_impl;
+ spdk_sock_cb cb_fn;
+ void *cb_arg;
+ TAILQ_ENTRY(spdk_sock) link;
+};
+
+struct spdk_sock_group {
+ STAILQ_HEAD(, spdk_sock_group_impl) group_impls;
+};
+
+struct spdk_sock_group_impl {
+ struct spdk_net_impl *net_impl;
+ TAILQ_HEAD(, spdk_sock) socks;
+ STAILQ_ENTRY(spdk_sock_group_impl) link;
+};
+
+struct spdk_net_impl {
+ const char *name;
+
+ int (*getaddr)(struct spdk_sock *sock, char *saddr, int slen, uint16_t *sport, char *caddr,
+ int clen, uint16_t *cport);
+ struct spdk_sock *(*connect)(const char *ip, int port);
+ struct spdk_sock *(*listen)(const char *ip, int port);
+ struct spdk_sock *(*accept)(struct spdk_sock *sock);
+ int (*close)(struct spdk_sock *sock);
+ ssize_t (*recv)(struct spdk_sock *sock, void *buf, size_t len);
+ ssize_t (*writev)(struct spdk_sock *sock, struct iovec *iov, int iovcnt);
+
+ int (*set_recvlowat)(struct spdk_sock *sock, int nbytes);
+ int (*set_recvbuf)(struct spdk_sock *sock, int sz);
+ int (*set_sendbuf)(struct spdk_sock *sock, int sz);
+
+ bool (*is_ipv6)(struct spdk_sock *sock);
+ bool (*is_ipv4)(struct spdk_sock *sock);
+
+ struct spdk_sock_group_impl *(*group_impl_create)(void);
+ int (*group_impl_add_sock)(struct spdk_sock_group_impl *group, struct spdk_sock *sock);
+ int (*group_impl_remove_sock)(struct spdk_sock_group_impl *group, struct spdk_sock *sock);
+ int (*group_impl_poll)(struct spdk_sock_group_impl *group, int max_events,
+ struct spdk_sock **socks);
+ int (*group_impl_close)(struct spdk_sock_group_impl *group);
+
+ STAILQ_ENTRY(spdk_net_impl) link;
+};
+
+void spdk_net_impl_register(struct spdk_net_impl *impl);
+
+#define SPDK_NET_IMPL_REGISTER(name, impl) \
+static void __attribute__((constructor)) net_impl_register_##name(void) \
+{ \
+ spdk_net_impl_register(impl); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPDK_INTERNAL_SOCK_H */
diff --git a/src/spdk/include/spdk_internal/utf.h b/src/spdk/include/spdk_internal/utf.h
new file mode 100644
index 00000000..b2b1c3c4
--- /dev/null
+++ b/src/spdk/include/spdk_internal/utf.h
@@ -0,0 +1,325 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SPDK_UTF_H_
+#define SPDK_UTF_H_
+
+#include "spdk/stdinc.h"
+
+#include "spdk/endian.h"
+#include "spdk/likely.h"
+#include "spdk/string.h"
+
+static inline bool
+utf8_tail(uint8_t c)
+{
+ /* c >= 0x80 && c <= 0xBF, or binary 01xxxxxx */
+ return (c & 0xC0) == 0x80;
+}
+
+/*
+ * Check for a valid UTF-8 encoding of a single codepoint.
+ *
+ * \return Length of valid UTF-8 byte sequence, or negative if invalid.
+ */
+static inline int
+utf8_valid(const uint8_t *start, const uint8_t *end)
+{
+ const uint8_t *p = start;
+ uint8_t b0, b1, b2, b3;
+
+ if (p == end) {
+ return 0;
+ }
+
+ b0 = *p;
+
+ if (b0 <= 0x7F) {
+ return 1;
+ }
+
+ if (b0 <= 0xC1) {
+ /* Invalid start byte */
+ return -1;
+ }
+
+ if (++p == end) {
+ /* Not enough bytes left */
+ return -1;
+ }
+ b1 = *p;
+
+ if (b0 <= 0xDF) {
+ /* C2..DF 80..BF */
+ if (!utf8_tail(b1)) {
+ return -1;
+ }
+ return 2;
+ }
+
+ if (++p == end) {
+ /* Not enough bytes left */
+ return -1;
+ }
+ b2 = *p;
+
+ if (b0 == 0xE0) {
+ /* E0 A0..BF 80..BF */
+ if (b1 < 0xA0 || b1 > 0xBF || !utf8_tail(b2)) {
+ return -1;
+ }
+ return 3;
+ } else if (b0 == 0xED && b1 >= 0xA0) {
+ /*
+ * UTF-16 surrogate pairs use U+D800..U+DFFF, which would be encoded as
+ * ED A0..BF 80..BF in UTF-8; however, surrogate pairs are not allowed in UTF-8.
+ */
+ return -1;
+ } else if (b0 <= 0xEF) {
+ /* E1..EF 80..BF 80..BF */
+ if (!utf8_tail(b1) || !utf8_tail(b2)) {
+ return -1;
+ }
+ return 3;
+ }
+
+ if (++p == end) {
+ /* Not enough bytes left */
+ return -1;
+ }
+ b3 = *p;
+
+ if (b0 == 0xF0) {
+ /* F0 90..BF 80..BF 80..BF */
+ if (b1 < 0x90 || b1 > 0xBF || !utf8_tail(b2) || !utf8_tail(b3)) {
+ return -1;
+ }
+ return 4;
+ } else if (b0 <= 0xF3) {
+ /* F1..F3 80..BF 80..BF 80..BF */
+ if (!utf8_tail(b1) || !utf8_tail(b2) || !utf8_tail(b3)) {
+ return -1;
+ }
+ return 4;
+ } else if (b0 == 0xF4) {
+ /* F4 80..8F 80..BF 80..BF */
+ if (b1 < 0x80 || b1 > 0x8F || !utf8_tail(b2) || !utf8_tail(b3)) {
+ return -1;
+ }
+ return 4;
+ }
+
+ return -1;
+}
+
+static inline uint32_t
+utf8_decode_unsafe_1(const uint8_t *data)
+{
+ return data[0];
+}
+
+static inline uint32_t
+utf8_decode_unsafe_2(const uint8_t *data)
+{
+ uint32_t codepoint;
+
+ codepoint = ((data[0] & 0x1F) << 6);
+ codepoint |= (data[1] & 0x3F);
+
+ return codepoint;
+}
+
+static inline uint32_t
+utf8_decode_unsafe_3(const uint8_t *data)
+{
+ uint32_t codepoint;
+
+ codepoint = ((data[0] & 0x0F) << 12);
+ codepoint |= (data[1] & 0x3F) << 6;
+ codepoint |= (data[2] & 0x3F);
+
+ return codepoint;
+}
+
+static inline uint32_t
+utf8_decode_unsafe_4(const uint8_t *data)
+{
+ uint32_t codepoint;
+
+ codepoint = ((data[0] & 0x07) << 18);
+ codepoint |= (data[1] & 0x3F) << 12;
+ codepoint |= (data[2] & 0x3F) << 6;
+ codepoint |= (data[3] & 0x3F);
+
+ return codepoint;
+}
+
+/*
+ * Encode a single Unicode codepoint as UTF-8.
+ *
+ * buf must have at least 4 bytes of space available (hence unsafe).
+ *
+ * \return Number of bytes appended to buf, or negative if encoding failed.
+ */
+static inline int
+utf8_encode_unsafe(uint8_t *buf, uint32_t c)
+{
+ if (c <= 0x7F) {
+ buf[0] = c;
+ return 1;
+ } else if (c <= 0x7FF) {
+ buf[0] = 0xC0 | (c >> 6);
+ buf[1] = 0x80 | (c & 0x3F);
+ return 2;
+ } else if (c >= 0xD800 && c <= 0xDFFF) {
+ /* UTF-16 surrogate pairs - invalid in UTF-8 */
+ return -1;
+ } else if (c <= 0xFFFF) {
+ buf[0] = 0xE0 | (c >> 12);
+ buf[1] = 0x80 | ((c >> 6) & 0x3F);
+ buf[2] = 0x80 | (c & 0x3F);
+ return 3;
+ } else if (c <= 0x10FFFF) {
+ buf[0] = 0xF0 | (c >> 18);
+ buf[1] = 0x80 | ((c >> 12) & 0x3F);
+ buf[2] = 0x80 | ((c >> 6) & 0x3F);
+ buf[3] = 0x80 | (c & 0x3F);
+ return 4;
+ }
+ return -1;
+}
+
+static inline int
+utf8_codepoint_len(uint32_t c)
+{
+ if (c <= 0x7F) {
+ return 1;
+ } else if (c <= 0x7FF) {
+ return 2;
+ } else if (c >= 0xD800 && c <= 0xDFFF) {
+ /* UTF-16 surrogate pairs - invalid in UTF-8 */
+ return -1;
+ } else if (c <= 0xFFFF) {
+ return 3;
+ } else if (c <= 0x10FFFF) {
+ return 4;
+ }
+ return -1;
+}
+
+static inline bool
+utf16_valid_surrogate_high(uint32_t val)
+{
+ return val >= 0xD800 && val <= 0xDBFF;
+}
+
+static inline bool
+utf16_valid_surrogate_low(uint32_t val)
+{
+ return val >= 0xDC00 && val <= 0xDFFF;
+}
+
+/*
+ * Check for a valid UTF-16LE encoding of a single codepoint.
+ *
+ * \return Length of valid UTF-16LE sequence in 16-bit code units, or negative if invalid.
+ */
+static inline int
+utf16le_valid(const uint16_t *start, const uint16_t *end)
+{
+ const uint16_t *p = start;
+ uint16_t high, low;
+
+ if (p == end) {
+ return 0;
+ }
+
+ high = from_le16(p);
+
+ if (high <= 0xD7FF || high >= 0xE000) {
+ /* Single code unit in BMP */
+ return 1;
+ }
+
+ if (high >= 0xDC00) {
+ /* Low surrogate in first code unit - invalid */
+ return -1;
+ }
+
+ assert(utf16_valid_surrogate_high(high));
+
+ if (++p == end) {
+ /* Not enough code units left */
+ return -1;
+ }
+ low = from_le16(p);
+
+ if (!utf16_valid_surrogate_low(low)) {
+ return -1;
+ }
+
+ /* Valid surrogate pair */
+ return 2;
+}
+
+static inline uint32_t
+utf16_decode_surrogate_pair(uint32_t high, uint32_t low)
+{
+ uint32_t codepoint;
+
+ assert(utf16_valid_surrogate_high(high));
+ assert(utf16_valid_surrogate_low(low));
+
+ codepoint = low;
+ codepoint &= 0x3FF;
+ codepoint |= ((high & 0x3FF) << 10);
+ codepoint += 0x10000;
+
+ return codepoint;
+}
+
+static inline void
+utf16_encode_surrogate_pair(uint32_t codepoint, uint16_t *high, uint16_t *low)
+{
+ assert(codepoint >= 0x10000);
+ assert(codepoint <= 0x10FFFF);
+
+ codepoint -= 0x10000;
+ *high = 0xD800 | (codepoint >> 10);
+ *low = 0xDC00 | (codepoint & 0x3FF);
+
+ assert(utf16_valid_surrogate_high(*high));
+ assert(utf16_valid_surrogate_low(*low));
+}
+
+#endif
diff --git a/src/spdk/include/spdk_internal/virtio.h b/src/spdk/include/spdk_internal/virtio.h
new file mode 100644
index 00000000..77744029
--- /dev/null
+++ b/src/spdk/include/spdk_internal/virtio.h
@@ -0,0 +1,490 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SPDK_VIRTIO_H
+#define SPDK_VIRTIO_H
+
+#include "spdk/stdinc.h"
+
+#include <linux/virtio_ring.h>
+#include <linux/virtio_pci.h>
+#include <linux/virtio_config.h>
+
+#include "spdk_internal/log.h"
+#include "spdk/likely.h"
+#include "spdk/queue.h"
+#include "spdk/json.h"
+#include "spdk/thread.h"
+#include "spdk/pci_ids.h"
+#include "spdk/env.h"
+
+#ifndef VHOST_USER_F_PROTOCOL_FEATURES
+#define VHOST_USER_F_PROTOCOL_FEATURES 30
+#endif
+
+/**
+ * The maximum virtqueue size is 2^15. Use that value as the end of
+ * descriptor chain terminator since it will never be a valid index
+ * in the descriptor table. This is used to verify we are correctly
+ * handling vq_free_cnt.
+ */
+#define VQ_RING_DESC_CHAIN_END 32768
+
+#define SPDK_VIRTIO_MAX_VIRTQUEUES 0x100
+
+/* Extra status define for readability */
+#define VIRTIO_CONFIG_S_RESET 0
+
+struct virtio_dev_ops;
+
+struct virtio_dev {
+ struct virtqueue **vqs;
+
+ /** Name of this virtio dev set by backend */
+ char *name;
+
+ /** Fixed number of backend-specific non-I/O virtqueues. */
+ uint16_t fixed_queues_num;
+
+ /** Max number of virtqueues the host supports. */
+ uint16_t max_queues;
+
+ /** Common device & guest features. */
+ uint64_t negotiated_features;
+
+ int is_hw;
+
+ /** Modern/legacy virtio device flag. */
+ uint8_t modern;
+
+ /** Mutex for asynchronous virtqueue-changing operations. */
+ pthread_mutex_t mutex;
+
+ /** Backend-specific callbacks. */
+ const struct virtio_dev_ops *backend_ops;
+
+ /** Context for the backend ops */
+ void *ctx;
+};
+
+struct virtio_dev_ops {
+ int (*read_dev_cfg)(struct virtio_dev *hw, size_t offset,
+ void *dst, int len);
+ int (*write_dev_cfg)(struct virtio_dev *hw, size_t offset,
+ const void *src, int len);
+ uint8_t (*get_status)(struct virtio_dev *hw);
+ void (*set_status)(struct virtio_dev *hw, uint8_t status);
+
+ /**
+ * Get device features. The features might be already
+ * negotiated with driver (guest) features.
+ */
+ uint64_t (*get_features)(struct virtio_dev *vdev);
+
+ /**
+ * Negotiate and set device features.
+ * The negotiation can fail with return code -1.
+ * This function should also set vdev->negotiated_features field.
+ */
+ int (*set_features)(struct virtio_dev *vdev, uint64_t features);
+
+ /** Destruct virtio device */
+ void (*destruct_dev)(struct virtio_dev *vdev);
+
+ uint16_t (*get_queue_size)(struct virtio_dev *vdev, uint16_t queue_id);
+ int (*setup_queue)(struct virtio_dev *hw, struct virtqueue *vq);
+ void (*del_queue)(struct virtio_dev *hw, struct virtqueue *vq);
+ void (*notify_queue)(struct virtio_dev *hw, struct virtqueue *vq);
+
+ void (*dump_json_info)(struct virtio_dev *hw, struct spdk_json_write_ctx *w);
+ void (*write_json_config)(struct virtio_dev *hw, struct spdk_json_write_ctx *w);
+};
+
+struct vq_desc_extra {
+ void *cookie;
+ uint16_t ndescs;
+};
+
+struct virtqueue {
+ struct virtio_dev *vdev; /**< owner of this virtqueue */
+ struct vring vq_ring; /**< vring keeping desc, used and avail */
+ /**
+ * Last consumed descriptor in the used table,
+ * trails vq_ring.used->idx.
+ */
+ uint16_t vq_used_cons_idx;
+ uint16_t vq_nentries; /**< vring desc numbers */
+ uint16_t vq_free_cnt; /**< num of desc available */
+ uint16_t vq_avail_idx; /**< sync until needed */
+
+ void *vq_ring_virt_mem; /**< virtual address of vring */
+ unsigned int vq_ring_size;
+
+ uint64_t vq_ring_mem; /**< physical address of vring */
+
+ /**
+ * Head of the free chain in the descriptor table. If
+ * there are no free descriptors, this will be set to
+ * VQ_RING_DESC_CHAIN_END.
+ */
+ uint16_t vq_desc_head_idx;
+
+ /**
+ * Tail of the free chain in desc table. If
+ * there are no free descriptors, this will be set to
+ * VQ_RING_DESC_CHAIN_END.
+ */
+ uint16_t vq_desc_tail_idx;
+ uint16_t vq_queue_index; /**< PCI queue index */
+ uint16_t *notify_addr;
+
+ /** Thread that's polling this queue. */
+ struct spdk_thread *owner_thread;
+
+ uint16_t req_start;
+ uint16_t req_end;
+ uint16_t reqs_finished;
+
+ struct vq_desc_extra vq_descx[0];
+};
+
+enum spdk_virtio_desc_type {
+ SPDK_VIRTIO_DESC_RO = 0, /**< Read only */
+ SPDK_VIRTIO_DESC_WR = VRING_DESC_F_WRITE, /**< Write only */
+ /* TODO VIRTIO_DESC_INDIRECT */
+};
+
+/** Context for creating PCI virtio_devs */
+struct virtio_pci_ctx;
+
+/**
+ * Callback for creating virtio_dev from a PCI device.
+ * \param pci_ctx PCI context to be associated with a virtio_dev
+ * \param ctx context provided by the user
+ * \return 0 on success, -1 on error.
+ */
+typedef int (*virtio_pci_create_cb)(struct virtio_pci_ctx *pci_ctx, void *ctx);
+
+uint16_t virtio_recv_pkts(struct virtqueue *vq, void **io, uint32_t *len, uint16_t io_cnt);
+
+/**
+ * Start a new request on the current vring head position and associate it
+ * with an opaque cookie object. The previous request in given vq will be
+ * made visible to the device in hopes it can be processed early, but there's
+ * no guarantee it will be until the device is notified with \c
+ * virtqueue_req_flush. This behavior is simply an optimization and virtqueues
+ * must always be flushed. Empty requests (with no descriptors added) will be
+ * ignored. The device owning given virtqueue must be started.
+ *
+ * \param vq virtio queue
+ * \param cookie opaque object to associate with this request. Once the request
+ * is sent, processed and a response is received, the same object will be
+ * returned to the user after calling the virtio poll API.
+ * \param iovcnt number of required iovectors for the request. This can be
+ * higher than than the actual number of iovectors to be added.
+ * \return 0 on success or negative errno otherwise. If the `iovcnt` is
+ * greater than virtqueue depth, -EINVAL is returned. If simply not enough
+ * iovectors are available, -ENOMEM is returned.
+ */
+int virtqueue_req_start(struct virtqueue *vq, void *cookie, int iovcnt);
+
+/**
+ * Flush a virtqueue. This will notify the device if it's required.
+ * The device owning given virtqueue must be started.
+ *
+ * \param vq virtio queue
+ */
+void virtqueue_req_flush(struct virtqueue *vq);
+
+/**
+ * Abort the very last request in a virtqueue. This will restore virtqueue
+ * state to the point before the last request was created. Note that this
+ * is only effective if a queue hasn't been flushed yet. The device owning
+ * given virtqueue must be started.
+ *
+ * \param vq virtio queue
+ */
+void virtqueue_req_abort(struct virtqueue *vq);
+
+/**
+ * Add iovec chain to the last created request. This call does not provide any
+ * error-checking. The caller has to ensure that he doesn't add more iovs than
+ * what was specified during request creation. The device owning given virtqueue
+ * must be started.
+ *
+ * \param vq virtio queue
+ * \param iovs iovec array
+ * \param iovcnt number of iovs in iovec array
+ * \param desc_type type of all given iovectors
+ */
+void virtqueue_req_add_iovs(struct virtqueue *vq, struct iovec *iovs, uint16_t iovcnt,
+ enum spdk_virtio_desc_type desc_type);
+
+/**
+ * Construct a virtio device. The device will be in stopped state by default.
+ * Before doing any I/O, it has to be manually started via \c virtio_dev_restart.
+ *
+ * \param vdev memory for virtio device, must be zeroed
+ * \param name name for the virtio device
+ * \param ops backend callbacks
+ * \param ops_ctx argument for the backend callbacks
+ * \return zero on success, or negative error code otherwise
+ */
+int virtio_dev_construct(struct virtio_dev *vdev, const char *name,
+ const struct virtio_dev_ops *ops, void *ops_ctx);
+
+/**
+ * Reset the device and prepare it to be `virtio_dev_start`ed. This call
+ * will also renegotiate feature flags.
+ *
+ * \param vdev virtio device
+ * \param req_features features this driver supports. A VIRTIO_F_VERSION_1
+ * flag will be automatically appended, as legacy devices are not supported.
+ */
+int virtio_dev_reset(struct virtio_dev *vdev, uint64_t req_features);
+
+/**
+ * Notify the host to start processing this virtio device. This is
+ * a blocking call that won't return until the host has started.
+ * This will also allocate virtqueues.
+ *
+ * \param vdev virtio device
+ * \param max_queues number of queues to allocate. The max number of
+ * usable I/O queues is also limited by the host device. `vdev` will be
+ * started successfully even if the host supports less queues than requested.
+ * \param fixed_queue_num number of queues preceeding the first
+ * request queue. For Virtio-SCSI this is equal to 2, as there are
+ * additional event and control queues.
+ */
+int virtio_dev_start(struct virtio_dev *vdev, uint16_t max_queues,
+ uint16_t fixed_queues_num);
+
+/**
+ * Stop the host from processing the device. This is a blocking call
+ * that won't return until all outstanding I/O has been processed on
+ * the host (virtio device) side. In order to re-start the device, it
+ * has to be `virtio_dev_reset` first.
+ *
+ * \param vdev virtio device
+ */
+void virtio_dev_stop(struct virtio_dev *vdev);
+
+/**
+ * Destruct a virtio device. Note that it must be in the stopped state.
+ * The virtio_dev should be manually freed afterwards.
+ *
+ * \param vdev virtio device
+ */
+void virtio_dev_destruct(struct virtio_dev *vdev);
+
+/**
+ * Bind a virtqueue with given index to the current thread;
+ *
+ * This function is thread-safe.
+ *
+ * \param vdev vhost device
+ * \param index virtqueue index
+ * \return 0 on success, -1 in case a virtqueue with given index either
+ * does not exists or is already acquired.
+ */
+int virtio_dev_acquire_queue(struct virtio_dev *vdev, uint16_t index);
+
+/**
+ * Look for unused queue and bind it to the current thread. This will
+ * scan the queues in range from *start_index* (inclusive) up to
+ * vdev->max_queues (exclusive).
+ *
+ * This function is thread-safe.
+ *
+ * \param vdev vhost device
+ * \param start_index virtqueue index to start looking from
+ * \return index of acquired queue or -1 in case no unused queue in given range
+ * has been found
+ */
+int32_t virtio_dev_find_and_acquire_queue(struct virtio_dev *vdev, uint16_t start_index);
+
+/**
+ * Get thread that acquired given virtqueue.
+ *
+ * This function is thread-safe.
+ *
+ * \param vdev vhost device
+ * \param index index of virtqueue
+ * \return thread that acquired given virtqueue. If the queue is unused
+ * or doesn't exist a NULL is returned.
+ */
+struct spdk_thread *virtio_dev_queue_get_thread(struct virtio_dev *vdev, uint16_t index);
+
+/**
+ * Check if virtqueue with given index is acquired.
+ *
+ * This function is thread-safe.
+ *
+ * \param vdev vhost device
+ * \param index index of virtqueue
+ * \return virtqueue acquire status. in case of invalid index *false* is returned.
+ */
+bool virtio_dev_queue_is_acquired(struct virtio_dev *vdev, uint16_t index);
+
+/**
+ * Release previously acquired queue.
+ *
+ * This function must be called from the thread that acquired the queue.
+ *
+ * \param vdev vhost device
+ * \param index index of virtqueue to release
+ */
+void virtio_dev_release_queue(struct virtio_dev *vdev, uint16_t index);
+
+/**
+ * Get Virtio status flags.
+ *
+ * \param vdev virtio device
+ */
+uint8_t virtio_dev_get_status(struct virtio_dev *vdev);
+
+/**
+ * Set Virtio status flag. The flags have to be set in very specific order
+ * defined the VIRTIO 1.0 spec section 3.1.1. To unset the flags, stop the
+ * device or set \c VIRTIO_CONFIG_S_RESET status flag. There is no way to
+ * unset only particular flags.
+ *
+ * \param vdev virtio device
+ * \param flag flag to set
+ */
+void virtio_dev_set_status(struct virtio_dev *vdev, uint8_t flag);
+
+/**
+ * Write raw data into the device config at given offset. This call does not
+ * provide any error checking.
+ *
+ * \param vdev virtio device
+ * \param offset offset in bytes
+ * \param src pointer to data to copy from
+ * \param len length of data to copy in bytes
+ * \return 0 on success, negative errno otherwise
+ */
+int virtio_dev_write_dev_config(struct virtio_dev *vdev, size_t offset, const void *src, int len);
+
+/**
+ * Read raw data from the device config at given offset. This call does not
+ * provide any error checking.
+ *
+ * \param vdev virtio device
+ * \param offset offset in bytes
+ * \param dst pointer to buffer to copy data into
+ * \param len length of data to copy in bytes
+ * \return 0 on success, negative errno otherwise
+ */
+int virtio_dev_read_dev_config(struct virtio_dev *vdev, size_t offset, void *dst, int len);
+
+/**
+ * Get backend-specific ops for given device.
+ *
+ * \param vdev virtio device
+ */
+const struct virtio_dev_ops *virtio_dev_backend_ops(struct virtio_dev *vdev);
+
+/**
+ * Check if the device has negotiated given feature bit.
+ *
+ * \param vdev virtio device
+ * \param bit feature bit
+ */
+static inline bool
+virtio_dev_has_feature(struct virtio_dev *vdev, uint64_t bit)
+{
+ return !!(vdev->negotiated_features & (1ULL << bit));
+}
+
+/**
+ * Dump all device specific information into given json stream.
+ *
+ * \param vdev virtio device
+ * \param w json stream
+ */
+void virtio_dev_dump_json_info(struct virtio_dev *vdev, struct spdk_json_write_ctx *w);
+
+/**
+ * Enumerate all PCI Virtio devices of given type on the system.
+ *
+ * \param enum_cb a function to be called for each valid PCI device.
+ * If a virtio_dev is has been created, the callback should return 0.
+ * Returning any other value will cause the PCI context to be freed,
+ * making it unusable.
+ * \param enum_ctx additional opaque context to be passed into `enum_cb`
+ * \param pci_device_id PCI Device ID of devices to iterate through
+ */
+int virtio_pci_dev_enumerate(virtio_pci_create_cb enum_cb, void *enum_ctx,
+ uint16_t pci_device_id);
+
+/**
+ * Attach a PCI Virtio device of given type.
+ *
+ * \param create_cb callback to create a virtio_dev.
+ * If virtio_dev is has been created, the callback should return 0.
+ * Returning any other value will cause the PCI context to be freed,
+ * making it unusable.
+ * \param enum_ctx additional opaque context to be passed into `enum_cb`
+ * \param pci_device_id PCI Device ID of devices to iterate through
+ * \param pci_addr PCI address of the device to attach
+ */
+int virtio_pci_dev_attach(virtio_pci_create_cb create_cb, void *enum_ctx,
+ uint16_t pci_device_id, struct spdk_pci_addr *pci_addr);
+
+/**
+ * Connect to a vhost-user device and init corresponding virtio_dev struct.
+ * The virtio_dev will have to be freed with \c virtio_dev_free.
+ *
+ * \param vdev preallocated vhost device struct to operate on
+ * \param name name of this virtio device
+ * \param path path to the Unix domain socket of the vhost-user device
+ * \param queue_size size of each of the queues
+ * \return virtio device
+ */
+int virtio_user_dev_init(struct virtio_dev *vdev, const char *name, const char *path,
+ uint32_t queue_size);
+
+/**
+ * Initialize virtio_dev for a given PCI device.
+ * The virtio_dev has to be freed with \c virtio_dev_destruct.
+ *
+ * \param vdev preallocated vhost device struct to operate on
+ * \param name name of this virtio device
+ * \param pci_ctx context of the PCI device
+ * \return 0 on success, -1 on error.
+ */
+int virtio_pci_dev_init(struct virtio_dev *vdev, const char *name,
+ struct virtio_pci_ctx *pci_ctx);
+
+#endif /* SPDK_VIRTIO_H */