nvmf: add NVMe over Fabrics userspace target

Change-Id: I739916824d033bd1a8f8b7f5def09e58f23d13cb
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
Daniel Verkamp 2016-06-06 14:44:30 -07:00
parent 22f741d539
commit 0f912a0eaf
32 changed files with 7579 additions and 0 deletions

4
CONFIG
View File

@ -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

View File

@ -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
View File

@ -0,0 +1 @@
nvmf_tgt

70
app/nvmf_tgt/Makefile Normal file
View 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
View 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
View 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
View 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__ */

View File

@ -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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

124
lib/nvmf/conn.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

81
lib/nvmf/rdma.h Normal file
View 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
View 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
View 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
View 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
View 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_ */

View File

@ -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=.