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