xref: /spdk/lib/iscsi/iscsi_subsystem.c (revision d1165a653907c85812beba21bf9cb6c657cf3bf1)
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 
40 #include "iscsi/iscsi.h"
41 #include "iscsi/init_grp.h"
42 #include "iscsi/portal_grp.h"
43 #include "iscsi/conn.h"
44 #include "iscsi/task.h"
45 
46 #include "spdk_internal/event.h"
47 #include "spdk_internal/log.h"
48 
49 static spdk_iscsi_init_cb g_init_cb_fn = NULL;
50 static void *g_init_cb_arg = NULL;
51 
52 static spdk_iscsi_fini_cb g_fini_cb_fn;
53 static void *g_fini_cb_arg;
54 
55 #define ISCSI_CONFIG_TMPL \
56 "[iSCSI]\n" \
57 "  # node name (not include optional part)\n" \
58 "  # Users can optionally change this to fit their environment.\n" \
59 "  NodeBase \"%s\"\n" \
60 "\n" \
61 "  # files\n" \
62 "  AuthFile %s\n" \
63 "\n" \
64 "  # socket I/O timeout sec. (polling is infinity)\n" \
65 "  Timeout %d\n" \
66 "\n" \
67 "  # authentication information for discovery session\n" \
68 "  DiscoveryAuthMethod %s\n" \
69 "  DiscoveryAuthGroup %s\n" \
70 "\n" \
71 "  MaxSessions %d\n" \
72 "  MaxConnectionsPerSession %d\n" \
73 "  MaxConnections %d\n" \
74 "  MaxQueueDepth %d\n" \
75 "\n" \
76 "  # iSCSI initial parameters negotiate with initiators\n" \
77 "  # NOTE: incorrect values might crash\n" \
78 "  DefaultTime2Wait %d\n" \
79 "  DefaultTime2Retain %d\n" \
80 "\n" \
81 "  ImmediateData %s\n" \
82 "  ErrorRecoveryLevel %d\n" \
83 "\n"
84 
85 static void
86 spdk_iscsi_config_dump_section(FILE *fp)
87 {
88 	const char *authmethod = "None";
89 	char authgroup[32] = "None";
90 
91 	if (NULL == fp) {
92 		return;
93 	}
94 
95 	if (g_spdk_iscsi.req_discovery_auth) {
96 		authmethod = "CHAP";
97 	} else if (g_spdk_iscsi.req_discovery_auth_mutual) {
98 		authmethod = "CHAP Mutual";
99 	} else if (!g_spdk_iscsi.no_discovery_auth) {
100 		authmethod = "Auto";
101 	}
102 
103 	if (g_spdk_iscsi.discovery_auth_group) {
104 		snprintf(authgroup, sizeof(authgroup), "AuthGroup%d", g_spdk_iscsi.discovery_auth_group);
105 	}
106 
107 	fprintf(fp, ISCSI_CONFIG_TMPL,
108 		g_spdk_iscsi.nodebase, g_spdk_iscsi.authfile,
109 		g_spdk_iscsi.timeout, authmethod, authgroup,
110 		g_spdk_iscsi.MaxSessions, g_spdk_iscsi.MaxConnectionsPerSession,
111 		g_spdk_iscsi.MaxConnections,
112 		g_spdk_iscsi.MaxQueueDepth,
113 		g_spdk_iscsi.DefaultTime2Wait, g_spdk_iscsi.DefaultTime2Retain,
114 		(g_spdk_iscsi.ImmediateData == 1) ? "Yes" : "No",
115 		g_spdk_iscsi.ErrorRecoveryLevel);
116 }
117 
118 
119 /* Portal groups */
120 static const char *portal_group_section = \
121 		"\n"
122 		"# Users must change the PortalGroup section(s) to match the IP addresses\n"
123 		"#  for their environment.\n"
124 		"# PortalGroup sections define which network portals the iSCSI target\n"
125 		"# will use to listen for incoming connections.  These are also used to\n"
126 		"#  determine which targets are accessible over each portal group.\n"
127 		"# Up to 1024 Portal directives are allowed.  These define the network\n"
128 		"#  portals of the portal group. The user must specify a IP address\n"
129 		"#  for each network portal, and may optionally specify a port and\n"
130 		"#  a cpumask. If the port is omitted, 3260 will be used. Cpumask will\n"
131 		"#  be used to set the processor affinity of the iSCSI connection\n"
132 		"#  through the portal.  If the cpumask is omitted, cpumask will be\n"
133 		"#  set to all available processors.\n"
134 		"#  Syntax:\n"
135 		"#    Portal <Name> <IP address>[:<port>[@<cpumask>]]\n";
136 
137 #define PORTAL_GROUP_TMPL \
138 "[PortalGroup%d]\n" \
139 "  Comment \"Portal%d\"\n"
140 
141 #define PORTAL_TMPL \
142 "  Portal DA1 %s:%s@0x%s\n"
143 
144 static void
145 spdk_iscsi_config_dump_portal_groups(FILE *fp)
146 {
147 	struct spdk_iscsi_portal *p = NULL;
148 	struct spdk_iscsi_portal_grp *pg = NULL;
149 
150 	/* Create portal group section */
151 	fprintf(fp, "%s", portal_group_section);
152 
153 	/* Dump portal groups */
154 	TAILQ_FOREACH(pg, &g_spdk_iscsi.pg_head, tailq) {
155 		if (NULL == pg) { continue; }
156 		fprintf(fp, PORTAL_GROUP_TMPL, pg->tag, pg->tag);
157 		/* Dump portals */
158 		TAILQ_FOREACH(p, &pg->head, per_pg_tailq) {
159 			if (NULL == p) { continue; }
160 			fprintf(fp, PORTAL_TMPL, p->host, p->port,
161 				spdk_cpuset_fmt(p->cpumask));
162 		}
163 	}
164 }
165 
166 /* Initiator Groups */
167 static const char *initiator_group_section = \
168 		"\n"
169 		"# Users must change the InitiatorGroup section(s) to match the IP\n"
170 		"#  addresses and initiator configuration in their environment.\n"
171 		"# Netmask can be used to specify a single IP address or a range of IP addresses\n"
172 		"#  Netmask 192.168.1.20   <== single IP address\n"
173 		"#  Netmask 192.168.1.0/24 <== IP range 192.168.1.*\n";
174 
175 #define INITIATOR_GROUP_TMPL \
176 "[InitiatorGroup%d]\n" \
177 "  Comment \"Initiator Group%d\"\n"
178 
179 #define INITIATOR_TMPL \
180 "  InitiatorName "
181 
182 #define NETMASK_TMPL \
183 "  Netmask "
184 
185 static void
186 spdk_iscsi_config_dump_initiator_groups(FILE *fp)
187 {
188 	struct spdk_iscsi_init_grp *ig;
189 	struct spdk_iscsi_initiator_name *iname;
190 	struct spdk_iscsi_initiator_netmask *imask;
191 
192 	/* Create initiator group section */
193 	fprintf(fp, "%s", initiator_group_section);
194 
195 	/* Dump initiator groups */
196 	TAILQ_FOREACH(ig, &g_spdk_iscsi.ig_head, tailq) {
197 		if (NULL == ig) { continue; }
198 		fprintf(fp, INITIATOR_GROUP_TMPL, ig->tag, ig->tag);
199 
200 		/* Dump initiators */
201 		fprintf(fp, INITIATOR_TMPL);
202 		TAILQ_FOREACH(iname, &ig->initiator_head, tailq) {
203 			fprintf(fp, "%s ", iname->name);
204 		}
205 		fprintf(fp, "\n");
206 
207 		/* Dump netmasks */
208 		fprintf(fp, NETMASK_TMPL);
209 		TAILQ_FOREACH(imask, &ig->netmask_head, tailq) {
210 			fprintf(fp, "%s ", imask->mask);
211 		}
212 		fprintf(fp, "\n");
213 	}
214 }
215 
216 /* Target nodes */
217 static const char *target_nodes_section = \
218 		"\n"
219 		"# Users should change the TargetNode section(s) below to match the\n"
220 		"#  desired iSCSI target node configuration.\n"
221 		"# TargetName, Mapping, LUN0 are minimum required\n";
222 
223 #define TARGET_NODE_TMPL \
224 "[TargetNode%d]\n" \
225 "  Comment \"Target%d\"\n" \
226 "  TargetName %s\n" \
227 "  TargetAlias \"%s\"\n"
228 
229 #define TARGET_NODE_PGIG_MAPPING_TMPL \
230 "  Mapping PortalGroup%d InitiatorGroup%d\n"
231 
232 #define TARGET_NODE_AUTH_TMPL \
233 "  AuthMethod %s\n" \
234 "  AuthGroup %s\n" \
235 "  UseDigest %s\n"
236 
237 #define TARGET_NODE_QD_TMPL \
238 "  QueueDepth %d\n\n"
239 
240 #define TARGET_NODE_LUN_TMPL \
241 "  LUN%d %s\n"
242 
243 static void
244 spdk_iscsi_config_dump_target_nodes(FILE *fp)
245 {
246 	int l = 0;
247 	struct spdk_scsi_dev *dev = NULL;
248 	struct spdk_iscsi_tgt_node *target = NULL;
249 	struct spdk_iscsi_pg_map *pg_map;
250 	struct spdk_iscsi_ig_map *ig_map;
251 
252 	/* Create target nodes section */
253 	fprintf(fp, "%s", target_nodes_section);
254 
255 	TAILQ_FOREACH(target, &g_spdk_iscsi.target_head, tailq) {
256 		int idx;
257 		const char *authmethod = "None";
258 		char authgroup[32] = "None";
259 		const char *usedigest = "Auto";
260 
261 		dev = target->dev;
262 		if (NULL == dev) { continue; }
263 
264 		idx = target->num;
265 		fprintf(fp, TARGET_NODE_TMPL, idx, idx, target->name, spdk_scsi_dev_get_name(dev));
266 
267 		TAILQ_FOREACH(pg_map, &target->pg_map_head, tailq) {
268 			TAILQ_FOREACH(ig_map, &pg_map->ig_map_head, tailq) {
269 				fprintf(fp, TARGET_NODE_PGIG_MAPPING_TMPL,
270 					pg_map->pg->tag,
271 					ig_map->ig->tag);
272 			}
273 		}
274 
275 		if (target->disable_chap) {
276 			authmethod = "None";
277 		} else if (!target->require_chap) {
278 			authmethod = "Auto";
279 		} else if (target->mutual_chap) {
280 			authmethod = "CHAP Mutual";
281 		} else {
282 			authmethod = "CHAP";
283 		}
284 
285 		if (target->chap_group > 0) {
286 			snprintf(authgroup, sizeof(authgroup), "AuthGroup%d", target->chap_group);
287 		}
288 
289 		if (target->header_digest) {
290 			usedigest = "Header";
291 		} else if (target->data_digest) {
292 			usedigest = "Data";
293 		}
294 
295 		fprintf(fp, TARGET_NODE_AUTH_TMPL,
296 			authmethod, authgroup, usedigest);
297 
298 		for (l = 0; l < SPDK_SCSI_DEV_MAX_LUN; l++) {
299 			struct spdk_scsi_lun *lun = spdk_scsi_dev_get_lun(dev, l);
300 
301 			if (!lun) {
302 				continue;
303 			}
304 
305 			fprintf(fp, TARGET_NODE_LUN_TMPL,
306 				spdk_scsi_lun_get_id(lun),
307 				spdk_scsi_lun_get_bdev_name(lun));
308 		}
309 
310 		fprintf(fp, TARGET_NODE_QD_TMPL,
311 			target->queue_depth);
312 	}
313 }
314 
315 static void
316 spdk_mobj_ctor(struct spdk_mempool *mp, __attribute__((unused)) void *arg,
317 	       void *_m, __attribute__((unused)) unsigned i)
318 {
319 	struct spdk_mobj *m = _m;
320 	uint64_t *phys_addr;
321 	ptrdiff_t off;
322 
323 	m->mp = mp;
324 	m->buf = (uint8_t *)m + sizeof(struct spdk_mobj);
325 	m->buf = (void *)((unsigned long)((uint8_t *)m->buf + 512) & ~511UL);
326 	off = (uint64_t)(uint8_t *)m->buf - (uint64_t)(uint8_t *)m;
327 
328 	/*
329 	 * we store the physical address in a 64bit unsigned integer
330 	 * right before the 512B aligned buffer area.
331 	 */
332 	phys_addr = (uint64_t *)m->buf - 1;
333 	*phys_addr = spdk_vtophys(m) + off;
334 }
335 
336 #define NUM_PDU_PER_CONNECTION(iscsi)	(2 * (iscsi->MaxQueueDepth + MAX_LARGE_DATAIN_PER_CONNECTION + 8))
337 #define PDU_POOL_SIZE(iscsi)	(iscsi->MaxConnections * NUM_PDU_PER_CONNECTION(iscsi))
338 #define IMMEDIATE_DATA_POOL_SIZE(iscsi)	(iscsi->MaxConnections * 128)
339 #define DATA_OUT_POOL_SIZE(iscsi)	(iscsi->MaxConnections * MAX_DATA_OUT_PER_CONNECTION)
340 
341 static int spdk_iscsi_initialize_pdu_pool(void)
342 {
343 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
344 	int imm_mobj_size = spdk_get_immediate_data_buffer_size() +
345 			    sizeof(struct spdk_mobj) + 512;
346 	int dout_mobj_size = spdk_get_data_out_buffer_size() +
347 			     sizeof(struct spdk_mobj) + 512;
348 
349 	/* create PDU pool */
350 	iscsi->pdu_pool = spdk_mempool_create("PDU_Pool",
351 					      PDU_POOL_SIZE(iscsi),
352 					      sizeof(struct spdk_iscsi_pdu),
353 					      256, SPDK_ENV_SOCKET_ID_ANY);
354 	if (!iscsi->pdu_pool) {
355 		SPDK_ERRLOG("create PDU pool failed\n");
356 		return -1;
357 	}
358 
359 	iscsi->pdu_immediate_data_pool = spdk_mempool_create_ctor("PDU_immediate_data_Pool",
360 					 IMMEDIATE_DATA_POOL_SIZE(iscsi),
361 					 imm_mobj_size, 0,
362 					 spdk_env_get_socket_id(spdk_env_get_current_core()),
363 					 spdk_mobj_ctor, NULL);
364 	if (!iscsi->pdu_immediate_data_pool) {
365 		SPDK_ERRLOG("create PDU 8k pool failed\n");
366 		return -1;
367 	}
368 
369 	iscsi->pdu_data_out_pool = spdk_mempool_create_ctor("PDU_data_out_Pool",
370 				   DATA_OUT_POOL_SIZE(iscsi),
371 				   dout_mobj_size, 0,
372 				   spdk_env_get_socket_id(spdk_env_get_current_core()),
373 				   spdk_mobj_ctor, NULL);
374 	if (!iscsi->pdu_data_out_pool) {
375 		SPDK_ERRLOG("create PDU 64k pool failed\n");
376 		return -1;
377 	}
378 
379 	return 0;
380 }
381 
382 static void spdk_iscsi_sess_ctor(struct spdk_mempool *pool, void *arg,
383 				 void *session_buf, unsigned index)
384 {
385 	struct spdk_iscsi_globals		*iscsi = arg;
386 	struct spdk_iscsi_sess	*sess = session_buf;
387 
388 	iscsi->session[index] = sess;
389 
390 	/* tsih 0 is reserved, so start tsih values at 1. */
391 	sess->tsih = index + 1;
392 }
393 
394 #define DEFAULT_TASK_POOL_SIZE 32768
395 
396 static int
397 spdk_iscsi_initialize_task_pool(void)
398 {
399 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
400 
401 	/* create scsi_task pool */
402 	iscsi->task_pool = spdk_mempool_create("SCSI_TASK_Pool",
403 					       DEFAULT_TASK_POOL_SIZE,
404 					       sizeof(struct spdk_iscsi_task),
405 					       128, SPDK_ENV_SOCKET_ID_ANY);
406 	if (!iscsi->task_pool) {
407 		SPDK_ERRLOG("create task pool failed\n");
408 		return -1;
409 	}
410 
411 	return 0;
412 }
413 
414 #define SESSION_POOL_SIZE(iscsi)	(iscsi->MaxSessions)
415 static int spdk_iscsi_initialize_session_pool(void)
416 {
417 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
418 
419 	iscsi->session_pool = spdk_mempool_create_ctor("Session_Pool",
420 			      SESSION_POOL_SIZE(iscsi),
421 			      sizeof(struct spdk_iscsi_sess), 0,
422 			      SPDK_ENV_SOCKET_ID_ANY,
423 			      spdk_iscsi_sess_ctor, iscsi);
424 	if (!iscsi->session_pool) {
425 		SPDK_ERRLOG("create session pool failed\n");
426 		return -1;
427 	}
428 
429 	return 0;
430 }
431 
432 static int
433 spdk_iscsi_initialize_all_pools(void)
434 {
435 	if (spdk_iscsi_initialize_pdu_pool() != 0) {
436 		return -1;
437 	}
438 
439 	if (spdk_iscsi_initialize_session_pool() != 0) {
440 		return -1;
441 	}
442 
443 	if (spdk_iscsi_initialize_task_pool() != 0) {
444 		return -1;
445 	}
446 
447 	return 0;
448 }
449 
450 static void
451 spdk_iscsi_check_pool(struct spdk_mempool *pool, size_t count)
452 {
453 	if (spdk_mempool_count(pool) != count) {
454 		SPDK_ERRLOG("spdk_mempool_count(%s) == %zu, should be %zu\n",
455 			    spdk_mempool_get_name(pool), spdk_mempool_count(pool), count);
456 	}
457 }
458 
459 static void
460 spdk_iscsi_check_pools(void)
461 {
462 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
463 
464 	spdk_iscsi_check_pool(iscsi->pdu_pool, PDU_POOL_SIZE(iscsi));
465 	spdk_iscsi_check_pool(iscsi->session_pool, SESSION_POOL_SIZE(iscsi));
466 	spdk_iscsi_check_pool(iscsi->pdu_immediate_data_pool, IMMEDIATE_DATA_POOL_SIZE(iscsi));
467 	spdk_iscsi_check_pool(iscsi->pdu_data_out_pool, DATA_OUT_POOL_SIZE(iscsi));
468 	/* TODO: check the task_pool on exit */
469 }
470 
471 static void
472 spdk_iscsi_free_pools(void)
473 {
474 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
475 
476 	spdk_mempool_free(iscsi->pdu_pool);
477 	spdk_mempool_free(iscsi->session_pool);
478 	spdk_mempool_free(iscsi->pdu_immediate_data_pool);
479 	spdk_mempool_free(iscsi->pdu_data_out_pool);
480 	spdk_mempool_free(iscsi->task_pool);
481 }
482 
483 void spdk_put_pdu(struct spdk_iscsi_pdu *pdu)
484 {
485 	if (!pdu) {
486 		return;
487 	}
488 
489 	pdu->ref--;
490 
491 	if (pdu->ref < 0) {
492 		SPDK_ERRLOG("Negative PDU refcount: %p\n", pdu);
493 		pdu->ref = 0;
494 	}
495 
496 	if (pdu->ref == 0) {
497 		if (pdu->mobj) {
498 			spdk_mempool_put(pdu->mobj->mp, (void *)pdu->mobj);
499 		}
500 
501 		if (pdu->data && !pdu->data_from_mempool) {
502 			free(pdu->data);
503 		}
504 
505 		spdk_mempool_put(g_spdk_iscsi.pdu_pool, (void *)pdu);
506 	}
507 }
508 
509 struct spdk_iscsi_pdu *spdk_get_pdu(void)
510 {
511 	struct spdk_iscsi_pdu *pdu;
512 
513 	pdu = spdk_mempool_get(g_spdk_iscsi.pdu_pool);
514 	if (!pdu) {
515 		SPDK_ERRLOG("Unable to get PDU\n");
516 		abort();
517 	}
518 
519 	/* we do not want to zero out the last part of the structure reserved for AHS and sense data */
520 	memset(pdu, 0, offsetof(struct spdk_iscsi_pdu, ahs));
521 	pdu->ref = 1;
522 
523 	return pdu;
524 }
525 
526 static void
527 spdk_iscsi_log_globals(void)
528 {
529 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "AuthFile %s\n", g_spdk_iscsi.authfile);
530 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "NodeBase %s\n", g_spdk_iscsi.nodebase);
531 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxSessions %d\n", g_spdk_iscsi.MaxSessions);
532 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxConnectionsPerSession %d\n",
533 		      g_spdk_iscsi.MaxConnectionsPerSession);
534 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxQueueDepth %d\n", g_spdk_iscsi.MaxQueueDepth);
535 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "DefaultTime2Wait %d\n",
536 		      g_spdk_iscsi.DefaultTime2Wait);
537 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "DefaultTime2Retain %d\n",
538 		      g_spdk_iscsi.DefaultTime2Retain);
539 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "ImmediateData %s\n",
540 		      g_spdk_iscsi.ImmediateData ? "Yes" : "No");
541 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "AllowDuplicateIsid %s\n",
542 		      g_spdk_iscsi.AllowDuplicateIsid ? "Yes" : "No");
543 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "ErrorRecoveryLevel %d\n",
544 		      g_spdk_iscsi.ErrorRecoveryLevel);
545 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Timeout %d\n", g_spdk_iscsi.timeout);
546 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "NopInInterval %d\n",
547 		      g_spdk_iscsi.nopininterval);
548 	if (g_spdk_iscsi.no_discovery_auth != 0) {
549 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
550 			      "DiscoveryAuthMethod None\n");
551 	} else if (g_spdk_iscsi.req_discovery_auth == 0) {
552 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
553 			      "DiscoveryAuthMethod Auto\n");
554 	} else {
555 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
556 			      "DiscoveryAuthMethod %s %s\n",
557 			      g_spdk_iscsi.req_discovery_auth ? "CHAP" : "",
558 			      g_spdk_iscsi.req_discovery_auth_mutual ? "Mutual" : "");
559 	}
560 
561 	if (g_spdk_iscsi.discovery_auth_group == 0) {
562 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
563 			      "DiscoveryAuthGroup None\n");
564 	} else {
565 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
566 			      "DiscoveryAuthGroup AuthGroup%d\n",
567 			      g_spdk_iscsi.discovery_auth_group);
568 	}
569 
570 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MinConnectionsPerCore%d\n",
571 		      spdk_iscsi_conn_get_min_per_core());
572 }
573 
574 static void
575 spdk_iscsi_read_parameters_from_config_file(struct spdk_conf_section *sp)
576 {
577 	const char *val;
578 	char *authfile, *nodebase;
579 	int MaxSessions;
580 	int MaxConnectionsPerSession;
581 	int MaxQueueDepth;
582 	int DefaultTime2Wait;
583 	int DefaultTime2Retain;
584 	int ErrorRecoveryLevel;
585 	int timeout;
586 	int nopininterval;
587 	int min_conn_per_core = 0;
588 	const char *ag_tag;
589 	int ag_tag_i;
590 
591 	val = spdk_conf_section_get_val(sp, "Comment");
592 	if (val != NULL) {
593 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Comment %s\n", val);
594 	}
595 
596 	val = spdk_conf_section_get_val(sp, "AuthFile");
597 	if (val != NULL) {
598 		authfile = strdup(val);
599 		if (authfile) {
600 			free(g_spdk_iscsi.authfile);
601 			g_spdk_iscsi.authfile = authfile;
602 		} else {
603 			SPDK_ERRLOG("could not strdup for authfile %s,"
604 				    "keeping %s instead\n", val, g_spdk_iscsi.authfile);
605 		}
606 	}
607 
608 	val = spdk_conf_section_get_val(sp, "NodeBase");
609 	if (val != NULL) {
610 		nodebase = strdup(val);
611 		if (nodebase) {
612 			free(g_spdk_iscsi.nodebase);
613 			g_spdk_iscsi.nodebase = nodebase;
614 		} else {
615 			SPDK_ERRLOG("could not strdup for nodebase %s,"
616 				    "keeping %s instead\n", val, g_spdk_iscsi.nodebase);
617 		}
618 	}
619 
620 	MaxSessions = spdk_conf_section_get_intval(sp, "MaxSessions");
621 	if (MaxSessions >= 0) {
622 		if (MaxSessions == 0) {
623 			SPDK_ERRLOG("MaxSessions == 0 invalid, ignoring\n");
624 		} else if (MaxSessions > 65535) {
625 			SPDK_ERRLOG("MaxSessions == %d invalid, ignoring\n", MaxSessions);
626 		} else {
627 			g_spdk_iscsi.MaxSessions = MaxSessions;
628 		}
629 	}
630 
631 	MaxConnectionsPerSession = spdk_conf_section_get_intval(sp, "MaxConnectionsPerSession");
632 	if (MaxConnectionsPerSession >= 0) {
633 		if (MaxConnectionsPerSession == 0) {
634 			SPDK_ERRLOG("MaxConnectionsPerSession == 0 invalid, ignoring\n");
635 		} else if (MaxConnectionsPerSession > 65535) {
636 			SPDK_ERRLOG("MaxConnectionsPerSession == %d invalid, ignoring\n",
637 				    MaxConnectionsPerSession);
638 		} else {
639 			g_spdk_iscsi.MaxConnectionsPerSession = MaxConnectionsPerSession;
640 		}
641 	}
642 
643 	MaxQueueDepth = spdk_conf_section_get_intval(sp, "MaxQueueDepth");
644 	if (MaxQueueDepth >= 0) {
645 		if (MaxQueueDepth == 0) {
646 			SPDK_ERRLOG("MaxQueueDepth == 0 invalid, ignoring\n");
647 		} else if (MaxQueueDepth > 256) {
648 			SPDK_ERRLOG("MaxQueueDepth == %d invalid, ignoring\n", MaxQueueDepth);
649 		} else {
650 			g_spdk_iscsi.MaxQueueDepth = MaxQueueDepth;
651 		}
652 	}
653 
654 	DefaultTime2Wait = spdk_conf_section_get_intval(sp, "DefaultTime2Wait");
655 	if (DefaultTime2Wait >= 0) {
656 		if (DefaultTime2Wait > 3600) {
657 			SPDK_ERRLOG("DefaultTime2Wait == %d invalid, ignoring\n", DefaultTime2Wait);
658 		} else {
659 			g_spdk_iscsi.DefaultTime2Wait = DefaultTime2Wait;
660 		}
661 	}
662 	DefaultTime2Retain = spdk_conf_section_get_intval(sp, "DefaultTime2Retain");
663 	if (DefaultTime2Retain >= 0) {
664 		if (DefaultTime2Retain > 3600) {
665 			SPDK_ERRLOG("DefaultTime2Retain == %d invalid, ignoring\n", DefaultTime2Retain);
666 		} else {
667 			g_spdk_iscsi.DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
668 		}
669 	}
670 	g_spdk_iscsi.ImmediateData = spdk_conf_section_get_boolval(sp, "ImmediateData",
671 				     g_spdk_iscsi.ImmediateData);
672 
673 	/* This option is only for test.
674 	 * If AllowDuplicateIsid is enabled, it allows different connections carrying
675 	 * TSIH=0 login the target within the same session.
676 	 */
677 	g_spdk_iscsi.AllowDuplicateIsid = spdk_conf_section_get_boolval(sp, "AllowDuplicateIsid",
678 					  g_spdk_iscsi.AllowDuplicateIsid);
679 
680 	ErrorRecoveryLevel = spdk_conf_section_get_intval(sp, "ErrorRecoveryLevel");
681 	if (ErrorRecoveryLevel >= 0) {
682 		if (ErrorRecoveryLevel > 2) {
683 			SPDK_ERRLOG("ErrorRecoveryLevel %d not supported, keeping existing %d\n",
684 				    ErrorRecoveryLevel, g_spdk_iscsi.ErrorRecoveryLevel);
685 		} else {
686 			g_spdk_iscsi.ErrorRecoveryLevel = ErrorRecoveryLevel;
687 		}
688 	}
689 	timeout = spdk_conf_section_get_intval(sp, "Timeout");
690 	if (timeout >= 0) {
691 		g_spdk_iscsi.timeout = timeout;
692 	}
693 	nopininterval = spdk_conf_section_get_intval(sp, "NopInInterval");
694 	if (nopininterval >= 0) {
695 		if (nopininterval > MAX_NOPININTERVAL) {
696 			SPDK_ERRLOG("NopInInterval == %d invalid, ignoring\n", nopininterval);
697 		} else {
698 			g_spdk_iscsi.nopininterval = nopininterval;
699 		}
700 	}
701 	val = spdk_conf_section_get_val(sp, "DiscoveryAuthMethod");
702 	if (val != NULL) {
703 		if (strcasecmp(val, "CHAP") == 0) {
704 			g_spdk_iscsi.no_discovery_auth = 0;
705 			g_spdk_iscsi.req_discovery_auth = 1;
706 			g_spdk_iscsi.req_discovery_auth_mutual = 0;
707 		} else if (strcasecmp(val, "Mutual") == 0) {
708 			g_spdk_iscsi.no_discovery_auth = 0;
709 			g_spdk_iscsi.req_discovery_auth = 1;
710 			g_spdk_iscsi.req_discovery_auth_mutual = 1;
711 		} else if (strcasecmp(val, "Auto") == 0) {
712 			g_spdk_iscsi.no_discovery_auth = 0;
713 			g_spdk_iscsi.req_discovery_auth = 0;
714 			g_spdk_iscsi.req_discovery_auth_mutual = 0;
715 		} else if (strcasecmp(val, "None") == 0) {
716 			g_spdk_iscsi.no_discovery_auth = 1;
717 			g_spdk_iscsi.req_discovery_auth = 0;
718 			g_spdk_iscsi.req_discovery_auth_mutual = 0;
719 		} else {
720 			SPDK_ERRLOG("unknown auth %s, ignoring\n", val);
721 		}
722 	}
723 	val = spdk_conf_section_get_val(sp, "DiscoveryAuthGroup");
724 	if (val != NULL) {
725 		ag_tag = val;
726 		if (strcasecmp(ag_tag, "None") == 0) {
727 			g_spdk_iscsi.discovery_auth_group = 0;
728 		} else {
729 			if (strncasecmp(ag_tag, "AuthGroup",
730 					strlen("AuthGroup")) != 0
731 			    || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1
732 			    || ag_tag_i == 0) {
733 				SPDK_ERRLOG("invalid auth group %s, ignoring\n", ag_tag);
734 			} else {
735 				g_spdk_iscsi.discovery_auth_group = ag_tag_i;
736 			}
737 		}
738 	}
739 	min_conn_per_core = spdk_conf_section_get_intval(sp, "MinConnectionsPerCore");
740 	if (min_conn_per_core >= 0) {
741 		spdk_iscsi_conn_set_min_per_core(min_conn_per_core);
742 	}
743 }
744 
745 static int
746 spdk_iscsi_app_read_parameters(void)
747 {
748 	struct spdk_conf_section *sp;
749 	int rc;
750 
751 	g_spdk_iscsi.MaxSessions = DEFAULT_MAX_SESSIONS;
752 	g_spdk_iscsi.MaxConnectionsPerSession = DEFAULT_MAX_CONNECTIONS_PER_SESSION;
753 	g_spdk_iscsi.MaxQueueDepth = DEFAULT_MAX_QUEUE_DEPTH;
754 	g_spdk_iscsi.DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT;
755 	g_spdk_iscsi.DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
756 	g_spdk_iscsi.ImmediateData = DEFAULT_IMMEDIATEDATA;
757 	g_spdk_iscsi.AllowDuplicateIsid = 0;
758 	g_spdk_iscsi.ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL;
759 	g_spdk_iscsi.timeout = DEFAULT_TIMEOUT;
760 	g_spdk_iscsi.nopininterval = DEFAULT_NOPININTERVAL;
761 	g_spdk_iscsi.no_discovery_auth = 0;
762 	g_spdk_iscsi.req_discovery_auth = 0;
763 	g_spdk_iscsi.req_discovery_auth_mutual = 0;
764 	g_spdk_iscsi.discovery_auth_group = 0;
765 	g_spdk_iscsi.authfile = strdup(SPDK_ISCSI_DEFAULT_AUTHFILE);
766 	if (!g_spdk_iscsi.authfile) {
767 		SPDK_ERRLOG("could not strdup() default authfile name\n");
768 		return -ENOMEM;
769 	}
770 	g_spdk_iscsi.nodebase = strdup(SPDK_ISCSI_DEFAULT_NODEBASE);
771 	if (!g_spdk_iscsi.nodebase) {
772 		SPDK_ERRLOG("could not strdup() default nodebase\n");
773 		return -ENOMEM;
774 	}
775 
776 	/* Process parameters */
777 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "spdk_iscsi_app_read_parameters\n");
778 	sp = spdk_conf_find_section(NULL, "iSCSI");
779 	if (sp != NULL) {
780 		spdk_iscsi_read_parameters_from_config_file(sp);
781 	}
782 
783 	g_spdk_iscsi.session = spdk_dma_zmalloc(sizeof(void *) * g_spdk_iscsi.MaxSessions, 0, NULL);
784 	if (!g_spdk_iscsi.session) {
785 		SPDK_ERRLOG("spdk_dma_zmalloc() failed for session array\n");
786 		return -1;
787 	}
788 
789 	/*
790 	 * For now, just support same number of total connections, rather
791 	 *  than MaxSessions * MaxConnectionsPerSession.  After we add better
792 	 *  handling for low resource conditions from our various buffer
793 	 *  pools, we can bump this up to support more connections.
794 	 */
795 	g_spdk_iscsi.MaxConnections = g_spdk_iscsi.MaxSessions;
796 
797 	spdk_iscsi_log_globals();
798 
799 	/* portal groups */
800 	rc = spdk_iscsi_portal_grp_array_create();
801 	if (rc < 0) {
802 		SPDK_ERRLOG("spdk_iscsi_portal_grp_array_create() failed\n");
803 		return -1;
804 	}
805 
806 	/* initiator groups */
807 	rc = spdk_iscsi_init_grp_array_create();
808 	if (rc < 0) {
809 		SPDK_ERRLOG("spdk_iscsi_init_grp_array_create() failed\n");
810 		return -1;
811 	}
812 
813 	rc = pthread_mutex_init(&g_spdk_iscsi.mutex, NULL);
814 	if (rc != 0) {
815 		SPDK_ERRLOG("mutex_init() failed\n");
816 		return -1;
817 	}
818 
819 	return 0;
820 }
821 
822 static void
823 spdk_iscsi_init_complete(int rc)
824 {
825 	spdk_iscsi_init_cb cb_fn = g_init_cb_fn;
826 	void *cb_arg = g_init_cb_arg;
827 
828 	g_init_cb_fn = NULL;
829 	g_init_cb_arg = NULL;
830 
831 	cb_fn(cb_arg, rc);
832 }
833 
834 static void
835 spdk_iscsi_poll_group_poll(void *ctx)
836 {
837 	struct spdk_iscsi_poll_group *group = ctx;
838 	struct spdk_iscsi_conn *conn, *tmp;
839 	int rc;
840 
841 	if (!STAILQ_EMPTY(&group->connections)) {
842 		rc = spdk_sock_group_poll(group->sock_group);
843 		if (rc < 0) {
844 			SPDK_ERRLOG("Failed to poll sock_group=%p\n", group->sock_group);
845 		}
846 	}
847 
848 	STAILQ_FOREACH_SAFE(conn, &group->connections, link, tmp) {
849 		conn->fn(conn);
850 	}
851 }
852 
853 static void
854 iscsi_create_poll_group_done(void *ctx)
855 {
856 	spdk_iscsi_init_complete(0);
857 }
858 
859 static void
860 iscsi_create_poll_group(void *ctx)
861 {
862 	struct spdk_iscsi_poll_group *pg;
863 
864 	pg = &g_spdk_iscsi.poll_group[spdk_env_get_current_core()];
865 	pg->core = spdk_env_get_current_core();
866 	assert(pg != NULL);
867 
868 	STAILQ_INIT(&pg->connections);
869 	pg->sock_group = spdk_sock_group_create();
870 	assert(pg->sock_group != NULL);
871 
872 	pg->poller = spdk_poller_register(spdk_iscsi_poll_group_poll, pg, 0);
873 }
874 
875 static void
876 iscsi_unregister_poll_group(void *ctx)
877 {
878 	struct spdk_iscsi_poll_group *pg;
879 
880 	pg = &g_spdk_iscsi.poll_group[spdk_env_get_current_core()];
881 	assert(pg != NULL);
882 	assert(pg->poller != NULL);
883 	assert(pg->sock_group != NULL);
884 
885 	spdk_sock_group_close(&pg->sock_group);
886 	spdk_poller_unregister(&pg->poller);
887 }
888 
889 static void
890 spdk_initialize_iscsi_poll_group(void)
891 {
892 	size_t g_num_poll_groups = spdk_env_get_last_core() + 1;
893 
894 	g_spdk_iscsi.poll_group = calloc(g_num_poll_groups, sizeof(struct spdk_iscsi_poll_group));
895 	if (!g_spdk_iscsi.poll_group) {
896 		SPDK_ERRLOG("Failed to allocated iscsi poll group\n");
897 		spdk_iscsi_init_complete(-1);
898 		return;
899 	}
900 
901 	/* Send a message to each thread and create a poll group */
902 	spdk_for_each_thread(iscsi_create_poll_group, NULL, iscsi_create_poll_group_done);
903 }
904 
905 void
906 spdk_iscsi_init(spdk_iscsi_init_cb cb_fn, void *cb_arg)
907 {
908 	int rc;
909 
910 	assert(cb_fn != NULL);
911 	g_init_cb_fn = cb_fn;
912 	g_init_cb_arg = cb_arg;
913 
914 	rc = spdk_iscsi_app_read_parameters();
915 	if (rc < 0) {
916 		SPDK_ERRLOG("spdk_iscsi_app_read_parameters() failed\n");
917 		spdk_iscsi_init_complete(-1);
918 		return;
919 	}
920 
921 	rc = spdk_iscsi_initialize_all_pools();
922 	if (rc != 0) {
923 		SPDK_ERRLOG("spdk_initialize_all_pools() failed\n");
924 		spdk_iscsi_init_complete(-1);
925 		return;
926 	}
927 
928 	rc = spdk_iscsi_init_tgt_nodes();
929 	if (rc < 0) {
930 		SPDK_ERRLOG("spdk_iscsi_init_tgt_nodes() failed\n");
931 		spdk_iscsi_init_complete(-1);
932 		return;
933 	}
934 
935 	rc = spdk_initialize_iscsi_conns();
936 	if (rc < 0) {
937 		SPDK_ERRLOG("spdk_initialize_iscsi_conns() failed\n");
938 		spdk_iscsi_init_complete(-1);
939 		return;
940 	}
941 
942 	spdk_initialize_iscsi_poll_group();
943 }
944 
945 void
946 spdk_iscsi_fini(spdk_iscsi_fini_cb cb_fn, void *cb_arg)
947 {
948 	g_fini_cb_fn = cb_fn;
949 	g_fini_cb_arg = cb_arg;
950 
951 	spdk_iscsi_portal_grp_close_all();
952 	spdk_shutdown_iscsi_conns();
953 }
954 
955 static void
956 spdk_iscsi_fini_done(void *arg)
957 {
958 	spdk_iscsi_check_pools();
959 	spdk_iscsi_free_pools();
960 
961 	spdk_iscsi_shutdown_tgt_nodes();
962 	spdk_iscsi_init_grp_array_destroy();
963 	spdk_iscsi_portal_grp_array_destroy();
964 	free(g_spdk_iscsi.authfile);
965 	free(g_spdk_iscsi.nodebase);
966 	free(g_spdk_iscsi.poll_group);
967 
968 	pthread_mutex_destroy(&g_spdk_iscsi.mutex);
969 	g_fini_cb_fn(g_fini_cb_arg);
970 }
971 
972 void
973 spdk_shutdown_iscsi_conns_done(void)
974 {
975 	spdk_for_each_thread(iscsi_unregister_poll_group, NULL, spdk_iscsi_fini_done);
976 }
977 
978 void
979 spdk_iscsi_config_text(FILE *fp)
980 {
981 	spdk_iscsi_config_dump_section(fp);
982 	spdk_iscsi_config_dump_portal_groups(fp);
983 	spdk_iscsi_config_dump_initiator_groups(fp);
984 	spdk_iscsi_config_dump_target_nodes(fp);
985 }
986 
987 SPDK_LOG_REGISTER_COMPONENT("iscsi", SPDK_LOG_ISCSI)
988