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