nvmf: add NVMe over Fabrics userspace target
Change-Id: I739916824d033bd1a8f8b7f5def09e58f23d13cb Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
parent
22f741d539
commit
0f912a0eaf
4
CONFIG
4
CONFIG
@ -68,3 +68,7 @@ CONFIG_FIO_PLUGIN?=n
|
||||
# This directory should contain the source code directory for fio
|
||||
# which is required for building the SPDK FIO plugin.
|
||||
FIO_SOURCE_DIR?=/usr/src/fio
|
||||
|
||||
# Build NVMf (NVMe over Fabrics) target.
|
||||
# Requires ibverbs development libraries.
|
||||
CONFIG_NVMF?=n
|
||||
|
@ -35,6 +35,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/..)
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
|
||||
DIRS-y += trace
|
||||
DIRS-$(CONFIG_NVMF) += nvmf_tgt
|
||||
|
||||
.PHONY: all clean $(DIRS-y)
|
||||
|
||||
|
1
app/nvmf_tgt/.gitignore
vendored
Normal file
1
app/nvmf_tgt/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
nvmf_tgt
|
70
app/nvmf_tgt/Makefile
Normal file
70
app/nvmf_tgt/Makefile
Normal file
@ -0,0 +1,70 @@
|
||||
#
|
||||
# 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
|
||||
|
||||
APP = nvmf_tgt
|
||||
|
||||
CFLAGS += $(DPDK_INC)
|
||||
|
||||
# Add NVMf library directory to include path
|
||||
# TODO: remove this once NVMf has a public API header
|
||||
CFLAGS += -I$(SPDK_ROOT_DIR)/lib
|
||||
|
||||
C_SRCS := nvmf_tgt.c
|
||||
|
||||
SPDK_LIBS = \
|
||||
$(SPDK_ROOT_DIR)/lib/nvmf/libspdk_nvmf.a \
|
||||
$(SPDK_ROOT_DIR)/lib/nvme/libspdk_nvme.a \
|
||||
$(SPDK_ROOT_DIR)/lib/event/libspdk_event.a \
|
||||
$(SPDK_ROOT_DIR)/lib/log/libspdk_log.a \
|
||||
$(SPDK_ROOT_DIR)/lib/trace/libspdk_trace.a \
|
||||
$(SPDK_ROOT_DIR)/lib/conf/libspdk_conf.a \
|
||||
$(SPDK_ROOT_DIR)/lib/util/libspdk_util.a \
|
||||
$(SPDK_ROOT_DIR)/lib/memory/libspdk_memory.a \
|
||||
|
||||
LIBS += $(SPDK_LIBS) $(PCIACCESS_LIB)
|
||||
|
||||
LIBS += -libverbs -lrdmacm
|
||||
LIBS += $(DPDK_LIB) -lpthread -lrt
|
||||
|
||||
all : $(APP)
|
||||
|
||||
$(APP) : $(OBJS) $(SPDK_LIBS)
|
||||
$(LINK_C)
|
||||
|
||||
clean :
|
||||
$(CLEAN_C) $(APP)
|
||||
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.deps.mk
|
240
app/nvmf_tgt/nvmf_tgt.c
Normal file
240
app/nvmf_tgt/nvmf_tgt.c
Normal file
@ -0,0 +1,240 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <rte_config.h>
|
||||
#include <rte_memzone.h>
|
||||
#include <rte_mempool.h>
|
||||
|
||||
#include "spdk/event.h"
|
||||
|
||||
#include "nvmf/conn.h"
|
||||
#include "nvmf/rdma.h"
|
||||
#include "nvmf/port.h"
|
||||
#include "nvmf/init_grp.h"
|
||||
#include "nvmf/nvmf.h"
|
||||
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/nvme.h"
|
||||
|
||||
struct rte_mempool *request_mempool;
|
||||
|
||||
#define SPDK_NVMF_DEFAULT_CONFIG SPDK_NVMF_BUILD_ETC "/nvmf.conf"
|
||||
|
||||
static void
|
||||
spdk_nvmf_shutdown_cb(void)
|
||||
{
|
||||
nvmf_acceptor_stop();
|
||||
spdk_shutdown_nvmf_conns();
|
||||
|
||||
fprintf(stdout, "\n=========================\n");
|
||||
fprintf(stdout, " NVMF shutdown signal\n");
|
||||
fprintf(stdout, "=========================\n");
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
printf("nvmf [options]\n");
|
||||
printf("options:\n");
|
||||
printf(" -c config - config file (default %s)\n", SPDK_NVMF_DEFAULT_CONFIG);
|
||||
printf(" -e mask - tracepoint group mask for spdk trace buffers (default 0x0)\n");
|
||||
printf(" -m mask - core mask for DPDK\n");
|
||||
printf(" -i instance ID\n");
|
||||
printf(" -l facility - use specific syslog facility (default %s)\n",
|
||||
SPDK_APP_DEFAULT_LOG_FACILITY);
|
||||
printf(" -n channel number of memory channels used for DPDK\n");
|
||||
printf(" -p core master (primary) core for DPDK\n");
|
||||
printf(" -s size memory size in MB for DPDK\n");
|
||||
|
||||
#ifdef DEBUG
|
||||
printf(" -t flag - trace flag options (all, rdma, nvmf, debug)\n");
|
||||
#else
|
||||
printf(" -t flag - trace flag options (not supported - must rebuild with CONFIG_DEBUG=y)\n");
|
||||
#endif
|
||||
printf(" -v - verbose (enable warnings)\n");
|
||||
printf(" -H - show this usage\n");
|
||||
printf(" -d - disable coredump file enabling\n");
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_nvmf_startup(spdk_event_t event)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* start the rdma poller that will listen
|
||||
on all available ports */
|
||||
rc = nvmf_acceptor_start();
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("nvmf_acceptor_start() failed\n");
|
||||
goto initialize_error;
|
||||
}
|
||||
|
||||
if (getenv("MEMZONE_DUMP") != NULL) {
|
||||
rte_memzone_dump(stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
initialize_error:
|
||||
spdk_app_stop(rc);
|
||||
}
|
||||
|
||||
/*! \file
|
||||
|
||||
This is the main file.
|
||||
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
||||
\brief This is the main function for the NVMf target application.
|
||||
|
||||
\msc
|
||||
|
||||
c_runtime [label="C Runtime"], dpdk [label="DPDK"], nvmf [label="NVMf target"];
|
||||
c_runtime=>nvmf [label="main()"];
|
||||
nvmf=> [label="rte_eal_init()"];
|
||||
nvmf=>nvmf [label="spdk_app_init()"];
|
||||
nvmf=>nvmf [label="spdk_event_allocate()"];
|
||||
nvmf=>nvmf [label="spdk_app_start()"];
|
||||
nvmf=>nvmf [label="spdk_app_fini()"];
|
||||
nvmf=>nvmf [label="spdk_nvmf_check_pools()"];
|
||||
c_runtime<<nvmf;
|
||||
|
||||
\endmsc
|
||||
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int ch;
|
||||
int rc;
|
||||
struct spdk_app_opts opts = {};
|
||||
|
||||
/* default value in opts */
|
||||
spdk_app_opts_init(&opts);
|
||||
|
||||
opts.name = "nvmf";
|
||||
opts.config_file = SPDK_NVMF_DEFAULT_CONFIG;
|
||||
|
||||
while ((ch = getopt(argc, argv, "c:de:i:l:m:n:p:qs:t:DH")) != -1) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
opts.enable_coredump = false;
|
||||
break;
|
||||
case 'c':
|
||||
opts.config_file = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
opts.instance_id = atoi(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
opts.log_facility = optarg;
|
||||
break;
|
||||
case 't':
|
||||
rc = spdk_log_set_trace_flag(optarg);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "unknown flag\n");
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#ifndef DEBUG
|
||||
fprintf(stderr, "%s must be rebuilt with CONFIG_DEBUG=y for -t flag.\n",
|
||||
argv[0]);
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
break;
|
||||
case 'm':
|
||||
opts.reactor_mask = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
opts.dpdk_mem_channel = atoi(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
opts.dpdk_master_core = atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
opts.dpdk_mem_size = atoi(optarg);
|
||||
break;
|
||||
case 'e':
|
||||
opts.tpoint_group_mask = optarg;
|
||||
break;
|
||||
case 'q':
|
||||
spdk_g_notice_stderr_flag = 0;
|
||||
break;
|
||||
case 'D':
|
||||
case 'H':
|
||||
default:
|
||||
usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
if (spdk_g_notice_stderr_flag == 1 &&
|
||||
isatty(STDERR_FILENO) &&
|
||||
!strncmp(ttyname(STDERR_FILENO), "/dev/tty", strlen("/dev/tty"))) {
|
||||
printf("Warning: printing stderr to console terminal without -q option specified.\n");
|
||||
printf("Suggest using -q to disable logging to stderr and monitor syslog, or\n");
|
||||
printf("redirect stderr to a file.\n");
|
||||
printf("(Delaying for 10 seconds...)\n");
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
spdk_init_dpdk(&opts);
|
||||
printf("Total cores available: %d\n", rte_lcore_count());
|
||||
|
||||
opts.shutdown_cb = spdk_nvmf_shutdown_cb;
|
||||
opts.start_fn = spdk_nvmf_startup;
|
||||
spdk_app_init(&opts);
|
||||
|
||||
/* Blocks until the application is exiting */
|
||||
rc = spdk_app_start(spdk_nvmf_startup, NULL, NULL);
|
||||
|
||||
spdk_app_fini();
|
||||
|
||||
if (spdk_nvmf_check_pools(&g_nvmf_tgt) != 0) {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
134
etc/spdk/nvmf.conf.in
Normal file
134
etc/spdk/nvmf.conf.in
Normal file
@ -0,0 +1,134 @@
|
||||
# nvmf target configuration file
|
||||
#
|
||||
# Please write all parameters using ASCII.
|
||||
# The parameter must be quoted if it includes whitespace.
|
||||
#
|
||||
# Configuration syntax:
|
||||
# Spaces at head of line are deleted, other spaces are as separator
|
||||
# Lines starting with '#' are comments and not evaluated.
|
||||
# Lines ending with '\' are concatenated with the next line.
|
||||
# Bracketed keys are section keys grouping the following value keys.
|
||||
# Number of section key is used as a tag number.
|
||||
# Ex. [TargetNode1] = TargetNode section key with tag number 1
|
||||
[Global]
|
||||
Comment "Global section"
|
||||
|
||||
# Users can restrict work items to only run on certain cores by
|
||||
# specifying a ReactorMask. Default ReactorMask mask is defined as
|
||||
# -c option in the 'ealargs' setting at beginning of file nvmf_tgt.c.
|
||||
#ReactorMask 0x00FF
|
||||
|
||||
# Tracepoint group mask for spdk trace buffers
|
||||
# Default: 0x0 (all tracepoint groups disabled)
|
||||
# Set to 0xFFFFFFFFFFFFFFFF to enable all tracepoint groups.
|
||||
#TpointGroupMask 0x0
|
||||
|
||||
# syslog facility
|
||||
LogFacility "local7"
|
||||
|
||||
[Rpc]
|
||||
# Defines whether nvmf will enable configuration via RPC
|
||||
#RpcConfiguration Yes
|
||||
|
||||
# This next section defines NVMf protocol specific global options
|
||||
[Nvmf]
|
||||
# node name (not include optional part)
|
||||
# Users can optionally change this to fit their environment.
|
||||
NodeBase "iqn.2013-06.com.intel.ch.spdk"
|
||||
|
||||
# files
|
||||
AuthFile /usr/local/etc/nvmf/auth.conf
|
||||
|
||||
# Set the optional in-capsule data byte length for I/O queue capsule size.
|
||||
# Accepted values must be divisible by 16 and less than or equal to
|
||||
# the default maximum transfer length NVMF_MAX_RECV_DATA_TRANSFER_SIZE.
|
||||
# A minimum recommended value of 1024 bytes allows NVMf connect
|
||||
# commands to use in-capsule data. Specifying a value greater than 4096
|
||||
# will allow NVMf write requests <= 4096 in length to use in-capsule
|
||||
# immediate data and bypass the need to perfrom an rdma_read operation
|
||||
# to pull the data from the host.
|
||||
MaxInCapsuleData 1024
|
||||
|
||||
# Set the maximum number of NVMf logical controller sessions allowed
|
||||
# for each subsystem provisioned below. The default value (1) is used if
|
||||
# not set here.
|
||||
#MaxSessionsPerSubsystem 1
|
||||
|
||||
# Set the maximum number of NVMf per-controller connections [admin_q + io_q(s)]
|
||||
MaxConnectionsPerSession 4
|
||||
|
||||
# Set the global default maximum queue depth to a value less than the
|
||||
# default (128). This value used for initial global pool allocation of
|
||||
# QP Rx/Tx descriptors and staging buffers. The actual queue depth
|
||||
# used is negotiated during connection establishment, the remote
|
||||
# initiator having the opportunity to specify a smaller value.
|
||||
#MaxQueueDepth 128
|
||||
|
||||
# Users must change the Port section(s) to match the IP addresses
|
||||
# for their environment.
|
||||
# Port sections define which fabric network ports the NVMf server
|
||||
# will use to listen and accept incoming connections. A Port is
|
||||
# also used to control which ports will be used for each individual
|
||||
# NVM subsystem controller session, providing a means to distribute NVMf
|
||||
# traffic across all network ports.
|
||||
[Port1]
|
||||
FabricIntf 15.15.15.2:7174
|
||||
|
||||
[Port2]
|
||||
FabricIntf 192.168.2.21:7174
|
||||
|
||||
# Users must change the InitiatorGroup section(s) to match the IP
|
||||
# addresses and initiator configuration in their environment.
|
||||
# Netmask can be used to specify a single IP address or a range of IP addresses
|
||||
# Netmask 192.168.1.20 <== single IP address
|
||||
# Netmask 192.168.1.0/24 <== IP range 192.168.1.*
|
||||
[InitiatorGroup1]
|
||||
Netmask 15.15.15.0/24
|
||||
|
||||
[InitiatorGroup2]
|
||||
Netmask 192.168.2.0/24
|
||||
|
||||
# NVMe Device Whitelist
|
||||
# Users may specify which NVMe devices to claim by their PCI
|
||||
# domain, bus, device, and function. The format is dddd:bb:dd.f, which is
|
||||
# the same format displayed by lspci or in /sys/bus/pci/devices. The second
|
||||
# argument is a "name" for the device that can be anything. The name
|
||||
# is referenced later in the SubsystemGroup section.
|
||||
#
|
||||
# Alternatively, the user can specify ClaimAllDevices. All
|
||||
# NVMe devices will be claimed and named Nvme0, Nvme1, etc.
|
||||
[Nvme]
|
||||
BDF 0000:00:00.0 Nvme0
|
||||
BDF 0000:01:00.0 Nvme1
|
||||
# ClaimAllDevices Yes
|
||||
|
||||
# Users should change the NVMfSubsystem section(s) below to define the
|
||||
# set of local NVMe resources that will be accessible by specific groups
|
||||
# of remote initiators. These mappings will be inspected to approve
|
||||
# remote fabric transport and NVMf protocol connection requests.
|
||||
#
|
||||
# Each approved NVMf connection represents a specific virtual controller
|
||||
# session within the NVMf subsystem. Any such session is allowed access
|
||||
# to all NVMe namespaces within the subsystem.
|
||||
#
|
||||
# SubsystemName, Mapping, Controller0 are minimum required
|
||||
# The SubsystemName is concatenated with NodeBase above to form the NVMf
|
||||
# subsystem NQN that will be used by remote initiator to identify the
|
||||
# target subsystem for connection.
|
||||
# The Mapping defines the local fabric network port to be used by remote
|
||||
# connecting initiator. Multiple mappings can be used to permit shared
|
||||
# access to the same subsystem.
|
||||
# Each Controller identifies a specific HW device from the Nvme whitelist
|
||||
# section above.
|
||||
[SubsystemGroup1]
|
||||
SubsystemName cnode1
|
||||
Mapping Port1 InitiatorGroup1
|
||||
# Using NVME 0 namespace 1
|
||||
Controller0 Nvme0
|
||||
|
||||
[SubsystemGroup2]
|
||||
SubsystemName cnode2
|
||||
Mapping Port2 InitiatorGroup2
|
||||
# Using NVME 1 namespace 1
|
||||
Controller0 Nvme1
|
||||
|
555
include/spdk/nvmf_spec.h
Normal file
555
include/spdk/nvmf_spec.h
Normal file
@ -0,0 +1,555 @@
|
||||
/*-
|
||||
* 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 <stdint.h>
|
||||
|
||||
#include "spdk/assert.h"
|
||||
#include "spdk/nvme_spec.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct spdk_nvmf_capsule_cmd {
|
||||
uint8_t opcode;
|
||||
uint8_t reserved1;
|
||||
uint16_t cid;
|
||||
uint8_t fctype;
|
||||
uint8_t reserved2[35];
|
||||
uint8_t fabric_specific[24];
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_capsule_cmd) == 64, "Incorrect size");
|
||||
|
||||
struct spdk_nvmf_capsule_rsp {
|
||||
uint8_t fabric_specific[8];
|
||||
uint16_t sqhd;
|
||||
uint8_t reserved1[2];
|
||||
uint16_t cid;
|
||||
struct spdk_nvme_status status;
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_capsule_rsp) == 16, "Incorrect size");
|
||||
|
||||
/* Fabric Command Set */
|
||||
#define SPDK_NVMF_FABRIC_OPCODE 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,
|
||||
};
|
||||
|
||||
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_recv_rsp {
|
||||
uint8_t reserved0[8];
|
||||
uint16_t sqhd;
|
||||
uint8_t reserved1[2];
|
||||
uint16_t cid;
|
||||
struct spdk_nvme_status status;
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fabric_auth_recv_rsp) == 16, "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_auth_send_rsp {
|
||||
uint8_t reserved0[8];
|
||||
uint16_t sqhd;
|
||||
uint8_t reserved1[2];
|
||||
uint16_t cid;
|
||||
struct spdk_nvme_status status;
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fabric_auth_send_rsp) == 16, "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");
|
||||
|
||||
#define SPDK_NVMF_CONNECT_ATTR_PRIORITY_URGENT 0x00
|
||||
#define SPDK_NVMF_CONNECT_ATTR_PRIORITY_HIGH 0x01
|
||||
#define SPDK_NVMF_CONNECT_ATTR_PRIORITY_MEDIUM 0x02
|
||||
#define SPDK_NVMF_CONNECT_ATTR_PRIORITY_LOW 0x03
|
||||
#define SPDK_NVMF_CONNECT_ATTR_RESERVED 0xFC
|
||||
|
||||
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_CAP_OFST 0x0
|
||||
#define SPDK_NVMF_PROP_VS_OFST 0x8
|
||||
#define SPDK_NVMF_PROP_INTMS_OFST 0xC
|
||||
#define SPDK_NVMF_PROP_INTMC_OFST 0x10
|
||||
#define SPDK_NVMF_PROP_CC_OFST 0x14
|
||||
#define SPDK_NVMF_PROP_CSTS_OFST 0x1C
|
||||
#define SPDK_NVMF_PROP_NSSR_OFST 0x20
|
||||
#define SPDK_NVMF_PROP_AQA_OFST 0x24
|
||||
#define SPDK_NVMF_PROP_ASQ_OFST 0x28
|
||||
#define SPDK_NVMF_PROP_ACQ_OFST 0x30
|
||||
#define SPDK_NVMF_PROP_CMBLOC_OFST 0x38
|
||||
#define SPDK_NVMF_PROP_CMBSZ_OFST 0x3C
|
||||
|
||||
#define SPDK_NVMF_PROP_CAP_LEN 0x8
|
||||
#define SPDK_NVMF_PROP_VS_LEN 0x4
|
||||
#define SPDK_NVMF_PROP_INTMS_LEN 0x4
|
||||
#define SPDK_NVMF_PROP_INTMC_LEN 0x4
|
||||
#define SPDK_NVMF_PROP_CC_LEN 0x4
|
||||
#define SPDK_NVMF_PROP_CSTS_LEN 0x4
|
||||
#define SPDK_NVMF_PROP_NSSR_LEN 0x4
|
||||
#define SPDK_NVMF_PROP_AQA_LEN 0x4
|
||||
#define SPDK_NVMF_PROP_ASQ_LEN 0x8
|
||||
#define SPDK_NVMF_PROP_ACQ_LEN 0x8
|
||||
#define SPDK_NVMF_PROP_CMBLOC_LEN 0x4
|
||||
#define SPDK_NVMF_PROP_CMBSZ_LEN 0x4
|
||||
|
||||
union spdk_nvmf_property_size {
|
||||
uint32_t raw;
|
||||
struct {
|
||||
uint32_t reserved : 16;
|
||||
|
||||
/** property address space size */
|
||||
uint32_t size : 16;
|
||||
} bits;
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(union spdk_nvmf_property_size) == 4, "Incorrect size");
|
||||
|
||||
union spdk_nvmf_capsule_attr_lo {
|
||||
uint32_t raw;
|
||||
struct {
|
||||
/** maximum response capsule size */
|
||||
uint32_t rspsz : 16;
|
||||
|
||||
/** maximum command capsule size */
|
||||
uint32_t cmdsz : 16;
|
||||
} bits;
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(union spdk_nvmf_capsule_attr_lo) == 4, "Incorrect size");
|
||||
|
||||
union spdk_nvmf_capsule_attr_hi {
|
||||
uint32_t raw;
|
||||
struct {
|
||||
/** support capsule alignment in response capsules */
|
||||
uint32_t reserved : 26;
|
||||
|
||||
/** support capsule alignment in response capsules */
|
||||
uint32_t cairsp : 1;
|
||||
|
||||
/** support capsule alignment in command capsules */
|
||||
uint32_t caicmd : 1;
|
||||
|
||||
/** support capsule metadata in response capsules */
|
||||
uint32_t cmirsp : 1;
|
||||
|
||||
/** support capsule metadata in command capsules */
|
||||
uint32_t cmicmd : 1;
|
||||
|
||||
/** support capsule data in response capsules */
|
||||
uint32_t cdirsp : 1;
|
||||
|
||||
/** support capsule data in command capsules */
|
||||
uint32_t cdicmd : 1;
|
||||
} bits;
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(union spdk_nvmf_capsule_attr_hi) == 4, "Incorrect size");
|
||||
|
||||
struct spdk_nvmf_ctrlr_properties {
|
||||
union spdk_nvme_cap_lo_register cap_lo;
|
||||
union spdk_nvme_cap_hi_register cap_hi;
|
||||
|
||||
uint32_t vs;
|
||||
uint32_t intms;
|
||||
uint32_t intmc;
|
||||
|
||||
union spdk_nvme_cc_register cc;
|
||||
|
||||
uint32_t reserved1;
|
||||
union spdk_nvme_csts_register csts;
|
||||
uint32_t nssr;
|
||||
|
||||
union spdk_nvme_aqa_register aqa;
|
||||
|
||||
uint64_t asq;
|
||||
uint64_t acq;
|
||||
|
||||
uint32_t cmbloc;
|
||||
uint32_t cmbsz;
|
||||
|
||||
uint8_t reserved2[0xEC0];
|
||||
uint8_t reserved3[0x100];
|
||||
union spdk_nvmf_property_size propsz;
|
||||
uint32_t reserved4;
|
||||
union spdk_nvmf_capsule_attr_lo capattr_lo;
|
||||
union spdk_nvmf_capsule_attr_hi capattr_hi;
|
||||
uint8_t reserved5[0x2F0];
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_ctrlr_properties) == 4864, "Incorrect size");
|
||||
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_CAP_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, cap_lo),
|
||||
"Incorrect register offset");
|
||||
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_VS_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, vs),
|
||||
"Incorrect register offset");
|
||||
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_INTMS_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, intms),
|
||||
"Incorrect register offset");
|
||||
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_INTMC_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, intmc),
|
||||
"Incorrect register offset");
|
||||
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_CC_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, cc),
|
||||
"Incorrect register offset");
|
||||
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_CSTS_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, csts),
|
||||
"Incorrect register offset");
|
||||
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_NSSR_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, nssr),
|
||||
"Incorrect register offset");
|
||||
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_AQA_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, aqa),
|
||||
"Incorrect register offset");
|
||||
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_ASQ_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, asq),
|
||||
"Incorrect register offset");
|
||||
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_ACQ_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, acq),
|
||||
"Incorrect register offset");
|
||||
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_CMBLOC_OFST == offsetof(struct spdk_nvmf_ctrlr_properties,
|
||||
cmbloc),
|
||||
"Incorrect property offset");
|
||||
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_CMBSZ_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, cmbsz),
|
||||
"Incorrect property offset");
|
||||
|
||||
struct spdk_nvmf_fabric_prop_get_cmd {
|
||||
uint8_t opcode;
|
||||
uint8_t reserved1;
|
||||
uint16_t cid;
|
||||
uint8_t fctype;
|
||||
uint8_t reserved2[35];
|
||||
uint8_t 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];
|
||||
uint8_t 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");
|
||||
|
||||
struct spdk_nvmf_fabric_prop_set_rsp {
|
||||
uint8_t reserved0[8];
|
||||
uint16_t sqhd;
|
||||
uint16_t reserved1;
|
||||
uint16_t cid;
|
||||
struct spdk_nvme_status status;
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fabric_prop_set_rsp) == 16, "Incorrect size");
|
||||
|
||||
/* Overlays on the existing identify controller structure */
|
||||
#define SPDK_NVMF_EXTENDED_CTRLR_DATA_OFFSET 1792
|
||||
struct spdk_nvmf_extended_identify_ctrlr_data {
|
||||
uint32_t ioccsz;
|
||||
uint32_t iorcsz;
|
||||
uint16_t icdoff;
|
||||
uint8_t ctrattr;
|
||||
uint8_t msdbd;
|
||||
uint8_t reserved[244];
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_extended_identify_ctrlr_data) == 256, "Incorrect size");
|
||||
|
||||
#define SPDK_NVMF_CTRLR_MAXCMD_OFFSET 514
|
||||
struct spdk_nvmf_ctrlr_maxcmd {
|
||||
uint16_t maxcmd;
|
||||
};
|
||||
|
||||
#define SPDK_NVMF_CTRLR_KAS_OFFSET 320
|
||||
struct spdk_nvmf_ctrlr_kas {
|
||||
uint16_t kas;
|
||||
};
|
||||
|
||||
struct spdk_nvmf_sgl_support {
|
||||
uint32_t supported : 1;
|
||||
uint32_t reserved1 : 1;
|
||||
uint32_t keyed_sgls : 1;
|
||||
uint32_t reserved2 : 13;
|
||||
uint32_t bit_bucket_descriptor_supported : 1;
|
||||
uint32_t metadata_pointer_supported : 1;
|
||||
uint32_t oversized_sgl_supported : 1;
|
||||
uint32_t single_aligned_sgl_supported : 1;
|
||||
uint32_t address_as_offset_sgl_supported : 1;
|
||||
uint32_t reserved3 : 11;
|
||||
};
|
||||
|
||||
#define SPDK_NVMF_DISCOVERY_NQN "nqn.2014-08.org.nvmexpress.discovery"
|
||||
|
||||
struct spdk_nvmf_discovery_identify_data {
|
||||
uint8_t reserved0[64];
|
||||
uint64_t fr;
|
||||
uint8_t reserved1[5];
|
||||
uint8_t mdts;
|
||||
uint16_t cntlid;
|
||||
uint32_t ver;
|
||||
uint8_t reserved2[177];
|
||||
uint8_t lpa;
|
||||
uint8_t elpe;
|
||||
uint8_t reserved3[505];
|
||||
uint8_t subnqn[256];
|
||||
uint8_t discovery[1024];
|
||||
uint8_t reserved4[1024];
|
||||
uint8_t vs[1024];
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_discovery_identify_data) == 4096, "Incorrect size");
|
||||
|
||||
#define SPDK_NVMF_LOG_PAGE_DISCOVERY 0x70
|
||||
|
||||
struct spdk_nvmf_discovery_log_page_entry {
|
||||
uint8_t trtype; /* transport type */
|
||||
uint8_t adrfam; /* address family */
|
||||
uint8_t subtype;
|
||||
uint8_t treq;
|
||||
uint16_t portid;
|
||||
uint16_t cntlid;
|
||||
uint8_t reserved0[24];
|
||||
uint8_t trsvcid[32];
|
||||
uint8_t reserved1[192];
|
||||
uint8_t subnqn[256];
|
||||
uint8_t traddr[256];
|
||||
uint8_t tsas[256];
|
||||
};
|
||||
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");
|
||||
|
||||
/* Add an additional type of SGL */
|
||||
#define SPDK_NVME_SGL_TYPE_KEYED_DATA_BLOCK 0x4
|
||||
|
||||
/* Further, add SGL subtypes */
|
||||
#define SPDK_NVME_SGL_SUBTYPE_ADDRESS 0x0
|
||||
#define SPDK_NVME_SGL_SUBTYPE_OFFSET 0x1
|
||||
|
||||
struct spdk_nvmf_keyed_sgl_descriptor {
|
||||
uint64_t address;
|
||||
uint64_t length : 24;
|
||||
uint64_t key : 32;
|
||||
uint64_t subtype : 4;
|
||||
uint64_t type : 4; /* SPDK_NVME_SGL_TYPE_KEYED_DATA_BLOCK */
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_keyed_sgl_descriptor) == 16, "Incorrect size");
|
||||
|
||||
/* Add a new admin command */
|
||||
#define SPDK_NVME_OPC_KEEP_ALIVE 0x18
|
||||
|
||||
/* Add new status codes */
|
||||
#define SPDK_NVME_SC_SGL_OFFSET_INVALID 0x16
|
||||
#define SPDK_NVME_SC_SGL_SUBTYPE_INVALID 0x17
|
||||
#define SPDK_NVME_SC_HOSTID_INCONSISTENT 0x18
|
||||
#define SPDK_NVME_SC_KEEP_ALIVE_EXPIRED 0x19
|
||||
#define SPDK_NVME_SC_KEEP_ALIVE_TIMEOUT_INVALID 0x1A
|
||||
|
||||
/* RDMA Fabric specific definitions below */
|
||||
|
||||
#define SPDK_NVME_SGL_SUBTYPE_INVALIDATE_KEY 0xF
|
||||
|
||||
struct spdk_nvmf_rdma_transport_specific_address {
|
||||
uint8_t rdma_qptype; /* see nvmf_rdma_qp_service_types */
|
||||
uint8_t rdma_prtype; /* see nvmf_rdma_provider_types */
|
||||
uint8_t rdma_cms; /* nvmf_rdma_connection_mgmt_service */
|
||||
uint8_t reserved0[5];
|
||||
uint16_t rdma_pkey;
|
||||
uint8_t reserved2[246];
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_rdma_transport_specific_address) == 256,
|
||||
"Incorrect size");
|
||||
|
||||
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 */
|
||||
uint8_t reserved[24];
|
||||
};
|
||||
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 */
|
||||
struct spdk_nvme_status 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_errors {
|
||||
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__ */
|
@ -36,6 +36,8 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
|
||||
DIRS-y += conf cunit event json jsonrpc log memory trace util nvme ioat
|
||||
|
||||
DIRS-$(CONFIG_NVMF) += nvmf
|
||||
|
||||
.PHONY: all clean $(DIRS-y)
|
||||
|
||||
all: $(DIRS-y)
|
||||
|
43
lib/nvmf/Makefile
Normal file
43
lib/nvmf/Makefile
Normal file
@ -0,0 +1,43 @@
|
||||
#
|
||||
# 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)/../..)
|
||||
|
||||
CFLAGS += $(DPDK_INC)
|
||||
LIBNAME = nvmf
|
||||
C_SRCS = nvmf_admin_cmd.c nvmf_io_cmd.c nvmf.c \
|
||||
rdma.c port.c conn.c controller.c \
|
||||
init_grp.c subsystem_grp.c conf.c \
|
||||
framework.c session.c
|
||||
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk
|
352
lib/nvmf/conf.c
Normal file
352
lib/nvmf/conf.c
Normal file
@ -0,0 +1,352 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "conf.h"
|
||||
#include "init_grp.h"
|
||||
#include "nvmf.h"
|
||||
#include "port.h"
|
||||
#include "spdk/conf.h"
|
||||
#include "spdk/log.h"
|
||||
|
||||
#define PORTNUMSTRLEN 32
|
||||
|
||||
static int
|
||||
spdk_nvmf_parse_nvmf_tgt(void)
|
||||
{
|
||||
struct spdk_conf_section *sp;
|
||||
char *authfile;
|
||||
char *nodebase;
|
||||
int max_in_capsule_data;
|
||||
int max_sessions_per_subsystem;
|
||||
int max_queue_depth;
|
||||
int max_conn_per_sess;
|
||||
int max_recv_seg_len;
|
||||
int listen_port;
|
||||
int rc;
|
||||
|
||||
sp = spdk_conf_find_section(NULL, "Nvmf");
|
||||
if (sp == NULL) {
|
||||
SPDK_ERRLOG("No Nvmf section in configuration file.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
authfile = spdk_conf_section_get_val(sp, "AuthFile");
|
||||
if (authfile == NULL) {
|
||||
authfile = SPDK_NVMF_DEFAULT_AUTHFILE;
|
||||
}
|
||||
|
||||
nodebase = spdk_conf_section_get_val(sp, "NodeBase");
|
||||
if (nodebase == NULL) {
|
||||
nodebase = SPDK_NVMF_DEFAULT_NODEBASE;
|
||||
}
|
||||
|
||||
max_in_capsule_data = spdk_conf_section_get_intval(sp, "MaxInCapsuleData");
|
||||
if (max_in_capsule_data < 0) {
|
||||
max_in_capsule_data = SPDK_NVMF_DEFAULT_IN_CAPSULE_DATA_SIZE;
|
||||
}
|
||||
|
||||
max_sessions_per_subsystem = spdk_conf_section_get_intval(sp, "MaxSessionsPerSubsystem");
|
||||
if (max_sessions_per_subsystem < 0) {
|
||||
max_sessions_per_subsystem = SPDK_NVMF_DEFAULT_MAX_SESSIONS_PER_SUBSYSTEM;
|
||||
}
|
||||
|
||||
max_queue_depth = spdk_conf_section_get_intval(sp, "MaxQueueDepth");
|
||||
if (max_queue_depth < 0) {
|
||||
max_queue_depth = SPDK_NVMF_DEFAULT_MAX_QUEUE_DEPTH;
|
||||
}
|
||||
|
||||
max_conn_per_sess = spdk_conf_section_get_intval(sp, "MaxConnectionsPerSession");
|
||||
if (max_conn_per_sess < 0) {
|
||||
max_conn_per_sess = SPDK_NVMF_DEFAULT_MAX_CONNECTIONS_PER_SESSION;
|
||||
}
|
||||
|
||||
max_recv_seg_len = SPDK_NVMF_MAX_RECV_DATA_TRANSFER_SIZE;
|
||||
listen_port = SPDK_NVMF_DEFAULT_SIN_PORT;
|
||||
|
||||
rc = nvmf_tgt_init(authfile, nodebase, max_in_capsule_data, max_sessions_per_subsystem,
|
||||
max_queue_depth, max_conn_per_sess, max_recv_seg_len, listen_port);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_nvmf_parse_addr(char *listen_addr, char **host, char **port)
|
||||
{
|
||||
int n, len;
|
||||
const char *p, *q;
|
||||
|
||||
if (listen_addr == NULL) {
|
||||
SPDK_ERRLOG("Invalid listen addr for Fabric Interface (NULL)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*host = NULL;
|
||||
*port = NULL;
|
||||
|
||||
if (listen_addr[0] == '[') {
|
||||
/* IPv6 */
|
||||
p = strchr(listen_addr + 1, ']');
|
||||
if (p == NULL) {
|
||||
return -1;
|
||||
}
|
||||
p++;
|
||||
n = p - listen_addr;
|
||||
*host = malloc(n + 1);
|
||||
if (!*host) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(*host, listen_addr, n);
|
||||
(*host)[n] = '\0';
|
||||
if (p[0] == '\0') {
|
||||
*port = malloc(PORTNUMSTRLEN);
|
||||
if (!*port) {
|
||||
free(*host);
|
||||
return -1;
|
||||
}
|
||||
snprintf(*port, PORTNUMSTRLEN, "%d", SPDK_NVMF_DEFAULT_SIN_PORT);
|
||||
} else {
|
||||
if (p[0] != ':') {
|
||||
free(*host);
|
||||
return -1;
|
||||
}
|
||||
q = strchr(listen_addr, '@');
|
||||
if (q == NULL) {
|
||||
q = listen_addr + strlen(listen_addr);
|
||||
}
|
||||
len = q - p - 1;
|
||||
|
||||
*port = malloc(len + 1);
|
||||
if (!*port) {
|
||||
free(*host);
|
||||
return -1;
|
||||
}
|
||||
memset(*port, 0, len + 1);
|
||||
memcpy(*port, p + 1, len);
|
||||
}
|
||||
} else {
|
||||
/* IPv4 */
|
||||
p = strchr(listen_addr, ':');
|
||||
if (p == NULL) {
|
||||
p = listen_addr + strlen(listen_addr);
|
||||
}
|
||||
n = p - listen_addr;
|
||||
*host = malloc(n + 1);
|
||||
if (!*host) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(*host, listen_addr, n);
|
||||
(*host)[n] = '\0';
|
||||
if (p[0] == '\0') {
|
||||
*port = malloc(PORTNUMSTRLEN);
|
||||
if (!*port) {
|
||||
free(*host);
|
||||
return -1;
|
||||
}
|
||||
snprintf(*port, PORTNUMSTRLEN, "%d", SPDK_NVMF_DEFAULT_SIN_PORT);
|
||||
} else {
|
||||
if (p[0] != ':') {
|
||||
free(*host);
|
||||
return -1;
|
||||
}
|
||||
q = strchr(listen_addr, '@');
|
||||
if (q == NULL) {
|
||||
q = listen_addr + strlen(listen_addr);
|
||||
}
|
||||
|
||||
if (q == p) {
|
||||
free(*host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = q - p - 1;
|
||||
*port = malloc(len + 1);
|
||||
if (!*port) {
|
||||
free(*host);
|
||||
return -1;
|
||||
}
|
||||
memset(*port, 0, len + 1);
|
||||
memcpy(*port, p + 1, len);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_nvmf_parse_port(struct spdk_conf_section *sp)
|
||||
{
|
||||
struct spdk_nvmf_port *port;
|
||||
struct spdk_nvmf_fabric_intf *fabric_intf;
|
||||
char *listen_addr, *host, *listen_port;
|
||||
int i = 0, rc = 0;
|
||||
|
||||
/* Create the Subsystem Port */
|
||||
port = spdk_nvmf_port_create(sp->num);
|
||||
if (!port) {
|
||||
SPDK_ERRLOG("Port create failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Loop over the fabric interfaces and add them to the port */
|
||||
for (i = 0; ; i++) {
|
||||
listen_addr = spdk_conf_section_get_nmval(sp, "FabricIntf", i, 1);
|
||||
if (listen_addr == NULL) {
|
||||
break;
|
||||
}
|
||||
rc = spdk_nvmf_parse_addr(listen_addr, &host, &listen_port);
|
||||
if (rc < 0) {
|
||||
continue;
|
||||
}
|
||||
fabric_intf = spdk_nvmf_fabric_intf_create(host, listen_port);
|
||||
if (!fabric_intf) {
|
||||
continue;
|
||||
}
|
||||
|
||||
spdk_nvmf_port_add_fabric_intf(port, fabric_intf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_nvmf_parse_ports(void)
|
||||
{
|
||||
int rc = 0;
|
||||
struct spdk_conf_section *sp;
|
||||
|
||||
sp = spdk_conf_first_section(NULL);
|
||||
while (sp != NULL) {
|
||||
if (spdk_conf_section_match_prefix(sp, "Port")) {
|
||||
rc = spdk_nvmf_parse_port(sp);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
sp = spdk_conf_next_section(sp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_nvmf_parse_init_grp(struct spdk_conf_section *sp)
|
||||
{
|
||||
int i;
|
||||
const char *mask;
|
||||
char **netmasks;
|
||||
int num_netmasks;
|
||||
struct spdk_nvmf_init_grp *init_grp;
|
||||
|
||||
|
||||
for (num_netmasks = 0; ; num_netmasks++) {
|
||||
mask = spdk_conf_section_get_nval(sp, "Netmask", num_netmasks);
|
||||
if (mask == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_netmasks == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
netmasks = calloc(num_netmasks, sizeof(char *));
|
||||
if (!netmasks) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_netmasks; i++) {
|
||||
mask = spdk_conf_section_get_nval(sp, "Netmask", i);
|
||||
netmasks[i] = strdup(mask);
|
||||
if (!netmasks[i]) {
|
||||
free(netmasks);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
init_grp = spdk_nvmf_init_grp_create(sp->num, num_netmasks, netmasks);
|
||||
|
||||
if (!init_grp) {
|
||||
free(netmasks);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_nvmf_parse_init_grps(void)
|
||||
{
|
||||
int rc = 0;
|
||||
struct spdk_conf_section *sp;
|
||||
|
||||
sp = spdk_conf_first_section(NULL);
|
||||
while (sp != NULL) {
|
||||
if (spdk_conf_section_match_prefix(sp, "InitiatorGroup")) {
|
||||
rc = spdk_nvmf_parse_init_grp(sp);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
sp = spdk_conf_next_section(sp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvmf_parse_conf(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* NVMf section */
|
||||
rc = spdk_nvmf_parse_nvmf_tgt();
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Port sections */
|
||||
rc = spdk_nvmf_parse_ports();
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Initiator Group sections */
|
||||
rc = spdk_nvmf_parse_init_grps();
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
40
lib/nvmf/conf.h
Normal file
40
lib/nvmf/conf.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*-
|
||||
* 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 NVMF_CONF_H
|
||||
#define NVMF_CONF_H
|
||||
|
||||
int
|
||||
spdk_nvmf_parse_conf(void);
|
||||
|
||||
#endif
|
1318
lib/nvmf/conn.c
Normal file
1318
lib/nvmf/conn.c
Normal file
File diff suppressed because it is too large
Load Diff
124
lib/nvmf/conn.h
Normal file
124
lib/nvmf/conn.h
Normal file
@ -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 NVMF_FABRIC_INTF_H
|
||||
#define NVMF_FABRIC_INTF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "spdk/event.h"
|
||||
#include "nvmf_internal.h"
|
||||
#include "spdk/queue.h"
|
||||
|
||||
/* NVMF Connection States */
|
||||
enum nvmf_cstate {
|
||||
NVMF_CSTATE_INIT,
|
||||
NVMF_CSTATE_ACCEPT,
|
||||
NVMF_CSTATE_CONNECTED,
|
||||
NVMF_CSTATE_TERMINATING,
|
||||
NVMF_CSTATE_DISCONNECTED,
|
||||
};
|
||||
|
||||
/*
|
||||
RDMA Connection Resouce Defaults
|
||||
*/
|
||||
#define NVMF_DEFAULT_TX_SGE 1
|
||||
#define NVMF_DEFAULT_RX_SGE 2
|
||||
|
||||
/* RDMA transport connection states */
|
||||
enum conn_state {
|
||||
CONN_STATE_INVALID = 0,
|
||||
CONN_STATE_RUNNING = 1,
|
||||
CONN_STATE_FABRIC_DISCONNECT = 2,
|
||||
CONN_STATE_OVERFLOW = 3,
|
||||
CONN_STATE_EXITING = 4,
|
||||
};
|
||||
|
||||
enum conn_type {
|
||||
CONN_TYPE_AQ = 0,
|
||||
CONN_TYPE_IOQ = 1,
|
||||
};
|
||||
|
||||
struct spdk_nvmf_conn {
|
||||
uint32_t is_valid;
|
||||
|
||||
struct nvmf_session *sess;
|
||||
|
||||
|
||||
/*
|
||||
* values saved from fabric connect and private data
|
||||
*/
|
||||
uint8_t responder_resources;
|
||||
uint8_t initiator_depth;
|
||||
uint16_t sq_depth;
|
||||
uint16_t cq_depth;
|
||||
uint16_t qid;
|
||||
uint16_t cntlid;
|
||||
|
||||
enum conn_type type;
|
||||
volatile enum conn_state state;
|
||||
|
||||
uint16_t sq_head;
|
||||
uint16_t sq_tail;
|
||||
|
||||
struct rdma_cm_id *cm_id;
|
||||
struct ibv_context *ctx;
|
||||
struct ibv_comp_channel *comp_channel;
|
||||
struct ibv_pd *pd;
|
||||
struct ibv_cq *cq;
|
||||
struct ibv_qp *qp;
|
||||
|
||||
uint8_t pending_rdma_read_count;
|
||||
STAILQ_HEAD(qp_pending_desc, nvme_qp_tx_desc) qp_pending_desc;
|
||||
|
||||
STAILQ_HEAD(qp_rx_desc, nvme_qp_rx_desc) qp_rx_desc;
|
||||
STAILQ_HEAD(qp_tx_desc, nvme_qp_tx_desc) qp_tx_desc;
|
||||
STAILQ_HEAD(qp_tx_active_desc, nvme_qp_tx_desc) qp_tx_active_desc;
|
||||
|
||||
TAILQ_ENTRY(spdk_nvmf_conn) link;
|
||||
struct spdk_poller poller;
|
||||
};
|
||||
|
||||
int spdk_initialize_nvmf_conns(int max_connections);
|
||||
|
||||
void spdk_shutdown_nvmf_conns(void);
|
||||
|
||||
struct spdk_nvmf_conn *
|
||||
spdk_nvmf_allocate_conn(void);
|
||||
|
||||
int spdk_nvmf_startup_conn(struct spdk_nvmf_conn *conn);
|
||||
|
||||
struct spdk_nvmf_conn *
|
||||
spdk_find_nvmf_conn_by_cm_id(struct rdma_cm_id *cm_id);
|
||||
|
||||
#endif /* NVMF_FABRIC_INTF_H */
|
315
lib/nvmf/controller.c
Normal file
315
lib/nvmf/controller.c
Normal file
@ -0,0 +1,315 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "controller.h"
|
||||
#include "spdk/conf.h"
|
||||
#include "spdk/nvme.h"
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/trace.h"
|
||||
|
||||
static TAILQ_HEAD(, spdk_nvmf_ctrlr) g_ctrlrs = TAILQ_HEAD_INITIALIZER(g_ctrlrs);
|
||||
|
||||
#define SPDK_NVMF_MAX_NVME_DEVICES 64
|
||||
|
||||
struct nvme_bdf_whitelist {
|
||||
uint16_t domain;
|
||||
uint8_t bus;
|
||||
uint8_t dev;
|
||||
uint8_t func;
|
||||
char name[MAX_NVME_NAME_LENGTH];
|
||||
};
|
||||
|
||||
struct spdk_nvmf_probe_ctx {
|
||||
bool claim_all;
|
||||
int whitelist_count;
|
||||
struct nvme_bdf_whitelist whitelist[SPDK_NVMF_MAX_NVME_DEVICES];
|
||||
};
|
||||
|
||||
static void
|
||||
spdk_nvmf_complete_ctrlr_aer(struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_cpl *cpl)
|
||||
{
|
||||
/* TODO: Temporarily disabled during refactoring. */
|
||||
#if 0
|
||||
struct spdk_nvmf_subsystem *subsystem;
|
||||
struct nvmf_session *sess;
|
||||
int i;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Scan the whitelist for any subsystems claiming namespaces
|
||||
* associated with this NVMe controller.
|
||||
*/
|
||||
for (i = 0; i < g_num_nvme_devices; i++) {
|
||||
if (g_whitelist[i].ctrlr == ctrlr &&
|
||||
g_whitelist[i].subsystem != NULL) {
|
||||
|
||||
subsystem = g_whitelist[i].subsystem;
|
||||
TAILQ_FOREACH(sess, &subsystem->sessions, entries) {
|
||||
if (sess->aer_req_state == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Process session AER request, sess %p, req_state %p\n",
|
||||
sess, sess->aer_req_state);
|
||||
nvmf_complete_cmd(sess->aer_req_state, cpl);
|
||||
/* clear this AER from the session */
|
||||
sess->aer_req_state = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
aer_cb(void *arg, const struct spdk_nvme_cpl *cpl)
|
||||
{
|
||||
struct spdk_nvme_ctrlr *ctrlr = arg;
|
||||
|
||||
if (spdk_nvme_cpl_is_error(cpl)) {
|
||||
fprintf(stderr, "Nvme AER failed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " Nvme AER callback, log_page_id %x\n",
|
||||
(cpl->cdw0 & 0xFF0000) >> 16);
|
||||
|
||||
spdk_nvmf_complete_ctrlr_aer(ctrlr, cpl);
|
||||
}
|
||||
|
||||
static struct spdk_nvmf_ctrlr *
|
||||
spdk_nvmf_ctrlr_create(char *name, int domain, int bus, int dev, int func,
|
||||
struct spdk_nvme_ctrlr *ctrlr)
|
||||
{
|
||||
struct spdk_nvmf_ctrlr *nvmf_ctrlr;
|
||||
|
||||
nvmf_ctrlr = calloc(1, sizeof(struct spdk_nvmf_ctrlr));
|
||||
if (nvmf_ctrlr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Found physical NVMe device. Name: %s\n", name);
|
||||
|
||||
nvmf_ctrlr->ctrlr = ctrlr;
|
||||
snprintf(nvmf_ctrlr->name, MAX_NVME_NAME_LENGTH, "%s", name);
|
||||
|
||||
spdk_nvme_ctrlr_register_aer_callback(ctrlr, aer_cb, ctrlr);
|
||||
|
||||
TAILQ_INSERT_HEAD(&g_ctrlrs, nvmf_ctrlr, entry);
|
||||
|
||||
return nvmf_ctrlr;
|
||||
}
|
||||
|
||||
static bool
|
||||
probe_cb(void *cb_ctx, struct spdk_pci_device *dev, struct spdk_nvme_ctrlr_opts *opts)
|
||||
{
|
||||
struct spdk_nvmf_probe_ctx *ctx = cb_ctx;
|
||||
uint16_t found_domain = spdk_pci_device_get_domain(dev);
|
||||
uint8_t found_bus = spdk_pci_device_get_bus(dev);
|
||||
uint8_t found_dev = spdk_pci_device_get_dev(dev);
|
||||
uint8_t found_func = spdk_pci_device_get_func(dev);
|
||||
int i;
|
||||
|
||||
SPDK_NOTICELOG("Probing device %x:%x:%x.%x\n",
|
||||
found_domain, found_bus, found_dev, found_func);
|
||||
|
||||
if (spdk_pci_device_has_non_uio_driver(dev)) {
|
||||
SPDK_NOTICELOG("Skipping device %x:%x:%x.%x because it is bound to the kernel\n",
|
||||
found_domain, found_bus, found_dev, found_func);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctx->claim_all) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (i = 0; i < SPDK_NVMF_MAX_NVME_DEVICES; i++) {
|
||||
if (found_domain == ctx->whitelist[i].domain &&
|
||||
found_bus == ctx->whitelist[i].bus &&
|
||||
found_dev == ctx->whitelist[i].dev &&
|
||||
found_func == ctx->whitelist[i].func) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
attach_cb(void *cb_ctx, struct spdk_pci_device *dev, struct spdk_nvme_ctrlr *ctrlr,
|
||||
const struct spdk_nvme_ctrlr_opts *opts)
|
||||
{
|
||||
struct spdk_nvmf_probe_ctx *ctx = cb_ctx;
|
||||
uint16_t found_domain = spdk_pci_device_get_domain(dev);
|
||||
uint8_t found_bus = spdk_pci_device_get_bus(dev);
|
||||
uint8_t found_dev = spdk_pci_device_get_dev(dev);
|
||||
uint8_t found_func = spdk_pci_device_get_func(dev);
|
||||
int i;
|
||||
|
||||
SPDK_NOTICELOG("Attempting to claim device %x:%x:%x.%x\n",
|
||||
found_domain, found_bus, found_dev, found_func);
|
||||
|
||||
if (ctx->claim_all) {
|
||||
/* If claim_all is true, whitelist_count can be repurposed here safely */
|
||||
char name[64];
|
||||
snprintf(name, 64, "Nvme%d", ctx->whitelist_count);
|
||||
spdk_nvmf_ctrlr_create(name, found_domain, found_bus,
|
||||
found_dev, found_func, ctrlr);
|
||||
ctx->whitelist_count++;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < SPDK_NVMF_MAX_NVME_DEVICES; i++) {
|
||||
if (found_domain == ctx->whitelist[i].domain &&
|
||||
found_bus == ctx->whitelist[i].bus &&
|
||||
found_dev == ctx->whitelist[i].dev &&
|
||||
found_func == ctx->whitelist[i].func) {
|
||||
spdk_nvmf_ctrlr_create(ctx->whitelist[i].name, found_domain, found_bus,
|
||||
found_dev, found_func, ctrlr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvmf_init_nvme(void)
|
||||
{
|
||||
struct spdk_conf_section *sp;
|
||||
struct spdk_nvmf_probe_ctx ctx = { 0 };
|
||||
const char *val;
|
||||
int i, rc;
|
||||
|
||||
SPDK_NOTICELOG("*** Initialize NVMe Devices ***\n");
|
||||
sp = spdk_conf_find_section(NULL, "Nvme");
|
||||
if (sp == NULL) {
|
||||
SPDK_ERRLOG("NVMe device section in config file not found!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
val = spdk_conf_section_get_val(sp, "ClaimAllDevices");
|
||||
if (val != NULL) {
|
||||
if (!strcmp(val, "Yes")) {
|
||||
ctx.claim_all = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx.claim_all) {
|
||||
for (i = 0; ; i++) {
|
||||
unsigned int domain, bus, dev, func;
|
||||
|
||||
val = spdk_conf_section_get_nmval(sp, "BDF", i, 0);
|
||||
if (val == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
rc = sscanf(val, "%x:%x:%x.%x", &domain, &bus, &dev, &func);
|
||||
if (rc != 4) {
|
||||
SPDK_ERRLOG("Invalid format for BDF: %s\n", val);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx.whitelist[ctx.whitelist_count].domain = domain;
|
||||
ctx.whitelist[ctx.whitelist_count].bus = bus;
|
||||
ctx.whitelist[ctx.whitelist_count].dev = dev;
|
||||
ctx.whitelist[ctx.whitelist_count].func = func;
|
||||
|
||||
val = spdk_conf_section_get_nmval(sp, "BDF", i, 1);
|
||||
if (val == NULL) {
|
||||
SPDK_ERRLOG("BDF section with no device name\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(ctx.whitelist[ctx.whitelist_count].name, MAX_NVME_NAME_LENGTH, "%s", val);
|
||||
|
||||
ctx.whitelist_count++;
|
||||
}
|
||||
|
||||
if (ctx.whitelist_count == 0) {
|
||||
SPDK_ERRLOG("No BDF section\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Probe the physical NVMe devices */
|
||||
if (spdk_nvme_probe(&ctx, probe_cb, attach_cb)) {
|
||||
SPDK_ERRLOG("One or more controllers failed in spdk_nvme_probe()\n");
|
||||
}
|
||||
|
||||
/* check whether any nvme controller is probed */
|
||||
if (TAILQ_EMPTY(&g_ctrlrs)) {
|
||||
SPDK_ERRLOG("No nvme controllers are probed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvmf_shutdown_nvme(void)
|
||||
{
|
||||
struct spdk_nvmf_ctrlr *ctrlr, *tctrlr;
|
||||
|
||||
TAILQ_FOREACH_SAFE(ctrlr, &g_ctrlrs, entry, tctrlr) {
|
||||
TAILQ_REMOVE(&g_ctrlrs, ctrlr, entry);
|
||||
spdk_nvme_detach(ctrlr->ctrlr);
|
||||
free(ctrlr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct spdk_nvmf_ctrlr *
|
||||
spdk_nvmf_ctrlr_claim(const char *name)
|
||||
{
|
||||
struct spdk_nvmf_ctrlr *ctrlr, *tctrlr;
|
||||
|
||||
if (name == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Attempting to claim NVMe controller %s\n", name);
|
||||
|
||||
TAILQ_FOREACH_SAFE(ctrlr, &g_ctrlrs, entry, tctrlr) {
|
||||
if (strncmp(ctrlr->name, name, MAX_NVME_NAME_LENGTH) == 0) {
|
||||
if (ctrlr->claimed) {
|
||||
SPDK_ERRLOG("Two subsystems are attempting to claim the same NVMe controller.\n");
|
||||
return NULL;
|
||||
}
|
||||
ctrlr->claimed = true;
|
||||
return ctrlr;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
57
lib/nvmf/controller.h
Normal file
57
lib/nvmf/controller.h
Normal file
@ -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 NVMF_CONTROLLER_H
|
||||
#define NVMF_CONTROLLER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "nvmf_internal.h"
|
||||
|
||||
#define MAX_NVME_NAME_LENGTH 64
|
||||
|
||||
struct spdk_nvmf_ctrlr {
|
||||
struct spdk_nvme_ctrlr *ctrlr;
|
||||
char name[MAX_NVME_NAME_LENGTH];
|
||||
bool claimed;
|
||||
TAILQ_ENTRY(spdk_nvmf_ctrlr) entry;
|
||||
};
|
||||
|
||||
int spdk_nvmf_init_nvme(void);
|
||||
int spdk_nvmf_shutdown_nvme(void);
|
||||
|
||||
struct spdk_nvmf_ctrlr *
|
||||
spdk_nvmf_ctrlr_claim(const char *name);
|
||||
|
||||
|
||||
#endif
|
370
lib/nvmf/framework.c
Normal file
370
lib/nvmf/framework.c
Normal file
@ -0,0 +1,370 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/conf.h"
|
||||
#include "nvmf.h"
|
||||
#include "conf.h"
|
||||
#include "conn.h"
|
||||
#include "controller.h"
|
||||
#include "port.h"
|
||||
#include "init_grp.h"
|
||||
#include "rdma.h"
|
||||
#include "subsystem_grp.h"
|
||||
#include "spdk/trace.h"
|
||||
|
||||
|
||||
#define MAX_SUBSYSTEMS 4
|
||||
|
||||
/*
|
||||
* Define the global pool sizes for the maximum possible
|
||||
* requests across all target connection queues.
|
||||
*
|
||||
* SPDK_NVMF_ADMINQ_POOL_SIZE: There is a single admin queue
|
||||
* for each subsystem session.
|
||||
*
|
||||
* SPDK_NVMF_IOQ_POOL_SIZE: MaxConnectionsPerSession is config
|
||||
* option that defines the total connection queues per session,
|
||||
* so we -1 here to not account for the admin queue.
|
||||
*
|
||||
* SPDK_NVMF_DESC_POOL_SIZE: The total number of RDMA descriptors
|
||||
* needed for all possible admin and I/O queue requests.
|
||||
*/
|
||||
#define SPDK_NVMF_ADMINQ_POOL_SIZE(spdk) (MAX_SUBSYSTEMS * \
|
||||
(spdk->MaxSessionsPerSubsystem) * \
|
||||
spdk->MaxQueueDepth)
|
||||
|
||||
#define SPDK_NVMF_IOQ_POOL_SIZE(spdk) (MAX_SUBSYSTEMS * \
|
||||
(spdk->MaxSessionsPerSubsystem) * \
|
||||
(spdk->MaxConnectionsPerSession - 1) * \
|
||||
spdk->MaxQueueDepth)
|
||||
|
||||
#define SPDK_NVMF_DESC_POOL_SIZE(spdk) (SPDK_NVMF_ADMINQ_POOL_SIZE(spdk) + \
|
||||
SPDK_NVMF_IOQ_POOL_SIZE(spdk))
|
||||
|
||||
#define SPDK_NVMF_MAX_CONNECTIONS(spdk) (MAX_SUBSYSTEMS * \
|
||||
((spdk)->MaxSessionsPerSubsystem) * \
|
||||
((spdk)->MaxConnectionsPerSession))
|
||||
|
||||
struct spdk_nvmf_globals g_nvmf_tgt;
|
||||
|
||||
extern struct rte_mempool *request_mempool;
|
||||
|
||||
static int
|
||||
spdk_nvmf_initialize_pools(struct spdk_nvmf_globals *spdk_nvmf)
|
||||
{
|
||||
SPDK_NOTICELOG("\n*** NVMf Pool Creation ***\n");
|
||||
|
||||
/* create NVMe backend request pool */
|
||||
spdk_nvmf->nvme_request_pool = rte_mempool_create("NVMe_Pool",
|
||||
SPDK_NVMF_DESC_POOL_SIZE(spdk_nvmf),
|
||||
spdk_nvme_request_size(),
|
||||
128, 0,
|
||||
NULL, NULL, NULL, NULL,
|
||||
SOCKET_ID_ANY, 0);
|
||||
if (!spdk_nvmf->nvme_request_pool) {
|
||||
SPDK_ERRLOG("create NVMe request pool failed\n");
|
||||
return -1;
|
||||
}
|
||||
/* set global pointer for this pool referenced by libraries */
|
||||
request_mempool = spdk_nvmf->nvme_request_pool;
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "NVMe request_mempool %p, size 0x%u bytes\n",
|
||||
request_mempool,
|
||||
(unsigned int)(SPDK_NVMF_DESC_POOL_SIZE(spdk_nvmf) * spdk_nvme_request_size()));
|
||||
|
||||
spdk_nvmf->bb_small_pool =
|
||||
rte_mempool_create("bb_small_pool",
|
||||
SPDK_NVMF_ADMINQ_POOL_SIZE(spdk_nvmf),
|
||||
SMALL_BB_MAX_SIZE,
|
||||
128, 0,
|
||||
NULL, NULL, NULL, NULL,
|
||||
SOCKET_ID_ANY, 0);
|
||||
if (!spdk_nvmf->bb_small_pool) {
|
||||
SPDK_ERRLOG("create bb small pool failed\n");
|
||||
return -1;
|
||||
}
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Small data buffer pool %p, size 0x%x bytes\n",
|
||||
spdk_nvmf->bb_small_pool,
|
||||
(SPDK_NVMF_ADMINQ_POOL_SIZE(spdk_nvmf) * SMALL_BB_MAX_SIZE));
|
||||
|
||||
spdk_nvmf->bb_large_pool =
|
||||
rte_mempool_create("bb_large_pool",
|
||||
SPDK_NVMF_IOQ_POOL_SIZE(spdk_nvmf),
|
||||
LARGE_BB_MAX_SIZE,
|
||||
32, 0,
|
||||
NULL, NULL, NULL, NULL,
|
||||
SOCKET_ID_ANY, 0);
|
||||
if (!spdk_nvmf->bb_large_pool) {
|
||||
SPDK_ERRLOG("create bb large pool failed\n");
|
||||
return -1;
|
||||
}
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Large data buffer pool %p, size 0x%x bytes\n",
|
||||
spdk_nvmf->bb_large_pool,
|
||||
(SPDK_NVMF_IOQ_POOL_SIZE(spdk_nvmf) * LARGE_BB_MAX_SIZE));
|
||||
|
||||
spdk_nvmf->rx_desc_pool =
|
||||
rte_mempool_create("RDMA RX Desc Pool",
|
||||
SPDK_NVMF_DESC_POOL_SIZE(spdk_nvmf),
|
||||
sizeof(struct nvme_qp_rx_desc),
|
||||
0, 0,
|
||||
NULL, NULL, NULL, NULL,
|
||||
SOCKET_ID_ANY, 0);
|
||||
if (!spdk_nvmf->rx_desc_pool) {
|
||||
SPDK_ERRLOG("create RX Desc pool failed\n");
|
||||
return -1;
|
||||
}
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "RDMA Rx descriptor pool %p, size 0x%lx bytes\n",
|
||||
spdk_nvmf->rx_desc_pool,
|
||||
(SPDK_NVMF_DESC_POOL_SIZE(spdk_nvmf) * sizeof(struct nvme_qp_rx_desc)));
|
||||
|
||||
spdk_nvmf->tx_desc_pool =
|
||||
rte_mempool_create("RDMA TX Desc Pool",
|
||||
SPDK_NVMF_DESC_POOL_SIZE(spdk_nvmf),
|
||||
sizeof(struct nvme_qp_tx_desc),
|
||||
0, 0,
|
||||
NULL, NULL, NULL, NULL,
|
||||
SOCKET_ID_ANY, 0);
|
||||
if (!spdk_nvmf->tx_desc_pool) {
|
||||
SPDK_ERRLOG("create TX Desc pool failed\n");
|
||||
return -1;
|
||||
}
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "RDMA Tx descriptor pool %p, size 0x%lx bytes\n",
|
||||
spdk_nvmf->tx_desc_pool,
|
||||
(SPDK_NVMF_DESC_POOL_SIZE(spdk_nvmf) * sizeof(struct nvme_qp_tx_desc)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spdk_nvmf_check_pool(struct rte_mempool *pool, uint32_t count)
|
||||
{
|
||||
if (rte_mempool_count(pool) != count) {
|
||||
SPDK_ERRLOG("rte_mempool_count(%s) == %d, should be %d\n",
|
||||
pool->name, rte_mempool_count(pool), count);
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvmf_check_pools(struct spdk_nvmf_globals *spdk_nvmf)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc += spdk_nvmf_check_pool(spdk_nvmf->nvme_request_pool, SPDK_NVMF_DESC_POOL_SIZE(spdk_nvmf));
|
||||
rc += spdk_nvmf_check_pool(spdk_nvmf->rx_desc_pool, SPDK_NVMF_DESC_POOL_SIZE(spdk_nvmf));
|
||||
rc += spdk_nvmf_check_pool(spdk_nvmf->tx_desc_pool, SPDK_NVMF_DESC_POOL_SIZE(spdk_nvmf));
|
||||
rc += spdk_nvmf_check_pool(spdk_nvmf->bb_small_pool, SPDK_NVMF_ADMINQ_POOL_SIZE(spdk_nvmf));
|
||||
rc += spdk_nvmf_check_pool(spdk_nvmf->bb_large_pool, SPDK_NVMF_IOQ_POOL_SIZE(spdk_nvmf));
|
||||
|
||||
if (rc == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
nvmf_tgt_init(char *authfile, char *nodebase, int max_in_capsule_data,
|
||||
int max_sessions_per_subsystem,
|
||||
int max_queue_depth, int max_conn_per_sess, int max_recv_seg_len, int listen_port)
|
||||
{
|
||||
int rc;
|
||||
|
||||
g_nvmf_tgt.authfile = strdup(authfile);
|
||||
if (!g_nvmf_tgt.authfile) {
|
||||
SPDK_ERRLOG("No authfile provided\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "AuthFile: %s\n", g_nvmf_tgt.authfile);
|
||||
|
||||
g_nvmf_tgt.nodebase = strdup(nodebase);
|
||||
if (!g_nvmf_tgt.nodebase) {
|
||||
SPDK_ERRLOG("No authfile provided\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "NodeBase: %s\n", g_nvmf_tgt.nodebase);
|
||||
|
||||
if (max_in_capsule_data >= 16 &&
|
||||
max_in_capsule_data % 16 == 0 &&
|
||||
max_in_capsule_data <= SPDK_NVMF_MAX_RECV_DATA_TRANSFER_SIZE) {
|
||||
g_nvmf_tgt.MaxInCapsuleData = max_in_capsule_data;
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxInCapsuleData: to %d\n",
|
||||
g_nvmf_tgt.MaxInCapsuleData);
|
||||
} else {
|
||||
SPDK_ERRLOG("Invalid MaxInCapsuleData: %d\n", max_in_capsule_data);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (max_sessions_per_subsystem >= 1 &&
|
||||
max_sessions_per_subsystem <= SPDK_NVMF_DEFAULT_MAX_SESSIONS_PER_SUBSYSTEM) {
|
||||
g_nvmf_tgt.MaxSessionsPerSubsystem = max_sessions_per_subsystem;
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxSessionsPerSubsystem: %d\n",
|
||||
g_nvmf_tgt.MaxSessionsPerSubsystem);
|
||||
} else {
|
||||
SPDK_ERRLOG("Invalid MaxSessionsPerSubsystem: %d\n", max_sessions_per_subsystem);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (max_queue_depth >= 1 &&
|
||||
max_queue_depth <= SPDK_NVMF_DEFAULT_MAX_QUEUE_DEPTH) {
|
||||
g_nvmf_tgt.MaxQueueDepth = max_queue_depth;
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxQueueDepth: %d\n",
|
||||
g_nvmf_tgt.MaxQueueDepth);
|
||||
} else {
|
||||
SPDK_ERRLOG("Invalid MaxQueueDepth: %d\n", max_queue_depth);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (max_conn_per_sess >= 1 &&
|
||||
max_conn_per_sess <= SPDK_NVMF_DEFAULT_MAX_CONNECTIONS_PER_SESSION) {
|
||||
g_nvmf_tgt.MaxConnectionsPerSession = max_conn_per_sess;
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxConnectionsPerSession: %d\n",
|
||||
g_nvmf_tgt.MaxConnectionsPerSession);
|
||||
} else {
|
||||
SPDK_ERRLOG("Invalid MaxConnectionsPerSession: %d\n", max_conn_per_sess);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
g_nvmf_tgt.MaxRecvDataSegmentLength = max_recv_seg_len;
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxRecvDataSegmentLength %d\n",
|
||||
g_nvmf_tgt.MaxRecvDataSegmentLength);
|
||||
|
||||
rc = pthread_mutex_init(&g_nvmf_tgt.mutex, NULL);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("mutex_init() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* init nvmf specific config options */
|
||||
if (!g_nvmf_tgt.sin_port) {
|
||||
g_nvmf_tgt.sin_port = htons(SPDK_NVMF_DEFAULT_SIN_PORT);
|
||||
}
|
||||
|
||||
rc = spdk_nvmf_initialize_pools(&g_nvmf_tgt);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("spdk_nvmf_initialize_pools() failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nvmf_tgt_subsystem_initialize(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* initialize from configuration file */
|
||||
rc = spdk_nvmf_parse_conf();
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("spdk_nvmf_parse_conf() failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* initialize with the NVMf transport */
|
||||
rc = nvmf_rdma_init();
|
||||
if (rc <= 0) {
|
||||
SPDK_ERRLOG("nvmf_rdma_init() failed\n");
|
||||
return rc;
|
||||
}
|
||||
/* initialize NVMe/NVMf backend */
|
||||
|
||||
SPDK_NOTICELOG("\n*** NVMf Library Init ***\n");
|
||||
rc = nvmf_initialize();
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("nvmf_initialize() failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = spdk_nvmf_init_nvme();
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "NVMf could not initialize NVMe devices.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = spdk_initialize_nvmf_subsystems();
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("spdk_initialize_nvmf_subsystems failed\n");
|
||||
return rc;
|
||||
}
|
||||
rc = spdk_initialize_nvmf_conns(SPDK_NVMF_MAX_CONNECTIONS(&g_nvmf_tgt));
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("spdk_initialize_nvmf_conns() failed\n");
|
||||
return rc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
nvmf_tgt_subsystem_fini(void)
|
||||
{
|
||||
spdk_shutdown_nvmf_subsystems();
|
||||
nvmf_shutdown();
|
||||
nvmf_initiator_group_array_destroy();
|
||||
spdk_nvmf_port_destroy_all();
|
||||
free(g_nvmf_tgt.authfile);
|
||||
free(g_nvmf_tgt.nodebase);
|
||||
|
||||
pthread_mutex_destroy(&g_nvmf_tgt.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
SPDK_SUBSYSTEM_REGISTER(nvmf, nvmf_tgt_subsystem_initialize, nvmf_tgt_subsystem_fini, NULL)
|
||||
|
||||
SPDK_TRACE_REGISTER_FN(nvmf_trace)
|
||||
{
|
||||
spdk_trace_register_object(OBJECT_NVMF_IO, 'r');
|
||||
spdk_trace_register_description("NVMF_IO_START", "", TRACE_NVMF_IO_START,
|
||||
OWNER_NONE, OBJECT_NVMF_IO, 1, 0, 0, "");
|
||||
spdk_trace_register_description("NVMF_RDMA_READ_START", "", TRACE_RDMA_READ_START,
|
||||
OWNER_NONE, OBJECT_NVMF_IO, 0, 0, 0, "");
|
||||
spdk_trace_register_description("NVMF_RDMA_WRITE_START", "", TRACE_RDMA_WRITE_START,
|
||||
OWNER_NONE, OBJECT_NVMF_IO, 0, 0, 0, "");
|
||||
spdk_trace_register_description("NVMF_RDMA_READ_COMPLETE", "", TRACE_RDMA_READ_COMPLETE,
|
||||
OWNER_NONE, OBJECT_NVMF_IO, 0, 0, 0, "");
|
||||
spdk_trace_register_description("NVMF_RDMA_WRITE_COMPLETE", "", TRACE_RDMA_WRITE_COMPLETE,
|
||||
OWNER_NONE, OBJECT_NVMF_IO, 0, 0, 0, "");
|
||||
spdk_trace_register_description("NVMF_LIB_READ_START", "", TRACE_NVMF_LIB_READ_START,
|
||||
OWNER_NONE, OBJECT_NVMF_IO, 0, 0, 0, "");
|
||||
spdk_trace_register_description("NVMF_LIB_WRITE_START", "", TRACE_NVMF_LIB_WRITE_START,
|
||||
OWNER_NONE, OBJECT_NVMF_IO, 0, 0, 0, "");
|
||||
spdk_trace_register_description("NVMF_LIB_COMPLETE", "", TRACE_NVMF_LIB_COMPLETE,
|
||||
OWNER_NONE, OBJECT_NVMF_IO, 0, 0, 0, "");
|
||||
spdk_trace_register_description("NVMF_IO_COMPLETION_DONE", "", TRACE_NVMF_IO_COMPLETE,
|
||||
OWNER_NONE, OBJECT_NVMF_IO, 0, 0, 0, "");
|
||||
}
|
299
lib/nvmf/init_grp.c
Normal file
299
lib/nvmf/init_grp.c
Normal file
@ -0,0 +1,299 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "init_grp.h"
|
||||
#include "nvmf.h"
|
||||
#include "subsystem_grp.h"
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/trace.h"
|
||||
|
||||
#define MAX_MASKBUF 128
|
||||
#define MAX_INITIATOR 8
|
||||
#define MAX_INITIATOR_GROUP 32
|
||||
|
||||
#define MAX_ADDRBUF 64
|
||||
#define MAX_INITIATOR_ADDR (MAX_ADDRBUF)
|
||||
#define MAX_INITIATOR_NAME 256
|
||||
#define MAX_NETMASK 256
|
||||
|
||||
static TAILQ_HEAD(, spdk_nvmf_init_grp) g_ig_head = TAILQ_HEAD_INITIALIZER(g_ig_head);
|
||||
|
||||
struct spdk_nvmf_init_grp *
|
||||
spdk_nvmf_init_grp_create(int tag,
|
||||
int num_netmasks,
|
||||
char **netmasks)
|
||||
{
|
||||
int i;
|
||||
struct spdk_nvmf_init_grp *ig = NULL;
|
||||
|
||||
/* Make sure there are no duplicate initiator group tags */
|
||||
if (nvmf_initiator_group_find_by_tag(tag)) {
|
||||
SPDK_ERRLOG("Initiator group creation failed due to duplicate initiator group tag (%d)\n",
|
||||
tag);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (num_netmasks > MAX_NETMASK) {
|
||||
SPDK_ERRLOG("%d > MAX_NETMASK\n", num_netmasks);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG,
|
||||
"add initiator group (from initiator list) tag=%d, #masks=%d\n",
|
||||
tag, num_netmasks);
|
||||
|
||||
ig = calloc(1, sizeof(*ig));
|
||||
if (!ig) {
|
||||
SPDK_ERRLOG("initiator group malloc error (%d)\n", tag);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ig->tag = tag;
|
||||
|
||||
ig->nnetmasks = num_netmasks;
|
||||
ig->netmasks = netmasks;
|
||||
for (i = 0; i < num_netmasks; i++) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Netmask %s\n", ig->netmasks[i]);
|
||||
}
|
||||
|
||||
ig->state = GROUP_INIT;
|
||||
|
||||
pthread_mutex_lock(&g_nvmf_tgt.mutex);
|
||||
ig->state = GROUP_READY;
|
||||
TAILQ_INSERT_TAIL(&g_ig_head, ig, tailq);
|
||||
pthread_mutex_unlock(&g_nvmf_tgt.mutex);
|
||||
|
||||
return ig;
|
||||
}
|
||||
|
||||
static void
|
||||
nvmf_initiator_group_destroy(struct spdk_nvmf_init_grp *ig)
|
||||
{
|
||||
#if 0 // TODO: fix bogus scan-build warning about use-after-free
|
||||
int i;
|
||||
|
||||
if (!ig) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ig->nnetmasks; i++) {
|
||||
free(ig->netmasks[i]);
|
||||
}
|
||||
|
||||
free(ig->netmasks);
|
||||
free(ig);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
spdk_nvmf_allow_ipv6(const char *netmask, const char *addr)
|
||||
{
|
||||
struct in6_addr in6_mask;
|
||||
struct in6_addr in6_addr;
|
||||
char mask[MAX_MASKBUF];
|
||||
const char *p;
|
||||
size_t n;
|
||||
int bits, bmask;
|
||||
int i;
|
||||
|
||||
if (netmask[0] != '[')
|
||||
return 0;
|
||||
p = strchr(netmask, ']');
|
||||
if (p == NULL)
|
||||
return 0;
|
||||
n = p - (netmask + 1);
|
||||
if (n + 1 > sizeof mask)
|
||||
return 0;
|
||||
|
||||
memcpy(mask, netmask + 1, n);
|
||||
mask[n] = '\0';
|
||||
p++;
|
||||
|
||||
if (p[0] == '/') {
|
||||
bits = (int) strtol(p + 1, NULL, 10);
|
||||
if (bits < 0 || bits > 128)
|
||||
return 0;
|
||||
} else {
|
||||
bits = 128;
|
||||
}
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "input %s\n", addr);
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "mask %s / %d\n", mask, bits);
|
||||
|
||||
/* presentation to network order binary */
|
||||
if (inet_pton(AF_INET6, mask, &in6_mask) <= 0
|
||||
|| inet_pton(AF_INET6, addr, &in6_addr) <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check 128bits */
|
||||
for (i = 0; i < (bits / 8); i++) {
|
||||
if (in6_mask.s6_addr[i] != in6_addr.s6_addr[i])
|
||||
return 0;
|
||||
}
|
||||
if (bits % 8 && i < (MAX_MASKBUF / 8)) {
|
||||
bmask = (0xffU << (8 - (bits % 8))) & 0xffU;
|
||||
if ((in6_mask.s6_addr[i] & bmask) != (in6_addr.s6_addr[i] & bmask))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* match */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_nvmf_allow_ipv4(const char *netmask, const char *addr)
|
||||
{
|
||||
struct in_addr in4_mask;
|
||||
struct in_addr in4_addr;
|
||||
char mask[MAX_MASKBUF];
|
||||
const char *p;
|
||||
uint32_t bmask;
|
||||
size_t n;
|
||||
int bits;
|
||||
|
||||
p = strchr(netmask, '/');
|
||||
if (p == NULL) {
|
||||
p = netmask + strlen(netmask);
|
||||
}
|
||||
n = p - netmask;
|
||||
if (n + 1 > sizeof mask)
|
||||
return 0;
|
||||
|
||||
memcpy(mask, netmask, n);
|
||||
mask[n] = '\0';
|
||||
|
||||
if (p[0] == '/') {
|
||||
bits = (int) strtol(p + 1, NULL, 10);
|
||||
if (bits < 0 || bits > 32)
|
||||
return 0;
|
||||
} else {
|
||||
bits = 32;
|
||||
}
|
||||
|
||||
/* presentation to network order binary */
|
||||
if (inet_pton(AF_INET, mask, &in4_mask) <= 0
|
||||
|| inet_pton(AF_INET, addr, &in4_addr) <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check 32bits */
|
||||
bmask = (0xffffffffULL << (32 - bits)) & 0xffffffffU;
|
||||
if ((ntohl(in4_mask.s_addr) & bmask) != (ntohl(in4_addr.s_addr) & bmask))
|
||||
return 0;
|
||||
|
||||
/* match */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_nvmf_allow_netmask(const char *netmask, const char *addr)
|
||||
{
|
||||
if (netmask == NULL || addr == NULL)
|
||||
return 0;
|
||||
if (strcasecmp(netmask, "ALL") == 0)
|
||||
return 1;
|
||||
if (netmask[0] == '[') {
|
||||
/* IPv6 */
|
||||
if (spdk_nvmf_allow_ipv6(netmask, addr))
|
||||
return 1;
|
||||
} else {
|
||||
/* IPv4 */
|
||||
if (spdk_nvmf_allow_ipv4(netmask, addr))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct spdk_nvmf_init_grp *
|
||||
nvmf_initiator_group_find_by_addr(char *addr)
|
||||
{
|
||||
struct spdk_nvmf_init_grp *ig;
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
if (addr == NULL)
|
||||
return NULL;
|
||||
|
||||
TAILQ_FOREACH(ig, &g_ig_head, tailq) {
|
||||
/* check netmask of each group looking for permission */
|
||||
for (i = 0; i < ig->nnetmasks; i++) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "netmask=%s, addr=%s\n",
|
||||
ig->netmasks[i], addr);
|
||||
rc = spdk_nvmf_allow_netmask(ig->netmasks[i], addr);
|
||||
if (rc > 0) {
|
||||
/* OK netmask */
|
||||
return ig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "No initiator group addr match for %s\n",
|
||||
addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct spdk_nvmf_init_grp *
|
||||
nvmf_initiator_group_find_by_tag(int tag)
|
||||
{
|
||||
struct spdk_nvmf_init_grp *ig;
|
||||
|
||||
TAILQ_FOREACH(ig, &g_ig_head, tailq) {
|
||||
if (ig->tag == tag) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, " found initiator group with tag: ig %p\n", ig);
|
||||
return ig;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
nvmf_initiator_group_array_destroy(void)
|
||||
{
|
||||
struct spdk_nvmf_init_grp *ig;
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Enter\n");
|
||||
pthread_mutex_lock(&g_nvmf_tgt.mutex);
|
||||
while (!TAILQ_EMPTY(&g_ig_head)) {
|
||||
ig = TAILQ_FIRST(&g_ig_head);
|
||||
ig->state = GROUP_DESTROY;
|
||||
TAILQ_REMOVE(&g_ig_head, ig, tailq);
|
||||
nvmf_initiator_group_destroy(ig);
|
||||
}
|
||||
pthread_mutex_unlock(&g_nvmf_tgt.mutex);
|
||||
}
|
64
lib/nvmf/init_grp.h
Normal file
64
lib/nvmf/init_grp.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*-
|
||||
* 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 NVMF_INIT_GRP_H
|
||||
#define NVMF_INIT_GRP_H
|
||||
|
||||
#include "spdk/queue.h"
|
||||
#include "port.h" // For enum group_state
|
||||
|
||||
struct spdk_nvmf_init_grp {
|
||||
int nnetmasks;
|
||||
char **netmasks;
|
||||
int ref;
|
||||
int tag;
|
||||
enum group_state state;
|
||||
TAILQ_ENTRY(spdk_nvmf_init_grp) tailq;
|
||||
};
|
||||
|
||||
/* NVMf Initiator Group management API */
|
||||
struct spdk_nvmf_init_grp *
|
||||
spdk_nvmf_init_grp_create(int tag,
|
||||
int num_netmasks,
|
||||
char **netmasks);
|
||||
|
||||
struct spdk_nvmf_init_grp *
|
||||
nvmf_initiator_group_find_by_tag(int tag);
|
||||
|
||||
struct spdk_nvmf_init_grp *
|
||||
nvmf_initiator_group_find_by_addr(char *addr);
|
||||
|
||||
void
|
||||
nvmf_initiator_group_array_destroy(void);
|
||||
|
||||
#endif /* NVMF_INIT_GRP_H */
|
91
lib/nvmf/nvmf.c
Normal file
91
lib/nvmf/nvmf.c
Normal file
@ -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.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "conn.h"
|
||||
#include "controller.h"
|
||||
#include "port.h"
|
||||
#include "init_grp.h"
|
||||
#include "nvmf_internal.h"
|
||||
#include "nvmf.h"
|
||||
#include "rdma.h"
|
||||
#include "subsystem_grp.h"
|
||||
#include "spdk/conf.h"
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/pci.h"
|
||||
#include "spdk/trace.h"
|
||||
|
||||
SPDK_LOG_REGISTER_TRACE_FLAG("nvmf", SPDK_TRACE_NVMF)
|
||||
|
||||
/*
|
||||
* The NVMf library maintains context for a list of subsystems. Each
|
||||
* subsystem will be associated with one or more NVMe controllers
|
||||
* that the library discovers. It is expected that the NVMf library
|
||||
* consumer will make requests to create the desired subsystems.
|
||||
*/
|
||||
struct nvmf_driver {
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
static struct nvmf_driver g_nvmf_driver;
|
||||
|
||||
extern struct rte_mempool *request_mempool;
|
||||
|
||||
int
|
||||
nvmf_initialize(void)
|
||||
{
|
||||
struct nvmf_driver *system = &g_nvmf_driver;
|
||||
int err;
|
||||
|
||||
if (request_mempool == NULL) {
|
||||
fprintf(stderr, "NVMf application has not created request mempool!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = pthread_mutex_init(&system->mutex, NULL);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "NVMf system pthread_mutex_init() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nvmf_shutdown(void)
|
||||
{
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_shutdown\n");
|
||||
|
||||
spdk_nvmf_shutdown_nvme();
|
||||
}
|
123
lib/nvmf/nvmf.h
Normal file
123
lib/nvmf/nvmf.h
Normal file
@ -0,0 +1,123 @@
|
||||
/*-
|
||||
* 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 __NVMF_H__
|
||||
#define __NVMF_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <rte_config.h>
|
||||
#include <rte_mempool.h>
|
||||
|
||||
#include "spdk/nvmf_spec.h"
|
||||
#include "spdk/nvme.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
*/
|
||||
|
||||
#define SMALL_BB_MAX_SIZE 4096
|
||||
#define LARGE_BB_MAX_SIZE (128 * 1024)
|
||||
|
||||
/*
|
||||
* NVMf target supports a maximum transfer size that is equal to
|
||||
* a single allocated bounce buffer per request.
|
||||
*/
|
||||
#define SPDK_NVMF_MAX_RECV_DATA_TRANSFER_SIZE LARGE_BB_MAX_SIZE
|
||||
|
||||
|
||||
#define SPDK_NVMF_BUILD_ETC "/usr/local/etc/nvmf"
|
||||
#define SPDK_NVMF_DEFAULT_NUM_SESSIONS_PER_LCORE 1
|
||||
#define SPDK_NVMF_DEFAULT_AUTHFILE SPDK_NVMF_BUILD_ETC "/auth.conf"
|
||||
#define SPDK_NVMF_DEFAULT_NODEBASE "iqn.2013-10.com.intel.spdk"
|
||||
#define SPDK_NVMF_DEFAULT_IN_CAPSULE_DATA_SIZE 1024
|
||||
#define SPDK_NVMF_DEFAULT_MAX_SESSIONS_PER_SUBSYSTEM 1
|
||||
#define SPDK_NVMF_DEFAULT_MAX_QUEUE_DEPTH 128
|
||||
#define SPDK_NVMF_DEFAULT_MAX_CONNECTIONS_PER_SESSION 4
|
||||
#define SPDK_NVMF_DEFAULT_SIN_PORT ((uint16_t)7174)
|
||||
|
||||
#define OBJECT_NVMF_IO 0x30
|
||||
|
||||
#define TRACE_GROUP_NVMF 0x3
|
||||
#define TRACE_NVMF_IO_START SPDK_TPOINT_ID(TRACE_GROUP_NVMF, 0x0)
|
||||
#define TRACE_RDMA_READ_START SPDK_TPOINT_ID(TRACE_GROUP_NVMF, 0x1)
|
||||
#define TRACE_RDMA_WRITE_START SPDK_TPOINT_ID(TRACE_GROUP_NVMF, 0x2)
|
||||
#define TRACE_RDMA_READ_COMPLETE SPDK_TPOINT_ID(TRACE_GROUP_NVMF, 0x3)
|
||||
#define TRACE_RDMA_WRITE_COMPLETE SPDK_TPOINT_ID(TRACE_GROUP_NVMF, 0x4)
|
||||
#define TRACE_NVMF_LIB_READ_START SPDK_TPOINT_ID(TRACE_GROUP_NVMF, 0x5)
|
||||
#define TRACE_NVMF_LIB_WRITE_START SPDK_TPOINT_ID(TRACE_GROUP_NVMF, 0x6)
|
||||
#define TRACE_NVMF_LIB_COMPLETE SPDK_TPOINT_ID(TRACE_GROUP_NVMF, 0x7)
|
||||
#define TRACE_NVMF_IO_COMPLETE SPDK_TPOINT_ID(TRACE_GROUP_NVMF, 0x8)
|
||||
|
||||
struct spdk_nvmf_globals {
|
||||
char *authfile;
|
||||
|
||||
char *nodebase;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
int MaxInCapsuleData;
|
||||
int MaxSessionsPerSubsystem;
|
||||
int MaxQueueDepth;
|
||||
int MaxConnectionsPerSession;
|
||||
int MaxRecvDataSegmentLength;
|
||||
|
||||
struct rte_mempool *rx_desc_pool;
|
||||
struct rte_mempool *tx_desc_pool;
|
||||
struct rte_mempool *nvme_request_pool;
|
||||
struct rte_mempool *bb_small_pool;
|
||||
struct rte_mempool *bb_large_pool;
|
||||
uint16_t sin_port;
|
||||
};
|
||||
|
||||
extern struct spdk_nvmf_globals g_nvmf_tgt;
|
||||
|
||||
int
|
||||
nvmf_tgt_init(char *authfile, char *nodebase, int max_in_capsule_data, int max_sessions,
|
||||
int max_queue_depth, int max_conn_per_sess, int max_recv_seg_len, int listen_port);
|
||||
|
||||
struct nvmf_request;
|
||||
|
||||
int
|
||||
spdk_nvmf_check_pools(struct spdk_nvmf_globals *spdk_nvmf);
|
||||
|
||||
int
|
||||
nvmf_initialize(void);
|
||||
|
||||
void
|
||||
nvmf_shutdown(void);
|
||||
|
||||
#endif /* __NVMF_H__ */
|
338
lib/nvmf/nvmf_admin_cmd.c
Normal file
338
lib/nvmf/nvmf_admin_cmd.c
Normal file
@ -0,0 +1,338 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "nvmf.h"
|
||||
#include "nvmf_internal.h"
|
||||
#include "session.h"
|
||||
#include "subsystem_grp.h"
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/nvme.h"
|
||||
#include "spdk/nvme_spec.h"
|
||||
#include "spdk/pci.h"
|
||||
#include "spdk/trace.h"
|
||||
|
||||
extern struct rte_mempool *request_mempool;
|
||||
|
||||
int
|
||||
nvmf_process_admin_cmd(struct nvmf_session *session,
|
||||
struct spdk_nvme_cmd *cmd,
|
||||
void *buf, uint32_t len,
|
||||
struct nvmf_request *req_state)
|
||||
{
|
||||
struct spdk_nvme_cpl *response;
|
||||
struct spdk_nvmf_subsystem *subsystem = session->subsys;
|
||||
struct spdk_nvme_ctrlr *ctrlr = NULL;
|
||||
uint32_t nsid = 0;
|
||||
int rc = 0;
|
||||
uint8_t feature;
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_admin_cmd: req_state %p\n",
|
||||
req_state);
|
||||
|
||||
/* pre-set response details for this command */
|
||||
response = &req_state->rsp->nvme_cpl;
|
||||
response->status.sc = SPDK_NVME_SC_SUCCESS;
|
||||
response->cid = cmd->cid;
|
||||
|
||||
/* verify subsystem */
|
||||
if (subsystem == NULL) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_admin_cmd: Subsystem Not Initialized!\n");
|
||||
response->status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cmd->nsid == 0) {
|
||||
/* may be valid for the requested command. but need
|
||||
to at least map to a known valid controller.
|
||||
Note: Issue when in multi-controller subsystem
|
||||
mode, commands that do not provide ns_id can not
|
||||
be mapped to valid HW ctrlr! This is where
|
||||
definition of a virtual controller is required */
|
||||
ctrlr = subsystem->ns_list_map[0].ctrlr;
|
||||
nsid = 0;
|
||||
} else {
|
||||
/* verify namespace id */
|
||||
if (cmd->nsid > MAX_PER_SUBSYSTEM_NAMESPACES) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_admin_cmd: Invalid NS_ID %x\n",
|
||||
cmd->nsid);
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctrlr = subsystem->ns_list_map[cmd->nsid - 1].ctrlr;
|
||||
nsid = subsystem->ns_list_map[cmd->nsid - 1].nvme_ns_id;
|
||||
}
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_admin_cmd: ctrlr %p nvme ns_id %d\n", ctrlr, nsid);
|
||||
|
||||
switch (cmd->opc) {
|
||||
case SPDK_NVME_OPC_IDENTIFY:
|
||||
if (buf == NULL) {
|
||||
SPDK_ERRLOG("identify command with no buffer\n");
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_FIELD;
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
if (cmd->cdw10 == 0) {
|
||||
/* identify namespace */
|
||||
struct spdk_nvme_ns *ns;
|
||||
const struct spdk_nvme_ns_data *nsdata;
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Identify Namespace\n");
|
||||
if (nsid == 0) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_admin_cmd: Invalid NS_ID = 0\n");
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT;
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid);
|
||||
if (ns == NULL) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Unsuccessful query for Namespace reference\n");
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_FIELD;
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
nsdata = spdk_nvme_ns_get_data(ns);
|
||||
memcpy((char *)buf, (char *)nsdata, sizeof(struct spdk_nvme_ns_data));
|
||||
req_state->cb_fn(req_state);
|
||||
} else if (cmd->cdw10 == 1) {
|
||||
/* identify controller */
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Identify Controller\n");
|
||||
/* pull from virtual controller context */
|
||||
memcpy(buf, (char *)&session->vcdata, sizeof(struct spdk_nvme_ctrlr_data));
|
||||
req_state->cb_fn(req_state);
|
||||
} else {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Identify Namespace List\n");
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_OPCODE;
|
||||
rc = -1;
|
||||
}
|
||||
break;
|
||||
case SPDK_NVME_OPC_DELETE_IO_SQ: {
|
||||
uint16_t qid = cmd->cdw10 & 0xffff;
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Delete IO SQ, QID %x\n", qid);
|
||||
|
||||
if (qid >= MAX_SESSION_IO_QUEUES) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " Exceeded Session QP Index Limit\n");
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_FIELD;
|
||||
rc = -1;
|
||||
} else if (session->qps[qid].sq_active == 0) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " Session SQ QP Index %x was not active!\n", qid);
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_FIELD;
|
||||
rc = -1;
|
||||
} else {
|
||||
session->qps[qid].sq_size = 0;
|
||||
session->qps[qid].sq_active = 0;
|
||||
if (session->qps[qid].cq_active)
|
||||
session->active_queues--;
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPDK_NVME_OPC_DELETE_IO_CQ: {
|
||||
uint16_t qid = cmd->cdw10 & 0xffff;
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Delete IO CQ, QID %x\n", qid);
|
||||
|
||||
if (qid >= MAX_SESSION_IO_QUEUES) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " Exceeded Session QP Index Limit\n");
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_FIELD;
|
||||
rc = -1;
|
||||
} else if (session->qps[qid].cq_active == 0) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " Session CQ QP Index %x was not active!\n", qid);
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_FIELD;
|
||||
rc = -1;
|
||||
} else {
|
||||
session->qps[qid].cq_size = 0;
|
||||
session->qps[qid].cq_active = 0;
|
||||
if (session->qps[qid].sq_active)
|
||||
session->active_queues--;
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPDK_NVME_OPC_CREATE_IO_SQ:
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Create IO SQ\n");
|
||||
/* queues have already been initialized for this session.
|
||||
so for now save details in the session for which QPs
|
||||
the remote host attempts to enable.
|
||||
*/
|
||||
{
|
||||
uint16_t qid = cmd->cdw10 & 0xffff;
|
||||
uint16_t qsize = cmd->cdw10 >> 16;
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " QID %x, Queue Size %x, CDW11 %x\n",
|
||||
qid, qsize, cmd->cdw11);
|
||||
|
||||
if (qid >= MAX_SESSION_IO_QUEUES) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " Exceeded Session QP Index Limit\n");
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_FIELD;
|
||||
rc = -1;
|
||||
} else if (session->qps[qid].sq_active > 0) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " Session SQ QP Index %x Already active!\n", qid);
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_FIELD;
|
||||
rc = -1;
|
||||
} else {
|
||||
session->qps[qid].sq_size = qsize;
|
||||
session->qps[qid].sq_active = 1;
|
||||
if (session->qps[qid].cq_active)
|
||||
session->active_queues++;
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPDK_NVME_OPC_CREATE_IO_CQ:
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Create IO CQ\n");
|
||||
/* queues have already been initialized for this session.
|
||||
so for now save details in the session for which QPs
|
||||
the remote host attempts to enable.
|
||||
*/
|
||||
{
|
||||
uint16_t qid = cmd->cdw10 & 0xffff;
|
||||
uint16_t qsize = cmd->cdw10 >> 16;
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " QID %x, Queue Size %x, CDW11 %x\n",
|
||||
qid, qsize, cmd->cdw11);
|
||||
|
||||
if (qid >= MAX_SESSION_IO_QUEUES) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " Exceeded Session QP Index Limit\n");
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_FIELD;
|
||||
rc = -1;
|
||||
} else if (session->qps[qid].cq_active > 0) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " Session CQ QP Index %x Already active!\n", qid);
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_FIELD;
|
||||
rc = -1;
|
||||
} else {
|
||||
session->qps[qid].cq_size = qsize;
|
||||
session->qps[qid].cq_active = 1;
|
||||
if (session->qps[qid].sq_active)
|
||||
session->active_queues++;
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPDK_NVME_OPC_GET_FEATURES:
|
||||
feature = cmd->cdw10 & 0xff; /* mask out the FID value */
|
||||
switch (feature) {
|
||||
case SPDK_NVME_FEAT_NUMBER_OF_QUEUES:
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Get Features - Number of Queues\n");
|
||||
response->cdw0 = ((session->max_io_queues - 1) << 16) | (session->max_io_queues - 1);
|
||||
rc = 1; /* immediate completion */
|
||||
break;
|
||||
case SPDK_NVME_FEAT_LBA_RANGE_TYPE:
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Get Features - LBA Range Type\n");
|
||||
cmd->nsid = nsid;
|
||||
goto passthrough;
|
||||
break;
|
||||
default:
|
||||
goto passthrough;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SPDK_NVME_OPC_SET_FEATURES:
|
||||
feature = cmd->cdw10 & 0xff; /* mask out the FID value */
|
||||
switch (feature) {
|
||||
case SPDK_NVME_FEAT_NUMBER_OF_QUEUES:
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Set Features - Number of Queues, cdw11 %x\n", cmd->cdw11);
|
||||
|
||||
/* verify that the contoller is ready to process commands */
|
||||
if (session->active_queues != 0) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Queue pairs already active!\n");
|
||||
response->status.sc = SPDK_NVME_SC_COMMAND_SEQUENCE_ERROR;
|
||||
} else {
|
||||
response->cdw0 = ((session->max_io_queues - 1) << 16) | (session->max_io_queues - 1);
|
||||
}
|
||||
rc = 1; /* immediate completion */
|
||||
break;
|
||||
default:
|
||||
goto passthrough;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SPDK_NVME_OPC_ASYNC_EVENT_REQUEST:
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Async Event Request\n");
|
||||
/*
|
||||
Trap request here and save in the session context
|
||||
until NVMe library indicates some event.
|
||||
*/
|
||||
if (session->aer_req_state == NULL) {
|
||||
session->aer_req_state = req_state;
|
||||
} else {
|
||||
/* AER already recorded, send error response */
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "AER already active!\n");
|
||||
response->status.sc = SPDK_NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED;
|
||||
rc = 1; /* immediate completion */
|
||||
}
|
||||
break;
|
||||
case SPDK_NVME_OPC_KEEP_ALIVE:
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Keep Alive\n");
|
||||
/*
|
||||
To handle keep alive just clear or reset the
|
||||
session based keep alive duration counter.
|
||||
When added, a separate timer based process
|
||||
will monitor if the time since last recorded
|
||||
keep alive has exceeded the max duration and
|
||||
take appropriate action.
|
||||
*/
|
||||
//session->keep_alive_timestamp = ;
|
||||
rc = 1; /* immediate completion */
|
||||
break;
|
||||
default:
|
||||
passthrough:
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "RAW Passthrough: Admin Opcode %x for ctrlr %p\n",
|
||||
cmd->opc, ctrlr);
|
||||
cmd->nsid = nsid;
|
||||
spdk_nvme_ctrlr_cmd_admin_raw(ctrlr,
|
||||
cmd,
|
||||
buf, len,
|
||||
nvmf_complete_cmd,
|
||||
(void *)req_state);
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
nvmf_check_admin_completions(struct nvmf_session *session)
|
||||
{
|
||||
struct spdk_nvmf_subsystem *subsystem = session->subsys;
|
||||
struct spdk_nvme_ctrlr *ctrlr, *prev_ctrlr = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_PER_SUBSYSTEM_NAMESPACES; i++) {
|
||||
ctrlr = subsystem->ns_list_map[i].ctrlr;
|
||||
if (ctrlr == NULL)
|
||||
continue;
|
||||
if (ctrlr != NULL && ctrlr != prev_ctrlr) {
|
||||
spdk_nvme_ctrlr_process_admin_completions(ctrlr);
|
||||
prev_ctrlr = ctrlr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
131
lib/nvmf/nvmf_internal.h
Normal file
131
lib/nvmf/nvmf_internal.h
Normal file
@ -0,0 +1,131 @@
|
||||
/*-
|
||||
* 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 __NVMF_INTERNAL_H__
|
||||
#define __NVMF_INTERNAL_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "spdk/nvmf_spec.h"
|
||||
#include "spdk/assert.h"
|
||||
#include "spdk/queue.h"
|
||||
|
||||
#define nvmf_min(a,b) (((a)<(b))?(a):(b))
|
||||
|
||||
struct nvmf_request;
|
||||
|
||||
typedef void (*nvmf_cb_fn_t)(struct nvmf_request *);
|
||||
|
||||
union sgl_shift {
|
||||
struct spdk_nvmf_keyed_sgl_descriptor nvmf_sgl;
|
||||
struct spdk_nvme_sgl_descriptor nvme_sgl;
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(union sgl_shift) == 16, "Incorrect size");
|
||||
|
||||
union nvmf_h2c_msg {
|
||||
struct spdk_nvmf_capsule_cmd nvmf_cmd;
|
||||
struct spdk_nvme_cmd nvme_cmd;
|
||||
struct spdk_nvmf_fabric_prop_set_cmd prop_set_cmd;
|
||||
struct spdk_nvmf_fabric_prop_get_cmd prop_get_cmd;
|
||||
struct spdk_nvmf_fabric_connect_cmd connect_cmd;
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(union nvmf_h2c_msg) == 64, "Incorrect size");
|
||||
|
||||
union nvmf_c2h_msg {
|
||||
struct spdk_nvmf_capsule_rsp nvmf_rsp;
|
||||
struct spdk_nvme_cpl nvme_cpl;
|
||||
struct spdk_nvmf_fabric_prop_set_rsp prop_set_rsp;
|
||||
struct spdk_nvmf_fabric_prop_get_rsp prop_get_rsp;
|
||||
struct spdk_nvmf_fabric_connect_rsp connect_rsp;
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(union nvmf_c2h_msg) == 16, "Incorrect size");
|
||||
|
||||
#define NVMF_H2C_MAX_MSG (sizeof(union nvmf_h2c_msg))
|
||||
#define NVMF_C2H_MAX_MSG (sizeof(union nvmf_c2h_msg))
|
||||
|
||||
#define NVMF_CNTLID_SUBS_SHIFT 8
|
||||
|
||||
enum pending_rdma_action {
|
||||
NVMF_PENDING_NONE = 0,
|
||||
NVMF_PENDING_CONNECT,
|
||||
NVMF_PENDING_READ,
|
||||
NVMF_PENDING_WRITE,
|
||||
NVMF_PENDING_ADMIN,
|
||||
};
|
||||
|
||||
struct nvmf_request {
|
||||
struct nvmf_session *session;
|
||||
void *fabric_tx_ctx;
|
||||
void *fabric_rx_ctx;
|
||||
uint16_t cid; /* command identifier */
|
||||
uint64_t remote_addr;
|
||||
uint32_t rkey;
|
||||
uint32_t length;
|
||||
union nvmf_h2c_msg *cmd;
|
||||
union nvmf_c2h_msg *rsp;
|
||||
enum pending_rdma_action pending;
|
||||
nvmf_cb_fn_t cb_fn;
|
||||
|
||||
TAILQ_ENTRY(nvmf_request) entries;
|
||||
};
|
||||
|
||||
/*
|
||||
* Some NVMe command definitions not provided in the nvme_spec.h file
|
||||
*/
|
||||
|
||||
/* read command dword 12 */
|
||||
struct __attribute__((packed)) nvme_read_cdw12 {
|
||||
uint16_t nlb; /* number of logical blocks */
|
||||
uint16_t rsvd : 10;
|
||||
uint8_t prinfo : 4; /* protection information field */
|
||||
uint8_t fua : 1; /* force unit access */
|
||||
uint8_t lr : 1; /* limited retry */
|
||||
};
|
||||
|
||||
/* read command dword 13 */
|
||||
struct __attribute__((packed)) nvme_read_cdw13 {
|
||||
uint8_t dsm_af : 4; /* access frequency */
|
||||
uint8_t dsm_lat : 2; /* access latency */
|
||||
uint8_t dsm_seq : 1; /* sequential request */
|
||||
uint8_t dsm_inc : 1; /* incompressible */
|
||||
uint8_t rsvd[3];
|
||||
};
|
||||
|
||||
void
|
||||
nvmf_complete_cmd(void *rsp, const struct spdk_nvme_cpl *cmp);
|
||||
|
||||
#endif /* __NVMF_INTERNAL_H__ */
|
161
lib/nvmf/nvmf_io_cmd.c
Normal file
161
lib/nvmf/nvmf_io_cmd.c
Normal file
@ -0,0 +1,161 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "nvmf.h"
|
||||
#include "nvmf_internal.h"
|
||||
#include "session.h"
|
||||
#include "subsystem_grp.h"
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/nvme.h"
|
||||
#include "spdk/nvme_spec.h"
|
||||
#include "spdk/pci.h"
|
||||
#include "spdk/trace.h"
|
||||
|
||||
extern struct rte_mempool *request_mempool;
|
||||
|
||||
int
|
||||
nvmf_process_io_cmd(struct nvmf_session *session,
|
||||
struct spdk_nvme_cmd *cmd,
|
||||
void *buf, uint32_t len,
|
||||
struct nvmf_request *req_state)
|
||||
{
|
||||
struct spdk_nvme_cpl *response;
|
||||
struct spdk_nvmf_subsystem *subsystem = session->subsys;
|
||||
struct spdk_nvmf_namespace *nvmf_ns;
|
||||
struct spdk_nvme_ctrlr *ctrlr = NULL;
|
||||
struct spdk_nvme_ns *ns = NULL;
|
||||
struct spdk_nvme_qpair *qpair;
|
||||
uint32_t nsid = 0;
|
||||
struct nvme_read_cdw12 *cdw12;
|
||||
uint64_t lba_address;
|
||||
uint32_t lba_count;
|
||||
uint32_t io_flags;
|
||||
int rc = 0;
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_io_cmd: req_state %p\n", req_state);
|
||||
|
||||
/* pre-set response details for this command */
|
||||
response = &req_state->rsp->nvme_cpl;
|
||||
response->status.sc = SPDK_NVME_SC_SUCCESS;
|
||||
response->cid = cmd->cid;
|
||||
|
||||
/* verify subsystem */
|
||||
if (subsystem == NULL) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_io_cmd: Subsystem Not Initialized!\n");
|
||||
response->status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* verify that the contoller is ready to process commands */
|
||||
if (session->vcprop.csts.bits.rdy == 0) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_io_cmd: Subsystem Controller Not Ready!\n");
|
||||
response->status.sc = SPDK_NVME_SC_NAMESPACE_NOT_READY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* verify namespace id */
|
||||
if (cmd->nsid == 0 || cmd->nsid > MAX_PER_SUBSYSTEM_NAMESPACES) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_io_cmd: Invalid NS_ID %x\n",
|
||||
cmd->nsid);
|
||||
response->status.sc = SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
nvmf_ns = &subsystem->ns_list_map[cmd->nsid - 1];
|
||||
ctrlr = nvmf_ns->ctrlr;
|
||||
nsid = nvmf_ns->nvme_ns_id;
|
||||
ns = nvmf_ns->ns;
|
||||
qpair = nvmf_ns->qpair;
|
||||
|
||||
switch (cmd->opc) {
|
||||
case SPDK_NVME_OPC_READ:
|
||||
case SPDK_NVME_OPC_WRITE:
|
||||
cdw12 = (struct nvme_read_cdw12 *)&cmd->cdw12;
|
||||
/* NVMe library read/write interface expects non-0based lba_count value */
|
||||
lba_count = cdw12->nlb + 1;
|
||||
lba_address = cmd->cdw11;
|
||||
lba_address = (lba_address << 32) + cmd->cdw10;
|
||||
io_flags = cmd->cdw12 & 0xFFFF0000U;
|
||||
|
||||
if (cmd->opc == SPDK_NVME_OPC_READ) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_io_cmd: Read; lba address %lx, lba count %x\n",
|
||||
lba_address, lba_count);
|
||||
spdk_trace_record(TRACE_NVMF_LIB_READ_START, 0, 0,
|
||||
(uint64_t)req_state->fabric_rx_ctx, 0);
|
||||
spdk_nvme_ns_cmd_read(ns, qpair,
|
||||
buf, lba_address, lba_count,
|
||||
nvmf_complete_cmd,
|
||||
(void *)req_state, io_flags);
|
||||
} else {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_io_cmd: Write; lba address %lx, lba count %x\n",
|
||||
lba_address, lba_count);
|
||||
spdk_trace_record(TRACE_NVMF_LIB_WRITE_START, 0, 0,
|
||||
(uint64_t)req_state->fabric_rx_ctx, 0);
|
||||
spdk_nvme_ns_cmd_write(ns, qpair,
|
||||
buf, lba_address, lba_count,
|
||||
nvmf_complete_cmd,
|
||||
(void *)req_state, io_flags);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "RAW Passthrough: I/O Opcode %x\n", cmd->opc);
|
||||
cmd->nsid = nsid;
|
||||
spdk_nvme_ctrlr_cmd_io_raw(ctrlr, qpair,
|
||||
cmd,
|
||||
buf, len,
|
||||
nvmf_complete_cmd,
|
||||
(void *)req_state);
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
nvmf_check_io_completions(struct nvmf_session *session)
|
||||
{
|
||||
struct spdk_nvmf_subsystem *subsystem = session->subsys;
|
||||
struct spdk_nvme_qpair *qpair, *prev_qpair = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_PER_SUBSYSTEM_NAMESPACES; i++) {
|
||||
qpair = subsystem->ns_list_map[i].qpair;
|
||||
if (qpair == NULL)
|
||||
continue;
|
||||
if (qpair != NULL && qpair != prev_qpair) {
|
||||
spdk_nvme_qpair_process_completions(qpair, 0);
|
||||
prev_qpair = qpair;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
208
lib/nvmf/port.c
Normal file
208
lib/nvmf/port.c
Normal file
@ -0,0 +1,208 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "conn.h"
|
||||
#include "nvmf.h"
|
||||
#include "rdma.h"
|
||||
#include "port.h"
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/trace.h"
|
||||
|
||||
#define MAX_FABRIC_INTF_PER_PORT 4
|
||||
#define MAX_PORTS 4
|
||||
|
||||
static TAILQ_HEAD(, spdk_nvmf_port) g_port_head = TAILQ_HEAD_INITIALIZER(g_port_head);
|
||||
|
||||
/* Assumes caller allocated host and port strings on the heap */
|
||||
struct spdk_nvmf_fabric_intf *
|
||||
spdk_nvmf_fabric_intf_create(char *host, char *sin_port)
|
||||
{
|
||||
struct spdk_nvmf_fabric_intf *fabric_intf = NULL;
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Creating fabric intf: host address %s, port %s\n",
|
||||
host, sin_port);
|
||||
|
||||
RTE_VERIFY(host != NULL);
|
||||
RTE_VERIFY(sin_port != NULL);
|
||||
|
||||
fabric_intf = calloc(1, sizeof(*fabric_intf));
|
||||
if (!fabric_intf) {
|
||||
SPDK_ERRLOG("fabric_intf calloc error\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fabric_intf->host = host;
|
||||
fabric_intf->sin_port = sin_port;
|
||||
|
||||
return fabric_intf;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_nvmf_fabric_intf_destroy(struct spdk_nvmf_fabric_intf *fabric_intf)
|
||||
{
|
||||
RTE_VERIFY(fabric_intf != NULL);
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Enter\n");
|
||||
free(fabric_intf);
|
||||
}
|
||||
|
||||
|
||||
struct spdk_nvmf_fabric_intf *
|
||||
spdk_nvmf_port_find_fabric_intf_by_addr(char *addr)
|
||||
{
|
||||
struct spdk_nvmf_port *port;
|
||||
struct spdk_nvmf_fabric_intf *fabric_intf;
|
||||
int i;
|
||||
|
||||
if (addr == NULL)
|
||||
goto find_error;
|
||||
|
||||
for (i = 1; i < MAX_PORTS; i++) {
|
||||
port = spdk_nvmf_port_find_by_tag(i);
|
||||
if (port == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(fabric_intf, &port->head, tailq) {
|
||||
if (!strncasecmp(fabric_intf->host, addr, strlen(fabric_intf->host))) {
|
||||
return fabric_intf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
find_error:
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "No device addr match for %s\n", addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct spdk_nvmf_port *
|
||||
spdk_nvmf_port_create(int tag)
|
||||
{
|
||||
struct spdk_nvmf_port *port;
|
||||
|
||||
if (tag <= 0) {
|
||||
SPDK_ERRLOG("invalid port tag (%d)\n", tag);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make sure there are no duplicate port tags */
|
||||
if (spdk_nvmf_port_find_by_tag(tag)) {
|
||||
SPDK_ERRLOG("port creation failed. duplicate port tag (%d)\n", tag);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
port = calloc(1, sizeof(*port));
|
||||
if (!port) {
|
||||
SPDK_ERRLOG("port calloc error (%d)\n", tag);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
port->state = GROUP_INIT;
|
||||
port->tag = tag;
|
||||
port->type = FABRIC_RDMA;
|
||||
|
||||
TAILQ_INIT(&port->head);
|
||||
|
||||
pthread_mutex_lock(&g_nvmf_tgt.mutex);
|
||||
port->state = GROUP_READY;
|
||||
TAILQ_INSERT_TAIL(&g_port_head, port, tailq);
|
||||
pthread_mutex_unlock(&g_nvmf_tgt.mutex);
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_nvmf_port_destroy(struct spdk_nvmf_port *port)
|
||||
{
|
||||
#if 0 // TODO: fix bogus scan-build warning about use-after-free
|
||||
struct spdk_nvmf_fabric_intf *fabric_intf;
|
||||
|
||||
RTE_VERIFY(port != NULL);
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Enter\n");
|
||||
while (!TAILQ_EMPTY(&port->head)) {
|
||||
fabric_intf = TAILQ_FIRST(&port->head);
|
||||
TAILQ_REMOVE(&port->head, fabric_intf, tailq);
|
||||
spdk_nvmf_fabric_intf_destroy(fabric_intf);
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&g_port_head, port, tailq);
|
||||
|
||||
free(port);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
spdk_nvmf_port_add_fabric_intf(struct spdk_nvmf_port *port,
|
||||
struct spdk_nvmf_fabric_intf *fabric_intf)
|
||||
{
|
||||
RTE_VERIFY(port != NULL);
|
||||
RTE_VERIFY(fabric_intf != NULL);
|
||||
|
||||
fabric_intf->port = port;
|
||||
TAILQ_INSERT_TAIL(&port->head, fabric_intf, tailq);
|
||||
}
|
||||
|
||||
struct spdk_nvmf_port *
|
||||
spdk_nvmf_port_find_by_tag(int tag)
|
||||
{
|
||||
struct spdk_nvmf_port *port;
|
||||
|
||||
if (tag <= 0) {
|
||||
SPDK_ERRLOG("invalid port tag (%d)\n", tag);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(port, &g_port_head, tailq) {
|
||||
if (port->tag == tag) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, " found port with tag: port %p\n", port);
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_nvmf_port_destroy_all(void)
|
||||
{
|
||||
struct spdk_nvmf_port *port;
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Enter\n");
|
||||
pthread_mutex_lock(&g_nvmf_tgt.mutex);
|
||||
while (!TAILQ_EMPTY(&g_port_head)) {
|
||||
port = TAILQ_FIRST(&g_port_head);
|
||||
spdk_nvmf_port_destroy(port);
|
||||
}
|
||||
pthread_mutex_unlock(&g_nvmf_tgt.mutex);
|
||||
}
|
105
lib/nvmf/port.h
Normal file
105
lib/nvmf/port.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*-
|
||||
* 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 NVMF_PORT_H
|
||||
#define NVMF_PORT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "spdk/conf.h"
|
||||
#include "spdk/queue.h"
|
||||
|
||||
/** \file
|
||||
* An NVMf subsystem port, referred to as simply "port" is defined by the
|
||||
* specification as follows:
|
||||
*
|
||||
* An NVM subsystem port (port) is a collection of one or more physical fabric
|
||||
* interfaces that together act as a single interface between the NVM subsystem
|
||||
* and a fabric. When link aggregation (e.g., Ethernet) is used, the physical
|
||||
* ports for the group of aggregated links constitute a single NVM subsystem port.
|
||||
*/
|
||||
|
||||
enum fabric_type {
|
||||
FABRIC_RDMA = 0x1,
|
||||
FABRIC_PCI = 0x2,
|
||||
FABRIC_ETHERNET = 0x3,
|
||||
};
|
||||
|
||||
enum group_state {
|
||||
GROUP_INIT = 0x0,
|
||||
GROUP_READY = 0x1,
|
||||
GROUP_DESTROY = 0x2,
|
||||
};
|
||||
|
||||
struct spdk_nvmf_fabric_intf {
|
||||
char *host;
|
||||
char *sin_port;
|
||||
struct spdk_nvmf_port *port;
|
||||
uint32_t num_sessions;
|
||||
TAILQ_ENTRY(spdk_nvmf_fabric_intf) tailq;
|
||||
};
|
||||
|
||||
struct spdk_nvmf_port {
|
||||
int tag;
|
||||
enum group_state state;
|
||||
enum fabric_type type;
|
||||
TAILQ_HEAD(, spdk_nvmf_fabric_intf) head;
|
||||
TAILQ_ENTRY(spdk_nvmf_port) tailq;
|
||||
};
|
||||
|
||||
struct spdk_nvmf_fabric_intf *
|
||||
spdk_nvmf_fabric_intf_create(char *host, char *sin_port);
|
||||
|
||||
void
|
||||
spdk_nvmf_fabric_intf_destroy(struct spdk_nvmf_fabric_intf *fabric_intf);
|
||||
|
||||
struct spdk_nvmf_fabric_intf *
|
||||
spdk_nvmf_port_find_fabric_intf_by_addr(char *addr);
|
||||
|
||||
struct spdk_nvmf_port *
|
||||
spdk_nvmf_port_create(int tag);
|
||||
|
||||
void
|
||||
spdk_nvmf_port_destroy(struct spdk_nvmf_port *port);
|
||||
|
||||
struct spdk_nvmf_port *
|
||||
spdk_nvmf_port_find_by_tag(int tag);
|
||||
|
||||
void
|
||||
spdk_nvmf_port_add_fabric_intf(struct spdk_nvmf_port *port,
|
||||
struct spdk_nvmf_fabric_intf *fabric_intf);
|
||||
|
||||
void
|
||||
spdk_nvmf_port_destroy_all(void);
|
||||
|
||||
#endif
|
1132
lib/nvmf/rdma.c
Normal file
1132
lib/nvmf/rdma.c
Normal file
File diff suppressed because it is too large
Load Diff
81
lib/nvmf/rdma.h
Normal file
81
lib/nvmf/rdma.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*-
|
||||
* 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 _NVMF_RDMA_H_
|
||||
#define _NVMF_RDMA_H_
|
||||
|
||||
#include <infiniband/verbs.h>
|
||||
|
||||
#include "nvmf_internal.h"
|
||||
#include "spdk/nvmf_spec.h"
|
||||
|
||||
/* Define the Admin Queue Rx/Tx Descriptors */
|
||||
|
||||
struct nvme_qp_rx_desc {
|
||||
union nvmf_h2c_msg msg_buf;
|
||||
struct spdk_nvmf_conn *conn;
|
||||
struct ibv_mr *msg_buf_mr;
|
||||
struct ibv_sge recv_sgl;
|
||||
struct ibv_sge bb_sgl; /* must follow recv_sgl */
|
||||
struct ibv_mr *bb_mr;
|
||||
uint8_t *bb;
|
||||
uint32_t bb_len;
|
||||
uint32_t recv_bc;
|
||||
STAILQ_ENTRY(nvme_qp_rx_desc) link;
|
||||
};
|
||||
|
||||
struct nvme_qp_tx_desc {
|
||||
union nvmf_c2h_msg msg_buf;
|
||||
struct spdk_nvmf_conn *conn;
|
||||
struct nvmf_request req_state;
|
||||
struct ibv_mr *msg_buf_mr;
|
||||
struct ibv_sge send_sgl;
|
||||
struct nvme_qp_rx_desc *rx_desc;
|
||||
STAILQ_ENTRY(nvme_qp_tx_desc) link;
|
||||
};
|
||||
|
||||
int nvmf_post_rdma_read(struct spdk_nvmf_conn *conn,
|
||||
struct nvme_qp_tx_desc *tx_desc);
|
||||
int nvmf_post_rdma_write(struct spdk_nvmf_conn *conn,
|
||||
struct nvme_qp_tx_desc *tx_desc);
|
||||
int nvmf_post_rdma_recv(struct spdk_nvmf_conn *conn,
|
||||
struct nvme_qp_rx_desc *rx_desc);
|
||||
int nvmf_post_rdma_send(struct spdk_nvmf_conn *conn,
|
||||
struct nvme_qp_tx_desc *tx_desc);
|
||||
int nvmf_rdma_init(void);
|
||||
void nvmf_rdma_conn_cleanup(struct spdk_nvmf_conn *conn);
|
||||
|
||||
int nvmf_acceptor_start(void);
|
||||
void nvmf_acceptor_stop(void);
|
||||
|
||||
#endif /* _NVMF_RDMA_H_ */
|
517
lib/nvmf/session.c
Normal file
517
lib/nvmf/session.c
Normal file
@ -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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "session.h"
|
||||
#include "nvmf.h"
|
||||
#include "nvmf_internal.h"
|
||||
#include "subsystem_grp.h"
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/trace.h"
|
||||
|
||||
static struct nvmf_session *
|
||||
nvmf_create_session(const char *subnqn)
|
||||
{
|
||||
struct nvmf_session *session;
|
||||
struct spdk_nvmf_subsystem *subsystem;
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_create_session:\n");
|
||||
|
||||
/* locate the previously provisioned subsystem */
|
||||
subsystem = nvmf_find_subsystem(subnqn);
|
||||
if (subsystem == NULL)
|
||||
return NULL;
|
||||
|
||||
session = malloc(sizeof(struct nvmf_session));
|
||||
if (session == NULL)
|
||||
goto exit;
|
||||
memset(session, 0, sizeof(struct nvmf_session));
|
||||
|
||||
subsystem->num_sessions++;
|
||||
/* define cntlid that is unique across all subsystems */
|
||||
session->cntlid = (subsystem->num << NVMF_CNTLID_SUBS_SHIFT) + subsystem->num_sessions;
|
||||
TAILQ_INSERT_HEAD(&subsystem->sessions, session, entries);
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_create_session: allocated session cntlid %d\n",
|
||||
session->cntlid);
|
||||
TAILQ_INIT(&session->connections);
|
||||
session->num_connections = 0;
|
||||
session->is_valid = 1;
|
||||
session->subsys = subsystem;
|
||||
|
||||
exit:
|
||||
return session;
|
||||
}
|
||||
|
||||
static void
|
||||
nvmf_delete_session(struct nvmf_session *session)
|
||||
{
|
||||
session->subsys->num_sessions--;
|
||||
TAILQ_REMOVE(&session->subsys->sessions, session, entries);
|
||||
|
||||
free(session);
|
||||
}
|
||||
|
||||
void
|
||||
nvmf_init_session_properties(struct nvmf_session *session, int aq_depth)
|
||||
{
|
||||
/* for now base virtual controller properties on first namespace controller */
|
||||
struct spdk_nvme_ctrlr *ctrlr = session->subsys->ns_list_map[0].ctrlr;
|
||||
const struct spdk_nvme_ctrlr_data *cdata;
|
||||
struct spdk_nvmf_ctrlr_maxcmd *maxcmd;
|
||||
struct spdk_nvmf_ctrlr_kas *kas;
|
||||
struct spdk_nvmf_extended_identify_ctrlr_data *nvmfdata;
|
||||
struct spdk_nvmf_sgl_support *nvmfsgl;
|
||||
uint8_t *vc_data;
|
||||
uint32_t io_depth;
|
||||
|
||||
/*
|
||||
Here we are going to initialize the features, properties, and
|
||||
identify controller details for the virtual controller associated
|
||||
with a specific subsystem session.
|
||||
*/
|
||||
|
||||
/* Init the virtual controller details using actual HW details */
|
||||
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
|
||||
memcpy((char *)&session->vcdata, (char *)cdata, sizeof(struct spdk_nvme_ctrlr_data));
|
||||
|
||||
/* update virtual controller data to represent merge of
|
||||
controllers for all namespaces
|
||||
*/
|
||||
session->vcdata.nn = session->subsys->ns_count;
|
||||
|
||||
/* indicate support for only a single AER */
|
||||
session->vcdata.aerl = 0;
|
||||
|
||||
/* reset cntlid in vcdata to match the logical cntlid known to NVMf */
|
||||
session->vcdata.cntlid = session->cntlid;
|
||||
|
||||
/* initialize the nvmf new and extension details in controller data */
|
||||
vc_data = (uint8_t *)&session->vcdata;
|
||||
kas = (struct spdk_nvmf_ctrlr_kas *)&vc_data[SPDK_NVMF_CTRLR_KAS_OFFSET];
|
||||
kas->kas = 10; /* for keep alive granularity in seconds (10 * 100ms) */
|
||||
maxcmd = (struct spdk_nvmf_ctrlr_maxcmd *)&vc_data[SPDK_NVMF_CTRLR_MAXCMD_OFFSET];
|
||||
io_depth = SPDK_NVMF_DEFAULT_MAX_QUEUE_DEPTH;
|
||||
maxcmd->maxcmd = io_depth;
|
||||
nvmfdata = (struct spdk_nvmf_extended_identify_ctrlr_data *)
|
||||
&vc_data[SPDK_NVMF_EXTENDED_CTRLR_DATA_OFFSET];
|
||||
nvmfdata->ioccsz = (NVMF_H2C_MAX_MSG / 16);
|
||||
nvmfdata->iorcsz = (NVMF_C2H_MAX_MSG / 16);
|
||||
nvmfdata->icdoff = 0; /* offset starts directly after SQE */
|
||||
nvmfdata->ctrattr = 0; /* dynamic controller model */
|
||||
nvmfdata->msdbd = 1; /* target supports single SGL in capsule */
|
||||
nvmfsgl = (struct spdk_nvmf_sgl_support *)&session->vcdata.sgls;
|
||||
nvmfsgl->keyed_sgls = 1;
|
||||
nvmfsgl->address_as_offset_sgl_supported = 1;
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: ctrlr data: maxcmd %x\n",
|
||||
maxcmd->maxcmd);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: ext ctrlr data: ioccsz %x\n",
|
||||
nvmfdata->ioccsz);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: ext ctrlr data: iorcsz %x\n",
|
||||
nvmfdata->iorcsz);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: ext ctrlr data: icdoff %x\n",
|
||||
nvmfdata->icdoff);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: ext ctrlr data: ctrattr %x\n",
|
||||
nvmfdata->ctrattr);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: ext ctrlr data: msdbd %x\n",
|
||||
nvmfdata->msdbd);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: sgls data: 0x%x\n",
|
||||
*(uint32_t *)nvmfsgl);
|
||||
|
||||
/* feature: Number Of Queues. */
|
||||
/* Init to zero. Host shall set before enabling the controller */
|
||||
session->max_io_queues = MAX_SESSION_IO_QUEUES;
|
||||
session->vcfeat.noq = 0;
|
||||
|
||||
session->vcprop.cap_lo.raw = 0;
|
||||
session->vcprop.cap_lo.bits.cqr = 0; /* queues not contiguous */
|
||||
session->vcprop.cap_lo.bits.mqes = (io_depth - 1); /* max queue depth */
|
||||
session->vcprop.cap_lo.bits.ams = 0; /* optional arb mechanisms */
|
||||
session->vcprop.cap_lo.bits.to = 1; /* ready timeout - 500 msec units */
|
||||
|
||||
session->vcprop.cap_hi.raw = 0;
|
||||
session->vcprop.cap_hi.bits.dstrd = 0; /* fixed to 0 for NVMf */
|
||||
session->vcprop.cap_hi.bits.css_nvm = 1; /* NVM command set */
|
||||
session->vcprop.cap_hi.bits.mpsmin = 0; /* 2 ^ 12 + mpsmin == 4k */
|
||||
session->vcprop.cap_hi.bits.mpsmax = 0; /* 2 ^ 12 + mpsmax == 4k */
|
||||
|
||||
session->vcprop.vs = 0x10000; /* Version Supported: Major 1, Minor 0 */
|
||||
|
||||
session->vcprop.cc.raw = 0;
|
||||
session->vcprop.cc.bits.en = 0; /* Init controller disabled */
|
||||
|
||||
session->vcprop.csts.raw = 0;
|
||||
session->vcprop.csts.bits.rdy = 0; /* Init controller as not ready */
|
||||
|
||||
/* nssr not defined for v1.0 */
|
||||
|
||||
/* Set AQA details to reflect the virtual connection SQ/CQ depth */
|
||||
session->vcprop.aqa.bits.asqs = (aq_depth & 0xFFF);
|
||||
session->vcprop.aqa.bits.acqs = (aq_depth & 0xFFF);
|
||||
|
||||
session->vcprop.propsz.bits.size = sizeof(struct spdk_nvmf_ctrlr_properties) / 64;
|
||||
session->vcprop.capattr_hi.raw = 0;
|
||||
session->vcprop.capattr_lo.bits.rspsz = sizeof(union nvmf_c2h_msg) / 16;
|
||||
session->vcprop.capattr_lo.bits.cmdsz = sizeof(union nvmf_h2c_msg) / 16;
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: max io queues %x\n",
|
||||
session->max_io_queues);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: cap_lo %x\n",
|
||||
session->vcprop.cap_lo.raw);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: cap_hi %x\n",
|
||||
session->vcprop.cap_hi.raw);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: vs %x\n", session->vcprop.vs);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: cc %x\n", session->vcprop.cc.raw);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: csts %x\n",
|
||||
session->vcprop.csts.raw);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: nssr %x\n", session->vcprop.nssr);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: aqa %x\n", session->vcprop.aqa.raw);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: propsz %x\n",
|
||||
session->vcprop.propsz.raw);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: capattr_lo %x\n",
|
||||
session->vcprop.capattr_lo.raw);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: capattr_hi %x\n",
|
||||
session->vcprop.capattr_hi.raw);
|
||||
}
|
||||
|
||||
static struct nvmf_session *
|
||||
nvmf_find_session_by_id(const char *subnqn, uint16_t session_id)
|
||||
{
|
||||
struct spdk_nvmf_subsystem *subsystem;
|
||||
struct nvmf_session *sess, *tsess;
|
||||
|
||||
subsystem = nvmf_find_subsystem(subnqn);
|
||||
if (subsystem == NULL)
|
||||
return NULL;
|
||||
|
||||
TAILQ_FOREACH_SAFE(sess, &subsystem->sessions, entries, tsess) {
|
||||
if (sess->cntlid == session_id) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Session Match cntlid %d, sess %p\n", session_id, sess);
|
||||
return sess;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nvmf_session *
|
||||
nvmf_connect(void *fabric_conn,
|
||||
struct spdk_nvmf_fabric_connect_cmd *connect,
|
||||
struct spdk_nvmf_fabric_connect_data *connect_data,
|
||||
struct spdk_nvmf_fabric_connect_rsp *response)
|
||||
{
|
||||
struct nvmf_session *session;
|
||||
struct nvmf_connection_entry *connection = NULL;
|
||||
|
||||
connection = malloc(sizeof(struct nvmf_connection_entry));
|
||||
if (connection == NULL)
|
||||
goto connect_fail;
|
||||
|
||||
/* Figure out if this is the first connect and we
|
||||
* need to allocate an nvmf_session or if this is
|
||||
* a subsequent connect for an I/O queue and we need
|
||||
* to return an existing session
|
||||
*/
|
||||
if (connect->qid == 0) {
|
||||
/* first connect for AQ connection */
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "AQ connect capsule\n");
|
||||
if (connect_data->cntlid == 0xffff) {
|
||||
/* no nvmf session/controller association, allocate one */
|
||||
session = nvmf_create_session(connect_data->subnqn);
|
||||
if (session == NULL) {
|
||||
SPDK_ERRLOG("create session failed\n");
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_CONTROLLER_BUSY;
|
||||
goto connect_fail;
|
||||
}
|
||||
} else {
|
||||
SPDK_ERRLOG("nvmf AQ connection attempt to cntlid %d\n", connect_data->cntlid);
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
goto connect_fail;
|
||||
}
|
||||
connection->is_aq_conn = 1;
|
||||
} else {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "IOQ connect capsule\n");
|
||||
/* locate the existing session */
|
||||
session = nvmf_find_session_by_id(connect_data->subnqn, connect_data->cntlid);
|
||||
if (session == NULL) {
|
||||
SPDK_ERRLOG("invalid nvmf cntlid %d\n", connect_data->cntlid);
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_RESTART_DISCOVERY;
|
||||
goto connect_fail;
|
||||
}
|
||||
/* check if we would exceed session connection limit */
|
||||
if (session->num_connections >= session->max_connections_allowed) {
|
||||
SPDK_ERRLOG("connection limit %d\n", session->num_connections);
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_CONTROLLER_BUSY;
|
||||
goto connect_fail;
|
||||
}
|
||||
|
||||
if (session->is_valid == 0) {
|
||||
SPDK_ERRLOG("session invalid or at IO connection limit %d\n", session->num_connections);
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_RESTART_DISCOVERY;
|
||||
goto connect_fail;
|
||||
}
|
||||
connection->is_aq_conn = 0;
|
||||
}
|
||||
|
||||
connection->fabric_conn = fabric_conn;
|
||||
|
||||
session->num_connections++;
|
||||
TAILQ_INSERT_HEAD(&session->connections, connection, entries);
|
||||
|
||||
response->status_code_specific.success.cntlid = session->cntlid;
|
||||
response->status.sc = 0;
|
||||
|
||||
return session;
|
||||
|
||||
connect_fail:
|
||||
if (connection)
|
||||
free(connection);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
nvmf_disconnect(void *fabric_conn,
|
||||
struct nvmf_session *session)
|
||||
{
|
||||
struct nvmf_connection_entry *conn, *tconn, *rconn = NULL;
|
||||
|
||||
/* Indication from the fabric transport that a
|
||||
* specific connection has gone way. If the
|
||||
* connection is the AQ connection then expect
|
||||
* that the complete session will go away
|
||||
*/
|
||||
if (session == NULL) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_disconnect: session not active!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH_SAFE(conn, &session->connections, entries, tconn) {
|
||||
if (conn->fabric_conn == fabric_conn) {
|
||||
rconn = conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rconn == NULL) {
|
||||
SPDK_ERRLOG("Session connection did not exist!\n");
|
||||
return;
|
||||
}
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Disconnect NVMf conn %p, sess %p\n", rconn, session);
|
||||
|
||||
session->num_connections--;
|
||||
TAILQ_REMOVE(&session->connections, rconn, entries);
|
||||
free(rconn);
|
||||
|
||||
if (session->num_connections == 0) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Session connection count 0, deleting session %p!\n",
|
||||
session);
|
||||
nvmf_delete_session(session);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nvmf_complete_cmd(void *rsp, const struct spdk_nvme_cpl *cmp)
|
||||
{
|
||||
struct nvmf_request *req_state = (struct nvmf_request *)rsp;
|
||||
struct spdk_nvme_cpl *response;
|
||||
|
||||
spdk_trace_record(TRACE_NVMF_LIB_COMPLETE, 0, 0, (uint64_t)req_state->fabric_rx_ctx, 0);
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_complete_cmd callback: req_state %p\n", req_state);
|
||||
|
||||
response = &req_state->rsp->nvme_cpl;
|
||||
memcpy(response, cmp, sizeof(*cmp));
|
||||
|
||||
req_state->cb_fn(req_state);
|
||||
}
|
||||
|
||||
void
|
||||
nvmf_property_get(struct nvmf_session *session,
|
||||
struct spdk_nvmf_fabric_prop_get_cmd *cmd,
|
||||
struct spdk_nvmf_fabric_prop_get_rsp *response)
|
||||
{
|
||||
response->status.sc = 0;
|
||||
response->value.u64 = 0;
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_property_get: attrib %d, offset %x\n",
|
||||
cmd->attrib, cmd->ofst);
|
||||
|
||||
if (cmd->ofst > offsetof(struct spdk_nvmf_ctrlr_properties, capattr_hi)) {
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cmd->ofst) {
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, cap_lo)):
|
||||
response->value.u32.low = session->vcprop.cap_lo.raw;
|
||||
if (cmd->attrib == 1)
|
||||
response->value.u32.high = session->vcprop.cap_hi.raw;
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, cap_hi)):
|
||||
if (cmd->attrib == 1)
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
else
|
||||
response->value.u32.low = session->vcprop.cap_hi.raw;
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, vs)):
|
||||
if (cmd->attrib == 1)
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
else
|
||||
response->value.u32.low = session->vcprop.vs;
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, intms)):
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, intmc)):
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, cc)):
|
||||
if (cmd->attrib == 1)
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
else
|
||||
response->value.u32.low = session->vcprop.cc.raw;
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, csts)):
|
||||
if (cmd->attrib == 1)
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
else
|
||||
response->value.u32.low = session->vcprop.csts.raw;
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, nssr)):
|
||||
if (cmd->attrib == 1)
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
else
|
||||
response->value.u32.low = session->vcprop.nssr;
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, aqa)):
|
||||
if (cmd->attrib == 1)
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
else
|
||||
response->value.u32.low = session->vcprop.aqa.raw;
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, asq)):
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, acq)):
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, propsz)):
|
||||
if (cmd->attrib == 1)
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
else
|
||||
response->value.u32.low = session->vcprop.propsz.raw;
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, capattr_lo)):
|
||||
response->value.u32.low = session->vcprop.capattr_lo.raw;
|
||||
if (cmd->attrib == 1)
|
||||
response->value.u32.high = session->vcprop.capattr_hi.raw;
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, capattr_hi)):
|
||||
if (cmd->attrib == 1)
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
else
|
||||
response->value.u32.low = session->vcprop.capattr_hi.raw;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nvmf_property_set(struct nvmf_session *session,
|
||||
struct spdk_nvmf_fabric_prop_set_cmd *cmd,
|
||||
struct spdk_nvmf_fabric_prop_set_rsp *response,
|
||||
bool *shutdown)
|
||||
{
|
||||
response->status.sc = 0;
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF,
|
||||
"nvmf_property_set: attrib %d, offset %x, value %lx, value low %x, value high %x\n",
|
||||
cmd->attrib, cmd->ofst, cmd->value.u64, cmd->value.u32.low, cmd->value.u32.high);
|
||||
|
||||
if (cmd->ofst > offsetof(struct spdk_nvmf_ctrlr_properties, capattr_hi)) {
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
return;
|
||||
}
|
||||
|
||||
/* TBD: determine which values we allow to be changed, deal with spec version
|
||||
difference. Fields within 32bit value, ex. for reset in csts */
|
||||
|
||||
switch (cmd->ofst) {
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, cc)): {
|
||||
union spdk_nvme_cc_register cc;
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set CC\n");
|
||||
if (cmd->attrib == 1)
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
else {
|
||||
cc.raw = cmd->value.u32.low;
|
||||
|
||||
if (cc.bits.en == 1 && session->vcprop.cc.bits.en == 0) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set CC Enable!\n");
|
||||
session->vcprop.csts.bits.rdy = 1;
|
||||
}
|
||||
|
||||
if (cc.bits.shn && session->vcprop.cc.bits.shn == 0) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set CC Shutdown!\n");
|
||||
session->vcprop.cc.bits.en = 0;
|
||||
*shutdown = true;
|
||||
}
|
||||
|
||||
session->vcprop.cc.raw = cc.raw;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, csts)):
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set CSTS\n");
|
||||
if (cmd->attrib == 1)
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
else
|
||||
session->vcprop.csts.raw = cmd->value.u32.low;
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, nssr)):
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set NSSR\n");
|
||||
if (cmd->attrib == 1)
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
else
|
||||
session->vcprop.nssr = cmd->value.u32.low;
|
||||
break;
|
||||
case (offsetof(struct spdk_nvmf_ctrlr_properties, aqa)):
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set AQA\n");
|
||||
if (cmd->attrib == 1)
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
else
|
||||
session->vcprop.aqa.raw = cmd->value.u32.low;
|
||||
break;
|
||||
default:
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set Invalid Offset %x\n", cmd->ofst);
|
||||
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
|
||||
break;
|
||||
}
|
||||
}
|
151
lib/nvmf/session.h
Normal file
151
lib/nvmf/session.h
Normal file
@ -0,0 +1,151 @@
|
||||
/*-
|
||||
* 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 NVMF_SESSION_H
|
||||
#define NVMF_SESSION_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "spdk/nvmf_spec.h"
|
||||
#include "spdk/queue.h"
|
||||
|
||||
/*
|
||||
* This structure maintains local NVMf library specific connection
|
||||
* state that includes an opaque pointer back to its parent fabric
|
||||
* transport connection context.
|
||||
*/
|
||||
struct nvmf_connection_entry {
|
||||
void *fabric_conn;
|
||||
int is_aq_conn;
|
||||
|
||||
TAILQ_ENTRY(nvmf_connection_entry) entries;
|
||||
};
|
||||
|
||||
/* define a virtual controller limit to the number of QPs supported */
|
||||
#define MAX_SESSION_IO_QUEUES 64
|
||||
|
||||
struct nvmf_io_queue {
|
||||
uint16_t sq_size;
|
||||
uint16_t sq_active;
|
||||
uint16_t cq_size;
|
||||
uint16_t cq_active;
|
||||
};
|
||||
|
||||
struct nvmf_vc_features {
|
||||
uint32_t arb; /* arbitration */
|
||||
uint32_t pm; /* power management */
|
||||
uint32_t temp; /* temp threshold */
|
||||
uint32_t err; /* error recovery */
|
||||
uint32_t vwc; /* volatile write cache */
|
||||
uint32_t noq; /* number of queues */
|
||||
uint32_t ic; /* interrupt coalescing */
|
||||
uint32_t ivc; /* interrupt vector config */
|
||||
uint32_t wan; /* write atomicity normal */
|
||||
uint32_t aec; /* async event config */
|
||||
uint32_t apst; /* autonomous power state transition */
|
||||
uint32_t hmb; /* host memory buffer */
|
||||
uint32_t spm; /* sw progress marker */
|
||||
uint32_t hostid; /* host identifier */
|
||||
uint32_t resnm; /* reservation notification mask */
|
||||
uint32_t resp; /* reservation persistence */
|
||||
};
|
||||
|
||||
/*
|
||||
* This structure maintains the NVMf virtual controller session
|
||||
* state. Each NVMf session permits some number of connections.
|
||||
* At least one admin connection and additional IOQ connections.
|
||||
*/
|
||||
struct nvmf_session {
|
||||
struct spdk_nvmf_subsystem *subsys;
|
||||
|
||||
uint16_t cntlid;
|
||||
uint32_t max_io_queues; /* maximum supported by backend NVMe library */
|
||||
struct nvmf_io_queue qps[MAX_SESSION_IO_QUEUES];
|
||||
int active_queues;
|
||||
int is_valid;
|
||||
struct spdk_nvmf_ctrlr_properties vcprop; /* virtual controller properties */
|
||||
struct nvmf_vc_features vcfeat; /* virtual controller features */
|
||||
struct spdk_nvme_ctrlr_data vcdata; /* virtual controller data */
|
||||
|
||||
TAILQ_HEAD(connection_q, nvmf_connection_entry) connections;
|
||||
int num_connections;
|
||||
int max_connections_allowed;
|
||||
|
||||
struct nvmf_request *aer_req_state;
|
||||
|
||||
TAILQ_ENTRY(nvmf_session) entries;
|
||||
};
|
||||
|
||||
struct nvmf_session *
|
||||
nvmf_connect(void *fabric_conn,
|
||||
struct spdk_nvmf_fabric_connect_cmd *connect,
|
||||
struct spdk_nvmf_fabric_connect_data *connect_data,
|
||||
struct spdk_nvmf_fabric_connect_rsp *response);
|
||||
|
||||
void
|
||||
nvmf_disconnect(void *fabric_conn, struct nvmf_session *session);
|
||||
|
||||
void
|
||||
nvmf_init_session_properties(struct nvmf_session *session, int aq_depth);
|
||||
|
||||
int
|
||||
nvmf_process_admin_cmd(struct nvmf_session *session,
|
||||
struct spdk_nvme_cmd *cmd,
|
||||
void *buf, uint32_t len,
|
||||
struct nvmf_request *req_state);
|
||||
|
||||
int
|
||||
nvmf_process_io_cmd(struct nvmf_session *session,
|
||||
struct spdk_nvme_cmd *cmd,
|
||||
void *buf, uint32_t len,
|
||||
struct nvmf_request *req_state);
|
||||
|
||||
void
|
||||
nvmf_property_get(struct nvmf_session *session,
|
||||
struct spdk_nvmf_fabric_prop_get_cmd *cmd,
|
||||
struct spdk_nvmf_fabric_prop_get_rsp *response);
|
||||
|
||||
void
|
||||
nvmf_property_set(struct nvmf_session *session,
|
||||
struct spdk_nvmf_fabric_prop_set_cmd *cmd,
|
||||
struct spdk_nvmf_fabric_prop_set_rsp *response,
|
||||
bool *shutdown);
|
||||
|
||||
void
|
||||
nvmf_check_io_completions(struct nvmf_session *session);
|
||||
|
||||
void
|
||||
nvmf_check_admin_completions(struct nvmf_session *session);
|
||||
|
||||
#endif
|
446
lib/nvmf/subsystem_grp.c
Normal file
446
lib/nvmf/subsystem_grp.c
Normal file
@ -0,0 +1,446 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "controller.h"
|
||||
#include "port.h"
|
||||
#include "init_grp.h"
|
||||
#include "nvmf_internal.h"
|
||||
#include "nvmf.h"
|
||||
#include "session.h"
|
||||
#include "subsystem_grp.h"
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/string.h"
|
||||
#include "spdk/trace.h"
|
||||
|
||||
#define MAX_TMPBUF 1024
|
||||
#define SPDK_CN_TAG_MAX 0x0000ffff
|
||||
|
||||
static TAILQ_HEAD(, spdk_nvmf_subsystem_grp) g_ssg_head = TAILQ_HEAD_INITIALIZER(g_ssg_head);
|
||||
static TAILQ_HEAD(, spdk_nvmf_subsystem) g_subsystems = TAILQ_HEAD_INITIALIZER(g_subsystems);
|
||||
|
||||
struct spdk_nvmf_subsystem *
|
||||
nvmf_find_subsystem(const char *subnqn)
|
||||
{
|
||||
struct spdk_nvmf_subsystem *subs;
|
||||
|
||||
if (subnqn == NULL)
|
||||
return NULL;
|
||||
|
||||
TAILQ_FOREACH(subs, &g_subsystems, entries) {
|
||||
if (strcasecmp(subnqn, subs->subnqn) == 0) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "found subsystem group with name: %s\n",
|
||||
subnqn);
|
||||
return subs;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "can't find subsystem %s\n", subnqn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct spdk_nvmf_subsystem *
|
||||
nvmf_create_subsystem(int num, char *name)
|
||||
{
|
||||
struct spdk_nvmf_subsystem *subsystem;
|
||||
|
||||
subsystem = calloc(1, sizeof(struct spdk_nvmf_subsystem));
|
||||
if (subsystem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subsystem, 0, sizeof(struct spdk_nvmf_subsystem));
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_create_subsystem: allocated subsystem %p\n", subsystem);
|
||||
|
||||
subsystem->num = num;
|
||||
snprintf(subsystem->subnqn, sizeof(subsystem->subnqn), "%s", name);
|
||||
TAILQ_INIT(&subsystem->sessions);
|
||||
|
||||
TAILQ_INSERT_HEAD(&g_subsystems, subsystem, entries);
|
||||
|
||||
return subsystem;
|
||||
}
|
||||
|
||||
int
|
||||
nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem)
|
||||
{
|
||||
struct nvmf_session *sess, *tsess;
|
||||
|
||||
if (subsystem == NULL) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF,
|
||||
"nvmf_delete_subsystem: there is no subsystem\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH_SAFE(sess, &subsystem->sessions, entries, tsess) {
|
||||
subsystem->num_sessions--;
|
||||
TAILQ_REMOVE(&subsystem->sessions, sess, entries);
|
||||
free(sess);
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&g_subsystems, subsystem, entries);
|
||||
|
||||
free(subsystem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem,
|
||||
struct spdk_nvme_ctrlr *ctrlr)
|
||||
{
|
||||
int i, count, total_ns;
|
||||
struct spdk_nvme_qpair *qpair;
|
||||
struct spdk_nvmf_namespace *nvmf_ns;
|
||||
|
||||
total_ns = spdk_nvme_ctrlr_get_num_ns(ctrlr);
|
||||
|
||||
/* Assume that all I/O will be handled on one thread for now */
|
||||
qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, 0);
|
||||
if (qpair == NULL) {
|
||||
SPDK_ERRLOG("spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Adding %d namespaces from ctrlr %p to subsystem %s\n",
|
||||
total_ns, ctrlr, subsystem->subnqn);
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < MAX_PER_SUBSYSTEM_NAMESPACES; i++) {
|
||||
if (count == total_ns) {
|
||||
break;
|
||||
}
|
||||
nvmf_ns = &subsystem->ns_list_map[i];
|
||||
if (nvmf_ns->ctrlr == NULL) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Adding namespace %d to subsystem %s\n", count + 1,
|
||||
subsystem->subnqn);
|
||||
nvmf_ns->ctrlr = ctrlr;
|
||||
nvmf_ns->qpair = qpair;
|
||||
nvmf_ns->nvme_ns_id = count + 1;
|
||||
nvmf_ns->ns = spdk_nvme_ctrlr_get_ns(ctrlr, count + 1);
|
||||
subsystem->ns_count++;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* nvmf uses iSCSI IQN format to name target subsystems. We expect that
|
||||
the nvmf subsiqn name provided diring connect requests will be
|
||||
equivalent to a individual controller name
|
||||
*/
|
||||
static int
|
||||
spdk_check_nvmf_name(const char *name)
|
||||
{
|
||||
const unsigned char *up = (const unsigned char *) name;
|
||||
size_t n;
|
||||
|
||||
/* valid iSCSI name? */
|
||||
for (n = 0; up[n] != 0; n++) {
|
||||
if (up[n] > 0x00U && up[n] <= 0x2cU)
|
||||
goto err0;
|
||||
if (up[n] == 0x2fU)
|
||||
goto err0;
|
||||
if (up[n] >= 0x3bU && up[n] <= 0x40U)
|
||||
goto err0;
|
||||
if (up[n] >= 0x5bU && up[n] <= 0x60U)
|
||||
goto err0;
|
||||
if (up[n] >= 0x7bU && up[n] <= 0x7fU)
|
||||
goto err0;
|
||||
if (isspace(up[n]))
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* valid format? */
|
||||
if (strncasecmp(name, "iqn.", 4) == 0) {
|
||||
/* iqn.YYYY-MM.reversed.domain.name */
|
||||
if (!isdigit(up[4]) || !isdigit(up[5]) || !isdigit(up[6])
|
||||
|| !isdigit(up[7]) || up[8] != '-' || !isdigit(up[9])
|
||||
|| !isdigit(up[10]) || up[11] != '.') {
|
||||
SPDK_ERRLOG("invalid iqn format. "
|
||||
"expect \"iqn.YYYY-MM.reversed.domain.name\"\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (strncasecmp(name, "eui.", 4) == 0) {
|
||||
/* EUI-64 -> 16bytes */
|
||||
/* XXX */
|
||||
} else if (strncasecmp(name, "naa.", 4) == 0) {
|
||||
/* 64bit -> 16bytes, 128bit -> 32bytes */
|
||||
/* XXX */
|
||||
}
|
||||
|
||||
return 0;
|
||||
err0:
|
||||
SPDK_ERRLOG("Invalid iSCSI character [val %x, index %d]\n", up[n], (int)n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_nvmf_subsystem_destruct(struct spdk_nvmf_subsystem_grp *ss_group)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ss_group == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(ss_group->name);
|
||||
|
||||
for (i = 0; i < ss_group->map_count; i++) {
|
||||
ss_group->map[i].ig->ref--;
|
||||
}
|
||||
|
||||
/* Call NVMf library to free the subsystem */
|
||||
nvmf_delete_subsystem(ss_group->subsystem);
|
||||
|
||||
free(ss_group);
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_nvmf_subsystem_add_map(struct spdk_nvmf_subsystem_grp *ss_group,
|
||||
int port_tag, int ig_tag)
|
||||
{
|
||||
struct spdk_nvmf_access_map *map;
|
||||
struct spdk_nvmf_port *port;
|
||||
struct spdk_nvmf_init_grp *ig;
|
||||
|
||||
port = spdk_nvmf_port_find_by_tag(port_tag);
|
||||
if (port == NULL) {
|
||||
SPDK_ERRLOG("%s: Port%d not found\n", ss_group->name, port_tag);
|
||||
return -1;
|
||||
}
|
||||
if (port->state != GROUP_READY) {
|
||||
SPDK_ERRLOG("%s: Port%d not active\n", ss_group->name, port_tag);
|
||||
return -1;
|
||||
}
|
||||
ig = nvmf_initiator_group_find_by_tag(ig_tag);
|
||||
if (ig == NULL) {
|
||||
SPDK_ERRLOG("%s: InitiatorGroup%d not found\n", ss_group->name, ig_tag);
|
||||
return -1;
|
||||
}
|
||||
if (ig->state != GROUP_READY) {
|
||||
SPDK_ERRLOG("%s: InitiatorGroup%d not active\n", ss_group->name, ig_tag);
|
||||
return -1;
|
||||
}
|
||||
ig->ref++;
|
||||
map = &ss_group->map[ss_group->map_count];
|
||||
map->port = port;
|
||||
map->ig = ig;
|
||||
ss_group->map_count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_cf_add_nvmf_subsystem(struct spdk_conf_section *sp)
|
||||
{
|
||||
char buf[MAX_TMPBUF];
|
||||
struct spdk_nvmf_subsystem_grp *ss_group;
|
||||
const char *port_tag, *ig_tag;
|
||||
const char *val, *name;
|
||||
int port_tag_i, ig_tag_i;
|
||||
struct spdk_nvmf_ctrlr *nvmf_ctrlr;
|
||||
int i, ret;
|
||||
|
||||
printf("Provisioning NVMf Subsystem %d:\n", sp->num);
|
||||
|
||||
ss_group = calloc(1, sizeof(*ss_group));
|
||||
if (!ss_group) {
|
||||
SPDK_ERRLOG("could not allocate new subsystem group\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ss_group->num = sp->num;
|
||||
|
||||
/* read in and verify the NQN for the subsystem */
|
||||
name = spdk_conf_section_get_val(sp, "SubsystemName");
|
||||
if (name == NULL) {
|
||||
SPDK_ERRLOG("Subsystem Group %d: SubsystemName not found\n", ss_group->num);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (strncasecmp(name, "iqn.", 4) != 0
|
||||
&& strncasecmp(name, "eui.", 4) != 0
|
||||
&& strncasecmp(name, "naa.", 4) != 0) {
|
||||
ss_group->name = spdk_sprintf_alloc("%s:%s", g_nvmf_tgt.nodebase, name);
|
||||
} else {
|
||||
ss_group->name = strdup(name);
|
||||
}
|
||||
|
||||
if (!ss_group->name) {
|
||||
SPDK_ERRLOG("Could not allocate Controller Node name\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (spdk_check_nvmf_name(ss_group->name) != 0) {
|
||||
SPDK_ERRLOG("Controller Node name (n=%s) (fn=%s) contains an invalid character or format.\n",
|
||||
name, ss_group->name);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
printf(" NVMf Subsystem: Name: %s\n", ss_group->name);
|
||||
|
||||
/* Setup initiator and port access mapping */
|
||||
val = spdk_conf_section_get_val(sp, "Mapping");
|
||||
if (val == NULL) {
|
||||
/* no access map */
|
||||
SPDK_ERRLOG("Subsystem Group %d: no access Mapping\n", ss_group->num);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
ss_group->map_count = 0;
|
||||
for (i = 0; i < MAX_PER_SUBSYSTEM_ACCESS_MAP; i++) {
|
||||
val = spdk_conf_section_get_nmval(sp, "Mapping", i, 0);
|
||||
if (val == NULL)
|
||||
break;
|
||||
port_tag = spdk_conf_section_get_nmval(sp, "Mapping", i, 0);
|
||||
ig_tag = spdk_conf_section_get_nmval(sp, "Mapping", i, 1);
|
||||
if (port_tag == NULL || ig_tag == NULL) {
|
||||
SPDK_ERRLOG("LU%d: mapping error\n", ss_group->num);
|
||||
goto err0;
|
||||
}
|
||||
if (strncasecmp(port_tag, "Port",
|
||||
strlen("Port")) != 0
|
||||
|| sscanf(port_tag, "%*[^0-9]%d", &port_tag_i) != 1) {
|
||||
SPDK_ERRLOG("LU%d: mapping port error\n", ss_group->num);
|
||||
goto err0;
|
||||
}
|
||||
if (strncasecmp(ig_tag, "InitiatorGroup",
|
||||
strlen("InitiatorGroup")) != 0
|
||||
|| sscanf(ig_tag, "%*[^0-9]%d", &ig_tag_i) != 1) {
|
||||
SPDK_ERRLOG("LU%d: mapping initiator error\n", ss_group->num);
|
||||
goto err0;
|
||||
}
|
||||
if (port_tag_i < 1 || ig_tag_i < 1) {
|
||||
SPDK_ERRLOG("LU%d: invalid group tag\n", ss_group->num);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
ret = spdk_nvmf_subsystem_add_map(ss_group, port_tag_i, ig_tag_i);
|
||||
if (ret < 0) {
|
||||
SPDK_ERRLOG("could not init access map within subsystem group\n");
|
||||
goto err0;
|
||||
}
|
||||
}
|
||||
|
||||
/* register this subsystem with the NVMf library */
|
||||
ss_group->subsystem = nvmf_create_subsystem(ss_group->num, ss_group->name);
|
||||
if (ss_group->subsystem == NULL) {
|
||||
SPDK_ERRLOG("Failed creating new nvmf library subsystem\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* add controllers into the subsystem */
|
||||
for (i = 0; i < MAX_PER_SUBSYSTEM_NAMESPACES; i++) {
|
||||
snprintf(buf, sizeof(buf), "Controller%d", i);
|
||||
val = spdk_conf_section_get_val(sp, buf);
|
||||
if (val == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
val = spdk_conf_section_get_nmval(sp, buf, 0, 0);
|
||||
if (val == NULL) {
|
||||
SPDK_ERRLOG("No name specified for Controller%d\n", i);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* claim this controller from the available controller list */
|
||||
nvmf_ctrlr = spdk_nvmf_ctrlr_claim(val);
|
||||
if (nvmf_ctrlr == NULL) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "nvme controller %s not found\n", val);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* notify nvmf library to add this device namespace
|
||||
to this subsystem.
|
||||
*/
|
||||
ret = nvmf_subsystem_add_ns(ss_group->subsystem, nvmf_ctrlr->ctrlr);
|
||||
if (ret < 0) {
|
||||
SPDK_ERRLOG("nvmf library add namespace failed!\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, " NVMf Subsystem: Nvme Controller: %s , %p\n",
|
||||
nvmf_ctrlr->name, nvmf_ctrlr->ctrlr);
|
||||
}
|
||||
|
||||
TAILQ_INSERT_TAIL(&g_ssg_head, ss_group, tailq);
|
||||
|
||||
return 0;
|
||||
err0:
|
||||
spdk_nvmf_subsystem_destruct(ss_group);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_initialize_nvmf_subsystems(void)
|
||||
{
|
||||
struct spdk_conf_section *sp;
|
||||
int rc;
|
||||
|
||||
SPDK_NOTICELOG("\n*** NVMf Controller Subsystems Init ***\n");
|
||||
|
||||
TAILQ_INIT(&g_ssg_head);
|
||||
|
||||
sp = spdk_conf_first_section(NULL);
|
||||
while (sp != NULL) {
|
||||
if (spdk_conf_section_match_prefix(sp, "SubsystemGroup")) {
|
||||
if (sp->num > SPDK_CN_TAG_MAX) {
|
||||
SPDK_ERRLOG("tag %d is invalid\n", sp->num);
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "tag %d is invalid\n", sp->num);
|
||||
return -1;
|
||||
}
|
||||
rc = spdk_cf_add_nvmf_subsystem(sp);
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("spdk_cf_add_nvmf_subsystem() failed\n");
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_cf_add_nvmf_subsystem() failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
sp = spdk_conf_next_section(sp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_shutdown_nvmf_subsystems(void)
|
||||
{
|
||||
struct spdk_nvmf_subsystem_grp *ss_group;
|
||||
|
||||
while (!TAILQ_EMPTY(&g_ssg_head)) {
|
||||
ss_group = TAILQ_FIRST(&g_ssg_head);
|
||||
TAILQ_REMOVE(&g_ssg_head, ss_group, tailq);
|
||||
spdk_nvmf_subsystem_destruct(ss_group);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
102
lib/nvmf/subsystem_grp.h
Normal file
102
lib/nvmf/subsystem_grp.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*-
|
||||
* 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 _NVMF_SUBSYSTEM_GROUP_H_
|
||||
#define _NVMF_SUBSYSTEM_GROUP_H_
|
||||
|
||||
#include "spdk/nvme.h"
|
||||
#include "spdk/queue.h"
|
||||
|
||||
struct spdk_nvmf_conn;
|
||||
|
||||
#define MAX_PER_SUBSYSTEM_ACCESS_MAP 2
|
||||
#define MAX_PER_SUBSYSTEM_NAMESPACES 32
|
||||
#define MAX_NQN_SIZE 255
|
||||
|
||||
struct spdk_nvmf_namespace {
|
||||
int nvme_ns_id;
|
||||
struct spdk_nvme_ns *ns;
|
||||
struct spdk_nvme_ctrlr *ctrlr;
|
||||
struct spdk_nvme_qpair *qpair;
|
||||
};
|
||||
|
||||
/*
|
||||
* The NVMf subsystem, as indicated in the specification, is a collection
|
||||
* of virtual controller sessions. Any individual controller session has
|
||||
* access to all the NVMe device/namespaces maintained by the subsystem.
|
||||
*/
|
||||
struct spdk_nvmf_subsystem {
|
||||
uint16_t num;
|
||||
char subnqn[MAX_NQN_SIZE];
|
||||
int num_sessions;
|
||||
TAILQ_HEAD(session_q, nvmf_session) sessions;
|
||||
struct spdk_nvmf_namespace ns_list_map[MAX_PER_SUBSYSTEM_NAMESPACES];
|
||||
int ns_count;
|
||||
|
||||
TAILQ_ENTRY(spdk_nvmf_subsystem) entries;
|
||||
};
|
||||
|
||||
struct spdk_nvmf_access_map {
|
||||
struct spdk_nvmf_port *port;
|
||||
struct spdk_nvmf_init_grp *ig;
|
||||
};
|
||||
|
||||
struct spdk_nvmf_subsystem_grp {
|
||||
int num;
|
||||
char *name;;
|
||||
struct spdk_nvmf_subsystem *subsystem;
|
||||
int map_count;
|
||||
struct spdk_nvmf_access_map map[MAX_PER_SUBSYSTEM_ACCESS_MAP];
|
||||
TAILQ_ENTRY(spdk_nvmf_subsystem_grp) tailq;
|
||||
};
|
||||
|
||||
struct spdk_nvmf_subsystem *
|
||||
nvmf_create_subsystem(int num, char *name);
|
||||
|
||||
int
|
||||
nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem);
|
||||
|
||||
int
|
||||
nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem,
|
||||
struct spdk_nvme_ctrlr *ctrlr);
|
||||
|
||||
struct spdk_nvmf_subsystem *
|
||||
nvmf_find_subsystem(const char *subnqn);
|
||||
|
||||
int
|
||||
spdk_initialize_nvmf_subsystems(void);
|
||||
|
||||
int
|
||||
spdk_shutdown_nvmf_subsystems(void);
|
||||
|
||||
#endif /* _NVMF_SUBSYSTEM_GROUP_H_ */
|
@ -23,6 +23,10 @@ case `uname` in
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -f /usr/include/infiniband/verbs.h ]; then
|
||||
MAKECONFIG="$MAKECONFIG CONFIG_NVMF=y"
|
||||
fi
|
||||
|
||||
if [ -z "$output_dir" ]; then
|
||||
if [ -z "$rootdir" ] || [ ! -d "$rootdir/../output" ]; then
|
||||
output_dir=.
|
||||
|
Loading…
Reference in New Issue
Block a user