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