diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/spdk/include | |
parent | Initial commit. (diff) | |
download | ceph-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 '')
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(®_ ## 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 */ |