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