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