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