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 { 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 "session logout failed (%d)\n", 1279 isp->sess_oid, status); 1280 isp = isp->sess_next; 1281 rtn = B_FALSE; 1282 } 1283 } else { 1284 isp = isp->sess_next; 1285 } 1286 } else { 1287 isp = isp->sess_next; 1288 } 1289 } 1290 rw_exit(&ihp->hba_sess_list_rwlock); 1291 return (rtn); 1292 } 1293 1294 1295 /* 1296 * iscsid_login_tgt - request target(s) to login 1297 */ 1298 boolean_t 1299 iscsid_login_tgt(iscsi_hba_t *ihp, char *target_name, 1300 iSCSIDiscoveryMethod_t method, struct sockaddr *addr_dsc) 1301 { 1302 boolean_t rtn = B_FALSE; 1303 iscsi_sess_t *isp = NULL; 1304 iscsi_sess_list_t *isp_list = NULL; 1305 iscsi_sess_list_t *last_sess = NULL; 1306 iscsi_sess_list_t *cur_sess = NULL; 1307 int total = 0; 1308 ddi_taskq_t *login_taskq = NULL; 1309 char taskq_name[ISCSI_TH_MAX_NAME_LEN] = {0}; 1310 time_t time_stamp; 1311 1312 ASSERT(ihp != NULL); 1313 1314 rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); 1315 /* Loop thru sessions */ 1316 isp = ihp->hba_sess_list; 1317 while (isp != NULL) { 1318 boolean_t try_online; 1319 if (!(method & iSCSIDiscoveryMethodBoot)) { 1320 if (target_name == NULL) { 1321 if (method == iSCSIDiscoveryMethodUnknown) { 1322 /* unknown method mean login to all */ 1323 try_online = B_TRUE; 1324 } else if (isp->sess_discovered_by & method) { 1325 if ((method == 1326 iSCSIDiscoveryMethodISNS) || 1327 (method == 1328 iSCSIDiscoveryMethodSendTargets)) { 1329 #define SESS_DISC_ADDR isp->sess_discovered_addr.sin 1330 if ((addr_dsc == NULL) || 1331 (bcmp( 1332 &isp->sess_discovered_addr, 1333 addr_dsc, SIZEOF_SOCKADDR( 1334 &SESS_DISC_ADDR)) 1335 == 0)) { 1336 /* 1337 * iSNS or sendtarget 1338 * discovery and 1339 * discovery address 1340 * is NULL or match 1341 */ 1342 try_online = B_TRUE; 1343 } else { 1344 /* addr_dsc not a match */ 1345 try_online = B_FALSE; 1346 } 1347 #undef SESS_DISC_ADDR 1348 } else { 1349 /* static configuration */ 1350 try_online = B_TRUE; 1351 } 1352 } else { 1353 /* method not a match */ 1354 try_online = B_FALSE; 1355 } 1356 } else if (strcmp(target_name, 1357 (char *)isp->sess_name) == 0) { 1358 /* target_name match */ 1359 try_online = B_TRUE; 1360 } else { 1361 /* target_name not a match */ 1362 try_online = B_FALSE; 1363 } 1364 } else { 1365 /* 1366 * online the boot session. 1367 */ 1368 if (isp->sess_boot == B_TRUE) { 1369 try_online = B_TRUE; 1370 } 1371 } 1372 1373 if (try_online == B_TRUE && 1374 isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { 1375 total++; 1376 /* Copy these sessions to the list. */ 1377 if (isp_list == NULL) { 1378 isp_list = 1379 (iscsi_sess_list_t *)kmem_zalloc( 1380 sizeof (iscsi_sess_list_t), KM_SLEEP); 1381 last_sess = isp_list; 1382 last_sess->session = isp; 1383 last_sess->next = NULL; 1384 } else { 1385 last_sess->next = 1386 (iscsi_sess_list_t *)kmem_zalloc( 1387 sizeof (iscsi_sess_list_t), KM_SLEEP); 1388 last_sess->next->session = isp; 1389 last_sess->next->next = NULL; 1390 last_sess = last_sess->next; 1391 } 1392 rtn = B_TRUE; 1393 } 1394 1395 isp = isp->sess_next; 1396 } 1397 1398 if (total > 0) { 1399 time_stamp = ddi_get_time(); 1400 (void) snprintf(taskq_name, (ISCSI_TH_MAX_NAME_LEN - 1), 1401 "login_queue.%lx", time_stamp); 1402 1403 login_taskq = ddi_taskq_create(ihp->hba_dip, 1404 taskq_name, total, TASKQ_DEFAULTPRI, 0); 1405 if (login_taskq == NULL) { 1406 while (isp_list != NULL) { 1407 cur_sess = isp_list; 1408 isp_list = isp_list->next; 1409 kmem_free(cur_sess, sizeof (iscsi_sess_list_t)); 1410 } 1411 rtn = B_FALSE; 1412 rw_exit(&ihp->hba_sess_list_rwlock); 1413 return (rtn); 1414 } 1415 1416 for (cur_sess = isp_list; cur_sess != NULL; 1417 cur_sess = cur_sess->next) { 1418 if (ddi_taskq_dispatch(login_taskq, 1419 iscsi_sess_online, (void *)cur_sess->session, 1420 DDI_SLEEP) != DDI_SUCCESS) { 1421 cmn_err(CE_NOTE, "Can't dispatch the task " 1422 "for login to the target: %s", 1423 cur_sess->session->sess_name); 1424 } 1425 } 1426 1427 ddi_taskq_wait(login_taskq); 1428 ddi_taskq_destroy(login_taskq); 1429 while (isp_list != NULL) { 1430 cur_sess = isp_list; 1431 isp_list = isp_list->next; 1432 kmem_free(cur_sess, sizeof (iscsi_sess_list_t)); 1433 } 1434 1435 } 1436 1437 rw_exit(&ihp->hba_sess_list_rwlock); 1438 return (rtn); 1439 } 1440 1441 /* 1442 * +--------------------------------------------------------------------+ 1443 * | Local Helper Functions | 1444 * +--------------------------------------------------------------------+ 1445 */ 1446 1447 /* 1448 * iscsid_init_config -- initialize configuration parameters of iSCSI initiator 1449 */ 1450 static boolean_t 1451 iscsid_init_config(iscsi_hba_t *ihp) 1452 { 1453 iscsi_param_set_t ips; 1454 void *v = NULL; 1455 char *name; 1456 char *initiatorName; 1457 persistent_param_t pp; 1458 persistent_tunable_param_t pparam; 1459 uint32_t param_id; 1460 int rc; 1461 1462 /* allocate memory to hold initiator names */ 1463 initiatorName = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 1464 1465 /* 1466 * initialize iSCSI initiator name 1467 */ 1468 bzero(&ips, sizeof (ips)); 1469 if (persistent_initiator_name_get(initiatorName, 1470 ISCSI_MAX_NAME_LEN) == B_TRUE) { 1471 ips.s_vers = ISCSI_INTERFACE_VERSION; 1472 ips.s_param = ISCSI_LOGIN_PARAM_INITIATOR_NAME; 1473 1474 if (iscsiboot_prop && !iscsi_cmp_boot_ini_name(initiatorName)) { 1475 (void) strncpy(initiatorName, 1476 (const char *)iscsiboot_prop->boot_init.ini_name, 1477 ISCSI_MAX_NAME_LEN); 1478 (void) strncpy((char *)ips.s_value.v_name, 1479 (const char *)iscsiboot_prop->boot_init.ini_name, 1480 sizeof (ips.s_value.v_name)); 1481 (void) iscsi_set_params(&ips, ihp, B_TRUE); 1482 /* use default tunable value */ 1483 ihp->hba_tunable_params.recv_login_rsp_timeout = 1484 ISCSI_DEFAULT_RX_TIMEOUT_VALUE; 1485 ihp->hba_tunable_params.polling_login_delay = 1486 ISCSI_DEFAULT_LOGIN_POLLING_DELAY; 1487 ihp->hba_tunable_params.conn_login_max = 1488 ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX; 1489 cmn_err(CE_NOTE, "Set initiator's name" 1490 " from firmware"); 1491 } else { 1492 (void) strncpy((char *)ips.s_value.v_name, 1493 initiatorName, sizeof (ips.s_value.v_name)); 1494 1495 (void) iscsi_set_params(&ips, ihp, B_FALSE); 1496 if (persistent_get_tunable_param(initiatorName, 1497 &pparam) == B_FALSE) { 1498 /* use default value */ 1499 pparam.p_params.recv_login_rsp_timeout = 1500 ISCSI_DEFAULT_RX_TIMEOUT_VALUE; 1501 pparam.p_params.polling_login_delay = 1502 ISCSI_DEFAULT_LOGIN_POLLING_DELAY; 1503 pparam.p_params.conn_login_max = 1504 ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX; 1505 } 1506 bcopy(&pparam.p_params, &ihp->hba_tunable_params, 1507 sizeof (iscsi_tunable_params_t)); 1508 } 1509 } else { 1510 /* 1511 * if no initiator-node name available it is most 1512 * likely due to a fresh install, or the persistent 1513 * store is not working correctly. Set 1514 * a default initiator name so that the initiator can 1515 * be brought up properly. 1516 */ 1517 iscsid_set_default_initiator_node_settings(ihp, B_FALSE); 1518 (void) strncpy(initiatorName, (const char *)ihp->hba_name, 1519 ISCSI_MAX_NAME_LEN); 1520 } 1521 1522 /* 1523 * initialize iSCSI initiator alias (if any) 1524 */ 1525 bzero(&ips, sizeof (ips)); 1526 if (persistent_alias_name_get((char *)ips.s_value.v_name, 1527 sizeof (ips.s_value.v_name)) == B_TRUE) { 1528 ips.s_param = ISCSI_LOGIN_PARAM_INITIATOR_ALIAS; 1529 (void) iscsi_set_params(&ips, ihp, B_FALSE); 1530 } else { 1531 /* EMPTY */ 1532 /* No alias defined - not a problem. */ 1533 } 1534 1535 /* 1536 * load up the overriden iSCSI initiator parameters 1537 */ 1538 name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 1539 persistent_param_lock(); 1540 v = NULL; 1541 while (persistent_param_next(&v, name, &pp) == B_TRUE) { 1542 if (strncmp(name, initiatorName, ISCSI_MAX_NAME_LEN) == 0) { 1543 ips.s_oid = ihp->hba_oid; 1544 ips.s_vers = ISCSI_INTERFACE_VERSION; 1545 for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM; 1546 param_id++) { 1547 if (pp.p_bitmap & (1 << param_id)) { 1548 rc = iscsid_copyto_param_set(param_id, 1549 &pp.p_params, &ips); 1550 if (rc == 0) { 1551 rc = iscsi_set_params(&ips, 1552 ihp, B_FALSE); 1553 } 1554 if (rc != 0) { 1555 /* note error but continue */ 1556 cmn_err(CE_NOTE, 1557 "Failed to set " 1558 "param %d for OID %d", 1559 ips.s_param, ips.s_oid); 1560 } 1561 } 1562 } /* END for() */ 1563 if (iscsiboot_prop && 1564 iscsi_chk_bootlun_mpxio(ihp)) { 1565 (void) iscsi_reconfig_boot_sess(ihp); 1566 } 1567 break; 1568 } 1569 } /* END while() */ 1570 persistent_param_unlock(); 1571 1572 kmem_free(initiatorName, ISCSI_MAX_NAME_LEN); 1573 kmem_free(name, ISCSI_MAX_NAME_LEN); 1574 return (B_TRUE); 1575 } 1576 1577 1578 /* 1579 * iscsid_init_targets -- Load up the driver with known static targets and 1580 * targets whose parameters have been modified. 1581 * 1582 * This is done so that the CLI can find a list of targets the driver 1583 * currently knows about. 1584 * 1585 * The driver doesn't need to log into these targets. Log in is done based 1586 * upon the enabled discovery methods. 1587 */ 1588 static boolean_t 1589 iscsid_init_targets(iscsi_hba_t *ihp) 1590 { 1591 void *v = NULL; 1592 char *name; 1593 iscsi_param_set_t ips; 1594 persistent_param_t pp; 1595 char *iname; 1596 uint32_t param_id; 1597 int rc; 1598 1599 ASSERT(ihp != NULL); 1600 1601 /* allocate memory to hold target names */ 1602 name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 1603 1604 /* 1605 * load up targets whose parameters have been overriden 1606 */ 1607 1608 /* ---- only need to be set once ---- */ 1609 bzero(&ips, sizeof (ips)); 1610 ips.s_vers = ISCSI_INTERFACE_VERSION; 1611 1612 /* allocate memory to hold initiator name */ 1613 iname = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 1614 (void) persistent_initiator_name_get(iname, ISCSI_MAX_NAME_LEN); 1615 1616 persistent_param_lock(); 1617 v = NULL; 1618 while (persistent_param_next(&v, name, &pp) == B_TRUE) { 1619 1620 if (strncmp(iname, name, ISCSI_MAX_NAME_LEN) == 0) { 1621 /* 1622 * target name matched initiator's name so, 1623 * continue to next target. Initiator's 1624 * parmeters have already been set. 1625 */ 1626 continue; 1627 } 1628 1629 if (iscsiboot_prop && iscsi_cmp_boot_tgt_name(name) && 1630 !iscsi_chk_bootlun_mpxio(ihp)) { 1631 /* 1632 * boot target is not mpxio enabled 1633 * simply ignore these overriden parameters 1634 */ 1635 continue; 1636 } 1637 1638 ips.s_oid = iscsi_targetparam_get_oid((unsigned char *)name); 1639 1640 for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM; 1641 param_id++) { 1642 if (pp.p_bitmap & (1 << param_id)) { 1643 rc = iscsid_copyto_param_set(param_id, 1644 &pp.p_params, &ips); 1645 if (rc == 0) { 1646 rc = iscsi_set_params(&ips, 1647 ihp, B_FALSE); 1648 } 1649 if (rc != 0) { 1650 /* note error but continue ---- */ 1651 cmn_err(CE_NOTE, "Failed to set " 1652 "param %d for OID %d", 1653 ips.s_param, ips.s_oid); 1654 } 1655 } 1656 } /* END for() */ 1657 if (iscsiboot_prop && iscsi_cmp_boot_tgt_name(name) && 1658 iscsi_chk_bootlun_mpxio(ihp)) { 1659 (void) iscsi_reconfig_boot_sess(ihp); 1660 } 1661 } /* END while() */ 1662 persistent_param_unlock(); 1663 1664 kmem_free(iname, ISCSI_MAX_NAME_LEN); 1665 kmem_free(name, ISCSI_MAX_NAME_LEN); 1666 1667 return (B_TRUE); 1668 } 1669 1670 1671 /* 1672 * iscsid_thread_static -- If static discovery is enabled, this routine obtains 1673 * all statically configured targets from the peristent store and issues a 1674 * login request to the driver. 1675 */ 1676 /* ARGSUSED */ 1677 static void 1678 iscsid_thread_static(iscsi_thread_t *thread, void *p) 1679 { 1680 iSCSIDiscoveryMethod_t dm; 1681 entry_t entry; 1682 char name[ISCSI_MAX_NAME_LEN]; 1683 void *v = NULL; 1684 iscsi_hba_t *ihp = (iscsi_hba_t *)p; 1685 1686 while (iscsi_thread_wait(thread, -1) != 0) { 1687 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodStatic, B_TRUE); 1688 1689 /* ---- ensure static target discovery is enabled ---- */ 1690 dm = persistent_disc_meth_get(); 1691 if ((dm & iSCSIDiscoveryMethodStatic) == 0) { 1692 cmn_err(CE_NOTE, 1693 "iscsi discovery failure - " 1694 "StaticTargets method is not enabled"); 1695 iscsi_discovery_event(ihp, 1696 iSCSIDiscoveryMethodStatic, B_FALSE); 1697 continue; 1698 } 1699 1700 /* 1701 * walk list of the statically configured targets from the 1702 * persistent store 1703 */ 1704 v = NULL; 1705 persistent_static_addr_lock(); 1706 while (persistent_static_addr_next(&v, name, &entry) == 1707 B_TRUE) { 1708 iscsi_sockaddr_t addr; 1709 1710 iscsid_addr_to_sockaddr(entry.e_insize, 1711 &(entry.e_u), entry.e_port, &addr.sin); 1712 1713 (void) iscsid_add(ihp, iSCSIDiscoveryMethodStatic, 1714 &addr.sin, name, entry.e_tpgt, &addr.sin); 1715 } 1716 persistent_static_addr_unlock(); 1717 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodStatic, B_FALSE); 1718 } 1719 } 1720 1721 1722 /* 1723 * iscsid_thread_sendtgts -- If SendTargets discovery is enabled, this routine 1724 * obtains all target discovery addresses configured from the peristent store 1725 * and probe the IP/port addresses for possible targets. It will then issue 1726 * a login request to the driver for all discoveryed targets. 1727 */ 1728 static void 1729 iscsid_thread_sendtgts(iscsi_thread_t *thread, void *p) 1730 { 1731 iscsi_hba_t *ihp = (iscsi_hba_t *)p; 1732 iSCSIDiscoveryMethod_t dm; 1733 entry_t entry; 1734 void *v = NULL; 1735 1736 while (iscsi_thread_wait(thread, -1) != 0) { 1737 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSendTargets, 1738 B_TRUE); 1739 1740 /* ---- ensure SendTargets discovery is enabled ---- */ 1741 dm = persistent_disc_meth_get(); 1742 if ((dm & iSCSIDiscoveryMethodSendTargets) == 0) { 1743 cmn_err(CE_NOTE, 1744 "iscsi discovery failure - " 1745 "SendTargets method is not enabled"); 1746 iscsi_discovery_event(ihp, 1747 iSCSIDiscoveryMethodSendTargets, B_FALSE); 1748 continue; 1749 } 1750 /* 1751 * walk list of the SendTarget discovery addresses from the 1752 * persistent store 1753 */ 1754 v = NULL; 1755 persistent_disc_addr_lock(); 1756 while (persistent_disc_addr_next(&v, &entry) == B_TRUE) { 1757 iscsid_do_sendtgts(&entry); 1758 } 1759 persistent_disc_addr_unlock(); 1760 1761 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSendTargets, 1762 B_FALSE); 1763 } 1764 } 1765 1766 /* 1767 * iscsid_thread_slp -- If SLP discovery is enabled, this routine provides 1768 * the SLP discovery service. 1769 */ 1770 static void 1771 iscsid_thread_slp(iscsi_thread_t *thread, void *p) 1772 { 1773 iscsi_hba_t *ihp = (iscsi_hba_t *)p; 1774 1775 do { 1776 /* 1777 * Even though we don't have support for SLP at this point 1778 * we'll send the events if someone has enabled this thread. 1779 * If this is not done the daemon waiting for discovery to 1780 * complete will pause forever holding up the boot process. 1781 */ 1782 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSLP, B_TRUE); 1783 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSLP, B_FALSE); 1784 } while (iscsi_thread_wait(thread, -1) != 0); 1785 } 1786 1787 /* 1788 * iscsid_thread_isns -- 1789 */ 1790 static void 1791 iscsid_thread_isns(iscsi_thread_t *thread, void *ptr) 1792 { 1793 iscsi_hba_t *ihp = (iscsi_hba_t *)ptr; 1794 iSCSIDiscoveryMethod_t dm; 1795 1796 while (iscsi_thread_wait(thread, -1) != 0) { 1797 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodISNS, B_TRUE); 1798 1799 /* ---- ensure iSNS discovery is enabled ---- */ 1800 dm = persistent_disc_meth_get(); 1801 if ((dm & iSCSIDiscoveryMethodISNS) == 0) { 1802 cmn_err(CE_NOTE, 1803 "iscsi discovery failure - " 1804 "iSNS method is not enabled"); 1805 iscsi_discovery_event(ihp, 1806 iSCSIDiscoveryMethodISNS, B_FALSE); 1807 continue; 1808 } 1809 1810 (void) isns_reg(ihp->hba_isid, 1811 ihp->hba_name, 1812 ISCSI_MAX_NAME_LEN, 1813 ihp->hba_alias, 1814 ISCSI_MAX_NAME_LEN, 1815 ISNS_INITIATOR_NODE_TYPE, 1816 isns_scn_callback); 1817 iscsid_do_isns_query(ihp); 1818 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodISNS, B_FALSE); 1819 } 1820 1821 /* Thread stopped. Deregister from iSNS servers(s). */ 1822 (void) isns_dereg(ihp->hba_isid, ihp->hba_name); 1823 } 1824 1825 1826 /* 1827 * iscsid_threads_create -- Creates all the discovery threads. 1828 */ 1829 static void 1830 iscsid_threads_create(iscsi_hba_t *ihp) 1831 { 1832 iscsid_thr_table *t; 1833 1834 /* 1835 * start a thread for each discovery method 1836 */ 1837 for (t = &iscsid_thr[0]; t->method != iSCSIDiscoveryMethodUnknown; 1838 t++) { 1839 if (t->thr_id == NULL) { 1840 t->thr_id = iscsi_thread_create(ihp->hba_dip, t->name, 1841 t->func_start, ihp); 1842 } 1843 } 1844 } 1845 1846 /* 1847 * iscsid_threads_destroy -- Destroys all the discovery threads. 1848 */ 1849 static void 1850 iscsid_threads_destroy(void) 1851 { 1852 iscsid_thr_table *t; 1853 1854 for (t = &iscsid_thr[0]; t->method != iSCSIDiscoveryMethodUnknown; 1855 t++) { 1856 if (t->thr_id != NULL) { 1857 iscsi_thread_destroy(t->thr_id); 1858 t->thr_id = NULL; 1859 } 1860 } 1861 } 1862 1863 /* 1864 * iscsid_copyto_param_set - helper function for iscsid_init_params. 1865 */ 1866 static int 1867 iscsid_copyto_param_set(uint32_t param_id, iscsi_login_params_t *params, 1868 iscsi_param_set_t *ipsp) 1869 { 1870 int rtn = 0; 1871 1872 if (param_id >= ISCSI_NUM_LOGIN_PARAM) { 1873 return (EINVAL); 1874 } 1875 1876 switch (param_id) { 1877 1878 /* 1879 * Boolean parameters 1880 */ 1881 case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER: 1882 ipsp->s_value.v_bool = params->data_pdu_in_order; 1883 break; 1884 case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA: 1885 ipsp->s_value.v_bool = params->immediate_data; 1886 break; 1887 case ISCSI_LOGIN_PARAM_INITIAL_R2T: 1888 ipsp->s_value.v_bool = params->initial_r2t; 1889 break; 1890 case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER: 1891 ipsp->s_value.v_bool = params->data_pdu_in_order; 1892 break; 1893 1894 /* 1895 * Integer parameters 1896 */ 1897 case ISCSI_LOGIN_PARAM_HEADER_DIGEST: 1898 ipsp->s_value.v_integer = params->header_digest; 1899 break; 1900 case ISCSI_LOGIN_PARAM_DATA_DIGEST: 1901 ipsp->s_value.v_integer = params->data_digest; 1902 break; 1903 case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN: 1904 ipsp->s_value.v_integer = params->default_time_to_retain; 1905 break; 1906 case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT: 1907 ipsp->s_value.v_integer = params->default_time_to_wait; 1908 break; 1909 case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH: 1910 ipsp->s_value.v_integer = params->max_recv_data_seg_len; 1911 break; 1912 case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH: 1913 ipsp->s_value.v_integer = params->first_burst_length; 1914 break; 1915 case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH: 1916 ipsp->s_value.v_integer = params->max_burst_length; 1917 break; 1918 1919 /* 1920 * Integer parameters which currently are unsettable 1921 */ 1922 case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS: 1923 case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T: 1924 case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL: 1925 /* ---- drop through to default case ---- */ 1926 default: 1927 rtn = EINVAL; 1928 break; 1929 } 1930 1931 /* if all is well, set the parameter identifier */ 1932 if (rtn == 0) { 1933 ipsp->s_param = param_id; 1934 } 1935 1936 return (rtn); 1937 } 1938 1939 /* 1940 * iscsid_add_pg_list_to_cache - Add portal groups in the list to the 1941 * discovery cache. 1942 */ 1943 static void 1944 iscsid_add_pg_list_to_cache(iscsi_hba_t *ihp, 1945 isns_portal_group_list_t *pg_list) 1946 { 1947 int i; 1948 1949 for (i = 0; i < pg_list->pg_out_cnt; i++) { 1950 iscsi_sockaddr_t addr_dsc; 1951 iscsi_sockaddr_t addr_tgt; 1952 1953 iscsid_addr_to_sockaddr( 1954 pg_list->pg_list[i].isns_server_ip.i_insize, 1955 &pg_list->pg_list[i].isns_server_ip.i_addr, 1956 pg_list->pg_list[i].isns_server_port, 1957 &addr_dsc.sin); 1958 iscsid_addr_to_sockaddr( 1959 pg_list->pg_list[i].insize, 1960 &pg_list->pg_list[i].pg_ip_addr, 1961 pg_list->pg_list[i].pg_port, 1962 &addr_tgt.sin); 1963 1964 (void) iscsid_add(ihp, iSCSIDiscoveryMethodISNS, &addr_dsc.sin, 1965 (char *)pg_list->pg_list[i].pg_iscsi_name, 1966 pg_list->pg_list[i].pg_tag, &addr_tgt.sin); 1967 } 1968 } 1969 1970 /* 1971 * set_initiator_name - set default initiator name and alias. 1972 * 1973 * This sets the default initiator name and alias. The 1974 * initiator name is composed of sun's reverse domain name 1975 * and registration followed and a unique classifier. This 1976 * classifier is the mac address of the first NIC in the 1977 * host and a timestamp to make sure the classifier is 1978 * unique if the NIC is moved between hosts. The alias 1979 * is just the hostname. 1980 */ 1981 void 1982 iscsid_set_default_initiator_node_settings(iscsi_hba_t *ihp, boolean_t minimal) 1983 { 1984 int i; 1985 time_t x; 1986 struct ether_addr eaddr; 1987 char val[10]; 1988 iscsi_chap_props_t *chap = NULL; 1989 1990 /* Set default initiator-node name */ 1991 if (iscsiboot_prop && iscsiboot_prop->boot_init.ini_name != NULL) { 1992 (void) strncpy((char *)ihp->hba_name, 1993 (const char *)iscsiboot_prop->boot_init.ini_name, 1994 ISCSI_MAX_NAME_LEN); 1995 } else { 1996 (void) snprintf((char *)ihp->hba_name, 1997 ISCSI_MAX_NAME_LEN, 1998 "iqn.1986-03.com.sun:01:"); 1999 2000 (void) localetheraddr(NULL, &eaddr); 2001 for (i = 0; i < ETHERADDRL; i++) { 2002 (void) snprintf(val, sizeof (val), "%02x", 2003 eaddr.ether_addr_octet[i]); 2004 (void) strncat((char *)ihp->hba_name, val, 2005 ISCSI_MAX_NAME_LEN); 2006 } 2007 2008 /* Set default initiator-node alias */ 2009 x = ddi_get_time(); 2010 (void) snprintf(val, sizeof (val), ".%lx", x); 2011 (void) strncat((char *)ihp->hba_name, val, ISCSI_MAX_NAME_LEN); 2012 2013 if (ihp->hba_alias[0] == '\0') { 2014 (void) strncpy((char *)ihp->hba_alias, 2015 utsname.nodename, ISCSI_MAX_NAME_LEN); 2016 ihp->hba_alias_length = strlen((char *)ihp->hba_alias); 2017 if (minimal == B_FALSE) { 2018 (void) persistent_alias_name_set( 2019 (char *)ihp->hba_alias); 2020 } 2021 } 2022 } 2023 2024 if (minimal == B_TRUE) { 2025 return; 2026 } 2027 2028 (void) persistent_initiator_name_set((char *)ihp->hba_name); 2029 2030 /* Set default initiator-node CHAP settings */ 2031 if (persistent_initiator_name_get((char *)ihp->hba_name, 2032 ISCSI_MAX_NAME_LEN) == B_TRUE) { 2033 chap = (iscsi_chap_props_t *)kmem_zalloc(sizeof (*chap), 2034 KM_SLEEP); 2035 if (persistent_chap_get((char *)ihp->hba_name, chap) == 2036 B_FALSE) { 2037 bcopy((char *)ihp->hba_name, chap->c_user, 2038 strlen((char *)ihp->hba_name)); 2039 chap->c_user_len = strlen((char *)ihp->hba_name); 2040 (void) persistent_chap_set((char *)ihp->hba_name, chap); 2041 } 2042 kmem_free(chap, sizeof (*chap)); 2043 } 2044 } 2045 2046 static void 2047 iscsid_remove_target_param(char *name) 2048 { 2049 persistent_param_t *pparam; 2050 uint32_t t_oid; 2051 iscsi_config_sess_t *ics; 2052 2053 ASSERT(name != NULL); 2054 2055 /* 2056 * Remove target-param <-> target mapping. 2057 * Only remove if there is not any overridden 2058 * parameters in the persistent store 2059 */ 2060 pparam = (persistent_param_t *)kmem_zalloc(sizeof (*pparam), KM_SLEEP); 2061 2062 /* 2063 * setup initial buffer for configured session 2064 * information 2065 */ 2066 ics = (iscsi_config_sess_t *)kmem_zalloc(sizeof (*ics), KM_SLEEP); 2067 ics->ics_in = 1; 2068 2069 if ((persistent_param_get(name, pparam) == B_FALSE) && 2070 (persistent_get_config_session(name, ics) == B_FALSE)) { 2071 t_oid = iscsi_targetparam_get_oid((uchar_t *)name); 2072 (void) iscsi_targetparam_remove_target(t_oid); 2073 } 2074 2075 kmem_free(pparam, sizeof (*pparam)); 2076 pparam = NULL; 2077 kmem_free(ics, sizeof (*ics)); 2078 ics = NULL; 2079 } 2080 2081 /* 2082 * iscsid_addr_to_sockaddr - convert other types to struct sockaddr 2083 */ 2084 void 2085 iscsid_addr_to_sockaddr(int src_insize, void *src_addr, int src_port, 2086 struct sockaddr *dst_addr) 2087 { 2088 ASSERT((src_insize == sizeof (struct in_addr)) || 2089 (src_insize == sizeof (struct in6_addr))); 2090 ASSERT(src_addr != NULL); 2091 ASSERT(dst_addr != NULL); 2092 2093 bzero(dst_addr, sizeof (*dst_addr)); 2094 2095 /* translate discovery information */ 2096 if (src_insize == sizeof (struct in_addr)) { 2097 struct sockaddr_in *addr_in = 2098 (struct sockaddr_in *)dst_addr; 2099 addr_in->sin_family = AF_INET; 2100 bcopy(src_addr, &addr_in->sin_addr.s_addr, 2101 sizeof (struct in_addr)); 2102 addr_in->sin_port = htons(src_port); 2103 } else { 2104 struct sockaddr_in6 *addr_in6 = 2105 (struct sockaddr_in6 *)dst_addr; 2106 addr_in6->sin6_family = AF_INET6; 2107 bcopy(src_addr, &addr_in6->sin6_addr.s6_addr, 2108 sizeof (struct in6_addr)); 2109 addr_in6->sin6_port = htons(src_port); 2110 } 2111 } 2112 2113 /* 2114 * iscsi_discovery_event -- send event associated with discovery operations 2115 * 2116 * Each discovery event has a start and end event. Which is sent is based 2117 * on the boolean argument start with the obvious results. 2118 */ 2119 static void 2120 iscsi_discovery_event(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t m, 2121 boolean_t start) 2122 { 2123 char *subclass = NULL; 2124 2125 mutex_enter(&ihp->hba_discovery_events_mutex); 2126 switch (m) { 2127 case iSCSIDiscoveryMethodStatic: 2128 if (start == B_TRUE) { 2129 subclass = ESC_ISCSI_STATIC_START; 2130 } else { 2131 ihp->hba_discovery_events |= iSCSIDiscoveryMethodStatic; 2132 subclass = ESC_ISCSI_STATIC_END; 2133 } 2134 break; 2135 2136 case iSCSIDiscoveryMethodSendTargets: 2137 if (start == B_TRUE) { 2138 subclass = ESC_ISCSI_SEND_TARGETS_START; 2139 } else { 2140 ihp->hba_discovery_events |= 2141 iSCSIDiscoveryMethodSendTargets; 2142 subclass = ESC_ISCSI_SEND_TARGETS_END; 2143 } 2144 break; 2145 2146 case iSCSIDiscoveryMethodSLP: 2147 if (start == B_TRUE) { 2148 subclass = ESC_ISCSI_SLP_START; 2149 } else { 2150 ihp->hba_discovery_events |= iSCSIDiscoveryMethodSLP; 2151 subclass = ESC_ISCSI_SLP_END; 2152 } 2153 break; 2154 2155 case iSCSIDiscoveryMethodISNS: 2156 if (start == B_TRUE) { 2157 subclass = ESC_ISCSI_ISNS_START; 2158 } else { 2159 ihp->hba_discovery_events |= iSCSIDiscoveryMethodISNS; 2160 subclass = ESC_ISCSI_ISNS_END; 2161 } 2162 break; 2163 } 2164 mutex_exit(&ihp->hba_discovery_events_mutex); 2165 iscsi_send_sysevent(ihp, EC_ISCSI, subclass, NULL); 2166 } 2167 2168 /* 2169 * iscsi_send_sysevent -- send sysevent using specified class 2170 */ 2171 void 2172 iscsi_send_sysevent( 2173 iscsi_hba_t *ihp, 2174 char *eventclass, 2175 char *subclass, 2176 nvlist_t *np) 2177 { 2178 (void) ddi_log_sysevent(ihp->hba_dip, DDI_VENDOR_SUNW, eventclass, 2179 subclass, np, NULL, DDI_SLEEP); 2180 } 2181 2182 static boolean_t 2183 iscsid_boot_init_config(iscsi_hba_t *ihp) 2184 { 2185 if (strlen((const char *)iscsiboot_prop->boot_init.ini_name) != 0) { 2186 bcopy(iscsiboot_prop->boot_init.ini_name, 2187 ihp->hba_name, 2188 strlen((const char *)iscsiboot_prop->boot_init.ini_name)); 2189 } 2190 /* or using default login param for boot session */ 2191 return (B_TRUE); 2192 } 2193 2194 boolean_t 2195 iscsi_reconfig_boot_sess(iscsi_hba_t *ihp) 2196 { 2197 iscsi_config_sess_t *ics; 2198 int idx; 2199 iscsi_sess_t *isp, *t_isp; 2200 int isid, size; 2201 char *name; 2202 boolean_t rtn = B_TRUE; 2203 2204 if (iscsiboot_prop == NULL) { 2205 return (B_FALSE); 2206 } 2207 size = sizeof (*ics); 2208 ics = kmem_zalloc(size, KM_SLEEP); 2209 ics->ics_in = 1; 2210 2211 /* get information of number of sessions to be configured */ 2212 name = (char *)iscsiboot_prop->boot_tgt.tgt_name; 2213 if (persistent_get_config_session(name, ics) == B_FALSE) { 2214 /* 2215 * No target information available to check 2216 * initiator information. Assume one session 2217 * by default. 2218 */ 2219 name = (char *)iscsiboot_prop->boot_init.ini_name; 2220 if (persistent_get_config_session(name, ics) == B_FALSE) { 2221 ics->ics_out = 1; 2222 ics->ics_bound = B_TRUE; 2223 } 2224 } 2225 2226 /* get necessary information */ 2227 if (ics->ics_out > 1) { 2228 idx = ics->ics_out; 2229 size = ISCSI_SESSION_CONFIG_SIZE(ics->ics_out); 2230 kmem_free(ics, sizeof (*ics)); 2231 2232 ics = kmem_zalloc(size, KM_SLEEP); 2233 ics->ics_in = idx; 2234 2235 /* get configured sessions information */ 2236 if (persistent_get_config_session((char *)name, 2237 ics) != B_TRUE) { 2238 cmn_err(CE_NOTE, "session(%s) - " 2239 "failed to setup multiple sessions", 2240 name); 2241 kmem_free(ics, size); 2242 return (B_FALSE); 2243 } 2244 } 2245 2246 /* create a temporary session to keep boot session connective */ 2247 t_isp = iscsi_add_boot_sess(ihp, ISCSI_MAX_CONFIG_SESSIONS); 2248 if (t_isp == NULL) { 2249 cmn_err(CE_NOTE, "session(%s) - " 2250 "failed to setup multiple sessions", name); 2251 rw_exit(&ihp->hba_sess_list_rwlock); 2252 kmem_free(ics, size); 2253 return (B_FALSE); 2254 } 2255 2256 /* destroy all old boot sessions */ 2257 rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); 2258 isp = ihp->hba_sess_list; 2259 while (isp != NULL) { 2260 if (iscsi_chk_bootlun_mpxio(ihp) && isp->sess_boot) { 2261 if (isp->sess_isid[5] != ISCSI_MAX_CONFIG_SESSIONS) { 2262 /* 2263 * destroy all stale sessions 2264 * except temporary boot session 2265 */ 2266 if (ISCSI_SUCCESS(iscsi_sess_destroy( 2267 isp))) { 2268 isp = ihp->hba_sess_list; 2269 } else { 2270 /* 2271 * couldn't destroy stale sessions 2272 * at least poke it to disconnect 2273 */ 2274 mutex_enter(&isp->sess_state_mutex); 2275 iscsi_sess_state_machine(isp, 2276 ISCSI_SESS_EVENT_N7); 2277 mutex_exit(&isp->sess_state_mutex); 2278 isp = isp->sess_next; 2279 cmn_err(CE_NOTE, "session(%s) - " 2280 "failed to setup multiple" 2281 " sessions", name); 2282 } 2283 } else { 2284 isp = isp->sess_next; 2285 } 2286 } else { 2287 isp = isp->sess_next; 2288 } 2289 } 2290 rw_exit(&ihp->hba_sess_list_rwlock); 2291 2292 for (isid = 0; isid < ics->ics_out; isid++) { 2293 isp = iscsi_add_boot_sess(ihp, isid); 2294 if (isp == NULL) { 2295 cmn_err(CE_NOTE, "session(%s) - failed to setup" 2296 " multiple sessions", name); 2297 rtn = B_FALSE; 2298 break; 2299 } 2300 } 2301 if (!rtn && (isid == 0)) { 2302 /* 2303 * fail to create any new boot session 2304 * so only the temporary session is alive 2305 * quit without destroying it 2306 */ 2307 kmem_free(ics, size); 2308 return (rtn); 2309 } 2310 2311 rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); 2312 if (!ISCSI_SUCCESS(iscsi_sess_destroy(t_isp))) { 2313 /* couldn't destroy temp boot session */ 2314 cmn_err(CE_NOTE, "session(%s) - " 2315 "failed to setup multiple sessions", name); 2316 rw_exit(&ihp->hba_sess_list_rwlock); 2317 rtn = B_FALSE; 2318 } 2319 rw_exit(&ihp->hba_sess_list_rwlock); 2320 2321 kmem_free(ics, size); 2322 return (rtn); 2323 } 2324 2325 static iscsi_sess_t * 2326 iscsi_add_boot_sess(iscsi_hba_t *ihp, int isid) 2327 { 2328 iscsi_sess_t *isp; 2329 iscsi_conn_t *icp; 2330 uint_t oid; 2331 2332 iscsi_sockaddr_t addr_dst; 2333 2334 addr_dst.sin.sa_family = iscsiboot_prop->boot_tgt.sin_family; 2335 if (addr_dst.sin.sa_family == AF_INET) { 2336 bcopy(&iscsiboot_prop->boot_tgt.tgt_ip_u.u_in4.s_addr, 2337 &addr_dst.sin4.sin_addr.s_addr, sizeof (struct in_addr)); 2338 addr_dst.sin4.sin_port = 2339 htons(iscsiboot_prop->boot_tgt.tgt_port); 2340 } else { 2341 bcopy(&iscsiboot_prop->boot_tgt.tgt_ip_u.u_in6.s6_addr, 2342 &addr_dst.sin6.sin6_addr.s6_addr, 2343 sizeof (struct in6_addr)); 2344 addr_dst.sin6.sin6_port = 2345 htons(iscsiboot_prop->boot_tgt.tgt_port); 2346 } 2347 2348 rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); 2349 isp = iscsi_sess_create(ihp, 2350 iSCSIDiscoveryMethodBoot|iSCSIDiscoveryMethodStatic, 2351 (struct sockaddr *)&addr_dst, 2352 (char *)iscsiboot_prop->boot_tgt.tgt_name, 2353 ISCSI_DEFAULT_TPGT, isid, ISCSI_SESS_TYPE_NORMAL, &oid); 2354 if (isp == NULL) { 2355 /* create temp booting session failed */ 2356 rw_exit(&ihp->hba_sess_list_rwlock); 2357 return (NULL); 2358 } 2359 isp->sess_boot = B_TRUE; 2360 2361 if (!ISCSI_SUCCESS(iscsi_conn_create((struct sockaddr *)&addr_dst, 2362 isp, &icp))) { 2363 rw_exit(&ihp->hba_sess_list_rwlock); 2364 return (NULL); 2365 } 2366 2367 rw_exit(&ihp->hba_sess_list_rwlock); 2368 /* now online created session */ 2369 if (iscsid_login_tgt(ihp, (char *)iscsiboot_prop->boot_tgt.tgt_name, 2370 iSCSIDiscoveryMethodBoot|iSCSIDiscoveryMethodStatic, 2371 (struct sockaddr *)&addr_dst) == B_FALSE) { 2372 return (NULL); 2373 } 2374 2375 return (isp); 2376 } 2377 2378 static void 2379 iscsid_thread_boot_wd(iscsi_thread_t *thread, void *p) 2380 { 2381 int rc = 1; 2382 iscsi_hba_t *ihp = (iscsi_hba_t *)p; 2383 boolean_t reconfigured = B_FALSE; 2384 2385 while (rc != 0) { 2386 if (iscsiboot_prop && (modrootloaded == 1)) { 2387 if (ihp->hba_persistent_loaded == B_FALSE) { 2388 if (persistent_load() == B_TRUE) { 2389 ihp->hba_persistent_loaded = B_TRUE; 2390 } 2391 } 2392 if ((ihp->hba_persistent_loaded == B_TRUE) && 2393 (reconfigured == B_FALSE)) { 2394 if (iscsi_chk_bootlun_mpxio(ihp) == B_TRUE) { 2395 (void) iscsi_reconfig_boot_sess(ihp); 2396 iscsid_poke_discovery(ihp, 2397 iSCSIDiscoveryMethodUnknown); 2398 (void) iscsid_login_tgt(ihp, NULL, 2399 iSCSIDiscoveryMethodUnknown, NULL); 2400 } 2401 reconfigured = B_TRUE; 2402 } 2403 break; 2404 } 2405 rc = iscsi_thread_wait(thread, SEC_TO_TICK(1)); 2406 } 2407 } 2408 2409 boolean_t 2410 iscsi_cmp_boot_tgt_name(char *name) 2411 { 2412 if (iscsiboot_prop && (strncmp((const char *)name, 2413 (const char *)iscsiboot_prop->boot_tgt.tgt_name, 2414 ISCSI_MAX_NAME_LEN) == 0)) { 2415 return (B_TRUE); 2416 } else { 2417 return (B_FALSE); 2418 } 2419 } 2420 2421 boolean_t 2422 iscsi_cmp_boot_ini_name(char *name) 2423 { 2424 if (iscsiboot_prop && (strncmp((const char *)name, 2425 (const char *)iscsiboot_prop->boot_init.ini_name, 2426 ISCSI_MAX_NAME_LEN) == 0)) { 2427 return (B_TRUE); 2428 } else { 2429 return (B_FALSE); 2430 } 2431 } 2432 2433 boolean_t 2434 iscsi_chk_bootlun_mpxio(iscsi_hba_t *ihp) 2435 { 2436 iscsi_sess_t *isp; 2437 iscsi_lun_t *ilp; 2438 isp = ihp->hba_sess_list; 2439 boolean_t tgt_mpxio_enabled = B_FALSE; 2440 boolean_t bootlun_found = B_FALSE; 2441 uint16_t lun_num; 2442 2443 if (iscsiboot_prop == NULL) { 2444 return (B_FALSE); 2445 } 2446 2447 if (!ihp->hba_mpxio_enabled) { 2448 return (B_FALSE); 2449 } 2450 2451 lun_num = *((uint64_t *)(iscsiboot_prop->boot_tgt.tgt_boot_lun)); 2452 2453 while (isp != NULL) { 2454 if ((strncmp((char *)isp->sess_name, 2455 (const char *)iscsiboot_prop->boot_tgt.tgt_name, 2456 ISCSI_MAX_NAME_LEN) == 0) && 2457 (isp->sess_boot == B_TRUE)) { 2458 /* 2459 * found boot session. 2460 * check its mdi path info is null or not 2461 */ 2462 ilp = isp->sess_lun_list; 2463 while (ilp != NULL) { 2464 if (lun_num == ilp->lun_num) { 2465 if (ilp->lun_pip) { 2466 tgt_mpxio_enabled = B_TRUE; 2467 } 2468 bootlun_found = B_TRUE; 2469 } 2470 ilp = ilp->lun_next; 2471 } 2472 } 2473 isp = isp->sess_next; 2474 } 2475 if (bootlun_found) { 2476 return (tgt_mpxio_enabled); 2477 } else { 2478 /* 2479 * iscsiboot_prop not NULL while no boot lun found 2480 * in most cases this is none iscsi boot while iscsiboot_prop 2481 * is not NULL, in this scenario return iscsi HBA's mpxio config 2482 */ 2483 return (ihp->hba_mpxio_enabled); 2484 } 2485 } 2486 2487 static boolean_t 2488 iscsid_check_active_boot_conn(iscsi_hba_t *ihp) 2489 { 2490 iscsi_sess_t *isp = NULL; 2491 iscsi_conn_t *icp = NULL; 2492 2493 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 2494 isp = ihp->hba_sess_list; 2495 while (isp != NULL) { 2496 if (isp->sess_boot == B_TRUE) { 2497 rw_enter(&isp->sess_conn_list_rwlock, RW_READER); 2498 icp = isp->sess_conn_list; 2499 while (icp != NULL) { 2500 if (icp->conn_state == 2501 ISCSI_CONN_STATE_LOGGED_IN) { 2502 rw_exit(&isp->sess_conn_list_rwlock); 2503 rw_exit(&ihp->hba_sess_list_rwlock); 2504 return (B_TRUE); 2505 } 2506 icp = icp->conn_next; 2507 } 2508 rw_exit(&isp->sess_conn_list_rwlock); 2509 } 2510 isp = isp->sess_next; 2511 } 2512 rw_exit(&ihp->hba_sess_list_rwlock); 2513 2514 return (B_FALSE); 2515 } 2516