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