]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/iscsi/iscsi_subsystem.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / lib / iscsi / iscsi_subsystem.c
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)