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