2016-08-02 16:34:45 +00:00
|
|
|
/*-
|
|
|
|
* BSD LICENSE
|
|
|
|
*
|
|
|
|
* Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
|
|
|
|
* Copyright (c) Intel Corporation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2017-05-02 18:18:25 +00:00
|
|
|
#include "spdk/stdinc.h"
|
2016-08-02 16:34:45 +00:00
|
|
|
|
2016-10-03 21:40:06 +00:00
|
|
|
#include <rte_config.h>
|
|
|
|
#include <rte_mempool.h>
|
|
|
|
#include <rte_version.h>
|
|
|
|
|
2016-08-02 16:34:45 +00:00
|
|
|
#include "iscsi/iscsi.h"
|
|
|
|
#include "iscsi/init_grp.h"
|
|
|
|
#include "iscsi/portal_grp.h"
|
|
|
|
#include "iscsi/acceptor.h"
|
|
|
|
#include "iscsi/conn.h"
|
|
|
|
#include "iscsi/task.h"
|
2016-08-17 20:35:18 +00:00
|
|
|
|
|
|
|
#include "spdk/env.h"
|
2016-11-07 22:10:28 +00:00
|
|
|
|
2017-01-04 23:45:29 +00:00
|
|
|
#include "spdk_internal/event.h"
|
2016-11-07 22:10:28 +00:00
|
|
|
#include "spdk_internal/log.h"
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
#define ISCSI_CONFIG_TMPL \
|
|
|
|
"[iSCSI]\n" \
|
|
|
|
" # node name (not include optional part)\n" \
|
|
|
|
" # Users can optionally change this to fit their environment.\n" \
|
|
|
|
" NodeBase \"%s\"\n" \
|
|
|
|
"\n" \
|
|
|
|
" # files\n" \
|
|
|
|
" AuthFile %s\n" \
|
|
|
|
"\n" \
|
|
|
|
" # socket I/O timeout sec. (polling is infinity)\n" \
|
|
|
|
" Timeout %d\n" \
|
|
|
|
"\n" \
|
|
|
|
" # authentication information for discovery session\n" \
|
|
|
|
" DiscoveryAuthMethod %s\n" \
|
|
|
|
" DiscoveryAuthGroup %s\n" \
|
|
|
|
"\n" \
|
|
|
|
" MaxSessions %d\n" \
|
|
|
|
" MaxConnectionsPerSession %d\n" \
|
|
|
|
" MaxConnections %d\n" \
|
|
|
|
" MaxOutstandingR2T %d\n" \
|
|
|
|
"\n" \
|
|
|
|
" # iSCSI initial parameters negotiate with initiators\n" \
|
|
|
|
" # NOTE: incorrect values might crash\n" \
|
|
|
|
" DefaultTime2Wait %d\n" \
|
|
|
|
" DefaultTime2Retain %d\n" \
|
|
|
|
"\n" \
|
|
|
|
" ImmediateData %s\n" \
|
|
|
|
" DataPDUInOrder %s\n" \
|
|
|
|
" DataSequenceInOrder %s\n" \
|
|
|
|
" ErrorRecoveryLevel %d\n" \
|
|
|
|
"\n" \
|
|
|
|
" # Defines whether iSCSI target will enable configuration via RPC\n" \
|
|
|
|
" # RpcConfiguration Yes\n" \
|
|
|
|
"\n"
|
|
|
|
|
|
|
|
static void
|
|
|
|
spdk_iscsi_config_dump_section(FILE *fp)
|
|
|
|
{
|
2016-08-08 17:59:49 +00:00
|
|
|
const char *authmethod = "None";
|
2016-08-02 16:34:45 +00:00
|
|
|
char authgroup[32] = "None";
|
|
|
|
|
|
|
|
if (NULL == fp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (g_spdk_iscsi.req_discovery_auth)
|
2016-08-08 17:59:49 +00:00
|
|
|
authmethod = "CHAP";
|
2016-08-02 16:34:45 +00:00
|
|
|
else if (g_spdk_iscsi.req_discovery_auth_mutual)
|
2016-08-08 17:59:49 +00:00
|
|
|
authmethod = "CHAP Mutual";
|
2016-08-02 16:34:45 +00:00
|
|
|
else if (!g_spdk_iscsi.no_discovery_auth)
|
2016-08-08 17:59:49 +00:00
|
|
|
authmethod = "Auto";
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
if (g_spdk_iscsi.discovery_auth_group)
|
2016-08-08 18:01:17 +00:00
|
|
|
snprintf(authgroup, sizeof(authgroup), "AuthGroup%d", g_spdk_iscsi.discovery_auth_group);
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
fprintf(fp, ISCSI_CONFIG_TMPL,
|
|
|
|
g_spdk_iscsi.nodebase, g_spdk_iscsi.authfile,
|
|
|
|
g_spdk_iscsi.timeout, authmethod, authgroup,
|
|
|
|
g_spdk_iscsi.MaxSessions, g_spdk_iscsi.MaxConnectionsPerSession,
|
|
|
|
g_spdk_iscsi.MaxConnections, g_spdk_iscsi.MaxOutstandingR2T,
|
|
|
|
g_spdk_iscsi.DefaultTime2Wait, g_spdk_iscsi.DefaultTime2Retain,
|
|
|
|
(g_spdk_iscsi.ImmediateData == 1) ? "Yes" : "No",
|
|
|
|
(g_spdk_iscsi.DataPDUInOrder == 1) ? "Yes" : "No",
|
|
|
|
(g_spdk_iscsi.DataSequenceInOrder == 1) ? "Yes" : "No",
|
|
|
|
g_spdk_iscsi.ErrorRecoveryLevel);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Portal groups */
|
2016-08-08 17:48:26 +00:00
|
|
|
static const char *portal_group_section = \
|
|
|
|
"\n"
|
|
|
|
"# Users must change the PortalGroup section(s) to match the IP addresses\n"
|
|
|
|
"# for their environment.\n"
|
|
|
|
"# PortalGroup sections define which TCP ports the iSCSI server will use\n"
|
|
|
|
"# to listen for incoming connections. These are also used to determine\n"
|
|
|
|
"# which targets are accessible over each portal group.\n";
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
#define PORTAL_GROUP_TMPL \
|
|
|
|
"[PortalGroup%d]\n" \
|
|
|
|
" Comment \"Portal%d\"\n"
|
|
|
|
|
|
|
|
#define PORTAL_TMPL \
|
|
|
|
" Portal DA1 %s:%s\n"
|
|
|
|
|
|
|
|
static void
|
|
|
|
spdk_iscsi_config_dump_portal_groups(FILE *fp)
|
|
|
|
{
|
|
|
|
struct spdk_iscsi_portal *p = NULL;
|
|
|
|
struct spdk_iscsi_portal_grp *pg = NULL;
|
|
|
|
|
|
|
|
/* Create portal group section */
|
|
|
|
fprintf(fp, "%s", portal_group_section);
|
|
|
|
|
|
|
|
/* Dump portal groups */
|
|
|
|
TAILQ_FOREACH(pg, &g_spdk_iscsi.pg_head, tailq) {
|
|
|
|
if (NULL == pg) continue;
|
|
|
|
fprintf(fp, PORTAL_GROUP_TMPL, pg->tag, pg->tag);
|
|
|
|
/* Dump portals */
|
|
|
|
TAILQ_FOREACH(p, &pg->head, tailq) {
|
|
|
|
if (NULL == p) continue;
|
|
|
|
fprintf(fp, PORTAL_TMPL, p->host, p->port);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initiator Groups */
|
2016-08-08 17:48:26 +00:00
|
|
|
static const char *initiator_group_section = \
|
|
|
|
"\n"
|
|
|
|
"# Users must change the InitiatorGroup section(s) to match the IP\n"
|
|
|
|
"# addresses and initiator configuration in their environment.\n"
|
|
|
|
"# Netmask can be used to specify a single IP address or a range of IP addresses\n"
|
|
|
|
"# Netmask 192.168.1.20 <== single IP address\n"
|
|
|
|
"# Netmask 192.168.1.0/24 <== IP range 192.168.1.*\n";
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
#define INITIATOR_GROUP_TMPL \
|
|
|
|
"[InitiatorGroup%d]\n" \
|
|
|
|
" Comment \"Initiator Group%d\"\n"
|
|
|
|
|
|
|
|
#define INITIATOR_TMPL \
|
|
|
|
" InitiatorName "
|
|
|
|
|
|
|
|
#define NETMASK_TMPL \
|
|
|
|
" Netmask "
|
|
|
|
|
|
|
|
static void
|
|
|
|
spdk_iscsi_config_dump_initiator_groups(FILE *fp)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct spdk_iscsi_init_grp *ig;
|
|
|
|
|
|
|
|
/* Create initiator group section */
|
|
|
|
fprintf(fp, "%s", initiator_group_section);
|
|
|
|
|
|
|
|
/* Dump initiator groups */
|
|
|
|
TAILQ_FOREACH(ig, &g_spdk_iscsi.ig_head, tailq) {
|
|
|
|
if (NULL == ig) continue;
|
|
|
|
fprintf(fp, INITIATOR_GROUP_TMPL, ig->tag, ig->tag);
|
|
|
|
|
|
|
|
/* Dump initiators */
|
|
|
|
fprintf(fp, INITIATOR_TMPL);
|
|
|
|
for (i = 0; i < ig->ninitiators; i++)
|
|
|
|
fprintf(fp, "%s ", ig->initiators[i]);
|
|
|
|
fprintf(fp, "\n");
|
|
|
|
|
|
|
|
/* Dump netmasks */
|
|
|
|
fprintf(fp, NETMASK_TMPL);
|
|
|
|
for (i = 0; i < ig->nnetmasks; i++)
|
|
|
|
fprintf(fp, "%s ", ig->netmasks[i]);
|
|
|
|
fprintf(fp, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Target nodes */
|
2016-08-08 17:48:26 +00:00
|
|
|
static const char *target_nodes_section = \
|
|
|
|
"\n"
|
|
|
|
"# Users should change the TargetNode section(s) below to match the\n"
|
|
|
|
"# desired iSCSI target node configuration.\n"
|
|
|
|
"# TargetName, Mapping, LUN0 are minimum required\n";
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
#define TARGET_NODE_TMPL \
|
|
|
|
"[TargetNode%d]\n" \
|
|
|
|
" Comment \"Target%d\"\n" \
|
|
|
|
" TargetName %s\n" \
|
|
|
|
" TargetAlias \"%s\"\n"
|
|
|
|
|
|
|
|
#define TARGET_NODE_PGIG_MAPPING_TMPL \
|
|
|
|
" Mapping PortalGroup%d InitiatorGroup%d\n"
|
|
|
|
|
|
|
|
#define TARGET_NODE_AUTH_TMPL \
|
|
|
|
" AuthMethod %s\n" \
|
|
|
|
" AuthGroup %s\n" \
|
|
|
|
" UseDigest %s\n"
|
|
|
|
|
|
|
|
#define TARGET_NODE_QD_TMPL \
|
|
|
|
" QueueDepth %d\n\n"
|
|
|
|
|
|
|
|
#define TARGET_NODE_LUN_TMPL \
|
|
|
|
" LUN%d %s\n"
|
|
|
|
|
|
|
|
static void
|
|
|
|
spdk_iscsi_config_dump_target_nodes(FILE *fp)
|
|
|
|
{
|
|
|
|
int t = 0, l = 0, m = 0;
|
2017-05-02 17:56:08 +00:00
|
|
|
int maxlun;
|
2016-08-02 16:34:45 +00:00
|
|
|
struct spdk_scsi_dev *dev = NULL;
|
|
|
|
struct spdk_iscsi_tgt_node *target = NULL;
|
|
|
|
|
|
|
|
/* Create target nodes section */
|
|
|
|
fprintf(fp, "%s", target_nodes_section);
|
|
|
|
|
|
|
|
for (t = 0; t < MAX_ISCSI_TARGET_NODE; t++) {
|
|
|
|
int idx;
|
2017-06-26 19:17:36 +00:00
|
|
|
const char *authmethod = "None";
|
|
|
|
char authgroup[32] = "None";
|
|
|
|
const char *usedigest = "Auto";
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
target = g_spdk_iscsi.target[t];
|
|
|
|
if (NULL == target) continue;
|
|
|
|
|
|
|
|
dev = target->dev;
|
|
|
|
if (NULL == dev) continue;
|
|
|
|
|
|
|
|
idx = target->num;
|
2017-05-02 17:56:08 +00:00
|
|
|
fprintf(fp, TARGET_NODE_TMPL, idx, idx, target->name, spdk_scsi_dev_get_name(dev));
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
for (m = 0; m < target->maxmap; m++) {
|
|
|
|
if (NULL == target->map[m].pg) continue;
|
|
|
|
if (NULL == target->map[m].ig) continue;
|
|
|
|
|
|
|
|
fprintf(fp, TARGET_NODE_PGIG_MAPPING_TMPL,
|
|
|
|
target->map[m].pg->tag,
|
|
|
|
target->map[m].ig->tag);
|
|
|
|
}
|
|
|
|
|
2016-09-28 20:55:56 +00:00
|
|
|
if (target->auth_chap_disabled)
|
|
|
|
authmethod = "None";
|
|
|
|
else if (!target->auth_chap_required)
|
|
|
|
authmethod = "Auto";
|
|
|
|
else if (target->auth_chap_mutual)
|
|
|
|
authmethod = "CHAP Mutual";
|
|
|
|
else
|
|
|
|
authmethod = "CHAP";
|
|
|
|
|
|
|
|
if (target->auth_group > 0)
|
|
|
|
snprintf(authgroup, sizeof(authgroup), "AuthGroup%d", target->auth_group);
|
|
|
|
|
|
|
|
if (target->header_digest)
|
|
|
|
usedigest = "Header";
|
|
|
|
else if (target->data_digest)
|
|
|
|
usedigest = "Data";
|
|
|
|
|
|
|
|
fprintf(fp, TARGET_NODE_AUTH_TMPL,
|
|
|
|
authmethod, authgroup, usedigest);
|
|
|
|
|
2017-05-02 17:56:08 +00:00
|
|
|
maxlun = spdk_scsi_dev_get_max_lun(dev);
|
|
|
|
for (l = 0; l < maxlun; l++) {
|
|
|
|
struct spdk_scsi_lun *lun = spdk_scsi_dev_get_lun(dev, l);
|
|
|
|
|
|
|
|
if (!lun) {
|
|
|
|
continue;
|
|
|
|
}
|
2016-09-28 20:55:56 +00:00
|
|
|
|
|
|
|
fprintf(fp, TARGET_NODE_LUN_TMPL,
|
2017-05-02 17:56:08 +00:00
|
|
|
spdk_scsi_lun_get_id(lun),
|
|
|
|
spdk_scsi_lun_get_name(lun));
|
2016-08-02 16:34:45 +00:00
|
|
|
}
|
2016-09-28 20:55:56 +00:00
|
|
|
|
|
|
|
fprintf(fp, TARGET_NODE_QD_TMPL,
|
|
|
|
target->queue_depth);
|
2016-08-02 16:34:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
spdk_mobj_ctor(struct rte_mempool *mp, __attribute__((unused)) void *arg,
|
|
|
|
void *_m, __attribute__((unused)) unsigned i)
|
|
|
|
{
|
|
|
|
struct spdk_mobj *m = _m;
|
|
|
|
uint64_t *phys_addr;
|
2016-09-29 20:23:56 +00:00
|
|
|
ptrdiff_t off;
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
m->mp = mp;
|
|
|
|
m->buf = (uint8_t *)m + sizeof(struct spdk_mobj);
|
|
|
|
m->buf = (void *)((unsigned long)((uint8_t *)m->buf + 512) & ~511UL);
|
|
|
|
off = (uint64_t)(uint8_t *)m->buf - (uint64_t)(uint8_t *)m;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we store the physical address in a 64bit unsigned integer
|
|
|
|
* right before the 512B aligned buffer area.
|
|
|
|
*/
|
|
|
|
phys_addr = (uint64_t *)m->buf - 1;
|
|
|
|
*phys_addr = rte_mempool_virt2phy(mp, m) + off;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define PDU_POOL_SIZE(iscsi) (iscsi->MaxConnections * NUM_PDU_PER_CONNECTION)
|
|
|
|
#define IMMEDIATE_DATA_POOL_SIZE(iscsi) (iscsi->MaxConnections * 128)
|
|
|
|
#define DATA_OUT_POOL_SIZE(iscsi) (iscsi->MaxConnections * MAX_DATA_OUT_PER_CONNECTION)
|
|
|
|
|
|
|
|
static int spdk_iscsi_initialize_pdu_pool(void)
|
|
|
|
{
|
|
|
|
struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
|
|
|
|
int imm_mobj_size = spdk_get_immediate_data_buffer_size() +
|
|
|
|
sizeof(struct spdk_mobj) + 512;
|
|
|
|
int dout_mobj_size = spdk_get_data_out_buffer_size() +
|
|
|
|
sizeof(struct spdk_mobj) + 512;
|
|
|
|
|
|
|
|
/* create PDU pool */
|
|
|
|
iscsi->pdu_pool = rte_mempool_create("PDU_Pool",
|
|
|
|
PDU_POOL_SIZE(iscsi),
|
|
|
|
sizeof(struct spdk_iscsi_pdu),
|
|
|
|
256, 0,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
SOCKET_ID_ANY, 0);
|
|
|
|
if (!iscsi->pdu_pool) {
|
|
|
|
SPDK_ERRLOG("create PDU pool failed\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
iscsi->pdu_immediate_data_pool =
|
|
|
|
rte_mempool_create("PDU_immediate_data_Pool",
|
|
|
|
IMMEDIATE_DATA_POOL_SIZE(iscsi),
|
|
|
|
imm_mobj_size,
|
|
|
|
0, 0, NULL, NULL,
|
|
|
|
spdk_mobj_ctor, NULL,
|
|
|
|
rte_socket_id(), 0);
|
|
|
|
if (!iscsi->pdu_immediate_data_pool) {
|
|
|
|
SPDK_ERRLOG("create PDU 8k pool failed\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
iscsi->pdu_data_out_pool = rte_mempool_create("PDU_data_out_Pool",
|
|
|
|
DATA_OUT_POOL_SIZE(iscsi),
|
|
|
|
dout_mobj_size,
|
|
|
|
0, 0, NULL, NULL,
|
|
|
|
spdk_mobj_ctor, NULL,
|
|
|
|
rte_socket_id(), 0);
|
|
|
|
if (!iscsi->pdu_data_out_pool) {
|
|
|
|
SPDK_ERRLOG("create PDU 64k pool failed\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void spdk_iscsi_sess_ctor(struct rte_mempool *pool, void *arg,
|
|
|
|
void *session_buf, unsigned index)
|
|
|
|
{
|
|
|
|
struct spdk_iscsi_globals *iscsi = arg;
|
|
|
|
struct spdk_iscsi_sess *sess = session_buf;
|
|
|
|
|
|
|
|
iscsi->session[index] = sess;
|
|
|
|
|
|
|
|
/* tsih 0 is reserved, so start tsih values at 1. */
|
|
|
|
sess->tsih = index + 1;
|
|
|
|
}
|
|
|
|
|
iscsi: fix the run out of task pool issue
When performed limitation iSCSI tests, 128 target nodes with 1
connection for each target node, for IO bigger than 256KiB iSCSI
target will report run of out task pool issue sometimes. When
all the iSCSI parameters with default values, each connection
will consume maximum 189 tasks, we hardcoded the task pool with
16384, so 189 * 128 connection will exceed 16384. Increase the
default number from 16384 to 32768 will fix the issue.
With 1MiB block size and queue depth with 128 for each connection,
there will be 64 outstanding iSCSI commands in the iSCSI target,
for Writes, the maximum R2T number is 4, so the maximum tasks for
the 4 R2T is (1 + 16) * 4 = 68, 8KiB for the first burst task, 16
for the data segment. For Reads, the maximum 64 data in segment can
be used as 4 iSCSI Read commands. The rest 56 iSCSI commands will
cost 56 tasks, so the total number is 56 + 64 + 68 = 188, 1 additional
task for NOP task.
Change-Id: I945871cbe3076139f08c2ef647af2d9c84601dcb
Signed-off-by: Changpeng Liu <changpeng.liu@intel.com>
2017-02-23 02:18:30 +00:00
|
|
|
#define DEFAULT_TASK_POOL_SIZE 32768
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
spdk_iscsi_initialize_task_pool(void)
|
|
|
|
{
|
|
|
|
struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
|
|
|
|
|
|
|
|
/* create scsi_task pool */
|
|
|
|
iscsi->task_pool = rte_mempool_create("SCSI_TASK_Pool",
|
|
|
|
DEFAULT_TASK_POOL_SIZE,
|
|
|
|
sizeof(struct spdk_iscsi_task),
|
|
|
|
128, 0,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
SOCKET_ID_ANY, 0);
|
|
|
|
if (!iscsi->task_pool) {
|
|
|
|
SPDK_ERRLOG("create task pool failed\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define SESSION_POOL_SIZE(iscsi) (iscsi->MaxSessions)
|
|
|
|
static int spdk_iscsi_initialize_session_pool(void)
|
|
|
|
{
|
|
|
|
struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
|
|
|
|
|
|
|
|
iscsi->session_pool = rte_mempool_create("Session_Pool",
|
|
|
|
SESSION_POOL_SIZE(iscsi),
|
|
|
|
sizeof(struct spdk_iscsi_sess),
|
|
|
|
0, 0,
|
|
|
|
NULL, NULL,
|
|
|
|
spdk_iscsi_sess_ctor, iscsi,
|
|
|
|
SOCKET_ID_ANY, 0);
|
|
|
|
if (!iscsi->session_pool) {
|
|
|
|
SPDK_ERRLOG("create session pool failed\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
spdk_iscsi_initialize_all_pools(void)
|
|
|
|
{
|
|
|
|
if (spdk_iscsi_initialize_pdu_pool() != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spdk_iscsi_initialize_session_pool() != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spdk_iscsi_initialize_task_pool() != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-08-04 21:46:03 +00:00
|
|
|
/*
|
|
|
|
* Wrapper to provide rte_mempool_avail_count() on older DPDK versions.
|
|
|
|
* Drop this if the minimum DPDK version is raised to at least 16.07.
|
|
|
|
*/
|
|
|
|
#if RTE_VERSION < RTE_VERSION_NUM(16, 7, 0, 1)
|
|
|
|
static unsigned rte_mempool_avail_count(const struct rte_mempool *pool)
|
|
|
|
{
|
|
|
|
return rte_mempool_count(pool);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-08-02 16:34:45 +00:00
|
|
|
static int
|
|
|
|
spdk_iscsi_check_pool(struct rte_mempool *pool, uint32_t count)
|
|
|
|
{
|
2016-08-04 21:46:03 +00:00
|
|
|
if (rte_mempool_avail_count(pool) != count) {
|
|
|
|
SPDK_ERRLOG("rte_mempool_avail_count(%s) == %d, should be %d\n",
|
|
|
|
pool->name, rte_mempool_avail_count(pool), count);
|
2016-08-02 16:34:45 +00:00
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-24 23:10:00 +00:00
|
|
|
static int
|
|
|
|
spdk_iscsi_check_pools(void)
|
2016-08-02 16:34:45 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
|
|
|
|
|
|
|
|
rc += spdk_iscsi_check_pool(iscsi->pdu_pool, PDU_POOL_SIZE(iscsi));
|
|
|
|
rc += spdk_iscsi_check_pool(iscsi->session_pool, SESSION_POOL_SIZE(iscsi));
|
|
|
|
rc += spdk_iscsi_check_pool(iscsi->pdu_immediate_data_pool, IMMEDIATE_DATA_POOL_SIZE(iscsi));
|
|
|
|
rc += spdk_iscsi_check_pool(iscsi->pdu_data_out_pool, DATA_OUT_POOL_SIZE(iscsi));
|
2017-05-24 23:10:00 +00:00
|
|
|
/* TODO: check the task_pool on exit */
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
if (rc == 0) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-24 23:10:00 +00:00
|
|
|
static void
|
|
|
|
spdk_iscsi_free_pools(void)
|
|
|
|
{
|
|
|
|
struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
|
|
|
|
|
|
|
|
rte_mempool_free(iscsi->pdu_pool);
|
|
|
|
rte_mempool_free(iscsi->session_pool);
|
|
|
|
rte_mempool_free(iscsi->pdu_immediate_data_pool);
|
|
|
|
rte_mempool_free(iscsi->pdu_data_out_pool);
|
|
|
|
rte_mempool_free(iscsi->task_pool);
|
|
|
|
}
|
|
|
|
|
2016-08-02 16:34:45 +00:00
|
|
|
void spdk_put_pdu(struct spdk_iscsi_pdu *pdu)
|
|
|
|
{
|
|
|
|
if (!pdu)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pdu->ref--;
|
|
|
|
|
|
|
|
if (pdu->ref < 0) {
|
|
|
|
SPDK_ERRLOG("Negative PDU refcount: %p\n", pdu);
|
|
|
|
pdu->ref = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pdu->ref == 0) {
|
|
|
|
if (pdu->mobj)
|
|
|
|
rte_mempool_put(pdu->mobj->mp, (void *)pdu->mobj);
|
|
|
|
|
2016-10-09 04:31:06 +00:00
|
|
|
if (pdu->data && !pdu->data_from_mempool)
|
2016-08-02 16:34:45 +00:00
|
|
|
free(pdu->data);
|
|
|
|
|
|
|
|
rte_mempool_put(g_spdk_iscsi.pdu_pool, (void *)pdu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-08 17:11:20 +00:00
|
|
|
struct spdk_iscsi_pdu *spdk_get_pdu(void)
|
2016-08-02 16:34:45 +00:00
|
|
|
{
|
|
|
|
struct spdk_iscsi_pdu *pdu;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = rte_mempool_get(g_spdk_iscsi.pdu_pool, (void **)&pdu);
|
|
|
|
if ((rc < 0) || !pdu) {
|
|
|
|
SPDK_ERRLOG("Unable to get PDU\n");
|
2016-11-07 21:03:27 +00:00
|
|
|
abort();
|
2016-08-02 16:34:45 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 17:39:59 +00:00
|
|
|
/* we do not want to zero out the last part of the structure reserved for AHS and sense data */
|
2016-08-02 16:34:45 +00:00
|
|
|
memset(pdu, 0, offsetof(struct spdk_iscsi_pdu, ahs_data));
|
|
|
|
pdu->ref = 1;
|
|
|
|
|
|
|
|
return pdu;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
spdk_iscsi_app_read_parameters(void)
|
|
|
|
{
|
|
|
|
struct spdk_conf_section *sp;
|
|
|
|
const char *ag_tag;
|
|
|
|
const char *val;
|
|
|
|
int ag_tag_i;
|
|
|
|
int MaxSessions;
|
|
|
|
int MaxConnectionsPerSession;
|
|
|
|
int DefaultTime2Wait;
|
|
|
|
int DefaultTime2Retain;
|
|
|
|
int InitialR2T;
|
|
|
|
int ImmediateData;
|
|
|
|
int DataPDUInOrder;
|
|
|
|
int DataSequenceInOrder;
|
|
|
|
int ErrorRecoveryLevel;
|
|
|
|
int timeout;
|
|
|
|
int nopininterval;
|
|
|
|
int rc;
|
|
|
|
int i;
|
|
|
|
int AllowDuplicateIsid;
|
|
|
|
int min_conn_per_core = 0;
|
|
|
|
int conn_idle_interval = 0;
|
2017-03-27 21:53:38 +00:00
|
|
|
unsigned long flush_timeout = 0;
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
/* Process parameters */
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_iscsi_app_read_parameters\n");
|
|
|
|
sp = spdk_conf_find_section(NULL, "iSCSI");
|
|
|
|
if (sp == NULL) {
|
|
|
|
SPDK_ERRLOG("iSCSI config section not found.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
val = spdk_conf_section_get_val(sp, "Comment");
|
|
|
|
if (val != NULL) {
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Comment %s\n", val);
|
|
|
|
}
|
|
|
|
|
|
|
|
val = spdk_conf_section_get_val(sp, "AuthFile");
|
|
|
|
if (val == NULL) {
|
|
|
|
val = SPDK_ISCSI_DEFAULT_AUTHFILE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_spdk_iscsi.authfile = strdup(val);
|
|
|
|
if (!g_spdk_iscsi.authfile) {
|
|
|
|
perror("authfile");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "AuthFile %s\n", g_spdk_iscsi.authfile);
|
|
|
|
|
|
|
|
/* ISCSI Global */
|
|
|
|
val = spdk_conf_section_get_val(sp, "NodeBase");
|
|
|
|
if (val == NULL) {
|
|
|
|
val = SPDK_ISCSI_DEFAULT_NODEBASE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_spdk_iscsi.nodebase = strdup(val);
|
|
|
|
if (!g_spdk_iscsi.nodebase) {
|
|
|
|
perror("nodebase");
|
|
|
|
free(g_spdk_iscsi.authfile);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "NodeBase %s\n",
|
|
|
|
g_spdk_iscsi.nodebase);
|
|
|
|
|
|
|
|
MaxSessions = spdk_conf_section_get_intval(sp, "MaxSessions");
|
|
|
|
if (MaxSessions < 1) {
|
|
|
|
MaxSessions = DEFAULT_MAX_SESSIONS;
|
|
|
|
} else if (MaxSessions > 0xffff) {
|
|
|
|
/* limited to 16bits - RFC3720(12.2) */
|
|
|
|
SPDK_ERRLOG("over 65535 sessions are not supported\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
g_spdk_iscsi.MaxSessions = MaxSessions;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxSessions %d\n", g_spdk_iscsi.MaxSessions);
|
|
|
|
|
2017-05-25 18:21:30 +00:00
|
|
|
g_spdk_iscsi.session = spdk_dma_zmalloc(sizeof(void *) * g_spdk_iscsi.MaxSessions, 0, NULL);
|
2016-08-02 16:34:45 +00:00
|
|
|
if (!g_spdk_iscsi.session) {
|
|
|
|
perror("Unable to allocate session pointer array\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
MaxConnectionsPerSession = spdk_conf_section_get_intval(sp, "MaxConnectionsPerSession");
|
|
|
|
if (MaxConnectionsPerSession < 1) {
|
|
|
|
MaxConnectionsPerSession = DEFAULT_MAX_CONNECTIONS_PER_SESSION;
|
|
|
|
}
|
|
|
|
g_spdk_iscsi.MaxConnectionsPerSession = MaxConnectionsPerSession;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxConnectionsPerSession %d\n",
|
|
|
|
g_spdk_iscsi.MaxConnectionsPerSession);
|
|
|
|
|
|
|
|
if (MaxConnectionsPerSession > 0xffff) {
|
|
|
|
SPDK_ERRLOG("over 65535 connections are not supported\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For now, just support same number of total connections, rather
|
|
|
|
* than MaxSessions * MaxConnectionsPerSession. After we add better
|
|
|
|
* handling for low resource conditions from our various buffer
|
|
|
|
* pools, we can bump this up to support more connections.
|
|
|
|
*/
|
|
|
|
g_spdk_iscsi.MaxConnections = g_spdk_iscsi.MaxSessions;
|
|
|
|
|
|
|
|
DefaultTime2Wait = spdk_conf_section_get_intval(sp, "DefaultTime2Wait");
|
|
|
|
if (DefaultTime2Wait < 0) {
|
|
|
|
DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT;
|
|
|
|
}
|
|
|
|
g_spdk_iscsi.DefaultTime2Wait = DefaultTime2Wait;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "DefaultTime2Wait %d\n",
|
|
|
|
g_spdk_iscsi.DefaultTime2Wait);
|
|
|
|
|
|
|
|
DefaultTime2Retain = spdk_conf_section_get_intval(sp, "DefaultTime2Retain");
|
|
|
|
if (DefaultTime2Retain < 0) {
|
|
|
|
DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
|
|
|
|
}
|
|
|
|
g_spdk_iscsi.DefaultTime2Retain = DefaultTime2Retain;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "DefaultTime2Retain %d\n",
|
|
|
|
g_spdk_iscsi.DefaultTime2Retain);
|
|
|
|
|
|
|
|
/* check size limit - RFC3720(12.15, 12.16, 12.17) */
|
|
|
|
if (g_spdk_iscsi.MaxOutstandingR2T > 65535) {
|
|
|
|
SPDK_ERRLOG("MaxOutstandingR2T(%d) > 65535\n", g_spdk_iscsi.MaxOutstandingR2T);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (g_spdk_iscsi.DefaultTime2Wait > 3600) {
|
|
|
|
SPDK_ERRLOG("DefaultTime2Wait(%d) > 3600\n", g_spdk_iscsi.DefaultTime2Wait);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (g_spdk_iscsi.DefaultTime2Retain > 3600) {
|
|
|
|
SPDK_ERRLOG("DefaultTime2Retain(%d) > 3600\n", g_spdk_iscsi.DefaultTime2Retain);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_spdk_iscsi.FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "FirstBurstLength %d\n",
|
|
|
|
g_spdk_iscsi.FirstBurstLength);
|
|
|
|
|
|
|
|
g_spdk_iscsi.MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxBurstLength %d\n",
|
|
|
|
g_spdk_iscsi.MaxBurstLength);
|
|
|
|
|
|
|
|
g_spdk_iscsi.MaxRecvDataSegmentLength = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxRecvDataSegmentLength %d\n",
|
|
|
|
g_spdk_iscsi.MaxRecvDataSegmentLength);
|
|
|
|
|
|
|
|
/* check size limit (up to 24bits - RFC3720(12.12)) */
|
|
|
|
if (g_spdk_iscsi.MaxBurstLength < 512) {
|
|
|
|
SPDK_ERRLOG("MaxBurstLength(%d) < 512\n", g_spdk_iscsi.MaxBurstLength);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (g_spdk_iscsi.FirstBurstLength < 512) {
|
|
|
|
SPDK_ERRLOG("FirstBurstLength(%d) < 512\n", g_spdk_iscsi.FirstBurstLength);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (g_spdk_iscsi.FirstBurstLength > g_spdk_iscsi.MaxBurstLength) {
|
|
|
|
SPDK_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n",
|
|
|
|
g_spdk_iscsi.FirstBurstLength, g_spdk_iscsi.MaxBurstLength);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (g_spdk_iscsi.MaxBurstLength > 0x00ffffff) {
|
|
|
|
SPDK_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n", g_spdk_iscsi.MaxBurstLength);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
val = spdk_conf_section_get_val(sp, "InitialR2T");
|
|
|
|
if (val == NULL) {
|
|
|
|
InitialR2T = DEFAULT_INITIALR2T;
|
|
|
|
} else if (strcasecmp(val, "Yes") == 0) {
|
|
|
|
InitialR2T = 1;
|
|
|
|
} else if (strcasecmp(val, "No") == 0) {
|
|
|
|
#if 0
|
|
|
|
InitialR2T = 0;
|
|
|
|
#else
|
|
|
|
SPDK_ERRLOG("not supported value %s\n", val);
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
SPDK_ERRLOG("unknown value %s\n", val);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
g_spdk_iscsi.InitialR2T = InitialR2T;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "InitialR2T %s\n",
|
|
|
|
g_spdk_iscsi.InitialR2T ? "Yes" : "No");
|
|
|
|
|
|
|
|
val = spdk_conf_section_get_val(sp, "ImmediateData");
|
|
|
|
if (val == NULL) {
|
|
|
|
ImmediateData = DEFAULT_IMMEDIATEDATA;
|
|
|
|
} else if (strcasecmp(val, "Yes") == 0) {
|
|
|
|
ImmediateData = 1;
|
|
|
|
} else if (strcasecmp(val, "No") == 0) {
|
|
|
|
ImmediateData = 0;
|
|
|
|
} else {
|
|
|
|
SPDK_ERRLOG("unknown value %s\n", val);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
g_spdk_iscsi.ImmediateData = ImmediateData;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "ImmediateData %s\n",
|
|
|
|
g_spdk_iscsi.ImmediateData ? "Yes" : "No");
|
|
|
|
|
|
|
|
val = spdk_conf_section_get_val(sp, "DataPDUInOrder");
|
|
|
|
if (val == NULL) {
|
|
|
|
DataPDUInOrder = DEFAULT_DATAPDUINORDER;
|
|
|
|
} else if (strcasecmp(val, "Yes") == 0) {
|
|
|
|
DataPDUInOrder = 1;
|
|
|
|
} else if (strcasecmp(val, "No") == 0) {
|
|
|
|
#if 0
|
|
|
|
DataPDUInOrder = 0;
|
|
|
|
#else
|
|
|
|
SPDK_ERRLOG("not supported value %s\n", val);
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
SPDK_ERRLOG("unknown value %s\n", val);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
g_spdk_iscsi.DataPDUInOrder = DataPDUInOrder;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "DataPDUInOrder %s\n",
|
|
|
|
g_spdk_iscsi.DataPDUInOrder ? "Yes" : "No");
|
|
|
|
|
|
|
|
/* This option is only for test.
|
|
|
|
* If AllowDuplicateIsid is enabled, it allows different connections carrying
|
|
|
|
* TSIH=0 login the target within the same session.
|
|
|
|
*/
|
|
|
|
val = spdk_conf_section_get_val(sp, "AllowDuplicateIsid");
|
|
|
|
if (val == NULL) {
|
|
|
|
AllowDuplicateIsid = 0;
|
|
|
|
} else if (strcasecmp(val, "Yes") == 0) {
|
|
|
|
AllowDuplicateIsid = 1;
|
|
|
|
} else if (strcasecmp(val, "No") == 0) {
|
|
|
|
AllowDuplicateIsid = 0;
|
|
|
|
} else {
|
|
|
|
SPDK_ERRLOG("unknown value %s\n", val);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
g_spdk_iscsi.AllowDuplicateIsid = AllowDuplicateIsid;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "AllowDuplicateIsid %s\n",
|
|
|
|
g_spdk_iscsi.AllowDuplicateIsid ? "Yes" : "No");
|
|
|
|
|
|
|
|
val = spdk_conf_section_get_val(sp, "DataSequenceInOrder");
|
|
|
|
if (val == NULL) {
|
|
|
|
DataSequenceInOrder = DEFAULT_DATASEQUENCEINORDER;
|
|
|
|
} else if (strcasecmp(val, "Yes") == 0) {
|
|
|
|
DataSequenceInOrder = 1;
|
|
|
|
} else if (strcasecmp(val, "No") == 0) {
|
|
|
|
#if 0
|
|
|
|
DataSequenceInOrder = 0;
|
|
|
|
#else
|
|
|
|
SPDK_ERRLOG("not supported value %s\n", val);
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
SPDK_ERRLOG("unknown value %s\n", val);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
g_spdk_iscsi.DataSequenceInOrder = DataSequenceInOrder;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "DataSequenceInOrder %s\n",
|
|
|
|
g_spdk_iscsi.DataSequenceInOrder ? "Yes" : "No");
|
|
|
|
|
|
|
|
ErrorRecoveryLevel = spdk_conf_section_get_intval(sp, "ErrorRecoveryLevel");
|
|
|
|
if (ErrorRecoveryLevel < 0) {
|
|
|
|
ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL;
|
|
|
|
} else if (ErrorRecoveryLevel > 2) {
|
|
|
|
SPDK_ERRLOG("ErrorRecoveryLevel %d not supported,\n", ErrorRecoveryLevel);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
g_spdk_iscsi.ErrorRecoveryLevel = ErrorRecoveryLevel;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "ErrorRecoveryLevel %d\n",
|
|
|
|
g_spdk_iscsi.ErrorRecoveryLevel);
|
|
|
|
|
|
|
|
timeout = spdk_conf_section_get_intval(sp, "Timeout");
|
|
|
|
if (timeout < 0) {
|
|
|
|
timeout = DEFAULT_TIMEOUT;
|
|
|
|
}
|
|
|
|
g_spdk_iscsi.timeout = timeout;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Timeout %d\n",
|
|
|
|
g_spdk_iscsi.timeout);
|
|
|
|
|
|
|
|
val = spdk_conf_section_get_val(sp, "FlushTimeout");
|
2017-03-27 21:53:38 +00:00
|
|
|
if (val) {
|
|
|
|
flush_timeout = strtoul(val, NULL, 10);
|
|
|
|
}
|
|
|
|
if (flush_timeout == 0) {
|
|
|
|
flush_timeout = DEFAULT_FLUSH_TIMEOUT;
|
2016-08-02 16:34:45 +00:00
|
|
|
}
|
2017-03-27 21:53:38 +00:00
|
|
|
g_spdk_iscsi.flush_timeout = flush_timeout * (spdk_get_ticks_hz() >> 20);
|
2016-08-08 17:41:09 +00:00
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "FlushTimeout %"PRIu64"\n", g_spdk_iscsi.flush_timeout);
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
nopininterval = spdk_conf_section_get_intval(sp, "NopInInterval");
|
|
|
|
if (nopininterval < 0) {
|
|
|
|
nopininterval = DEFAULT_NOPININTERVAL;
|
|
|
|
}
|
|
|
|
if (nopininterval > MAX_NOPININTERVAL) {
|
|
|
|
SPDK_ERRLOG("%d NopInInterval too big, using %d instead.\n",
|
|
|
|
nopininterval, DEFAULT_NOPININTERVAL);
|
|
|
|
nopininterval = DEFAULT_NOPININTERVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_spdk_iscsi.nopininterval = nopininterval;
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "NopInInterval %d\n",
|
|
|
|
g_spdk_iscsi.nopininterval);
|
|
|
|
|
|
|
|
val = spdk_conf_section_get_val(sp, "DiscoveryAuthMethod");
|
|
|
|
if (val == NULL) {
|
|
|
|
g_spdk_iscsi.no_discovery_auth = 0;
|
|
|
|
g_spdk_iscsi.req_discovery_auth = 0;
|
|
|
|
g_spdk_iscsi.req_discovery_auth_mutual = 0;
|
|
|
|
} else {
|
|
|
|
g_spdk_iscsi.no_discovery_auth = 0;
|
|
|
|
for (i = 0; ; i++) {
|
|
|
|
val = spdk_conf_section_get_nmval(sp, "DiscoveryAuthMethod", 0, i);
|
|
|
|
if (val == NULL)
|
|
|
|
break;
|
|
|
|
if (strcasecmp(val, "CHAP") == 0) {
|
|
|
|
g_spdk_iscsi.req_discovery_auth = 1;
|
|
|
|
} else if (strcasecmp(val, "Mutual") == 0) {
|
|
|
|
g_spdk_iscsi.req_discovery_auth_mutual = 1;
|
|
|
|
} else if (strcasecmp(val, "Auto") == 0) {
|
|
|
|
g_spdk_iscsi.req_discovery_auth = 0;
|
|
|
|
g_spdk_iscsi.req_discovery_auth_mutual = 0;
|
|
|
|
} else if (strcasecmp(val, "None") == 0) {
|
|
|
|
g_spdk_iscsi.no_discovery_auth = 1;
|
|
|
|
g_spdk_iscsi.req_discovery_auth = 0;
|
|
|
|
g_spdk_iscsi.req_discovery_auth_mutual = 0;
|
|
|
|
} else {
|
|
|
|
SPDK_ERRLOG("unknown auth\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (g_spdk_iscsi.req_discovery_auth_mutual && !g_spdk_iscsi.req_discovery_auth) {
|
|
|
|
SPDK_ERRLOG("Mutual but not CHAP\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (g_spdk_iscsi.no_discovery_auth != 0) {
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG,
|
|
|
|
"DiscoveryAuthMethod None\n");
|
|
|
|
} else if (g_spdk_iscsi.req_discovery_auth == 0) {
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG,
|
|
|
|
"DiscoveryAuthMethod Auto\n");
|
|
|
|
} else {
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG,
|
|
|
|
"DiscoveryAuthMethod %s %s\n",
|
|
|
|
g_spdk_iscsi.req_discovery_auth ? "CHAP" : "",
|
|
|
|
g_spdk_iscsi.req_discovery_auth_mutual ? "Mutual" : "");
|
|
|
|
}
|
|
|
|
|
|
|
|
val = spdk_conf_section_get_val(sp, "DiscoveryAuthGroup");
|
|
|
|
if (val == NULL) {
|
|
|
|
g_spdk_iscsi.discovery_auth_group = 0;
|
|
|
|
} else {
|
|
|
|
ag_tag = val;
|
|
|
|
if (strcasecmp(ag_tag, "None") == 0) {
|
|
|
|
ag_tag_i = 0;
|
|
|
|
} else {
|
|
|
|
if (strncasecmp(ag_tag, "AuthGroup",
|
|
|
|
strlen("AuthGroup")) != 0
|
|
|
|
|| sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1) {
|
|
|
|
SPDK_ERRLOG("auth group error\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (ag_tag_i == 0) {
|
|
|
|
SPDK_ERRLOG("invalid auth group %d\n", ag_tag_i);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_spdk_iscsi.discovery_auth_group = ag_tag_i;
|
|
|
|
}
|
|
|
|
if (g_spdk_iscsi.discovery_auth_group == 0) {
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG,
|
|
|
|
"DiscoveryAuthGroup None\n");
|
|
|
|
} else {
|
|
|
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG,
|
|
|
|
"DiscoveryAuthGroup AuthGroup%d\n",
|
|
|
|
g_spdk_iscsi.discovery_auth_group);
|
|
|
|
}
|
|
|
|
|
|
|
|
min_conn_per_core = spdk_conf_section_get_intval(sp, "MinConnectionsPerCore");
|
|
|
|
if (min_conn_per_core >= 0)
|
|
|
|
spdk_iscsi_conn_set_min_per_core(min_conn_per_core);
|
|
|
|
|
|
|
|
conn_idle_interval = spdk_conf_section_get_intval(sp, "MinConnectionIdleInterval");
|
|
|
|
if (conn_idle_interval > 0)
|
|
|
|
spdk_iscsi_set_min_conn_idle_interval(conn_idle_interval);
|
|
|
|
|
|
|
|
/* portal groups */
|
|
|
|
rc = spdk_iscsi_portal_grp_array_create();
|
|
|
|
if (rc < 0) {
|
|
|
|
SPDK_ERRLOG("spdk_iscsi_portal_grp_array_create() failed\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initiator groups */
|
|
|
|
rc = spdk_iscsi_init_grp_array_create();
|
|
|
|
if (rc < 0) {
|
|
|
|
SPDK_ERRLOG("spdk_iscsi_init_grp_array_create() failed\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = pthread_mutex_init(&g_spdk_iscsi.mutex, NULL);
|
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("mutex_init() failed\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-01-05 01:19:02 +00:00
|
|
|
spdk_iscsi_setup(void *arg1, void *arg2)
|
2016-08-02 16:34:45 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* open portals */
|
|
|
|
rc = spdk_iscsi_portal_grp_open_all();
|
|
|
|
if (rc < 0) {
|
|
|
|
SPDK_ERRLOG("spdk_iscsi_portal_grp_open_all() failed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_iscsi_acceptor_start();
|
|
|
|
}
|
|
|
|
|
2017-06-14 22:59:16 +00:00
|
|
|
int
|
|
|
|
spdk_iscsi_init(void)
|
2016-08-02 16:34:45 +00:00
|
|
|
{
|
2017-06-14 22:59:16 +00:00
|
|
|
int rc;
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
rc = spdk_iscsi_app_read_parameters();
|
|
|
|
if (rc < 0) {
|
|
|
|
SPDK_ERRLOG("spdk_iscsi_app_read_parameters() failed\n");
|
2017-06-14 22:59:16 +00:00
|
|
|
return -1;
|
2016-08-02 16:34:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rc = spdk_iscsi_initialize_all_pools();
|
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("spdk_initialize_all_pools() failed\n");
|
2017-06-14 22:59:16 +00:00
|
|
|
return -1;
|
2016-08-02 16:34:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rc = spdk_iscsi_init_tgt_nodes();
|
|
|
|
if (rc < 0) {
|
|
|
|
SPDK_ERRLOG("spdk_iscsi_init_tgt_nodes() failed\n");
|
2017-06-14 22:59:16 +00:00
|
|
|
return -1;
|
2016-08-02 16:34:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rc = spdk_initialize_iscsi_conns();
|
|
|
|
if (rc < 0) {
|
|
|
|
SPDK_ERRLOG("spdk_initialize_iscsi_conns() failed\n");
|
2017-06-14 22:59:16 +00:00
|
|
|
return -1;
|
2016-08-02 16:34:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2016-10-04 20:23:29 +00:00
|
|
|
* Defer creation of listening sockets until the reactor has started.
|
2016-08-02 16:34:45 +00:00
|
|
|
*/
|
2017-03-27 19:59:40 +00:00
|
|
|
spdk_event_call(spdk_event_allocate(spdk_env_get_current_core(), spdk_iscsi_setup, NULL, NULL));
|
2016-08-02 16:34:45 +00:00
|
|
|
|
2017-06-14 22:59:16 +00:00
|
|
|
return 0;
|
2016-08-02 16:34:45 +00:00
|
|
|
}
|
|
|
|
|
2017-06-13 17:38:16 +00:00
|
|
|
int
|
2017-06-14 22:59:16 +00:00
|
|
|
spdk_iscsi_fini(void)
|
2016-08-02 16:34:45 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = spdk_iscsi_check_pools();
|
2017-05-24 23:10:00 +00:00
|
|
|
spdk_iscsi_free_pools();
|
2016-08-02 16:34:45 +00:00
|
|
|
|
|
|
|
spdk_iscsi_shutdown_tgt_nodes();
|
|
|
|
spdk_iscsi_init_grp_array_destroy();
|
|
|
|
spdk_iscsi_portal_grp_array_destroy();
|
|
|
|
free(g_spdk_iscsi.authfile);
|
|
|
|
free(g_spdk_iscsi.nodebase);
|
|
|
|
|
|
|
|
pthread_mutex_destroy(&g_spdk_iscsi.mutex);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2017-06-13 17:38:16 +00:00
|
|
|
void
|
2016-08-02 16:34:45 +00:00
|
|
|
spdk_iscsi_config_text(FILE *fp)
|
|
|
|
{
|
|
|
|
spdk_iscsi_config_dump_section(fp);
|
|
|
|
spdk_iscsi_config_dump_portal_groups(fp);
|
|
|
|
spdk_iscsi_config_dump_initiator_groups(fp);
|
|
|
|
spdk_iscsi_config_dump_target_nodes(fp);
|
|
|
|
}
|
|
|
|
|
|
|
|
SPDK_LOG_REGISTER_TRACE_FLAG("iscsi", SPDK_TRACE_ISCSI)
|