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 2008 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 45 /* 46 * local function prototypes 47 */ 48 static boolean_t iscsid_init_config(iscsi_hba_t *ihp); 49 static boolean_t iscsid_init_targets(iscsi_hba_t *ihp); 50 static void iscsid_thread_static(iscsi_thread_t *thread, void *p); 51 static void iscsid_thread_sendtgts(iscsi_thread_t *thread, void *p); 52 static void iscsid_thread_isns(iscsi_thread_t *thread, void *p); 53 static void iscsid_thread_slp(iscsi_thread_t *thread, void *p); 54 static void iscsid_threads_create(iscsi_hba_t *ihp); 55 static void iscsid_threads_destroy(void); 56 static int iscsid_copyto_param_set(uint32_t param_id, 57 iscsi_login_params_t *params, iscsi_param_set_t *ipsp); 58 static void iscsid_add_pg_list_to_cache(iscsi_hba_t *ihp, 59 isns_portal_group_list_t *pg_list); 60 static void iscsid_set_default_initiator_node_settings(iscsi_hba_t *ihp); 61 static void iscsid_remove_target_param(char *name); 62 static boolean_t iscsid_add(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method, 63 struct sockaddr *addr_dsc, char *target_name, int tpgt, 64 struct sockaddr *addr_tgt); 65 66 static void iscsi_discovery_event(iscsi_hba_t *ihp, 67 iSCSIDiscoveryMethod_t m, boolean_t start); 68 static void iscsi_send_sysevent(iscsi_hba_t *ihp, 69 char *subclass, nvlist_t *np); 70 71 /* 72 * iSCSI target discovery thread table 73 */ 74 typedef struct iscsid_thr_table { 75 void (*func_start)(iscsi_thread_t *, void *); 76 iscsi_thread_t *thr_id; 77 iSCSIDiscoveryMethod_t method; 78 char *name; 79 } iscsid_thr_table; 80 81 static iscsid_thr_table iscsid_thr[] = { 82 { iscsid_thread_static, NULL, 83 iSCSIDiscoveryMethodStatic, 84 "Static" }, 85 { iscsid_thread_sendtgts, NULL, 86 iSCSIDiscoveryMethodSendTargets, 87 "SendTarget" }, 88 { iscsid_thread_slp, NULL, 89 iSCSIDiscoveryMethodSLP, 90 "SLP" }, 91 { iscsid_thread_isns, NULL, 92 iSCSIDiscoveryMethodISNS, 93 "iSNS" }, 94 { NULL, NULL, 95 iSCSIDiscoveryMethodUnknown, 96 NULL } 97 }; 98 99 100 /* 101 * discovery method event table 102 */ 103 iSCSIDiscoveryMethod_t for_failure[] = { 104 iSCSIDiscoveryMethodStatic, 105 iSCSIDiscoveryMethodSLP, 106 iSCSIDiscoveryMethodISNS, 107 iSCSIDiscoveryMethodSendTargets, 108 iSCSIDiscoveryMethodUnknown /* terminating value */ 109 }; 110 111 /* 112 * discovery configuration semaphore 113 */ 114 ksema_t iscsid_config_semaphore; 115 116 #define CHECK_METHOD(v) ((dm & v) ? B_TRUE : B_FALSE) 117 118 /* 119 * iscsid_init -- load data from persistent storage and start discovery threads 120 * 121 * If restart is B_TRUE than someone has issued an ISCSI_DB_RELOAD ioctl. 122 * The most likely reason is that a new database has been copied into 123 * /etc/iscsi and the driver needs to read the contents. 124 */ 125 boolean_t 126 iscsid_init(iscsi_hba_t *ihp, boolean_t restart) 127 { 128 boolean_t rval = B_FALSE; 129 iSCSIDiscoveryMethod_t dm; 130 iSCSIDiscoveryMethod_t *fdm; 131 132 sema_init(&iscsid_config_semaphore, 1, NULL, 133 SEMA_DRIVER, NULL); 134 135 rval = persistent_init(restart); 136 if (rval == B_TRUE) { 137 rval = iscsid_init_config(ihp); 138 if (rval == B_TRUE) { 139 rval = iscsid_init_targets(ihp); 140 } 141 } 142 143 if (rval == B_TRUE) { 144 if (restart == B_FALSE) { 145 iscsid_threads_create(ihp); 146 } 147 148 dm = persistent_disc_meth_get(); 149 rval = iscsid_enable_discovery(ihp, dm, B_FALSE); 150 if (rval == B_TRUE) { 151 rval = iscsid_disable_discovery(ihp, ~dm); 152 } 153 } 154 155 if (rval == B_FALSE) { 156 /* 157 * In case of failure the events still need to be sent 158 * because the door daemon will pause until all these 159 * events have occurred. 160 */ 161 for (fdm = &for_failure[0]; *fdm != iSCSIDiscoveryMethodUnknown; 162 fdm++) { 163 /* ---- Send both start and end events ---- */ 164 iscsi_discovery_event(ihp, *fdm, B_TRUE); 165 iscsi_discovery_event(ihp, *fdm, B_FALSE); 166 } 167 } 168 169 return (rval); 170 } 171 172 /* 173 * iscsid_fini -- do whatever is required to clean up 174 */ 175 /* ARGSUSED */ 176 void 177 iscsid_fini() 178 { 179 iscsid_threads_destroy(); 180 persistent_fini(); 181 sema_destroy(&iscsid_config_semaphore); 182 } 183 184 /* 185 * iscsid_props -- returns discovery thread information, used by ioctl code 186 */ 187 void 188 iscsid_props(iSCSIDiscoveryProperties_t *props) 189 { 190 iSCSIDiscoveryMethod_t dm; 191 192 dm = persistent_disc_meth_get(); 193 194 props->vers = ISCSI_INTERFACE_VERSION; 195 196 /* ---- change once thread is implemented ---- */ 197 props->iSNSDiscoverySettable = B_FALSE; 198 props->SLPDiscoverySettable = B_FALSE; 199 props->StaticDiscoverySettable = B_TRUE; 200 props->SendTargetsDiscoverySettable = B_TRUE; 201 props->iSNSDiscoveryMethod = iSNSDiscoveryMethodStatic; 202 203 props->iSNSDiscoveryEnabled = CHECK_METHOD(iSCSIDiscoveryMethodISNS); 204 props->StaticDiscoveryEnabled = 205 CHECK_METHOD(iSCSIDiscoveryMethodStatic); 206 props->SendTargetsDiscoveryEnabled = 207 CHECK_METHOD(iSCSIDiscoveryMethodSendTargets); 208 props->SLPDiscoveryEnabled = CHECK_METHOD(iSCSIDiscoveryMethodSLP); 209 } 210 211 /* 212 * iscsid_enable_discovery - start specified discovery methods 213 */ 214 /* ARGSUSED */ 215 boolean_t 216 iscsid_enable_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t idm, 217 boolean_t poke) 218 { 219 boolean_t rval = B_TRUE; 220 iscsid_thr_table *dt; 221 222 /* 223 * start the specified discovery method(s) 224 */ 225 for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown; 226 dt++) { 227 if (idm & dt->method) { 228 if (dt->thr_id != NULL) { 229 rval = iscsi_thread_start(dt->thr_id); 230 if (rval == B_FALSE) { 231 break; 232 } 233 if (poke == B_TRUE) { 234 iscsi_thread_send_wakeup(dt->thr_id); 235 } 236 } else { 237 /* 238 * unexpected condition. The threads for each 239 * discovery method should have started at 240 * initialization 241 */ 242 ASSERT(B_FALSE); 243 } 244 } 245 } /* END for() */ 246 247 return (rval); 248 } 249 250 251 /* 252 * iscsid_disable_discovery - stop specified discovery methods 253 */ 254 boolean_t 255 iscsid_disable_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t idm) 256 { 257 boolean_t rval = B_TRUE; 258 iscsid_thr_table *dt; 259 260 /* 261 * stop the specified discovery method(s) 262 */ 263 for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown; 264 dt++) { 265 if (idm & dt->method) { 266 267 /* signal discovery event change - begin */ 268 iscsi_discovery_event(ihp, dt->method, B_TRUE); 269 270 /* Attempt to logout of all associated targets */ 271 rval = iscsid_del(ihp, NULL, dt->method, NULL); 272 if (rval == B_TRUE) { 273 /* Successfully logged out of targets */ 274 if (dt->thr_id != NULL) { 275 rval = iscsi_thread_stop(dt->thr_id); 276 if (rval == B_FALSE) { 277 /* 278 * signal discovery 279 * event change - end 280 */ 281 iscsi_discovery_event(ihp, 282 dt->method, B_FALSE); 283 break; 284 } 285 286 } else { 287 /* 288 * unexpected condition. The threads 289 * for each discovery method should 290 * have started at initialization 291 */ 292 ASSERT(B_FALSE); 293 } 294 } 295 296 /* signal discovery event change - end */ 297 iscsi_discovery_event(ihp, dt->method, B_FALSE); 298 299 } 300 } /* END for() */ 301 302 return (rval); 303 } 304 305 /* 306 * iscsid_poke_discovery - wakeup discovery methods to find any new targets 307 * and wait for all discovery processes to complete. 308 */ 309 void 310 iscsid_poke_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method) 311 { 312 #define ISCSI_DISCOVERY_DELAY 1 313 314 iSCSIDiscoveryMethod_t dm; 315 iscsid_thr_table *dt; 316 317 ASSERT(ihp != NULL); 318 319 /* reset discovery flags */ 320 mutex_enter(&ihp->hba_discovery_events_mutex); 321 ihp->hba_discovery_in_progress = B_TRUE; 322 ihp->hba_discovery_events = iSCSIDiscoveryMethodUnknown; 323 mutex_exit(&ihp->hba_discovery_events_mutex); 324 325 /* start all enabled discovery methods */ 326 dm = persistent_disc_meth_get(); 327 for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown; 328 dt++) { 329 if ((method == iSCSIDiscoveryMethodUnknown) || 330 (method == dt->method)) { 331 if ((dm & dt->method) && (dt->thr_id != NULL)) { 332 iscsi_thread_send_wakeup(dt->thr_id); 333 } else { 334 iscsi_discovery_event(ihp, dt->method, B_TRUE); 335 iscsi_discovery_event(ihp, dt->method, B_FALSE); 336 } 337 } else { 338 iscsi_discovery_event(ihp, dt->method, B_TRUE); 339 iscsi_discovery_event(ihp, dt->method, B_FALSE); 340 } 341 } 342 343 mutex_enter(&ihp->hba_discovery_events_mutex); 344 while (ihp->hba_discovery_events != ISCSI_ALL_DISCOVERY_METHODS) { 345 mutex_exit(&ihp->hba_discovery_events_mutex); 346 delay(SEC_TO_TICK(ISCSI_DISCOVERY_DELAY)); 347 mutex_enter(&ihp->hba_discovery_events_mutex); 348 } 349 ihp->hba_discovery_in_progress = B_FALSE; 350 mutex_exit(&ihp->hba_discovery_events_mutex); 351 352 } 353 354 /* 355 * iscsid_do_sendtgts - issue send targets command to the given discovery 356 * address and then add the discovered targets to the discovery queue 357 */ 358 void 359 iscsid_do_sendtgts(entry_t *disc_addr) 360 { 361 362 #define SENDTGTS_DEFAULT_NUM_TARGETS 10 363 364 int stl_sz; 365 int stl_num_tgts = SENDTGTS_DEFAULT_NUM_TARGETS; 366 iscsi_sendtgts_list_t *stl_hdr = NULL; 367 boolean_t retry = B_TRUE; 368 char inp_buf[INET6_ADDRSTRLEN]; 369 const char *ip; 370 int ctr; 371 int rc; 372 iscsi_hba_t *ihp; 373 374 /* allocate and initialize sendtargets list header */ 375 stl_sz = sizeof (*stl_hdr) + ((stl_num_tgts - 1) * 376 sizeof (iscsi_sendtgts_entry_t)); 377 stl_hdr = kmem_zalloc(stl_sz, KM_SLEEP); 378 379 retry_sendtgts: 380 stl_hdr->stl_in_cnt = stl_num_tgts; 381 bcopy(disc_addr, &(stl_hdr->stl_entry), 382 sizeof (stl_hdr->stl_entry)); 383 stl_hdr->stl_entry.e_vers = ISCSI_INTERFACE_VERSION; 384 385 /* lock interface so only one SendTargets operation occurs */ 386 if ((ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, 0)) == NULL) { 387 cmn_err(CE_NOTE, "!iscsi discovery failure - SendTargets. " 388 "failure to get soft state"); 389 kmem_free(stl_hdr, stl_sz); 390 return; 391 } 392 sema_p(&ihp->hba_sendtgts_semaphore); 393 rc = iscsi_ioctl_sendtgts_get(ihp, stl_hdr); 394 sema_v(&ihp->hba_sendtgts_semaphore); 395 if (rc) { 396 ip = inet_ntop((disc_addr->e_insize == 397 sizeof (struct in_addr) ? AF_INET : AF_INET6), 398 &disc_addr->e_u, inp_buf, sizeof (inp_buf)); 399 cmn_err(CE_NOTE, 400 "iscsi discovery failure - SendTargets (%s)\n", ip); 401 kmem_free(stl_hdr, stl_sz); 402 return; 403 } 404 405 /* check if all targets received */ 406 if (stl_hdr->stl_in_cnt < stl_hdr->stl_out_cnt) { 407 if (retry == B_TRUE) { 408 stl_num_tgts = stl_hdr->stl_out_cnt; 409 kmem_free(stl_hdr, stl_sz); 410 stl_sz = sizeof (*stl_hdr) + 411 ((stl_num_tgts - 1) * 412 sizeof (iscsi_sendtgts_entry_t)); 413 stl_hdr = kmem_zalloc(stl_sz, KM_SLEEP); 414 retry = B_FALSE; 415 goto retry_sendtgts; 416 } else { 417 ip = inet_ntop((disc_addr->e_insize == 418 sizeof (struct in_addr) ? 419 AF_INET : AF_INET6), &disc_addr->e_u, 420 inp_buf, sizeof (inp_buf)); 421 cmn_err(CE_NOTE, "iscsi discovery failure - " 422 "SendTargets overflow (%s)\n", ip); 423 kmem_free(stl_hdr, stl_sz); 424 return; 425 } 426 } 427 428 for (ctr = 0; ctr < stl_hdr->stl_out_cnt; ctr++) { 429 iscsi_sockaddr_t addr_dsc; 430 iscsi_sockaddr_t addr_tgt; 431 432 iscsid_addr_to_sockaddr(disc_addr->e_insize, 433 &disc_addr->e_u, disc_addr->e_port, &addr_dsc.sin); 434 iscsid_addr_to_sockaddr( 435 stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize, 436 &(stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_addr), 437 stl_hdr->stl_list[ctr].ste_ipaddr.a_port, 438 &addr_tgt.sin); 439 440 (void) iscsid_add(ihp, iSCSIDiscoveryMethodSendTargets, 441 &addr_dsc.sin, (char *)stl_hdr->stl_list[ctr].ste_name, 442 stl_hdr->stl_list[ctr].ste_tpgt, 443 &addr_tgt.sin); 444 } 445 kmem_free(stl_hdr, stl_sz); 446 } 447 448 void 449 iscsid_do_isns_query_one_server(iscsi_hba_t *ihp, entry_t *isns_server) 450 { 451 int pg_sz, query_status; 452 iscsi_addr_t *ap; 453 isns_portal_group_list_t *pg_list; 454 455 ap = (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP); 456 ap->a_port = isns_server->e_port; 457 ap->a_addr.i_insize = isns_server->e_insize; 458 459 if (isns_server->e_insize == sizeof (struct in_addr)) { 460 ap->a_addr.i_addr.in4.s_addr = (isns_server->e_u.u_in4.s_addr); 461 } else if (isns_server->e_insize == sizeof (struct in6_addr)) { 462 bcopy(&(isns_server->e_u.u_in6.s6_addr), 463 ap->a_addr.i_addr.in6.s6_addr, 16); 464 } else { 465 kmem_free(ap, sizeof (iscsi_addr_t)); 466 return; 467 } 468 469 pg_list = NULL; 470 query_status = isns_query_one_server( 471 ap, ihp->hba_isid, 472 ihp->hba_name, ihp->hba_alias, 473 ISNS_INITIATOR_NODE_TYPE, &pg_list); 474 kmem_free(ap, sizeof (iscsi_addr_t)); 475 if (query_status != isns_ok || pg_list == NULL) { 476 DTRACE_PROBE1(iscsid_do_isns_query_one_server_status, 477 int, query_status); 478 return; 479 } 480 481 iscsid_add_pg_list_to_cache(ihp, pg_list); 482 pg_sz = sizeof (isns_portal_group_list_t); 483 if (pg_list->pg_out_cnt > 0) { 484 pg_sz += (pg_list->pg_out_cnt - 1) * 485 sizeof (isns_portal_group_t); 486 } 487 kmem_free(pg_list, pg_sz); 488 } 489 490 void 491 iscsid_do_isns_query(iscsi_hba_t *ihp) 492 { 493 int pg_sz, query_status; 494 isns_portal_group_list_t *pg_list; 495 496 pg_list = NULL; 497 query_status = isns_query(ihp->hba_isid, 498 ihp->hba_name, 499 ihp->hba_alias, 500 ISNS_INITIATOR_NODE_TYPE, 501 &pg_list); 502 if ((query_status != isns_ok && 503 query_status != isns_op_partially_failed) || 504 pg_list == NULL) { 505 DTRACE_PROBE1(iscsid_do_isns_query_status, 506 int, query_status); 507 return; 508 } 509 iscsid_add_pg_list_to_cache(ihp, pg_list); 510 511 pg_sz = sizeof (isns_portal_group_list_t); 512 if (pg_list->pg_out_cnt > 0) { 513 pg_sz += (pg_list->pg_out_cnt - 1) * 514 sizeof (isns_portal_group_t); 515 } 516 kmem_free(pg_list, pg_sz); 517 } 518 519 /* 520 * iscsid_config_one - for the given target name, attempt 521 * to login to all targets associated with name. If target 522 * name is not found in discovery queue, reset the discovery 523 * queue, kick the discovery processes, and then retry. 524 * 525 * NOTE: The caller of this function must hold the 526 * iscsid_config_semaphore across this call. 527 */ 528 void 529 iscsid_config_one(iscsi_hba_t *ihp, char *name, boolean_t protect) 530 { 531 boolean_t rc; 532 533 rc = iscsid_login_tgt(ihp, name, 534 iSCSIDiscoveryMethodUnknown, NULL); 535 /* 536 * If we didn't login to the device we might have 537 * to update our discovery information and attempt 538 * the login again. 539 */ 540 if (rc == B_FALSE) { 541 /* 542 * Stale /dev links can cause us to get floods 543 * of config requests. Prevent these repeated 544 * requests from causing unneeded discovery updates 545 * if ISCSI_CONFIG_STORM_PROTECT is set. 546 */ 547 if ((protect == B_FALSE) || 548 (ddi_get_lbolt() > ihp->hba_config_lbolt + 549 SEC_TO_TICK(ihp->hba_config_storm_delay))) { 550 ihp->hba_config_lbolt = ddi_get_lbolt(); 551 iscsid_poke_discovery(ihp, iSCSIDiscoveryMethodUnknown); 552 (void) iscsid_login_tgt(ihp, name, 553 iSCSIDiscoveryMethodUnknown, NULL); 554 } 555 } 556 } 557 558 /* 559 * iscsid_config_all - reset the discovery queue, kick the 560 * discovery processes, and login to all targets found 561 * 562 * NOTE: The caller of this function must hold the 563 * iscsid_config_semaphore across this call. 564 */ 565 void 566 iscsid_config_all(iscsi_hba_t *ihp, boolean_t protect) 567 { 568 /* 569 * Stale /dev links can cause us to get floods 570 * of config requests. Prevent these repeated 571 * requests from causing unneeded discovery updates 572 * if ISCSI_CONFIG_STORM_PROTECT is set. 573 */ 574 if ((protect == B_FALSE) || 575 (ddi_get_lbolt() > ihp->hba_config_lbolt + 576 SEC_TO_TICK(ihp->hba_config_storm_delay))) { 577 ihp->hba_config_lbolt = ddi_get_lbolt(); 578 iscsid_poke_discovery(ihp, iSCSIDiscoveryMethodUnknown); 579 } 580 (void) iscsid_login_tgt(ihp, NULL, 581 iSCSIDiscoveryMethodUnknown, NULL); 582 } 583 584 /* 585 * isns_scn_callback - iSNS client received an SCN 586 * 587 * This code processes the iSNS client SCN events. These 588 * could relate to the addition, removal, or update of a 589 * logical unit. 590 */ 591 void 592 isns_scn_callback(void *arg) 593 { 594 int i, pg_sz; 595 int qry_status; 596 isns_portal_group_list_t *pg_list; 597 uint32_t scn_type; 598 iscsi_hba_t *ihp; 599 600 if (arg == NULL) { 601 /* No argument */ 602 return; 603 } 604 605 if ((ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, 0)) == NULL) { 606 return; 607 } 608 609 scn_type = ((isns_scn_callback_arg_t *)arg)->scn_type; 610 DTRACE_PROBE1(isns_scn_callback_scn_type, int, scn_type); 611 switch (scn_type) { 612 /* 613 * ISNS_OBJ_ADDED - An object has been added. 614 */ 615 case ISNS_OBJ_ADDED: 616 /* Query iSNS server for contact information */ 617 pg_list = NULL; 618 qry_status = isns_query_one_node( 619 ((isns_scn_callback_arg_t *)arg)->source_key_attr, 620 ihp->hba_isid, 621 ihp->hba_name, 622 (uint8_t *)"", 623 ISNS_INITIATOR_NODE_TYPE, 624 &pg_list); 625 626 /* Verify portal group is found */ 627 if ((qry_status != isns_ok && 628 qry_status != isns_op_partially_failed) || 629 pg_list == NULL) { 630 break; 631 } 632 633 DTRACE_PROBE1(pg_list, 634 isns_portal_group_list_t *, pg_list); 635 636 /* Add all portals for logical unit to discovery cache */ 637 for (i = 0; i < pg_list->pg_out_cnt; i++) { 638 iscsi_sockaddr_t addr_dsc; 639 iscsi_sockaddr_t addr_tgt; 640 641 iscsid_addr_to_sockaddr( 642 pg_list->pg_list[i].isns_server_ip.i_insize, 643 &pg_list->pg_list[i].isns_server_ip.i_addr, 644 pg_list->pg_list[i].isns_server_port, 645 &addr_dsc.sin); 646 iscsid_addr_to_sockaddr(pg_list->pg_list[i].insize, 647 &pg_list->pg_list[i].pg_ip_addr, 648 pg_list->pg_list[i].pg_port, &addr_tgt.sin); 649 650 (void) iscsid_add(ihp, iSCSIDiscoveryMethodISNS, 651 &addr_dsc.sin, (char *)pg_list->pg_list[i]. 652 pg_iscsi_name, pg_list->pg_list[i].pg_tag, 653 &addr_tgt.sin); 654 655 /* Force target to login */ 656 (void) iscsid_login_tgt(ihp, (char *)pg_list-> 657 pg_list[i].pg_iscsi_name, iSCSIDiscoveryMethodISNS, 658 NULL); 659 } 660 661 if (pg_list != NULL) { 662 pg_sz = sizeof (isns_portal_group_list_t); 663 if (pg_list->pg_out_cnt > 0) { 664 pg_sz += (pg_list->pg_out_cnt - 1) * 665 sizeof (isns_portal_group_t); 666 } 667 kmem_free(pg_list, pg_sz); 668 } 669 break; 670 671 /* 672 * ISNS_OBJ_REMOVED - logical unit has been removed 673 */ 674 case ISNS_OBJ_REMOVED: 675 if (iscsid_del(ihp, 676 (char *)((isns_scn_callback_arg_t *)arg)-> 677 source_key_attr, iSCSIDiscoveryMethodISNS, NULL) != 678 B_TRUE) { 679 cmn_err(CE_NOTE, "iscsi initiator - " 680 "isns remove scn failed for target %s\n", 681 (char *)((isns_scn_callback_arg_t *)arg)-> 682 source_key_attr); 683 684 } 685 break; 686 687 /* 688 * ISNS_OBJ_UPDATED - logical unit has changed 689 */ 690 case ISNS_OBJ_UPDATED: 691 cmn_err(CE_NOTE, "iscsi initiator - " 692 "received iSNS update SCN for %s\n", 693 (char *)((isns_scn_callback_arg_t *)arg)-> 694 source_key_attr); 695 break; 696 697 /* 698 * ISNS_OBJ_UNKNOWN - 699 */ 700 default: 701 cmn_err(CE_NOTE, "iscsi initiator - " 702 "received unknown iSNS SCN type 0x%x\n", scn_type); 703 break; 704 } 705 706 kmem_free(arg, sizeof (isns_scn_callback_arg_t)); 707 } 708 709 710 /* 711 * iscsid_add - Creates discovered session and connection 712 */ 713 static boolean_t 714 iscsid_add(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method, 715 struct sockaddr *addr_dsc, char *target_name, int tpgt, 716 struct sockaddr *addr_tgt) 717 { 718 boolean_t rtn = B_TRUE; 719 iscsi_sess_t *isp; 720 iscsi_conn_t *icp; 721 uint_t oid; 722 int idx; 723 int isid; 724 iscsi_config_sess_t *ics; 725 int size; 726 char *tmp; 727 728 ASSERT(ihp != NULL); 729 ASSERT(addr_dsc != NULL); 730 ASSERT(target_name != NULL); 731 ASSERT(addr_tgt != NULL); 732 733 /* setup initial buffer for configured session information */ 734 size = sizeof (*ics); 735 ics = kmem_zalloc(size, KM_SLEEP); 736 ics->ics_in = 1; 737 738 /* get configured sessions information */ 739 tmp = target_name; 740 if (persistent_get_config_session(tmp, ics) == B_FALSE) { 741 /* 742 * No target information available check for 743 * initiator information. 744 */ 745 tmp = (char *)ihp->hba_name; 746 if (persistent_get_config_session(tmp, ics) == B_FALSE) { 747 /* 748 * No hba information is 749 * found. So assume default 750 * one session unbound behavior. 751 */ 752 ics->ics_out = 1; 753 ics->ics_bound = B_TRUE; 754 } 755 } 756 757 /* Check to see if we need to get more information */ 758 if (ics->ics_out > 1) { 759 /* record new size and free last buffer */ 760 idx = ics->ics_out; 761 size = ISCSI_SESSION_CONFIG_SIZE(ics->ics_out); 762 kmem_free(ics, sizeof (*ics)); 763 764 /* allocate new buffer */ 765 ics = kmem_zalloc(size, KM_SLEEP); 766 ics->ics_in = idx; 767 768 /* get configured sessions information */ 769 if (persistent_get_config_session(tmp, ics) != B_TRUE) { 770 cmn_err(CE_NOTE, "iscsi session(%s) - " 771 "unable to get configured session information\n", 772 target_name); 773 kmem_free(ics, size); 774 return (B_FALSE); 775 } 776 } 777 778 /* loop for all configured sessions */ 779 rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); 780 for (isid = 0; isid < ics->ics_out; isid++) { 781 /* create or find matching session */ 782 isp = iscsi_sess_create(ihp, method, addr_dsc, target_name, 783 tpgt, isid, ISCSI_SESS_TYPE_NORMAL, &oid); 784 if (isp == NULL) { 785 rtn = B_FALSE; 786 break; 787 } 788 789 /* create or find matching connection */ 790 if (!ISCSI_SUCCESS(iscsi_conn_create(addr_tgt, isp, &icp))) { 791 rtn = B_FALSE; 792 break; 793 } 794 } 795 rw_exit(&ihp->hba_sess_list_rwlock); 796 kmem_free(ics, size); 797 return (rtn); 798 } 799 800 /* 801 * iscsid_del - Attempts to delete all associated sessions 802 */ 803 boolean_t 804 iscsid_del(iscsi_hba_t *ihp, char *target_name, 805 iSCSIDiscoveryMethod_t method, struct sockaddr *addr_dsc) 806 { 807 boolean_t rtn = B_TRUE; 808 iscsi_status_t status; 809 iscsi_sess_t *isp; 810 char name[ISCSI_MAX_NAME_LEN]; 811 812 ASSERT(ihp != NULL); 813 /* target name can be NULL or !NULL */ 814 /* addr_dsc can be NULL or !NULL */ 815 816 rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); 817 isp = ihp->hba_sess_list; 818 while (isp != NULL) { 819 /* 820 * If no target_name is listed (meaning all targets) 821 * or this specific target was listed. And the same 822 * discovery method discovered this target then 823 * continue evaulation. Otherwise fail. 824 */ 825 if (((target_name == NULL) || 826 (strcmp((char *)isp->sess_name, target_name) == 0)) && 827 (isp->sess_discovered_by == method)) { 828 boolean_t try_destroy; 829 830 /* 831 * If iSNS, SendTargets, or Static then special 832 * handling for disc_addr. 833 */ 834 if ((method == iSCSIDiscoveryMethodISNS) || 835 (method == iSCSIDiscoveryMethodSendTargets)) { 836 /* 837 * If NULL addr_dsc (meaning all disc_addr) 838 * or matching discovered addr. 839 */ 840 if ((addr_dsc == NULL) || 841 (bcmp(addr_dsc, &isp->sess_discovered_addr, 842 SIZEOF_SOCKADDR( 843 &isp->sess_discovered_addr.sin)) == 0)) { 844 try_destroy = B_TRUE; 845 } else { 846 try_destroy = B_FALSE; 847 } 848 } else if (method == iSCSIDiscoveryMethodStatic) { 849 /* 850 * If NULL addr_dsc (meaning all disc_addr) 851 * or matching active connection. 852 */ 853 if ((addr_dsc == NULL) || 854 ((isp->sess_conn_act != NULL) && 855 (bcmp(addr_dsc, 856 &isp->sess_conn_act->conn_base_addr.sin, 857 SIZEOF_SOCKADDR( 858 &isp->sess_conn_act->conn_base_addr.sin)) 859 == 0))) { 860 try_destroy = B_TRUE; 861 } else { 862 try_destroy = B_FALSE; 863 } 864 } else { 865 /* Unknown discovery specified */ 866 try_destroy = B_TRUE; 867 } 868 869 if (try_destroy == B_TRUE) { 870 (void) strcpy(name, (char *)isp->sess_name); 871 status = iscsi_sess_destroy(isp); 872 if (ISCSI_SUCCESS(status)) { 873 iscsid_remove_target_param(name); 874 isp = ihp->hba_sess_list; 875 } else { 876 /* 877 * The most likely destroy failure 878 * is that ndi/mdi offline failed. 879 * This means that the resource is 880 * in_use/busy. 881 */ 882 cmn_err(CE_NOTE, "iscsi session(%d) - " 883 "session logout failed (%d)\n", 884 isp->sess_oid, status); 885 isp = isp->sess_next; 886 rtn = B_FALSE; 887 } 888 } else { 889 isp = isp->sess_next; 890 } 891 } else { 892 isp = isp->sess_next; 893 } 894 } 895 rw_exit(&ihp->hba_sess_list_rwlock); 896 return (rtn); 897 } 898 899 900 /* 901 * iscsid_login_tgt - request target(s) to login 902 */ 903 boolean_t 904 iscsid_login_tgt(iscsi_hba_t *ihp, char *target_name, 905 iSCSIDiscoveryMethod_t method, struct sockaddr *addr_dsc) 906 { 907 boolean_t rtn = B_FALSE; 908 iscsi_sess_t *isp; 909 910 ASSERT(ihp != NULL); 911 912 rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); 913 /* Loop thru sessions */ 914 isp = ihp->hba_sess_list; 915 while (isp != NULL) { 916 boolean_t try_online; 917 918 if (target_name == NULL) { 919 if (method == iSCSIDiscoveryMethodUnknown) { 920 /* unknown method mean login to all */ 921 try_online = B_TRUE; 922 } else if (isp->sess_discovered_by & method) { 923 if ((method == iSCSIDiscoveryMethodISNS) || 924 (method == 925 iSCSIDiscoveryMethodSendTargets)) { 926 if ((addr_dsc == NULL) || 927 (bcmp(&isp->sess_discovered_addr, 928 addr_dsc, SIZEOF_SOCKADDR( 929 &isp->sess_discovered_addr.sin)) 930 == 0)) { 931 /* 932 * iSNS or sendtarget 933 * discovery and discovery 934 * address is NULL or match 935 */ 936 try_online = B_TRUE; 937 } else { 938 /* addr_dsc not a match */ 939 try_online = B_FALSE; 940 } 941 } else { 942 /* static configuration */ 943 try_online = B_TRUE; 944 } 945 } else { 946 /* method not a match */ 947 try_online = B_FALSE; 948 } 949 } else if (strcmp(target_name, (char *)isp->sess_name) == 0) { 950 /* target_name match */ 951 try_online = B_TRUE; 952 } else { 953 /* target_name not a match */ 954 try_online = B_FALSE; 955 } 956 957 if (try_online == B_TRUE) { 958 iscsi_sess_online(isp); 959 rtn = B_TRUE; 960 } 961 isp = isp->sess_next; 962 } 963 rw_exit(&ihp->hba_sess_list_rwlock); 964 return (rtn); 965 } 966 967 /* 968 * +--------------------------------------------------------------------+ 969 * | Local Helper Functions | 970 * +--------------------------------------------------------------------+ 971 */ 972 973 /* 974 * iscsid_init_config -- initialize configuration parameters of iSCSI initiator 975 */ 976 static boolean_t 977 iscsid_init_config(iscsi_hba_t *ihp) 978 { 979 iscsi_param_set_t ips; 980 void *v = NULL; 981 char *name; 982 char *initiatorName; 983 persistent_param_t pp; 984 uint32_t param_id; 985 int rc; 986 987 /* allocate memory to hold initiator names */ 988 initiatorName = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 989 990 /* 991 * initialize iSCSI initiator name 992 */ 993 bzero(&ips, sizeof (ips)); 994 if (persistent_initiator_name_get(initiatorName, 995 ISCSI_MAX_NAME_LEN) == B_TRUE) { 996 (void) strncpy((char *)ips.s_value.v_name, initiatorName, 997 sizeof (ips.s_value.v_name)); 998 999 ips.s_vers = ISCSI_INTERFACE_VERSION; 1000 ips.s_param = ISCSI_LOGIN_PARAM_INITIATOR_NAME; 1001 1002 (void) iscsi_set_params(&ips, ihp, B_FALSE); 1003 } else { 1004 /* 1005 * if we don't have an initiator-node name it's most 1006 * likely because this is a fresh install (or we 1007 * couldn't read the persistent store properly). Set 1008 * a default initiator name so the initiator can 1009 * be brought up properly. 1010 */ 1011 iscsid_set_default_initiator_node_settings(ihp); 1012 } 1013 1014 /* 1015 * initialize iSCSI initiator alias (if any) 1016 */ 1017 bzero(&ips, sizeof (ips)); 1018 if (persistent_alias_name_get((char *)ips.s_value.v_name, 1019 sizeof (ips.s_value.v_name)) == B_TRUE) { 1020 ips.s_param = ISCSI_LOGIN_PARAM_INITIATOR_ALIAS; 1021 (void) iscsi_set_params(&ips, ihp, B_FALSE); 1022 } else { 1023 /* EMPTY */ 1024 /* No alias defined - not a problem. */ 1025 } 1026 1027 /* 1028 * load up the overriden iSCSI initiator parameters 1029 */ 1030 name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 1031 persistent_param_lock(); 1032 v = NULL; 1033 while (persistent_param_next(&v, name, &pp) == B_TRUE) { 1034 if (strncmp(name, initiatorName, ISCSI_MAX_NAME_LEN) == 0) { 1035 ips.s_oid = ihp->hba_oid; 1036 ips.s_vers = ISCSI_INTERFACE_VERSION; 1037 for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM; 1038 param_id++) { 1039 if (pp.p_bitmap & (1 << param_id)) { 1040 rc = iscsid_copyto_param_set(param_id, 1041 &pp.p_params, &ips); 1042 if (rc == 0) { 1043 rc = iscsi_set_params(&ips, 1044 ihp, B_FALSE); 1045 } 1046 if (rc != 0) { 1047 /* note error but continue */ 1048 cmn_err(CE_NOTE, 1049 "Failed to set " 1050 "param %d for OID %d", 1051 ips.s_param, ips.s_oid); 1052 } 1053 } 1054 } /* END for() */ 1055 break; 1056 } 1057 } /* END while() */ 1058 persistent_param_unlock(); 1059 1060 kmem_free(initiatorName, ISCSI_MAX_NAME_LEN); 1061 kmem_free(name, ISCSI_MAX_NAME_LEN); 1062 return (B_TRUE); 1063 } 1064 1065 1066 /* 1067 * iscsid_init_targets -- Load up the driver with known static targets and 1068 * targets whose parameters have been modified. 1069 * 1070 * This is done so that the CLI can find a list of targets the driver 1071 * currently knows about. 1072 * 1073 * The driver doesn't need to log into these targets. Log in is done based 1074 * upon the enabled discovery methods. 1075 */ 1076 static boolean_t 1077 iscsid_init_targets(iscsi_hba_t *ihp) 1078 { 1079 void *v = NULL; 1080 char *name; 1081 iscsi_param_set_t ips; 1082 persistent_param_t pp; 1083 char *iname; 1084 uint32_t param_id; 1085 int rc; 1086 1087 ASSERT(ihp != NULL); 1088 1089 /* allocate memory to hold target names */ 1090 name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 1091 1092 /* 1093 * load up targets whose parameters have been overriden 1094 */ 1095 1096 /* ---- only need to be set once ---- */ 1097 bzero(&ips, sizeof (ips)); 1098 ips.s_vers = ISCSI_INTERFACE_VERSION; 1099 1100 /* allocate memory to hold initiator name */ 1101 iname = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 1102 (void) persistent_initiator_name_get(iname, ISCSI_MAX_NAME_LEN); 1103 1104 persistent_param_lock(); 1105 v = NULL; 1106 while (persistent_param_next(&v, name, &pp) == B_TRUE) { 1107 1108 if (strncmp(iname, name, ISCSI_MAX_NAME_LEN) == 0) { 1109 /* 1110 * target name matched initiator's name so, 1111 * continue to next target. Initiator's 1112 * parmeters have already been set. 1113 */ 1114 continue; 1115 } 1116 1117 ips.s_oid = iscsi_targetparam_get_oid((unsigned char *)name); 1118 1119 for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM; 1120 param_id++) { 1121 if (pp.p_bitmap & (1 << param_id)) { 1122 rc = iscsid_copyto_param_set(param_id, 1123 &pp.p_params, &ips); 1124 if (rc == 0) { 1125 rc = iscsi_set_params(&ips, 1126 ihp, B_FALSE); 1127 } 1128 if (rc != 0) { 1129 /* note error but continue ---- */ 1130 cmn_err(CE_NOTE, "Failed to set " 1131 "param %d for OID %d", 1132 ips.s_param, ips.s_oid); 1133 } 1134 } 1135 } /* END for() */ 1136 } /* END while() */ 1137 persistent_param_unlock(); 1138 1139 kmem_free(iname, ISCSI_MAX_NAME_LEN); 1140 kmem_free(name, ISCSI_MAX_NAME_LEN); 1141 1142 return (B_TRUE); 1143 } 1144 1145 1146 /* 1147 * iscsid_thread_static -- If static discovery is enabled, this routine obtains 1148 * all statically configured targets from the peristent store and issues a 1149 * login request to the driver. 1150 */ 1151 /* ARGSUSED */ 1152 static void 1153 iscsid_thread_static(iscsi_thread_t *thread, void *p) 1154 { 1155 iSCSIDiscoveryMethod_t dm; 1156 entry_t entry; 1157 char name[ISCSI_MAX_NAME_LEN]; 1158 void *v = NULL; 1159 iscsi_hba_t *ihp = (iscsi_hba_t *)p; 1160 1161 while (iscsi_thread_wait(thread, -1) != 0) { 1162 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodStatic, B_TRUE); 1163 1164 /* ---- ensure static target discovery is enabled ---- */ 1165 dm = persistent_disc_meth_get(); 1166 if ((dm & iSCSIDiscoveryMethodStatic) == 0) { 1167 cmn_err(CE_NOTE, 1168 "iscsi discovery failure - " 1169 "StaticTargets method is not enabled"); 1170 iscsi_discovery_event(ihp, 1171 iSCSIDiscoveryMethodStatic, B_FALSE); 1172 continue; 1173 } 1174 1175 /* 1176 * walk list of the statically configured targets from the 1177 * persistent store 1178 */ 1179 v = NULL; 1180 persistent_static_addr_lock(); 1181 while (persistent_static_addr_next(&v, name, &entry) == 1182 B_TRUE) { 1183 iscsi_sockaddr_t addr; 1184 1185 iscsid_addr_to_sockaddr(entry.e_insize, 1186 &(entry.e_u), entry.e_port, &addr.sin); 1187 1188 (void) iscsid_add(ihp, iSCSIDiscoveryMethodStatic, 1189 &addr.sin, name, entry.e_tpgt, &addr.sin); 1190 } 1191 persistent_static_addr_unlock(); 1192 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodStatic, B_FALSE); 1193 } 1194 } 1195 1196 1197 /* 1198 * iscsid_thread_sendtgts -- If SendTargets discovery is enabled, this routine 1199 * obtains all target discovery addresses configured from the peristent store 1200 * and probe the IP/port addresses for possible targets. It will then issue 1201 * a login request to the driver for all discoveryed targets. 1202 */ 1203 static void 1204 iscsid_thread_sendtgts(iscsi_thread_t *thread, void *p) 1205 { 1206 iscsi_hba_t *ihp = (iscsi_hba_t *)p; 1207 iSCSIDiscoveryMethod_t dm; 1208 entry_t entry; 1209 void *v = NULL; 1210 1211 while (iscsi_thread_wait(thread, -1) != 0) { 1212 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSendTargets, 1213 B_TRUE); 1214 1215 /* ---- ensure SendTargets discovery is enabled ---- */ 1216 dm = persistent_disc_meth_get(); 1217 if ((dm & iSCSIDiscoveryMethodSendTargets) == 0) { 1218 cmn_err(CE_NOTE, 1219 "iscsi discovery failure - " 1220 "SendTargets method is not enabled"); 1221 iscsi_discovery_event(ihp, 1222 iSCSIDiscoveryMethodSendTargets, B_FALSE); 1223 continue; 1224 } 1225 /* 1226 * walk list of the SendTarget discovery addresses from the 1227 * persistent store 1228 */ 1229 v = NULL; 1230 persistent_disc_addr_lock(); 1231 while (persistent_disc_addr_next(&v, &entry) == B_TRUE) { 1232 iscsid_do_sendtgts(&entry); 1233 } 1234 persistent_disc_addr_unlock(); 1235 1236 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSendTargets, 1237 B_FALSE); 1238 } 1239 } 1240 1241 /* 1242 * iscsid_thread_slp -- If SLP discovery is enabled, this routine provides 1243 * the SLP discovery service. 1244 */ 1245 static void 1246 iscsid_thread_slp(iscsi_thread_t *thread, void *p) 1247 { 1248 iscsi_hba_t *ihp = (iscsi_hba_t *)p; 1249 1250 do { 1251 /* 1252 * Even though we don't have support for SLP at this point 1253 * we'll send the events if someone has enabled this thread. 1254 * If this is not done the daemon waiting for discovery to 1255 * complete will pause forever holding up the boot process. 1256 */ 1257 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSLP, B_TRUE); 1258 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSLP, B_FALSE); 1259 } while (iscsi_thread_wait(thread, -1) != 0); 1260 } 1261 1262 /* 1263 * iscsid_thread_isns -- 1264 */ 1265 static void 1266 iscsid_thread_isns(iscsi_thread_t *thread, void *ptr) 1267 { 1268 iscsi_hba_t *ihp = (iscsi_hba_t *)ptr; 1269 iSCSIDiscoveryMethod_t dm; 1270 1271 while (iscsi_thread_wait(thread, -1) != 0) { 1272 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodISNS, B_TRUE); 1273 1274 /* ---- ensure iSNS discovery is enabled ---- */ 1275 dm = persistent_disc_meth_get(); 1276 if ((dm & iSCSIDiscoveryMethodISNS) == 0) { 1277 cmn_err(CE_NOTE, 1278 "iscsi discovery failure - " 1279 "iSNS method is not enabled"); 1280 iscsi_discovery_event(ihp, 1281 iSCSIDiscoveryMethodISNS, B_FALSE); 1282 continue; 1283 } 1284 1285 (void) isns_reg(ihp->hba_isid, 1286 ihp->hba_name, 1287 ISCSI_MAX_NAME_LEN, 1288 ihp->hba_alias, 1289 ISCSI_MAX_NAME_LEN, 1290 ISNS_INITIATOR_NODE_TYPE, 1291 isns_scn_callback); 1292 iscsid_do_isns_query(ihp); 1293 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodISNS, B_FALSE); 1294 } 1295 1296 /* Thread stopped. Deregister from iSNS servers(s). */ 1297 (void) isns_dereg(ihp->hba_isid, ihp->hba_name); 1298 } 1299 1300 1301 /* 1302 * iscsid_threads_create -- Creates all the discovery threads. 1303 */ 1304 static void 1305 iscsid_threads_create(iscsi_hba_t *ihp) 1306 { 1307 iscsid_thr_table *t; 1308 1309 /* 1310 * start a thread for each discovery method 1311 */ 1312 for (t = &iscsid_thr[0]; t->method != iSCSIDiscoveryMethodUnknown; 1313 t++) { 1314 if (t->thr_id == NULL) { 1315 t->thr_id = iscsi_thread_create(ihp->hba_dip, t->name, 1316 t->func_start, ihp); 1317 } 1318 } 1319 } 1320 1321 /* 1322 * iscsid_threads_destroy -- Destroys all the discovery threads. 1323 */ 1324 static void 1325 iscsid_threads_destroy(void) 1326 { 1327 iscsid_thr_table *t; 1328 1329 for (t = &iscsid_thr[0]; t->method != iSCSIDiscoveryMethodUnknown; 1330 t++) { 1331 if (t->thr_id != NULL) { 1332 iscsi_thread_destroy(t->thr_id); 1333 t->thr_id = NULL; 1334 } 1335 } 1336 } 1337 1338 /* 1339 * iscsid_copyto_param_set - helper function for iscsid_init_params. 1340 */ 1341 static int 1342 iscsid_copyto_param_set(uint32_t param_id, iscsi_login_params_t *params, 1343 iscsi_param_set_t *ipsp) 1344 { 1345 int rtn = 0; 1346 1347 if (param_id >= ISCSI_NUM_LOGIN_PARAM) { 1348 return (EINVAL); 1349 } 1350 1351 switch (param_id) { 1352 1353 /* 1354 * Boolean parameters 1355 */ 1356 case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER: 1357 ipsp->s_value.v_bool = params->data_pdu_in_order; 1358 break; 1359 case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA: 1360 ipsp->s_value.v_bool = params->immediate_data; 1361 break; 1362 case ISCSI_LOGIN_PARAM_INITIAL_R2T: 1363 ipsp->s_value.v_bool = params->initial_r2t; 1364 break; 1365 case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER: 1366 ipsp->s_value.v_bool = params->data_pdu_in_order; 1367 break; 1368 1369 /* 1370 * Integer parameters 1371 */ 1372 case ISCSI_LOGIN_PARAM_HEADER_DIGEST: 1373 ipsp->s_value.v_integer = params->header_digest; 1374 break; 1375 case ISCSI_LOGIN_PARAM_DATA_DIGEST: 1376 ipsp->s_value.v_integer = params->data_digest; 1377 break; 1378 case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN: 1379 ipsp->s_value.v_integer = params->default_time_to_retain; 1380 break; 1381 case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT: 1382 ipsp->s_value.v_integer = params->default_time_to_wait; 1383 break; 1384 case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH: 1385 ipsp->s_value.v_integer = params->max_recv_data_seg_len; 1386 break; 1387 case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH: 1388 ipsp->s_value.v_integer = params->first_burst_length; 1389 break; 1390 case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH: 1391 ipsp->s_value.v_integer = params->max_burst_length; 1392 break; 1393 1394 /* 1395 * Integer parameters which currently are unsettable 1396 */ 1397 case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS: 1398 case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T: 1399 case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL: 1400 /* ---- drop through to default case ---- */ 1401 default: 1402 rtn = EINVAL; 1403 break; 1404 } 1405 1406 /* if all is well, set the parameter identifier */ 1407 if (rtn == 0) { 1408 ipsp->s_param = param_id; 1409 } 1410 1411 return (rtn); 1412 } 1413 1414 /* 1415 * iscsid_add_pg_list_to_cache - Add portal groups in the list to the 1416 * discovery cache. 1417 */ 1418 static void 1419 iscsid_add_pg_list_to_cache(iscsi_hba_t *ihp, 1420 isns_portal_group_list_t *pg_list) 1421 { 1422 int i; 1423 1424 for (i = 0; i < pg_list->pg_out_cnt; i++) { 1425 iscsi_sockaddr_t addr_dsc; 1426 iscsi_sockaddr_t addr_tgt; 1427 1428 iscsid_addr_to_sockaddr( 1429 pg_list->pg_list[i].isns_server_ip.i_insize, 1430 &pg_list->pg_list[i].isns_server_ip.i_addr, 1431 pg_list->pg_list[i].isns_server_port, 1432 &addr_dsc.sin); 1433 iscsid_addr_to_sockaddr( 1434 pg_list->pg_list[i].insize, 1435 &pg_list->pg_list[i].pg_ip_addr, 1436 pg_list->pg_list[i].pg_port, 1437 &addr_tgt.sin); 1438 1439 (void) iscsid_add(ihp, iSCSIDiscoveryMethodISNS, &addr_dsc.sin, 1440 (char *)pg_list->pg_list[i].pg_iscsi_name, 1441 pg_list->pg_list[i].pg_tag, &addr_tgt.sin); 1442 } 1443 } 1444 1445 /* 1446 * set_initiator_name - set default initiator name and alias. 1447 * 1448 * This sets the default initiator name and alias. The 1449 * initiator name is composed of sun's reverse domain name 1450 * and registration followed and a unique classifier. This 1451 * classifier is the mac address of the first NIC in the 1452 * host and a timestamp to make sure the classifier is 1453 * unique if the NIC is moved between hosts. The alias 1454 * is just the hostname. 1455 */ 1456 static void 1457 iscsid_set_default_initiator_node_settings(iscsi_hba_t *ihp) 1458 { 1459 int i; 1460 time_t x; 1461 struct ether_addr eaddr; 1462 char val[10]; 1463 iscsi_chap_props_t *chap = NULL; 1464 1465 /* Set default initiator-node name */ 1466 (void) snprintf((char *)ihp->hba_name, 1467 ISCSI_MAX_NAME_LEN, 1468 "iqn.1986-03.com.sun:01:"); 1469 1470 (void) localetheraddr(NULL, &eaddr); 1471 for (i = 0; i < ETHERADDRL; i++) { 1472 (void) snprintf(val, sizeof (val), "%02x", 1473 eaddr.ether_addr_octet[i]); 1474 (void) strncat((char *)ihp->hba_name, val, ISCSI_MAX_NAME_LEN); 1475 } 1476 1477 /* Set default initiator-node alias */ 1478 x = ddi_get_time(); 1479 (void) snprintf(val, sizeof (val), ".%lx", x); 1480 (void) strncat((char *)ihp->hba_name, val, ISCSI_MAX_NAME_LEN); 1481 (void) persistent_initiator_name_set((char *)ihp->hba_name); 1482 if (ihp->hba_alias[0] == '\0') { 1483 (void) strncpy((char *)ihp->hba_alias, 1484 utsname.nodename, ISCSI_MAX_NAME_LEN); 1485 ihp->hba_alias_length = strlen((char *)ihp->hba_alias); 1486 (void) persistent_alias_name_set((char *)ihp->hba_alias); 1487 } 1488 1489 /* Set default initiator-node CHAP settings */ 1490 if (persistent_initiator_name_get((char *)ihp->hba_name, 1491 ISCSI_MAX_NAME_LEN) == B_TRUE) { 1492 chap = (iscsi_chap_props_t *)kmem_zalloc(sizeof (*chap), 1493 KM_SLEEP); 1494 if (persistent_chap_get((char *)ihp->hba_name, chap) == 1495 B_FALSE) { 1496 bcopy((char *)ihp->hba_name, chap->c_user, 1497 strlen((char *)ihp->hba_name)); 1498 chap->c_user_len = strlen((char *)ihp->hba_name); 1499 (void) persistent_chap_set((char *)ihp->hba_name, chap); 1500 } 1501 kmem_free(chap, sizeof (*chap)); 1502 } 1503 } 1504 1505 static void 1506 iscsid_remove_target_param(char *name) 1507 { 1508 persistent_param_t *pparam; 1509 uint32_t t_oid; 1510 iscsi_config_sess_t *ics; 1511 1512 ASSERT(name != NULL); 1513 1514 /* 1515 * Remove target-param <-> target mapping. 1516 * Only remove if there is not any overridden 1517 * parameters in the persistent store 1518 */ 1519 pparam = (persistent_param_t *)kmem_zalloc(sizeof (*pparam), KM_SLEEP); 1520 1521 /* 1522 * setup initial buffer for configured session 1523 * information 1524 */ 1525 ics = (iscsi_config_sess_t *)kmem_zalloc(sizeof (*ics), KM_SLEEP); 1526 ics->ics_in = 1; 1527 1528 if ((persistent_param_get(name, pparam) == B_FALSE) && 1529 (persistent_get_config_session(name, ics) == B_FALSE)) { 1530 t_oid = iscsi_targetparam_get_oid((uchar_t *)name); 1531 (void) iscsi_targetparam_remove_target(t_oid); 1532 } 1533 1534 kmem_free(pparam, sizeof (*pparam)); 1535 pparam = NULL; 1536 kmem_free(ics, sizeof (*ics)); 1537 ics = NULL; 1538 } 1539 1540 /* 1541 * iscsid_addr_to_sockaddr - convert other types to struct sockaddr 1542 */ 1543 void 1544 iscsid_addr_to_sockaddr(int src_insize, void *src_addr, int src_port, 1545 struct sockaddr *dst_addr) 1546 { 1547 ASSERT((src_insize == sizeof (struct in_addr)) || 1548 (src_insize == sizeof (struct in6_addr))); 1549 ASSERT(src_addr != NULL); 1550 ASSERT(dst_addr != NULL); 1551 1552 bzero(dst_addr, sizeof (*dst_addr)); 1553 1554 /* translate discovery information */ 1555 if (src_insize == sizeof (struct in_addr)) { 1556 struct sockaddr_in *addr_in = 1557 (struct sockaddr_in *)dst_addr; 1558 addr_in->sin_family = AF_INET; 1559 bcopy(src_addr, &addr_in->sin_addr.s_addr, 1560 sizeof (struct in_addr)); 1561 addr_in->sin_port = htons(src_port); 1562 } else { 1563 struct sockaddr_in6 *addr_in6 = 1564 (struct sockaddr_in6 *)dst_addr; 1565 addr_in6->sin6_family = AF_INET6; 1566 bcopy(src_addr, &addr_in6->sin6_addr.s6_addr, 1567 sizeof (struct in6_addr)); 1568 addr_in6->sin6_port = htons(src_port); 1569 } 1570 } 1571 1572 /* 1573 * iscsi_discovery_event -- send event associated with discovery operations 1574 * 1575 * Each discovery event has a start and end event. Which is sent is based 1576 * on the boolean argument start with the obvious results. 1577 */ 1578 static void 1579 iscsi_discovery_event(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t m, 1580 boolean_t start) 1581 { 1582 char *subclass = NULL; 1583 1584 mutex_enter(&ihp->hba_discovery_events_mutex); 1585 switch (m) { 1586 case iSCSIDiscoveryMethodStatic: 1587 if (start == B_TRUE) { 1588 subclass = ESC_ISCSI_STATIC_START; 1589 } else { 1590 ihp->hba_discovery_events |= iSCSIDiscoveryMethodStatic; 1591 subclass = ESC_ISCSI_STATIC_END; 1592 } 1593 break; 1594 1595 case iSCSIDiscoveryMethodSendTargets: 1596 if (start == B_TRUE) { 1597 subclass = ESC_ISCSI_SEND_TARGETS_START; 1598 } else { 1599 ihp->hba_discovery_events |= 1600 iSCSIDiscoveryMethodSendTargets; 1601 subclass = ESC_ISCSI_SEND_TARGETS_END; 1602 } 1603 break; 1604 1605 case iSCSIDiscoveryMethodSLP: 1606 if (start == B_TRUE) { 1607 subclass = ESC_ISCSI_SLP_START; 1608 } else { 1609 ihp->hba_discovery_events |= iSCSIDiscoveryMethodSLP; 1610 subclass = ESC_ISCSI_SLP_END; 1611 } 1612 break; 1613 1614 case iSCSIDiscoveryMethodISNS: 1615 if (start == B_TRUE) { 1616 subclass = ESC_ISCSI_ISNS_START; 1617 } else { 1618 ihp->hba_discovery_events |= iSCSIDiscoveryMethodISNS; 1619 subclass = ESC_ISCSI_ISNS_END; 1620 } 1621 break; 1622 } 1623 mutex_exit(&ihp->hba_discovery_events_mutex); 1624 iscsi_send_sysevent(ihp, subclass, NULL); 1625 } 1626 1627 /* 1628 * iscsi_send_sysevent -- send sysevent using iscsi class 1629 */ 1630 static void 1631 iscsi_send_sysevent(iscsi_hba_t *ihp, char *subclass, nvlist_t *np) 1632 { 1633 (void) ddi_log_sysevent(ihp->hba_dip, DDI_VENDOR_SUNW, EC_ISCSI, 1634 subclass, np, NULL, DDI_SLEEP); 1635 } 1636