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