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