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