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