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