xref: /spdk/lib/iscsi/iscsi_subsystem.c (revision 179ed697b3c461d100e675915d074be717b7b9cc)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
5  *   Copyright (c) Intel Corporation.
6  *   All rights reserved.
7  *
8  *   Redistribution and use in source and binary forms, with or without
9  *   modification, are permitted provided that the following conditions
10  *   are met:
11  *
12  *     * Redistributions of source code must retain the above copyright
13  *       notice, this list of conditions and the following disclaimer.
14  *     * Redistributions in binary form must reproduce the above copyright
15  *       notice, this list of conditions and the following disclaimer in
16  *       the documentation and/or other materials provided with the
17  *       distribution.
18  *     * Neither the name of Intel Corporation nor the names of its
19  *       contributors may be used to endorse or promote products derived
20  *       from this software without specific prior written permission.
21  *
22  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include "spdk/stdinc.h"
36 
37 #include <rte_config.h>
38 #include <rte_mempool.h>
39 #include <rte_version.h>
40 
41 #include "iscsi/iscsi.h"
42 #include "iscsi/init_grp.h"
43 #include "iscsi/portal_grp.h"
44 #include "iscsi/acceptor.h"
45 #include "iscsi/conn.h"
46 #include "iscsi/task.h"
47 
48 #include "spdk/env.h"
49 
50 #include "spdk_internal/event.h"
51 #include "spdk_internal/log.h"
52 
53 #define ISCSI_CONFIG_TMPL \
54 "[iSCSI]\n" \
55 "  # node name (not include optional part)\n" \
56 "  # Users can optionally change this to fit their environment.\n" \
57 "  NodeBase \"%s\"\n" \
58 "\n" \
59 "  # files\n" \
60 "  AuthFile %s\n" \
61 "\n" \
62 "  # socket I/O timeout sec. (polling is infinity)\n" \
63 "  Timeout %d\n" \
64 "\n" \
65 "  # authentication information for discovery session\n" \
66 "  DiscoveryAuthMethod %s\n" \
67 "  DiscoveryAuthGroup %s\n" \
68 "\n" \
69 "  MaxSessions %d\n" \
70 "  MaxConnectionsPerSession %d\n" \
71 "  MaxConnections %d\n" \
72 "  MaxOutstandingR2T %d\n" \
73 "\n" \
74 "  # iSCSI initial parameters negotiate with initiators\n" \
75 "  # NOTE: incorrect values might crash\n" \
76 "  DefaultTime2Wait %d\n" \
77 "  DefaultTime2Retain %d\n" \
78 "\n" \
79 "  ImmediateData %s\n" \
80 "  DataPDUInOrder %s\n" \
81 "  DataSequenceInOrder %s\n" \
82 "  ErrorRecoveryLevel %d\n" \
83 "\n" \
84 "  # Defines whether iSCSI target will enable configuration via RPC\n" \
85 "  # RpcConfiguration Yes\n" \
86 "\n"
87 
88 static void
89 spdk_iscsi_config_dump_section(FILE *fp)
90 {
91 	const char *authmethod = "None";
92 	char authgroup[32] = "None";
93 
94 	if (NULL == fp)
95 		return;
96 
97 	if (g_spdk_iscsi.req_discovery_auth)
98 		authmethod = "CHAP";
99 	else if (g_spdk_iscsi.req_discovery_auth_mutual)
100 		authmethod = "CHAP Mutual";
101 	else if (!g_spdk_iscsi.no_discovery_auth)
102 		authmethod = "Auto";
103 
104 	if (g_spdk_iscsi.discovery_auth_group)
105 		snprintf(authgroup, sizeof(authgroup), "AuthGroup%d", g_spdk_iscsi.discovery_auth_group);
106 
107 	fprintf(fp, ISCSI_CONFIG_TMPL,
108 		g_spdk_iscsi.nodebase, g_spdk_iscsi.authfile,
109 		g_spdk_iscsi.timeout, authmethod, authgroup,
110 		g_spdk_iscsi.MaxSessions, g_spdk_iscsi.MaxConnectionsPerSession,
111 		g_spdk_iscsi.MaxConnections, g_spdk_iscsi.MaxOutstandingR2T,
112 		g_spdk_iscsi.DefaultTime2Wait, g_spdk_iscsi.DefaultTime2Retain,
113 		(g_spdk_iscsi.ImmediateData == 1) ? "Yes" : "No",
114 		(g_spdk_iscsi.DataPDUInOrder == 1) ? "Yes" : "No",
115 		(g_spdk_iscsi.DataSequenceInOrder == 1) ? "Yes" : "No",
116 		g_spdk_iscsi.ErrorRecoveryLevel);
117 }
118 
119 
120 /* Portal groups */
121 static const char *portal_group_section = \
122 		"\n"
123 		"# Users must change the PortalGroup section(s) to match the IP addresses\n"
124 		"#  for their environment.\n"
125 		"# PortalGroup sections define which TCP ports the iSCSI server will use\n"
126 		"#  to listen for incoming connections.  These are also used to determine\n"
127 		"#  which targets are accessible over each portal group.\n";
128 
129 #define PORTAL_GROUP_TMPL \
130 "[PortalGroup%d]\n" \
131 "  Comment \"Portal%d\"\n"
132 
133 #define PORTAL_TMPL \
134 "  Portal DA1 %s:%s\n"
135 
136 static void
137 spdk_iscsi_config_dump_portal_groups(FILE *fp)
138 {
139 	struct spdk_iscsi_portal *p = NULL;
140 	struct spdk_iscsi_portal_grp *pg = NULL;
141 
142 	/* Create portal group section */
143 	fprintf(fp, "%s", portal_group_section);
144 
145 	/* Dump portal groups */
146 	TAILQ_FOREACH(pg, &g_spdk_iscsi.pg_head, tailq) {
147 		if (NULL == pg) continue;
148 		fprintf(fp, PORTAL_GROUP_TMPL, pg->tag, pg->tag);
149 		/* Dump portals */
150 		TAILQ_FOREACH(p, &pg->head, tailq) {
151 			if (NULL == p) continue;
152 			fprintf(fp, PORTAL_TMPL, p->host, p->port);
153 		}
154 	}
155 }
156 
157 /* Initiator Groups */
158 static const char *initiator_group_section = \
159 		"\n"
160 		"# Users must change the InitiatorGroup section(s) to match the IP\n"
161 		"#  addresses and initiator configuration in their environment.\n"
162 		"# Netmask can be used to specify a single IP address or a range of IP addresses\n"
163 		"#  Netmask 192.168.1.20   <== single IP address\n"
164 		"#  Netmask 192.168.1.0/24 <== IP range 192.168.1.*\n";
165 
166 #define INITIATOR_GROUP_TMPL \
167 "[InitiatorGroup%d]\n" \
168 "  Comment \"Initiator Group%d\"\n"
169 
170 #define INITIATOR_TMPL \
171 "  InitiatorName "
172 
173 #define NETMASK_TMPL \
174 "  Netmask "
175 
176 static void
177 spdk_iscsi_config_dump_initiator_groups(FILE *fp)
178 {
179 	int i;
180 	struct spdk_iscsi_init_grp *ig;
181 
182 	/* Create initiator group section */
183 	fprintf(fp, "%s", initiator_group_section);
184 
185 	/* Dump initiator groups */
186 	TAILQ_FOREACH(ig, &g_spdk_iscsi.ig_head, tailq) {
187 		if (NULL == ig) continue;
188 		fprintf(fp, INITIATOR_GROUP_TMPL, ig->tag, ig->tag);
189 
190 		/* Dump initiators */
191 		fprintf(fp, INITIATOR_TMPL);
192 		for (i = 0; i < ig->ninitiators; i++)
193 			fprintf(fp, "%s ", ig->initiators[i]);
194 		fprintf(fp, "\n");
195 
196 		/* Dump netmasks */
197 		fprintf(fp, NETMASK_TMPL);
198 		for (i = 0; i < ig->nnetmasks; i++)
199 			fprintf(fp, "%s ", ig->netmasks[i]);
200 		fprintf(fp, "\n");
201 	}
202 }
203 
204 /* Target nodes */
205 static const char *target_nodes_section = \
206 		"\n"
207 		"# Users should change the TargetNode section(s) below to match the\n"
208 		"#  desired iSCSI target node configuration.\n"
209 		"# TargetName, Mapping, LUN0 are minimum required\n";
210 
211 #define TARGET_NODE_TMPL \
212 "[TargetNode%d]\n" \
213 "  Comment \"Target%d\"\n" \
214 "  TargetName %s\n" \
215 "  TargetAlias \"%s\"\n"
216 
217 #define TARGET_NODE_PGIG_MAPPING_TMPL \
218 "  Mapping PortalGroup%d InitiatorGroup%d\n"
219 
220 #define TARGET_NODE_AUTH_TMPL \
221 "  AuthMethod %s\n" \
222 "  AuthGroup %s\n" \
223 "  UseDigest %s\n"
224 
225 #define TARGET_NODE_QD_TMPL \
226 "  QueueDepth %d\n\n"
227 
228 #define TARGET_NODE_LUN_TMPL \
229 "  LUN%d %s\n"
230 
231 static void
232 spdk_iscsi_config_dump_target_nodes(FILE *fp)
233 {
234 	int t = 0, l = 0, m = 0;
235 	struct spdk_scsi_dev *dev = NULL;
236 	struct spdk_iscsi_tgt_node *target = NULL;
237 
238 	/* Create target nodes section */
239 	fprintf(fp, "%s", target_nodes_section);
240 
241 	for (t = 0; t < MAX_ISCSI_TARGET_NODE; t++) {
242 		int idx;
243 		const char *authmethod = "None";
244 		char authgroup[32] = "None";
245 		const char *usedigest = "Auto";
246 
247 		target = g_spdk_iscsi.target[t];
248 		if (NULL == target) continue;
249 
250 		dev = target->dev;
251 		if (NULL == dev) continue;
252 
253 		idx = target->num;
254 		fprintf(fp, TARGET_NODE_TMPL, idx, idx, target->name, spdk_scsi_dev_get_name(dev));
255 
256 		for (m = 0; m < target->maxmap; m++) {
257 			if (NULL == target->map[m].pg) continue;
258 			if (NULL == target->map[m].ig) continue;
259 
260 			fprintf(fp, TARGET_NODE_PGIG_MAPPING_TMPL,
261 				target->map[m].pg->tag,
262 				target->map[m].ig->tag);
263 		}
264 
265 		if (target->auth_chap_disabled)
266 			authmethod = "None";
267 		else if (!target->auth_chap_required)
268 			authmethod = "Auto";
269 		else if (target->auth_chap_mutual)
270 			authmethod = "CHAP Mutual";
271 		else
272 			authmethod = "CHAP";
273 
274 		if (target->auth_group > 0)
275 			snprintf(authgroup, sizeof(authgroup), "AuthGroup%d", target->auth_group);
276 
277 		if (target->header_digest)
278 			usedigest = "Header";
279 		else if (target->data_digest)
280 			usedigest = "Data";
281 
282 		fprintf(fp, TARGET_NODE_AUTH_TMPL,
283 			authmethod, authgroup, usedigest);
284 
285 		for (l = 0; l < SPDK_SCSI_DEV_MAX_LUN; l++) {
286 			struct spdk_scsi_lun *lun = spdk_scsi_dev_get_lun(dev, l);
287 
288 			if (!lun) {
289 				continue;
290 			}
291 
292 			fprintf(fp, TARGET_NODE_LUN_TMPL,
293 				spdk_scsi_lun_get_id(lun),
294 				spdk_scsi_lun_get_name(lun));
295 		}
296 
297 		fprintf(fp, TARGET_NODE_QD_TMPL,
298 			target->queue_depth);
299 	}
300 }
301 
302 static void
303 spdk_mobj_ctor(struct rte_mempool *mp, __attribute__((unused)) void *arg,
304 	       void *_m, __attribute__((unused)) unsigned i)
305 {
306 	struct spdk_mobj *m = _m;
307 	uint64_t *phys_addr;
308 	ptrdiff_t off;
309 
310 	m->mp = mp;
311 	m->buf = (uint8_t *)m + sizeof(struct spdk_mobj);
312 	m->buf = (void *)((unsigned long)((uint8_t *)m->buf + 512) & ~511UL);
313 	off = (uint64_t)(uint8_t *)m->buf - (uint64_t)(uint8_t *)m;
314 
315 	/*
316 	 * we store the physical address in a 64bit unsigned integer
317 	 * right before the 512B aligned buffer area.
318 	 */
319 	phys_addr = (uint64_t *)m->buf - 1;
320 	*phys_addr = rte_mempool_virt2phy(mp, m) + off;
321 }
322 
323 #define PDU_POOL_SIZE(iscsi)	(iscsi->MaxConnections * NUM_PDU_PER_CONNECTION)
324 #define IMMEDIATE_DATA_POOL_SIZE(iscsi)	(iscsi->MaxConnections * 128)
325 #define DATA_OUT_POOL_SIZE(iscsi)	(iscsi->MaxConnections * MAX_DATA_OUT_PER_CONNECTION)
326 
327 static int spdk_iscsi_initialize_pdu_pool(void)
328 {
329 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
330 	int imm_mobj_size = spdk_get_immediate_data_buffer_size() +
331 			    sizeof(struct spdk_mobj) + 512;
332 	int dout_mobj_size = spdk_get_data_out_buffer_size() +
333 			     sizeof(struct spdk_mobj) + 512;
334 
335 	/* create PDU pool */
336 	iscsi->pdu_pool = rte_mempool_create("PDU_Pool",
337 					     PDU_POOL_SIZE(iscsi),
338 					     sizeof(struct spdk_iscsi_pdu),
339 					     256, 0,
340 					     NULL, NULL, NULL, NULL,
341 					     SOCKET_ID_ANY, 0);
342 	if (!iscsi->pdu_pool) {
343 		SPDK_ERRLOG("create PDU pool failed\n");
344 		return -1;
345 	}
346 
347 	iscsi->pdu_immediate_data_pool =
348 		rte_mempool_create("PDU_immediate_data_Pool",
349 				   IMMEDIATE_DATA_POOL_SIZE(iscsi),
350 				   imm_mobj_size,
351 				   0, 0, NULL, NULL,
352 				   spdk_mobj_ctor, NULL,
353 				   rte_socket_id(), 0);
354 	if (!iscsi->pdu_immediate_data_pool) {
355 		SPDK_ERRLOG("create PDU 8k pool failed\n");
356 		return -1;
357 	}
358 
359 	iscsi->pdu_data_out_pool = rte_mempool_create("PDU_data_out_Pool",
360 				   DATA_OUT_POOL_SIZE(iscsi),
361 				   dout_mobj_size,
362 				   0, 0, NULL, NULL,
363 				   spdk_mobj_ctor, NULL,
364 				   rte_socket_id(), 0);
365 	if (!iscsi->pdu_data_out_pool) {
366 		SPDK_ERRLOG("create PDU 64k pool failed\n");
367 		return -1;
368 	}
369 
370 	return 0;
371 }
372 
373 static void spdk_iscsi_sess_ctor(struct rte_mempool *pool, void *arg,
374 				 void *session_buf, unsigned index)
375 {
376 	struct spdk_iscsi_globals		*iscsi = arg;
377 	struct spdk_iscsi_sess	*sess = session_buf;
378 
379 	iscsi->session[index] = sess;
380 
381 	/* tsih 0 is reserved, so start tsih values at 1. */
382 	sess->tsih = index + 1;
383 }
384 
385 #define DEFAULT_TASK_POOL_SIZE 32768
386 
387 static int
388 spdk_iscsi_initialize_task_pool(void)
389 {
390 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
391 
392 	/* create scsi_task pool */
393 	iscsi->task_pool = rte_mempool_create("SCSI_TASK_Pool",
394 					      DEFAULT_TASK_POOL_SIZE,
395 					      sizeof(struct spdk_iscsi_task),
396 					      128, 0,
397 					      NULL, NULL, NULL, NULL,
398 					      SOCKET_ID_ANY, 0);
399 	if (!iscsi->task_pool) {
400 		SPDK_ERRLOG("create task pool failed\n");
401 		return -1;
402 	}
403 
404 	return 0;
405 }
406 
407 #define SESSION_POOL_SIZE(iscsi)	(iscsi->MaxSessions)
408 static int spdk_iscsi_initialize_session_pool(void)
409 {
410 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
411 
412 	iscsi->session_pool = rte_mempool_create("Session_Pool",
413 			      SESSION_POOL_SIZE(iscsi),
414 			      sizeof(struct spdk_iscsi_sess),
415 			      0, 0,
416 			      NULL, NULL,
417 			      spdk_iscsi_sess_ctor, iscsi,
418 			      SOCKET_ID_ANY, 0);
419 	if (!iscsi->session_pool) {
420 		SPDK_ERRLOG("create session pool failed\n");
421 		return -1;
422 	}
423 
424 	return 0;
425 }
426 
427 static int
428 spdk_iscsi_initialize_all_pools(void)
429 {
430 	if (spdk_iscsi_initialize_pdu_pool() != 0) {
431 		return -1;
432 	}
433 
434 	if (spdk_iscsi_initialize_session_pool() != 0) {
435 		return -1;
436 	}
437 
438 	if (spdk_iscsi_initialize_task_pool() != 0) {
439 		return -1;
440 	}
441 
442 	return 0;
443 }
444 
445 /*
446  * Wrapper to provide rte_mempool_avail_count() on older DPDK versions.
447  * Drop this if the minimum DPDK version is raised to at least 16.07.
448  */
449 #if RTE_VERSION < RTE_VERSION_NUM(16, 7, 0, 1)
450 static unsigned rte_mempool_avail_count(const struct rte_mempool *pool)
451 {
452 	return rte_mempool_count(pool);
453 }
454 #endif
455 
456 static int
457 spdk_iscsi_check_pool(struct rte_mempool *pool, uint32_t count)
458 {
459 	if (rte_mempool_avail_count(pool) != count) {
460 		SPDK_ERRLOG("rte_mempool_avail_count(%s) == %d, should be %d\n",
461 			    pool->name, rte_mempool_avail_count(pool), count);
462 		return -1;
463 	} else {
464 		return 0;
465 	}
466 }
467 
468 static int
469 spdk_iscsi_check_pools(void)
470 {
471 	int rc = 0;
472 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
473 
474 	rc += spdk_iscsi_check_pool(iscsi->pdu_pool, PDU_POOL_SIZE(iscsi));
475 	rc += spdk_iscsi_check_pool(iscsi->session_pool, SESSION_POOL_SIZE(iscsi));
476 	rc += spdk_iscsi_check_pool(iscsi->pdu_immediate_data_pool, IMMEDIATE_DATA_POOL_SIZE(iscsi));
477 	rc += spdk_iscsi_check_pool(iscsi->pdu_data_out_pool, DATA_OUT_POOL_SIZE(iscsi));
478 	/* TODO: check the task_pool on exit */
479 
480 	if (rc == 0) {
481 		return 0;
482 	} else {
483 		return -1;
484 	}
485 }
486 
487 static void
488 spdk_iscsi_free_pools(void)
489 {
490 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
491 
492 	rte_mempool_free(iscsi->pdu_pool);
493 	rte_mempool_free(iscsi->session_pool);
494 	rte_mempool_free(iscsi->pdu_immediate_data_pool);
495 	rte_mempool_free(iscsi->pdu_data_out_pool);
496 	rte_mempool_free(iscsi->task_pool);
497 }
498 
499 void spdk_put_pdu(struct spdk_iscsi_pdu *pdu)
500 {
501 	if (!pdu)
502 		return;
503 
504 	pdu->ref--;
505 
506 	if (pdu->ref < 0) {
507 		SPDK_ERRLOG("Negative PDU refcount: %p\n", pdu);
508 		pdu->ref = 0;
509 	}
510 
511 	if (pdu->ref == 0) {
512 		if (pdu->mobj)
513 			rte_mempool_put(pdu->mobj->mp, (void *)pdu->mobj);
514 
515 		if (pdu->data && !pdu->data_from_mempool)
516 			free(pdu->data);
517 
518 		rte_mempool_put(g_spdk_iscsi.pdu_pool, (void *)pdu);
519 	}
520 }
521 
522 struct spdk_iscsi_pdu *spdk_get_pdu(void)
523 {
524 	struct spdk_iscsi_pdu *pdu;
525 	int rc;
526 
527 	rc = rte_mempool_get(g_spdk_iscsi.pdu_pool, (void **)&pdu);
528 	if ((rc < 0) || !pdu) {
529 		SPDK_ERRLOG("Unable to get PDU\n");
530 		abort();
531 	}
532 
533 	/* we do not want to zero out the last part of the structure reserved for AHS and sense data */
534 	memset(pdu, 0, offsetof(struct spdk_iscsi_pdu, ahs));
535 	pdu->ref = 1;
536 
537 	return pdu;
538 }
539 
540 static int
541 spdk_iscsi_app_read_parameters(void)
542 {
543 	struct spdk_conf_section *sp;
544 	const char *ag_tag;
545 	const char *val;
546 	int ag_tag_i;
547 	int MaxSessions;
548 	int MaxConnectionsPerSession;
549 	int DefaultTime2Wait;
550 	int DefaultTime2Retain;
551 	int InitialR2T;
552 	int ImmediateData;
553 	int DataPDUInOrder;
554 	int DataSequenceInOrder;
555 	int ErrorRecoveryLevel;
556 	int timeout;
557 	int nopininterval;
558 	int rc;
559 	int i;
560 	int AllowDuplicateIsid;
561 	int min_conn_per_core = 0;
562 	int conn_idle_interval = 0;
563 	unsigned long flush_timeout = 0;
564 
565 	/* Process parameters */
566 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_iscsi_app_read_parameters\n");
567 	sp = spdk_conf_find_section(NULL, "iSCSI");
568 	if (sp == NULL) {
569 		SPDK_ERRLOG("iSCSI config section not found.\n");
570 		return -1;
571 	}
572 
573 	val = spdk_conf_section_get_val(sp, "Comment");
574 	if (val != NULL) {
575 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Comment %s\n", val);
576 	}
577 
578 	val = spdk_conf_section_get_val(sp, "AuthFile");
579 	if (val == NULL) {
580 		val = SPDK_ISCSI_DEFAULT_AUTHFILE;
581 	}
582 
583 	g_spdk_iscsi.authfile = strdup(val);
584 	if (!g_spdk_iscsi.authfile) {
585 		perror("authfile");
586 		return -ENOMEM;
587 	}
588 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "AuthFile %s\n", g_spdk_iscsi.authfile);
589 
590 	/* ISCSI Global */
591 	val = spdk_conf_section_get_val(sp, "NodeBase");
592 	if (val == NULL) {
593 		val = SPDK_ISCSI_DEFAULT_NODEBASE;
594 	}
595 
596 	g_spdk_iscsi.nodebase = strdup(val);
597 	if (!g_spdk_iscsi.nodebase) {
598 		perror("nodebase");
599 		free(g_spdk_iscsi.authfile);
600 		return -ENOMEM;
601 	}
602 
603 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "NodeBase %s\n",
604 		      g_spdk_iscsi.nodebase);
605 
606 	MaxSessions = spdk_conf_section_get_intval(sp, "MaxSessions");
607 	if (MaxSessions < 1) {
608 		MaxSessions = DEFAULT_MAX_SESSIONS;
609 	} else if (MaxSessions > 0xffff) {
610 		/* limited to 16bits - RFC3720(12.2) */
611 		SPDK_ERRLOG("over 65535 sessions are not supported\n");
612 		return -1;
613 	}
614 	g_spdk_iscsi.MaxSessions = MaxSessions;
615 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxSessions %d\n", g_spdk_iscsi.MaxSessions);
616 
617 	g_spdk_iscsi.session = spdk_dma_zmalloc(sizeof(void *) * g_spdk_iscsi.MaxSessions, 0, NULL);
618 	if (!g_spdk_iscsi.session) {
619 		perror("Unable to allocate session pointer array\n");
620 		return -1;
621 	}
622 
623 	MaxConnectionsPerSession = spdk_conf_section_get_intval(sp, "MaxConnectionsPerSession");
624 	if (MaxConnectionsPerSession < 1) {
625 		MaxConnectionsPerSession = DEFAULT_MAX_CONNECTIONS_PER_SESSION;
626 	}
627 	g_spdk_iscsi.MaxConnectionsPerSession = MaxConnectionsPerSession;
628 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxConnectionsPerSession %d\n",
629 		      g_spdk_iscsi.MaxConnectionsPerSession);
630 
631 	if (MaxConnectionsPerSession > 0xffff) {
632 		SPDK_ERRLOG("over 65535 connections are not supported\n");
633 		return -1;
634 	}
635 
636 	/*
637 	 * For now, just support same number of total connections, rather
638 	 *  than MaxSessions * MaxConnectionsPerSession.  After we add better
639 	 *  handling for low resource conditions from our various buffer
640 	 *  pools, we can bump this up to support more connections.
641 	 */
642 	g_spdk_iscsi.MaxConnections = g_spdk_iscsi.MaxSessions;
643 
644 	DefaultTime2Wait = spdk_conf_section_get_intval(sp, "DefaultTime2Wait");
645 	if (DefaultTime2Wait < 0) {
646 		DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT;
647 	}
648 	g_spdk_iscsi.DefaultTime2Wait = DefaultTime2Wait;
649 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "DefaultTime2Wait %d\n",
650 		      g_spdk_iscsi.DefaultTime2Wait);
651 
652 	DefaultTime2Retain = spdk_conf_section_get_intval(sp, "DefaultTime2Retain");
653 	if (DefaultTime2Retain < 0) {
654 		DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
655 	}
656 	g_spdk_iscsi.DefaultTime2Retain = DefaultTime2Retain;
657 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "DefaultTime2Retain %d\n",
658 		      g_spdk_iscsi.DefaultTime2Retain);
659 
660 	/* check size limit - RFC3720(12.15, 12.16, 12.17) */
661 	if (g_spdk_iscsi.MaxOutstandingR2T > 65535) {
662 		SPDK_ERRLOG("MaxOutstandingR2T(%d) > 65535\n", g_spdk_iscsi.MaxOutstandingR2T);
663 		return -1;
664 	}
665 	if (g_spdk_iscsi.DefaultTime2Wait > 3600) {
666 		SPDK_ERRLOG("DefaultTime2Wait(%d) > 3600\n", g_spdk_iscsi.DefaultTime2Wait);
667 		return -1;
668 	}
669 	if (g_spdk_iscsi.DefaultTime2Retain > 3600) {
670 		SPDK_ERRLOG("DefaultTime2Retain(%d) > 3600\n", g_spdk_iscsi.DefaultTime2Retain);
671 		return -1;
672 	}
673 
674 	g_spdk_iscsi.FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
675 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "FirstBurstLength %d\n",
676 		      g_spdk_iscsi.FirstBurstLength);
677 
678 	g_spdk_iscsi.MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH;
679 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxBurstLength %d\n",
680 		      g_spdk_iscsi.MaxBurstLength);
681 
682 	g_spdk_iscsi.MaxRecvDataSegmentLength = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
683 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxRecvDataSegmentLength %d\n",
684 		      g_spdk_iscsi.MaxRecvDataSegmentLength);
685 
686 	/* check size limit (up to 24bits - RFC3720(12.12)) */
687 	if (g_spdk_iscsi.MaxBurstLength < 512) {
688 		SPDK_ERRLOG("MaxBurstLength(%d) < 512\n", g_spdk_iscsi.MaxBurstLength);
689 		return -1;
690 	}
691 	if (g_spdk_iscsi.FirstBurstLength < 512) {
692 		SPDK_ERRLOG("FirstBurstLength(%d) < 512\n", g_spdk_iscsi.FirstBurstLength);
693 		return -1;
694 	}
695 	if (g_spdk_iscsi.FirstBurstLength > g_spdk_iscsi.MaxBurstLength) {
696 		SPDK_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n",
697 			    g_spdk_iscsi.FirstBurstLength, g_spdk_iscsi.MaxBurstLength);
698 		return -1;
699 	}
700 	if (g_spdk_iscsi.MaxBurstLength > 0x00ffffff) {
701 		SPDK_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n", g_spdk_iscsi.MaxBurstLength);
702 		return -1;
703 	}
704 
705 	val = spdk_conf_section_get_val(sp, "InitialR2T");
706 	if (val == NULL) {
707 		InitialR2T = DEFAULT_INITIALR2T;
708 	} else if (strcasecmp(val, "Yes") == 0) {
709 		InitialR2T = 1;
710 	} else if (strcasecmp(val, "No") == 0) {
711 #if 0
712 		InitialR2T = 0;
713 #else
714 		SPDK_ERRLOG("not supported value %s\n", val);
715 		return -1;
716 #endif
717 	} else {
718 		SPDK_ERRLOG("unknown value %s\n", val);
719 		return -1;
720 	}
721 	g_spdk_iscsi.InitialR2T = InitialR2T;
722 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "InitialR2T %s\n",
723 		      g_spdk_iscsi.InitialR2T ? "Yes" : "No");
724 
725 	val = spdk_conf_section_get_val(sp, "ImmediateData");
726 	if (val == NULL) {
727 		ImmediateData = DEFAULT_IMMEDIATEDATA;
728 	} else if (strcasecmp(val, "Yes") == 0) {
729 		ImmediateData = 1;
730 	} else if (strcasecmp(val, "No") == 0) {
731 		ImmediateData = 0;
732 	} else {
733 		SPDK_ERRLOG("unknown value %s\n", val);
734 		return -1;
735 	}
736 	g_spdk_iscsi.ImmediateData = ImmediateData;
737 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "ImmediateData %s\n",
738 		      g_spdk_iscsi.ImmediateData ? "Yes" : "No");
739 
740 	val = spdk_conf_section_get_val(sp, "DataPDUInOrder");
741 	if (val == NULL) {
742 		DataPDUInOrder = DEFAULT_DATAPDUINORDER;
743 	} else if (strcasecmp(val, "Yes") == 0) {
744 		DataPDUInOrder = 1;
745 	} else if (strcasecmp(val, "No") == 0) {
746 #if 0
747 		DataPDUInOrder = 0;
748 #else
749 		SPDK_ERRLOG("not supported value %s\n", val);
750 		return -1;
751 #endif
752 	} else {
753 		SPDK_ERRLOG("unknown value %s\n", val);
754 		return -1;
755 	}
756 	g_spdk_iscsi.DataPDUInOrder = DataPDUInOrder;
757 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "DataPDUInOrder %s\n",
758 		      g_spdk_iscsi.DataPDUInOrder ? "Yes" : "No");
759 
760 	/* This option is only for test.
761 	 * If AllowDuplicateIsid is enabled, it allows different connections carrying
762 	 * TSIH=0 login the target within the same session.
763 	 */
764 	val = spdk_conf_section_get_val(sp, "AllowDuplicateIsid");
765 	if (val == NULL) {
766 		AllowDuplicateIsid = 0;
767 	} else if (strcasecmp(val, "Yes") == 0) {
768 		AllowDuplicateIsid = 1;
769 	} else if (strcasecmp(val, "No") == 0) {
770 		AllowDuplicateIsid = 0;
771 	} else {
772 		SPDK_ERRLOG("unknown value %s\n", val);
773 		return -1;
774 	}
775 	g_spdk_iscsi.AllowDuplicateIsid = AllowDuplicateIsid;
776 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "AllowDuplicateIsid %s\n",
777 		      g_spdk_iscsi.AllowDuplicateIsid ? "Yes" : "No");
778 
779 	val = spdk_conf_section_get_val(sp, "DataSequenceInOrder");
780 	if (val == NULL) {
781 		DataSequenceInOrder = DEFAULT_DATASEQUENCEINORDER;
782 	} else if (strcasecmp(val, "Yes") == 0) {
783 		DataSequenceInOrder = 1;
784 	} else if (strcasecmp(val, "No") == 0) {
785 #if 0
786 		DataSequenceInOrder = 0;
787 #else
788 		SPDK_ERRLOG("not supported value %s\n", val);
789 		return -1;
790 #endif
791 	} else {
792 		SPDK_ERRLOG("unknown value %s\n", val);
793 		return -1;
794 	}
795 	g_spdk_iscsi.DataSequenceInOrder = DataSequenceInOrder;
796 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "DataSequenceInOrder %s\n",
797 		      g_spdk_iscsi.DataSequenceInOrder ? "Yes" : "No");
798 
799 	ErrorRecoveryLevel = spdk_conf_section_get_intval(sp, "ErrorRecoveryLevel");
800 	if (ErrorRecoveryLevel < 0) {
801 		ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL;
802 	} else if (ErrorRecoveryLevel > 2) {
803 		SPDK_ERRLOG("ErrorRecoveryLevel %d not supported,\n", ErrorRecoveryLevel);
804 		return -1;
805 	}
806 	g_spdk_iscsi.ErrorRecoveryLevel = ErrorRecoveryLevel;
807 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "ErrorRecoveryLevel %d\n",
808 		      g_spdk_iscsi.ErrorRecoveryLevel);
809 
810 	timeout = spdk_conf_section_get_intval(sp, "Timeout");
811 	if (timeout < 0) {
812 		timeout = DEFAULT_TIMEOUT;
813 	}
814 	g_spdk_iscsi.timeout = timeout;
815 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Timeout %d\n",
816 		      g_spdk_iscsi.timeout);
817 
818 	val = spdk_conf_section_get_val(sp, "FlushTimeout");
819 	if (val) {
820 		flush_timeout = strtoul(val, NULL, 10);
821 	}
822 	if (flush_timeout == 0) {
823 		flush_timeout = DEFAULT_FLUSH_TIMEOUT;
824 	}
825 	g_spdk_iscsi.flush_timeout = flush_timeout * (spdk_get_ticks_hz() >> 20);
826 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "FlushTimeout %"PRIu64"\n", g_spdk_iscsi.flush_timeout);
827 
828 	nopininterval = spdk_conf_section_get_intval(sp, "NopInInterval");
829 	if (nopininterval < 0) {
830 		nopininterval = DEFAULT_NOPININTERVAL;
831 	}
832 	if (nopininterval > MAX_NOPININTERVAL) {
833 		SPDK_ERRLOG("%d NopInInterval too big, using %d instead.\n",
834 			    nopininterval, DEFAULT_NOPININTERVAL);
835 		nopininterval = DEFAULT_NOPININTERVAL;
836 	}
837 
838 	g_spdk_iscsi.nopininterval = nopininterval;
839 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "NopInInterval %d\n",
840 		      g_spdk_iscsi.nopininterval);
841 
842 	val = spdk_conf_section_get_val(sp, "DiscoveryAuthMethod");
843 	if (val == NULL) {
844 		g_spdk_iscsi.no_discovery_auth = 0;
845 		g_spdk_iscsi.req_discovery_auth = 0;
846 		g_spdk_iscsi.req_discovery_auth_mutual = 0;
847 	} else {
848 		g_spdk_iscsi.no_discovery_auth = 0;
849 		for (i = 0; ; i++) {
850 			val = spdk_conf_section_get_nmval(sp, "DiscoveryAuthMethod", 0, i);
851 			if (val == NULL)
852 				break;
853 			if (strcasecmp(val, "CHAP") == 0) {
854 				g_spdk_iscsi.req_discovery_auth = 1;
855 			} else if (strcasecmp(val, "Mutual") == 0) {
856 				g_spdk_iscsi.req_discovery_auth_mutual = 1;
857 			} else if (strcasecmp(val, "Auto") == 0) {
858 				g_spdk_iscsi.req_discovery_auth = 0;
859 				g_spdk_iscsi.req_discovery_auth_mutual = 0;
860 			} else if (strcasecmp(val, "None") == 0) {
861 				g_spdk_iscsi.no_discovery_auth = 1;
862 				g_spdk_iscsi.req_discovery_auth = 0;
863 				g_spdk_iscsi.req_discovery_auth_mutual = 0;
864 			} else {
865 				SPDK_ERRLOG("unknown auth\n");
866 				return -1;
867 			}
868 		}
869 		if (g_spdk_iscsi.req_discovery_auth_mutual && !g_spdk_iscsi.req_discovery_auth) {
870 			SPDK_ERRLOG("Mutual but not CHAP\n");
871 			return -1;
872 		}
873 	}
874 	if (g_spdk_iscsi.no_discovery_auth != 0) {
875 		SPDK_TRACELOG(SPDK_TRACE_DEBUG,
876 			      "DiscoveryAuthMethod None\n");
877 	} else if (g_spdk_iscsi.req_discovery_auth == 0) {
878 		SPDK_TRACELOG(SPDK_TRACE_DEBUG,
879 			      "DiscoveryAuthMethod Auto\n");
880 	} else {
881 		SPDK_TRACELOG(SPDK_TRACE_DEBUG,
882 			      "DiscoveryAuthMethod %s %s\n",
883 			      g_spdk_iscsi.req_discovery_auth ? "CHAP" : "",
884 			      g_spdk_iscsi.req_discovery_auth_mutual ? "Mutual" : "");
885 	}
886 
887 	val = spdk_conf_section_get_val(sp, "DiscoveryAuthGroup");
888 	if (val == NULL) {
889 		g_spdk_iscsi.discovery_auth_group = 0;
890 	} else {
891 		ag_tag = val;
892 		if (strcasecmp(ag_tag, "None") == 0) {
893 			ag_tag_i = 0;
894 		} else {
895 			if (strncasecmp(ag_tag, "AuthGroup",
896 					strlen("AuthGroup")) != 0
897 			    || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1) {
898 				SPDK_ERRLOG("auth group error\n");
899 				return -1;
900 			}
901 			if (ag_tag_i == 0) {
902 				SPDK_ERRLOG("invalid auth group %d\n", ag_tag_i);
903 				return -1;
904 			}
905 		}
906 		g_spdk_iscsi.discovery_auth_group = ag_tag_i;
907 	}
908 	if (g_spdk_iscsi.discovery_auth_group == 0) {
909 		SPDK_TRACELOG(SPDK_TRACE_DEBUG,
910 			      "DiscoveryAuthGroup None\n");
911 	} else {
912 		SPDK_TRACELOG(SPDK_TRACE_DEBUG,
913 			      "DiscoveryAuthGroup AuthGroup%d\n",
914 			      g_spdk_iscsi.discovery_auth_group);
915 	}
916 
917 	min_conn_per_core = spdk_conf_section_get_intval(sp, "MinConnectionsPerCore");
918 	if (min_conn_per_core >= 0)
919 		spdk_iscsi_conn_set_min_per_core(min_conn_per_core);
920 
921 	conn_idle_interval = spdk_conf_section_get_intval(sp, "MinConnectionIdleInterval");
922 	if (conn_idle_interval > 0)
923 		spdk_iscsi_set_min_conn_idle_interval(conn_idle_interval);
924 
925 	/* portal groups */
926 	rc = spdk_iscsi_portal_grp_array_create();
927 	if (rc < 0) {
928 		SPDK_ERRLOG("spdk_iscsi_portal_grp_array_create() failed\n");
929 		return -1;
930 	}
931 
932 	/* initiator groups */
933 	rc = spdk_iscsi_init_grp_array_create();
934 	if (rc < 0) {
935 		SPDK_ERRLOG("spdk_iscsi_init_grp_array_create() failed\n");
936 		return -1;
937 	}
938 
939 	rc = pthread_mutex_init(&g_spdk_iscsi.mutex, NULL);
940 	if (rc != 0) {
941 		SPDK_ERRLOG("mutex_init() failed\n");
942 		return -1;
943 	}
944 
945 	return 0;
946 }
947 
948 static void
949 spdk_iscsi_setup(void *arg1, void *arg2)
950 {
951 	int rc;
952 
953 	/* open portals */
954 	rc = spdk_iscsi_portal_grp_open_all();
955 	if (rc < 0) {
956 		SPDK_ERRLOG("spdk_iscsi_portal_grp_open_all() failed\n");
957 		return;
958 	}
959 
960 	spdk_iscsi_acceptor_start();
961 }
962 
963 int
964 spdk_iscsi_init(void)
965 {
966 	int rc;
967 
968 	rc = spdk_iscsi_app_read_parameters();
969 	if (rc < 0) {
970 		SPDK_ERRLOG("spdk_iscsi_app_read_parameters() failed\n");
971 		return -1;
972 	}
973 
974 	rc = spdk_iscsi_initialize_all_pools();
975 	if (rc != 0) {
976 		SPDK_ERRLOG("spdk_initialize_all_pools() failed\n");
977 		return -1;
978 	}
979 
980 	rc = spdk_iscsi_init_tgt_nodes();
981 	if (rc < 0) {
982 		SPDK_ERRLOG("spdk_iscsi_init_tgt_nodes() failed\n");
983 		return -1;
984 	}
985 
986 	rc = spdk_initialize_iscsi_conns();
987 	if (rc < 0) {
988 		SPDK_ERRLOG("spdk_initialize_iscsi_conns() failed\n");
989 		return -1;
990 	}
991 
992 	/*
993 	 * Defer creation of listening sockets until the reactor has started.
994 	 */
995 	spdk_event_call(spdk_event_allocate(spdk_env_get_current_core(), spdk_iscsi_setup, NULL, NULL));
996 
997 	return 0;
998 }
999 
1000 int
1001 spdk_iscsi_fini(void)
1002 {
1003 	int rc;
1004 
1005 	rc = spdk_iscsi_check_pools();
1006 	spdk_iscsi_free_pools();
1007 
1008 	spdk_iscsi_shutdown_tgt_nodes();
1009 	spdk_iscsi_init_grp_array_destroy();
1010 	spdk_iscsi_portal_grp_array_destroy();
1011 	free(g_spdk_iscsi.authfile);
1012 	free(g_spdk_iscsi.nodebase);
1013 
1014 	pthread_mutex_destroy(&g_spdk_iscsi.mutex);
1015 
1016 	return rc;
1017 }
1018 
1019 void
1020 spdk_iscsi_config_text(FILE *fp)
1021 {
1022 	spdk_iscsi_config_dump_section(fp);
1023 	spdk_iscsi_config_dump_portal_groups(fp);
1024 	spdk_iscsi_config_dump_initiator_groups(fp);
1025 	spdk_iscsi_config_dump_target_nodes(fp);
1026 }
1027 
1028 SPDK_LOG_REGISTER_TRACE_FLAG("iscsi", SPDK_TRACE_ISCSI)
1029