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