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