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