xref: /spdk/lib/iscsi/iscsi_subsystem.c (revision 8a0a98d35e21f282088edf28b9e8da66ec390e3a)
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 "  AuthFile %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 "  ImmediateData %s\n" \
85 "  ErrorRecoveryLevel %d\n" \
86 "\n"
87 
88 static void
89 spdk_iscsi_globals_config_text(FILE *fp)
90 {
91 	const char *authmethod = "None";
92 	char authgroup[32] = "None";
93 
94 	if (NULL == fp) {
95 		return;
96 	}
97 
98 	if (g_spdk_iscsi.req_discovery_auth) {
99 		authmethod = "CHAP";
100 	} else if (g_spdk_iscsi.req_discovery_auth_mutual) {
101 		authmethod = "CHAP Mutual";
102 	} else if (!g_spdk_iscsi.no_discovery_auth) {
103 		authmethod = "Auto";
104 	}
105 
106 	if (g_spdk_iscsi.discovery_auth_group) {
107 		snprintf(authgroup, sizeof(authgroup), "AuthGroup%d", g_spdk_iscsi.discovery_auth_group);
108 	}
109 
110 	fprintf(fp, ISCSI_CONFIG_TMPL,
111 		g_spdk_iscsi.nodebase, g_spdk_iscsi.authfile,
112 		g_spdk_iscsi.timeout, authmethod, authgroup,
113 		g_spdk_iscsi.MaxSessions, g_spdk_iscsi.MaxConnectionsPerSession,
114 		g_spdk_iscsi.MaxConnections,
115 		g_spdk_iscsi.MaxQueueDepth,
116 		g_spdk_iscsi.DefaultTime2Wait, g_spdk_iscsi.DefaultTime2Retain,
117 		(g_spdk_iscsi.ImmediateData) ? "Yes" : "No",
118 		g_spdk_iscsi.ErrorRecoveryLevel);
119 }
120 
121 static void
122 spdk_mobj_ctor(struct spdk_mempool *mp, __attribute__((unused)) void *arg,
123 	       void *_m, __attribute__((unused)) unsigned i)
124 {
125 	struct spdk_mobj *m = _m;
126 	uint64_t *phys_addr;
127 	ptrdiff_t off;
128 
129 	m->mp = mp;
130 	m->buf = (uint8_t *)m + sizeof(struct spdk_mobj);
131 	m->buf = (void *)((unsigned long)((uint8_t *)m->buf + 512) & ~511UL);
132 	off = (uint64_t)(uint8_t *)m->buf - (uint64_t)(uint8_t *)m;
133 
134 	/*
135 	 * we store the physical address in a 64bit unsigned integer
136 	 * right before the 512B aligned buffer area.
137 	 */
138 	phys_addr = (uint64_t *)m->buf - 1;
139 	*phys_addr = spdk_vtophys(m) + off;
140 }
141 
142 #define NUM_PDU_PER_CONNECTION(iscsi)	(2 * (iscsi->MaxQueueDepth + MAX_LARGE_DATAIN_PER_CONNECTION + 8))
143 #define PDU_POOL_SIZE(iscsi)	(iscsi->MaxConnections * NUM_PDU_PER_CONNECTION(iscsi))
144 #define IMMEDIATE_DATA_POOL_SIZE(iscsi)	(iscsi->MaxConnections * 128)
145 #define DATA_OUT_POOL_SIZE(iscsi)	(iscsi->MaxConnections * MAX_DATA_OUT_PER_CONNECTION)
146 
147 static int spdk_iscsi_initialize_pdu_pool(void)
148 {
149 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
150 	int imm_mobj_size = spdk_get_immediate_data_buffer_size() +
151 			    sizeof(struct spdk_mobj) + 512;
152 	int dout_mobj_size = spdk_get_data_out_buffer_size() +
153 			     sizeof(struct spdk_mobj) + 512;
154 
155 	/* create PDU pool */
156 	iscsi->pdu_pool = spdk_mempool_create("PDU_Pool",
157 					      PDU_POOL_SIZE(iscsi),
158 					      sizeof(struct spdk_iscsi_pdu),
159 					      256, SPDK_ENV_SOCKET_ID_ANY);
160 	if (!iscsi->pdu_pool) {
161 		SPDK_ERRLOG("create PDU pool failed\n");
162 		return -1;
163 	}
164 
165 	iscsi->pdu_immediate_data_pool = spdk_mempool_create_ctor("PDU_immediate_data_Pool",
166 					 IMMEDIATE_DATA_POOL_SIZE(iscsi),
167 					 imm_mobj_size, 0,
168 					 spdk_env_get_socket_id(spdk_env_get_current_core()),
169 					 spdk_mobj_ctor, NULL);
170 	if (!iscsi->pdu_immediate_data_pool) {
171 		SPDK_ERRLOG("create PDU 8k pool failed\n");
172 		return -1;
173 	}
174 
175 	iscsi->pdu_data_out_pool = spdk_mempool_create_ctor("PDU_data_out_Pool",
176 				   DATA_OUT_POOL_SIZE(iscsi),
177 				   dout_mobj_size, 256,
178 				   spdk_env_get_socket_id(spdk_env_get_current_core()),
179 				   spdk_mobj_ctor, NULL);
180 	if (!iscsi->pdu_data_out_pool) {
181 		SPDK_ERRLOG("create PDU 64k pool failed\n");
182 		return -1;
183 	}
184 
185 	return 0;
186 }
187 
188 static void spdk_iscsi_sess_ctor(struct spdk_mempool *pool, void *arg,
189 				 void *session_buf, 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 spdk_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 spdk_iscsi_initialize_session_pool(void)
222 {
223 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
224 
225 	iscsi->session_pool = spdk_mempool_create_ctor("Session_Pool",
226 			      SESSION_POOL_SIZE(iscsi),
227 			      sizeof(struct spdk_iscsi_sess), 0,
228 			      SPDK_ENV_SOCKET_ID_ANY,
229 			      spdk_iscsi_sess_ctor, iscsi);
230 	if (!iscsi->session_pool) {
231 		SPDK_ERRLOG("create session pool failed\n");
232 		return -1;
233 	}
234 
235 	return 0;
236 }
237 
238 static int
239 spdk_iscsi_initialize_all_pools(void)
240 {
241 	if (spdk_iscsi_initialize_pdu_pool() != 0) {
242 		return -1;
243 	}
244 
245 	if (spdk_iscsi_initialize_session_pool() != 0) {
246 		return -1;
247 	}
248 
249 	if (spdk_iscsi_initialize_task_pool() != 0) {
250 		return -1;
251 	}
252 
253 	return 0;
254 }
255 
256 static void
257 spdk_iscsi_check_pool(struct spdk_mempool *pool, size_t count)
258 {
259 	if (spdk_mempool_count(pool) != count) {
260 		SPDK_ERRLOG("spdk_mempool_count(%s) == %zu, should be %zu\n",
261 			    spdk_mempool_get_name(pool), spdk_mempool_count(pool), count);
262 	}
263 }
264 
265 static void
266 spdk_iscsi_check_pools(void)
267 {
268 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
269 
270 	spdk_iscsi_check_pool(iscsi->pdu_pool, PDU_POOL_SIZE(iscsi));
271 	spdk_iscsi_check_pool(iscsi->session_pool, SESSION_POOL_SIZE(iscsi));
272 	spdk_iscsi_check_pool(iscsi->pdu_immediate_data_pool, IMMEDIATE_DATA_POOL_SIZE(iscsi));
273 	spdk_iscsi_check_pool(iscsi->pdu_data_out_pool, DATA_OUT_POOL_SIZE(iscsi));
274 	spdk_iscsi_check_pool(iscsi->task_pool, DEFAULT_TASK_POOL_SIZE);
275 }
276 
277 static void
278 spdk_iscsi_free_pools(void)
279 {
280 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
281 
282 	spdk_mempool_free(iscsi->pdu_pool);
283 	spdk_mempool_free(iscsi->session_pool);
284 	spdk_mempool_free(iscsi->pdu_immediate_data_pool);
285 	spdk_mempool_free(iscsi->pdu_data_out_pool);
286 	spdk_mempool_free(iscsi->task_pool);
287 }
288 
289 void spdk_put_pdu(struct spdk_iscsi_pdu *pdu)
290 {
291 	if (!pdu) {
292 		return;
293 	}
294 
295 	pdu->ref--;
296 
297 	if (pdu->ref < 0) {
298 		SPDK_ERRLOG("Negative PDU refcount: %p\n", pdu);
299 		pdu->ref = 0;
300 	}
301 
302 	if (pdu->ref == 0) {
303 		if (pdu->mobj) {
304 			spdk_mempool_put(pdu->mobj->mp, (void *)pdu->mobj);
305 		}
306 
307 		if (pdu->data && !pdu->data_from_mempool) {
308 			free(pdu->data);
309 		}
310 
311 		spdk_mempool_put(g_spdk_iscsi.pdu_pool, (void *)pdu);
312 	}
313 }
314 
315 struct spdk_iscsi_pdu *spdk_get_pdu(void)
316 {
317 	struct spdk_iscsi_pdu *pdu;
318 
319 	pdu = spdk_mempool_get(g_spdk_iscsi.pdu_pool);
320 	if (!pdu) {
321 		SPDK_ERRLOG("Unable to get PDU\n");
322 		abort();
323 	}
324 
325 	/* we do not want to zero out the last part of the structure reserved for AHS and sense data */
326 	memset(pdu, 0, offsetof(struct spdk_iscsi_pdu, ahs));
327 	pdu->ref = 1;
328 
329 	return pdu;
330 }
331 
332 static void
333 spdk_iscsi_log_globals(void)
334 {
335 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "AuthFile %s\n", g_spdk_iscsi.authfile);
336 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "NodeBase %s\n", g_spdk_iscsi.nodebase);
337 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxSessions %d\n", g_spdk_iscsi.MaxSessions);
338 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxConnectionsPerSession %d\n",
339 		      g_spdk_iscsi.MaxConnectionsPerSession);
340 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxQueueDepth %d\n", g_spdk_iscsi.MaxQueueDepth);
341 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "DefaultTime2Wait %d\n",
342 		      g_spdk_iscsi.DefaultTime2Wait);
343 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "DefaultTime2Retain %d\n",
344 		      g_spdk_iscsi.DefaultTime2Retain);
345 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "ImmediateData %s\n",
346 		      g_spdk_iscsi.ImmediateData ? "Yes" : "No");
347 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "AllowDuplicateIsid %s\n",
348 		      g_spdk_iscsi.AllowDuplicateIsid ? "Yes" : "No");
349 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "ErrorRecoveryLevel %d\n",
350 		      g_spdk_iscsi.ErrorRecoveryLevel);
351 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Timeout %d\n", g_spdk_iscsi.timeout);
352 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "NopInInterval %d\n",
353 		      g_spdk_iscsi.nopininterval);
354 	if (g_spdk_iscsi.no_discovery_auth) {
355 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
356 			      "DiscoveryAuthMethod None\n");
357 	} else if (!g_spdk_iscsi.req_discovery_auth) {
358 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
359 			      "DiscoveryAuthMethod Auto\n");
360 	} else {
361 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
362 			      "DiscoveryAuthMethod %s %s\n",
363 			      g_spdk_iscsi.req_discovery_auth ? "CHAP" : "",
364 			      g_spdk_iscsi.req_discovery_auth_mutual ? "Mutual" : "");
365 	}
366 
367 	if (g_spdk_iscsi.discovery_auth_group == 0) {
368 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
369 			      "DiscoveryAuthGroup None\n");
370 	} else {
371 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
372 			      "DiscoveryAuthGroup AuthGroup%d\n",
373 			      g_spdk_iscsi.discovery_auth_group);
374 	}
375 
376 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MinConnectionsPerCore%d\n",
377 		      spdk_iscsi_conn_get_min_per_core());
378 }
379 
380 static void
381 spdk_iscsi_opts_init(struct spdk_iscsi_opts *opts)
382 {
383 	opts->MaxSessions = DEFAULT_MAX_SESSIONS;
384 	opts->MaxConnectionsPerSession = DEFAULT_MAX_CONNECTIONS_PER_SESSION;
385 	opts->MaxQueueDepth = DEFAULT_MAX_QUEUE_DEPTH;
386 	opts->DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT;
387 	opts->DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
388 	opts->ImmediateData = DEFAULT_IMMEDIATEDATA;
389 	opts->AllowDuplicateIsid = false;
390 	opts->ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL;
391 	opts->timeout = DEFAULT_TIMEOUT;
392 	opts->nopininterval = DEFAULT_NOPININTERVAL;
393 	opts->no_discovery_auth = false;
394 	opts->req_discovery_auth = false;
395 	opts->req_discovery_auth_mutual = false;
396 	opts->discovery_auth_group = 0;
397 	opts->authfile = NULL;
398 	opts->nodebase = NULL;
399 	opts->min_connections_per_core = DEFAULT_CONNECTIONS_PER_LCORE;
400 }
401 
402 struct spdk_iscsi_opts *
403 spdk_iscsi_opts_alloc(void)
404 {
405 	struct spdk_iscsi_opts *opts;
406 
407 	opts = calloc(1, sizeof(*opts));
408 	if (!opts) {
409 		SPDK_ERRLOG("calloc() failed for iscsi options\n");
410 		return NULL;
411 	}
412 
413 	spdk_iscsi_opts_init(opts);
414 
415 	return opts;
416 }
417 
418 void
419 spdk_iscsi_opts_free(struct spdk_iscsi_opts *opts)
420 {
421 	free(opts->authfile);
422 	free(opts->nodebase);
423 	free(opts);
424 }
425 
426 /* Deep copy of spdk_iscsi_opts */
427 struct spdk_iscsi_opts *
428 spdk_iscsi_opts_copy(struct spdk_iscsi_opts *src)
429 {
430 	struct spdk_iscsi_opts *dst;
431 
432 	dst = calloc(1, sizeof(*dst));
433 	if (!dst) {
434 		SPDK_ERRLOG("calloc() failed for iscsi options\n");
435 		return NULL;
436 	}
437 
438 	if (src->authfile) {
439 		dst->authfile = strdup(src->authfile);
440 		if (!dst->authfile) {
441 			free(dst);
442 			SPDK_ERRLOG("failed to strdup for auth file %s\n", src->authfile);
443 			return NULL;
444 		}
445 	}
446 
447 	if (src->nodebase) {
448 		dst->nodebase = strdup(src->nodebase);
449 		if (!dst->nodebase) {
450 			free(dst->authfile);
451 			free(dst);
452 			SPDK_ERRLOG("failed to strdup for nodebase %s\n", src->nodebase);
453 			return NULL;
454 		}
455 	}
456 
457 	dst->MaxSessions = src->MaxSessions;
458 	dst->MaxConnectionsPerSession = src->MaxConnectionsPerSession;
459 	dst->MaxQueueDepth = src->MaxQueueDepth;
460 	dst->DefaultTime2Wait = src->DefaultTime2Wait;
461 	dst->DefaultTime2Retain = src->DefaultTime2Retain;
462 	dst->ImmediateData = src->ImmediateData;
463 	dst->AllowDuplicateIsid = src->AllowDuplicateIsid;
464 	dst->ErrorRecoveryLevel = src->ErrorRecoveryLevel;
465 	dst->timeout = src->timeout;
466 	dst->nopininterval = src->nopininterval;
467 	dst->no_discovery_auth = src->no_discovery_auth;
468 	dst->req_discovery_auth = src->req_discovery_auth;
469 	dst->req_discovery_auth_mutual = src->req_discovery_auth;
470 	dst->discovery_auth_group = src->discovery_auth_group;
471 	dst->min_connections_per_core = src->min_connections_per_core;
472 
473 	return dst;
474 }
475 
476 static int
477 spdk_iscsi_read_config_file_params(struct spdk_conf_section *sp,
478 				   struct spdk_iscsi_opts *opts)
479 {
480 	const char *val;
481 	int MaxSessions;
482 	int MaxConnectionsPerSession;
483 	int MaxQueueDepth;
484 	int DefaultTime2Wait;
485 	int DefaultTime2Retain;
486 	int ErrorRecoveryLevel;
487 	int timeout;
488 	int nopininterval;
489 	int min_conn_per_core = 0;
490 	const char *ag_tag;
491 	int ag_tag_i;
492 
493 	val = spdk_conf_section_get_val(sp, "Comment");
494 	if (val != NULL) {
495 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Comment %s\n", val);
496 	}
497 
498 	val = spdk_conf_section_get_val(sp, "AuthFile");
499 	if (val != NULL) {
500 		opts->authfile = strdup(val);
501 		if (!opts->authfile) {
502 			SPDK_ERRLOG("strdup() failed for AuthFile\n");
503 			return -ENOMEM;
504 		}
505 	}
506 
507 	val = spdk_conf_section_get_val(sp, "NodeBase");
508 	if (val != NULL) {
509 		opts->nodebase = strdup(val);
510 		if (!opts->nodebase) {
511 			free(opts->authfile);
512 			SPDK_ERRLOG("strdup() failed for NodeBase\n");
513 			return -ENOMEM;
514 		}
515 	}
516 
517 	MaxSessions = spdk_conf_section_get_intval(sp, "MaxSessions");
518 	if (MaxSessions >= 0) {
519 		opts->MaxSessions = MaxSessions;
520 	}
521 
522 	MaxConnectionsPerSession = spdk_conf_section_get_intval(sp, "MaxConnectionsPerSession");
523 	if (MaxConnectionsPerSession >= 0) {
524 		opts->MaxConnectionsPerSession = MaxConnectionsPerSession;
525 	}
526 
527 	MaxQueueDepth = spdk_conf_section_get_intval(sp, "MaxQueueDepth");
528 	if (MaxQueueDepth >= 0) {
529 		opts->MaxQueueDepth = MaxQueueDepth;
530 	}
531 
532 	DefaultTime2Wait = spdk_conf_section_get_intval(sp, "DefaultTime2Wait");
533 	if (DefaultTime2Wait >= 0) {
534 		opts->DefaultTime2Wait = DefaultTime2Wait;
535 	}
536 	DefaultTime2Retain = spdk_conf_section_get_intval(sp, "DefaultTime2Retain");
537 	if (DefaultTime2Retain >= 0) {
538 		opts->DefaultTime2Retain = DefaultTime2Retain;
539 	}
540 	opts->ImmediateData = spdk_conf_section_get_boolval(sp, "ImmediateData",
541 			      opts->ImmediateData);
542 
543 	/* This option is only for test.
544 	 * If AllowDuplicateIsid is enabled, it allows different connections carrying
545 	 * TSIH=0 login the target within the same session.
546 	 */
547 	opts->AllowDuplicateIsid = spdk_conf_section_get_boolval(sp, "AllowDuplicateIsid",
548 				   opts->AllowDuplicateIsid);
549 
550 	ErrorRecoveryLevel = spdk_conf_section_get_intval(sp, "ErrorRecoveryLevel");
551 	if (ErrorRecoveryLevel >= 0) {
552 		opts->ErrorRecoveryLevel = ErrorRecoveryLevel;
553 	}
554 	timeout = spdk_conf_section_get_intval(sp, "Timeout");
555 	if (timeout >= 0) {
556 		opts->timeout = timeout;
557 	}
558 	nopininterval = spdk_conf_section_get_intval(sp, "NopInInterval");
559 	if (nopininterval >= 0) {
560 		opts->nopininterval = nopininterval;
561 	}
562 	val = spdk_conf_section_get_val(sp, "DiscoveryAuthMethod");
563 	if (val != NULL) {
564 		if (strcasecmp(val, "CHAP") == 0) {
565 			opts->no_discovery_auth = false;
566 			opts->req_discovery_auth = true;
567 			opts->req_discovery_auth_mutual = false;
568 		} else if (strcasecmp(val, "Mutual") == 0) {
569 			opts->no_discovery_auth = false;
570 			opts->req_discovery_auth = true;
571 			opts->req_discovery_auth_mutual = true;
572 		} else if (strcasecmp(val, "Auto") == 0) {
573 			opts->no_discovery_auth = false;
574 			opts->req_discovery_auth = false;
575 			opts->req_discovery_auth_mutual = false;
576 		} else if (strcasecmp(val, "None") == 0) {
577 			opts->no_discovery_auth = true;
578 			opts->req_discovery_auth = false;
579 			opts->req_discovery_auth_mutual = false;
580 		} else {
581 			SPDK_ERRLOG("unknown auth %s, ignoring\n", val);
582 		}
583 	}
584 	val = spdk_conf_section_get_val(sp, "DiscoveryAuthGroup");
585 	if (val != NULL) {
586 		ag_tag = val;
587 		if (strcasecmp(ag_tag, "None") == 0) {
588 			opts->discovery_auth_group = 0;
589 		} else {
590 			if (strncasecmp(ag_tag, "AuthGroup",
591 					strlen("AuthGroup")) != 0
592 			    || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1
593 			    || ag_tag_i == 0) {
594 				SPDK_ERRLOG("invalid auth group %s, ignoring\n", ag_tag);
595 			} else {
596 				opts->discovery_auth_group = ag_tag_i;
597 			}
598 		}
599 	}
600 	min_conn_per_core = spdk_conf_section_get_intval(sp, "MinConnectionsPerCore");
601 	if (min_conn_per_core >= 0) {
602 		opts->min_connections_per_core = min_conn_per_core;
603 	}
604 
605 	return 0;
606 }
607 
608 static int
609 spdk_iscsi_opts_verify(struct spdk_iscsi_opts *opts)
610 {
611 	if (!opts->authfile) {
612 		opts->authfile = strdup(SPDK_ISCSI_DEFAULT_AUTHFILE);
613 		if (opts->authfile == NULL) {
614 			SPDK_ERRLOG("strdup() failed for default authfile\n");
615 			return -ENOMEM;
616 		}
617 	}
618 
619 	if (!opts->nodebase) {
620 		opts->nodebase = strdup(SPDK_ISCSI_DEFAULT_NODEBASE);
621 		if (opts->nodebase == NULL) {
622 			SPDK_ERRLOG("strdup() failed for default nodebase\n");
623 			return -ENOMEM;
624 		}
625 	}
626 
627 	if (opts->MaxSessions == 0 || opts->MaxSessions > 65535) {
628 		SPDK_ERRLOG("%d is invalid. MaxSessions must be more than 0 and no more than 65535\n",
629 			    opts->MaxSessions);
630 		return -EINVAL;
631 	}
632 
633 	if (opts->MaxConnectionsPerSession == 0 || opts->MaxConnectionsPerSession > 65535) {
634 		SPDK_ERRLOG("%d is invalid. MaxConnectionsPerSession must be more than 0 and no more than 65535\n",
635 			    opts->MaxConnectionsPerSession);
636 		return -EINVAL;
637 	}
638 
639 	if (opts->MaxQueueDepth == 0 || opts->MaxQueueDepth > 256) {
640 		SPDK_ERRLOG("%d is invalid. MaxQueueDepth must be more than 0 and no more than 256\n",
641 			    opts->MaxQueueDepth);
642 		return -EINVAL;
643 	}
644 
645 	if (opts->DefaultTime2Wait > 3600) {
646 		SPDK_ERRLOG("%d is invalid. DefaultTime2Wait must be no more than 3600\n",
647 			    opts->DefaultTime2Wait);
648 		return -EINVAL;
649 	}
650 
651 	if (opts->DefaultTime2Retain > 3600) {
652 		SPDK_ERRLOG("%d is invalid. DefaultTime2Retain must be no more than 3600\n",
653 			    opts->DefaultTime2Retain);
654 		return -EINVAL;
655 	}
656 
657 	if (opts->ErrorRecoveryLevel > 2) {
658 		SPDK_ERRLOG("ErrorRecoveryLevel %d is not supported.\n", opts->ErrorRecoveryLevel);
659 		return -EINVAL;
660 	}
661 
662 	if (opts->timeout < 0) {
663 		SPDK_ERRLOG("%d is invalid. timeout must not be less than 0\n", opts->timeout);
664 		return -EINVAL;
665 	}
666 
667 	if (opts->nopininterval < 0 || opts->nopininterval > MAX_NOPININTERVAL) {
668 		SPDK_ERRLOG("%d is invalid. nopinterval must be between 0 and %d\n",
669 			    opts->nopininterval, MAX_NOPININTERVAL);
670 		return -EINVAL;
671 	}
672 
673 	if (!spdk_iscsi_check_chap_params(opts->no_discovery_auth, opts->req_discovery_auth,
674 					  opts->req_discovery_auth_mutual,
675 					  opts->discovery_auth_group)) {
676 		SPDK_ERRLOG("CHAP params in opts are illegal combination\n");
677 		return -EINVAL;
678 	}
679 
680 	return 0;
681 }
682 
683 static int
684 spdk_iscsi_parse_options(struct spdk_iscsi_opts **popts)
685 {
686 	struct spdk_iscsi_opts *opts;
687 	struct spdk_conf_section *sp;
688 	int rc;
689 
690 	opts = spdk_iscsi_opts_alloc();
691 	if (!opts) {
692 		SPDK_ERRLOG("spdk_iscsi_opts_alloc_failed() failed\n");
693 		return -ENOMEM;
694 	}
695 
696 	/* Process parameters */
697 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "spdk_iscsi_read_config_file_parmas\n");
698 	sp = spdk_conf_find_section(NULL, "iSCSI");
699 	if (sp != NULL) {
700 		rc = spdk_iscsi_read_config_file_params(sp, opts);
701 		if (rc != 0) {
702 			free(opts);
703 			SPDK_ERRLOG("spdk_iscsi_read_config_file_params() failed\n");
704 			return rc;
705 		}
706 	}
707 
708 	*popts = opts;
709 
710 	return 0;
711 }
712 
713 static int
714 spdk_iscsi_set_global_params(struct spdk_iscsi_opts *opts)
715 {
716 	int rc;
717 
718 	rc = spdk_iscsi_opts_verify(opts);
719 	if (rc != 0) {
720 		SPDK_ERRLOG("spdk_iscsi_opts_verify() failed\n");
721 		return rc;
722 	}
723 
724 	g_spdk_iscsi.authfile = strdup(opts->authfile);
725 	if (!g_spdk_iscsi.authfile) {
726 		SPDK_ERRLOG("failed to strdup for auth file %s\n", opts->authfile);
727 		return -ENOMEM;
728 	}
729 
730 	g_spdk_iscsi.nodebase = strdup(opts->nodebase);
731 	if (!g_spdk_iscsi.nodebase) {
732 		SPDK_ERRLOG("failed to strdup for nodebase %s\n", opts->nodebase);
733 		return -ENOMEM;
734 	}
735 
736 	g_spdk_iscsi.MaxSessions = opts->MaxSessions;
737 	g_spdk_iscsi.MaxConnectionsPerSession = opts->MaxConnectionsPerSession;
738 	g_spdk_iscsi.MaxQueueDepth = opts->MaxQueueDepth;
739 	g_spdk_iscsi.DefaultTime2Wait = opts->DefaultTime2Wait;
740 	g_spdk_iscsi.DefaultTime2Retain = opts->DefaultTime2Retain;
741 	g_spdk_iscsi.ImmediateData = opts->ImmediateData;
742 	g_spdk_iscsi.AllowDuplicateIsid = opts->AllowDuplicateIsid;
743 	g_spdk_iscsi.ErrorRecoveryLevel = opts->ErrorRecoveryLevel;
744 	g_spdk_iscsi.timeout = opts->timeout;
745 	g_spdk_iscsi.nopininterval = opts->nopininterval;
746 	g_spdk_iscsi.no_discovery_auth = opts->no_discovery_auth;
747 	g_spdk_iscsi.req_discovery_auth = opts->req_discovery_auth;
748 	g_spdk_iscsi.req_discovery_auth_mutual = opts->req_discovery_auth;
749 	g_spdk_iscsi.discovery_auth_group = opts->discovery_auth_group;
750 
751 	spdk_iscsi_conn_set_min_per_core(opts->min_connections_per_core);
752 
753 	spdk_iscsi_log_globals();
754 
755 	return 0;
756 }
757 
758 static int
759 spdk_iscsi_initialize_global_params(void)
760 {
761 	int rc;
762 
763 	if (!g_spdk_iscsi_opts) {
764 		rc = spdk_iscsi_parse_options(&g_spdk_iscsi_opts);
765 		if (rc != 0) {
766 			SPDK_ERRLOG("spdk_iscsi_parse_options() failed\n");
767 			return rc;
768 		}
769 	}
770 
771 	rc = spdk_iscsi_set_global_params(g_spdk_iscsi_opts);
772 	if (rc != 0) {
773 		SPDK_ERRLOG("spdk_iscsi_set_global_params() failed\n");
774 	}
775 
776 	spdk_iscsi_opts_free(g_spdk_iscsi_opts);
777 	g_spdk_iscsi_opts = NULL;
778 
779 	return rc;
780 }
781 
782 static void
783 spdk_iscsi_init_complete(int rc)
784 {
785 	spdk_iscsi_init_cb cb_fn = g_init_cb_fn;
786 	void *cb_arg = g_init_cb_arg;
787 
788 	g_init_cb_fn = NULL;
789 	g_init_cb_arg = NULL;
790 
791 	cb_fn(cb_arg, rc);
792 }
793 
794 static int
795 spdk_iscsi_poll_group_poll(void *ctx)
796 {
797 	struct spdk_iscsi_poll_group *group = ctx;
798 	struct spdk_iscsi_conn *conn, *tmp;
799 	int rc;
800 
801 	if (spdk_unlikely(STAILQ_EMPTY(&group->connections))) {
802 		return 0;
803 	}
804 
805 	rc = spdk_sock_group_poll(group->sock_group);
806 	if (rc < 0) {
807 		SPDK_ERRLOG("Failed to poll sock_group=%p\n", group->sock_group);
808 	}
809 
810 	STAILQ_FOREACH_SAFE(conn, &group->connections, link, tmp) {
811 		if (conn->state == ISCSI_CONN_STATE_EXITING) {
812 			spdk_iscsi_conn_destruct(conn);
813 		}
814 	}
815 
816 	return -1;
817 }
818 
819 static int
820 spdk_iscsi_poll_group_handle_nop(void *ctx)
821 {
822 	struct spdk_iscsi_poll_group *group = ctx;
823 	struct spdk_iscsi_conn *conn, *tmp;
824 
825 	STAILQ_FOREACH_SAFE(conn, &group->connections, link, tmp) {
826 		spdk_iscsi_conn_handle_nop(conn);
827 	}
828 
829 	return -1;
830 }
831 
832 static void
833 iscsi_create_poll_group(void *ctx)
834 {
835 	struct spdk_iscsi_poll_group *pg;
836 
837 	assert(g_spdk_iscsi.poll_group != NULL);
838 	pg = &g_spdk_iscsi.poll_group[spdk_env_get_current_core()];
839 	pg->core = spdk_env_get_current_core();
840 
841 	STAILQ_INIT(&pg->connections);
842 	pg->sock_group = spdk_sock_group_create();
843 	assert(pg->sock_group != NULL);
844 
845 	pg->poller = spdk_poller_register(spdk_iscsi_poll_group_poll, pg, 0);
846 	/* set the period to 1 sec */
847 	pg->nop_poller = spdk_poller_register(spdk_iscsi_poll_group_handle_nop, pg, 1000000);
848 }
849 
850 static void
851 iscsi_unregister_poll_group(void *ctx)
852 {
853 	struct spdk_iscsi_poll_group *pg;
854 
855 	assert(g_spdk_iscsi.poll_group != NULL);
856 	pg = &g_spdk_iscsi.poll_group[spdk_env_get_current_core()];
857 	assert(pg->poller != NULL);
858 	assert(pg->sock_group != NULL);
859 
860 	spdk_sock_group_close(&pg->sock_group);
861 	spdk_poller_unregister(&pg->poller);
862 	spdk_poller_unregister(&pg->nop_poller);
863 }
864 
865 static void
866 spdk_initialize_iscsi_poll_group(spdk_thread_fn cpl)
867 {
868 	size_t g_num_poll_groups = spdk_env_get_last_core() + 1;
869 
870 	g_spdk_iscsi.poll_group = calloc(g_num_poll_groups, sizeof(struct spdk_iscsi_poll_group));
871 	if (!g_spdk_iscsi.poll_group) {
872 		SPDK_ERRLOG("Failed to allocated iscsi poll group\n");
873 		spdk_iscsi_init_complete(-1);
874 		return;
875 	}
876 
877 	/* Send a message to each thread and create a poll group */
878 	spdk_for_each_thread(iscsi_create_poll_group, NULL, cpl);
879 }
880 
881 static void
882 spdk_iscsi_parse_configuration(void *ctx)
883 {
884 	int rc;
885 
886 	rc = spdk_iscsi_parse_portal_grps();
887 	if (rc < 0) {
888 		SPDK_ERRLOG("spdk_iscsi_parse_portal_grps() failed\n");
889 		goto end;
890 	}
891 
892 	rc = spdk_iscsi_parse_init_grps();
893 	if (rc < 0) {
894 		SPDK_ERRLOG("spdk_iscsi_parse_init_grps() failed\n");
895 		goto end;
896 	}
897 
898 	rc = spdk_iscsi_parse_tgt_nodes();
899 	if (rc < 0) {
900 		SPDK_ERRLOG("spdk_iscsi_parse_tgt_nodes() failed\n");
901 	}
902 
903 end:
904 	spdk_iscsi_init_complete(rc);
905 }
906 
907 static int
908 spdk_iscsi_parse_globals(void)
909 {
910 	int rc;
911 
912 	rc = spdk_iscsi_initialize_global_params();
913 	if (rc != 0) {
914 		SPDK_ERRLOG("spdk_iscsi_initialize_iscsi_global_params() failed\n");
915 		return rc;
916 	}
917 
918 	g_spdk_iscsi.session = spdk_dma_zmalloc(sizeof(void *) * g_spdk_iscsi.MaxSessions, 0, NULL);
919 	if (!g_spdk_iscsi.session) {
920 		SPDK_ERRLOG("spdk_dma_zmalloc() failed for session array\n");
921 		return -1;
922 	}
923 
924 	/*
925 	 * For now, just support same number of total connections, rather
926 	 *  than MaxSessions * MaxConnectionsPerSession.  After we add better
927 	 *  handling for low resource conditions from our various buffer
928 	 *  pools, we can bump this up to support more connections.
929 	 */
930 	g_spdk_iscsi.MaxConnections = g_spdk_iscsi.MaxSessions;
931 
932 	rc = spdk_iscsi_initialize_all_pools();
933 	if (rc != 0) {
934 		SPDK_ERRLOG("spdk_initialize_all_pools() failed\n");
935 		return -1;
936 	}
937 
938 	rc = spdk_initialize_iscsi_conns();
939 	if (rc < 0) {
940 		SPDK_ERRLOG("spdk_initialize_iscsi_conns() failed\n");
941 		return rc;
942 	}
943 
944 	spdk_initialize_iscsi_poll_group(spdk_iscsi_parse_configuration);
945 	return 0;
946 }
947 
948 void
949 spdk_iscsi_init(spdk_iscsi_init_cb cb_fn, void *cb_arg)
950 {
951 	int rc;
952 
953 	assert(cb_fn != NULL);
954 	g_init_cb_fn = cb_fn;
955 	g_init_cb_arg = cb_arg;
956 
957 	rc = spdk_iscsi_parse_globals();
958 	if (rc < 0) {
959 		SPDK_ERRLOG("spdk_iscsi_parse_globals() failed\n");
960 		spdk_iscsi_init_complete(-1);
961 	}
962 
963 	/*
964 	 * spdk_iscsi_parse_configuration() will be called as the callback to
965 	 * spdk_initialize_iscsi_poll_group() and will complete iSCSI
966 	 * subsystem initialization.
967 	 */
968 }
969 
970 void
971 spdk_iscsi_fini(spdk_iscsi_fini_cb cb_fn, void *cb_arg)
972 {
973 	g_fini_cb_fn = cb_fn;
974 	g_fini_cb_arg = cb_arg;
975 
976 	spdk_iscsi_portal_grp_close_all();
977 	spdk_shutdown_iscsi_conns();
978 }
979 
980 static void
981 spdk_iscsi_fini_done(void *arg)
982 {
983 	spdk_iscsi_check_pools();
984 	spdk_iscsi_free_pools();
985 
986 	spdk_iscsi_shutdown_tgt_nodes();
987 	spdk_iscsi_init_grps_destroy();
988 	spdk_iscsi_portal_grps_destroy();
989 	free(g_spdk_iscsi.authfile);
990 	free(g_spdk_iscsi.nodebase);
991 	free(g_spdk_iscsi.poll_group);
992 
993 	pthread_mutex_destroy(&g_spdk_iscsi.mutex);
994 	g_fini_cb_fn(g_fini_cb_arg);
995 }
996 
997 void
998 spdk_shutdown_iscsi_conns_done(void)
999 {
1000 	if (g_spdk_iscsi.poll_group) {
1001 		spdk_for_each_thread(iscsi_unregister_poll_group, NULL, spdk_iscsi_fini_done);
1002 	} else {
1003 		spdk_iscsi_fini_done(NULL);
1004 	}
1005 }
1006 
1007 void
1008 spdk_iscsi_config_text(FILE *fp)
1009 {
1010 	spdk_iscsi_globals_config_text(fp);
1011 	spdk_iscsi_portal_grps_config_text(fp);
1012 	spdk_iscsi_init_grps_config_text(fp);
1013 	spdk_iscsi_tgt_nodes_config_text(fp);
1014 }
1015 
1016 void
1017 spdk_iscsi_opts_info_json(struct spdk_json_write_ctx *w)
1018 {
1019 	spdk_json_write_object_begin(w);
1020 
1021 	spdk_json_write_named_string(w, "auth_file", g_spdk_iscsi.authfile);
1022 	spdk_json_write_named_string(w, "node_base", g_spdk_iscsi.nodebase);
1023 
1024 	spdk_json_write_named_uint32(w, "max_sessions", g_spdk_iscsi.MaxSessions);
1025 	spdk_json_write_named_uint32(w, "max_connections_per_session",
1026 				     g_spdk_iscsi.MaxConnectionsPerSession);
1027 
1028 	spdk_json_write_named_uint32(w, "max_queue_depth", g_spdk_iscsi.MaxQueueDepth);
1029 
1030 	spdk_json_write_named_uint32(w, "default_time2wait", g_spdk_iscsi.DefaultTime2Wait);
1031 	spdk_json_write_named_uint32(w, "default_time2retain", g_spdk_iscsi.DefaultTime2Retain);
1032 
1033 	spdk_json_write_named_bool(w, "immediate_data", g_spdk_iscsi.ImmediateData);
1034 
1035 	spdk_json_write_named_bool(w, "allow_duplicated_isid", g_spdk_iscsi.AllowDuplicateIsid);
1036 
1037 	spdk_json_write_named_uint32(w, "error_recovery_level", g_spdk_iscsi.ErrorRecoveryLevel);
1038 
1039 	spdk_json_write_named_uint32(w, "timeout", g_spdk_iscsi.timeout);
1040 	spdk_json_write_named_int32(w, "nop_in_interval", g_spdk_iscsi.nopininterval);
1041 
1042 	spdk_json_write_named_bool(w, "no_discovery_auth", g_spdk_iscsi.no_discovery_auth);
1043 	spdk_json_write_named_bool(w, "req_discovery_auth", g_spdk_iscsi.req_discovery_auth);
1044 	spdk_json_write_named_bool(w, "req_discovery_auth_mutual",
1045 				   g_spdk_iscsi.req_discovery_auth_mutual);
1046 	spdk_json_write_named_int32(w, "discovery_auth_group", g_spdk_iscsi.discovery_auth_group);
1047 
1048 	spdk_json_write_named_int32(w, "min_connections_per_core",
1049 				    spdk_iscsi_conn_get_min_per_core());
1050 
1051 	spdk_json_write_object_end(w);
1052 }
1053 
1054 static void
1055 spdk_iscsi_opts_config_json(struct spdk_json_write_ctx *w)
1056 {
1057 	spdk_json_write_object_begin(w);
1058 
1059 	spdk_json_write_named_string(w, "method", "set_iscsi_options");
1060 
1061 	spdk_json_write_name(w, "params");
1062 	spdk_iscsi_opts_info_json(w);
1063 
1064 	spdk_json_write_object_end(w);
1065 }
1066 
1067 void
1068 spdk_iscsi_config_json(struct spdk_json_write_ctx *w)
1069 {
1070 	spdk_json_write_array_begin(w);
1071 	spdk_iscsi_opts_config_json(w);
1072 	spdk_iscsi_portal_grps_config_json(w);
1073 	spdk_iscsi_init_grps_config_json(w);
1074 	spdk_iscsi_tgt_nodes_config_json(w);
1075 	spdk_json_write_array_end(w);
1076 }
1077 
1078 SPDK_LOG_REGISTER_COMPONENT("iscsi", SPDK_LOG_ISCSI)
1079