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