xref: /spdk/lib/iscsi/iscsi_subsystem.c (revision 56e12b00711b40d1e2ff45d4147193f45fdd9af0)
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 
47 #include "spdk_internal/event.h"
48 #include "spdk_internal/log.h"
49 
50 struct spdk_iscsi_opts *g_spdk_iscsi_opts = NULL;
51 
52 static spdk_iscsi_init_cb g_init_cb_fn = NULL;
53 static void *g_init_cb_arg = NULL;
54 
55 static spdk_iscsi_fini_cb g_fini_cb_fn;
56 static void *g_fini_cb_arg;
57 
58 #define ISCSI_CONFIG_TMPL \
59 "[iSCSI]\n" \
60 "  # node name (not include optional part)\n" \
61 "  # Users can optionally change this to fit their environment.\n" \
62 "  NodeBase \"%s\"\n" \
63 "\n" \
64 "  # files\n" \
65 "  %s %s\n" \
66 "\n" \
67 "  # socket I/O timeout sec. (polling is infinity)\n" \
68 "  Timeout %d\n" \
69 "\n" \
70 "  # authentication information for discovery session\n" \
71 "  DiscoveryAuthMethod %s\n" \
72 "  DiscoveryAuthGroup %s\n" \
73 "\n" \
74 "  MaxSessions %d\n" \
75 "  MaxConnectionsPerSession %d\n" \
76 "  MaxConnections %d\n" \
77 "  MaxQueueDepth %d\n" \
78 "\n" \
79 "  # iSCSI initial parameters negotiate with initiators\n" \
80 "  # NOTE: incorrect values might crash\n" \
81 "  DefaultTime2Wait %d\n" \
82 "  DefaultTime2Retain %d\n" \
83 "\n" \
84 "  FirstBurstLength %d\n" \
85 "  ImmediateData %s\n" \
86 "  ErrorRecoveryLevel %d\n" \
87 "\n"
88 
89 static void
90 spdk_iscsi_globals_config_text(FILE *fp)
91 {
92 	const char *authmethod = "None";
93 	char authgroup[32] = "None";
94 
95 	if (NULL == fp) {
96 		return;
97 	}
98 
99 	if (g_spdk_iscsi.require_chap) {
100 		authmethod = "CHAP";
101 	} else if (g_spdk_iscsi.mutual_chap) {
102 		authmethod = "CHAP Mutual";
103 	} else if (!g_spdk_iscsi.disable_chap) {
104 		authmethod = "Auto";
105 	}
106 
107 	if (g_spdk_iscsi.chap_group) {
108 		snprintf(authgroup, sizeof(authgroup), "AuthGroup%d", g_spdk_iscsi.chap_group);
109 	}
110 
111 	fprintf(fp, ISCSI_CONFIG_TMPL,
112 		g_spdk_iscsi.nodebase,
113 		g_spdk_iscsi.authfile ? "AuthFile" : "",
114 		g_spdk_iscsi.authfile ? g_spdk_iscsi.authfile : "",
115 		g_spdk_iscsi.timeout, authmethod, authgroup,
116 		g_spdk_iscsi.MaxSessions, g_spdk_iscsi.MaxConnectionsPerSession,
117 		g_spdk_iscsi.MaxConnections,
118 		g_spdk_iscsi.MaxQueueDepth,
119 		g_spdk_iscsi.DefaultTime2Wait, g_spdk_iscsi.DefaultTime2Retain,
120 		g_spdk_iscsi.FirstBurstLength,
121 		(g_spdk_iscsi.ImmediateData) ? "Yes" : "No",
122 		g_spdk_iscsi.ErrorRecoveryLevel);
123 }
124 
125 #define ISCSI_DATA_BUFFER_ALIGNMENT	(0x1000)
126 #define ISCSI_DATA_BUFFER_MASK		(ISCSI_DATA_BUFFER_ALIGNMENT - 1)
127 
128 static void
129 spdk_mobj_ctor(struct spdk_mempool *mp, __attribute__((unused)) void *arg,
130 	       void *_m, __attribute__((unused)) unsigned i)
131 {
132 	struct spdk_mobj *m = _m;
133 
134 	m->mp = mp;
135 	m->buf = (uint8_t *)m + sizeof(struct spdk_mobj);
136 	m->buf = (void *)((unsigned long)((uint8_t *)m->buf + ISCSI_DATA_BUFFER_ALIGNMENT) &
137 			  ~ISCSI_DATA_BUFFER_MASK);
138 }
139 
140 #define NUM_PDU_PER_CONNECTION(iscsi)	(2 * (iscsi->MaxQueueDepth + MAX_LARGE_DATAIN_PER_CONNECTION + 8))
141 #define PDU_POOL_SIZE(iscsi)	(iscsi->MaxConnections * NUM_PDU_PER_CONNECTION(iscsi))
142 #define IMMEDIATE_DATA_POOL_SIZE(iscsi)	(iscsi->MaxConnections * 128)
143 #define DATA_OUT_POOL_SIZE(iscsi)	(iscsi->MaxConnections * MAX_DATA_OUT_PER_CONNECTION)
144 
145 static int spdk_iscsi_initialize_pdu_pool(void)
146 {
147 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
148 	int imm_mobj_size = spdk_get_immediate_data_buffer_size() +
149 			    sizeof(struct spdk_mobj) + ISCSI_DATA_BUFFER_ALIGNMENT;
150 	int dout_mobj_size = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH +
151 			     sizeof(struct spdk_mobj) + ISCSI_DATA_BUFFER_ALIGNMENT;
152 
153 	/* create PDU pool */
154 	iscsi->pdu_pool = spdk_mempool_create("PDU_Pool",
155 					      PDU_POOL_SIZE(iscsi),
156 					      sizeof(struct spdk_iscsi_pdu),
157 					      256, SPDK_ENV_SOCKET_ID_ANY);
158 	if (!iscsi->pdu_pool) {
159 		SPDK_ERRLOG("create PDU pool failed\n");
160 		return -1;
161 	}
162 
163 	iscsi->pdu_immediate_data_pool = spdk_mempool_create_ctor("PDU_immediate_data_Pool",
164 					 IMMEDIATE_DATA_POOL_SIZE(iscsi),
165 					 imm_mobj_size, 256,
166 					 spdk_env_get_socket_id(spdk_env_get_current_core()),
167 					 spdk_mobj_ctor, NULL);
168 	if (!iscsi->pdu_immediate_data_pool) {
169 		SPDK_ERRLOG("create PDU immediate data pool failed\n");
170 		return -1;
171 	}
172 
173 	iscsi->pdu_data_out_pool = spdk_mempool_create_ctor("PDU_data_out_Pool",
174 				   DATA_OUT_POOL_SIZE(iscsi),
175 				   dout_mobj_size, 256,
176 				   spdk_env_get_socket_id(spdk_env_get_current_core()),
177 				   spdk_mobj_ctor, NULL);
178 	if (!iscsi->pdu_data_out_pool) {
179 		SPDK_ERRLOG("create PDU data out pool failed\n");
180 		return -1;
181 	}
182 
183 	return 0;
184 }
185 
186 static void spdk_iscsi_sess_ctor(struct spdk_mempool *pool, void *arg,
187 				 void *session_buf, unsigned index)
188 {
189 	struct spdk_iscsi_globals		*iscsi = arg;
190 	struct spdk_iscsi_sess	*sess = session_buf;
191 
192 	iscsi->session[index] = sess;
193 
194 	/* tsih 0 is reserved, so start tsih values at 1. */
195 	sess->tsih = index + 1;
196 }
197 
198 #define DEFAULT_TASK_POOL_SIZE 32768
199 
200 static int
201 spdk_iscsi_initialize_task_pool(void)
202 {
203 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
204 
205 	/* create scsi_task pool */
206 	iscsi->task_pool = spdk_mempool_create("SCSI_TASK_Pool",
207 					       DEFAULT_TASK_POOL_SIZE,
208 					       sizeof(struct spdk_iscsi_task),
209 					       128, SPDK_ENV_SOCKET_ID_ANY);
210 	if (!iscsi->task_pool) {
211 		SPDK_ERRLOG("create task pool failed\n");
212 		return -1;
213 	}
214 
215 	return 0;
216 }
217 
218 #define SESSION_POOL_SIZE(iscsi)	(iscsi->MaxSessions)
219 static int spdk_iscsi_initialize_session_pool(void)
220 {
221 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
222 
223 	iscsi->session_pool = spdk_mempool_create_ctor("Session_Pool",
224 			      SESSION_POOL_SIZE(iscsi),
225 			      sizeof(struct spdk_iscsi_sess), 0,
226 			      SPDK_ENV_SOCKET_ID_ANY,
227 			      spdk_iscsi_sess_ctor, iscsi);
228 	if (!iscsi->session_pool) {
229 		SPDK_ERRLOG("create session pool failed\n");
230 		return -1;
231 	}
232 
233 	return 0;
234 }
235 
236 static int
237 spdk_iscsi_initialize_all_pools(void)
238 {
239 	if (spdk_iscsi_initialize_pdu_pool() != 0) {
240 		return -1;
241 	}
242 
243 	if (spdk_iscsi_initialize_session_pool() != 0) {
244 		return -1;
245 	}
246 
247 	if (spdk_iscsi_initialize_task_pool() != 0) {
248 		return -1;
249 	}
250 
251 	return 0;
252 }
253 
254 static void
255 spdk_iscsi_check_pool(struct spdk_mempool *pool, size_t count)
256 {
257 	if (spdk_mempool_count(pool) != count) {
258 		SPDK_ERRLOG("spdk_mempool_count(%s) == %zu, should be %zu\n",
259 			    spdk_mempool_get_name(pool), spdk_mempool_count(pool), count);
260 	}
261 }
262 
263 static void
264 spdk_iscsi_check_pools(void)
265 {
266 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
267 
268 	spdk_iscsi_check_pool(iscsi->pdu_pool, PDU_POOL_SIZE(iscsi));
269 	spdk_iscsi_check_pool(iscsi->session_pool, SESSION_POOL_SIZE(iscsi));
270 	spdk_iscsi_check_pool(iscsi->pdu_immediate_data_pool, IMMEDIATE_DATA_POOL_SIZE(iscsi));
271 	spdk_iscsi_check_pool(iscsi->pdu_data_out_pool, DATA_OUT_POOL_SIZE(iscsi));
272 	spdk_iscsi_check_pool(iscsi->task_pool, DEFAULT_TASK_POOL_SIZE);
273 }
274 
275 static void
276 spdk_iscsi_free_pools(void)
277 {
278 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
279 
280 	spdk_mempool_free(iscsi->pdu_pool);
281 	spdk_mempool_free(iscsi->session_pool);
282 	spdk_mempool_free(iscsi->pdu_immediate_data_pool);
283 	spdk_mempool_free(iscsi->pdu_data_out_pool);
284 	spdk_mempool_free(iscsi->task_pool);
285 }
286 
287 void spdk_put_pdu(struct spdk_iscsi_pdu *pdu)
288 {
289 	if (!pdu) {
290 		return;
291 	}
292 
293 	pdu->ref--;
294 
295 	if (pdu->ref < 0) {
296 		SPDK_ERRLOG("Negative PDU refcount: %p\n", pdu);
297 		pdu->ref = 0;
298 	}
299 
300 	if (pdu->ref == 0) {
301 		if (pdu->mobj) {
302 			spdk_mempool_put(pdu->mobj->mp, (void *)pdu->mobj);
303 		}
304 
305 		if (pdu->data && !pdu->data_from_mempool) {
306 			free(pdu->data);
307 		}
308 
309 		spdk_mempool_put(g_spdk_iscsi.pdu_pool, (void *)pdu);
310 	}
311 }
312 
313 struct spdk_iscsi_pdu *spdk_get_pdu(void)
314 {
315 	struct spdk_iscsi_pdu *pdu;
316 
317 	pdu = spdk_mempool_get(g_spdk_iscsi.pdu_pool);
318 	if (!pdu) {
319 		SPDK_ERRLOG("Unable to get PDU\n");
320 		abort();
321 	}
322 
323 	/* we do not want to zero out the last part of the structure reserved for AHS and sense data */
324 	memset(pdu, 0, offsetof(struct spdk_iscsi_pdu, ahs));
325 	pdu->ref = 1;
326 
327 	return pdu;
328 }
329 
330 static void
331 spdk_iscsi_log_globals(void)
332 {
333 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "AuthFile %s\n",
334 		      g_spdk_iscsi.authfile ? g_spdk_iscsi.authfile : "(none)");
335 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "NodeBase %s\n", g_spdk_iscsi.nodebase);
336 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxSessions %d\n", g_spdk_iscsi.MaxSessions);
337 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxConnectionsPerSession %d\n",
338 		      g_spdk_iscsi.MaxConnectionsPerSession);
339 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxQueueDepth %d\n", g_spdk_iscsi.MaxQueueDepth);
340 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "DefaultTime2Wait %d\n",
341 		      g_spdk_iscsi.DefaultTime2Wait);
342 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "DefaultTime2Retain %d\n",
343 		      g_spdk_iscsi.DefaultTime2Retain);
344 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "FirstBurstLength %d\n",
345 		      g_spdk_iscsi.FirstBurstLength);
346 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "ImmediateData %s\n",
347 		      g_spdk_iscsi.ImmediateData ? "Yes" : "No");
348 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "AllowDuplicateIsid %s\n",
349 		      g_spdk_iscsi.AllowDuplicateIsid ? "Yes" : "No");
350 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "ErrorRecoveryLevel %d\n",
351 		      g_spdk_iscsi.ErrorRecoveryLevel);
352 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Timeout %d\n", g_spdk_iscsi.timeout);
353 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "NopInInterval %d\n",
354 		      g_spdk_iscsi.nopininterval);
355 	if (g_spdk_iscsi.disable_chap) {
356 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
357 			      "DiscoveryAuthMethod None\n");
358 	} else if (!g_spdk_iscsi.require_chap) {
359 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
360 			      "DiscoveryAuthMethod Auto\n");
361 	} else {
362 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
363 			      "DiscoveryAuthMethod %s %s\n",
364 			      g_spdk_iscsi.require_chap ? "CHAP" : "",
365 			      g_spdk_iscsi.mutual_chap ? "Mutual" : "");
366 	}
367 
368 	if (g_spdk_iscsi.chap_group == 0) {
369 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
370 			      "DiscoveryAuthGroup None\n");
371 	} else {
372 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
373 			      "DiscoveryAuthGroup AuthGroup%d\n",
374 			      g_spdk_iscsi.chap_group);
375 	}
376 
377 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MinConnectionsPerCore%d\n",
378 		      spdk_iscsi_conn_get_min_per_core());
379 }
380 
381 static void
382 spdk_iscsi_opts_init(struct spdk_iscsi_opts *opts)
383 {
384 	opts->MaxSessions = DEFAULT_MAX_SESSIONS;
385 	opts->MaxConnectionsPerSession = DEFAULT_MAX_CONNECTIONS_PER_SESSION;
386 	opts->MaxQueueDepth = DEFAULT_MAX_QUEUE_DEPTH;
387 	opts->DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT;
388 	opts->DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
389 	opts->FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
390 	opts->ImmediateData = DEFAULT_IMMEDIATEDATA;
391 	opts->AllowDuplicateIsid = false;
392 	opts->ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL;
393 	opts->timeout = DEFAULT_TIMEOUT;
394 	opts->nopininterval = DEFAULT_NOPININTERVAL;
395 	opts->disable_chap = false;
396 	opts->require_chap = false;
397 	opts->mutual_chap = false;
398 	opts->chap_group = 0;
399 	opts->authfile = NULL;
400 	opts->nodebase = NULL;
401 	opts->min_connections_per_core = DEFAULT_CONNECTIONS_PER_LCORE;
402 }
403 
404 struct spdk_iscsi_opts *
405 spdk_iscsi_opts_alloc(void)
406 {
407 	struct spdk_iscsi_opts *opts;
408 
409 	opts = calloc(1, sizeof(*opts));
410 	if (!opts) {
411 		SPDK_ERRLOG("calloc() failed for iscsi options\n");
412 		return NULL;
413 	}
414 
415 	spdk_iscsi_opts_init(opts);
416 
417 	return opts;
418 }
419 
420 void
421 spdk_iscsi_opts_free(struct spdk_iscsi_opts *opts)
422 {
423 	free(opts->authfile);
424 	free(opts->nodebase);
425 	free(opts);
426 }
427 
428 /* Deep copy of spdk_iscsi_opts */
429 struct spdk_iscsi_opts *
430 spdk_iscsi_opts_copy(struct spdk_iscsi_opts *src)
431 {
432 	struct spdk_iscsi_opts *dst;
433 
434 	dst = calloc(1, sizeof(*dst));
435 	if (!dst) {
436 		SPDK_ERRLOG("calloc() failed for iscsi options\n");
437 		return NULL;
438 	}
439 
440 	if (src->authfile) {
441 		dst->authfile = strdup(src->authfile);
442 		if (!dst->authfile) {
443 			free(dst);
444 			SPDK_ERRLOG("failed to strdup for auth file %s\n", src->authfile);
445 			return NULL;
446 		}
447 	}
448 
449 	if (src->nodebase) {
450 		dst->nodebase = strdup(src->nodebase);
451 		if (!dst->nodebase) {
452 			free(dst->authfile);
453 			free(dst);
454 			SPDK_ERRLOG("failed to strdup for nodebase %s\n", src->nodebase);
455 			return NULL;
456 		}
457 	}
458 
459 	dst->MaxSessions = src->MaxSessions;
460 	dst->MaxConnectionsPerSession = src->MaxConnectionsPerSession;
461 	dst->MaxQueueDepth = src->MaxQueueDepth;
462 	dst->DefaultTime2Wait = src->DefaultTime2Wait;
463 	dst->DefaultTime2Retain = src->DefaultTime2Retain;
464 	dst->FirstBurstLength = src->FirstBurstLength;
465 	dst->ImmediateData = src->ImmediateData;
466 	dst->AllowDuplicateIsid = src->AllowDuplicateIsid;
467 	dst->ErrorRecoveryLevel = src->ErrorRecoveryLevel;
468 	dst->timeout = src->timeout;
469 	dst->nopininterval = src->nopininterval;
470 	dst->disable_chap = src->disable_chap;
471 	dst->require_chap = src->require_chap;
472 	dst->mutual_chap = src->mutual_chap;
473 	dst->chap_group = src->chap_group;
474 	dst->min_connections_per_core = src->min_connections_per_core;
475 
476 	return dst;
477 }
478 
479 static int
480 spdk_iscsi_read_config_file_params(struct spdk_conf_section *sp,
481 				   struct spdk_iscsi_opts *opts)
482 {
483 	const char *val;
484 	int MaxSessions;
485 	int MaxConnectionsPerSession;
486 	int MaxQueueDepth;
487 	int DefaultTime2Wait;
488 	int DefaultTime2Retain;
489 	int FirstBurstLength;
490 	int ErrorRecoveryLevel;
491 	int timeout;
492 	int nopininterval;
493 	int min_conn_per_core = 0;
494 	const char *ag_tag;
495 	int ag_tag_i;
496 	int i;
497 
498 	val = spdk_conf_section_get_val(sp, "Comment");
499 	if (val != NULL) {
500 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Comment %s\n", val);
501 	}
502 
503 	val = spdk_conf_section_get_val(sp, "AuthFile");
504 	if (val != NULL) {
505 		opts->authfile = strdup(val);
506 		if (!opts->authfile) {
507 			SPDK_ERRLOG("strdup() failed for AuthFile\n");
508 			return -ENOMEM;
509 		}
510 	}
511 
512 	val = spdk_conf_section_get_val(sp, "NodeBase");
513 	if (val != NULL) {
514 		opts->nodebase = strdup(val);
515 		if (!opts->nodebase) {
516 			free(opts->authfile);
517 			SPDK_ERRLOG("strdup() failed for NodeBase\n");
518 			return -ENOMEM;
519 		}
520 	}
521 
522 	MaxSessions = spdk_conf_section_get_intval(sp, "MaxSessions");
523 	if (MaxSessions >= 0) {
524 		opts->MaxSessions = MaxSessions;
525 	}
526 
527 	MaxConnectionsPerSession = spdk_conf_section_get_intval(sp, "MaxConnectionsPerSession");
528 	if (MaxConnectionsPerSession >= 0) {
529 		opts->MaxConnectionsPerSession = MaxConnectionsPerSession;
530 	}
531 
532 	MaxQueueDepth = spdk_conf_section_get_intval(sp, "MaxQueueDepth");
533 	if (MaxQueueDepth >= 0) {
534 		opts->MaxQueueDepth = MaxQueueDepth;
535 	}
536 
537 	DefaultTime2Wait = spdk_conf_section_get_intval(sp, "DefaultTime2Wait");
538 	if (DefaultTime2Wait >= 0) {
539 		opts->DefaultTime2Wait = DefaultTime2Wait;
540 	}
541 
542 	DefaultTime2Retain = spdk_conf_section_get_intval(sp, "DefaultTime2Retain");
543 	if (DefaultTime2Retain >= 0) {
544 		opts->DefaultTime2Retain = DefaultTime2Retain;
545 	}
546 
547 	FirstBurstLength = spdk_conf_section_get_intval(sp, "FirstBurstLength");
548 	if (FirstBurstLength >= 0) {
549 		opts->FirstBurstLength = FirstBurstLength;
550 	}
551 
552 	opts->ImmediateData = spdk_conf_section_get_boolval(sp, "ImmediateData",
553 			      opts->ImmediateData);
554 
555 	/* This option is only for test.
556 	 * If AllowDuplicateIsid is enabled, it allows different connections carrying
557 	 * TSIH=0 login the target within the same session.
558 	 */
559 	opts->AllowDuplicateIsid = spdk_conf_section_get_boolval(sp, "AllowDuplicateIsid",
560 				   opts->AllowDuplicateIsid);
561 
562 	ErrorRecoveryLevel = spdk_conf_section_get_intval(sp, "ErrorRecoveryLevel");
563 	if (ErrorRecoveryLevel >= 0) {
564 		opts->ErrorRecoveryLevel = ErrorRecoveryLevel;
565 	}
566 	timeout = spdk_conf_section_get_intval(sp, "Timeout");
567 	if (timeout >= 0) {
568 		opts->timeout = timeout;
569 	}
570 	nopininterval = spdk_conf_section_get_intval(sp, "NopInInterval");
571 	if (nopininterval >= 0) {
572 		opts->nopininterval = nopininterval;
573 	}
574 	val = spdk_conf_section_get_val(sp, "DiscoveryAuthMethod");
575 	if (val != NULL) {
576 		for (i = 0; ; i++) {
577 			val = spdk_conf_section_get_nmval(sp, "DiscoveryAuthMethod", 0, i);
578 			if (val == NULL) {
579 				break;
580 			}
581 			if (strcasecmp(val, "CHAP") == 0) {
582 				opts->require_chap = true;
583 			} else if (strcasecmp(val, "Mutual") == 0) {
584 				opts->require_chap = true;
585 				opts->mutual_chap = true;
586 			} else if (strcasecmp(val, "Auto") == 0) {
587 				opts->disable_chap = false;
588 				opts->require_chap = false;
589 				opts->mutual_chap = false;
590 			} else if (strcasecmp(val, "None") == 0) {
591 				opts->disable_chap = true;
592 				opts->require_chap = false;
593 				opts->mutual_chap = false;
594 			} else {
595 				SPDK_ERRLOG("unknown CHAP mode %s\n", val);
596 			}
597 		}
598 		if (opts->mutual_chap && !opts->require_chap) {
599 			SPDK_ERRLOG("CHAP must set to be required when using mutual CHAP.\n");
600 			return -EINVAL;
601 		}
602 	}
603 	val = spdk_conf_section_get_val(sp, "DiscoveryAuthGroup");
604 	if (val != NULL) {
605 		ag_tag = val;
606 		if (strcasecmp(ag_tag, "None") == 0) {
607 			opts->chap_group = 0;
608 		} else {
609 			if (strncasecmp(ag_tag, "AuthGroup",
610 					strlen("AuthGroup")) != 0
611 			    || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1
612 			    || ag_tag_i == 0) {
613 				SPDK_ERRLOG("invalid auth group %s, ignoring\n", ag_tag);
614 			} else {
615 				opts->chap_group = ag_tag_i;
616 			}
617 		}
618 	}
619 	min_conn_per_core = spdk_conf_section_get_intval(sp, "MinConnectionsPerCore");
620 	if (min_conn_per_core >= 0) {
621 		opts->min_connections_per_core = min_conn_per_core;
622 	}
623 
624 	return 0;
625 }
626 
627 static int
628 spdk_iscsi_opts_verify(struct spdk_iscsi_opts *opts)
629 {
630 	if (!opts->nodebase) {
631 		opts->nodebase = strdup(SPDK_ISCSI_DEFAULT_NODEBASE);
632 		if (opts->nodebase == NULL) {
633 			SPDK_ERRLOG("strdup() failed for default nodebase\n");
634 			return -ENOMEM;
635 		}
636 	}
637 
638 	if (opts->MaxSessions == 0 || opts->MaxSessions > 65535) {
639 		SPDK_ERRLOG("%d is invalid. MaxSessions must be more than 0 and no more than 65535\n",
640 			    opts->MaxSessions);
641 		return -EINVAL;
642 	}
643 
644 	if (opts->MaxConnectionsPerSession == 0 || opts->MaxConnectionsPerSession > 65535) {
645 		SPDK_ERRLOG("%d is invalid. MaxConnectionsPerSession must be more than 0 and no more than 65535\n",
646 			    opts->MaxConnectionsPerSession);
647 		return -EINVAL;
648 	}
649 
650 	if (opts->MaxQueueDepth == 0 || opts->MaxQueueDepth > 256) {
651 		SPDK_ERRLOG("%d is invalid. MaxQueueDepth must be more than 0 and no more than 256\n",
652 			    opts->MaxQueueDepth);
653 		return -EINVAL;
654 	}
655 
656 	if (opts->DefaultTime2Wait > 3600) {
657 		SPDK_ERRLOG("%d is invalid. DefaultTime2Wait must be no more than 3600\n",
658 			    opts->DefaultTime2Wait);
659 		return -EINVAL;
660 	}
661 
662 	if (opts->DefaultTime2Retain > 3600) {
663 		SPDK_ERRLOG("%d is invalid. DefaultTime2Retain must be no more than 3600\n",
664 			    opts->DefaultTime2Retain);
665 		return -EINVAL;
666 	}
667 
668 	if (opts->FirstBurstLength >= SPDK_ISCSI_MIN_FIRST_BURST_LENGTH) {
669 		if (opts->FirstBurstLength > SPDK_ISCSI_MAX_BURST_LENGTH) {
670 			SPDK_ERRLOG("FirstBurstLength %d shall not exceed MaxBurstLength %d\n",
671 				    opts->FirstBurstLength, SPDK_ISCSI_MAX_BURST_LENGTH);
672 			return -EINVAL;
673 		}
674 	} else {
675 		SPDK_ERRLOG("FirstBurstLength %d shall be no less than %d\n",
676 			    opts->FirstBurstLength, SPDK_ISCSI_MIN_FIRST_BURST_LENGTH);
677 		return -EINVAL;
678 	}
679 
680 	if (opts->ErrorRecoveryLevel > 2) {
681 		SPDK_ERRLOG("ErrorRecoveryLevel %d is not supported.\n", opts->ErrorRecoveryLevel);
682 		return -EINVAL;
683 	}
684 
685 	if (opts->timeout < 0) {
686 		SPDK_ERRLOG("%d is invalid. timeout must not be less than 0\n", opts->timeout);
687 		return -EINVAL;
688 	}
689 
690 	if (opts->nopininterval < 0 || opts->nopininterval > MAX_NOPININTERVAL) {
691 		SPDK_ERRLOG("%d is invalid. nopinterval must be between 0 and %d\n",
692 			    opts->nopininterval, MAX_NOPININTERVAL);
693 		return -EINVAL;
694 	}
695 
696 	if (!spdk_iscsi_check_chap_params(opts->disable_chap, opts->require_chap,
697 					  opts->mutual_chap, opts->chap_group)) {
698 		SPDK_ERRLOG("CHAP params in opts are illegal combination\n");
699 		return -EINVAL;
700 	}
701 
702 	return 0;
703 }
704 
705 static int
706 spdk_iscsi_parse_options(struct spdk_iscsi_opts **popts)
707 {
708 	struct spdk_iscsi_opts *opts;
709 	struct spdk_conf_section *sp;
710 	int rc;
711 
712 	opts = spdk_iscsi_opts_alloc();
713 	if (!opts) {
714 		SPDK_ERRLOG("spdk_iscsi_opts_alloc_failed() failed\n");
715 		return -ENOMEM;
716 	}
717 
718 	/* Process parameters */
719 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "spdk_iscsi_read_config_file_parmas\n");
720 	sp = spdk_conf_find_section(NULL, "iSCSI");
721 	if (sp != NULL) {
722 		rc = spdk_iscsi_read_config_file_params(sp, opts);
723 		if (rc != 0) {
724 			free(opts);
725 			SPDK_ERRLOG("spdk_iscsi_read_config_file_params() failed\n");
726 			return rc;
727 		}
728 	}
729 
730 	*popts = opts;
731 
732 	return 0;
733 }
734 
735 static int
736 spdk_iscsi_set_global_params(struct spdk_iscsi_opts *opts)
737 {
738 	int rc;
739 
740 	rc = spdk_iscsi_opts_verify(opts);
741 	if (rc != 0) {
742 		SPDK_ERRLOG("spdk_iscsi_opts_verify() failed\n");
743 		return rc;
744 	}
745 
746 	if (opts->authfile != NULL) {
747 		g_spdk_iscsi.authfile = strdup(opts->authfile);
748 		if (!g_spdk_iscsi.authfile) {
749 			SPDK_ERRLOG("failed to strdup for auth file %s\n", opts->authfile);
750 			return -ENOMEM;
751 		}
752 	}
753 
754 	g_spdk_iscsi.nodebase = strdup(opts->nodebase);
755 	if (!g_spdk_iscsi.nodebase) {
756 		SPDK_ERRLOG("failed to strdup for nodebase %s\n", opts->nodebase);
757 		return -ENOMEM;
758 	}
759 
760 	g_spdk_iscsi.MaxSessions = opts->MaxSessions;
761 	g_spdk_iscsi.MaxConnectionsPerSession = opts->MaxConnectionsPerSession;
762 	g_spdk_iscsi.MaxQueueDepth = opts->MaxQueueDepth;
763 	g_spdk_iscsi.DefaultTime2Wait = opts->DefaultTime2Wait;
764 	g_spdk_iscsi.DefaultTime2Retain = opts->DefaultTime2Retain;
765 	g_spdk_iscsi.FirstBurstLength = opts->FirstBurstLength;
766 	g_spdk_iscsi.ImmediateData = opts->ImmediateData;
767 	g_spdk_iscsi.AllowDuplicateIsid = opts->AllowDuplicateIsid;
768 	g_spdk_iscsi.ErrorRecoveryLevel = opts->ErrorRecoveryLevel;
769 	g_spdk_iscsi.timeout = opts->timeout;
770 	g_spdk_iscsi.nopininterval = opts->nopininterval;
771 	g_spdk_iscsi.disable_chap = opts->disable_chap;
772 	g_spdk_iscsi.require_chap = opts->require_chap;
773 	g_spdk_iscsi.mutual_chap = opts->mutual_chap;
774 	g_spdk_iscsi.chap_group = opts->chap_group;
775 
776 	spdk_iscsi_conn_set_min_per_core(opts->min_connections_per_core);
777 
778 	spdk_iscsi_log_globals();
779 
780 	return 0;
781 }
782 
783 int
784 spdk_iscsi_set_discovery_auth(bool disable_chap, bool require_chap, bool mutual_chap,
785 			      int32_t chap_group)
786 {
787 	if (!spdk_iscsi_check_chap_params(disable_chap, require_chap, mutual_chap,
788 					  chap_group)) {
789 		SPDK_ERRLOG("CHAP params are illegal combination\n");
790 		return -EINVAL;
791 	}
792 
793 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
794 	g_spdk_iscsi.disable_chap = disable_chap;
795 	g_spdk_iscsi.require_chap = require_chap;
796 	g_spdk_iscsi.mutual_chap = mutual_chap;
797 	g_spdk_iscsi.chap_group = chap_group;
798 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
799 
800 	return 0;
801 }
802 
803 int
804 spdk_iscsi_auth_group_add_secret(struct spdk_iscsi_auth_group *group,
805 				 const char *user, const char *secret,
806 				 const char *muser, const char *msecret)
807 {
808 	struct spdk_iscsi_auth_secret *_secret;
809 	size_t len;
810 
811 	if (user == NULL || secret == NULL) {
812 		SPDK_ERRLOG("user and secret must be specified\n");
813 		return -EINVAL;
814 	}
815 
816 	if (muser != NULL && msecret == NULL) {
817 		SPDK_ERRLOG("msecret must be specified with muser\n");
818 		return -EINVAL;
819 	}
820 
821 	TAILQ_FOREACH(_secret, &group->secret_head, tailq) {
822 		if (strcmp(_secret->user, user) == 0) {
823 			SPDK_ERRLOG("user for secret is duplicated\n");
824 			return -EEXIST;
825 		}
826 	}
827 
828 	_secret = calloc(1, sizeof(*_secret));
829 	if (_secret == NULL) {
830 		SPDK_ERRLOG("calloc() failed for CHAP secret\n");
831 		return -ENOMEM;
832 	}
833 
834 	len = strnlen(user, sizeof(_secret->user));
835 	if (len > sizeof(_secret->user) - 1) {
836 		SPDK_ERRLOG("CHAP user longer than %zu characters: %s\n",
837 			    sizeof(_secret->user) - 1, user);
838 		free(_secret);
839 		return -EINVAL;
840 	}
841 	memcpy(_secret->user, user, len);
842 
843 	len = strnlen(secret, sizeof(_secret->secret));
844 	if (len > sizeof(_secret->secret) - 1) {
845 		SPDK_ERRLOG("CHAP secret longer than %zu characters: %s\n",
846 			    sizeof(_secret->secret) - 1, secret);
847 		free(_secret);
848 		return -EINVAL;
849 	}
850 	memcpy(_secret->secret, secret, len);
851 
852 	if (muser != NULL) {
853 		len = strnlen(muser, sizeof(_secret->muser));
854 		if (len > sizeof(_secret->muser) - 1) {
855 			SPDK_ERRLOG("Mutual CHAP user longer than %zu characters: %s\n",
856 				    sizeof(_secret->muser) - 1, muser);
857 			free(_secret);
858 			return -EINVAL;
859 		}
860 		memcpy(_secret->muser, muser, len);
861 
862 		len = strnlen(msecret, sizeof(_secret->msecret));
863 		if (len > sizeof(_secret->msecret) - 1) {
864 			SPDK_ERRLOG("Mutual CHAP secret longer than %zu characters: %s\n",
865 				    sizeof(_secret->msecret) - 1, msecret);
866 			free(_secret);
867 			return -EINVAL;
868 		}
869 		memcpy(_secret->msecret, msecret, len);
870 	}
871 
872 	TAILQ_INSERT_TAIL(&group->secret_head, _secret, tailq);
873 	return 0;
874 }
875 
876 int
877 spdk_iscsi_auth_group_delete_secret(struct spdk_iscsi_auth_group *group,
878 				    const char *user)
879 {
880 	struct spdk_iscsi_auth_secret *_secret;
881 
882 	if (user == NULL) {
883 		SPDK_ERRLOG("user must be specified\n");
884 		return -EINVAL;
885 	}
886 
887 	TAILQ_FOREACH(_secret, &group->secret_head, tailq) {
888 		if (strcmp(_secret->user, user) == 0) {
889 			break;
890 		}
891 	}
892 
893 	if (_secret == NULL) {
894 		SPDK_ERRLOG("secret is not found\n");
895 		return -ENODEV;
896 	}
897 
898 	TAILQ_REMOVE(&group->secret_head, _secret, tailq);
899 	free(_secret);
900 
901 	return 0;
902 }
903 
904 int
905 spdk_iscsi_add_auth_group(int32_t tag, struct spdk_iscsi_auth_group **_group)
906 {
907 	struct spdk_iscsi_auth_group *group;
908 
909 	TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) {
910 		if (group->tag == tag) {
911 			SPDK_ERRLOG("Auth group (%d) already exists\n", tag);
912 			return -EEXIST;
913 		}
914 	}
915 
916 	group = calloc(1, sizeof(*group));
917 	if (group == NULL) {
918 		SPDK_ERRLOG("calloc() failed for auth group\n");
919 		return -ENOMEM;
920 	}
921 
922 	TAILQ_INIT(&group->secret_head);
923 	group->tag = tag;
924 
925 	TAILQ_INSERT_TAIL(&g_spdk_iscsi.auth_group_head, group, tailq);
926 
927 	*_group = group;
928 	return 0;
929 }
930 
931 void
932 spdk_iscsi_delete_auth_group(struct spdk_iscsi_auth_group *group)
933 {
934 	struct spdk_iscsi_auth_secret *_secret, *tmp;
935 
936 	TAILQ_REMOVE(&g_spdk_iscsi.auth_group_head, group, tailq);
937 
938 	TAILQ_FOREACH_SAFE(_secret, &group->secret_head, tailq, tmp) {
939 		TAILQ_REMOVE(&group->secret_head, _secret, tailq);
940 		free(_secret);
941 	}
942 	free(group);
943 }
944 
945 struct spdk_iscsi_auth_group *
946 spdk_iscsi_find_auth_group_by_tag(int32_t tag)
947 {
948 	struct spdk_iscsi_auth_group *group;
949 
950 	TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) {
951 		if (group->tag == tag) {
952 			return group;
953 		}
954 	}
955 
956 	return NULL;
957 }
958 
959 static void
960 spdk_iscsi_auth_groups_destroy(void)
961 {
962 	struct spdk_iscsi_auth_group *group, *tmp;
963 
964 	TAILQ_FOREACH_SAFE(group, &g_spdk_iscsi.auth_group_head, tailq, tmp) {
965 		spdk_iscsi_delete_auth_group(group);
966 	}
967 }
968 
969 static int
970 spdk_iscsi_parse_auth_group(struct spdk_conf_section *sp)
971 {
972 	int rc;
973 	int i;
974 	int tag;
975 	const char *val, *user, *secret, *muser, *msecret;
976 	struct spdk_iscsi_auth_group *group = NULL;
977 
978 	val = spdk_conf_section_get_val(sp, "Comment");
979 	if (val != NULL) {
980 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Comment %s\n", val);
981 	}
982 
983 	tag = spdk_conf_section_get_num(sp);
984 
985 	rc = spdk_iscsi_add_auth_group(tag, &group);
986 	if (rc != 0) {
987 		SPDK_ERRLOG("Failed to add auth group\n");
988 		return rc;
989 	}
990 
991 	for (i = 0; ; i++) {
992 		val = spdk_conf_section_get_nval(sp, "Auth", i);
993 		if (val == NULL) {
994 			break;
995 		}
996 
997 		user = spdk_conf_section_get_nmval(sp, "Auth", i, 0);
998 		secret = spdk_conf_section_get_nmval(sp, "Auth", i, 1);
999 		muser = spdk_conf_section_get_nmval(sp, "Auth", i, 2);
1000 		msecret = spdk_conf_section_get_nmval(sp, "Auth", i, 3);
1001 
1002 		rc = spdk_iscsi_auth_group_add_secret(group, user, secret, muser, msecret);
1003 		if (rc != 0) {
1004 			SPDK_ERRLOG("Failed to add secret to auth group\n");
1005 			spdk_iscsi_delete_auth_group(group);
1006 			return rc;
1007 		}
1008 	}
1009 
1010 	return 0;
1011 }
1012 
1013 static int
1014 spdk_iscsi_parse_auth_info(void)
1015 {
1016 	struct spdk_conf *config;
1017 	struct spdk_conf_section *sp;
1018 	int rc;
1019 
1020 	config = spdk_conf_allocate();
1021 	if (!config) {
1022 		SPDK_ERRLOG("Failed to allocate config file\n");
1023 		return -ENOMEM;
1024 	}
1025 
1026 	rc = spdk_conf_read(config, g_spdk_iscsi.authfile);
1027 	if (rc != 0) {
1028 		SPDK_INFOLOG(SPDK_LOG_ISCSI, "Failed to load auth file\n");
1029 		spdk_conf_free(config);
1030 		return rc;
1031 	}
1032 
1033 	sp = spdk_conf_first_section(config);
1034 	while (sp != NULL) {
1035 		if (spdk_conf_section_match_prefix(sp, "AuthGroup")) {
1036 			if (spdk_conf_section_get_num(sp) == 0) {
1037 				SPDK_ERRLOG("Group 0 is invalid\n");
1038 				spdk_iscsi_auth_groups_destroy();
1039 				spdk_conf_free(config);
1040 				return -EINVAL;
1041 			}
1042 
1043 			rc = spdk_iscsi_parse_auth_group(sp);
1044 			if (rc != 0) {
1045 				SPDK_ERRLOG("parse_auth_group() failed\n");
1046 				spdk_iscsi_auth_groups_destroy();
1047 				spdk_conf_free(config);
1048 				return rc;
1049 			}
1050 		}
1051 		sp = spdk_conf_next_section(sp);
1052 	}
1053 
1054 	spdk_conf_free(config);
1055 	return 0;
1056 }
1057 
1058 static struct spdk_iscsi_auth_secret *
1059 spdk_iscsi_find_auth_secret(const char *authuser, int ag_tag)
1060 {
1061 	struct spdk_iscsi_auth_group *group;
1062 	struct spdk_iscsi_auth_secret *_secret;
1063 
1064 	TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) {
1065 		if (group->tag == ag_tag) {
1066 			TAILQ_FOREACH(_secret, &group->secret_head, tailq) {
1067 				if (strcmp(_secret->user, authuser) == 0) {
1068 					return _secret;
1069 				}
1070 			}
1071 		}
1072 	}
1073 
1074 	return NULL;
1075 }
1076 
1077 int
1078 spdk_iscsi_chap_get_authinfo(struct iscsi_chap_auth *auth, const char *authuser,
1079 			     int ag_tag)
1080 {
1081 	struct spdk_iscsi_auth_secret *_secret;
1082 
1083 	if (authuser == NULL) {
1084 		return -EINVAL;
1085 	}
1086 
1087 	if (auth->user[0] != '\0') {
1088 		memset(auth->user, 0, sizeof(auth->user));
1089 		memset(auth->secret, 0, sizeof(auth->secret));
1090 		memset(auth->muser, 0, sizeof(auth->muser));
1091 		memset(auth->msecret, 0, sizeof(auth->msecret));
1092 	}
1093 
1094 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
1095 
1096 	_secret = spdk_iscsi_find_auth_secret(authuser, ag_tag);
1097 	if (_secret == NULL) {
1098 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1099 
1100 		SPDK_ERRLOG("CHAP secret is not found: user:%s, tag:%d\n",
1101 			    authuser, ag_tag);
1102 		return -ENOENT;
1103 	}
1104 
1105 	memcpy(auth->user, _secret->user, sizeof(auth->user));
1106 	memcpy(auth->secret, _secret->secret, sizeof(auth->secret));
1107 
1108 	if (_secret->muser[0] != '\0') {
1109 		memcpy(auth->muser, _secret->muser, sizeof(auth->muser));
1110 		memcpy(auth->msecret, _secret->msecret, sizeof(auth->msecret));
1111 	}
1112 
1113 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1114 	return 0;
1115 }
1116 
1117 static int
1118 spdk_iscsi_initialize_global_params(void)
1119 {
1120 	int rc;
1121 
1122 	if (!g_spdk_iscsi_opts) {
1123 		rc = spdk_iscsi_parse_options(&g_spdk_iscsi_opts);
1124 		if (rc != 0) {
1125 			SPDK_ERRLOG("spdk_iscsi_parse_options() failed\n");
1126 			return rc;
1127 		}
1128 	}
1129 
1130 	rc = spdk_iscsi_set_global_params(g_spdk_iscsi_opts);
1131 	if (rc != 0) {
1132 		SPDK_ERRLOG("spdk_iscsi_set_global_params() failed\n");
1133 	}
1134 
1135 	spdk_iscsi_opts_free(g_spdk_iscsi_opts);
1136 	g_spdk_iscsi_opts = NULL;
1137 
1138 	return rc;
1139 }
1140 
1141 static void
1142 spdk_iscsi_init_complete(int rc)
1143 {
1144 	spdk_iscsi_init_cb cb_fn = g_init_cb_fn;
1145 	void *cb_arg = g_init_cb_arg;
1146 
1147 	g_init_cb_fn = NULL;
1148 	g_init_cb_arg = NULL;
1149 
1150 	cb_fn(cb_arg, rc);
1151 }
1152 
1153 static int
1154 spdk_iscsi_poll_group_poll(void *ctx)
1155 {
1156 	struct spdk_iscsi_poll_group *group = ctx;
1157 	struct spdk_iscsi_conn *conn, *tmp;
1158 	int rc;
1159 
1160 	if (spdk_unlikely(STAILQ_EMPTY(&group->connections))) {
1161 		return 0;
1162 	}
1163 
1164 	rc = spdk_sock_group_poll(group->sock_group);
1165 	if (rc < 0) {
1166 		SPDK_ERRLOG("Failed to poll sock_group=%p\n", group->sock_group);
1167 	}
1168 
1169 	STAILQ_FOREACH_SAFE(conn, &group->connections, link, tmp) {
1170 		if (conn->state == ISCSI_CONN_STATE_EXITING) {
1171 			spdk_iscsi_conn_destruct(conn);
1172 		}
1173 	}
1174 
1175 	return -1;
1176 }
1177 
1178 static int
1179 spdk_iscsi_poll_group_handle_nop(void *ctx)
1180 {
1181 	struct spdk_iscsi_poll_group *group = ctx;
1182 	struct spdk_iscsi_conn *conn, *tmp;
1183 
1184 	STAILQ_FOREACH_SAFE(conn, &group->connections, link, tmp) {
1185 		spdk_iscsi_conn_handle_nop(conn);
1186 	}
1187 
1188 	return -1;
1189 }
1190 
1191 static void
1192 iscsi_create_poll_group(void *ctx)
1193 {
1194 	struct spdk_iscsi_poll_group *pg;
1195 
1196 	assert(g_spdk_iscsi.poll_group != NULL);
1197 	pg = &g_spdk_iscsi.poll_group[spdk_env_get_current_core()];
1198 	pg->core = spdk_env_get_current_core();
1199 
1200 	STAILQ_INIT(&pg->connections);
1201 	pg->sock_group = spdk_sock_group_create();
1202 	assert(pg->sock_group != NULL);
1203 
1204 	pg->poller = spdk_poller_register(spdk_iscsi_poll_group_poll, pg, 0);
1205 	/* set the period to 1 sec */
1206 	pg->nop_poller = spdk_poller_register(spdk_iscsi_poll_group_handle_nop, pg, 1000000);
1207 }
1208 
1209 static void
1210 iscsi_unregister_poll_group(void *ctx)
1211 {
1212 	struct spdk_iscsi_poll_group *pg;
1213 
1214 	assert(g_spdk_iscsi.poll_group != NULL);
1215 	pg = &g_spdk_iscsi.poll_group[spdk_env_get_current_core()];
1216 	assert(pg->poller != NULL);
1217 	assert(pg->sock_group != NULL);
1218 
1219 	spdk_sock_group_close(&pg->sock_group);
1220 	spdk_poller_unregister(&pg->poller);
1221 	spdk_poller_unregister(&pg->nop_poller);
1222 }
1223 
1224 static void
1225 spdk_initialize_iscsi_poll_group(spdk_msg_fn cpl)
1226 {
1227 	size_t g_num_poll_groups = spdk_env_get_last_core() + 1;
1228 
1229 	g_spdk_iscsi.poll_group = calloc(g_num_poll_groups, sizeof(struct spdk_iscsi_poll_group));
1230 	if (!g_spdk_iscsi.poll_group) {
1231 		SPDK_ERRLOG("Failed to allocated iscsi poll group\n");
1232 		spdk_iscsi_init_complete(-1);
1233 		return;
1234 	}
1235 
1236 	/* Send a message to each thread and create a poll group */
1237 	spdk_for_each_thread(iscsi_create_poll_group, NULL, cpl);
1238 }
1239 
1240 static void
1241 spdk_iscsi_parse_configuration(void *ctx)
1242 {
1243 	int rc;
1244 
1245 	rc = spdk_iscsi_parse_portal_grps();
1246 	if (rc < 0) {
1247 		SPDK_ERRLOG("spdk_iscsi_parse_portal_grps() failed\n");
1248 		goto end;
1249 	}
1250 
1251 	rc = spdk_iscsi_parse_init_grps();
1252 	if (rc < 0) {
1253 		SPDK_ERRLOG("spdk_iscsi_parse_init_grps() failed\n");
1254 		goto end;
1255 	}
1256 
1257 	rc = spdk_iscsi_parse_tgt_nodes();
1258 	if (rc < 0) {
1259 		SPDK_ERRLOG("spdk_iscsi_parse_tgt_nodes() failed\n");
1260 	}
1261 
1262 	if (g_spdk_iscsi.authfile != NULL) {
1263 		if (access(g_spdk_iscsi.authfile, R_OK) == 0) {
1264 			rc = spdk_iscsi_parse_auth_info();
1265 			if (rc < 0) {
1266 				SPDK_ERRLOG("spdk_iscsi_parse_auth_info() failed\n");
1267 			}
1268 		} else {
1269 			SPDK_INFOLOG(SPDK_LOG_ISCSI, "CHAP secret file is not found in the path %s\n",
1270 				     g_spdk_iscsi.authfile);
1271 		}
1272 	}
1273 
1274 end:
1275 	spdk_iscsi_init_complete(rc);
1276 }
1277 
1278 static int
1279 spdk_iscsi_parse_globals(void)
1280 {
1281 	int rc;
1282 
1283 	rc = spdk_iscsi_initialize_global_params();
1284 	if (rc != 0) {
1285 		SPDK_ERRLOG("spdk_iscsi_initialize_iscsi_global_params() failed\n");
1286 		return rc;
1287 	}
1288 
1289 	g_spdk_iscsi.session = spdk_dma_zmalloc(sizeof(void *) * g_spdk_iscsi.MaxSessions, 0, NULL);
1290 	if (!g_spdk_iscsi.session) {
1291 		SPDK_ERRLOG("spdk_dma_zmalloc() failed for session array\n");
1292 		return -1;
1293 	}
1294 
1295 	/*
1296 	 * For now, just support same number of total connections, rather
1297 	 *  than MaxSessions * MaxConnectionsPerSession.  After we add better
1298 	 *  handling for low resource conditions from our various buffer
1299 	 *  pools, we can bump this up to support more connections.
1300 	 */
1301 	g_spdk_iscsi.MaxConnections = g_spdk_iscsi.MaxSessions;
1302 
1303 	rc = spdk_iscsi_initialize_all_pools();
1304 	if (rc != 0) {
1305 		SPDK_ERRLOG("spdk_initialize_all_pools() failed\n");
1306 		return -1;
1307 	}
1308 
1309 	rc = spdk_initialize_iscsi_conns();
1310 	if (rc < 0) {
1311 		SPDK_ERRLOG("spdk_initialize_iscsi_conns() failed\n");
1312 		return rc;
1313 	}
1314 
1315 	spdk_initialize_iscsi_poll_group(spdk_iscsi_parse_configuration);
1316 	return 0;
1317 }
1318 
1319 void
1320 spdk_iscsi_init(spdk_iscsi_init_cb cb_fn, void *cb_arg)
1321 {
1322 	int rc;
1323 
1324 	assert(cb_fn != NULL);
1325 	g_init_cb_fn = cb_fn;
1326 	g_init_cb_arg = cb_arg;
1327 
1328 	rc = spdk_iscsi_parse_globals();
1329 	if (rc < 0) {
1330 		SPDK_ERRLOG("spdk_iscsi_parse_globals() failed\n");
1331 		spdk_iscsi_init_complete(-1);
1332 	}
1333 
1334 	/*
1335 	 * spdk_iscsi_parse_configuration() will be called as the callback to
1336 	 * spdk_initialize_iscsi_poll_group() and will complete iSCSI
1337 	 * subsystem initialization.
1338 	 */
1339 }
1340 
1341 void
1342 spdk_iscsi_fini(spdk_iscsi_fini_cb cb_fn, void *cb_arg)
1343 {
1344 	g_fini_cb_fn = cb_fn;
1345 	g_fini_cb_arg = cb_arg;
1346 
1347 	spdk_iscsi_portal_grp_close_all();
1348 	spdk_shutdown_iscsi_conns();
1349 }
1350 
1351 static void
1352 spdk_iscsi_fini_done(void *arg)
1353 {
1354 	spdk_iscsi_check_pools();
1355 	spdk_iscsi_free_pools();
1356 
1357 	spdk_iscsi_shutdown_tgt_nodes();
1358 	spdk_iscsi_init_grps_destroy();
1359 	spdk_iscsi_portal_grps_destroy();
1360 	spdk_iscsi_auth_groups_destroy();
1361 	free(g_spdk_iscsi.authfile);
1362 	free(g_spdk_iscsi.nodebase);
1363 	free(g_spdk_iscsi.poll_group);
1364 
1365 	pthread_mutex_destroy(&g_spdk_iscsi.mutex);
1366 	g_fini_cb_fn(g_fini_cb_arg);
1367 }
1368 
1369 void
1370 spdk_shutdown_iscsi_conns_done(void)
1371 {
1372 	if (g_spdk_iscsi.poll_group) {
1373 		spdk_for_each_thread(iscsi_unregister_poll_group, NULL, spdk_iscsi_fini_done);
1374 	} else {
1375 		spdk_iscsi_fini_done(NULL);
1376 	}
1377 }
1378 
1379 void
1380 spdk_iscsi_config_text(FILE *fp)
1381 {
1382 	spdk_iscsi_globals_config_text(fp);
1383 	spdk_iscsi_portal_grps_config_text(fp);
1384 	spdk_iscsi_init_grps_config_text(fp);
1385 	spdk_iscsi_tgt_nodes_config_text(fp);
1386 }
1387 
1388 void
1389 spdk_iscsi_opts_info_json(struct spdk_json_write_ctx *w)
1390 {
1391 	spdk_json_write_object_begin(w);
1392 
1393 	if (g_spdk_iscsi.authfile != NULL) {
1394 		spdk_json_write_named_string(w, "auth_file", g_spdk_iscsi.authfile);
1395 	}
1396 	spdk_json_write_named_string(w, "node_base", g_spdk_iscsi.nodebase);
1397 
1398 	spdk_json_write_named_uint32(w, "max_sessions", g_spdk_iscsi.MaxSessions);
1399 	spdk_json_write_named_uint32(w, "max_connections_per_session",
1400 				     g_spdk_iscsi.MaxConnectionsPerSession);
1401 
1402 	spdk_json_write_named_uint32(w, "max_queue_depth", g_spdk_iscsi.MaxQueueDepth);
1403 
1404 	spdk_json_write_named_uint32(w, "default_time2wait", g_spdk_iscsi.DefaultTime2Wait);
1405 	spdk_json_write_named_uint32(w, "default_time2retain", g_spdk_iscsi.DefaultTime2Retain);
1406 
1407 	spdk_json_write_named_uint32(w, "first_burst_length", g_spdk_iscsi.FirstBurstLength);
1408 
1409 	spdk_json_write_named_bool(w, "immediate_data", g_spdk_iscsi.ImmediateData);
1410 
1411 	spdk_json_write_named_bool(w, "allow_duplicated_isid", g_spdk_iscsi.AllowDuplicateIsid);
1412 
1413 	spdk_json_write_named_uint32(w, "error_recovery_level", g_spdk_iscsi.ErrorRecoveryLevel);
1414 
1415 	spdk_json_write_named_int32(w, "nop_timeout", g_spdk_iscsi.timeout);
1416 	spdk_json_write_named_int32(w, "nop_in_interval", g_spdk_iscsi.nopininterval);
1417 
1418 	spdk_json_write_named_bool(w, "disable_chap", g_spdk_iscsi.disable_chap);
1419 	spdk_json_write_named_bool(w, "require_chap", g_spdk_iscsi.require_chap);
1420 	spdk_json_write_named_bool(w, "mutual_chap", g_spdk_iscsi.mutual_chap);
1421 	spdk_json_write_named_int32(w, "chap_group", g_spdk_iscsi.chap_group);
1422 
1423 	spdk_json_write_named_uint32(w, "min_connections_per_core",
1424 				     spdk_iscsi_conn_get_min_per_core());
1425 
1426 	spdk_json_write_object_end(w);
1427 }
1428 
1429 static void
1430 spdk_iscsi_auth_group_info_json(struct spdk_iscsi_auth_group *group,
1431 				struct spdk_json_write_ctx *w)
1432 {
1433 	struct spdk_iscsi_auth_secret *_secret;
1434 
1435 	spdk_json_write_object_begin(w);
1436 
1437 	spdk_json_write_named_int32(w, "tag", group->tag);
1438 
1439 	spdk_json_write_named_array_begin(w, "secrets");
1440 	TAILQ_FOREACH(_secret, &group->secret_head, tailq) {
1441 		spdk_json_write_object_begin(w);
1442 
1443 		spdk_json_write_named_string(w, "user", _secret->user);
1444 		spdk_json_write_named_string(w, "secret", _secret->secret);
1445 
1446 		if (_secret->muser[0] != '\0') {
1447 			spdk_json_write_named_string(w, "muser", _secret->muser);
1448 			spdk_json_write_named_string(w, "msecret", _secret->msecret);
1449 		}
1450 
1451 		spdk_json_write_object_end(w);
1452 	}
1453 	spdk_json_write_array_end(w);
1454 
1455 	spdk_json_write_object_end(w);
1456 }
1457 
1458 static void
1459 spdk_iscsi_auth_group_config_json(struct spdk_iscsi_auth_group *group,
1460 				  struct spdk_json_write_ctx *w)
1461 {
1462 	spdk_json_write_object_begin(w);
1463 
1464 	spdk_json_write_named_string(w, "method", "add_iscsi_auth_group");
1465 
1466 	spdk_json_write_name(w, "params");
1467 	spdk_iscsi_auth_group_info_json(group, w);
1468 
1469 	spdk_json_write_object_end(w);
1470 }
1471 
1472 void
1473 spdk_iscsi_auth_groups_info_json(struct spdk_json_write_ctx *w)
1474 {
1475 	struct spdk_iscsi_auth_group *group;
1476 
1477 	TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) {
1478 		spdk_iscsi_auth_group_info_json(group, w);
1479 	}
1480 }
1481 
1482 static void
1483 spdk_iscsi_auth_groups_config_json(struct spdk_json_write_ctx *w)
1484 {
1485 	struct spdk_iscsi_auth_group *group;
1486 
1487 	TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) {
1488 		spdk_iscsi_auth_group_config_json(group, w);
1489 	}
1490 }
1491 
1492 static void
1493 spdk_iscsi_opts_config_json(struct spdk_json_write_ctx *w)
1494 {
1495 	spdk_json_write_object_begin(w);
1496 
1497 	spdk_json_write_named_string(w, "method", "set_iscsi_options");
1498 
1499 	spdk_json_write_name(w, "params");
1500 	spdk_iscsi_opts_info_json(w);
1501 
1502 	spdk_json_write_object_end(w);
1503 }
1504 
1505 void
1506 spdk_iscsi_config_json(struct spdk_json_write_ctx *w)
1507 {
1508 	spdk_json_write_array_begin(w);
1509 	spdk_iscsi_opts_config_json(w);
1510 	spdk_iscsi_portal_grps_config_json(w);
1511 	spdk_iscsi_init_grps_config_json(w);
1512 	spdk_iscsi_tgt_nodes_config_json(w);
1513 	spdk_iscsi_auth_groups_config_json(w);
1514 	spdk_json_write_array_end(w);
1515 }
1516 
1517 SPDK_LOG_REGISTER_COMPONENT("iscsi", SPDK_LOG_ISCSI)
1518