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