1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * ISCSID -- 28 * 29 * Discovery of targets and access to the persistent storage starts here. 30 */ 31 32 #include <sys/thread.h> 33 #include <sys/types.h> 34 #include <sys/proc.h> /* declares: p0 */ 35 #include <sys/cmn_err.h> 36 #include <sys/scsi/adapters/iscsi_if.h> 37 #include <netinet/in.h> 38 #include "iscsi_targetparam.h" 39 #include "isns_client.h" 40 #include "isns_protocol.h" 41 #include "persistent.h" 42 #include "iscsi.h" 43 #include <sys/ethernet.h> 44 #include <sys/bootprops.h> 45 46 /* 47 * local function prototypes 48 */ 49 static boolean_t iscsid_init_config(iscsi_hba_t *ihp); 50 static boolean_t iscsid_init_targets(iscsi_hba_t *ihp); 51 static void iscsid_thread_static(iscsi_thread_t *thread, void *p); 52 static void iscsid_thread_sendtgts(iscsi_thread_t *thread, void *p); 53 static void iscsid_thread_isns(iscsi_thread_t *thread, void *p); 54 static void iscsid_thread_slp(iscsi_thread_t *thread, void *p); 55 static void iscsid_thread_boot_wd(iscsi_thread_t *thread, void *p); 56 static void iscsid_threads_create(iscsi_hba_t *ihp); 57 static void iscsid_threads_destroy(void); 58 static int iscsid_copyto_param_set(uint32_t param_id, 59 iscsi_login_params_t *params, iscsi_param_set_t *ipsp); 60 static void iscsid_add_pg_list_to_cache(iscsi_hba_t *ihp, 61 isns_portal_group_list_t *pg_list); 62 static void iscsid_remove_target_param(char *name); 63 static boolean_t iscsid_add(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method, 64 struct sockaddr *addr_dsc, char *target_name, int tpgt, 65 struct sockaddr *addr_tgt); 66 static void iscsi_discovery_event(iscsi_hba_t *ihp, 67 iSCSIDiscoveryMethod_t m, boolean_t start); 68 static boolean_t iscsid_boot_init_config(iscsi_hba_t *ihp); 69 static iscsi_sess_t *iscsi_add_boot_sess(iscsi_hba_t *ihp, int isid); 70 static boolean_t iscsid_make_entry(ib_boot_prop_t *boot_prop_entry, 71 entry_t *entry); 72 static boolean_t iscsid_check_active_boot_conn(iscsi_hba_t *ihp); 73 74 extern int modrootloaded; 75 int iscsi_configroot_retry = 20; 76 static boolean_t iscsi_configroot_printed = FALSE; 77 static int iscsi_net_up = 0; 78 extern ib_boot_prop_t *iscsiboot_prop; 79 80 #define ISCSI_CONFIGROOT_DELAY 1 81 82 /* 83 * iSCSI target discovery thread table 84 */ 85 typedef struct iscsid_thr_table { 86 void (*func_start)(iscsi_thread_t *, void *); 87 iscsi_thread_t *thr_id; 88 iSCSIDiscoveryMethod_t method; 89 char *name; 90 } iscsid_thr_table; 91 92 static iscsid_thr_table iscsid_thr[] = { 93 { iscsid_thread_static, NULL, 94 iSCSIDiscoveryMethodStatic, 95 "Static" }, 96 { iscsid_thread_sendtgts, NULL, 97 iSCSIDiscoveryMethodSendTargets, 98 "SendTarget" }, 99 { iscsid_thread_slp, NULL, 100 iSCSIDiscoveryMethodSLP, 101 "SLP" }, 102 { iscsid_thread_isns, NULL, 103 iSCSIDiscoveryMethodISNS, 104 "iSNS" }, 105 { NULL, NULL, 106 iSCSIDiscoveryMethodUnknown, 107 NULL } 108 }; 109 110 /* 111 * discovery method event table 112 */ 113 iSCSIDiscoveryMethod_t for_failure[] = { 114 iSCSIDiscoveryMethodStatic, 115 iSCSIDiscoveryMethodSLP, 116 iSCSIDiscoveryMethodISNS, 117 iSCSIDiscoveryMethodSendTargets, 118 iSCSIDiscoveryMethodUnknown /* terminating value */ 119 }; 120 121 /* 122 * The following private tunable, set in /etc/system, e.g., 123 * set iscsi:iscsi_boot_max_delay = 360 124 * , provides with customer a max wait time in 125 * seconds to wait for boot lun online during iscsi boot. 126 * Defaults to 180s. 127 */ 128 int iscsi_boot_max_delay = ISCSI_BOOT_DEFAULT_MAX_DELAY; 129 130 /* 131 * discovery configuration semaphore 132 */ 133 ksema_t iscsid_config_semaphore; 134 135 static iscsi_thread_t *iscsi_boot_wd_handle = NULL; 136 137 #define CHECK_METHOD(v) ((dm & v) ? B_TRUE : B_FALSE) 138 139 /* 140 * Check if IP is valid 141 */ 142 static boolean_t 143 iscsid_ip_check(char *ip) 144 { 145 int i = 0; 146 147 if (!ip) 148 return (B_FALSE); 149 for (; (ip[i] == 0) && (i < IB_IP_BUFLEN); i++) {} 150 if (i == IB_IP_BUFLEN) { 151 /* invalid IP address */ 152 return (B_FALSE); 153 } 154 return (B_TRUE); 155 } 156 157 /* 158 * Make an entry for the boot target. 159 * return B_TRUE upon success 160 * B_FALSE if fail 161 */ 162 static boolean_t 163 iscsid_make_entry(ib_boot_prop_t *boot_prop_entry, entry_t *entry) 164 { 165 if (entry == NULL || boot_prop_entry == NULL) { 166 return (B_FALSE); 167 } 168 169 if (!iscsid_ip_check( 170 (char *)&boot_prop_entry->boot_tgt.tgt_ip_u)) 171 return (B_FALSE); 172 173 if (boot_prop_entry->boot_tgt.sin_family != AF_INET && 174 boot_prop_entry->boot_tgt.sin_family != AF_INET6) 175 return (B_FALSE); 176 177 entry->e_vers = ISCSI_INTERFACE_VERSION; 178 179 mutex_enter(&iscsi_oid_mutex); 180 entry->e_oid = iscsi_oid++; 181 mutex_exit(&iscsi_oid_mutex); 182 183 entry->e_tpgt = ISCSI_DEFAULT_TPGT; 184 185 if (boot_prop_entry->boot_tgt.sin_family == AF_INET) { 186 entry->e_u.u_in4.s_addr = 187 boot_prop_entry->boot_tgt.tgt_ip_u.u_in4.s_addr; 188 entry->e_insize = sizeof (struct in_addr); 189 } else { 190 (void) bcopy( 191 &boot_prop_entry->boot_tgt.tgt_ip_u.u_in6.s6_addr, 192 entry->e_u.u_in6.s6_addr, 16); 193 entry->e_insize = sizeof (struct in6_addr); 194 } 195 196 entry->e_port = boot_prop_entry->boot_tgt.tgt_port; 197 entry->e_boot = B_TRUE; 198 return (B_TRUE); 199 } 200 201 /* 202 * Create the boot session 203 */ 204 static void 205 iscsi_boot_session_create(iscsi_hba_t *ihp, 206 ib_boot_prop_t *boot_prop_table) 207 { 208 iSCSIDiscoveryMethod_t dm; 209 entry_t e; 210 iscsi_sockaddr_t addr_dsc; 211 212 if (ihp == NULL || boot_prop_table == NULL) { 213 return; 214 } 215 216 if (!iscsid_ip_check( 217 (char *)&boot_prop_table->boot_tgt.tgt_ip_u)) { 218 return; 219 } 220 221 if (boot_prop_table->boot_tgt.tgt_name != NULL) { 222 dm = iSCSIDiscoveryMethodStatic | 223 iSCSIDiscoveryMethodBoot; 224 if (!iscsid_make_entry(boot_prop_table, &e)) 225 return; 226 iscsid_addr_to_sockaddr(e.e_insize, &e.e_u, 227 e.e_port, &addr_dsc.sin); 228 229 (void) iscsid_add(ihp, dm, &addr_dsc.sin, 230 (char *)boot_prop_table->boot_tgt.tgt_name, 231 e.e_tpgt, &addr_dsc.sin); 232 } else { 233 dm = iSCSIDiscoveryMethodSendTargets | 234 iSCSIDiscoveryMethodBoot; 235 if (!iscsid_make_entry(boot_prop_table, &e)) 236 return; 237 iscsid_addr_to_sockaddr(e.e_insize, &e.e_u, 238 e.e_port, &addr_dsc.sin); 239 iscsid_do_sendtgts(&e); 240 (void) iscsid_login_tgt(ihp, NULL, dm, 241 &addr_dsc.sin); 242 } 243 } 244 245 /* 246 * iscsid_init -- to initialize stuffs related to iscsi daemon, 247 * and to create boot session if needed 248 */ 249 boolean_t 250 iscsid_init(iscsi_hba_t *ihp) 251 { 252 boolean_t rval = B_TRUE; 253 254 sema_init(&iscsid_config_semaphore, 1, NULL, 255 SEMA_DRIVER, NULL); 256 persistent_init(); 257 iscsid_threads_create(ihp); 258 259 if (modrootloaded == 1) { 260 /* normal case, load the persistent store */ 261 if (persistent_load() == B_TRUE) { 262 ihp->hba_persistent_loaded = B_TRUE; 263 } else { 264 return (B_FALSE); 265 } 266 } 267 268 if ((modrootloaded == 0) && (iscsiboot_prop != NULL)) { 269 if (!iscsid_boot_init_config(ihp)) { 270 rval = B_FALSE; 271 } else { 272 iscsi_boot_session_create(ihp, iscsiboot_prop); 273 iscsi_boot_wd_handle = 274 iscsi_thread_create(ihp->hba_dip, 275 "BootWD", iscsid_thread_boot_wd, ihp); 276 if (iscsi_boot_wd_handle) { 277 rval = iscsi_thread_start( 278 iscsi_boot_wd_handle); 279 } else { 280 rval = B_FALSE; 281 } 282 } 283 if (rval == B_FALSE) { 284 cmn_err(CE_NOTE, "Initializaton of iscsi boot session" 285 " partially failed"); 286 } 287 } 288 289 return (rval); 290 } 291 292 /* 293 * iscsid_start -- start the iscsi initiator daemon, actually this code 294 * is just to enable discovery methods which are set enabled in 295 * persistent store, as an economic way to present the 'daemon' funtionality 296 */ 297 boolean_t 298 iscsid_start(iscsi_hba_t *ihp) { 299 boolean_t rval = B_FALSE; 300 iSCSIDiscoveryMethod_t dm; 301 iSCSIDiscoveryMethod_t *fdm; 302 303 rval = iscsid_init_config(ihp); 304 if (rval == B_TRUE) { 305 rval = iscsid_init_targets(ihp); 306 } 307 308 if (rval == B_TRUE) { 309 dm = persistent_disc_meth_get(); 310 rval = iscsid_enable_discovery(ihp, dm, B_TRUE); 311 if (rval == B_TRUE) { 312 iscsid_poke_discovery(ihp, 313 iSCSIDiscoveryMethodUnknown); 314 (void) iscsid_login_tgt(ihp, NULL, 315 iSCSIDiscoveryMethodUnknown, NULL); 316 } 317 } 318 319 if (rval == B_FALSE) { 320 /* 321 * In case of failure the events still need to be sent 322 * because the door daemon will pause until all these 323 * events have occurred. 324 */ 325 for (fdm = &for_failure[0]; *fdm != 326 iSCSIDiscoveryMethodUnknown; fdm++) { 327 /* ---- Send both start and end events ---- */ 328 iscsi_discovery_event(ihp, *fdm, B_TRUE); 329 iscsi_discovery_event(ihp, *fdm, B_FALSE); 330 } 331 } 332 333 return (rval); 334 } 335 336 /* 337 * iscsid_stop -- stop the iscsi initiator daemon, by disabling 338 * all the discovery methods first, and then try to stop all 339 * related threads 340 */ 341 boolean_t 342 iscsid_stop(iscsi_hba_t *ihp) { 343 boolean_t rval = B_FALSE; 344 iscsi_sess_t *isp = NULL; 345 346 if (iscsid_disable_discovery(ihp, 347 ISCSI_ALL_DISCOVERY_METHODS) == B_FALSE) { 348 (void) iscsid_enable_discovery(ihp, 349 ISCSI_ALL_DISCOVERY_METHODS, B_TRUE); 350 return (rval); 351 } 352 353 /* final check */ 354 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 355 if (ihp->hba_sess_list == NULL) { 356 rval = B_TRUE; 357 } else { 358 /* 359 * If only boot session is left, that is OK. 360 * Otherwise, we should consider stop failed. 361 */ 362 rval = B_TRUE; 363 for (isp = ihp->hba_sess_list; isp != NULL; 364 isp = isp->sess_next) { 365 if (isp->sess_boot == B_FALSE) { 366 rval = B_FALSE; 367 break; 368 } 369 } 370 } 371 rw_exit(&ihp->hba_sess_list_rwlock); 372 373 if (rval == B_FALSE) { 374 (void) iscsid_enable_discovery(ihp, 375 ISCSI_ALL_DISCOVERY_METHODS, B_TRUE); 376 return (rval); 377 } 378 379 return (rval); 380 } 381 382 /* 383 * iscsid_fini -- do whatever is required to clean up 384 */ 385 /* ARGSUSED */ 386 void 387 iscsid_fini() 388 { 389 if (iscsi_boot_wd_handle != NULL) { 390 iscsi_thread_destroy(iscsi_boot_wd_handle); 391 iscsi_boot_wd_handle = NULL; 392 } 393 iscsid_threads_destroy(); 394 persistent_fini(); 395 sema_destroy(&iscsid_config_semaphore); 396 } 397 398 /* 399 * iscsid_props -- returns discovery thread information, used by ioctl code 400 */ 401 void 402 iscsid_props(iSCSIDiscoveryProperties_t *props) 403 { 404 iSCSIDiscoveryMethod_t dm; 405 406 dm = persistent_disc_meth_get(); 407 408 props->vers = ISCSI_INTERFACE_VERSION; 409 410 /* ---- change once thread is implemented ---- */ 411 props->iSNSDiscoverySettable = B_FALSE; 412 props->SLPDiscoverySettable = B_FALSE; 413 props->StaticDiscoverySettable = B_TRUE; 414 props->SendTargetsDiscoverySettable = B_TRUE; 415 props->iSNSDiscoveryMethod = iSNSDiscoveryMethodStatic; 416 417 props->iSNSDiscoveryEnabled = CHECK_METHOD(iSCSIDiscoveryMethodISNS); 418 props->StaticDiscoveryEnabled = 419 CHECK_METHOD(iSCSIDiscoveryMethodStatic); 420 props->SendTargetsDiscoveryEnabled = 421 CHECK_METHOD(iSCSIDiscoveryMethodSendTargets); 422 props->SLPDiscoveryEnabled = CHECK_METHOD(iSCSIDiscoveryMethodSLP); 423 } 424 425 /* 426 * iscsid_enable_discovery - start specified discovery methods 427 */ 428 /* ARGSUSED */ 429 boolean_t 430 iscsid_enable_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t idm, 431 boolean_t poke) 432 { 433 boolean_t rval = B_TRUE; 434 iscsid_thr_table *dt; 435 436 /* 437 * start the specified discovery method(s) 438 */ 439 for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown; 440 dt++) { 441 if (idm & dt->method) { 442 if (dt->thr_id != NULL) { 443 rval = iscsi_thread_start(dt->thr_id); 444 if (rval == B_FALSE) { 445 break; 446 } 447 if (poke == B_TRUE) { 448 (void) iscsi_thread_send_wakeup( 449 dt->thr_id); 450 } 451 } else { 452 /* 453 * unexpected condition. The threads for each 454 * discovery method should have started at 455 * initialization 456 */ 457 ASSERT(B_FALSE); 458 } 459 } 460 } /* END for() */ 461 462 return (rval); 463 } 464 465 466 /* 467 * iscsid_disable_discovery - stop specified discovery methods 468 */ 469 boolean_t 470 iscsid_disable_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t idm) 471 { 472 boolean_t rval = B_TRUE; 473 iscsid_thr_table *dt; 474 475 /* 476 * stop the specified discovery method(s) 477 */ 478 for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown; 479 dt++) { 480 if (idm & dt->method) { 481 482 /* signal discovery event change - begin */ 483 iscsi_discovery_event(ihp, dt->method, B_TRUE); 484 485 /* Attempt to logout of all associated targets */ 486 rval = iscsid_del(ihp, NULL, dt->method, NULL); 487 if (rval == B_TRUE) { 488 /* Successfully logged out of targets */ 489 if (dt->thr_id != NULL) { 490 rval = iscsi_thread_stop(dt->thr_id); 491 if (rval == B_FALSE) { 492 /* 493 * signal discovery 494 * event change - end 495 */ 496 iscsi_discovery_event(ihp, 497 dt->method, B_FALSE); 498 break; 499 } 500 501 } else { 502 /* 503 * unexpected condition. The threads 504 * for each discovery method should 505 * have started at initialization 506 */ 507 ASSERT(B_FALSE); 508 } 509 } 510 511 /* signal discovery event change - end */ 512 iscsi_discovery_event(ihp, dt->method, B_FALSE); 513 514 } 515 } /* END for() */ 516 517 return (rval); 518 } 519 520 /* 521 * iscsid_poke_discovery - wakeup discovery methods to find any new targets 522 * and wait for all discovery processes to complete. 523 */ 524 void 525 iscsid_poke_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method) 526 { 527 #define ISCSI_DISCOVERY_DELAY 1 528 529 iSCSIDiscoveryMethod_t dm; 530 iscsid_thr_table *dt; 531 boolean_t send_wakeup; 532 533 ASSERT(ihp != NULL); 534 535 /* reset discovery flags */ 536 mutex_enter(&ihp->hba_discovery_events_mutex); 537 ihp->hba_discovery_in_progress = B_TRUE; 538 ihp->hba_discovery_events = iSCSIDiscoveryMethodUnknown; 539 mutex_exit(&ihp->hba_discovery_events_mutex); 540 541 /* start all enabled discovery methods */ 542 dm = persistent_disc_meth_get(); 543 for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown; 544 dt++) { 545 send_wakeup = B_FALSE; 546 547 if ((method == iSCSIDiscoveryMethodUnknown) || 548 (method == dt->method)) { 549 if ((dm & dt->method) && (dt->thr_id != NULL)) { 550 if (iscsi_thread_send_wakeup(dt->thr_id) == 551 B_TRUE) { 552 send_wakeup = B_TRUE; 553 } 554 } 555 } 556 557 if (send_wakeup == B_FALSE) { 558 iscsi_discovery_event(ihp, dt->method, B_TRUE); 559 iscsi_discovery_event(ihp, dt->method, B_FALSE); 560 } 561 } 562 563 mutex_enter(&ihp->hba_discovery_events_mutex); 564 while (ihp->hba_discovery_events != ISCSI_ALL_DISCOVERY_METHODS) { 565 mutex_exit(&ihp->hba_discovery_events_mutex); 566 delay(SEC_TO_TICK(ISCSI_DISCOVERY_DELAY)); 567 mutex_enter(&ihp->hba_discovery_events_mutex); 568 } 569 ihp->hba_discovery_in_progress = B_FALSE; 570 mutex_exit(&ihp->hba_discovery_events_mutex); 571 572 } 573 574 /* 575 * iscsid_do_sendtgts - issue send targets command to the given discovery 576 * address and then add the discovered targets to the discovery queue 577 */ 578 void 579 iscsid_do_sendtgts(entry_t *disc_addr) 580 { 581 582 #define SENDTGTS_DEFAULT_NUM_TARGETS 10 583 584 int stl_sz; 585 int stl_num_tgts = SENDTGTS_DEFAULT_NUM_TARGETS; 586 iscsi_sendtgts_list_t *stl_hdr = NULL; 587 boolean_t retry = B_TRUE; 588 char inp_buf[INET6_ADDRSTRLEN]; 589 const char *ip; 590 int ctr; 591 int rc; 592 iscsi_hba_t *ihp; 593 iSCSIDiscoveryMethod_t dm = iSCSIDiscoveryMethodSendTargets; 594 595 /* allocate and initialize sendtargets list header */ 596 stl_sz = sizeof (*stl_hdr) + ((stl_num_tgts - 1) * 597 sizeof (iscsi_sendtgts_entry_t)); 598 stl_hdr = kmem_zalloc(stl_sz, KM_SLEEP); 599 600 retry_sendtgts: 601 stl_hdr->stl_in_cnt = stl_num_tgts; 602 bcopy(disc_addr, &(stl_hdr->stl_entry), 603 sizeof (stl_hdr->stl_entry)); 604 stl_hdr->stl_entry.e_vers = ISCSI_INTERFACE_VERSION; 605 606 /* lock interface so only one SendTargets operation occurs */ 607 if ((ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, 0)) == NULL) { 608 cmn_err(CE_NOTE, "!iscsi discovery failure - SendTargets. " 609 "failure to get soft state"); 610 kmem_free(stl_hdr, stl_sz); 611 return; 612 } 613 sema_p(&ihp->hba_sendtgts_semaphore); 614 rc = iscsi_ioctl_sendtgts_get(ihp, stl_hdr); 615 sema_v(&ihp->hba_sendtgts_semaphore); 616 if (rc) { 617 ip = inet_ntop((disc_addr->e_insize == 618 sizeof (struct in_addr) ? AF_INET : AF_INET6), 619 &disc_addr->e_u, inp_buf, sizeof (inp_buf)); 620 cmn_err(CE_NOTE, 621 "iscsi discovery failure - SendTargets (%s)\n", ip); 622 kmem_free(stl_hdr, stl_sz); 623 return; 624 } 625 626 /* check if all targets received */ 627 if (stl_hdr->stl_in_cnt < stl_hdr->stl_out_cnt) { 628 if (retry == B_TRUE) { 629 stl_num_tgts = stl_hdr->stl_out_cnt; 630 kmem_free(stl_hdr, stl_sz); 631 stl_sz = sizeof (*stl_hdr) + 632 ((stl_num_tgts - 1) * 633 sizeof (iscsi_sendtgts_entry_t)); 634 stl_hdr = kmem_zalloc(stl_sz, KM_SLEEP); 635 retry = B_FALSE; 636 goto retry_sendtgts; 637 } else { 638 ip = inet_ntop((disc_addr->e_insize == 639 sizeof (struct in_addr) ? 640 AF_INET : AF_INET6), &disc_addr->e_u, 641 inp_buf, sizeof (inp_buf)); 642 cmn_err(CE_NOTE, "iscsi discovery failure - " 643 "SendTargets overflow (%s)\n", ip); 644 kmem_free(stl_hdr, stl_sz); 645 return; 646 } 647 } 648 649 for (ctr = 0; ctr < stl_hdr->stl_out_cnt; ctr++) { 650 iscsi_sockaddr_t addr_dsc; 651 iscsi_sockaddr_t addr_tgt; 652 653 iscsid_addr_to_sockaddr(disc_addr->e_insize, 654 &disc_addr->e_u, disc_addr->e_port, &addr_dsc.sin); 655 iscsid_addr_to_sockaddr( 656 stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize, 657 &(stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_addr), 658 stl_hdr->stl_list[ctr].ste_ipaddr.a_port, 659 &addr_tgt.sin); 660 if (disc_addr->e_boot == B_TRUE) { 661 dm = dm | iSCSIDiscoveryMethodBoot; 662 } 663 (void) iscsid_add(ihp, dm, 664 &addr_dsc.sin, (char *)stl_hdr->stl_list[ctr].ste_name, 665 stl_hdr->stl_list[ctr].ste_tpgt, 666 &addr_tgt.sin); 667 } 668 kmem_free(stl_hdr, stl_sz); 669 } 670 671 void 672 iscsid_do_isns_query_one_server(iscsi_hba_t *ihp, entry_t *isns_server) 673 { 674 int pg_sz, query_status; 675 iscsi_addr_t *ap; 676 isns_portal_group_list_t *pg_list; 677 678 ap = (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP); 679 ap->a_port = isns_server->e_port; 680 ap->a_addr.i_insize = isns_server->e_insize; 681 682 if (isns_server->e_insize == sizeof (struct in_addr)) { 683 ap->a_addr.i_addr.in4.s_addr = (isns_server->e_u.u_in4.s_addr); 684 } else if (isns_server->e_insize == sizeof (struct in6_addr)) { 685 bcopy(&(isns_server->e_u.u_in6.s6_addr), 686 ap->a_addr.i_addr.in6.s6_addr, 16); 687 } else { 688 kmem_free(ap, sizeof (iscsi_addr_t)); 689 return; 690 } 691 692 pg_list = NULL; 693 query_status = isns_query_one_server( 694 ap, ihp->hba_isid, 695 ihp->hba_name, ihp->hba_alias, 696 ISNS_INITIATOR_NODE_TYPE, &pg_list); 697 kmem_free(ap, sizeof (iscsi_addr_t)); 698 if (query_status != isns_ok || pg_list == NULL) { 699 DTRACE_PROBE1(iscsid_do_isns_query_one_server_status, 700 int, query_status); 701 return; 702 } 703 704 iscsid_add_pg_list_to_cache(ihp, pg_list); 705 pg_sz = sizeof (isns_portal_group_list_t); 706 if (pg_list->pg_out_cnt > 0) { 707 pg_sz += (pg_list->pg_out_cnt - 1) * 708 sizeof (isns_portal_group_t); 709 } 710 kmem_free(pg_list, pg_sz); 711 } 712 713 void 714 iscsid_do_isns_query(iscsi_hba_t *ihp) 715 { 716 int pg_sz, query_status; 717 isns_portal_group_list_t *pg_list; 718 719 pg_list = NULL; 720 query_status = isns_query(ihp->hba_isid, 721 ihp->hba_name, 722 ihp->hba_alias, 723 ISNS_INITIATOR_NODE_TYPE, 724 &pg_list); 725 726 if (pg_list == NULL) { 727 DTRACE_PROBE1(iscsid_do_isns_query_status, 728 int, query_status); 729 return; 730 } 731 732 if ((query_status != isns_ok && 733 query_status != isns_op_partially_failed)) { 734 DTRACE_PROBE1(iscsid_do_isns_query_status, 735 int, query_status); 736 pg_sz = sizeof (isns_portal_group_list_t); 737 if (pg_list->pg_out_cnt > 0) { 738 pg_sz += (pg_list->pg_out_cnt - 1) * 739 sizeof (isns_portal_group_t); 740 } 741 kmem_free(pg_list, pg_sz); 742 return; 743 } 744 745 iscsid_add_pg_list_to_cache(ihp, pg_list); 746 747 pg_sz = sizeof (isns_portal_group_list_t); 748 if (pg_list->pg_out_cnt > 0) { 749 pg_sz += (pg_list->pg_out_cnt - 1) * 750 sizeof (isns_portal_group_t); 751 } 752 kmem_free(pg_list, pg_sz); 753 } 754 755 /* 756 * iscsid_config_one - for the given target name, attempt 757 * to login to all targets associated with name. If target 758 * name is not found in discovery queue, reset the discovery 759 * queue, kick the discovery processes, and then retry. 760 * 761 * NOTE: The caller of this function must hold the 762 * iscsid_config_semaphore across this call. 763 */ 764 void 765 iscsid_config_one(iscsi_hba_t *ihp, char *name, boolean_t protect) 766 { 767 boolean_t rc = B_FALSE; 768 int retry = 0; 769 int lun_online = 0; 770 int cur_sec = 0; 771 772 if (!modrootloaded && (iscsiboot_prop != NULL)) { 773 if (!iscsi_configroot_printed) { 774 cmn_err(CE_NOTE, "Configuring" 775 " iSCSI boot session..."); 776 iscsi_configroot_printed = B_TRUE; 777 } 778 if (iscsi_net_up == 0) { 779 if (iscsi_net_interface(B_FALSE) == 780 ISCSI_STATUS_SUCCESS) { 781 iscsi_net_up = 1; 782 } else { 783 cmn_err(CE_WARN, "Failed to configure interface" 784 " for iSCSI boot session"); 785 return; 786 } 787 } 788 while (rc == B_FALSE && retry < 789 iscsi_configroot_retry) { 790 rc = iscsid_login_tgt(ihp, name, 791 iSCSIDiscoveryMethodBoot, NULL); 792 if (rc == B_FALSE) { 793 /* 794 * create boot session 795 */ 796 iscsi_boot_session_create(ihp, 797 iscsiboot_prop); 798 retry++; 799 continue; 800 } 801 rc = iscsid_check_active_boot_conn(ihp); 802 if (rc == B_FALSE) { 803 /* 804 * no active connection for the boot 805 * session, retry the login until 806 * one is found or the retry count 807 * is exceeded 808 */ 809 delay(SEC_TO_TICK(ISCSI_CONFIGROOT_DELAY)); 810 retry++; 811 continue; 812 } 813 /* 814 * The boot session has been created with active 815 * connection. If the target lun has not been online, 816 * we should wait here for a while 817 */ 818 do { 819 lun_online = 820 iscsiboot_prop->boot_tgt.lun_online; 821 if (lun_online == 0) { 822 delay(SEC_TO_TICK( 823 ISCSI_CONFIGROOT_DELAY)); 824 cur_sec++; 825 } 826 } while ((lun_online == 0) && 827 (cur_sec < iscsi_boot_max_delay)); 828 retry++; 829 } 830 if (!rc) { 831 cmn_err(CE_WARN, "Failed to configure iSCSI" 832 " boot session"); 833 } 834 } else { 835 rc = iscsid_login_tgt(ihp, name, iSCSIDiscoveryMethodUnknown, 836 NULL); 837 /* 838 * If we didn't login to the device we might have 839 * to update our discovery information and attempt 840 * the login again. 841 */ 842 if (rc == B_FALSE) { 843 /* 844 * Stale /dev links can cause us to get floods 845 * of config requests. Prevent these repeated 846 * requests from causing unneeded discovery updates 847 * if ISCSI_CONFIG_STORM_PROTECT is set. 848 */ 849 if ((protect == B_FALSE) || 850 (ddi_get_lbolt() > ihp->hba_config_lbolt + 851 SEC_TO_TICK(ihp->hba_config_storm_delay))) { 852 ihp->hba_config_lbolt = ddi_get_lbolt(); 853 iscsid_poke_discovery(ihp, 854 iSCSIDiscoveryMethodUnknown); 855 (void) iscsid_login_tgt(ihp, name, 856 iSCSIDiscoveryMethodUnknown, NULL); 857 } 858 } 859 } 860 } 861 862 /* 863 * iscsid_config_all - reset the discovery queue, kick the 864 * discovery processes, and login to all targets found 865 * 866 * NOTE: The caller of this function must hold the 867 * iscsid_config_semaphore across this call. 868 */ 869 void 870 iscsid_config_all(iscsi_hba_t *ihp, boolean_t protect) 871 { 872 boolean_t rc = B_FALSE; 873 int retry = 0; 874 int lun_online = 0; 875 int cur_sec = 0; 876 877 if (!modrootloaded && iscsiboot_prop != NULL) { 878 if (!iscsi_configroot_printed) { 879 cmn_err(CE_NOTE, "Configuring" 880 " iSCSI boot session..."); 881 iscsi_configroot_printed = B_TRUE; 882 } 883 if (iscsi_net_up == 0) { 884 if (iscsi_net_interface(B_FALSE) == 885 ISCSI_STATUS_SUCCESS) { 886 iscsi_net_up = 1; 887 } 888 } 889 while (rc == B_FALSE && retry < 890 iscsi_configroot_retry) { 891 rc = iscsid_login_tgt(ihp, NULL, 892 iSCSIDiscoveryMethodBoot, NULL); 893 if (rc == B_FALSE) { 894 /* 895 * No boot session has been created. 896 * We would like to create the boot 897 * Session first. 898 */ 899 iscsi_boot_session_create(ihp, 900 iscsiboot_prop); 901 retry++; 902 continue; 903 } 904 rc = iscsid_check_active_boot_conn(ihp); 905 if (rc == B_FALSE) { 906 /* 907 * no active connection for the boot 908 * session, retry the login until 909 * one is found or the retry count 910 * is exceeded 911 */ 912 delay(SEC_TO_TICK(ISCSI_CONFIGROOT_DELAY)); 913 retry++; 914 continue; 915 } 916 /* 917 * The boot session has been created with active 918 * connection. If the target lun has not been online, 919 * we should wait here for a while 920 */ 921 do { 922 lun_online = 923 iscsiboot_prop->boot_tgt.lun_online; 924 if (lun_online == 0) { 925 delay(SEC_TO_TICK( 926 ISCSI_CONFIGROOT_DELAY)); 927 cur_sec++; 928 } 929 } while ((lun_online == 0) && 930 (cur_sec < iscsi_boot_max_delay)); 931 retry++; 932 } 933 if (!rc) { 934 cmn_err(CE_WARN, "Failed to configure" 935 " boot session"); 936 } 937 } else { 938 /* 939 * Stale /dev links can cause us to get floods 940 * of config requests. Prevent these repeated 941 * requests from causing unneeded discovery updates 942 * if ISCSI_CONFIG_STORM_PROTECT is set. 943 */ 944 if ((protect == B_FALSE) || 945 (ddi_get_lbolt() > ihp->hba_config_lbolt + 946 SEC_TO_TICK(ihp->hba_config_storm_delay))) { 947 ihp->hba_config_lbolt = ddi_get_lbolt(); 948 iscsid_poke_discovery(ihp, 949 iSCSIDiscoveryMethodUnknown); 950 } 951 (void) iscsid_login_tgt(ihp, NULL, 952 iSCSIDiscoveryMethodUnknown, NULL); 953 } 954 } 955 956 /* 957 * isns_scn_callback - iSNS client received an SCN 958 * 959 * This code processes the iSNS client SCN events. These 960 * could relate to the addition, removal, or update of a 961 * logical unit. 962 */ 963 void 964 isns_scn_callback(void *arg) 965 { 966 int i, pg_sz; 967 int qry_status; 968 isns_portal_group_list_t *pg_list; 969 uint32_t scn_type; 970 iscsi_hba_t *ihp; 971 972 if (arg == NULL) { 973 /* No argument */ 974 return; 975 } 976 977 if ((ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, 0)) == NULL) { 978 kmem_free(arg, sizeof (isns_scn_callback_arg_t)); 979 return; 980 } 981 982 /* 983 * All isns callbacks are from a standalone taskq 984 * therefore the blocking here doesn't affect the enable/disable 985 * of isns discovery method 986 */ 987 if (iscsi_client_request_service(ihp) == B_FALSE) { 988 kmem_free(arg, sizeof (isns_scn_callback_arg_t)); 989 return; 990 } 991 992 scn_type = ((isns_scn_callback_arg_t *)arg)->scn_type; 993 DTRACE_PROBE1(isns_scn_callback_scn_type, int, scn_type); 994 switch (scn_type) { 995 /* 996 * ISNS_OBJ_ADDED - An object has been added. 997 */ 998 case ISNS_OBJ_ADDED: 999 /* Query iSNS server for contact information */ 1000 pg_list = NULL; 1001 qry_status = isns_query_one_node( 1002 ((isns_scn_callback_arg_t *)arg)->source_key_attr, 1003 ihp->hba_isid, 1004 ihp->hba_name, 1005 (uint8_t *)"", 1006 ISNS_INITIATOR_NODE_TYPE, 1007 &pg_list); 1008 1009 /* Verify portal group is found */ 1010 if ((qry_status != isns_ok && 1011 qry_status != isns_op_partially_failed) || 1012 pg_list == NULL) { 1013 break; 1014 } 1015 1016 DTRACE_PROBE1(pg_list, 1017 isns_portal_group_list_t *, pg_list); 1018 1019 /* Add all portals for logical unit to discovery cache */ 1020 for (i = 0; i < pg_list->pg_out_cnt; i++) { 1021 iscsi_sockaddr_t addr_dsc; 1022 iscsi_sockaddr_t addr_tgt; 1023 1024 iscsid_addr_to_sockaddr( 1025 pg_list->pg_list[i].isns_server_ip.i_insize, 1026 &pg_list->pg_list[i].isns_server_ip.i_addr, 1027 pg_list->pg_list[i].isns_server_port, 1028 &addr_dsc.sin); 1029 iscsid_addr_to_sockaddr(pg_list->pg_list[i].insize, 1030 &pg_list->pg_list[i].pg_ip_addr, 1031 pg_list->pg_list[i].pg_port, &addr_tgt.sin); 1032 1033 (void) iscsid_add(ihp, iSCSIDiscoveryMethodISNS, 1034 &addr_dsc.sin, (char *)pg_list->pg_list[i]. 1035 pg_iscsi_name, pg_list->pg_list[i].pg_tag, 1036 &addr_tgt.sin); 1037 1038 /* Force target to login */ 1039 (void) iscsid_login_tgt(ihp, (char *)pg_list-> 1040 pg_list[i].pg_iscsi_name, iSCSIDiscoveryMethodISNS, 1041 NULL); 1042 } 1043 1044 if (pg_list != NULL) { 1045 pg_sz = sizeof (isns_portal_group_list_t); 1046 if (pg_list->pg_out_cnt > 0) { 1047 pg_sz += (pg_list->pg_out_cnt - 1) * 1048 sizeof (isns_portal_group_t); 1049 } 1050 kmem_free(pg_list, pg_sz); 1051 } 1052 break; 1053 1054 /* 1055 * ISNS_OBJ_REMOVED - logical unit has been removed 1056 */ 1057 case ISNS_OBJ_REMOVED: 1058 if (iscsid_del(ihp, 1059 (char *)((isns_scn_callback_arg_t *)arg)-> 1060 source_key_attr, iSCSIDiscoveryMethodISNS, NULL) != 1061 B_TRUE) { 1062 cmn_err(CE_NOTE, "iscsi initiator - " 1063 "isns remove scn failed for target %s\n", 1064 (char *)((isns_scn_callback_arg_t *)arg)-> 1065 source_key_attr); 1066 1067 } 1068 break; 1069 1070 /* 1071 * ISNS_OBJ_UPDATED - logical unit has changed 1072 */ 1073 case ISNS_OBJ_UPDATED: 1074 cmn_err(CE_NOTE, "iscsi initiator - " 1075 "received iSNS update SCN for %s\n", 1076 (char *)((isns_scn_callback_arg_t *)arg)-> 1077 source_key_attr); 1078 break; 1079 1080 /* 1081 * ISNS_OBJ_UNKNOWN - 1082 */ 1083 default: 1084 cmn_err(CE_NOTE, "iscsi initiator - " 1085 "received unknown iSNS SCN type 0x%x\n", scn_type); 1086 break; 1087 } 1088 1089 iscsi_client_release_service(ihp); 1090 kmem_free(arg, sizeof (isns_scn_callback_arg_t)); 1091 } 1092 1093 1094 /* 1095 * iscsid_add - Creates discovered session and connection 1096 */ 1097 static boolean_t 1098 iscsid_add(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method, 1099 struct sockaddr *addr_dsc, char *target_name, int tpgt, 1100 struct sockaddr *addr_tgt) 1101 { 1102 boolean_t rtn = B_TRUE; 1103 iscsi_sess_t *isp; 1104 iscsi_conn_t *icp; 1105 uint_t oid; 1106 int idx; 1107 int isid; 1108 iscsi_config_sess_t *ics; 1109 int size; 1110 char *tmp; 1111 1112 ASSERT(ihp != NULL); 1113 ASSERT(addr_dsc != NULL); 1114 ASSERT(target_name != NULL); 1115 ASSERT(addr_tgt != NULL); 1116 1117 /* setup initial buffer for configured session information */ 1118 size = sizeof (*ics); 1119 ics = kmem_zalloc(size, KM_SLEEP); 1120 ics->ics_in = 1; 1121 1122 /* get configured sessions information */ 1123 tmp = target_name; 1124 if (persistent_get_config_session(tmp, ics) == B_FALSE) { 1125 /* 1126 * No target information available check for 1127 * initiator information. 1128 */ 1129 tmp = (char *)ihp->hba_name; 1130 if (persistent_get_config_session(tmp, ics) == B_FALSE) { 1131 /* 1132 * No hba information is 1133 * found. So assume default 1134 * one session unbound behavior. 1135 */ 1136 ics->ics_out = 1; 1137 ics->ics_bound = B_TRUE; 1138 } 1139 } 1140 1141 if (iscsiboot_prop && (ics->ics_out > 1) && 1142 !iscsi_chk_bootlun_mpxio(ihp)) { 1143 /* 1144 * iscsi boot with mpxio disabled 1145 * no need to search configured boot session 1146 */ 1147 1148 if (iscsi_cmp_boot_ini_name(tmp) || 1149 iscsi_cmp_boot_tgt_name(tmp)) { 1150 ics->ics_out = 1; 1151 ics->ics_bound = B_FALSE; 1152 } 1153 } 1154 /* Check to see if we need to get more information */ 1155 if (ics->ics_out > 1) { 1156 /* record new size and free last buffer */ 1157 idx = ics->ics_out; 1158 size = ISCSI_SESSION_CONFIG_SIZE(ics->ics_out); 1159 kmem_free(ics, sizeof (*ics)); 1160 1161 /* allocate new buffer */ 1162 ics = kmem_zalloc(size, KM_SLEEP); 1163 ics->ics_in = idx; 1164 1165 /* get configured sessions information */ 1166 if (persistent_get_config_session(tmp, ics) != B_TRUE) { 1167 cmn_err(CE_NOTE, "iscsi session(%s) - " 1168 "unable to get configured session information\n", 1169 target_name); 1170 kmem_free(ics, size); 1171 return (B_FALSE); 1172 } 1173 } 1174 1175 /* loop for all configured sessions */ 1176 rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); 1177 for (isid = 0; isid < ics->ics_out; isid++) { 1178 /* create or find matching session */ 1179 isp = iscsi_sess_create(ihp, method, addr_dsc, target_name, 1180 tpgt, isid, ISCSI_SESS_TYPE_NORMAL, &oid); 1181 if (isp == NULL) { 1182 rtn = B_FALSE; 1183 break; 1184 } 1185 1186 /* create or find matching connection */ 1187 if (!ISCSI_SUCCESS(iscsi_conn_create(addr_tgt, isp, &icp))) { 1188 /* 1189 * Teardown the session we just created. It can't 1190 * have any luns or connections associated with it 1191 * so this should always succeed (luckily since what 1192 * would we do if it failed?) 1193 */ 1194 (void) iscsi_sess_destroy(isp); 1195 rtn = B_FALSE; 1196 break; 1197 } 1198 } 1199 rw_exit(&ihp->hba_sess_list_rwlock); 1200 kmem_free(ics, size); 1201 return (rtn); 1202 } 1203 1204 /* 1205 * iscsid_del - Attempts to delete all associated sessions 1206 */ 1207 boolean_t 1208 iscsid_del(iscsi_hba_t *ihp, char *target_name, 1209 iSCSIDiscoveryMethod_t method, struct sockaddr *addr_dsc) 1210 { 1211 boolean_t rtn = B_TRUE; 1212 iscsi_status_t status; 1213 iscsi_sess_t *isp; 1214 char name[ISCSI_MAX_NAME_LEN]; 1215 1216 ASSERT(ihp != NULL); 1217 /* target name can be NULL or !NULL */ 1218 /* addr_dsc can be NULL or !NULL */ 1219 1220 rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); 1221 isp = ihp->hba_sess_list; 1222 while (isp != NULL) { 1223 /* 1224 * If no target_name is listed (meaning all targets) 1225 * or this specific target was listed. And the same 1226 * discovery method discovered this target then 1227 * continue evaulation. Otherwise fail. 1228 */ 1229 if (((target_name == NULL) || 1230 (strcmp((char *)isp->sess_name, target_name) == 0)) && 1231 (isp->sess_discovered_by == method)) { 1232 boolean_t try_destroy; 1233 1234 /* 1235 * If iSNS, SendTargets, or Static then special 1236 * handling for disc_addr. 1237 */ 1238 if ((method == iSCSIDiscoveryMethodISNS) || 1239 (method == iSCSIDiscoveryMethodSendTargets)) { 1240 /* 1241 * If NULL addr_dsc (meaning all disc_addr) 1242 * or matching discovered addr. 1243 */ 1244 if ((addr_dsc == NULL) || 1245 (bcmp(addr_dsc, &isp->sess_discovered_addr, 1246 SIZEOF_SOCKADDR( 1247 &isp->sess_discovered_addr.sin)) == 0)) { 1248 try_destroy = B_TRUE; 1249 } else { 1250 try_destroy = B_FALSE; 1251 } 1252 } else if (method == iSCSIDiscoveryMethodStatic) { 1253 /* 1254 * If NULL addr_dsc (meaning all disc_addr) 1255 * or matching active connection. 1256 */ 1257 if ((addr_dsc == NULL) || 1258 ((isp->sess_conn_act != NULL) && 1259 (bcmp(addr_dsc, 1260 &isp->sess_conn_act->conn_base_addr.sin, 1261 SIZEOF_SOCKADDR( 1262 &isp->sess_conn_act->conn_base_addr.sin)) 1263 == 0))) { 1264 try_destroy = B_TRUE; 1265 } else { 1266 try_destroy = B_FALSE; 1267 } 1268 } else { 1269 /* Unknown discovery specified */ 1270 try_destroy = B_TRUE; 1271 } 1272 1273 if (try_destroy == B_TRUE && 1274 isp->sess_boot == B_FALSE) { 1275 (void) strcpy(name, (char *)isp->sess_name); 1276 status = iscsi_sess_destroy(isp); 1277 if (ISCSI_SUCCESS(status)) { 1278 iscsid_remove_target_param(name); 1279 isp = ihp->hba_sess_list; 1280 } else { 1281 /* 1282 * The most likely destroy failure 1283 * is that ndi/mdi offline failed. 1284 * This means that the resource is 1285 * in_use/busy. 1286 */ 1287 cmn_err(CE_NOTE, "iscsi session(%d) - " 1288 "session logout failed (%d)\n", 1289 isp->sess_oid, status); 1290 isp = isp->sess_next; 1291 rtn = B_FALSE; 1292 } 1293 } else { 1294 isp = isp->sess_next; 1295 } 1296 } else { 1297 isp = isp->sess_next; 1298 } 1299 } 1300 rw_exit(&ihp->hba_sess_list_rwlock); 1301 return (rtn); 1302 } 1303 1304 1305 /* 1306 * iscsid_login_tgt - request target(s) to login 1307 */ 1308 boolean_t 1309 iscsid_login_tgt(iscsi_hba_t *ihp, char *target_name, 1310 iSCSIDiscoveryMethod_t method, struct sockaddr *addr_dsc) 1311 { 1312 boolean_t rtn = B_FALSE; 1313 iscsi_sess_t *isp = NULL; 1314 iscsi_sess_list_t *isp_list = NULL; 1315 iscsi_sess_list_t *last_sess = NULL; 1316 iscsi_sess_list_t *cur_sess = NULL; 1317 int total = 0; 1318 ddi_taskq_t *login_taskq = NULL; 1319 char taskq_name[ISCSI_TH_MAX_NAME_LEN] = {0}; 1320 time_t time_stamp; 1321 1322 ASSERT(ihp != NULL); 1323 1324 rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); 1325 /* Loop thru sessions */ 1326 isp = ihp->hba_sess_list; 1327 while (isp != NULL) { 1328 boolean_t try_online; 1329 if (!(method & iSCSIDiscoveryMethodBoot)) { 1330 if (target_name == NULL) { 1331 if (method == iSCSIDiscoveryMethodUnknown) { 1332 /* unknown method mean login to all */ 1333 try_online = B_TRUE; 1334 } else if (isp->sess_discovered_by & method) { 1335 if ((method == 1336 iSCSIDiscoveryMethodISNS) || 1337 (method == 1338 iSCSIDiscoveryMethodSendTargets)) { 1339 #define SESS_DISC_ADDR isp->sess_discovered_addr.sin 1340 if ((addr_dsc == NULL) || 1341 (bcmp( 1342 &isp->sess_discovered_addr, 1343 addr_dsc, SIZEOF_SOCKADDR( 1344 &SESS_DISC_ADDR)) 1345 == 0)) { 1346 /* 1347 * iSNS or sendtarget 1348 * discovery and 1349 * discovery address 1350 * is NULL or match 1351 */ 1352 try_online = B_TRUE; 1353 } else { 1354 /* addr_dsc not a match */ 1355 try_online = B_FALSE; 1356 } 1357 #undef SESS_DISC_ADDR 1358 } else { 1359 /* static configuration */ 1360 try_online = B_TRUE; 1361 } 1362 } else { 1363 /* method not a match */ 1364 try_online = B_FALSE; 1365 } 1366 } else if (strcmp(target_name, 1367 (char *)isp->sess_name) == 0) { 1368 /* target_name match */ 1369 try_online = B_TRUE; 1370 } else { 1371 /* target_name not a match */ 1372 try_online = B_FALSE; 1373 } 1374 } else { 1375 /* 1376 * online the boot session. 1377 */ 1378 if (isp->sess_boot == B_TRUE) { 1379 try_online = B_TRUE; 1380 } 1381 } 1382 1383 if (try_online == B_TRUE && 1384 isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { 1385 total++; 1386 /* Copy these sessions to the list. */ 1387 if (isp_list == NULL) { 1388 isp_list = 1389 (iscsi_sess_list_t *)kmem_zalloc( 1390 sizeof (iscsi_sess_list_t), KM_SLEEP); 1391 last_sess = isp_list; 1392 last_sess->session = isp; 1393 last_sess->next = NULL; 1394 } else { 1395 last_sess->next = 1396 (iscsi_sess_list_t *)kmem_zalloc( 1397 sizeof (iscsi_sess_list_t), KM_SLEEP); 1398 last_sess->next->session = isp; 1399 last_sess->next->next = NULL; 1400 last_sess = last_sess->next; 1401 } 1402 rtn = B_TRUE; 1403 } 1404 1405 isp = isp->sess_next; 1406 } 1407 1408 if (total > 0) { 1409 time_stamp = ddi_get_time(); 1410 (void) snprintf(taskq_name, (ISCSI_TH_MAX_NAME_LEN - 1), 1411 "login_queue.%lx", time_stamp); 1412 1413 login_taskq = ddi_taskq_create(ihp->hba_dip, 1414 taskq_name, total, TASKQ_DEFAULTPRI, 0); 1415 if (login_taskq == NULL) { 1416 while (isp_list != NULL) { 1417 cur_sess = isp_list; 1418 isp_list = isp_list->next; 1419 kmem_free(cur_sess, sizeof (iscsi_sess_list_t)); 1420 } 1421 rtn = B_FALSE; 1422 rw_exit(&ihp->hba_sess_list_rwlock); 1423 return (rtn); 1424 } 1425 1426 for (cur_sess = isp_list; cur_sess != NULL; 1427 cur_sess = cur_sess->next) { 1428 if (ddi_taskq_dispatch(login_taskq, 1429 iscsi_sess_online, (void *)cur_sess->session, 1430 DDI_SLEEP) != DDI_SUCCESS) { 1431 cmn_err(CE_NOTE, "Can't dispatch the task " 1432 "for login to the target: %s", 1433 cur_sess->session->sess_name); 1434 } 1435 } 1436 1437 ddi_taskq_wait(login_taskq); 1438 ddi_taskq_destroy(login_taskq); 1439 while (isp_list != NULL) { 1440 cur_sess = isp_list; 1441 isp_list = isp_list->next; 1442 kmem_free(cur_sess, sizeof (iscsi_sess_list_t)); 1443 } 1444 1445 } 1446 1447 rw_exit(&ihp->hba_sess_list_rwlock); 1448 return (rtn); 1449 } 1450 1451 /* 1452 * +--------------------------------------------------------------------+ 1453 * | Local Helper Functions | 1454 * +--------------------------------------------------------------------+ 1455 */ 1456 1457 /* 1458 * iscsid_init_config -- initialize configuration parameters of iSCSI initiator 1459 */ 1460 static boolean_t 1461 iscsid_init_config(iscsi_hba_t *ihp) 1462 { 1463 iscsi_param_set_t ips; 1464 void *v = NULL; 1465 char *name; 1466 char *initiatorName; 1467 persistent_param_t pp; 1468 persistent_tunable_param_t pparam; 1469 uint32_t param_id; 1470 int rc; 1471 1472 /* allocate memory to hold initiator names */ 1473 initiatorName = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 1474 1475 /* 1476 * initialize iSCSI initiator name 1477 */ 1478 bzero(&ips, sizeof (ips)); 1479 if (persistent_initiator_name_get(initiatorName, 1480 ISCSI_MAX_NAME_LEN) == B_TRUE) { 1481 ips.s_vers = ISCSI_INTERFACE_VERSION; 1482 ips.s_param = ISCSI_LOGIN_PARAM_INITIATOR_NAME; 1483 1484 if (iscsiboot_prop && !iscsi_cmp_boot_ini_name(initiatorName)) { 1485 (void) strncpy(initiatorName, 1486 (const char *)iscsiboot_prop->boot_init.ini_name, 1487 ISCSI_MAX_NAME_LEN); 1488 (void) strncpy((char *)ips.s_value.v_name, 1489 (const char *)iscsiboot_prop->boot_init.ini_name, 1490 sizeof (ips.s_value.v_name)); 1491 (void) iscsi_set_params(&ips, ihp, B_TRUE); 1492 /* use default tunable value */ 1493 ihp->hba_tunable_params.recv_login_rsp_timeout = 1494 ISCSI_DEFAULT_RX_TIMEOUT_VALUE; 1495 ihp->hba_tunable_params.polling_login_delay = 1496 ISCSI_DEFAULT_LOGIN_POLLING_DELAY; 1497 ihp->hba_tunable_params.conn_login_max = 1498 ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX; 1499 cmn_err(CE_NOTE, "Set initiator's name" 1500 " from firmware"); 1501 } else { 1502 (void) strncpy((char *)ips.s_value.v_name, 1503 initiatorName, sizeof (ips.s_value.v_name)); 1504 1505 (void) iscsi_set_params(&ips, ihp, B_FALSE); 1506 if (persistent_get_tunable_param(initiatorName, 1507 &pparam) == B_FALSE) { 1508 /* use default value */ 1509 pparam.p_params.recv_login_rsp_timeout = 1510 ISCSI_DEFAULT_RX_TIMEOUT_VALUE; 1511 pparam.p_params.polling_login_delay = 1512 ISCSI_DEFAULT_LOGIN_POLLING_DELAY; 1513 pparam.p_params.conn_login_max = 1514 ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX; 1515 } 1516 bcopy(&pparam.p_params, &ihp->hba_tunable_params, 1517 sizeof (iscsi_tunable_params_t)); 1518 } 1519 } else { 1520 /* 1521 * if no initiator-node name available it is most 1522 * likely due to a fresh install, or the persistent 1523 * store is not working correctly. Set 1524 * a default initiator name so that the initiator can 1525 * be brought up properly. 1526 */ 1527 iscsid_set_default_initiator_node_settings(ihp, B_FALSE); 1528 (void) strncpy(initiatorName, (const char *)ihp->hba_name, 1529 ISCSI_MAX_NAME_LEN); 1530 } 1531 1532 /* 1533 * initialize iSCSI initiator alias (if any) 1534 */ 1535 bzero(&ips, sizeof (ips)); 1536 if (persistent_alias_name_get((char *)ips.s_value.v_name, 1537 sizeof (ips.s_value.v_name)) == B_TRUE) { 1538 ips.s_param = ISCSI_LOGIN_PARAM_INITIATOR_ALIAS; 1539 (void) iscsi_set_params(&ips, ihp, B_FALSE); 1540 } else { 1541 /* EMPTY */ 1542 /* No alias defined - not a problem. */ 1543 } 1544 1545 /* 1546 * load up the overriden iSCSI initiator parameters 1547 */ 1548 name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 1549 persistent_param_lock(); 1550 v = NULL; 1551 while (persistent_param_next(&v, name, &pp) == B_TRUE) { 1552 if (strncmp(name, initiatorName, ISCSI_MAX_NAME_LEN) == 0) { 1553 ips.s_oid = ihp->hba_oid; 1554 ips.s_vers = ISCSI_INTERFACE_VERSION; 1555 for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM; 1556 param_id++) { 1557 if (pp.p_bitmap & (1 << param_id)) { 1558 rc = iscsid_copyto_param_set(param_id, 1559 &pp.p_params, &ips); 1560 if (rc == 0) { 1561 rc = iscsi_set_params(&ips, 1562 ihp, B_FALSE); 1563 } 1564 if (rc != 0) { 1565 /* note error but continue */ 1566 cmn_err(CE_NOTE, 1567 "Failed to set " 1568 "param %d for OID %d", 1569 ips.s_param, ips.s_oid); 1570 } 1571 } 1572 } /* END for() */ 1573 if (iscsiboot_prop && 1574 iscsi_chk_bootlun_mpxio(ihp)) { 1575 (void) iscsi_reconfig_boot_sess(ihp); 1576 } 1577 break; 1578 } 1579 } /* END while() */ 1580 persistent_param_unlock(); 1581 1582 kmem_free(initiatorName, ISCSI_MAX_NAME_LEN); 1583 kmem_free(name, ISCSI_MAX_NAME_LEN); 1584 return (B_TRUE); 1585 } 1586 1587 1588 /* 1589 * iscsid_init_targets -- Load up the driver with known static targets and 1590 * targets whose parameters have been modified. 1591 * 1592 * This is done so that the CLI can find a list of targets the driver 1593 * currently knows about. 1594 * 1595 * The driver doesn't need to log into these targets. Log in is done based 1596 * upon the enabled discovery methods. 1597 */ 1598 static boolean_t 1599 iscsid_init_targets(iscsi_hba_t *ihp) 1600 { 1601 void *v = NULL; 1602 char *name; 1603 iscsi_param_set_t ips; 1604 persistent_param_t pp; 1605 char *iname; 1606 uint32_t param_id; 1607 int rc; 1608 1609 ASSERT(ihp != NULL); 1610 1611 /* allocate memory to hold target names */ 1612 name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 1613 1614 /* 1615 * load up targets whose parameters have been overriden 1616 */ 1617 1618 /* ---- only need to be set once ---- */ 1619 bzero(&ips, sizeof (ips)); 1620 ips.s_vers = ISCSI_INTERFACE_VERSION; 1621 1622 /* allocate memory to hold initiator name */ 1623 iname = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 1624 (void) persistent_initiator_name_get(iname, ISCSI_MAX_NAME_LEN); 1625 1626 persistent_param_lock(); 1627 v = NULL; 1628 while (persistent_param_next(&v, name, &pp) == B_TRUE) { 1629 1630 if (strncmp(iname, name, ISCSI_MAX_NAME_LEN) == 0) { 1631 /* 1632 * target name matched initiator's name so, 1633 * continue to next target. Initiator's 1634 * parmeters have already been set. 1635 */ 1636 continue; 1637 } 1638 1639 if (iscsiboot_prop && iscsi_cmp_boot_tgt_name(name) && 1640 !iscsi_chk_bootlun_mpxio(ihp)) { 1641 /* 1642 * boot target is not mpxio enabled 1643 * simply ignore these overriden parameters 1644 */ 1645 continue; 1646 } 1647 1648 ips.s_oid = iscsi_targetparam_get_oid((unsigned char *)name); 1649 1650 for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM; 1651 param_id++) { 1652 if (pp.p_bitmap & (1 << param_id)) { 1653 rc = iscsid_copyto_param_set(param_id, 1654 &pp.p_params, &ips); 1655 if (rc == 0) { 1656 rc = iscsi_set_params(&ips, 1657 ihp, B_FALSE); 1658 } 1659 if (rc != 0) { 1660 /* note error but continue ---- */ 1661 cmn_err(CE_NOTE, "Failed to set " 1662 "param %d for OID %d", 1663 ips.s_param, ips.s_oid); 1664 } 1665 } 1666 } /* END for() */ 1667 if (iscsiboot_prop && iscsi_cmp_boot_tgt_name(name) && 1668 iscsi_chk_bootlun_mpxio(ihp)) { 1669 (void) iscsi_reconfig_boot_sess(ihp); 1670 } 1671 } /* END while() */ 1672 persistent_param_unlock(); 1673 1674 kmem_free(iname, ISCSI_MAX_NAME_LEN); 1675 kmem_free(name, ISCSI_MAX_NAME_LEN); 1676 1677 return (B_TRUE); 1678 } 1679 1680 1681 /* 1682 * iscsid_thread_static -- If static discovery is enabled, this routine obtains 1683 * all statically configured targets from the peristent store and issues a 1684 * login request to the driver. 1685 */ 1686 /* ARGSUSED */ 1687 static void 1688 iscsid_thread_static(iscsi_thread_t *thread, void *p) 1689 { 1690 iSCSIDiscoveryMethod_t dm; 1691 entry_t entry; 1692 char name[ISCSI_MAX_NAME_LEN]; 1693 void *v = NULL; 1694 iscsi_hba_t *ihp = (iscsi_hba_t *)p; 1695 1696 while (iscsi_thread_wait(thread, -1) != 0) { 1697 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodStatic, B_TRUE); 1698 1699 /* ---- ensure static target discovery is enabled ---- */ 1700 dm = persistent_disc_meth_get(); 1701 if ((dm & iSCSIDiscoveryMethodStatic) == 0) { 1702 cmn_err(CE_NOTE, 1703 "iscsi discovery failure - " 1704 "StaticTargets method is not enabled"); 1705 iscsi_discovery_event(ihp, 1706 iSCSIDiscoveryMethodStatic, B_FALSE); 1707 continue; 1708 } 1709 1710 /* 1711 * walk list of the statically configured targets from the 1712 * persistent store 1713 */ 1714 v = NULL; 1715 persistent_static_addr_lock(); 1716 while (persistent_static_addr_next(&v, name, &entry) == 1717 B_TRUE) { 1718 iscsi_sockaddr_t addr; 1719 1720 iscsid_addr_to_sockaddr(entry.e_insize, 1721 &(entry.e_u), entry.e_port, &addr.sin); 1722 1723 (void) iscsid_add(ihp, iSCSIDiscoveryMethodStatic, 1724 &addr.sin, name, entry.e_tpgt, &addr.sin); 1725 } 1726 persistent_static_addr_unlock(); 1727 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodStatic, B_FALSE); 1728 } 1729 } 1730 1731 1732 /* 1733 * iscsid_thread_sendtgts -- If SendTargets discovery is enabled, this routine 1734 * obtains all target discovery addresses configured from the peristent store 1735 * and probe the IP/port addresses for possible targets. It will then issue 1736 * a login request to the driver for all discoveryed targets. 1737 */ 1738 static void 1739 iscsid_thread_sendtgts(iscsi_thread_t *thread, void *p) 1740 { 1741 iscsi_hba_t *ihp = (iscsi_hba_t *)p; 1742 iSCSIDiscoveryMethod_t dm; 1743 entry_t entry; 1744 void *v = NULL; 1745 1746 while (iscsi_thread_wait(thread, -1) != 0) { 1747 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSendTargets, 1748 B_TRUE); 1749 1750 /* ---- ensure SendTargets discovery is enabled ---- */ 1751 dm = persistent_disc_meth_get(); 1752 if ((dm & iSCSIDiscoveryMethodSendTargets) == 0) { 1753 cmn_err(CE_NOTE, 1754 "iscsi discovery failure - " 1755 "SendTargets method is not enabled"); 1756 iscsi_discovery_event(ihp, 1757 iSCSIDiscoveryMethodSendTargets, B_FALSE); 1758 continue; 1759 } 1760 /* 1761 * walk list of the SendTarget discovery addresses from the 1762 * persistent store 1763 */ 1764 v = NULL; 1765 persistent_disc_addr_lock(); 1766 while (persistent_disc_addr_next(&v, &entry) == B_TRUE) { 1767 iscsid_do_sendtgts(&entry); 1768 } 1769 persistent_disc_addr_unlock(); 1770 1771 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSendTargets, 1772 B_FALSE); 1773 } 1774 } 1775 1776 /* 1777 * iscsid_thread_slp -- If SLP discovery is enabled, this routine provides 1778 * the SLP discovery service. 1779 */ 1780 static void 1781 iscsid_thread_slp(iscsi_thread_t *thread, void *p) 1782 { 1783 iscsi_hba_t *ihp = (iscsi_hba_t *)p; 1784 1785 do { 1786 /* 1787 * Even though we don't have support for SLP at this point 1788 * we'll send the events if someone has enabled this thread. 1789 * If this is not done the daemon waiting for discovery to 1790 * complete will pause forever holding up the boot process. 1791 */ 1792 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSLP, B_TRUE); 1793 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSLP, B_FALSE); 1794 } while (iscsi_thread_wait(thread, -1) != 0); 1795 } 1796 1797 /* 1798 * iscsid_thread_isns -- 1799 */ 1800 static void 1801 iscsid_thread_isns(iscsi_thread_t *thread, void *ptr) 1802 { 1803 iscsi_hba_t *ihp = (iscsi_hba_t *)ptr; 1804 iSCSIDiscoveryMethod_t dm; 1805 1806 while (iscsi_thread_wait(thread, -1) != 0) { 1807 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodISNS, B_TRUE); 1808 1809 /* ---- ensure iSNS discovery is enabled ---- */ 1810 dm = persistent_disc_meth_get(); 1811 if ((dm & iSCSIDiscoveryMethodISNS) == 0) { 1812 cmn_err(CE_NOTE, 1813 "iscsi discovery failure - " 1814 "iSNS method is not enabled"); 1815 iscsi_discovery_event(ihp, 1816 iSCSIDiscoveryMethodISNS, B_FALSE); 1817 continue; 1818 } 1819 1820 (void) isns_reg(ihp->hba_isid, 1821 ihp->hba_name, 1822 ISCSI_MAX_NAME_LEN, 1823 ihp->hba_alias, 1824 ISCSI_MAX_NAME_LEN, 1825 ISNS_INITIATOR_NODE_TYPE, 1826 isns_scn_callback); 1827 iscsid_do_isns_query(ihp); 1828 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodISNS, B_FALSE); 1829 } 1830 1831 /* Thread stopped. Deregister from iSNS servers(s). */ 1832 (void) isns_dereg(ihp->hba_isid, ihp->hba_name); 1833 } 1834 1835 1836 /* 1837 * iscsid_threads_create -- Creates all the discovery threads. 1838 */ 1839 static void 1840 iscsid_threads_create(iscsi_hba_t *ihp) 1841 { 1842 iscsid_thr_table *t; 1843 1844 /* 1845 * start a thread for each discovery method 1846 */ 1847 for (t = &iscsid_thr[0]; t->method != iSCSIDiscoveryMethodUnknown; 1848 t++) { 1849 if (t->thr_id == NULL) { 1850 t->thr_id = iscsi_thread_create(ihp->hba_dip, t->name, 1851 t->func_start, ihp); 1852 } 1853 } 1854 } 1855 1856 /* 1857 * iscsid_threads_destroy -- Destroys all the discovery threads. 1858 */ 1859 static void 1860 iscsid_threads_destroy(void) 1861 { 1862 iscsid_thr_table *t; 1863 1864 for (t = &iscsid_thr[0]; t->method != iSCSIDiscoveryMethodUnknown; 1865 t++) { 1866 if (t->thr_id != NULL) { 1867 iscsi_thread_destroy(t->thr_id); 1868 t->thr_id = NULL; 1869 } 1870 } 1871 } 1872 1873 /* 1874 * iscsid_copyto_param_set - helper function for iscsid_init_params. 1875 */ 1876 static int 1877 iscsid_copyto_param_set(uint32_t param_id, iscsi_login_params_t *params, 1878 iscsi_param_set_t *ipsp) 1879 { 1880 int rtn = 0; 1881 1882 if (param_id >= ISCSI_NUM_LOGIN_PARAM) { 1883 return (EINVAL); 1884 } 1885 1886 switch (param_id) { 1887 1888 /* 1889 * Boolean parameters 1890 */ 1891 case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER: 1892 ipsp->s_value.v_bool = params->data_pdu_in_order; 1893 break; 1894 case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA: 1895 ipsp->s_value.v_bool = params->immediate_data; 1896 break; 1897 case ISCSI_LOGIN_PARAM_INITIAL_R2T: 1898 ipsp->s_value.v_bool = params->initial_r2t; 1899 break; 1900 case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER: 1901 ipsp->s_value.v_bool = params->data_pdu_in_order; 1902 break; 1903 1904 /* 1905 * Integer parameters 1906 */ 1907 case ISCSI_LOGIN_PARAM_HEADER_DIGEST: 1908 ipsp->s_value.v_integer = params->header_digest; 1909 break; 1910 case ISCSI_LOGIN_PARAM_DATA_DIGEST: 1911 ipsp->s_value.v_integer = params->data_digest; 1912 break; 1913 case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN: 1914 ipsp->s_value.v_integer = params->default_time_to_retain; 1915 break; 1916 case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT: 1917 ipsp->s_value.v_integer = params->default_time_to_wait; 1918 break; 1919 case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH: 1920 ipsp->s_value.v_integer = params->max_recv_data_seg_len; 1921 break; 1922 case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH: 1923 ipsp->s_value.v_integer = params->first_burst_length; 1924 break; 1925 case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH: 1926 ipsp->s_value.v_integer = params->max_burst_length; 1927 break; 1928 1929 /* 1930 * Integer parameters which currently are unsettable 1931 */ 1932 case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS: 1933 case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T: 1934 case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL: 1935 /* ---- drop through to default case ---- */ 1936 default: 1937 rtn = EINVAL; 1938 break; 1939 } 1940 1941 /* if all is well, set the parameter identifier */ 1942 if (rtn == 0) { 1943 ipsp->s_param = param_id; 1944 } 1945 1946 return (rtn); 1947 } 1948 1949 /* 1950 * iscsid_add_pg_list_to_cache - Add portal groups in the list to the 1951 * discovery cache. 1952 */ 1953 static void 1954 iscsid_add_pg_list_to_cache(iscsi_hba_t *ihp, 1955 isns_portal_group_list_t *pg_list) 1956 { 1957 int i; 1958 1959 for (i = 0; i < pg_list->pg_out_cnt; i++) { 1960 iscsi_sockaddr_t addr_dsc; 1961 iscsi_sockaddr_t addr_tgt; 1962 1963 iscsid_addr_to_sockaddr( 1964 pg_list->pg_list[i].isns_server_ip.i_insize, 1965 &pg_list->pg_list[i].isns_server_ip.i_addr, 1966 pg_list->pg_list[i].isns_server_port, 1967 &addr_dsc.sin); 1968 iscsid_addr_to_sockaddr( 1969 pg_list->pg_list[i].insize, 1970 &pg_list->pg_list[i].pg_ip_addr, 1971 pg_list->pg_list[i].pg_port, 1972 &addr_tgt.sin); 1973 1974 (void) iscsid_add(ihp, iSCSIDiscoveryMethodISNS, &addr_dsc.sin, 1975 (char *)pg_list->pg_list[i].pg_iscsi_name, 1976 pg_list->pg_list[i].pg_tag, &addr_tgt.sin); 1977 } 1978 } 1979 1980 /* 1981 * set_initiator_name - set default initiator name and alias. 1982 * 1983 * This sets the default initiator name and alias. The 1984 * initiator name is composed of sun's reverse domain name 1985 * and registration followed and a unique classifier. This 1986 * classifier is the mac address of the first NIC in the 1987 * host and a timestamp to make sure the classifier is 1988 * unique if the NIC is moved between hosts. The alias 1989 * is just the hostname. 1990 */ 1991 void 1992 iscsid_set_default_initiator_node_settings(iscsi_hba_t *ihp, boolean_t minimal) 1993 { 1994 int i; 1995 time_t x; 1996 struct ether_addr eaddr; 1997 char val[10]; 1998 iscsi_chap_props_t *chap = NULL; 1999 2000 /* Set default initiator-node name */ 2001 if (iscsiboot_prop && iscsiboot_prop->boot_init.ini_name != NULL) { 2002 (void) strncpy((char *)ihp->hba_name, 2003 (const char *)iscsiboot_prop->boot_init.ini_name, 2004 ISCSI_MAX_NAME_LEN); 2005 } else { 2006 (void) snprintf((char *)ihp->hba_name, 2007 ISCSI_MAX_NAME_LEN, 2008 "iqn.1986-03.com.sun:01:"); 2009 2010 (void) localetheraddr(NULL, &eaddr); 2011 for (i = 0; i < ETHERADDRL; i++) { 2012 (void) snprintf(val, sizeof (val), "%02x", 2013 eaddr.ether_addr_octet[i]); 2014 (void) strncat((char *)ihp->hba_name, val, 2015 ISCSI_MAX_NAME_LEN); 2016 } 2017 2018 /* Set default initiator-node alias */ 2019 x = ddi_get_time(); 2020 (void) snprintf(val, sizeof (val), ".%lx", x); 2021 (void) strncat((char *)ihp->hba_name, val, ISCSI_MAX_NAME_LEN); 2022 2023 if (ihp->hba_alias[0] == '\0') { 2024 (void) strncpy((char *)ihp->hba_alias, 2025 utsname.nodename, ISCSI_MAX_NAME_LEN); 2026 ihp->hba_alias_length = strlen((char *)ihp->hba_alias); 2027 if (minimal == B_FALSE) { 2028 (void) persistent_alias_name_set( 2029 (char *)ihp->hba_alias); 2030 } 2031 } 2032 } 2033 2034 if (minimal == B_TRUE) { 2035 return; 2036 } 2037 2038 (void) persistent_initiator_name_set((char *)ihp->hba_name); 2039 2040 /* Set default initiator-node CHAP settings */ 2041 if (persistent_initiator_name_get((char *)ihp->hba_name, 2042 ISCSI_MAX_NAME_LEN) == B_TRUE) { 2043 chap = (iscsi_chap_props_t *)kmem_zalloc(sizeof (*chap), 2044 KM_SLEEP); 2045 if (persistent_chap_get((char *)ihp->hba_name, chap) == 2046 B_FALSE) { 2047 bcopy((char *)ihp->hba_name, chap->c_user, 2048 strlen((char *)ihp->hba_name)); 2049 chap->c_user_len = strlen((char *)ihp->hba_name); 2050 (void) persistent_chap_set((char *)ihp->hba_name, chap); 2051 } 2052 kmem_free(chap, sizeof (*chap)); 2053 } 2054 } 2055 2056 static void 2057 iscsid_remove_target_param(char *name) 2058 { 2059 persistent_param_t *pparam; 2060 uint32_t t_oid; 2061 iscsi_config_sess_t *ics; 2062 2063 ASSERT(name != NULL); 2064 2065 /* 2066 * Remove target-param <-> target mapping. 2067 * Only remove if there is not any overridden 2068 * parameters in the persistent store 2069 */ 2070 pparam = (persistent_param_t *)kmem_zalloc(sizeof (*pparam), KM_SLEEP); 2071 2072 /* 2073 * setup initial buffer for configured session 2074 * information 2075 */ 2076 ics = (iscsi_config_sess_t *)kmem_zalloc(sizeof (*ics), KM_SLEEP); 2077 ics->ics_in = 1; 2078 2079 if ((persistent_param_get(name, pparam) == B_FALSE) && 2080 (persistent_get_config_session(name, ics) == B_FALSE)) { 2081 t_oid = iscsi_targetparam_get_oid((uchar_t *)name); 2082 (void) iscsi_targetparam_remove_target(t_oid); 2083 } 2084 2085 kmem_free(pparam, sizeof (*pparam)); 2086 pparam = NULL; 2087 kmem_free(ics, sizeof (*ics)); 2088 ics = NULL; 2089 } 2090 2091 /* 2092 * iscsid_addr_to_sockaddr - convert other types to struct sockaddr 2093 */ 2094 void 2095 iscsid_addr_to_sockaddr(int src_insize, void *src_addr, int src_port, 2096 struct sockaddr *dst_addr) 2097 { 2098 ASSERT((src_insize == sizeof (struct in_addr)) || 2099 (src_insize == sizeof (struct in6_addr))); 2100 ASSERT(src_addr != NULL); 2101 ASSERT(dst_addr != NULL); 2102 2103 bzero(dst_addr, sizeof (*dst_addr)); 2104 2105 /* translate discovery information */ 2106 if (src_insize == sizeof (struct in_addr)) { 2107 struct sockaddr_in *addr_in = 2108 (struct sockaddr_in *)dst_addr; 2109 addr_in->sin_family = AF_INET; 2110 bcopy(src_addr, &addr_in->sin_addr.s_addr, 2111 sizeof (struct in_addr)); 2112 addr_in->sin_port = htons(src_port); 2113 } else { 2114 struct sockaddr_in6 *addr_in6 = 2115 (struct sockaddr_in6 *)dst_addr; 2116 addr_in6->sin6_family = AF_INET6; 2117 bcopy(src_addr, &addr_in6->sin6_addr.s6_addr, 2118 sizeof (struct in6_addr)); 2119 addr_in6->sin6_port = htons(src_port); 2120 } 2121 } 2122 2123 /* 2124 * iscsi_discovery_event -- send event associated with discovery operations 2125 * 2126 * Each discovery event has a start and end event. Which is sent is based 2127 * on the boolean argument start with the obvious results. 2128 */ 2129 static void 2130 iscsi_discovery_event(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t m, 2131 boolean_t start) 2132 { 2133 char *subclass = NULL; 2134 2135 mutex_enter(&ihp->hba_discovery_events_mutex); 2136 switch (m) { 2137 case iSCSIDiscoveryMethodStatic: 2138 if (start == B_TRUE) { 2139 subclass = ESC_ISCSI_STATIC_START; 2140 } else { 2141 ihp->hba_discovery_events |= iSCSIDiscoveryMethodStatic; 2142 subclass = ESC_ISCSI_STATIC_END; 2143 } 2144 break; 2145 2146 case iSCSIDiscoveryMethodSendTargets: 2147 if (start == B_TRUE) { 2148 subclass = ESC_ISCSI_SEND_TARGETS_START; 2149 } else { 2150 ihp->hba_discovery_events |= 2151 iSCSIDiscoveryMethodSendTargets; 2152 subclass = ESC_ISCSI_SEND_TARGETS_END; 2153 } 2154 break; 2155 2156 case iSCSIDiscoveryMethodSLP: 2157 if (start == B_TRUE) { 2158 subclass = ESC_ISCSI_SLP_START; 2159 } else { 2160 ihp->hba_discovery_events |= iSCSIDiscoveryMethodSLP; 2161 subclass = ESC_ISCSI_SLP_END; 2162 } 2163 break; 2164 2165 case iSCSIDiscoveryMethodISNS: 2166 if (start == B_TRUE) { 2167 subclass = ESC_ISCSI_ISNS_START; 2168 } else { 2169 ihp->hba_discovery_events |= iSCSIDiscoveryMethodISNS; 2170 subclass = ESC_ISCSI_ISNS_END; 2171 } 2172 break; 2173 } 2174 mutex_exit(&ihp->hba_discovery_events_mutex); 2175 iscsi_send_sysevent(ihp, EC_ISCSI, subclass, NULL); 2176 } 2177 2178 /* 2179 * iscsi_send_sysevent -- send sysevent using specified class 2180 */ 2181 void 2182 iscsi_send_sysevent( 2183 iscsi_hba_t *ihp, 2184 char *eventclass, 2185 char *subclass, 2186 nvlist_t *np) 2187 { 2188 (void) ddi_log_sysevent(ihp->hba_dip, DDI_VENDOR_SUNW, eventclass, 2189 subclass, np, NULL, DDI_SLEEP); 2190 } 2191 2192 static boolean_t 2193 iscsid_boot_init_config(iscsi_hba_t *ihp) 2194 { 2195 if (strlen((const char *)iscsiboot_prop->boot_init.ini_name) != 0) { 2196 bcopy(iscsiboot_prop->boot_init.ini_name, 2197 ihp->hba_name, 2198 strlen((const char *)iscsiboot_prop->boot_init.ini_name)); 2199 } 2200 /* or using default login param for boot session */ 2201 return (B_TRUE); 2202 } 2203 2204 boolean_t 2205 iscsi_reconfig_boot_sess(iscsi_hba_t *ihp) 2206 { 2207 iscsi_config_sess_t *ics; 2208 int idx; 2209 iscsi_sess_t *isp, *t_isp; 2210 int isid, size; 2211 char *name; 2212 boolean_t rtn = B_TRUE; 2213 2214 if (iscsiboot_prop == NULL) { 2215 return (B_FALSE); 2216 } 2217 size = sizeof (*ics); 2218 ics = kmem_zalloc(size, KM_SLEEP); 2219 ics->ics_in = 1; 2220 2221 /* get information of number of sessions to be configured */ 2222 name = (char *)iscsiboot_prop->boot_tgt.tgt_name; 2223 if (persistent_get_config_session(name, ics) == B_FALSE) { 2224 /* 2225 * No target information available to check 2226 * initiator information. Assume one session 2227 * by default. 2228 */ 2229 name = (char *)iscsiboot_prop->boot_init.ini_name; 2230 if (persistent_get_config_session(name, ics) == B_FALSE) { 2231 ics->ics_out = 1; 2232 ics->ics_bound = B_TRUE; 2233 } 2234 } 2235 2236 /* get necessary information */ 2237 if (ics->ics_out > 1) { 2238 idx = ics->ics_out; 2239 size = ISCSI_SESSION_CONFIG_SIZE(ics->ics_out); 2240 kmem_free(ics, sizeof (*ics)); 2241 2242 ics = kmem_zalloc(size, KM_SLEEP); 2243 ics->ics_in = idx; 2244 2245 /* get configured sessions information */ 2246 if (persistent_get_config_session((char *)name, 2247 ics) != B_TRUE) { 2248 cmn_err(CE_NOTE, "session(%s) - " 2249 "failed to setup multiple sessions", 2250 name); 2251 kmem_free(ics, size); 2252 return (B_FALSE); 2253 } 2254 } 2255 2256 /* create a temporary session to keep boot session connective */ 2257 t_isp = iscsi_add_boot_sess(ihp, ISCSI_MAX_CONFIG_SESSIONS); 2258 if (t_isp == NULL) { 2259 cmn_err(CE_NOTE, "session(%s) - " 2260 "failed to setup multiple sessions", name); 2261 rw_exit(&ihp->hba_sess_list_rwlock); 2262 kmem_free(ics, size); 2263 return (B_FALSE); 2264 } 2265 2266 /* destroy all old boot sessions */ 2267 rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); 2268 isp = ihp->hba_sess_list; 2269 while (isp != NULL) { 2270 if (iscsi_chk_bootlun_mpxio(ihp) && isp->sess_boot) { 2271 if (isp->sess_isid[5] != ISCSI_MAX_CONFIG_SESSIONS) { 2272 /* 2273 * destroy all stale sessions 2274 * except temporary boot session 2275 */ 2276 if (ISCSI_SUCCESS(iscsi_sess_destroy( 2277 isp))) { 2278 isp = ihp->hba_sess_list; 2279 } else { 2280 /* 2281 * couldn't destroy stale sessions 2282 * at least poke it to disconnect 2283 */ 2284 mutex_enter(&isp->sess_state_mutex); 2285 iscsi_sess_state_machine(isp, 2286 ISCSI_SESS_EVENT_N7); 2287 mutex_exit(&isp->sess_state_mutex); 2288 isp = isp->sess_next; 2289 cmn_err(CE_NOTE, "session(%s) - " 2290 "failed to setup multiple" 2291 " sessions", name); 2292 } 2293 } else { 2294 isp = isp->sess_next; 2295 } 2296 } else { 2297 isp = isp->sess_next; 2298 } 2299 } 2300 rw_exit(&ihp->hba_sess_list_rwlock); 2301 2302 for (isid = 0; isid < ics->ics_out; isid++) { 2303 isp = iscsi_add_boot_sess(ihp, isid); 2304 if (isp == NULL) { 2305 cmn_err(CE_NOTE, "session(%s) - failed to setup" 2306 " multiple sessions", name); 2307 rtn = B_FALSE; 2308 break; 2309 } 2310 } 2311 if (!rtn && (isid == 0)) { 2312 /* 2313 * fail to create any new boot session 2314 * so only the temporary session is alive 2315 * quit without destroying it 2316 */ 2317 kmem_free(ics, size); 2318 return (rtn); 2319 } 2320 2321 rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); 2322 if (!ISCSI_SUCCESS(iscsi_sess_destroy(t_isp))) { 2323 /* couldn't destroy temp boot session */ 2324 cmn_err(CE_NOTE, "session(%s) - " 2325 "failed to setup multiple sessions", name); 2326 rw_exit(&ihp->hba_sess_list_rwlock); 2327 rtn = B_FALSE; 2328 } 2329 rw_exit(&ihp->hba_sess_list_rwlock); 2330 2331 kmem_free(ics, size); 2332 return (rtn); 2333 } 2334 2335 static iscsi_sess_t * 2336 iscsi_add_boot_sess(iscsi_hba_t *ihp, int isid) 2337 { 2338 iscsi_sess_t *isp; 2339 iscsi_conn_t *icp; 2340 uint_t oid; 2341 2342 iscsi_sockaddr_t addr_dst; 2343 2344 addr_dst.sin.sa_family = iscsiboot_prop->boot_tgt.sin_family; 2345 if (addr_dst.sin.sa_family == AF_INET) { 2346 bcopy(&iscsiboot_prop->boot_tgt.tgt_ip_u.u_in4.s_addr, 2347 &addr_dst.sin4.sin_addr.s_addr, sizeof (struct in_addr)); 2348 addr_dst.sin4.sin_port = 2349 htons(iscsiboot_prop->boot_tgt.tgt_port); 2350 } else { 2351 bcopy(&iscsiboot_prop->boot_tgt.tgt_ip_u.u_in6.s6_addr, 2352 &addr_dst.sin6.sin6_addr.s6_addr, 2353 sizeof (struct in6_addr)); 2354 addr_dst.sin6.sin6_port = 2355 htons(iscsiboot_prop->boot_tgt.tgt_port); 2356 } 2357 2358 rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); 2359 isp = iscsi_sess_create(ihp, 2360 iSCSIDiscoveryMethodBoot|iSCSIDiscoveryMethodStatic, 2361 (struct sockaddr *)&addr_dst, 2362 (char *)iscsiboot_prop->boot_tgt.tgt_name, 2363 ISCSI_DEFAULT_TPGT, isid, ISCSI_SESS_TYPE_NORMAL, &oid); 2364 if (isp == NULL) { 2365 /* create temp booting session failed */ 2366 rw_exit(&ihp->hba_sess_list_rwlock); 2367 return (NULL); 2368 } 2369 isp->sess_boot = B_TRUE; 2370 2371 if (!ISCSI_SUCCESS(iscsi_conn_create((struct sockaddr *)&addr_dst, 2372 isp, &icp))) { 2373 rw_exit(&ihp->hba_sess_list_rwlock); 2374 return (NULL); 2375 } 2376 2377 rw_exit(&ihp->hba_sess_list_rwlock); 2378 /* now online created session */ 2379 if (iscsid_login_tgt(ihp, (char *)iscsiboot_prop->boot_tgt.tgt_name, 2380 iSCSIDiscoveryMethodBoot|iSCSIDiscoveryMethodStatic, 2381 (struct sockaddr *)&addr_dst) == B_FALSE) { 2382 return (NULL); 2383 } 2384 2385 return (isp); 2386 } 2387 2388 static void 2389 iscsid_thread_boot_wd(iscsi_thread_t *thread, void *p) 2390 { 2391 int rc = 1; 2392 iscsi_hba_t *ihp = (iscsi_hba_t *)p; 2393 boolean_t reconfigured = B_FALSE; 2394 2395 while (rc != 0) { 2396 if (iscsiboot_prop && (modrootloaded == 1)) { 2397 if (ihp->hba_persistent_loaded == B_FALSE) { 2398 if (persistent_load() == B_TRUE) { 2399 ihp->hba_persistent_loaded = B_TRUE; 2400 } 2401 } 2402 if ((ihp->hba_persistent_loaded == B_TRUE) && 2403 (reconfigured == B_FALSE)) { 2404 if (iscsi_chk_bootlun_mpxio(ihp) == B_TRUE) { 2405 (void) iscsi_reconfig_boot_sess(ihp); 2406 iscsid_poke_discovery(ihp, 2407 iSCSIDiscoveryMethodUnknown); 2408 (void) iscsid_login_tgt(ihp, NULL, 2409 iSCSIDiscoveryMethodUnknown, NULL); 2410 } 2411 reconfigured = B_TRUE; 2412 } 2413 break; 2414 } 2415 rc = iscsi_thread_wait(thread, SEC_TO_TICK(1)); 2416 } 2417 } 2418 2419 boolean_t 2420 iscsi_cmp_boot_tgt_name(char *name) 2421 { 2422 if (iscsiboot_prop && (strncmp((const char *)name, 2423 (const char *)iscsiboot_prop->boot_tgt.tgt_name, 2424 ISCSI_MAX_NAME_LEN) == 0)) { 2425 return (B_TRUE); 2426 } else { 2427 return (B_FALSE); 2428 } 2429 } 2430 2431 boolean_t 2432 iscsi_cmp_boot_ini_name(char *name) 2433 { 2434 if (iscsiboot_prop && (strncmp((const char *)name, 2435 (const char *)iscsiboot_prop->boot_init.ini_name, 2436 ISCSI_MAX_NAME_LEN) == 0)) { 2437 return (B_TRUE); 2438 } else { 2439 return (B_FALSE); 2440 } 2441 } 2442 2443 boolean_t 2444 iscsi_chk_bootlun_mpxio(iscsi_hba_t *ihp) 2445 { 2446 iscsi_sess_t *isp; 2447 iscsi_lun_t *ilp; 2448 isp = ihp->hba_sess_list; 2449 boolean_t tgt_mpxio_enabled = B_FALSE; 2450 boolean_t bootlun_found = B_FALSE; 2451 uint16_t lun_num; 2452 2453 if (iscsiboot_prop == NULL) { 2454 return (B_FALSE); 2455 } 2456 2457 if (!ihp->hba_mpxio_enabled) { 2458 return (B_FALSE); 2459 } 2460 2461 lun_num = *((uint64_t *)(iscsiboot_prop->boot_tgt.tgt_boot_lun)); 2462 2463 while (isp != NULL) { 2464 if ((strncmp((char *)isp->sess_name, 2465 (const char *)iscsiboot_prop->boot_tgt.tgt_name, 2466 ISCSI_MAX_NAME_LEN) == 0) && 2467 (isp->sess_boot == B_TRUE)) { 2468 /* 2469 * found boot session. 2470 * check its mdi path info is null or not 2471 */ 2472 ilp = isp->sess_lun_list; 2473 while (ilp != NULL) { 2474 if (lun_num == ilp->lun_num) { 2475 if (ilp->lun_pip) { 2476 tgt_mpxio_enabled = B_TRUE; 2477 } 2478 bootlun_found = B_TRUE; 2479 } 2480 ilp = ilp->lun_next; 2481 } 2482 } 2483 isp = isp->sess_next; 2484 } 2485 if (bootlun_found) { 2486 return (tgt_mpxio_enabled); 2487 } else { 2488 /* 2489 * iscsiboot_prop not NULL while no boot lun found 2490 * in most cases this is none iscsi boot while iscsiboot_prop 2491 * is not NULL, in this scenario return iscsi HBA's mpxio config 2492 */ 2493 return (ihp->hba_mpxio_enabled); 2494 } 2495 } 2496 2497 static boolean_t 2498 iscsid_check_active_boot_conn(iscsi_hba_t *ihp) 2499 { 2500 iscsi_sess_t *isp = NULL; 2501 iscsi_conn_t *icp = NULL; 2502 2503 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 2504 isp = ihp->hba_sess_list; 2505 while (isp != NULL) { 2506 if (isp->sess_boot == B_TRUE) { 2507 rw_enter(&isp->sess_conn_list_rwlock, RW_READER); 2508 icp = isp->sess_conn_list; 2509 while (icp != NULL) { 2510 if (icp->conn_state == 2511 ISCSI_CONN_STATE_LOGGED_IN) { 2512 rw_exit(&isp->sess_conn_list_rwlock); 2513 rw_exit(&ihp->hba_sess_list_rwlock); 2514 return (B_TRUE); 2515 } 2516 icp = icp->conn_next; 2517 } 2518 rw_exit(&isp->sess_conn_list_rwlock); 2519 } 2520 isp = isp->sess_next; 2521 } 2522 rw_exit(&ihp->hba_sess_list_rwlock); 2523 2524 return (B_FALSE); 2525 } 2526