xref: /spdk/lib/iscsi/iscsi_subsystem.c (revision 043d541132d566d7340d20dbed8da6bae3c1300e)
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 	int maxlun;
236 	struct spdk_scsi_dev *dev = NULL;
237 	struct spdk_iscsi_tgt_node *target = NULL;
238 
239 	/* Create target nodes section */
240 	fprintf(fp, "%s", target_nodes_section);
241 
242 	for (t = 0; t < MAX_ISCSI_TARGET_NODE; t++) {
243 		int idx;
244 		const char *authmethod = "None";
245 		char authgroup[32] = "None";
246 		const char *usedigest = "Auto";
247 
248 		target = g_spdk_iscsi.target[t];
249 		if (NULL == target) continue;
250 
251 		dev = target->dev;
252 		if (NULL == dev) continue;
253 
254 		idx = target->num;
255 		fprintf(fp, TARGET_NODE_TMPL, idx, idx, target->name, spdk_scsi_dev_get_name(dev));
256 
257 		for (m = 0; m < target->maxmap; m++) {
258 			if (NULL == target->map[m].pg) continue;
259 			if (NULL == target->map[m].ig) continue;
260 
261 			fprintf(fp, TARGET_NODE_PGIG_MAPPING_TMPL,
262 				target->map[m].pg->tag,
263 				target->map[m].ig->tag);
264 		}
265 
266 		if (target->auth_chap_disabled)
267 			authmethod = "None";
268 		else if (!target->auth_chap_required)
269 			authmethod = "Auto";
270 		else if (target->auth_chap_mutual)
271 			authmethod = "CHAP Mutual";
272 		else
273 			authmethod = "CHAP";
274 
275 		if (target->auth_group > 0)
276 			snprintf(authgroup, sizeof(authgroup), "AuthGroup%d", target->auth_group);
277 
278 		if (target->header_digest)
279 			usedigest = "Header";
280 		else if (target->data_digest)
281 			usedigest = "Data";
282 
283 		fprintf(fp, TARGET_NODE_AUTH_TMPL,
284 			authmethod, authgroup, usedigest);
285 
286 		maxlun = spdk_scsi_dev_get_max_lun(dev);
287 		for (l = 0; l < maxlun; l++) {
288 			struct spdk_scsi_lun *lun = spdk_scsi_dev_get_lun(dev, l);
289 
290 			if (!lun) {
291 				continue;
292 			}
293 
294 			fprintf(fp, TARGET_NODE_LUN_TMPL,
295 				spdk_scsi_lun_get_id(lun),
296 				spdk_scsi_lun_get_name(lun));
297 		}
298 
299 		fprintf(fp, TARGET_NODE_QD_TMPL,
300 			target->queue_depth);
301 	}
302 }
303 
304 static void
305 spdk_mobj_ctor(struct rte_mempool *mp, __attribute__((unused)) void *arg,
306 	       void *_m, __attribute__((unused)) unsigned i)
307 {
308 	struct spdk_mobj *m = _m;
309 	uint64_t *phys_addr;
310 	ptrdiff_t off;
311 
312 	m->mp = mp;
313 	m->buf = (uint8_t *)m + sizeof(struct spdk_mobj);
314 	m->buf = (void *)((unsigned long)((uint8_t *)m->buf + 512) & ~511UL);
315 	off = (uint64_t)(uint8_t *)m->buf - (uint64_t)(uint8_t *)m;
316 
317 	/*
318 	 * we store the physical address in a 64bit unsigned integer
319 	 * right before the 512B aligned buffer area.
320 	 */
321 	phys_addr = (uint64_t *)m->buf - 1;
322 	*phys_addr = rte_mempool_virt2phy(mp, m) + off;
323 }
324 
325 #define PDU_POOL_SIZE(iscsi)	(iscsi->MaxConnections * NUM_PDU_PER_CONNECTION)
326 #define IMMEDIATE_DATA_POOL_SIZE(iscsi)	(iscsi->MaxConnections * 128)
327 #define DATA_OUT_POOL_SIZE(iscsi)	(iscsi->MaxConnections * MAX_DATA_OUT_PER_CONNECTION)
328 
329 static int spdk_iscsi_initialize_pdu_pool(void)
330 {
331 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
332 	int imm_mobj_size = spdk_get_immediate_data_buffer_size() +
333 			    sizeof(struct spdk_mobj) + 512;
334 	int dout_mobj_size = spdk_get_data_out_buffer_size() +
335 			     sizeof(struct spdk_mobj) + 512;
336 
337 	/* create PDU pool */
338 	iscsi->pdu_pool = rte_mempool_create("PDU_Pool",
339 					     PDU_POOL_SIZE(iscsi),
340 					     sizeof(struct spdk_iscsi_pdu),
341 					     256, 0,
342 					     NULL, NULL, NULL, NULL,
343 					     SOCKET_ID_ANY, 0);
344 	if (!iscsi->pdu_pool) {
345 		SPDK_ERRLOG("create PDU pool failed\n");
346 		return -1;
347 	}
348 
349 	iscsi->pdu_immediate_data_pool =
350 		rte_mempool_create("PDU_immediate_data_Pool",
351 				   IMMEDIATE_DATA_POOL_SIZE(iscsi),
352 				   imm_mobj_size,
353 				   0, 0, NULL, NULL,
354 				   spdk_mobj_ctor, NULL,
355 				   rte_socket_id(), 0);
356 	if (!iscsi->pdu_immediate_data_pool) {
357 		SPDK_ERRLOG("create PDU 8k pool failed\n");
358 		return -1;
359 	}
360 
361 	iscsi->pdu_data_out_pool = rte_mempool_create("PDU_data_out_Pool",
362 				   DATA_OUT_POOL_SIZE(iscsi),
363 				   dout_mobj_size,
364 				   0, 0, NULL, NULL,
365 				   spdk_mobj_ctor, NULL,
366 				   rte_socket_id(), 0);
367 	if (!iscsi->pdu_data_out_pool) {
368 		SPDK_ERRLOG("create PDU 64k pool failed\n");
369 		return -1;
370 	}
371 
372 	return 0;
373 }
374 
375 static void spdk_iscsi_sess_ctor(struct rte_mempool *pool, void *arg,
376 				 void *session_buf, unsigned index)
377 {
378 	struct spdk_iscsi_globals		*iscsi = arg;
379 	struct spdk_iscsi_sess	*sess = session_buf;
380 
381 	iscsi->session[index] = sess;
382 
383 	/* tsih 0 is reserved, so start tsih values at 1. */
384 	sess->tsih = index + 1;
385 }
386 
387 #define DEFAULT_TASK_POOL_SIZE 32768
388 
389 static int
390 spdk_iscsi_initialize_task_pool(void)
391 {
392 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
393 
394 	/* create scsi_task pool */
395 	iscsi->task_pool = rte_mempool_create("SCSI_TASK_Pool",
396 					      DEFAULT_TASK_POOL_SIZE,
397 					      sizeof(struct spdk_iscsi_task),
398 					      128, 0,
399 					      NULL, NULL, NULL, NULL,
400 					      SOCKET_ID_ANY, 0);
401 	if (!iscsi->task_pool) {
402 		SPDK_ERRLOG("create task pool failed\n");
403 		return -1;
404 	}
405 
406 	return 0;
407 }
408 
409 #define SESSION_POOL_SIZE(iscsi)	(iscsi->MaxSessions)
410 static int spdk_iscsi_initialize_session_pool(void)
411 {
412 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
413 
414 	iscsi->session_pool = rte_mempool_create("Session_Pool",
415 			      SESSION_POOL_SIZE(iscsi),
416 			      sizeof(struct spdk_iscsi_sess),
417 			      0, 0,
418 			      NULL, NULL,
419 			      spdk_iscsi_sess_ctor, iscsi,
420 			      SOCKET_ID_ANY, 0);
421 	if (!iscsi->session_pool) {
422 		SPDK_ERRLOG("create session pool failed\n");
423 		return -1;
424 	}
425 
426 	return 0;
427 }
428 
429 static int
430 spdk_iscsi_initialize_all_pools(void)
431 {
432 	if (spdk_iscsi_initialize_pdu_pool() != 0) {
433 		return -1;
434 	}
435 
436 	if (spdk_iscsi_initialize_session_pool() != 0) {
437 		return -1;
438 	}
439 
440 	if (spdk_iscsi_initialize_task_pool() != 0) {
441 		return -1;
442 	}
443 
444 	return 0;
445 }
446 
447 /*
448  * Wrapper to provide rte_mempool_avail_count() on older DPDK versions.
449  * Drop this if the minimum DPDK version is raised to at least 16.07.
450  */
451 #if RTE_VERSION < RTE_VERSION_NUM(16, 7, 0, 1)
452 static unsigned rte_mempool_avail_count(const struct rte_mempool *pool)
453 {
454 	return rte_mempool_count(pool);
455 }
456 #endif
457 
458 static int
459 spdk_iscsi_check_pool(struct rte_mempool *pool, uint32_t count)
460 {
461 	if (rte_mempool_avail_count(pool) != count) {
462 		SPDK_ERRLOG("rte_mempool_avail_count(%s) == %d, should be %d\n",
463 			    pool->name, rte_mempool_avail_count(pool), count);
464 		return -1;
465 	} else {
466 		return 0;
467 	}
468 }
469 
470 static int
471 spdk_iscsi_check_pools(void)
472 {
473 	int rc = 0;
474 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
475 
476 	rc += spdk_iscsi_check_pool(iscsi->pdu_pool, PDU_POOL_SIZE(iscsi));
477 	rc += spdk_iscsi_check_pool(iscsi->session_pool, SESSION_POOL_SIZE(iscsi));
478 	rc += spdk_iscsi_check_pool(iscsi->pdu_immediate_data_pool, IMMEDIATE_DATA_POOL_SIZE(iscsi));
479 	rc += spdk_iscsi_check_pool(iscsi->pdu_data_out_pool, DATA_OUT_POOL_SIZE(iscsi));
480 	/* TODO: check the task_pool on exit */
481 
482 	if (rc == 0) {
483 		return 0;
484 	} else {
485 		return -1;
486 	}
487 }
488 
489 static void
490 spdk_iscsi_free_pools(void)
491 {
492 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
493 
494 	rte_mempool_free(iscsi->pdu_pool);
495 	rte_mempool_free(iscsi->session_pool);
496 	rte_mempool_free(iscsi->pdu_immediate_data_pool);
497 	rte_mempool_free(iscsi->pdu_data_out_pool);
498 	rte_mempool_free(iscsi->task_pool);
499 }
500 
501 void spdk_put_pdu(struct spdk_iscsi_pdu *pdu)
502 {
503 	if (!pdu)
504 		return;
505 
506 	pdu->ref--;
507 
508 	if (pdu->ref < 0) {
509 		SPDK_ERRLOG("Negative PDU refcount: %p\n", pdu);
510 		pdu->ref = 0;
511 	}
512 
513 	if (pdu->ref == 0) {
514 		if (pdu->mobj)
515 			rte_mempool_put(pdu->mobj->mp, (void *)pdu->mobj);
516 
517 		if (pdu->data && !pdu->data_from_mempool)
518 			free(pdu->data);
519 
520 		rte_mempool_put(g_spdk_iscsi.pdu_pool, (void *)pdu);
521 	}
522 }
523 
524 struct spdk_iscsi_pdu *spdk_get_pdu(void)
525 {
526 	struct spdk_iscsi_pdu *pdu;
527 	int rc;
528 
529 	rc = rte_mempool_get(g_spdk_iscsi.pdu_pool, (void **)&pdu);
530 	if ((rc < 0) || !pdu) {
531 		SPDK_ERRLOG("Unable to get PDU\n");
532 		abort();
533 	}
534 
535 	/* we do not want to zero out the last part of the structure reserved for AHS and sense data */
536 	memset(pdu, 0, offsetof(struct spdk_iscsi_pdu, ahs_data));
537 	pdu->ref = 1;
538 
539 	return pdu;
540 }
541 
542 static int
543 spdk_iscsi_app_read_parameters(void)
544 {
545 	struct spdk_conf_section *sp;
546 	const char *ag_tag;
547 	const char *val;
548 	int ag_tag_i;
549 	int MaxSessions;
550 	int MaxConnectionsPerSession;
551 	int DefaultTime2Wait;
552 	int DefaultTime2Retain;
553 	int InitialR2T;
554 	int ImmediateData;
555 	int DataPDUInOrder;
556 	int DataSequenceInOrder;
557 	int ErrorRecoveryLevel;
558 	int timeout;
559 	int nopininterval;
560 	int rc;
561 	int i;
562 	int AllowDuplicateIsid;
563 	int min_conn_per_core = 0;
564 	int conn_idle_interval = 0;
565 	unsigned long flush_timeout = 0;
566 
567 	/* Process parameters */
568 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_iscsi_app_read_parameters\n");
569 	sp = spdk_conf_find_section(NULL, "iSCSI");
570 	if (sp == NULL) {
571 		SPDK_ERRLOG("iSCSI config section not found.\n");
572 		return -1;
573 	}
574 
575 	val = spdk_conf_section_get_val(sp, "Comment");
576 	if (val != NULL) {
577 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Comment %s\n", val);
578 	}
579 
580 	val = spdk_conf_section_get_val(sp, "AuthFile");
581 	if (val == NULL) {
582 		val = SPDK_ISCSI_DEFAULT_AUTHFILE;
583 	}
584 
585 	g_spdk_iscsi.authfile = strdup(val);
586 	if (!g_spdk_iscsi.authfile) {
587 		perror("authfile");
588 		return -ENOMEM;
589 	}
590 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "AuthFile %s\n", g_spdk_iscsi.authfile);
591 
592 	/* ISCSI Global */
593 	val = spdk_conf_section_get_val(sp, "NodeBase");
594 	if (val == NULL) {
595 		val = SPDK_ISCSI_DEFAULT_NODEBASE;
596 	}
597 
598 	g_spdk_iscsi.nodebase = strdup(val);
599 	if (!g_spdk_iscsi.nodebase) {
600 		perror("nodebase");
601 		free(g_spdk_iscsi.authfile);
602 		return -ENOMEM;
603 	}
604 
605 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "NodeBase %s\n",
606 		      g_spdk_iscsi.nodebase);
607 
608 	MaxSessions = spdk_conf_section_get_intval(sp, "MaxSessions");
609 	if (MaxSessions < 1) {
610 		MaxSessions = DEFAULT_MAX_SESSIONS;
611 	} else if (MaxSessions > 0xffff) {
612 		/* limited to 16bits - RFC3720(12.2) */
613 		SPDK_ERRLOG("over 65535 sessions are not supported\n");
614 		return -1;
615 	}
616 	g_spdk_iscsi.MaxSessions = MaxSessions;
617 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxSessions %d\n", g_spdk_iscsi.MaxSessions);
618 
619 	g_spdk_iscsi.session = spdk_dma_zmalloc(sizeof(void *) * g_spdk_iscsi.MaxSessions, 0, NULL);
620 	if (!g_spdk_iscsi.session) {
621 		perror("Unable to allocate session pointer array\n");
622 		return -1;
623 	}
624 
625 	MaxConnectionsPerSession = spdk_conf_section_get_intval(sp, "MaxConnectionsPerSession");
626 	if (MaxConnectionsPerSession < 1) {
627 		MaxConnectionsPerSession = DEFAULT_MAX_CONNECTIONS_PER_SESSION;
628 	}
629 	g_spdk_iscsi.MaxConnectionsPerSession = MaxConnectionsPerSession;
630 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxConnectionsPerSession %d\n",
631 		      g_spdk_iscsi.MaxConnectionsPerSession);
632 
633 	if (MaxConnectionsPerSession > 0xffff) {
634 		SPDK_ERRLOG("over 65535 connections are not supported\n");
635 		return -1;
636 	}
637 
638 	/*
639 	 * For now, just support same number of total connections, rather
640 	 *  than MaxSessions * MaxConnectionsPerSession.  After we add better
641 	 *  handling for low resource conditions from our various buffer
642 	 *  pools, we can bump this up to support more connections.
643 	 */
644 	g_spdk_iscsi.MaxConnections = g_spdk_iscsi.MaxSessions;
645 
646 	DefaultTime2Wait = spdk_conf_section_get_intval(sp, "DefaultTime2Wait");
647 	if (DefaultTime2Wait < 0) {
648 		DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT;
649 	}
650 	g_spdk_iscsi.DefaultTime2Wait = DefaultTime2Wait;
651 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "DefaultTime2Wait %d\n",
652 		      g_spdk_iscsi.DefaultTime2Wait);
653 
654 	DefaultTime2Retain = spdk_conf_section_get_intval(sp, "DefaultTime2Retain");
655 	if (DefaultTime2Retain < 0) {
656 		DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
657 	}
658 	g_spdk_iscsi.DefaultTime2Retain = DefaultTime2Retain;
659 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "DefaultTime2Retain %d\n",
660 		      g_spdk_iscsi.DefaultTime2Retain);
661 
662 	/* check size limit - RFC3720(12.15, 12.16, 12.17) */
663 	if (g_spdk_iscsi.MaxOutstandingR2T > 65535) {
664 		SPDK_ERRLOG("MaxOutstandingR2T(%d) > 65535\n", g_spdk_iscsi.MaxOutstandingR2T);
665 		return -1;
666 	}
667 	if (g_spdk_iscsi.DefaultTime2Wait > 3600) {
668 		SPDK_ERRLOG("DefaultTime2Wait(%d) > 3600\n", g_spdk_iscsi.DefaultTime2Wait);
669 		return -1;
670 	}
671 	if (g_spdk_iscsi.DefaultTime2Retain > 3600) {
672 		SPDK_ERRLOG("DefaultTime2Retain(%d) > 3600\n", g_spdk_iscsi.DefaultTime2Retain);
673 		return -1;
674 	}
675 
676 	g_spdk_iscsi.FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
677 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "FirstBurstLength %d\n",
678 		      g_spdk_iscsi.FirstBurstLength);
679 
680 	g_spdk_iscsi.MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH;
681 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxBurstLength %d\n",
682 		      g_spdk_iscsi.MaxBurstLength);
683 
684 	g_spdk_iscsi.MaxRecvDataSegmentLength = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
685 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "MaxRecvDataSegmentLength %d\n",
686 		      g_spdk_iscsi.MaxRecvDataSegmentLength);
687 
688 	/* check size limit (up to 24bits - RFC3720(12.12)) */
689 	if (g_spdk_iscsi.MaxBurstLength < 512) {
690 		SPDK_ERRLOG("MaxBurstLength(%d) < 512\n", g_spdk_iscsi.MaxBurstLength);
691 		return -1;
692 	}
693 	if (g_spdk_iscsi.FirstBurstLength < 512) {
694 		SPDK_ERRLOG("FirstBurstLength(%d) < 512\n", g_spdk_iscsi.FirstBurstLength);
695 		return -1;
696 	}
697 	if (g_spdk_iscsi.FirstBurstLength > g_spdk_iscsi.MaxBurstLength) {
698 		SPDK_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n",
699 			    g_spdk_iscsi.FirstBurstLength, g_spdk_iscsi.MaxBurstLength);
700 		return -1;
701 	}
702 	if (g_spdk_iscsi.MaxBurstLength > 0x00ffffff) {
703 		SPDK_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n", g_spdk_iscsi.MaxBurstLength);
704 		return -1;
705 	}
706 
707 	val = spdk_conf_section_get_val(sp, "InitialR2T");
708 	if (val == NULL) {
709 		InitialR2T = DEFAULT_INITIALR2T;
710 	} else if (strcasecmp(val, "Yes") == 0) {
711 		InitialR2T = 1;
712 	} else if (strcasecmp(val, "No") == 0) {
713 #if 0
714 		InitialR2T = 0;
715 #else
716 		SPDK_ERRLOG("not supported value %s\n", val);
717 		return -1;
718 #endif
719 	} else {
720 		SPDK_ERRLOG("unknown value %s\n", val);
721 		return -1;
722 	}
723 	g_spdk_iscsi.InitialR2T = InitialR2T;
724 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "InitialR2T %s\n",
725 		      g_spdk_iscsi.InitialR2T ? "Yes" : "No");
726 
727 	val = spdk_conf_section_get_val(sp, "ImmediateData");
728 	if (val == NULL) {
729 		ImmediateData = DEFAULT_IMMEDIATEDATA;
730 	} else if (strcasecmp(val, "Yes") == 0) {
731 		ImmediateData = 1;
732 	} else if (strcasecmp(val, "No") == 0) {
733 		ImmediateData = 0;
734 	} else {
735 		SPDK_ERRLOG("unknown value %s\n", val);
736 		return -1;
737 	}
738 	g_spdk_iscsi.ImmediateData = ImmediateData;
739 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "ImmediateData %s\n",
740 		      g_spdk_iscsi.ImmediateData ? "Yes" : "No");
741 
742 	val = spdk_conf_section_get_val(sp, "DataPDUInOrder");
743 	if (val == NULL) {
744 		DataPDUInOrder = DEFAULT_DATAPDUINORDER;
745 	} else if (strcasecmp(val, "Yes") == 0) {
746 		DataPDUInOrder = 1;
747 	} else if (strcasecmp(val, "No") == 0) {
748 #if 0
749 		DataPDUInOrder = 0;
750 #else
751 		SPDK_ERRLOG("not supported value %s\n", val);
752 		return -1;
753 #endif
754 	} else {
755 		SPDK_ERRLOG("unknown value %s\n", val);
756 		return -1;
757 	}
758 	g_spdk_iscsi.DataPDUInOrder = DataPDUInOrder;
759 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "DataPDUInOrder %s\n",
760 		      g_spdk_iscsi.DataPDUInOrder ? "Yes" : "No");
761 
762 	/* This option is only for test.
763 	 * If AllowDuplicateIsid is enabled, it allows different connections carrying
764 	 * TSIH=0 login the target within the same session.
765 	 */
766 	val = spdk_conf_section_get_val(sp, "AllowDuplicateIsid");
767 	if (val == NULL) {
768 		AllowDuplicateIsid = 0;
769 	} else if (strcasecmp(val, "Yes") == 0) {
770 		AllowDuplicateIsid = 1;
771 	} else if (strcasecmp(val, "No") == 0) {
772 		AllowDuplicateIsid = 0;
773 	} else {
774 		SPDK_ERRLOG("unknown value %s\n", val);
775 		return -1;
776 	}
777 	g_spdk_iscsi.AllowDuplicateIsid = AllowDuplicateIsid;
778 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "AllowDuplicateIsid %s\n",
779 		      g_spdk_iscsi.AllowDuplicateIsid ? "Yes" : "No");
780 
781 	val = spdk_conf_section_get_val(sp, "DataSequenceInOrder");
782 	if (val == NULL) {
783 		DataSequenceInOrder = DEFAULT_DATASEQUENCEINORDER;
784 	} else if (strcasecmp(val, "Yes") == 0) {
785 		DataSequenceInOrder = 1;
786 	} else if (strcasecmp(val, "No") == 0) {
787 #if 0
788 		DataSequenceInOrder = 0;
789 #else
790 		SPDK_ERRLOG("not supported value %s\n", val);
791 		return -1;
792 #endif
793 	} else {
794 		SPDK_ERRLOG("unknown value %s\n", val);
795 		return -1;
796 	}
797 	g_spdk_iscsi.DataSequenceInOrder = DataSequenceInOrder;
798 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "DataSequenceInOrder %s\n",
799 		      g_spdk_iscsi.DataSequenceInOrder ? "Yes" : "No");
800 
801 	ErrorRecoveryLevel = spdk_conf_section_get_intval(sp, "ErrorRecoveryLevel");
802 	if (ErrorRecoveryLevel < 0) {
803 		ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL;
804 	} else if (ErrorRecoveryLevel > 2) {
805 		SPDK_ERRLOG("ErrorRecoveryLevel %d not supported,\n", ErrorRecoveryLevel);
806 		return -1;
807 	}
808 	g_spdk_iscsi.ErrorRecoveryLevel = ErrorRecoveryLevel;
809 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "ErrorRecoveryLevel %d\n",
810 		      g_spdk_iscsi.ErrorRecoveryLevel);
811 
812 	timeout = spdk_conf_section_get_intval(sp, "Timeout");
813 	if (timeout < 0) {
814 		timeout = DEFAULT_TIMEOUT;
815 	}
816 	g_spdk_iscsi.timeout = timeout;
817 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Timeout %d\n",
818 		      g_spdk_iscsi.timeout);
819 
820 	val = spdk_conf_section_get_val(sp, "FlushTimeout");
821 	if (val) {
822 		flush_timeout = strtoul(val, NULL, 10);
823 	}
824 	if (flush_timeout == 0) {
825 		flush_timeout = DEFAULT_FLUSH_TIMEOUT;
826 	}
827 	g_spdk_iscsi.flush_timeout = flush_timeout * (spdk_get_ticks_hz() >> 20);
828 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "FlushTimeout %"PRIu64"\n", g_spdk_iscsi.flush_timeout);
829 
830 	nopininterval = spdk_conf_section_get_intval(sp, "NopInInterval");
831 	if (nopininterval < 0) {
832 		nopininterval = DEFAULT_NOPININTERVAL;
833 	}
834 	if (nopininterval > MAX_NOPININTERVAL) {
835 		SPDK_ERRLOG("%d NopInInterval too big, using %d instead.\n",
836 			    nopininterval, DEFAULT_NOPININTERVAL);
837 		nopininterval = DEFAULT_NOPININTERVAL;
838 	}
839 
840 	g_spdk_iscsi.nopininterval = nopininterval;
841 	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "NopInInterval %d\n",
842 		      g_spdk_iscsi.nopininterval);
843 
844 	val = spdk_conf_section_get_val(sp, "DiscoveryAuthMethod");
845 	if (val == NULL) {
846 		g_spdk_iscsi.no_discovery_auth = 0;
847 		g_spdk_iscsi.req_discovery_auth = 0;
848 		g_spdk_iscsi.req_discovery_auth_mutual = 0;
849 	} else {
850 		g_spdk_iscsi.no_discovery_auth = 0;
851 		for (i = 0; ; i++) {
852 			val = spdk_conf_section_get_nmval(sp, "DiscoveryAuthMethod", 0, i);
853 			if (val == NULL)
854 				break;
855 			if (strcasecmp(val, "CHAP") == 0) {
856 				g_spdk_iscsi.req_discovery_auth = 1;
857 			} else if (strcasecmp(val, "Mutual") == 0) {
858 				g_spdk_iscsi.req_discovery_auth_mutual = 1;
859 			} else if (strcasecmp(val, "Auto") == 0) {
860 				g_spdk_iscsi.req_discovery_auth = 0;
861 				g_spdk_iscsi.req_discovery_auth_mutual = 0;
862 			} else if (strcasecmp(val, "None") == 0) {
863 				g_spdk_iscsi.no_discovery_auth = 1;
864 				g_spdk_iscsi.req_discovery_auth = 0;
865 				g_spdk_iscsi.req_discovery_auth_mutual = 0;
866 			} else {
867 				SPDK_ERRLOG("unknown auth\n");
868 				return -1;
869 			}
870 		}
871 		if (g_spdk_iscsi.req_discovery_auth_mutual && !g_spdk_iscsi.req_discovery_auth) {
872 			SPDK_ERRLOG("Mutual but not CHAP\n");
873 			return -1;
874 		}
875 	}
876 	if (g_spdk_iscsi.no_discovery_auth != 0) {
877 		SPDK_TRACELOG(SPDK_TRACE_DEBUG,
878 			      "DiscoveryAuthMethod None\n");
879 	} else if (g_spdk_iscsi.req_discovery_auth == 0) {
880 		SPDK_TRACELOG(SPDK_TRACE_DEBUG,
881 			      "DiscoveryAuthMethod Auto\n");
882 	} else {
883 		SPDK_TRACELOG(SPDK_TRACE_DEBUG,
884 			      "DiscoveryAuthMethod %s %s\n",
885 			      g_spdk_iscsi.req_discovery_auth ? "CHAP" : "",
886 			      g_spdk_iscsi.req_discovery_auth_mutual ? "Mutual" : "");
887 	}
888 
889 	val = spdk_conf_section_get_val(sp, "DiscoveryAuthGroup");
890 	if (val == NULL) {
891 		g_spdk_iscsi.discovery_auth_group = 0;
892 	} else {
893 		ag_tag = val;
894 		if (strcasecmp(ag_tag, "None") == 0) {
895 			ag_tag_i = 0;
896 		} else {
897 			if (strncasecmp(ag_tag, "AuthGroup",
898 					strlen("AuthGroup")) != 0
899 			    || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1) {
900 				SPDK_ERRLOG("auth group error\n");
901 				return -1;
902 			}
903 			if (ag_tag_i == 0) {
904 				SPDK_ERRLOG("invalid auth group %d\n", ag_tag_i);
905 				return -1;
906 			}
907 		}
908 		g_spdk_iscsi.discovery_auth_group = ag_tag_i;
909 	}
910 	if (g_spdk_iscsi.discovery_auth_group == 0) {
911 		SPDK_TRACELOG(SPDK_TRACE_DEBUG,
912 			      "DiscoveryAuthGroup None\n");
913 	} else {
914 		SPDK_TRACELOG(SPDK_TRACE_DEBUG,
915 			      "DiscoveryAuthGroup AuthGroup%d\n",
916 			      g_spdk_iscsi.discovery_auth_group);
917 	}
918 
919 	min_conn_per_core = spdk_conf_section_get_intval(sp, "MinConnectionsPerCore");
920 	if (min_conn_per_core >= 0)
921 		spdk_iscsi_conn_set_min_per_core(min_conn_per_core);
922 
923 	conn_idle_interval = spdk_conf_section_get_intval(sp, "MinConnectionIdleInterval");
924 	if (conn_idle_interval > 0)
925 		spdk_iscsi_set_min_conn_idle_interval(conn_idle_interval);
926 
927 	/* portal groups */
928 	rc = spdk_iscsi_portal_grp_array_create();
929 	if (rc < 0) {
930 		SPDK_ERRLOG("spdk_iscsi_portal_grp_array_create() failed\n");
931 		return -1;
932 	}
933 
934 	/* initiator groups */
935 	rc = spdk_iscsi_init_grp_array_create();
936 	if (rc < 0) {
937 		SPDK_ERRLOG("spdk_iscsi_init_grp_array_create() failed\n");
938 		return -1;
939 	}
940 
941 	rc = pthread_mutex_init(&g_spdk_iscsi.mutex, NULL);
942 	if (rc != 0) {
943 		SPDK_ERRLOG("mutex_init() failed\n");
944 		return -1;
945 	}
946 
947 	return 0;
948 }
949 
950 static void
951 spdk_iscsi_setup(void *arg1, void *arg2)
952 {
953 	int rc;
954 
955 	/* open portals */
956 	rc = spdk_iscsi_portal_grp_open_all();
957 	if (rc < 0) {
958 		SPDK_ERRLOG("spdk_iscsi_portal_grp_open_all() failed\n");
959 		return;
960 	}
961 
962 	spdk_iscsi_acceptor_start();
963 }
964 
965 int
966 spdk_iscsi_init(void)
967 {
968 	int rc;
969 
970 	rc = spdk_iscsi_app_read_parameters();
971 	if (rc < 0) {
972 		SPDK_ERRLOG("spdk_iscsi_app_read_parameters() failed\n");
973 		return -1;
974 	}
975 
976 	rc = spdk_iscsi_initialize_all_pools();
977 	if (rc != 0) {
978 		SPDK_ERRLOG("spdk_initialize_all_pools() failed\n");
979 		return -1;
980 	}
981 
982 	rc = spdk_iscsi_init_tgt_nodes();
983 	if (rc < 0) {
984 		SPDK_ERRLOG("spdk_iscsi_init_tgt_nodes() failed\n");
985 		return -1;
986 	}
987 
988 	rc = spdk_initialize_iscsi_conns();
989 	if (rc < 0) {
990 		SPDK_ERRLOG("spdk_initialize_iscsi_conns() failed\n");
991 		return -1;
992 	}
993 
994 	/*
995 	 * Defer creation of listening sockets until the reactor has started.
996 	 */
997 	spdk_event_call(spdk_event_allocate(spdk_env_get_current_core(), spdk_iscsi_setup, NULL, NULL));
998 
999 	return 0;
1000 }
1001 
1002 int
1003 spdk_iscsi_fini(void)
1004 {
1005 	int rc;
1006 
1007 	rc = spdk_iscsi_check_pools();
1008 	spdk_iscsi_free_pools();
1009 
1010 	spdk_iscsi_shutdown_tgt_nodes();
1011 	spdk_iscsi_init_grp_array_destroy();
1012 	spdk_iscsi_portal_grp_array_destroy();
1013 	free(g_spdk_iscsi.authfile);
1014 	free(g_spdk_iscsi.nodebase);
1015 
1016 	pthread_mutex_destroy(&g_spdk_iscsi.mutex);
1017 
1018 	return rc;
1019 }
1020 
1021 void
1022 spdk_iscsi_config_text(FILE *fp)
1023 {
1024 	spdk_iscsi_config_dump_section(fp);
1025 	spdk_iscsi_config_dump_portal_groups(fp);
1026 	spdk_iscsi_config_dump_initiator_groups(fp);
1027 	spdk_iscsi_config_dump_target_nodes(fp);
1028 }
1029 
1030 SPDK_LOG_REGISTER_TRACE_FLAG("iscsi", SPDK_TRACE_ISCSI)
1031