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