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