xref: /spdk/lib/iscsi/iscsi_subsystem.c (revision 6569a0ea0630b45bb83582ac2893cda584375dc4)
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 #include "spdk/env.h"
37 #include "spdk/string.h"
38 #include "spdk/sock.h"
39 #include "spdk/likely.h"
40 
41 #include "iscsi/iscsi.h"
42 #include "iscsi/init_grp.h"
43 #include "iscsi/portal_grp.h"
44 #include "iscsi/conn.h"
45 #include "iscsi/task.h"
46 #include "iscsi/tgt_node.h"
47 
48 #include "spdk_internal/event.h"
49 #include "spdk_internal/log.h"
50 
51 struct spdk_iscsi_opts *g_spdk_iscsi_opts = NULL;
52 
53 static struct spdk_thread *g_init_thread = NULL;
54 static spdk_iscsi_init_cb g_init_cb_fn = NULL;
55 static void *g_init_cb_arg = NULL;
56 
57 static spdk_iscsi_fini_cb g_fini_cb_fn;
58 static void *g_fini_cb_arg;
59 
60 #define ISCSI_CONFIG_TMPL \
61 "[iSCSI]\n" \
62 "  # node name (not include optional part)\n" \
63 "  # Users can optionally change this to fit their environment.\n" \
64 "  NodeBase \"%s\"\n" \
65 "\n" \
66 "  # files\n" \
67 "  %s %s\n" \
68 "\n" \
69 "  # socket I/O timeout sec. (polling is infinity)\n" \
70 "  Timeout %d\n" \
71 "\n" \
72 "  # authentication information for discovery session\n" \
73 "  DiscoveryAuthMethod %s\n" \
74 "  DiscoveryAuthGroup %s\n" \
75 "\n" \
76 "  MaxSessions %d\n" \
77 "  MaxConnectionsPerSession %d\n" \
78 "  MaxConnections %d\n" \
79 "  MaxQueueDepth %d\n" \
80 "\n" \
81 "  # iSCSI initial parameters negotiate with initiators\n" \
82 "  # NOTE: incorrect values might crash\n" \
83 "  DefaultTime2Wait %d\n" \
84 "  DefaultTime2Retain %d\n" \
85 "\n" \
86 "  FirstBurstLength %d\n" \
87 "  ImmediateData %s\n" \
88 "  ErrorRecoveryLevel %d\n" \
89 "\n"
90 
91 static void
92 iscsi_globals_config_text(FILE *fp)
93 {
94 	const char *authmethod = "None";
95 	char authgroup[32] = "None";
96 
97 	if (NULL == fp) {
98 		return;
99 	}
100 
101 	if (g_iscsi.require_chap) {
102 		authmethod = "CHAP";
103 	} else if (g_iscsi.mutual_chap) {
104 		authmethod = "CHAP Mutual";
105 	} else if (!g_iscsi.disable_chap) {
106 		authmethod = "Auto";
107 	}
108 
109 	if (g_iscsi.chap_group) {
110 		snprintf(authgroup, sizeof(authgroup), "AuthGroup%d", g_iscsi.chap_group);
111 	}
112 
113 	fprintf(fp, ISCSI_CONFIG_TMPL,
114 		g_iscsi.nodebase,
115 		g_iscsi.authfile ? "AuthFile" : "",
116 		g_iscsi.authfile ? g_iscsi.authfile : "",
117 		g_iscsi.timeout, authmethod, authgroup,
118 		g_iscsi.MaxSessions, g_iscsi.MaxConnectionsPerSession,
119 		g_iscsi.MaxConnections,
120 		g_iscsi.MaxQueueDepth,
121 		g_iscsi.DefaultTime2Wait, g_iscsi.DefaultTime2Retain,
122 		g_iscsi.FirstBurstLength,
123 		(g_iscsi.ImmediateData) ? "Yes" : "No",
124 		g_iscsi.ErrorRecoveryLevel);
125 }
126 
127 #define ISCSI_DATA_BUFFER_ALIGNMENT	(0x1000)
128 #define ISCSI_DATA_BUFFER_MASK		(ISCSI_DATA_BUFFER_ALIGNMENT - 1)
129 
130 static void
131 mobj_ctor(struct spdk_mempool *mp, __attribute__((unused)) void *arg,
132 	  void *_m, __attribute__((unused)) unsigned i)
133 {
134 	struct spdk_mobj *m = _m;
135 
136 	m->mp = mp;
137 	m->buf = (uint8_t *)m + sizeof(struct spdk_mobj);
138 	m->buf = (void *)((unsigned long)((uint8_t *)m->buf + ISCSI_DATA_BUFFER_ALIGNMENT) &
139 			  ~ISCSI_DATA_BUFFER_MASK);
140 }
141 
142 #define NUM_PDU_PER_CONNECTION(iscsi)	(2 * (iscsi->MaxQueueDepth + MAX_LARGE_DATAIN_PER_CONNECTION + 8))
143 #define PDU_POOL_SIZE(iscsi)		(iscsi->MaxConnections * NUM_PDU_PER_CONNECTION(iscsi))
144 #define IMMEDIATE_DATA_POOL_SIZE(iscsi)	(iscsi->MaxConnections * 128)
145 #define DATA_OUT_POOL_SIZE(iscsi)	(iscsi->MaxConnections * MAX_DATA_OUT_PER_CONNECTION)
146 
147 static int
148 iscsi_initialize_pdu_pool(void)
149 {
150 	struct spdk_iscsi_globals *iscsi = &g_iscsi;
151 	int imm_mobj_size = SPDK_BDEV_BUF_SIZE_WITH_MD(iscsi_get_max_immediate_data_size()) +
152 			    sizeof(struct spdk_mobj) + ISCSI_DATA_BUFFER_ALIGNMENT;
153 	int dout_mobj_size = SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) +
154 			     sizeof(struct spdk_mobj) + ISCSI_DATA_BUFFER_ALIGNMENT;
155 
156 	/* create PDU pool */
157 	iscsi->pdu_pool = spdk_mempool_create("PDU_Pool",
158 					      PDU_POOL_SIZE(iscsi),
159 					      sizeof(struct spdk_iscsi_pdu),
160 					      256, SPDK_ENV_SOCKET_ID_ANY);
161 	if (!iscsi->pdu_pool) {
162 		SPDK_ERRLOG("create PDU pool failed\n");
163 		return -1;
164 	}
165 
166 	iscsi->pdu_immediate_data_pool = spdk_mempool_create_ctor("PDU_immediate_data_Pool",
167 					 IMMEDIATE_DATA_POOL_SIZE(iscsi),
168 					 imm_mobj_size, 256,
169 					 SPDK_ENV_SOCKET_ID_ANY,
170 					 mobj_ctor, NULL);
171 	if (!iscsi->pdu_immediate_data_pool) {
172 		SPDK_ERRLOG("create PDU immediate data pool failed\n");
173 		return -1;
174 	}
175 
176 	iscsi->pdu_data_out_pool = spdk_mempool_create_ctor("PDU_data_out_Pool",
177 				   DATA_OUT_POOL_SIZE(iscsi),
178 				   dout_mobj_size, 256,
179 				   SPDK_ENV_SOCKET_ID_ANY,
180 				   mobj_ctor, NULL);
181 	if (!iscsi->pdu_data_out_pool) {
182 		SPDK_ERRLOG("create PDU data out pool failed\n");
183 		return -1;
184 	}
185 
186 	return 0;
187 }
188 
189 static void
190 iscsi_sess_ctor(struct spdk_mempool *pool, void *arg, void *session_buf,
191 		unsigned index)
192 {
193 	struct spdk_iscsi_globals		*iscsi = arg;
194 	struct spdk_iscsi_sess	*sess = session_buf;
195 
196 	iscsi->session[index] = sess;
197 
198 	/* tsih 0 is reserved, so start tsih values at 1. */
199 	sess->tsih = index + 1;
200 }
201 
202 #define DEFAULT_TASK_POOL_SIZE 32768
203 
204 static int
205 iscsi_initialize_task_pool(void)
206 {
207 	struct spdk_iscsi_globals *iscsi = &g_iscsi;
208 
209 	/* create scsi_task pool */
210 	iscsi->task_pool = spdk_mempool_create("SCSI_TASK_Pool",
211 					       DEFAULT_TASK_POOL_SIZE,
212 					       sizeof(struct spdk_iscsi_task),
213 					       128, SPDK_ENV_SOCKET_ID_ANY);
214 	if (!iscsi->task_pool) {
215 		SPDK_ERRLOG("create task pool failed\n");
216 		return -1;
217 	}
218 
219 	return 0;
220 }
221 
222 #define SESSION_POOL_SIZE(iscsi)	(iscsi->MaxSessions)
223 static int
224 iscsi_initialize_session_pool(void)
225 {
226 	struct spdk_iscsi_globals *iscsi = &g_iscsi;
227 
228 	iscsi->session_pool = spdk_mempool_create_ctor("Session_Pool",
229 			      SESSION_POOL_SIZE(iscsi),
230 			      sizeof(struct spdk_iscsi_sess), 0,
231 			      SPDK_ENV_SOCKET_ID_ANY,
232 			      iscsi_sess_ctor, iscsi);
233 	if (!iscsi->session_pool) {
234 		SPDK_ERRLOG("create session pool failed\n");
235 		return -1;
236 	}
237 
238 	return 0;
239 }
240 
241 static int
242 iscsi_initialize_all_pools(void)
243 {
244 	if (iscsi_initialize_pdu_pool() != 0) {
245 		return -1;
246 	}
247 
248 	if (iscsi_initialize_session_pool() != 0) {
249 		return -1;
250 	}
251 
252 	if (iscsi_initialize_task_pool() != 0) {
253 		return -1;
254 	}
255 
256 	return 0;
257 }
258 
259 static void
260 iscsi_check_pool(struct spdk_mempool *pool, size_t count)
261 {
262 	if (pool && spdk_mempool_count(pool) != count) {
263 		SPDK_ERRLOG("spdk_mempool_count(%s) == %zu, should be %zu\n",
264 			    spdk_mempool_get_name(pool), spdk_mempool_count(pool), count);
265 	}
266 }
267 
268 static void
269 iscsi_check_pools(void)
270 {
271 	struct spdk_iscsi_globals *iscsi = &g_iscsi;
272 
273 	iscsi_check_pool(iscsi->pdu_pool, PDU_POOL_SIZE(iscsi));
274 	iscsi_check_pool(iscsi->session_pool, SESSION_POOL_SIZE(iscsi));
275 	iscsi_check_pool(iscsi->pdu_immediate_data_pool, IMMEDIATE_DATA_POOL_SIZE(iscsi));
276 	iscsi_check_pool(iscsi->pdu_data_out_pool, DATA_OUT_POOL_SIZE(iscsi));
277 	iscsi_check_pool(iscsi->task_pool, DEFAULT_TASK_POOL_SIZE);
278 }
279 
280 static void
281 iscsi_free_pools(void)
282 {
283 	struct spdk_iscsi_globals *iscsi = &g_iscsi;
284 
285 	spdk_mempool_free(iscsi->pdu_pool);
286 	spdk_mempool_free(iscsi->session_pool);
287 	spdk_mempool_free(iscsi->pdu_immediate_data_pool);
288 	spdk_mempool_free(iscsi->pdu_data_out_pool);
289 	spdk_mempool_free(iscsi->task_pool);
290 }
291 
292 void iscsi_put_pdu(struct spdk_iscsi_pdu *pdu)
293 {
294 	if (!pdu) {
295 		return;
296 	}
297 
298 	assert(pdu->ref > 0);
299 	pdu->ref--;
300 
301 	if (pdu->ref == 0) {
302 		if (pdu->mobj) {
303 			spdk_mempool_put(pdu->mobj->mp, (void *)pdu->mobj);
304 		}
305 
306 		if (pdu->data && !pdu->data_from_mempool) {
307 			free(pdu->data);
308 		}
309 
310 		spdk_mempool_put(g_iscsi.pdu_pool, (void *)pdu);
311 	}
312 }
313 
314 struct spdk_iscsi_pdu *iscsi_get_pdu(struct spdk_iscsi_conn *conn)
315 {
316 	struct spdk_iscsi_pdu *pdu;
317 
318 	assert(conn != NULL);
319 	pdu = spdk_mempool_get(g_iscsi.pdu_pool);
320 	if (!pdu) {
321 		SPDK_ERRLOG("Unable to get PDU\n");
322 		abort();
323 	}
324 
325 	/* we do not want to zero out the last part of the structure reserved for AHS and sense data */
326 	memset(pdu, 0, offsetof(struct spdk_iscsi_pdu, ahs));
327 	pdu->ref = 1;
328 	pdu->conn = conn;
329 
330 	return pdu;
331 }
332 
333 static void
334 iscsi_log_globals(void)
335 {
336 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "AuthFile %s\n",
337 		      g_iscsi.authfile ? g_iscsi.authfile : "(none)");
338 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "NodeBase %s\n", g_iscsi.nodebase);
339 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxSessions %d\n", g_iscsi.MaxSessions);
340 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxConnectionsPerSession %d\n",
341 		      g_iscsi.MaxConnectionsPerSession);
342 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxQueueDepth %d\n", g_iscsi.MaxQueueDepth);
343 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "DefaultTime2Wait %d\n",
344 		      g_iscsi.DefaultTime2Wait);
345 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "DefaultTime2Retain %d\n",
346 		      g_iscsi.DefaultTime2Retain);
347 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "FirstBurstLength %d\n",
348 		      g_iscsi.FirstBurstLength);
349 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "ImmediateData %s\n",
350 		      g_iscsi.ImmediateData ? "Yes" : "No");
351 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "AllowDuplicateIsid %s\n",
352 		      g_iscsi.AllowDuplicateIsid ? "Yes" : "No");
353 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "ErrorRecoveryLevel %d\n",
354 		      g_iscsi.ErrorRecoveryLevel);
355 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Timeout %d\n", g_iscsi.timeout);
356 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "NopInInterval %d\n",
357 		      g_iscsi.nopininterval);
358 	if (g_iscsi.disable_chap) {
359 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
360 			      "DiscoveryAuthMethod None\n");
361 	} else if (!g_iscsi.require_chap) {
362 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
363 			      "DiscoveryAuthMethod Auto\n");
364 	} else {
365 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
366 			      "DiscoveryAuthMethod %s %s\n",
367 			      g_iscsi.require_chap ? "CHAP" : "",
368 			      g_iscsi.mutual_chap ? "Mutual" : "");
369 	}
370 
371 	if (g_iscsi.chap_group == 0) {
372 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
373 			      "DiscoveryAuthGroup None\n");
374 	} else {
375 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
376 			      "DiscoveryAuthGroup AuthGroup%d\n",
377 			      g_iscsi.chap_group);
378 	}
379 }
380 
381 static void
382 iscsi_opts_init(struct spdk_iscsi_opts *opts)
383 {
384 	opts->MaxSessions = DEFAULT_MAX_SESSIONS;
385 	opts->MaxConnectionsPerSession = DEFAULT_MAX_CONNECTIONS_PER_SESSION;
386 	opts->MaxQueueDepth = DEFAULT_MAX_QUEUE_DEPTH;
387 	opts->DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT;
388 	opts->DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
389 	opts->FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
390 	opts->ImmediateData = DEFAULT_IMMEDIATEDATA;
391 	opts->AllowDuplicateIsid = false;
392 	opts->ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL;
393 	opts->timeout = DEFAULT_TIMEOUT;
394 	opts->nopininterval = DEFAULT_NOPININTERVAL;
395 	opts->disable_chap = false;
396 	opts->require_chap = false;
397 	opts->mutual_chap = false;
398 	opts->chap_group = 0;
399 	opts->authfile = NULL;
400 	opts->nodebase = NULL;
401 }
402 
403 struct spdk_iscsi_opts *
404 iscsi_opts_alloc(void)
405 {
406 	struct spdk_iscsi_opts *opts;
407 
408 	opts = calloc(1, sizeof(*opts));
409 	if (!opts) {
410 		SPDK_ERRLOG("calloc() failed for iscsi options\n");
411 		return NULL;
412 	}
413 
414 	iscsi_opts_init(opts);
415 
416 	return opts;
417 }
418 
419 void
420 iscsi_opts_free(struct spdk_iscsi_opts *opts)
421 {
422 	free(opts->authfile);
423 	free(opts->nodebase);
424 	free(opts);
425 }
426 
427 /* Deep copy of spdk_iscsi_opts */
428 struct spdk_iscsi_opts *
429 iscsi_opts_copy(struct spdk_iscsi_opts *src)
430 {
431 	struct spdk_iscsi_opts *dst;
432 
433 	dst = calloc(1, sizeof(*dst));
434 	if (!dst) {
435 		SPDK_ERRLOG("calloc() failed for iscsi options\n");
436 		return NULL;
437 	}
438 
439 	if (src->authfile) {
440 		dst->authfile = strdup(src->authfile);
441 		if (!dst->authfile) {
442 			free(dst);
443 			SPDK_ERRLOG("failed to strdup for auth file %s\n", src->authfile);
444 			return NULL;
445 		}
446 	}
447 
448 	if (src->nodebase) {
449 		dst->nodebase = strdup(src->nodebase);
450 		if (!dst->nodebase) {
451 			free(dst->authfile);
452 			free(dst);
453 			SPDK_ERRLOG("failed to strdup for nodebase %s\n", src->nodebase);
454 			return NULL;
455 		}
456 	}
457 
458 	dst->MaxSessions = src->MaxSessions;
459 	dst->MaxConnectionsPerSession = src->MaxConnectionsPerSession;
460 	dst->MaxQueueDepth = src->MaxQueueDepth;
461 	dst->DefaultTime2Wait = src->DefaultTime2Wait;
462 	dst->DefaultTime2Retain = src->DefaultTime2Retain;
463 	dst->FirstBurstLength = src->FirstBurstLength;
464 	dst->ImmediateData = src->ImmediateData;
465 	dst->AllowDuplicateIsid = src->AllowDuplicateIsid;
466 	dst->ErrorRecoveryLevel = src->ErrorRecoveryLevel;
467 	dst->timeout = src->timeout;
468 	dst->nopininterval = src->nopininterval;
469 	dst->disable_chap = src->disable_chap;
470 	dst->require_chap = src->require_chap;
471 	dst->mutual_chap = src->mutual_chap;
472 	dst->chap_group = src->chap_group;
473 
474 	return dst;
475 }
476 
477 static int
478 iscsi_read_config_file_params(struct spdk_conf_section *sp,
479 			      struct spdk_iscsi_opts *opts)
480 {
481 	const char *val;
482 	int MaxSessions;
483 	int MaxConnectionsPerSession;
484 	int MaxQueueDepth;
485 	int DefaultTime2Wait;
486 	int DefaultTime2Retain;
487 	int FirstBurstLength;
488 	int ErrorRecoveryLevel;
489 	int timeout;
490 	int nopininterval;
491 	const char *ag_tag;
492 	int ag_tag_i;
493 	int i;
494 
495 	val = spdk_conf_section_get_val(sp, "Comment");
496 	if (val != NULL) {
497 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Comment %s\n", val);
498 	}
499 
500 	val = spdk_conf_section_get_val(sp, "AuthFile");
501 	if (val != NULL) {
502 		opts->authfile = strdup(val);
503 		if (!opts->authfile) {
504 			SPDK_ERRLOG("strdup() failed for AuthFile\n");
505 			return -ENOMEM;
506 		}
507 	}
508 
509 	val = spdk_conf_section_get_val(sp, "NodeBase");
510 	if (val != NULL) {
511 		opts->nodebase = strdup(val);
512 		if (!opts->nodebase) {
513 			free(opts->authfile);
514 			SPDK_ERRLOG("strdup() failed for NodeBase\n");
515 			return -ENOMEM;
516 		}
517 	}
518 
519 	MaxSessions = spdk_conf_section_get_intval(sp, "MaxSessions");
520 	if (MaxSessions >= 0) {
521 		opts->MaxSessions = MaxSessions;
522 	}
523 
524 	MaxConnectionsPerSession = spdk_conf_section_get_intval(sp, "MaxConnectionsPerSession");
525 	if (MaxConnectionsPerSession >= 0) {
526 		opts->MaxConnectionsPerSession = MaxConnectionsPerSession;
527 	}
528 
529 	MaxQueueDepth = spdk_conf_section_get_intval(sp, "MaxQueueDepth");
530 	if (MaxQueueDepth >= 0) {
531 		opts->MaxQueueDepth = MaxQueueDepth;
532 	}
533 
534 	DefaultTime2Wait = spdk_conf_section_get_intval(sp, "DefaultTime2Wait");
535 	if (DefaultTime2Wait >= 0) {
536 		opts->DefaultTime2Wait = DefaultTime2Wait;
537 	}
538 
539 	DefaultTime2Retain = spdk_conf_section_get_intval(sp, "DefaultTime2Retain");
540 	if (DefaultTime2Retain >= 0) {
541 		opts->DefaultTime2Retain = DefaultTime2Retain;
542 	}
543 
544 	FirstBurstLength = spdk_conf_section_get_intval(sp, "FirstBurstLength");
545 	if (FirstBurstLength >= 0) {
546 		opts->FirstBurstLength = FirstBurstLength;
547 	}
548 
549 	opts->ImmediateData = spdk_conf_section_get_boolval(sp, "ImmediateData",
550 			      opts->ImmediateData);
551 
552 	/* This option is only for test.
553 	 * If AllowDuplicateIsid is enabled, it allows different connections carrying
554 	 * TSIH=0 login the target within the same session.
555 	 */
556 	opts->AllowDuplicateIsid = spdk_conf_section_get_boolval(sp, "AllowDuplicateIsid",
557 				   opts->AllowDuplicateIsid);
558 
559 	ErrorRecoveryLevel = spdk_conf_section_get_intval(sp, "ErrorRecoveryLevel");
560 	if (ErrorRecoveryLevel >= 0) {
561 		opts->ErrorRecoveryLevel = ErrorRecoveryLevel;
562 	}
563 	timeout = spdk_conf_section_get_intval(sp, "Timeout");
564 	if (timeout >= 0) {
565 		opts->timeout = timeout;
566 	}
567 	nopininterval = spdk_conf_section_get_intval(sp, "NopInInterval");
568 	if (nopininterval >= 0) {
569 		opts->nopininterval = nopininterval;
570 	}
571 	val = spdk_conf_section_get_val(sp, "DiscoveryAuthMethod");
572 	if (val != NULL) {
573 		for (i = 0; ; i++) {
574 			val = spdk_conf_section_get_nmval(sp, "DiscoveryAuthMethod", 0, i);
575 			if (val == NULL) {
576 				break;
577 			}
578 			if (strcasecmp(val, "CHAP") == 0) {
579 				opts->require_chap = true;
580 			} else if (strcasecmp(val, "Mutual") == 0) {
581 				opts->require_chap = true;
582 				opts->mutual_chap = true;
583 			} else if (strcasecmp(val, "Auto") == 0) {
584 				opts->disable_chap = false;
585 				opts->require_chap = false;
586 				opts->mutual_chap = false;
587 			} else if (strcasecmp(val, "None") == 0) {
588 				opts->disable_chap = true;
589 				opts->require_chap = false;
590 				opts->mutual_chap = false;
591 			} else {
592 				SPDK_ERRLOG("unknown CHAP mode %s\n", val);
593 			}
594 		}
595 		if (opts->mutual_chap && !opts->require_chap) {
596 			free(opts->authfile);
597 			free(opts->nodebase);
598 			SPDK_ERRLOG("CHAP must set to be required when using mutual CHAP.\n");
599 			return -EINVAL;
600 		}
601 	}
602 	val = spdk_conf_section_get_val(sp, "DiscoveryAuthGroup");
603 	if (val != NULL) {
604 		ag_tag = val;
605 		if (strcasecmp(ag_tag, "None") == 0) {
606 			opts->chap_group = 0;
607 		} else {
608 			if (strncasecmp(ag_tag, "AuthGroup",
609 					strlen("AuthGroup")) != 0
610 			    || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1
611 			    || ag_tag_i == 0) {
612 				SPDK_ERRLOG("invalid auth group %s, ignoring\n", ag_tag);
613 			} else {
614 				opts->chap_group = ag_tag_i;
615 			}
616 		}
617 	}
618 
619 	return 0;
620 }
621 
622 static int
623 iscsi_opts_verify(struct spdk_iscsi_opts *opts)
624 {
625 	if (!opts->nodebase) {
626 		opts->nodebase = strdup(SPDK_ISCSI_DEFAULT_NODEBASE);
627 		if (opts->nodebase == NULL) {
628 			SPDK_ERRLOG("strdup() failed for default nodebase\n");
629 			return -ENOMEM;
630 		}
631 	}
632 
633 	if (opts->MaxSessions == 0 || opts->MaxSessions > 65535) {
634 		SPDK_ERRLOG("%d is invalid. MaxSessions must be more than 0 and no more than 65535\n",
635 			    opts->MaxSessions);
636 		return -EINVAL;
637 	}
638 
639 	if (opts->MaxConnectionsPerSession == 0 || opts->MaxConnectionsPerSession > 65535) {
640 		SPDK_ERRLOG("%d is invalid. MaxConnectionsPerSession must be more than 0 and no more than 65535\n",
641 			    opts->MaxConnectionsPerSession);
642 		return -EINVAL;
643 	}
644 
645 	if (opts->MaxQueueDepth == 0 || opts->MaxQueueDepth > 256) {
646 		SPDK_ERRLOG("%d is invalid. MaxQueueDepth must be more than 0 and no more than 256\n",
647 			    opts->MaxQueueDepth);
648 		return -EINVAL;
649 	}
650 
651 	if (opts->DefaultTime2Wait > 3600) {
652 		SPDK_ERRLOG("%d is invalid. DefaultTime2Wait must be no more than 3600\n",
653 			    opts->DefaultTime2Wait);
654 		return -EINVAL;
655 	}
656 
657 	if (opts->DefaultTime2Retain > 3600) {
658 		SPDK_ERRLOG("%d is invalid. DefaultTime2Retain must be no more than 3600\n",
659 			    opts->DefaultTime2Retain);
660 		return -EINVAL;
661 	}
662 
663 	if (opts->FirstBurstLength >= SPDK_ISCSI_MIN_FIRST_BURST_LENGTH) {
664 		if (opts->FirstBurstLength > SPDK_ISCSI_MAX_BURST_LENGTH) {
665 			SPDK_ERRLOG("FirstBurstLength %d shall not exceed MaxBurstLength %d\n",
666 				    opts->FirstBurstLength, SPDK_ISCSI_MAX_BURST_LENGTH);
667 			return -EINVAL;
668 		}
669 	} else {
670 		SPDK_ERRLOG("FirstBurstLength %d shall be no less than %d\n",
671 			    opts->FirstBurstLength, SPDK_ISCSI_MIN_FIRST_BURST_LENGTH);
672 		return -EINVAL;
673 	}
674 
675 	if (opts->ErrorRecoveryLevel > 2) {
676 		SPDK_ERRLOG("ErrorRecoveryLevel %d is not supported.\n", opts->ErrorRecoveryLevel);
677 		return -EINVAL;
678 	}
679 
680 	if (opts->timeout < 0) {
681 		SPDK_ERRLOG("%d is invalid. timeout must not be less than 0\n", opts->timeout);
682 		return -EINVAL;
683 	}
684 
685 	if (opts->nopininterval < 0 || opts->nopininterval > MAX_NOPININTERVAL) {
686 		SPDK_ERRLOG("%d is invalid. nopinterval must be between 0 and %d\n",
687 			    opts->nopininterval, MAX_NOPININTERVAL);
688 		return -EINVAL;
689 	}
690 
691 	if (!iscsi_check_chap_params(opts->disable_chap, opts->require_chap,
692 				     opts->mutual_chap, opts->chap_group)) {
693 		SPDK_ERRLOG("CHAP params in opts are illegal combination\n");
694 		return -EINVAL;
695 	}
696 
697 	return 0;
698 }
699 
700 static int
701 iscsi_parse_options(struct spdk_iscsi_opts **popts)
702 {
703 	struct spdk_iscsi_opts *opts;
704 	struct spdk_conf_section *sp;
705 	int rc;
706 
707 	opts = iscsi_opts_alloc();
708 	if (!opts) {
709 		SPDK_ERRLOG("iscsi_opts_alloc_failed() failed\n");
710 		return -ENOMEM;
711 	}
712 
713 	/* Process parameters */
714 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "iscsi_read_config_file_parmas\n");
715 	sp = spdk_conf_find_section(NULL, "iSCSI");
716 	if (sp != NULL) {
717 		rc = iscsi_read_config_file_params(sp, opts);
718 		if (rc != 0) {
719 			free(opts);
720 			SPDK_ERRLOG("iscsi_read_config_file_params() failed\n");
721 			return rc;
722 		}
723 	}
724 
725 	*popts = opts;
726 
727 	return 0;
728 }
729 
730 static int
731 iscsi_set_global_params(struct spdk_iscsi_opts *opts)
732 {
733 	int rc;
734 
735 	rc = iscsi_opts_verify(opts);
736 	if (rc != 0) {
737 		SPDK_ERRLOG("spdk_iscsi_opts_verify() failed\n");
738 		return rc;
739 	}
740 
741 	if (opts->authfile != NULL) {
742 		g_iscsi.authfile = strdup(opts->authfile);
743 		if (!g_iscsi.authfile) {
744 			SPDK_ERRLOG("failed to strdup for auth file %s\n", opts->authfile);
745 			return -ENOMEM;
746 		}
747 	}
748 
749 	g_iscsi.nodebase = strdup(opts->nodebase);
750 	if (!g_iscsi.nodebase) {
751 		SPDK_ERRLOG("failed to strdup for nodebase %s\n", opts->nodebase);
752 		return -ENOMEM;
753 	}
754 
755 	g_iscsi.MaxSessions = opts->MaxSessions;
756 	g_iscsi.MaxConnectionsPerSession = opts->MaxConnectionsPerSession;
757 	g_iscsi.MaxQueueDepth = opts->MaxQueueDepth;
758 	g_iscsi.DefaultTime2Wait = opts->DefaultTime2Wait;
759 	g_iscsi.DefaultTime2Retain = opts->DefaultTime2Retain;
760 	g_iscsi.FirstBurstLength = opts->FirstBurstLength;
761 	g_iscsi.ImmediateData = opts->ImmediateData;
762 	g_iscsi.AllowDuplicateIsid = opts->AllowDuplicateIsid;
763 	g_iscsi.ErrorRecoveryLevel = opts->ErrorRecoveryLevel;
764 	g_iscsi.timeout = opts->timeout;
765 	g_iscsi.nopininterval = opts->nopininterval;
766 	g_iscsi.disable_chap = opts->disable_chap;
767 	g_iscsi.require_chap = opts->require_chap;
768 	g_iscsi.mutual_chap = opts->mutual_chap;
769 	g_iscsi.chap_group = opts->chap_group;
770 
771 	iscsi_log_globals();
772 
773 	return 0;
774 }
775 
776 int
777 iscsi_set_discovery_auth(bool disable_chap, bool require_chap, bool mutual_chap,
778 			 int32_t chap_group)
779 {
780 	if (!iscsi_check_chap_params(disable_chap, require_chap, mutual_chap,
781 				     chap_group)) {
782 		SPDK_ERRLOG("CHAP params are illegal combination\n");
783 		return -EINVAL;
784 	}
785 
786 	pthread_mutex_lock(&g_iscsi.mutex);
787 	g_iscsi.disable_chap = disable_chap;
788 	g_iscsi.require_chap = require_chap;
789 	g_iscsi.mutual_chap = mutual_chap;
790 	g_iscsi.chap_group = chap_group;
791 	pthread_mutex_unlock(&g_iscsi.mutex);
792 
793 	return 0;
794 }
795 
796 int
797 iscsi_auth_group_add_secret(struct spdk_iscsi_auth_group *group,
798 			    const char *user, const char *secret,
799 			    const char *muser, const char *msecret)
800 {
801 	struct spdk_iscsi_auth_secret *_secret;
802 	size_t len;
803 
804 	if (user == NULL || secret == NULL) {
805 		SPDK_ERRLOG("user and secret must be specified\n");
806 		return -EINVAL;
807 	}
808 
809 	if (muser != NULL && msecret == NULL) {
810 		SPDK_ERRLOG("msecret must be specified with muser\n");
811 		return -EINVAL;
812 	}
813 
814 	TAILQ_FOREACH(_secret, &group->secret_head, tailq) {
815 		if (strcmp(_secret->user, user) == 0) {
816 			SPDK_ERRLOG("user for secret is duplicated\n");
817 			return -EEXIST;
818 		}
819 	}
820 
821 	_secret = calloc(1, sizeof(*_secret));
822 	if (_secret == NULL) {
823 		SPDK_ERRLOG("calloc() failed for CHAP secret\n");
824 		return -ENOMEM;
825 	}
826 
827 	len = strnlen(user, sizeof(_secret->user));
828 	if (len > sizeof(_secret->user) - 1) {
829 		SPDK_ERRLOG("CHAP user longer than %zu characters: %s\n",
830 			    sizeof(_secret->user) - 1, user);
831 		free(_secret);
832 		return -EINVAL;
833 	}
834 	memcpy(_secret->user, user, len);
835 
836 	len = strnlen(secret, sizeof(_secret->secret));
837 	if (len > sizeof(_secret->secret) - 1) {
838 		SPDK_ERRLOG("CHAP secret longer than %zu characters: %s\n",
839 			    sizeof(_secret->secret) - 1, secret);
840 		free(_secret);
841 		return -EINVAL;
842 	}
843 	memcpy(_secret->secret, secret, len);
844 
845 	if (muser != NULL) {
846 		len = strnlen(muser, sizeof(_secret->muser));
847 		if (len > sizeof(_secret->muser) - 1) {
848 			SPDK_ERRLOG("Mutual CHAP user longer than %zu characters: %s\n",
849 				    sizeof(_secret->muser) - 1, muser);
850 			free(_secret);
851 			return -EINVAL;
852 		}
853 		memcpy(_secret->muser, muser, len);
854 
855 		len = strnlen(msecret, sizeof(_secret->msecret));
856 		if (len > sizeof(_secret->msecret) - 1) {
857 			SPDK_ERRLOG("Mutual CHAP secret longer than %zu characters: %s\n",
858 				    sizeof(_secret->msecret) - 1, msecret);
859 			free(_secret);
860 			return -EINVAL;
861 		}
862 		memcpy(_secret->msecret, msecret, len);
863 	}
864 
865 	TAILQ_INSERT_TAIL(&group->secret_head, _secret, tailq);
866 	return 0;
867 }
868 
869 int
870 iscsi_auth_group_delete_secret(struct spdk_iscsi_auth_group *group,
871 			       const char *user)
872 {
873 	struct spdk_iscsi_auth_secret *_secret;
874 
875 	if (user == NULL) {
876 		SPDK_ERRLOG("user must be specified\n");
877 		return -EINVAL;
878 	}
879 
880 	TAILQ_FOREACH(_secret, &group->secret_head, tailq) {
881 		if (strcmp(_secret->user, user) == 0) {
882 			break;
883 		}
884 	}
885 
886 	if (_secret == NULL) {
887 		SPDK_ERRLOG("secret is not found\n");
888 		return -ENODEV;
889 	}
890 
891 	TAILQ_REMOVE(&group->secret_head, _secret, tailq);
892 	free(_secret);
893 
894 	return 0;
895 }
896 
897 int
898 iscsi_add_auth_group(int32_t tag, struct spdk_iscsi_auth_group **_group)
899 {
900 	struct spdk_iscsi_auth_group *group;
901 
902 	TAILQ_FOREACH(group, &g_iscsi.auth_group_head, tailq) {
903 		if (group->tag == tag) {
904 			SPDK_ERRLOG("Auth group (%d) already exists\n", tag);
905 			return -EEXIST;
906 		}
907 	}
908 
909 	group = calloc(1, sizeof(*group));
910 	if (group == NULL) {
911 		SPDK_ERRLOG("calloc() failed for auth group\n");
912 		return -ENOMEM;
913 	}
914 
915 	TAILQ_INIT(&group->secret_head);
916 	group->tag = tag;
917 
918 	TAILQ_INSERT_TAIL(&g_iscsi.auth_group_head, group, tailq);
919 
920 	*_group = group;
921 	return 0;
922 }
923 
924 void
925 iscsi_delete_auth_group(struct spdk_iscsi_auth_group *group)
926 {
927 	struct spdk_iscsi_auth_secret *_secret, *tmp;
928 
929 	TAILQ_REMOVE(&g_iscsi.auth_group_head, group, tailq);
930 
931 	TAILQ_FOREACH_SAFE(_secret, &group->secret_head, tailq, tmp) {
932 		TAILQ_REMOVE(&group->secret_head, _secret, tailq);
933 		free(_secret);
934 	}
935 	free(group);
936 }
937 
938 struct spdk_iscsi_auth_group *
939 iscsi_find_auth_group_by_tag(int32_t tag)
940 {
941 	struct spdk_iscsi_auth_group *group;
942 
943 	TAILQ_FOREACH(group, &g_iscsi.auth_group_head, tailq) {
944 		if (group->tag == tag) {
945 			return group;
946 		}
947 	}
948 
949 	return NULL;
950 }
951 
952 static void
953 iscsi_auth_groups_destroy(void)
954 {
955 	struct spdk_iscsi_auth_group *group, *tmp;
956 
957 	TAILQ_FOREACH_SAFE(group, &g_iscsi.auth_group_head, tailq, tmp) {
958 		iscsi_delete_auth_group(group);
959 	}
960 }
961 
962 static int
963 iscsi_parse_auth_group(struct spdk_conf_section *sp)
964 {
965 	int rc;
966 	int i;
967 	int tag;
968 	const char *val, *user, *secret, *muser, *msecret;
969 	struct spdk_iscsi_auth_group *group = NULL;
970 
971 	val = spdk_conf_section_get_val(sp, "Comment");
972 	if (val != NULL) {
973 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Comment %s\n", val);
974 	}
975 
976 	tag = spdk_conf_section_get_num(sp);
977 
978 	rc = iscsi_add_auth_group(tag, &group);
979 	if (rc != 0) {
980 		SPDK_ERRLOG("Failed to add auth group\n");
981 		return rc;
982 	}
983 
984 	for (i = 0; ; i++) {
985 		val = spdk_conf_section_get_nval(sp, "Auth", i);
986 		if (val == NULL) {
987 			break;
988 		}
989 
990 		user = spdk_conf_section_get_nmval(sp, "Auth", i, 0);
991 		secret = spdk_conf_section_get_nmval(sp, "Auth", i, 1);
992 		muser = spdk_conf_section_get_nmval(sp, "Auth", i, 2);
993 		msecret = spdk_conf_section_get_nmval(sp, "Auth", i, 3);
994 
995 		rc = iscsi_auth_group_add_secret(group, user, secret, muser, msecret);
996 		if (rc != 0) {
997 			SPDK_ERRLOG("Failed to add secret to auth group\n");
998 			iscsi_delete_auth_group(group);
999 			return rc;
1000 		}
1001 	}
1002 
1003 	return 0;
1004 }
1005 
1006 static int
1007 iscsi_parse_auth_info(void)
1008 {
1009 	struct spdk_conf *config;
1010 	struct spdk_conf_section *sp;
1011 	int rc;
1012 
1013 	config = spdk_conf_allocate();
1014 	if (!config) {
1015 		SPDK_ERRLOG("Failed to allocate config file\n");
1016 		return -ENOMEM;
1017 	}
1018 
1019 	rc = spdk_conf_read(config, g_iscsi.authfile);
1020 	if (rc != 0) {
1021 		SPDK_INFOLOG(SPDK_LOG_ISCSI, "Failed to load auth file\n");
1022 		spdk_conf_free(config);
1023 		return rc;
1024 	}
1025 
1026 	sp = spdk_conf_first_section(config);
1027 	while (sp != NULL) {
1028 		if (spdk_conf_section_match_prefix(sp, "AuthGroup")) {
1029 			if (spdk_conf_section_get_num(sp) == 0) {
1030 				SPDK_ERRLOG("Group 0 is invalid\n");
1031 				iscsi_auth_groups_destroy();
1032 				spdk_conf_free(config);
1033 				return -EINVAL;
1034 			}
1035 
1036 			rc = iscsi_parse_auth_group(sp);
1037 			if (rc != 0) {
1038 				SPDK_ERRLOG("parse_auth_group() failed\n");
1039 				iscsi_auth_groups_destroy();
1040 				spdk_conf_free(config);
1041 				return rc;
1042 			}
1043 		}
1044 		sp = spdk_conf_next_section(sp);
1045 	}
1046 
1047 	spdk_conf_free(config);
1048 	return 0;
1049 }
1050 
1051 static struct spdk_iscsi_auth_secret *
1052 iscsi_find_auth_secret(const char *authuser, int ag_tag)
1053 {
1054 	struct spdk_iscsi_auth_group *group;
1055 	struct spdk_iscsi_auth_secret *_secret;
1056 
1057 	TAILQ_FOREACH(group, &g_iscsi.auth_group_head, tailq) {
1058 		if (group->tag == ag_tag) {
1059 			TAILQ_FOREACH(_secret, &group->secret_head, tailq) {
1060 				if (strcmp(_secret->user, authuser) == 0) {
1061 					return _secret;
1062 				}
1063 			}
1064 		}
1065 	}
1066 
1067 	return NULL;
1068 }
1069 
1070 int
1071 iscsi_chap_get_authinfo(struct iscsi_chap_auth *auth, const char *authuser,
1072 			int ag_tag)
1073 {
1074 	struct spdk_iscsi_auth_secret *_secret;
1075 
1076 	if (authuser == NULL) {
1077 		return -EINVAL;
1078 	}
1079 
1080 	if (auth->user[0] != '\0') {
1081 		memset(auth->user, 0, sizeof(auth->user));
1082 		memset(auth->secret, 0, sizeof(auth->secret));
1083 		memset(auth->muser, 0, sizeof(auth->muser));
1084 		memset(auth->msecret, 0, sizeof(auth->msecret));
1085 	}
1086 
1087 	pthread_mutex_lock(&g_iscsi.mutex);
1088 
1089 	_secret = iscsi_find_auth_secret(authuser, ag_tag);
1090 	if (_secret == NULL) {
1091 		pthread_mutex_unlock(&g_iscsi.mutex);
1092 
1093 		SPDK_ERRLOG("CHAP secret is not found: user:%s, tag:%d\n",
1094 			    authuser, ag_tag);
1095 		return -ENOENT;
1096 	}
1097 
1098 	memcpy(auth->user, _secret->user, sizeof(auth->user));
1099 	memcpy(auth->secret, _secret->secret, sizeof(auth->secret));
1100 
1101 	if (_secret->muser[0] != '\0') {
1102 		memcpy(auth->muser, _secret->muser, sizeof(auth->muser));
1103 		memcpy(auth->msecret, _secret->msecret, sizeof(auth->msecret));
1104 	}
1105 
1106 	pthread_mutex_unlock(&g_iscsi.mutex);
1107 	return 0;
1108 }
1109 
1110 static int
1111 iscsi_initialize_global_params(void)
1112 {
1113 	int rc;
1114 
1115 	if (!g_spdk_iscsi_opts) {
1116 		rc = iscsi_parse_options(&g_spdk_iscsi_opts);
1117 		if (rc != 0) {
1118 			SPDK_ERRLOG("iscsi_parse_options() failed\n");
1119 			return rc;
1120 		}
1121 	}
1122 
1123 	rc = iscsi_set_global_params(g_spdk_iscsi_opts);
1124 	if (rc != 0) {
1125 		SPDK_ERRLOG("iscsi_set_global_params() failed\n");
1126 	}
1127 
1128 	iscsi_opts_free(g_spdk_iscsi_opts);
1129 	g_spdk_iscsi_opts = NULL;
1130 
1131 	return rc;
1132 }
1133 
1134 static void
1135 iscsi_init_complete(int rc)
1136 {
1137 	spdk_iscsi_init_cb cb_fn = g_init_cb_fn;
1138 	void *cb_arg = g_init_cb_arg;
1139 
1140 	g_init_cb_fn = NULL;
1141 	g_init_cb_arg = NULL;
1142 
1143 	cb_fn(cb_arg, rc);
1144 }
1145 
1146 static void
1147 iscsi_parse_configuration(void)
1148 {
1149 	int rc;
1150 
1151 	rc = iscsi_parse_portal_grps();
1152 	if (rc < 0) {
1153 		SPDK_ERRLOG("iscsi_parse_portal_grps() failed\n");
1154 		goto end;
1155 	}
1156 
1157 	rc = iscsi_parse_init_grps();
1158 	if (rc < 0) {
1159 		SPDK_ERRLOG("iscsi_parse_init_grps() failed\n");
1160 		goto end;
1161 	}
1162 
1163 	rc = iscsi_parse_tgt_nodes();
1164 	if (rc < 0) {
1165 		SPDK_ERRLOG("iscsi_parse_tgt_nodes() failed\n");
1166 	}
1167 
1168 	if (g_iscsi.authfile != NULL) {
1169 		if (access(g_iscsi.authfile, R_OK) == 0) {
1170 			rc = iscsi_parse_auth_info();
1171 			if (rc < 0) {
1172 				SPDK_ERRLOG("iscsi_parse_auth_info() failed\n");
1173 			}
1174 		} else {
1175 			SPDK_INFOLOG(SPDK_LOG_ISCSI, "CHAP secret file is not found in the path %s\n",
1176 				     g_iscsi.authfile);
1177 		}
1178 	}
1179 
1180 end:
1181 	iscsi_init_complete(rc);
1182 }
1183 
1184 static int
1185 iscsi_poll_group_poll(void *ctx)
1186 {
1187 	struct spdk_iscsi_poll_group *group = ctx;
1188 	struct spdk_iscsi_conn *conn, *tmp;
1189 	int rc;
1190 
1191 	if (spdk_unlikely(STAILQ_EMPTY(&group->connections))) {
1192 		return 0;
1193 	}
1194 
1195 	rc = spdk_sock_group_poll(group->sock_group);
1196 	if (rc < 0) {
1197 		SPDK_ERRLOG("Failed to poll sock_group=%p\n", group->sock_group);
1198 	}
1199 
1200 	STAILQ_FOREACH_SAFE(conn, &group->connections, link, tmp) {
1201 		if (conn->state == ISCSI_CONN_STATE_EXITING) {
1202 			iscsi_conn_destruct(conn);
1203 		}
1204 	}
1205 
1206 	return rc;
1207 }
1208 
1209 static int
1210 iscsi_poll_group_handle_nop(void *ctx)
1211 {
1212 	struct spdk_iscsi_poll_group *group = ctx;
1213 	struct spdk_iscsi_conn *conn, *tmp;
1214 
1215 	STAILQ_FOREACH_SAFE(conn, &group->connections, link, tmp) {
1216 		iscsi_conn_handle_nop(conn);
1217 	}
1218 
1219 	return -1;
1220 }
1221 
1222 static int
1223 iscsi_poll_group_create(void *io_device, void *ctx_buf)
1224 {
1225 	struct spdk_iscsi_poll_group *pg = ctx_buf;
1226 
1227 	STAILQ_INIT(&pg->connections);
1228 	pg->sock_group = spdk_sock_group_create(NULL);
1229 	assert(pg->sock_group != NULL);
1230 
1231 	pg->poller = SPDK_POLLER_REGISTER(iscsi_poll_group_poll, pg, 0);
1232 	/* set the period to 1 sec */
1233 	pg->nop_poller = SPDK_POLLER_REGISTER(iscsi_poll_group_handle_nop, pg, 1000000);
1234 
1235 	return 0;
1236 }
1237 
1238 static void
1239 iscsi_poll_group_destroy(void *io_device, void *ctx_buf)
1240 {
1241 	struct spdk_iscsi_poll_group *pg = ctx_buf;
1242 	struct spdk_io_channel *ch;
1243 	struct spdk_thread *thread;
1244 
1245 	assert(pg->poller != NULL);
1246 	assert(pg->sock_group != NULL);
1247 
1248 	spdk_sock_group_close(&pg->sock_group);
1249 	spdk_poller_unregister(&pg->poller);
1250 	spdk_poller_unregister(&pg->nop_poller);
1251 
1252 	ch = spdk_io_channel_from_ctx(pg);
1253 	thread = spdk_io_channel_get_thread(ch);
1254 
1255 	assert(thread == spdk_get_thread());
1256 
1257 	spdk_thread_exit(thread);
1258 }
1259 
1260 static void
1261 _iscsi_init_thread_done(void *ctx)
1262 {
1263 	struct spdk_iscsi_poll_group *pg = ctx;
1264 
1265 	TAILQ_INSERT_TAIL(&g_iscsi.poll_group_head, pg, link);
1266 	if (--g_iscsi.refcnt == 0) {
1267 		iscsi_parse_configuration();
1268 	}
1269 }
1270 
1271 static void
1272 _iscsi_init_thread(void *ctx)
1273 {
1274 	struct spdk_io_channel *ch;
1275 	struct spdk_iscsi_poll_group *pg;
1276 
1277 	ch = spdk_get_io_channel(&g_iscsi);
1278 	pg = spdk_io_channel_get_ctx(ch);
1279 
1280 	spdk_thread_send_msg(g_init_thread, _iscsi_init_thread_done, pg);
1281 }
1282 
1283 static void
1284 initialize_iscsi_poll_group(void)
1285 {
1286 	struct spdk_cpuset tmp_cpumask = {};
1287 	uint32_t i;
1288 	char thread_name[32];
1289 	struct spdk_thread *thread;
1290 
1291 	spdk_io_device_register(&g_iscsi, iscsi_poll_group_create, iscsi_poll_group_destroy,
1292 				sizeof(struct spdk_iscsi_poll_group), "iscsi_tgt");
1293 
1294 	/* Create threads for CPU cores active for this application, and send a
1295 	 * message to each thread to create a poll group on it.
1296 	 */
1297 	g_init_thread = spdk_get_thread();
1298 	assert(g_init_thread != NULL);
1299 	assert(g_iscsi.refcnt == 0);
1300 
1301 	SPDK_ENV_FOREACH_CORE(i) {
1302 		spdk_cpuset_zero(&tmp_cpumask);
1303 		spdk_cpuset_set_cpu(&tmp_cpumask, i, true);
1304 		snprintf(thread_name, sizeof(thread_name), "iscsi_poll_group_%u", i);
1305 
1306 		thread = spdk_thread_create(thread_name, &tmp_cpumask);
1307 		assert(thread != NULL);
1308 
1309 		g_iscsi.refcnt++;
1310 		spdk_thread_send_msg(thread, _iscsi_init_thread, NULL);
1311 	}
1312 }
1313 
1314 static int
1315 iscsi_parse_globals(void)
1316 {
1317 	int rc;
1318 
1319 	rc = iscsi_initialize_global_params();
1320 	if (rc != 0) {
1321 		SPDK_ERRLOG("iscsi_initialize_iscsi_global_params() failed\n");
1322 		return rc;
1323 	}
1324 
1325 	g_iscsi.session = calloc(1, sizeof(struct spdk_iscsi_sess *) * g_iscsi.MaxSessions);
1326 	if (!g_iscsi.session) {
1327 		SPDK_ERRLOG("calloc() failed for session array\n");
1328 		return -1;
1329 	}
1330 
1331 	/*
1332 	 * For now, just support same number of total connections, rather
1333 	 *  than MaxSessions * MaxConnectionsPerSession.  After we add better
1334 	 *  handling for low resource conditions from our various buffer
1335 	 *  pools, we can bump this up to support more connections.
1336 	 */
1337 	g_iscsi.MaxConnections = g_iscsi.MaxSessions;
1338 
1339 	rc = iscsi_initialize_all_pools();
1340 	if (rc != 0) {
1341 		SPDK_ERRLOG("initialize_all_pools() failed\n");
1342 		free(g_iscsi.session);
1343 		g_iscsi.session = NULL;
1344 		return -1;
1345 	}
1346 
1347 	rc = initialize_iscsi_conns();
1348 	if (rc < 0) {
1349 		SPDK_ERRLOG("initialize_iscsi_conns() failed\n");
1350 		free(g_iscsi.session);
1351 		g_iscsi.session = NULL;
1352 		return rc;
1353 	}
1354 
1355 	initialize_iscsi_poll_group();
1356 	return 0;
1357 }
1358 
1359 void
1360 spdk_iscsi_init(spdk_iscsi_init_cb cb_fn, void *cb_arg)
1361 {
1362 	int rc;
1363 
1364 	assert(cb_fn != NULL);
1365 	g_init_cb_fn = cb_fn;
1366 	g_init_cb_arg = cb_arg;
1367 
1368 	rc = iscsi_parse_globals();
1369 	if (rc < 0) {
1370 		SPDK_ERRLOG("iscsi_parse_globals() failed\n");
1371 		iscsi_init_complete(-1);
1372 	}
1373 
1374 	/*
1375 	 * iscsi_parse_configuration() will be called as the callback to
1376 	 * spdk_initialize_iscsi_poll_group() and will complete iSCSI
1377 	 * subsystem initialization.
1378 	 */
1379 }
1380 
1381 void
1382 spdk_iscsi_fini(spdk_iscsi_fini_cb cb_fn, void *cb_arg)
1383 {
1384 	g_fini_cb_fn = cb_fn;
1385 	g_fini_cb_arg = cb_arg;
1386 
1387 	iscsi_portal_grp_close_all();
1388 	shutdown_iscsi_conns();
1389 }
1390 
1391 static void
1392 iscsi_fini_done(void *io_device)
1393 {
1394 	free(g_iscsi.authfile);
1395 	free(g_iscsi.nodebase);
1396 
1397 	pthread_mutex_destroy(&g_iscsi.mutex);
1398 	g_fini_cb_fn(g_fini_cb_arg);
1399 }
1400 
1401 static void
1402 _iscsi_fini_dev_unreg(struct spdk_io_channel_iter *i, int status)
1403 {
1404 	iscsi_check_pools();
1405 	iscsi_free_pools();
1406 	free(g_iscsi.session);
1407 
1408 	assert(TAILQ_EMPTY(&g_iscsi.poll_group_head));
1409 
1410 	iscsi_shutdown_tgt_nodes();
1411 	iscsi_init_grps_destroy();
1412 	iscsi_portal_grps_destroy();
1413 	iscsi_auth_groups_destroy();
1414 
1415 	spdk_io_device_unregister(&g_iscsi, iscsi_fini_done);
1416 }
1417 
1418 static void
1419 _iscsi_fini_thread(struct spdk_io_channel_iter *i)
1420 {
1421 	struct spdk_io_channel *ch;
1422 	struct spdk_iscsi_poll_group *pg;
1423 
1424 	ch = spdk_io_channel_iter_get_channel(i);
1425 	pg = spdk_io_channel_get_ctx(ch);
1426 
1427 	pthread_mutex_lock(&g_iscsi.mutex);
1428 	TAILQ_REMOVE(&g_iscsi.poll_group_head, pg, link);
1429 	pthread_mutex_unlock(&g_iscsi.mutex);
1430 
1431 	spdk_put_io_channel(ch);
1432 
1433 	spdk_for_each_channel_continue(i, 0);
1434 }
1435 
1436 void
1437 shutdown_iscsi_conns_done(void)
1438 {
1439 	spdk_for_each_channel(&g_iscsi, _iscsi_fini_thread, NULL, _iscsi_fini_dev_unreg);
1440 }
1441 
1442 void
1443 spdk_iscsi_config_text(FILE *fp)
1444 {
1445 	iscsi_globals_config_text(fp);
1446 	iscsi_portal_grps_config_text(fp);
1447 	iscsi_init_grps_config_text(fp);
1448 	iscsi_tgt_nodes_config_text(fp);
1449 }
1450 
1451 void
1452 iscsi_opts_info_json(struct spdk_json_write_ctx *w)
1453 {
1454 	spdk_json_write_object_begin(w);
1455 
1456 	if (g_iscsi.authfile != NULL) {
1457 		spdk_json_write_named_string(w, "auth_file", g_iscsi.authfile);
1458 	}
1459 	spdk_json_write_named_string(w, "node_base", g_iscsi.nodebase);
1460 
1461 	spdk_json_write_named_uint32(w, "max_sessions", g_iscsi.MaxSessions);
1462 	spdk_json_write_named_uint32(w, "max_connections_per_session",
1463 				     g_iscsi.MaxConnectionsPerSession);
1464 
1465 	spdk_json_write_named_uint32(w, "max_queue_depth", g_iscsi.MaxQueueDepth);
1466 
1467 	spdk_json_write_named_uint32(w, "default_time2wait", g_iscsi.DefaultTime2Wait);
1468 	spdk_json_write_named_uint32(w, "default_time2retain", g_iscsi.DefaultTime2Retain);
1469 
1470 	spdk_json_write_named_uint32(w, "first_burst_length", g_iscsi.FirstBurstLength);
1471 
1472 	spdk_json_write_named_bool(w, "immediate_data", g_iscsi.ImmediateData);
1473 
1474 	spdk_json_write_named_bool(w, "allow_duplicated_isid", g_iscsi.AllowDuplicateIsid);
1475 
1476 	spdk_json_write_named_uint32(w, "error_recovery_level", g_iscsi.ErrorRecoveryLevel);
1477 
1478 	spdk_json_write_named_int32(w, "nop_timeout", g_iscsi.timeout);
1479 	spdk_json_write_named_int32(w, "nop_in_interval", g_iscsi.nopininterval);
1480 
1481 	spdk_json_write_named_bool(w, "disable_chap", g_iscsi.disable_chap);
1482 	spdk_json_write_named_bool(w, "require_chap", g_iscsi.require_chap);
1483 	spdk_json_write_named_bool(w, "mutual_chap", g_iscsi.mutual_chap);
1484 	spdk_json_write_named_int32(w, "chap_group", g_iscsi.chap_group);
1485 
1486 	spdk_json_write_object_end(w);
1487 }
1488 
1489 static void
1490 iscsi_auth_group_info_json(struct spdk_iscsi_auth_group *group,
1491 			   struct spdk_json_write_ctx *w)
1492 {
1493 	struct spdk_iscsi_auth_secret *_secret;
1494 
1495 	spdk_json_write_object_begin(w);
1496 
1497 	spdk_json_write_named_int32(w, "tag", group->tag);
1498 
1499 	spdk_json_write_named_array_begin(w, "secrets");
1500 	TAILQ_FOREACH(_secret, &group->secret_head, tailq) {
1501 		spdk_json_write_object_begin(w);
1502 
1503 		spdk_json_write_named_string(w, "user", _secret->user);
1504 		spdk_json_write_named_string(w, "secret", _secret->secret);
1505 
1506 		if (_secret->muser[0] != '\0') {
1507 			spdk_json_write_named_string(w, "muser", _secret->muser);
1508 			spdk_json_write_named_string(w, "msecret", _secret->msecret);
1509 		}
1510 
1511 		spdk_json_write_object_end(w);
1512 	}
1513 	spdk_json_write_array_end(w);
1514 
1515 	spdk_json_write_object_end(w);
1516 }
1517 
1518 static void
1519 iscsi_auth_group_config_json(struct spdk_iscsi_auth_group *group,
1520 			     struct spdk_json_write_ctx *w)
1521 {
1522 	spdk_json_write_object_begin(w);
1523 
1524 	spdk_json_write_named_string(w, "method", "iscsi_create_auth_group");
1525 
1526 	spdk_json_write_name(w, "params");
1527 	iscsi_auth_group_info_json(group, w);
1528 
1529 	spdk_json_write_object_end(w);
1530 }
1531 
1532 void
1533 iscsi_auth_groups_info_json(struct spdk_json_write_ctx *w)
1534 {
1535 	struct spdk_iscsi_auth_group *group;
1536 
1537 	TAILQ_FOREACH(group, &g_iscsi.auth_group_head, tailq) {
1538 		iscsi_auth_group_info_json(group, w);
1539 	}
1540 }
1541 
1542 static void
1543 iscsi_auth_groups_config_json(struct spdk_json_write_ctx *w)
1544 {
1545 	struct spdk_iscsi_auth_group *group;
1546 
1547 	TAILQ_FOREACH(group, &g_iscsi.auth_group_head, tailq) {
1548 		iscsi_auth_group_config_json(group, w);
1549 	}
1550 }
1551 
1552 static void
1553 iscsi_opts_config_json(struct spdk_json_write_ctx *w)
1554 {
1555 	spdk_json_write_object_begin(w);
1556 
1557 	spdk_json_write_named_string(w, "method", "iscsi_set_options");
1558 
1559 	spdk_json_write_name(w, "params");
1560 	iscsi_opts_info_json(w);
1561 
1562 	spdk_json_write_object_end(w);
1563 }
1564 
1565 void
1566 spdk_iscsi_config_json(struct spdk_json_write_ctx *w)
1567 {
1568 	spdk_json_write_array_begin(w);
1569 	iscsi_opts_config_json(w);
1570 	iscsi_portal_grps_config_json(w);
1571 	iscsi_init_grps_config_json(w);
1572 	iscsi_tgt_nodes_config_json(w);
1573 	iscsi_auth_groups_config_json(w);
1574 	spdk_json_write_array_end(w);
1575 }
1576 
1577 SPDK_LOG_REGISTER_COMPONENT("iscsi", SPDK_LOG_ISCSI)
1578