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