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 #include <sys/cpuvar.h> 27 #include <sys/types.h> 28 #include <sys/conf.h> 29 #include <sys/file.h> 30 #include <sys/ddi.h> 31 #include <sys/sunddi.h> 32 #include <sys/socket.h> 33 #include <inet/tcp.h> 34 #include <sys/sdt.h> 35 36 #include <sys/stmf.h> 37 #include <sys/stmf_ioctl.h> 38 #include <sys/portif.h> 39 #include <sys/idm/idm.h> 40 #include <sys/idm/idm_so.h> 41 #include <sys/iscsit/iscsit_common.h> 42 #include <sys/iscsit/isns_protocol.h> 43 #include <iscsit.h> 44 #include <iscsit_isns.h> 45 #include <sys/ksocket.h> 46 47 /* 48 * iscsit_isns.c -- isns client that is part of the iscsit server 49 * 50 * The COMSTAR iSCSI target uses four pieces of iSNS functionality: 51 * - DevAttrReg to notify the iSNS server of our targets and portals. 52 * - DeregDev to notify when a target goes away or we shut down 53 * - DevAttrQry (self-query) to see if iSNS server still knows us. 54 * - Request ESI probes from iSNS server as a keepalive mechanism 55 * 56 * We send only two kinds of DevAttrReg messages. 57 * 58 * REPLACE-ALL the info the iSNS server knows about us: 59 * Set Flag in PDU header to ISNS_FLAG_REPLACE_REG 60 * Set "source" to same iSCSI target each time 61 * EID (Entity Identifier) == our DNS name 62 * "Delimiter" 63 * Object operated on = EID 64 * "Entity Portals" owned by this "network entity" 65 * List of targets 66 * (Targets with TPGT are followed by PGT and PG portal info) 67 * 68 * UPDATE-EXISTING - used to register/change one target at a time 69 * Flag for replace reg not set 70 * Source and EID and Delimiter and Object Operated On as above 71 * Single Target 72 * (Targets with TPGT are followed by PGT and PG portal info) 73 * 74 * Interfaces to iscsit 75 * 76 * iscsit_isns_init -- called when iscsi/target service goes online 77 * iscsit_isns_fini -- called when iscsi/target service goes offline 78 * iscsit_isns_register -- a new target comes online 79 * iscsit_isns_deregister -- target goes offline 80 * iscsit_isns_target_update -- called when a target is modified 81 * iscsit_isns_portal_online -- called when defining a new portal 82 * iscsit_isns_portal_offline -- no longer using a portal 83 * 84 * Copying Data Structures 85 * 86 * The above routines copy all the data they need, so iscsit can 87 * proceed without interfering with us. This is moving in the 88 * direction of having this isns_client be a standalone user-mode 89 * program. Specifically, we copy the target name, alias, and 90 * tpgt+portal information. 91 * 92 * The iscsit_isns_mutex protects the shadow copies of target and portal 93 * information. The ISNS_GLOBAL_LOCK protects the iSNS run time structures 94 * that the monitor thread uses. The routine isnst_copy_global_status_changes 95 * has to acquire both locks and copy all the required information from the 96 * global structs to the per-server structs. Once it completes, the monitor 97 * thread should run completely off the per-server copies. 98 * 99 * Global State vs Per-Server state 100 * There is a global list of targets and portals that is kept updated 101 * by iscsit. Each svr keeps its own list of targets that have been 102 * announced to the iSNS server. 103 * 104 * Invariants 105 * 106 * 1) If svr->svr_registered, then there is some itarget with 107 * itarget->target_registered. 108 * 2) If itarget->target_delete_needed, then also itarget->target_registered. 109 * (Corollary: Any time you remove the last registered target, you have 110 * to send an unregister-all message.) 111 * 3) If a target has a non-default portal, then the portal goes online 112 * before the target goes online, and comes offline afterwards. 113 * (This is enforced by the iscsit state machines.) 114 */ 115 /* local defines */ 116 #define MAX_XID (2^16) 117 #define ISNS_IDLE_TIME 60 118 #define MAX_RETRY (3) 119 #define ISNS_RCV_TIMER_SECONDS 5 120 121 #define VALID_NAME(NAME, LEN) \ 122 ((LEN) > 0 && (NAME)[0] != 0 && (NAME)[(LEN) - 1] == 0) 123 124 125 #define ISNST_LOG if (iscsit_isns_logging) cmn_err 126 127 static kmutex_t isns_monitor_mutex; 128 volatile kthread_t *isns_monitor_thr_id; 129 static kt_did_t isns_monitor_thr_did; 130 static boolean_t isns_monitor_thr_running; 131 132 static kcondvar_t isns_idle_cv; 133 134 static uint16_t xid; 135 #define GET_XID() atomic_inc_16_nv(&xid) 136 137 static clock_t monitor_idle_interval; 138 139 /* The ISNS_GLOBAL_LOCK protects the per-server data structures */ 140 #define ISNS_GLOBAL_LOCK() \ 141 mutex_enter(&iscsit_global.global_isns_cfg.isns_mutex) 142 143 #define ISNS_GLOBAL_LOCK_HELD() \ 144 MUTEX_HELD(&iscsit_global.global_isns_cfg.isns_mutex) 145 146 #define ISNS_GLOBAL_UNLOCK() \ 147 mutex_exit(&iscsit_global.global_isns_cfg.isns_mutex) 148 149 /* 150 * "Configurable" parameters (set in /etc/system for now). 151 */ 152 boolean_t iscsit_isns_logging = B_FALSE; 153 154 155 /* 156 * If fail this many times to send an update to the server, then 157 * declare the server non-responsive and reregister everything with 158 * the server when we next connect. 159 */ 160 int isns_max_retry = MAX_RETRY; 161 162 /* 163 * The use of ESI probes to all active portals is not appropriate in 164 * all network environments, since the iSNS server may not have 165 * connectivity to all portals, so we turn it off by default. 166 */ 167 boolean_t isns_use_esi = B_FALSE; 168 169 /* 170 * Interval to request ESI probes at, in seconds. The server is free 171 * to specify a different frequency in its response. 172 */ 173 int isns_default_esi_interval = ISNS_DEFAULT_ESI_INTERVAL; 174 175 176 /* 177 * Registration Period -- we guarantee to check in with iSNS server at 178 * least this often. Used when ESI probes are turned off. 179 */ 180 int isns_registration_period = ISNS_DEFAULT_REGISTRATION_PERIOD; 181 182 /* 183 * Socket connect, PDU receive, and PDU send must complete 184 * within this number of microseconds. 185 */ 186 uint32_t isns_timeout_usec = ISNS_RCV_TIMER_SECONDS * 1000000; 187 188 189 /* 190 * iSNS Message size -- we start with the max that can fit into one PDU. 191 * If the message doesn't fit, we will expand at run time to a higher 192 * value. This parameter could be set in /etc/system if some particular 193 * installation knows it always goes over the standard limit. 194 */ 195 uint32_t isns_message_buf_size = ISNSP_MAX_PDU_SIZE; 196 197 /* 198 * Number of seconds to wait after isnst_monitor thread starts up 199 * before sending first DevAttrReg message. 200 */ 201 int isns_initial_delay = ISNS_INITIAL_DELAY; 202 203 /* If PDU sizes ever go over the following, we need to rearchitect */ 204 #define ISNST_MAX_MSG_SIZE (16 * ISNSP_MAX_PDU_SIZE) 205 206 /* 207 * iSNS ESI thread state 208 */ 209 static isns_esi_tinfo_t esi; 210 211 /* 212 * Our list of targets. Kept in lock-step synch with iscsit. 213 * The iscsit_isns_mutex protects the global data structures that are 214 * kept in lock-step with iscsit. 215 * NOTE: Now that isnst runs independently of iscsit, we could remove the 216 * shadow copies of iscsit structures, such as isns_target_list and 217 * isns_tpg_portals, and have isnst_copy_global_status_changes reconcile 218 * isnst directly with the iscsit data structures. 219 */ 220 static kmutex_t iscsit_isns_mutex; 221 static avl_tree_t isns_target_list; 222 static boolean_t isns_targets_changed; 223 224 /* 225 * List of portals from TPGs. Protected by iscsit_isns_mutex. 226 */ 227 static boolean_t isns_portals_changed; 228 static avl_tree_t isns_tpg_portals; 229 static boolean_t default_portal_online; 230 231 /* List of all portals. Protected by ISNS_GLOBAL_LOCK */ 232 static avl_tree_t isns_all_portals; 233 static int num_default_portals; 234 static int num_tpg_portals; 235 236 /* 237 * Our entity identifier (fully-qualified hostname). Passed in from libiscsit. 238 */ 239 static char *isns_eid = NULL; 240 241 /* 242 * in6addr_any is currently all zeroes, but use the macro in case this 243 * ever changes. 244 */ 245 static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 246 247 static void 248 isnst_start(); 249 250 static void 251 isnst_stop(); 252 253 static void 254 iscsit_set_isns(boolean_t state); 255 256 static void 257 iscsit_add_isns(it_portal_t *cfg_svr); 258 259 static void 260 isnst_mark_delete_isns(iscsit_isns_svr_t *svr); 261 262 static void 263 isnst_finish_delete_isns(iscsit_isns_svr_t *svr); 264 265 static iscsit_isns_svr_t * 266 iscsit_isns_svr_lookup(struct sockaddr_storage *sa); 267 268 static void 269 isnst_monitor(void *arg); 270 271 static int 272 isnst_monitor_one_server(iscsit_isns_svr_t *svr, boolean_t enabled); 273 274 static void 275 isnst_monitor_awaken(void); 276 277 static boolean_t 278 isnst_update_server_timestamp(struct sockaddr_storage *sa); 279 280 static void 281 isnst_copy_global_status_changes(void); 282 283 static void 284 isnst_mark_deleted_targets(iscsit_isns_svr_t *svr); 285 286 static int 287 isnst_update_one_server(iscsit_isns_svr_t *svr, isns_target_t *target, 288 isns_reg_type_t reg); 289 290 static boolean_t isnst_retry_registration(int rsp_status_code); 291 292 static int isnst_register(iscsit_isns_svr_t *svr, isns_target_t *itarget, 293 isns_reg_type_t regtype); 294 static int isnst_deregister(iscsit_isns_svr_t *svr, isns_target_t *itarget); 295 296 static size_t 297 isnst_make_dereg_pdu(iscsit_isns_svr_t *svr, isns_pdu_t **pdu, 298 isns_target_t *itarge); 299 300 static int isnst_keepalive(iscsit_isns_svr_t *svr); 301 static size_t 302 isnst_make_keepalive_pdu(iscsit_isns_svr_t *svr, isns_pdu_t **pdu); 303 304 static isns_target_t *isnst_get_registered_source(iscsit_isns_svr_t *srv); 305 306 static int 307 isnst_verify_rsp(iscsit_isns_svr_t *svr, isns_pdu_t *pdu, 308 isns_pdu_t *rsp, size_t rsp_size); 309 310 static uint16_t 311 isnst_pdu_get_op(isns_pdu_t *pdu, uint8_t **pp); 312 313 static size_t 314 isnst_make_reg_pdu(isns_pdu_t **pdu, isns_target_t *target, 315 iscsit_isns_svr_t *svr, isns_reg_type_t regtype); 316 317 static int 318 isnst_reg_pdu_add_entity_portals(isns_pdu_t *pdu, size_t pdu_size); 319 320 static int 321 isnst_reg_pdu_add_pg(isns_pdu_t *pdu, size_t pdu_size, isns_target_t *target); 322 323 static int 324 isnst_add_default_pg(isns_pdu_t *pdu, size_t pdu_size, 325 avl_tree_t *null_portal_list); 326 327 static int 328 isnst_add_tpg_pg(isns_pdu_t *pdu, size_t pdu_size, 329 isns_target_info_t *ti, avl_tree_t *null_portal_list); 330 331 static int 332 isnst_add_null_pg(isns_pdu_t *pdu, size_t pdu_size, 333 avl_tree_t *null_portal_list); 334 335 static int 336 isnst_add_portal_attr(isns_pdu_t *pdu, size_t pdu_size, 337 uint32_t ip_attr_id, uint32_t port_attr_id, 338 struct sockaddr_storage *ss, boolean_t esi_info); 339 340 static size_t 341 isnst_create_pdu_header(uint16_t func_id, isns_pdu_t **pdu, uint16_t flags); 342 343 static int 344 isnst_add_attr(isns_pdu_t *pdu, 345 size_t max_pdu_size, 346 uint32_t attr_id, 347 uint32_t attr_len, 348 void *attr_data, 349 uint32_t attr_numeric_data); 350 351 static int 352 isnst_send_pdu(void *so, isns_pdu_t *pdu); 353 354 static size_t 355 isnst_rcv_pdu(void *so, isns_pdu_t **pdu); 356 357 static void * 358 isnst_open_so(struct sockaddr_storage *sa); 359 360 static void 361 isnst_close_so(void *); 362 363 static void 364 isnst_esi_thread(void *arg); 365 366 static void 367 isnst_handle_esi_req(ksocket_t so, isns_pdu_t *pdu, size_t pl_size); 368 369 static void isnst_esi_start(void); 370 static void isnst_esi_stop(void); 371 static isns_target_t *isnst_latch_to_target_list(isns_target_t *target, 372 avl_tree_t *list); 373 static void isnst_clear_target_list(iscsit_isns_svr_t *svr); 374 static void isnst_clear_from_target_list(isns_target_t *target, 375 avl_tree_t *target_list); 376 static int isnst_tgt_avl_compare(const void *t1, const void *t2); 377 static void isnst_set_server_status(iscsit_isns_svr_t *svr, 378 boolean_t registered); 379 static void isnst_monitor_start(void); 380 static void isnst_monitor_stop(void); 381 382 static void 383 isnst_monitor_default_portal_list(void); 384 385 static int 386 isnst_find_default_portals(idm_addr_list_t *alist); 387 388 static int 389 isnst_add_default_portals(idm_addr_list_t *alist); 390 391 static void 392 isnst_clear_default_portals(void); 393 394 395 static void 396 isnst_clear_portal_list(avl_tree_t *portal_list); 397 398 static void 399 isnst_copy_portal_list(avl_tree_t *t1, avl_tree_t *t2); 400 401 static isns_portal_t * 402 isnst_lookup_portal(struct sockaddr_storage *sa); 403 404 static isns_portal_t * 405 isnst_add_to_portal_list(struct sockaddr_storage *sa, avl_tree_t *portal_list); 406 407 static void 408 isnst_remove_from_portal_list(struct sockaddr_storage *sa, 409 avl_tree_t *portal_list); 410 411 static int 412 isnst_portal_avl_compare(const void *t1, const void *t2); 413 414 415 416 417 418 419 it_cfg_status_t 420 isnst_config_merge(it_config_t *cfg) 421 { 422 boolean_t new_isns_state = B_FALSE; 423 iscsit_isns_svr_t *isns_svr, *next_isns_svr; 424 it_portal_t *cfg_isns_svr; 425 426 ISNS_GLOBAL_LOCK(); 427 428 /* 429 * Determine whether iSNS is enabled in the new config. 430 * Isns property may not be set up yet. 431 */ 432 (void) nvlist_lookup_boolean_value(cfg->config_global_properties, 433 PROP_ISNS_ENABLED, &new_isns_state); 434 435 /* Delete iSNS servers that are no longer part of the config */ 436 for (isns_svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs); 437 isns_svr != NULL; 438 isns_svr = next_isns_svr) { 439 next_isns_svr = list_next( 440 &iscsit_global.global_isns_cfg.isns_svrs, isns_svr); 441 if (it_sns_svr_lookup(cfg, &isns_svr->svr_sa) == NULL) 442 isnst_mark_delete_isns(isns_svr); 443 } 444 445 /* Add new iSNS servers */ 446 for (cfg_isns_svr = cfg->config_isns_svr_list; 447 cfg_isns_svr != NULL; 448 cfg_isns_svr = cfg_isns_svr->next) { 449 isns_svr = iscsit_isns_svr_lookup(&cfg_isns_svr->portal_addr); 450 if (isns_svr == NULL) { 451 iscsit_add_isns(cfg_isns_svr); 452 } else if (isns_svr->svr_delete_needed) { 453 /* 454 * If reactivating a server that was being 455 * deleted, turn it into a reset. 456 */ 457 isns_svr->svr_delete_needed = B_FALSE; 458 isns_svr->svr_reset_needed = B_TRUE; 459 } 460 } 461 462 /* 463 * There is no "modify case" since the user specifies a complete 464 * server list each time. A modify is the same as a remove+add. 465 */ 466 467 /* Start/Stop iSNS if necessary */ 468 iscsit_set_isns(new_isns_state); 469 470 ISNS_GLOBAL_UNLOCK(); 471 472 473 /* Wake up the monitor thread to complete the state change */ 474 isnst_monitor_awaken(); 475 476 return (0); 477 } 478 479 int 480 iscsit_isns_init(iscsit_hostinfo_t *hostinfo) 481 { 482 mutex_init(&iscsit_global.global_isns_cfg.isns_mutex, NULL, 483 MUTEX_DEFAULT, NULL); 484 485 ISNS_GLOBAL_LOCK(); 486 mutex_init(&iscsit_isns_mutex, NULL, MUTEX_DEFAULT, NULL); 487 488 iscsit_global.global_isns_cfg.isns_state = B_FALSE; 489 list_create(&iscsit_global.global_isns_cfg.isns_svrs, 490 sizeof (iscsit_isns_svr_t), offsetof(iscsit_isns_svr_t, svr_ln)); 491 avl_create(&isns_tpg_portals, isnst_portal_avl_compare, 492 sizeof (isns_portal_t), offsetof(isns_portal_t, portal_node)); 493 avl_create(&isns_all_portals, isnst_portal_avl_compare, 494 sizeof (isns_portal_t), offsetof(isns_portal_t, portal_node)); 495 num_default_portals = 0; 496 if (hostinfo->length > ISCSIT_MAX_HOSTNAME_LEN) 497 hostinfo->length = ISCSIT_MAX_HOSTNAME_LEN; 498 isns_eid = kmem_alloc(hostinfo->length, KM_SLEEP); 499 (void) strlcpy(isns_eid, hostinfo->fqhn, hostinfo->length); 500 avl_create(&isns_target_list, isnst_tgt_avl_compare, 501 sizeof (isns_target_t), offsetof(isns_target_t, target_node)); 502 503 /* initialize isns client */ 504 mutex_init(&isns_monitor_mutex, NULL, MUTEX_DEFAULT, NULL); 505 mutex_init(&esi.esi_mutex, NULL, MUTEX_DEFAULT, NULL); 506 isns_monitor_thr_id = NULL; 507 monitor_idle_interval = ISNS_IDLE_TIME * drv_usectohz(1000000); 508 cv_init(&isns_idle_cv, NULL, CV_DEFAULT, NULL); 509 cv_init(&esi.esi_cv, NULL, CV_DEFAULT, NULL); 510 xid = 0; 511 ISNS_GLOBAL_UNLOCK(); 512 513 return (0); 514 } 515 516 void 517 iscsit_isns_fini() 518 { 519 ISNS_GLOBAL_LOCK(); 520 521 /* 522 * The following call to iscsit_set_isns waits until all the 523 * iSNS servers have been fully deactivated and the monitor and esi 524 * threads have stopped. 525 */ 526 iscsit_set_isns(B_FALSE); 527 528 /* Clean up data structures */ 529 mutex_destroy(&isns_monitor_mutex); 530 cv_destroy(&isns_idle_cv); 531 mutex_destroy(&esi.esi_mutex); 532 cv_destroy(&esi.esi_cv); 533 mutex_destroy(&iscsit_isns_mutex); 534 535 /* 536 * Free our EID and target list. 537 */ 538 539 if (isns_eid) { 540 kmem_free(isns_eid, strlen(isns_eid) + 1); 541 isns_eid = NULL; 542 } 543 544 iscsit_global.global_isns_cfg.isns_state = B_FALSE; 545 avl_destroy(&isns_target_list); 546 list_destroy(&iscsit_global.global_isns_cfg.isns_svrs); 547 avl_destroy(&isns_tpg_portals); 548 avl_destroy(&isns_all_portals); 549 num_default_portals = 0; 550 ISNS_GLOBAL_UNLOCK(); 551 552 mutex_destroy(&iscsit_global.global_isns_cfg.isns_mutex); 553 } 554 555 static void 556 iscsit_set_isns(boolean_t state) 557 { 558 iscsit_isns_svr_t *svr; 559 560 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 561 562 /* 563 * Update state and isns stop flag 564 */ 565 if (iscsit_global.global_isns_cfg.isns_state != state) { 566 /* reset retry count for all servers */ 567 for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs); 568 svr != NULL; 569 svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, 570 svr)) { 571 svr->svr_retry_count = 0; 572 } 573 574 iscsit_global.global_isns_cfg.isns_state = state; 575 576 if (state) { 577 isnst_start(); 578 } else { 579 isnst_stop(); 580 } 581 } 582 } 583 584 void 585 iscsit_add_isns(it_portal_t *cfg_svr) 586 { 587 iscsit_isns_svr_t *svr; 588 589 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 590 591 svr = kmem_zalloc(sizeof (iscsit_isns_svr_t), KM_SLEEP); 592 bcopy(&cfg_svr->portal_addr, &svr->svr_sa, 593 sizeof (struct sockaddr_storage)); 594 avl_create(&svr->svr_target_list, isnst_tgt_avl_compare, 595 sizeof (isns_target_t), offsetof(isns_target_t, target_node)); 596 svr->svr_esi_interval = isns_default_esi_interval; 597 598 /* put it on the global isns server list */ 599 list_insert_tail(&iscsit_global.global_isns_cfg.isns_svrs, svr); 600 } 601 602 void 603 isnst_mark_delete_isns(iscsit_isns_svr_t *svr) 604 { 605 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 606 607 /* If monitor thread not running, finish delete here */ 608 if (iscsit_global.global_isns_cfg.isns_state == B_FALSE) { 609 isnst_finish_delete_isns(svr); 610 } else { 611 svr->svr_delete_needed = B_TRUE; 612 } 613 614 } 615 616 void 617 isnst_finish_delete_isns(iscsit_isns_svr_t *svr) 618 { 619 620 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 621 isnst_clear_target_list(svr); 622 623 list_remove(&iscsit_global.global_isns_cfg.isns_svrs, svr); 624 /* free the memory */ 625 avl_destroy(&svr->svr_target_list); 626 kmem_free(svr, sizeof (*svr)); 627 } 628 629 static iscsit_isns_svr_t * 630 iscsit_isns_svr_lookup(struct sockaddr_storage *sa) 631 { 632 iscsit_isns_svr_t *svr; 633 it_portal_t portal1; 634 635 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 636 637 bcopy(sa, &portal1.portal_addr, sizeof (struct sockaddr_storage)); 638 639 for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs); 640 svr != NULL; 641 svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, svr)) { 642 if (it_sa_compare(&svr->svr_sa, sa) == 0) 643 return (svr); 644 } 645 646 return (NULL); 647 } 648 649 static isns_target_info_t * 650 isnst_create_target_info(iscsit_tgt_t *target) 651 { 652 653 isns_target_info_t *ti; 654 isns_tpgt_t *tig; 655 isns_tpgt_addr_t *tip; 656 iscsit_tpgt_t *tpgt; 657 iscsit_tpg_t *tpg; 658 iscsit_portal_t *tp; 659 char *str; 660 661 ti = kmem_zalloc(sizeof (isns_target_info_t), KM_SLEEP); 662 list_create(&ti->ti_tpgt_list, 663 sizeof (isns_tpgt_t), offsetof(isns_tpgt_t, ti_tpgt_ln)); 664 idm_refcnt_init(&ti->ti_refcnt, ti); 665 666 mutex_enter(&target->target_mutex); 667 (void) strncpy(ti->ti_tgt_name, target->target_name, 668 MAX_ISCSI_NODENAMELEN); 669 670 671 if (nvlist_lookup_string(target->target_props, PROP_ALIAS, 672 &str) == 0) { 673 (void) strncpy(ti->ti_tgt_alias, str, MAX_ISCSI_NODENAMELEN); 674 } 675 676 tpgt = avl_first(&target->target_tpgt_list); 677 ASSERT(tpgt != NULL); 678 do { 679 tig = kmem_zalloc(sizeof (isns_tpgt_t), KM_SLEEP); 680 list_create(&tig->ti_portal_list, sizeof (isns_tpgt_addr_t), 681 offsetof(isns_tpgt_addr_t, portal_ln)); 682 tig->ti_tpgt_tag = tpgt->tpgt_tag; 683 684 /* 685 * Only need portal list for non-default portal. 686 */ 687 if (tpgt->tpgt_tag != ISCSIT_DEFAULT_TPGT) { 688 tpg = tpgt->tpgt_tpg; 689 690 mutex_enter(&tpg->tpg_mutex); 691 692 tp = avl_first(&tpg->tpg_portal_list); 693 do { 694 tip = kmem_zalloc(sizeof (isns_tpgt_addr_t), 695 KM_SLEEP); 696 bcopy(&tp->portal_addr, &tip->portal_addr, 697 sizeof (tip->portal_addr)); 698 list_insert_tail(&tig->ti_portal_list, tip); 699 700 tp = AVL_NEXT(&tpg->tpg_portal_list, tp); 701 } while (tp != NULL); 702 mutex_exit(&tpg->tpg_mutex); 703 } 704 list_insert_tail(&ti->ti_tpgt_list, tig); 705 tpgt = AVL_NEXT(&target->target_tpgt_list, tpgt); 706 } while (tpgt != NULL); 707 mutex_exit(&target->target_mutex); 708 709 return (ti); 710 } 711 712 static void 713 isnst_clear_target_info_cb(void *arg) 714 { 715 isns_target_info_t *ti = (isns_target_info_t *)arg; 716 isns_tpgt_t *tig; 717 isns_tpgt_addr_t *tip; 718 719 while ((tig = list_remove_head(&ti->ti_tpgt_list)) != NULL) { 720 while ((tip = list_remove_head(&tig->ti_portal_list)) != NULL) { 721 kmem_free(tip, sizeof (isns_tpgt_addr_t)); 722 } 723 list_destroy(&tig->ti_portal_list); 724 kmem_free(tig, sizeof (isns_tpgt_t)); 725 } 726 list_destroy(&ti->ti_tpgt_list); 727 idm_refcnt_destroy(&ti->ti_refcnt); 728 kmem_free(ti, sizeof (isns_target_info_t)); 729 } 730 731 732 /* 733 * iscsit_isns_register 734 * called by iscsit when a target goes online 735 */ 736 int 737 iscsit_isns_register(iscsit_tgt_t *target) 738 { 739 isns_target_t *itarget, tmptgt; 740 avl_index_t where; 741 742 mutex_enter(&iscsit_isns_mutex); 743 744 tmptgt.target = target; 745 if ((itarget = (isns_target_t *)avl_find(&isns_target_list, 746 &tmptgt, &where)) == NULL) { 747 itarget = kmem_zalloc(sizeof (isns_target_t), KM_SLEEP); 748 749 itarget->target = target; 750 avl_insert(&isns_target_list, (void *)itarget, where); 751 } else { 752 ASSERT(0); 753 } 754 755 /* Copy the target info so it will last beyond deregister */ 756 itarget->target_info = isnst_create_target_info(target); 757 idm_refcnt_hold(&itarget->target_info->ti_refcnt); 758 759 isns_targets_changed = B_TRUE; 760 761 mutex_exit(&iscsit_isns_mutex); 762 763 isnst_monitor_awaken(); 764 return (0); 765 } 766 767 /* 768 * iscsit_isns_deregister 769 * called by iscsit when a target goes offline 770 */ 771 int 772 iscsit_isns_deregister(iscsit_tgt_t *target) 773 { 774 isns_target_t *itarget, tmptgt; 775 isns_target_info_t *ti; 776 777 tmptgt.target = target; 778 779 mutex_enter(&iscsit_isns_mutex); 780 781 itarget = avl_find(&isns_target_list, &tmptgt, NULL); 782 ASSERT(itarget != NULL); 783 ti = itarget->target_info; 784 785 /* 786 * The main thread is done with the target_info object. 787 * Make sure the delete callback is called when 788 * all the svrs are done with it. 789 */ 790 idm_refcnt_rele(&ti->ti_refcnt); 791 idm_refcnt_async_wait_ref(&ti->ti_refcnt, 792 (idm_refcnt_cb_t *)&isnst_clear_target_info_cb); 793 794 itarget->target_info = NULL; 795 avl_remove(&isns_target_list, itarget); 796 kmem_free(itarget, sizeof (isns_target_t)); 797 798 isns_targets_changed = B_TRUE; 799 800 mutex_exit(&iscsit_isns_mutex); 801 802 isnst_monitor_awaken(); 803 return (0); 804 } 805 806 /* 807 * iscsit_isns_target_update 808 * This function is called by iscsit when a target's configuration 809 * has changed. 810 */ 811 812 void 813 iscsit_isns_target_update(iscsit_tgt_t *target) 814 { 815 isns_target_t *itarget, tmptgt; 816 817 mutex_enter(&iscsit_isns_mutex); 818 819 /* 820 * If iscsit calls us to modify a target, that target should 821 * already exist in the isns_svr_list 822 */ 823 tmptgt.target = target; 824 itarget = avl_find(&isns_target_list, &tmptgt, NULL); 825 if (itarget == NULL) { 826 /* 827 * If target-update gets called while the target is still 828 * offline, then there is nothing to do. The target will be 829 * completely registered when it comes online. 830 */ 831 mutex_exit(&iscsit_isns_mutex); 832 return; 833 } 834 835 itarget->target_update_needed = B_TRUE; 836 837 isns_targets_changed = B_TRUE; 838 839 mutex_exit(&iscsit_isns_mutex); 840 841 isnst_monitor_awaken(); 842 } 843 844 static void 845 isnst_start() 846 { 847 ISNST_LOG(CE_NOTE, "**** isnst_start"); 848 849 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 850 851 /* 852 * Start ESI thread(s) 853 */ 854 isnst_esi_start(); 855 856 /* 857 * Create a thread for monitoring server communications 858 */ 859 isnst_monitor_start(); 860 } 861 862 static void 863 isnst_stop() 864 { 865 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 866 ISNST_LOG(CE_NOTE, "**** isnst_stop"); 867 868 869 ISNS_GLOBAL_UNLOCK(); 870 isnst_esi_stop(); 871 isnst_monitor_stop(); 872 ISNS_GLOBAL_LOCK(); 873 } 874 875 static void 876 isnst_monitor_start(void) 877 { 878 ISNST_LOG(CE_NOTE, "isnst_monitor_start"); 879 880 881 mutex_enter(&isns_monitor_mutex); 882 ASSERT(!isns_monitor_thr_running); 883 isns_monitor_thr_id = thread_create(NULL, 0, 884 isnst_monitor, NULL, 0, &p0, TS_RUN, minclsyspri); 885 while (!isns_monitor_thr_running) 886 cv_wait(&isns_idle_cv, &isns_monitor_mutex); 887 mutex_exit(&isns_monitor_mutex); 888 } 889 890 static void 891 isnst_monitor_stop(void) 892 { 893 ISNST_LOG(CE_NOTE, "isnst_monitor_stop"); 894 895 mutex_enter(&isns_monitor_mutex); 896 if (isns_monitor_thr_running) { 897 isns_monitor_thr_running = B_FALSE; 898 cv_signal(&isns_idle_cv); 899 mutex_exit(&isns_monitor_mutex); 900 901 thread_join(isns_monitor_thr_did); 902 return; 903 } 904 mutex_exit(&isns_monitor_mutex); 905 } 906 907 /* 908 * isnst_update_server_timestamp 909 * 910 * When we receive an ESI request, update the timestamp for the server. 911 * If we don't receive one for the specified period of time, we'll attempt 912 * to re-register. 913 * 914 */ 915 static boolean_t 916 isnst_update_server_timestamp(struct sockaddr_storage *ss) 917 { 918 iscsit_isns_svr_t *svr; 919 920 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 921 922 /* 923 * Find the server and update the timestamp 924 */ 925 for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs); 926 svr != NULL; 927 svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, svr)) { 928 /* 929 * Note that the port number in incoming probe will be 930 * different than the iSNS server's port number. 931 */ 932 if (idm_ss_compare(ss, &svr->svr_sa, 933 B_TRUE /* v4_mapped_as_v4 */, 934 B_FALSE /* don't compare_ports */) == 0) { 935 break; 936 } 937 } 938 939 if (svr != NULL) { 940 /* Update the timestamp we keep for this server */ 941 svr->svr_last_msg = ddi_get_lbolt(); 942 /* 943 * If we receive ESI probe from a server we are not 944 * registered to, then cause a re-reg attempt. 945 */ 946 if (!svr->svr_registered) { 947 isnst_monitor_awaken(); 948 } 949 return (B_TRUE); 950 } 951 952 return (B_FALSE); 953 } 954 955 956 /* 957 * isnst_monitor_all_servers -- loop through all servers 958 */ 959 960 961 static void 962 isnst_monitor_all_servers() 963 { 964 iscsit_isns_svr_t *svr, *next_svr; 965 boolean_t enabled; 966 list_t *svr_list; 967 int rc; 968 969 svr_list = &iscsit_global.global_isns_cfg.isns_svrs; 970 971 ISNS_GLOBAL_LOCK(); 972 973 isnst_copy_global_status_changes(); 974 975 enabled = iscsit_global.global_isns_cfg.isns_state; 976 for (svr = list_head(svr_list); svr != NULL; svr = next_svr) { 977 next_svr = list_next(svr_list, svr); 978 979 rc = isnst_monitor_one_server(svr, enabled); 980 if (rc != 0) { 981 svr->svr_retry_count++; 982 if (svr->svr_registered && 983 svr->svr_retry_count > isns_max_retry) { 984 char server_buf[IDM_SA_NTOP_BUFSIZ]; 985 986 if (! svr->svr_reset_needed) { 987 ISNST_LOG(CE_WARN, 988 "isnst: iSNS server %s" 989 " not responding (rc=%d).", 990 idm_sa_ntop(&svr->svr_sa, 991 server_buf, sizeof (server_buf)), 992 rc); 993 svr->svr_reset_needed = B_TRUE; 994 } 995 } 996 } else { 997 svr->svr_retry_count = 0; 998 } 999 /* 1000 * If we have finished unregistering this server, 1001 * it is now OK to delete it. 1002 */ 1003 if (svr->svr_delete_needed == B_TRUE && 1004 svr->svr_registered == B_FALSE) { 1005 isnst_finish_delete_isns(svr); 1006 } 1007 } 1008 ISNS_GLOBAL_UNLOCK(); 1009 } 1010 1011 static void 1012 isnst_monitor_awaken(void) 1013 { 1014 mutex_enter(&isns_monitor_mutex); 1015 if (isns_monitor_thr_running) { 1016 DTRACE_PROBE(iscsit__isns__monitor__awaken); 1017 cv_signal(&isns_idle_cv); 1018 } 1019 mutex_exit(&isns_monitor_mutex); 1020 } 1021 1022 /* 1023 * isnst_monitor -- the monitor thread for iSNS 1024 */ 1025 /*ARGSUSED*/ 1026 static void 1027 isnst_monitor(void *arg) 1028 { 1029 mutex_enter(&isns_monitor_mutex); 1030 isns_monitor_thr_did = curthread->t_did; 1031 isns_monitor_thr_running = B_TRUE; 1032 cv_signal(&isns_idle_cv); 1033 1034 /* 1035 * Start with a short pause (5 sec) to allow all targets 1036 * to be registered before we send register-all. This is 1037 * purely an optimization to cut down on the number of 1038 * messages we send to the iSNS server. 1039 */ 1040 mutex_exit(&isns_monitor_mutex); 1041 delay(drv_usectohz(isns_initial_delay * 1000000)); 1042 mutex_enter(&isns_monitor_mutex); 1043 1044 /* Force an initialization of isns_all_portals */ 1045 mutex_enter(&iscsit_isns_mutex); 1046 isns_portals_changed = B_TRUE; 1047 mutex_exit(&iscsit_isns_mutex); 1048 1049 while (isns_monitor_thr_running) { 1050 1051 /* Update servers */ 1052 mutex_exit(&isns_monitor_mutex); 1053 isnst_monitor_all_servers(); 1054 mutex_enter(&isns_monitor_mutex); 1055 1056 /* If something needs attention, go right to the top */ 1057 mutex_enter(&iscsit_isns_mutex); 1058 if (isns_targets_changed || isns_portals_changed) { 1059 DTRACE_PROBE(iscsit__isns__monitor__reenter); 1060 mutex_exit(&iscsit_isns_mutex); 1061 /* isns_monitor_mutex still held */ 1062 continue; 1063 } 1064 mutex_exit(&iscsit_isns_mutex); 1065 1066 /* 1067 * Keep running until isns_monitor_thr_running is set to 1068 * B_FALSE. 1069 */ 1070 if (! isns_monitor_thr_running) 1071 break; 1072 1073 DTRACE_PROBE(iscsit__isns__monitor__sleep); 1074 (void) cv_timedwait(&isns_idle_cv, &isns_monitor_mutex, 1075 ddi_get_lbolt() + monitor_idle_interval); 1076 DTRACE_PROBE1(iscsit__isns__monitor__wakeup, 1077 boolean_t, isns_monitor_thr_running); 1078 } 1079 1080 mutex_exit(&isns_monitor_mutex); 1081 1082 /* Update the servers one last time for deregistration */ 1083 isnst_monitor_all_servers(); 1084 1085 /* Clean up the all-portals list */ 1086 ISNS_GLOBAL_LOCK(); 1087 isnst_clear_default_portals(); 1088 ISNS_GLOBAL_UNLOCK(); 1089 1090 /* terminate the thread at the last */ 1091 thread_exit(); 1092 } 1093 1094 static int 1095 isnst_monitor_one_server(iscsit_isns_svr_t *svr, boolean_t enabled) 1096 { 1097 int rc = 0; 1098 isns_target_t *itarget; 1099 1100 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 1101 1102 /* 1103 * First, take care of the case where iSNS is no longer enabled. 1104 * 1105 */ 1106 1107 if (enabled == B_FALSE || svr->svr_delete_needed) { 1108 /* 1109 * Just try one time to deregister all from server. 1110 * Doesn't matter if this fails. We're disabled. 1111 */ 1112 (void) isnst_update_one_server(svr, NULL, ISNS_DEREGISTER_ALL); 1113 isnst_set_server_status(svr, B_FALSE); 1114 return (0); 1115 } 1116 1117 retry_replace_all: 1118 /* 1119 * If the server needs replace-all, check if it should 1120 * be a DevDereg (i.e. if the last target is gone.) 1121 */ 1122 1123 if (svr->svr_registered && svr->svr_reset_needed) { 1124 /* Send DevDereg if last registered target */ 1125 isns_target_t *jtarget; 1126 for (jtarget = avl_first(&svr->svr_target_list); 1127 jtarget != NULL; 1128 jtarget = AVL_NEXT(&svr->svr_target_list, jtarget)) { 1129 if (!jtarget->target_delete_needed) { 1130 break; 1131 } 1132 } 1133 /* 1134 * jtarget is null IFF all tgts need deletion, 1135 * and there are no new targets to register. 1136 */ 1137 if (jtarget == NULL) { 1138 rc = isnst_update_one_server(svr, NULL, 1139 ISNS_DEREGISTER_ALL); 1140 if (rc != 0) { 1141 return (rc); 1142 } 1143 isnst_set_server_status(svr, B_FALSE); 1144 return (0); 1145 } 1146 } 1147 1148 /* 1149 * If the server is not yet registered, do the registration 1150 */ 1151 if (! svr->svr_registered || svr->svr_reset_needed) { 1152 1153 if (avl_numnodes(&svr->svr_target_list) == 0) { 1154 /* If no targets, nothing to register */ 1155 return (0); 1156 } 1157 if ((rc = isnst_update_one_server(svr, NULL, 1158 ISNS_REGISTER_ALL)) != 0) { 1159 /* Registration failed */ 1160 return (rc); 1161 } 1162 isnst_set_server_status(svr, B_TRUE); 1163 1164 } 1165 1166 /* The following checks are expensive, so only do them if needed */ 1167 if (svr->svr_targets_changed) { 1168 isns_target_t *next_target; 1169 /* 1170 * If there is a target to be deleted, send the 1171 * deletion request for one target at a time. 1172 */ 1173 for (itarget = avl_first(&svr->svr_target_list); 1174 itarget != NULL; 1175 itarget = next_target) { 1176 next_target = AVL_NEXT(&svr->svr_target_list, itarget); 1177 if (itarget->target_delete_needed) { 1178 /* See if last non-deleted target */ 1179 isns_target_t *jtarget; 1180 ASSERT(itarget->target_registered); 1181 for (jtarget = avl_first(&svr->svr_target_list); 1182 jtarget != NULL; 1183 jtarget = AVL_NEXT(&svr->svr_target_list, 1184 jtarget)) { 1185 if (jtarget->target_registered && 1186 !jtarget->target_delete_needed) { 1187 break; 1188 } 1189 } 1190 /* jtarget is null if last registered tgt */ 1191 if (jtarget == NULL) { 1192 /* 1193 * Removing last tgt -- deregister all. 1194 * Doesn't matter if this fails. 1195 * We're disabled. 1196 */ 1197 rc = isnst_update_one_server(svr, 1198 NULL, ISNS_DEREGISTER_ALL); 1199 if (rc != 0) { 1200 return (rc); 1201 } 1202 isnst_set_server_status(svr, B_FALSE); 1203 return (0); 1204 } 1205 rc = isnst_update_one_server(svr, 1206 itarget, ISNS_DEREGISTER_TARGET); 1207 if (rc != 0 && isnst_retry_registration(rc)) { 1208 /* Retryable code => try replace-all */ 1209 svr->svr_reset_needed = B_TRUE; 1210 goto retry_replace_all; 1211 } 1212 1213 if (rc != 0) { 1214 return (rc); 1215 } 1216 isnst_clear_from_target_list(itarget, 1217 &svr->svr_target_list); 1218 } 1219 } 1220 1221 /* If any target needs a register or an update, do so */ 1222 itarget = avl_first(&svr->svr_target_list); 1223 while (itarget) { 1224 if (!itarget->target_registered || 1225 itarget->target_update_needed) { 1226 1227 /* Try to update existing info for one tgt */ 1228 rc = isnst_update_one_server(svr, 1229 itarget, 1230 ISNS_MODIFY_TARGET); 1231 if (rc != 0 && isnst_retry_registration(rc)) { 1232 /* Retryable code => try replace-all */ 1233 svr->svr_reset_needed = B_TRUE; 1234 goto retry_replace_all; 1235 } 1236 if (rc != 0) { 1237 return (rc); 1238 } 1239 itarget->target_update_needed = 1240 B_FALSE; 1241 itarget->target_registered = B_TRUE; 1242 } 1243 itarget = AVL_NEXT(&svr->svr_target_list, 1244 itarget); 1245 } 1246 1247 /* 1248 * We have gone through all the cases -- this server 1249 * is now up to date. 1250 */ 1251 svr->svr_targets_changed = B_FALSE; 1252 } 1253 1254 1255 if (isns_use_esi) { 1256 /* 1257 * If using ESI, and no ESI request is received within 1258 * MAX_ESI_INTERVALS (3) number of intervals, we'll 1259 * try to re-register with the server. The server will 1260 * delete our information if we fail to respond for 2 1261 * ESI intervals. 1262 */ 1263 if (ddi_get_lbolt() >= (svr->svr_last_msg + 1264 drv_usectohz(svr->svr_esi_interval * 1000000 * 1265 MAX_ESI_INTERVALS))) { 1266 /* re-register everything */ 1267 svr->svr_reset_needed = B_TRUE; 1268 goto retry_replace_all; 1269 } 1270 } else { 1271 /* 1272 * If not using ESI, make sure to ping server during 1273 * each registration period. Do this at half the 1274 * registration interval, so we won't get timed out. 1275 */ 1276 if (ddi_get_lbolt() >= (svr->svr_last_msg + 1277 drv_usectohz(isns_registration_period * (1000000/3)))) { 1278 /* Send a self-query as a keepalive. */ 1279 rc = isnst_keepalive(svr); 1280 if (rc != 0 && isnst_retry_registration(rc)) { 1281 /* Retryable code => try replace-all */ 1282 svr->svr_reset_needed = B_TRUE; 1283 goto retry_replace_all; 1284 } 1285 if (rc != 0) { 1286 return (rc); 1287 } 1288 } 1289 } 1290 return (0); 1291 1292 } 1293 1294 /* 1295 * isnst_mark_deleted_target -- find tgt in svr list but not global list 1296 */ 1297 static void 1298 isnst_mark_deleted_targets(iscsit_isns_svr_t *svr) 1299 { 1300 isns_target_t *itarget, *nxt_target, tmptgt; 1301 1302 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 1303 ASSERT(mutex_owned(&iscsit_isns_mutex)); 1304 1305 for (itarget = avl_first(&svr->svr_target_list); 1306 itarget != NULL; 1307 itarget = nxt_target) { 1308 tmptgt.target = itarget->target; 1309 nxt_target = AVL_NEXT(&svr->svr_target_list, itarget); 1310 if (avl_find(&isns_target_list, &tmptgt, NULL) == NULL) { 1311 if (itarget->target_registered) { 1312 itarget->target_delete_needed = B_TRUE; 1313 } else { 1314 isnst_clear_from_target_list(itarget, 1315 &svr->svr_target_list); 1316 } 1317 } 1318 } 1319 } 1320 1321 static isns_target_t * 1322 isnst_latch_to_target_list(isns_target_t *jtarget, avl_tree_t *target_list) 1323 { 1324 isns_target_t *itarget, tmptgt; 1325 avl_index_t where; 1326 1327 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 1328 ASSERT(mutex_owned(&iscsit_isns_mutex)); 1329 /* 1330 * Make sure this target isn't already in our list. 1331 */ 1332 1333 tmptgt.target = jtarget->target; 1334 if ((itarget = (isns_target_t *)avl_find(target_list, 1335 &tmptgt, &where)) == NULL) { 1336 itarget = kmem_zalloc(sizeof (isns_target_t), KM_SLEEP); 1337 1338 itarget->target = jtarget->target; 1339 itarget->target_info = jtarget->target_info; 1340 idm_refcnt_hold(&itarget->target_info->ti_refcnt); 1341 1342 avl_insert(target_list, (void *)itarget, where); 1343 } else { 1344 ASSERT(0); 1345 } 1346 1347 return (itarget); 1348 } 1349 1350 static void 1351 isnst_clear_target_list(iscsit_isns_svr_t *svr) 1352 { 1353 isns_target_t *itarget; 1354 1355 while ((itarget = avl_first(&svr->svr_target_list)) != NULL) { 1356 isnst_clear_from_target_list(itarget, 1357 &svr->svr_target_list); 1358 } 1359 } 1360 1361 static void 1362 isnst_clear_from_target_list(isns_target_t *jtarget, avl_tree_t *target_list) 1363 { 1364 isns_target_t *itarget, tmptgt; 1365 1366 tmptgt.target = jtarget->target; 1367 1368 if ((itarget = avl_find(target_list, &tmptgt, NULL)) 1369 != NULL) { 1370 1371 avl_remove(target_list, itarget); 1372 idm_refcnt_rele(&itarget->target_info->ti_refcnt); 1373 kmem_free(itarget, sizeof (isns_target_t)); 1374 } else { 1375 ASSERT(0); 1376 } 1377 } 1378 1379 /* 1380 * isnst_copy_global_status_changes -- update svrs to match iscsit 1381 * 1382 * At the end of this routine svr->svr_target_list has all the entries 1383 * in the current isns_target_list plus any targets that are marked 1384 * for deletion. 1385 */ 1386 static void 1387 isnst_copy_global_status_changes(void) 1388 { 1389 isns_target_t *ttarget, *itarget, tmptgt; 1390 iscsit_isns_svr_t *svr; 1391 1392 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 1393 1394 /* 1395 * Copy info about recent transitions from global state to 1396 * per-server state. We use the global state so that iscsit 1397 * functions can proceed without blocking on slow-to-release 1398 * iSNS locks. 1399 */ 1400 mutex_enter(&iscsit_isns_mutex); 1401 1402 /* 1403 * Periodically check for changed IP addresses. This function 1404 * sets isns_all_portals to the current set, and sets 1405 * isns_portals_changed if a portal is added or removed. 1406 */ 1407 isnst_monitor_default_portal_list(); 1408 1409 /* Initialize the per-server structs to some basic values */ 1410 for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs); 1411 svr != NULL; 1412 svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, 1413 svr)) { 1414 if (isns_portals_changed && svr->svr_registered) { 1415 /* 1416 * Cause re-register, for now, when portals change. 1417 * Eventually, we should add new portals one by one 1418 */ 1419 svr->svr_reset_needed = B_TRUE; 1420 } 1421 if (!svr->svr_registered) { 1422 /* To re-register, start with empty target list */ 1423 isnst_clear_target_list(svr); 1424 /* And set flag to add all current targets, below */ 1425 isns_targets_changed = B_TRUE; 1426 } else if (isns_targets_changed || svr->svr_reset_needed) { 1427 /* Mark to look for target changes */ 1428 isnst_mark_deleted_targets(svr); 1429 svr->svr_targets_changed = B_TRUE; 1430 } 1431 } 1432 1433 /* 1434 * If any target has been modified, tell all the svrs to 1435 * update that target. 1436 */ 1437 if (isns_targets_changed) { 1438 ttarget = avl_first(&isns_target_list); 1439 while (ttarget) { 1440 for (svr = list_head( 1441 &iscsit_global.global_isns_cfg.isns_svrs); 1442 svr != NULL; 1443 svr = list_next( 1444 &iscsit_global.global_isns_cfg.isns_svrs, 1445 svr)) { 1446 tmptgt.target = ttarget->target; 1447 itarget = avl_find( 1448 &svr->svr_target_list, 1449 &tmptgt, NULL); 1450 if (itarget == NULL) { 1451 /* Add a new target */ 1452 (void) isnst_latch_to_target_list( 1453 ttarget, &svr->svr_target_list); 1454 } else if (ttarget->target_update_needed) { 1455 /* Modify existing target */ 1456 itarget->target_update_needed = 1457 B_TRUE; 1458 } 1459 ttarget->target_update_needed = B_FALSE; 1460 } 1461 ttarget = AVL_NEXT(&isns_target_list, ttarget); 1462 } 1463 } 1464 1465 /* 1466 * Now we have updated the per-server state for all servers. 1467 * Clear the global state flags 1468 */ 1469 isns_targets_changed = B_FALSE; 1470 isns_portals_changed = B_FALSE; 1471 mutex_exit(&iscsit_isns_mutex); 1472 } 1473 1474 static int 1475 isnst_update_one_server(iscsit_isns_svr_t *svr, isns_target_t *itarget, 1476 isns_reg_type_t reg) 1477 { 1478 int rc = 0; 1479 1480 switch (reg) { 1481 case ISNS_DEREGISTER_TARGET: 1482 rc = isnst_deregister(svr, itarget); 1483 break; 1484 1485 case ISNS_DEREGISTER_ALL: 1486 rc = isnst_deregister(svr, NULL); 1487 break; 1488 1489 case ISNS_MODIFY_TARGET: 1490 case ISNS_REGISTER_TARGET: 1491 rc = isnst_register(svr, itarget, reg); 1492 break; 1493 1494 case ISNS_REGISTER_ALL: 1495 rc = isnst_register(svr, NULL, reg); 1496 break; 1497 1498 default: 1499 ASSERT(0); 1500 /* NOTREACHED */ 1501 } 1502 1503 return (rc); 1504 } 1505 1506 /* 1507 * isnst_retry_registration 1508 * 1509 * This function checks the return value from a registration pdu and 1510 * determines whether or not we should retry this request. If the 1511 * request is retried, it will do so as an "update", which means we 1512 * re-register everything. 1513 */ 1514 1515 static boolean_t 1516 isnst_retry_registration(int rsp_status_code) 1517 { 1518 boolean_t retry; 1519 1520 /* 1521 * The following are the error codes that indicate isns-client 1522 * and isns-server are out of synch. E.g. No-Such-Entry can 1523 * occur on a keepalive if the server has timed out our 1524 * connection. If we get one of these messages, we replace-all 1525 * right away to get back in synch faster. 1526 */ 1527 switch (rsp_status_code) { 1528 case ISNS_RSP_INVALID_REGIS: 1529 case ISNS_RSP_SRC_UNAUTHORIZED: 1530 case ISNS_RSP_BUSY: 1531 case ISNS_RSP_INVALID_UPDATE: 1532 case ISNS_RSP_NO_SUCH_ENTRY: 1533 retry = B_TRUE; 1534 break; 1535 default: 1536 retry = B_FALSE; 1537 break; 1538 } 1539 1540 return (retry); 1541 } 1542 1543 1544 1545 static int 1546 isnst_register(iscsit_isns_svr_t *svr, isns_target_t *itarget, 1547 isns_reg_type_t regtype) 1548 { 1549 struct sonode *so; 1550 int rc = 0; 1551 isns_pdu_t *pdu, *rsp; 1552 size_t pdu_size, rsp_size; 1553 1554 /* create TCP connection to the isns server */ 1555 so = isnst_open_so(&svr->svr_sa); 1556 if (so == NULL) { 1557 return (-1); 1558 } 1559 1560 pdu_size = isnst_make_reg_pdu(&pdu, itarget, svr, regtype); 1561 if (pdu_size == 0) { 1562 isnst_close_so(so); 1563 return (-1); 1564 } 1565 1566 rc = isnst_send_pdu(so, pdu); 1567 if (rc != 0) { 1568 kmem_free(pdu, pdu_size); 1569 isnst_close_so(so); 1570 return (rc); 1571 } 1572 1573 rsp_size = isnst_rcv_pdu(so, &rsp); 1574 if (rsp_size == 0) { 1575 kmem_free(pdu, pdu_size); 1576 isnst_close_so(so); 1577 return (-1); 1578 } 1579 1580 rc = isnst_verify_rsp(svr, pdu, rsp, rsp_size); 1581 1582 kmem_free(pdu, pdu_size); 1583 kmem_free(rsp, rsp_size); 1584 isnst_close_so(so); 1585 1586 return (rc); 1587 } 1588 1589 /* 1590 * isnst_make_reg_pdu: 1591 * Cases: 1592 * initial registration of all targets (replace-all) 1593 * initial registration of a single target (update-existing) 1594 * modify an existing target (update-existing) 1595 */ 1596 static size_t 1597 isnst_make_reg_pdu(isns_pdu_t **pdu, isns_target_t *itarget, 1598 iscsit_isns_svr_t *svr, isns_reg_type_t regtype) 1599 { 1600 size_t pdu_size; 1601 char *str; 1602 int len; 1603 isns_target_t *src; 1604 boolean_t reg_all = B_FALSE; 1605 uint16_t flags = 0; 1606 1607 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 1608 1609 /* 1610 * Find a source attribute for this registration. 1611 * 1612 * If updating a specific target for the first time, use that 1613 * target. 1614 * If already registered, use a registered target 1615 * Otherwise, use the first target we are going to register. 1616 */ 1617 ASSERT(avl_numnodes(&svr->svr_target_list) != 0); 1618 if (itarget != NULL && ! svr->svr_registered) { 1619 src = itarget; 1620 } else if (svr->svr_registered) { 1621 src = isnst_get_registered_source(svr); 1622 } else { 1623 /* 1624 * When registering to a server, and we don't know which 1625 * of our targets the server might already know, 1626 * cycle through each of our targets as source. The server 1627 * does source validation. If the server knows any of our 1628 * targets, it will eventually accept one of our registrations. 1629 */ 1630 int i; 1631 isns_target_t *jtarget; 1632 1633 if (svr->svr_last_target_index >= 1634 avl_numnodes(&svr->svr_target_list) - 1) { 1635 svr->svr_last_target_index = 0; 1636 } else { 1637 svr->svr_last_target_index++; 1638 } 1639 for (i = 0, jtarget = avl_first(&svr->svr_target_list); 1640 i < svr->svr_last_target_index; 1641 i++, jtarget = AVL_NEXT(&svr->svr_target_list, jtarget)) { 1642 ASSERT(jtarget != NULL); 1643 } 1644 src = jtarget; 1645 ASSERT(src != NULL); 1646 } 1647 1648 /* 1649 * Null target means we're replacing everything. 1650 */ 1651 if (itarget == NULL) { 1652 reg_all = B_TRUE; 1653 flags = ISNS_FLAG_REPLACE_REG; 1654 /* Reset itarget to the beginning of our list */ 1655 itarget = (isns_target_t *)avl_first(&svr->svr_target_list); 1656 } else if (regtype == ISNS_REGISTER_TARGET) { 1657 flags = ISNS_FLAG_REPLACE_REG; 1658 ASSERT(!itarget->target_delete_needed); 1659 } 1660 1661 pdu_size = isnst_create_pdu_header(ISNS_DEV_ATTR_REG, pdu, flags); 1662 if (pdu_size == 0) { 1663 return (0); 1664 } 1665 1666 /* Source Attribute */ 1667 1668 len = strlen(src->target_info->ti_tgt_name) + 1; 1669 if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 1670 len, src->target_info->ti_tgt_name, 0) != 0) { 1671 goto pdu_error; 1672 } 1673 1674 /* 1675 * Message Key Attributes - EID 1676 */ 1677 len = strlen(isns_eid) + 1; 1678 1679 if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID, 1680 len, isns_eid, 0) != 0) { 1681 goto pdu_error; 1682 } 1683 1684 /* Delimiter */ 1685 if (isnst_add_attr(*pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 1686 0, 0, 0) != 0) { 1687 goto pdu_error; 1688 } 1689 1690 /* 1691 * Operating Attributes 1692 */ 1693 if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID, len, 1694 isns_eid, 0) != 0) { 1695 goto pdu_error; 1696 } 1697 1698 1699 /* ENTITY Protocol - Section 6.2.2 */ 1700 if (isnst_add_attr(*pdu, pdu_size, 1701 ISNS_ENTITY_PROTOCOL_ATTR_ID, 1702 4, 0, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) { 1703 goto pdu_error; 1704 } 1705 1706 if (reg_all) { 1707 /* Registration Period -- use if not using ESI */ 1708 if (!isns_use_esi && 1709 isnst_add_attr(*pdu, pdu_size, 1710 ISNS_ENTITY_REG_PERIOD_ATTR_ID, 4, 1711 0, isns_registration_period) != 0) { 1712 goto pdu_error; 1713 } 1714 /* 1715 * Network entity portal information - only when 1716 * replacing all. Since targets are only registered 1717 * to iSNS when their portals are already registered 1718 * to iSNS, we can assume entity portals exist. 1719 */ 1720 if (isnst_reg_pdu_add_entity_portals(*pdu, pdu_size) != 0) { 1721 goto pdu_error; 1722 } 1723 1724 /* 1725 * Skip over delete-pending tgts. There must be at 1726 * least one non-deleted tgt, or it is an error. 1727 */ 1728 while (itarget->target_delete_needed) { 1729 itarget = AVL_NEXT(&svr->svr_target_list, 1730 itarget); 1731 ASSERT(itarget != NULL); 1732 } 1733 } 1734 1735 1736 /* Add information about each target or one target */ 1737 do { 1738 1739 /* iSCSI Name - Section 6.4.1 */ 1740 str = itarget->target_info->ti_tgt_name; 1741 len = strlen(str) + 1; 1742 if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 1743 len, str, 0) != 0) { 1744 goto pdu_error; 1745 } 1746 1747 /* iSCSI Node Type */ 1748 if (isnst_add_attr(*pdu, pdu_size, 1749 ISNS_ISCSI_NODE_TYPE_ATTR_ID, 4, 0, 1750 ISNS_TARGET_NODE_TYPE) != 0) { 1751 goto pdu_error; 1752 } 1753 1754 /* iSCSI Alias */ 1755 str = itarget->target_info->ti_tgt_alias; 1756 len = strnlen(str, 1757 sizeof (itarget->target_info->ti_tgt_alias)); 1758 if (len) { 1759 /* Found alias in property list */ 1760 if (isnst_add_attr(*pdu, pdu_size, 1761 ISNS_ISCSI_ALIAS_ATTR_ID, len+1, str, 0) != 0) { 1762 goto pdu_error; 1763 } 1764 } 1765 1766 if (isnst_reg_pdu_add_pg(*pdu, pdu_size, itarget) != 0) { 1767 goto pdu_error; 1768 } 1769 1770 /* If registering one target, then we are done. */ 1771 if (!reg_all) { 1772 break; 1773 } 1774 1775 /* Skip over delete-pending tgts */ 1776 do { 1777 itarget = AVL_NEXT(&svr->svr_target_list, itarget); 1778 } while (itarget != NULL && itarget->target_delete_needed); 1779 1780 } while (itarget != NULL); 1781 1782 return (pdu_size); 1783 1784 pdu_error: 1785 /* packet too large, no memory (or other error) */ 1786 len = ntohs((*pdu)->payload_len); 1787 if (len + 1000 > isns_message_buf_size) { 1788 /* Increase the PDU size we will ask for next time */ 1789 if (isns_message_buf_size * 2 <= ISNST_MAX_MSG_SIZE) { 1790 isns_message_buf_size *= 2; 1791 ISNST_LOG(CE_NOTE, 1792 "Increasing isns_message_buf_size to %d", 1793 isns_message_buf_size); 1794 } else { 1795 cmn_err(CE_WARN, "iscsit: isns: no space" 1796 " to send required PDU"); 1797 } 1798 } 1799 1800 kmem_free(*pdu, pdu_size); 1801 *pdu = NULL; 1802 1803 return (0); 1804 } 1805 1806 static int 1807 isnst_reg_pdu_add_entity_portals(isns_pdu_t *pdu, size_t pdu_size) 1808 { 1809 int rc = 0; 1810 isns_portal_t *iportal; 1811 1812 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 1813 1814 iportal = (isns_portal_t *)avl_first(&isns_all_portals); 1815 while (iportal != NULL) { 1816 /* Do not include ESI port if not using ESI */ 1817 if (isnst_add_portal_attr(pdu, pdu_size, 1818 ISNS_PORTAL_IP_ADDR_ATTR_ID, 1819 ISNS_PORTAL_PORT_ATTR_ID, 1820 &iportal->portal_addr, 1821 isns_use_esi /* ESI info */) != 0) { 1822 rc = -1; 1823 break; 1824 } 1825 iportal = AVL_NEXT(&isns_all_portals, iportal); 1826 } 1827 1828 return (rc); 1829 } 1830 1831 1832 /* 1833 * isnst_reg_pdu_add_pg -- add the PG and PGT entries for one target. 1834 */ 1835 static int 1836 isnst_reg_pdu_add_pg(isns_pdu_t *pdu, size_t pdu_size, isns_target_t *itarget) 1837 { 1838 int rval = 0; 1839 avl_tree_t null_portals; 1840 isns_target_info_t *ti; 1841 isns_tpgt_t *tig; 1842 1843 1844 ti = itarget->target_info; 1845 1846 /* 1847 * If all registered targets only use the default TPGT, then 1848 * we can skip sending PG info to the iSNS server. 1849 */ 1850 if (num_tpg_portals == 0) 1851 return (0); 1852 1853 /* 1854 * For each target, we start with the full portal list, 1855 * and then remove portals as we add them to TPGTs for this target. 1856 * At the end, all the remaining portals go into the "null pg". 1857 */ 1858 avl_create(&null_portals, isnst_portal_avl_compare, 1859 sizeof (isns_portal_t), offsetof(isns_portal_t, portal_node)); 1860 isnst_copy_portal_list(&isns_all_portals, &null_portals); 1861 1862 for (tig = list_head(&ti->ti_tpgt_list); 1863 tig != NULL; 1864 tig = list_next(&ti->ti_tpgt_list, tig)) { 1865 1866 if (tig->ti_tpgt_tag == ISCSIT_DEFAULT_TPGT) { 1867 /* Add portal info from list of default portals */ 1868 if (isnst_add_default_pg(pdu, pdu_size, 1869 &null_portals) != 0) { 1870 rval = 1; 1871 break; 1872 } 1873 } else { 1874 /* Add portal info from this target's TPGT entries */ 1875 if (isnst_add_tpg_pg(pdu, pdu_size, ti, 1876 &null_portals) != 0) { 1877 rval = 1; 1878 break; 1879 } 1880 } 1881 } 1882 1883 /* Add the remaining portals (if any) to the null PG */ 1884 if (rval == 0 && 1885 isnst_add_null_pg(pdu, pdu_size, &null_portals) != 0) { 1886 rval = 1; 1887 } 1888 isnst_clear_portal_list(&null_portals); 1889 avl_destroy(&null_portals); 1890 return (rval); 1891 } 1892 1893 static int 1894 isnst_add_tpg_pg(isns_pdu_t *pdu, size_t pdu_size, 1895 isns_target_info_t *ti, avl_tree_t *null_portal_list) 1896 { 1897 isns_tpgt_t *tig; 1898 isns_tpgt_addr_t *tip; 1899 int rval = 0; 1900 1901 tig = list_head(&ti->ti_tpgt_list); 1902 ASSERT(tig->ti_tpgt_tag != ISCSIT_DEFAULT_TPGT); 1903 1904 do { 1905 /* Write one TPGT's info into the PDU */ 1906 1907 /* Portal Group Tag */ 1908 if (isnst_add_attr(pdu, pdu_size, 1909 ISNS_PG_TAG_ATTR_ID, 4, 0, tig->ti_tpgt_tag) != 0) { 1910 rval = 1; 1911 goto pg_done; 1912 } 1913 1914 tip = list_head(&tig->ti_portal_list); 1915 ASSERT(tip != NULL); 1916 do { 1917 /* PG Portal Addr and PG Portal Port */ 1918 if (isnst_add_portal_attr(pdu, pdu_size, 1919 ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, 1920 ISNS_PG_PORTAL_PORT_ATTR_ID, 1921 &tip->portal_addr, B_FALSE /* ESI */) != 0) { 1922 rval = 1; 1923 goto pg_done; 1924 } 1925 isnst_remove_from_portal_list(&tip->portal_addr, 1926 null_portal_list); 1927 1928 tip = list_next(&tig->ti_portal_list, tip); 1929 } while (tip != NULL); 1930 tig = list_next(&ti->ti_tpgt_list, tig); 1931 } while (tig != NULL); 1932 1933 pg_done: 1934 return (rval); 1935 } 1936 1937 static int 1938 isnst_add_default_pg(isns_pdu_t *pdu, size_t pdu_size, 1939 avl_tree_t *null_portal_list) 1940 { 1941 isns_portal_t *iportal; 1942 1943 /* Portal Group Tag */ 1944 if (isnst_add_attr(pdu, pdu_size, 1945 ISNS_PG_TAG_ATTR_ID, 4, 0, ISCSIT_DEFAULT_TPGT) != 0) { 1946 return (1); 1947 } 1948 1949 for (iportal = avl_first(&isns_all_portals); 1950 iportal != NULL; 1951 iportal = AVL_NEXT(&isns_all_portals, iportal)) { 1952 if (iportal->portal_default) { 1953 /* PG Portal Addr and PG Portal Port */ 1954 if (isnst_add_portal_attr(pdu, pdu_size, 1955 ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, 1956 ISNS_PG_PORTAL_PORT_ATTR_ID, 1957 &iportal->portal_addr, B_FALSE) != 0) { 1958 return (1); 1959 } 1960 isnst_remove_from_portal_list(&iportal->portal_addr, 1961 null_portal_list); 1962 } 1963 } 1964 1965 return (0); 1966 } 1967 1968 static int 1969 isnst_add_null_pg(isns_pdu_t *pdu, size_t pdu_size, 1970 avl_tree_t *null_portal_list) 1971 { 1972 isns_portal_t *iportal; 1973 1974 /* NULL Portal Group Tag means no access via these portals. */ 1975 if (isnst_add_attr(pdu, pdu_size, 1976 ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) { 1977 return (1); 1978 } 1979 1980 for (iportal = avl_first(null_portal_list); 1981 iportal != NULL; 1982 iportal = AVL_NEXT(null_portal_list, iportal)) { 1983 if (isnst_add_portal_attr(pdu, pdu_size, 1984 ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, 1985 ISNS_PG_PORTAL_PORT_ATTR_ID, 1986 &iportal->portal_addr, B_FALSE) != 0) { 1987 return (1); 1988 } 1989 } 1990 1991 return (0); 1992 } 1993 1994 static int 1995 isnst_add_portal_attr(isns_pdu_t *pdu, size_t pdu_size, 1996 uint32_t ip_attr_id, uint32_t port_attr_id, 1997 struct sockaddr_storage *ss, boolean_t esi_info) 1998 { 1999 struct sockaddr_in *in; 2000 struct sockaddr_in6 *in6; 2001 uint32_t attr_numeric_data; 2002 void *inaddrp; 2003 2004 in = (struct sockaddr_in *)ss; 2005 in6 = (struct sockaddr_in6 *)ss; 2006 2007 ASSERT((ss->ss_family == AF_INET) || (ss->ss_family == AF_INET6)); 2008 2009 if (ss->ss_family == AF_INET) { 2010 attr_numeric_data = sizeof (in_addr_t); 2011 inaddrp = (void *)&in->sin_addr; 2012 } else if (ss->ss_family == AF_INET6) { 2013 attr_numeric_data = sizeof (in6_addr_t); 2014 inaddrp = (void *)&in6->sin6_addr; 2015 } 2016 2017 /* Portal Group Portal IP Address */ 2018 if (isnst_add_attr(pdu, pdu_size, ip_attr_id, 2019 16, inaddrp, attr_numeric_data) != 0) { 2020 return (1); 2021 } 2022 2023 /* Portal Group Portal Port */ 2024 if (isnst_add_attr(pdu, pdu_size, port_attr_id, 2025 4, 0, ntohs(in->sin_port)) != 0) { 2026 return (1); 2027 } 2028 2029 mutex_enter(&esi.esi_mutex); 2030 if (esi_info && esi.esi_valid) { 2031 /* ESI interval and port */ 2032 if (isnst_add_attr(pdu, pdu_size, ISNS_ESI_INTERVAL_ATTR_ID, 4, 2033 NULL, isns_default_esi_interval) != 0) { 2034 return (1); 2035 } 2036 2037 if (isnst_add_attr(pdu, pdu_size, ISNS_ESI_PORT_ATTR_ID, 4, 2038 NULL, esi.esi_port) != 0) { 2039 return (1); 2040 } 2041 } 2042 mutex_exit(&esi.esi_mutex); 2043 2044 return (0); 2045 } 2046 2047 static int 2048 isnst_deregister(iscsit_isns_svr_t *svr, isns_target_t *itarget) 2049 { 2050 int rc; 2051 isns_pdu_t *pdu, *rsp; 2052 size_t pdu_size, rsp_size; 2053 struct sonode *so; 2054 2055 so = isnst_open_so(&svr->svr_sa); 2056 2057 if (so == NULL) { 2058 return (-1); 2059 } 2060 2061 pdu_size = isnst_make_dereg_pdu(svr, &pdu, itarget); 2062 if (pdu_size == 0) { 2063 isnst_close_so(so); 2064 return (-1); 2065 } 2066 2067 rc = isnst_send_pdu(so, pdu); 2068 if (rc != 0) { 2069 isnst_close_so(so); 2070 kmem_free(pdu, pdu_size); 2071 return (rc); 2072 } 2073 2074 rsp_size = isnst_rcv_pdu(so, &rsp); 2075 if (rsp_size == 0) { 2076 isnst_close_so(so); 2077 kmem_free(pdu, pdu_size); 2078 return (-1); 2079 } 2080 2081 rc = isnst_verify_rsp(svr, pdu, rsp, rsp_size); 2082 2083 isnst_close_so(so); 2084 kmem_free(pdu, pdu_size); 2085 kmem_free(rsp, rsp_size); 2086 2087 return (rc); 2088 } 2089 2090 static int 2091 isnst_keepalive(iscsit_isns_svr_t *svr) 2092 { 2093 int rc; 2094 isns_pdu_t *pdu, *rsp; 2095 size_t pdu_size, rsp_size; 2096 struct sonode *so; 2097 2098 so = isnst_open_so(&svr->svr_sa); 2099 2100 if (so == NULL) { 2101 return (-1); 2102 } 2103 2104 pdu_size = isnst_make_keepalive_pdu(svr, &pdu); 2105 if (pdu_size == 0) { 2106 isnst_close_so(so); 2107 return (-1); 2108 } 2109 2110 rc = isnst_send_pdu(so, pdu); 2111 if (rc != 0) { 2112 isnst_close_so(so); 2113 kmem_free(pdu, pdu_size); 2114 return (rc); 2115 } 2116 2117 rsp_size = isnst_rcv_pdu(so, &rsp); 2118 if (rsp_size == 0) { 2119 isnst_close_so(so); 2120 kmem_free(pdu, pdu_size); 2121 return (-1); 2122 } 2123 2124 rc = isnst_verify_rsp(svr, pdu, rsp, rsp_size); 2125 2126 isnst_close_so(so); 2127 kmem_free(pdu, pdu_size); 2128 kmem_free(rsp, rsp_size); 2129 2130 return (rc); 2131 } 2132 2133 static size_t 2134 isnst_make_dereg_pdu(iscsit_isns_svr_t *svr, isns_pdu_t **pdu, 2135 isns_target_t *itarget) 2136 { 2137 size_t pdu_size; 2138 int len; 2139 isns_target_t *src; 2140 2141 /* 2142 * create DevDereg Message with all of target nodes 2143 */ 2144 pdu_size = isnst_create_pdu_header(ISNS_DEV_DEREG, pdu, 0); 2145 if (pdu_size == 0) { 2146 return (0); 2147 } 2148 2149 /* 2150 * Source attribute - Must be a storage node in the same 2151 * network entity. 2152 */ 2153 if (svr->svr_registered) { 2154 src = isnst_get_registered_source(svr); 2155 } else if (itarget != NULL) { 2156 src = itarget; 2157 } else { 2158 goto dereg_pdu_error; 2159 } 2160 2161 len = strlen(src->target_info->ti_tgt_name) + 1; 2162 if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2163 len, src->target_info->ti_tgt_name, 0) != 0) { 2164 goto dereg_pdu_error; 2165 } 2166 2167 2168 /* Delimiter */ 2169 if (isnst_add_attr(*pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 2170 0, 0, 0) != 0) { 2171 goto dereg_pdu_error; 2172 } 2173 2174 /* 2175 * Operating attributes 2176 */ 2177 if (itarget == NULL) { 2178 /* dereg everything */ 2179 len = strlen(isns_eid) + 1; 2180 if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID, 2181 len, isns_eid, 0) != 0) { 2182 goto dereg_pdu_error; 2183 } 2184 } else { 2185 /* dereg one target only */ 2186 len = strlen(itarget->target_info->ti_tgt_name) + 1; 2187 if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2188 len, itarget->target_info->ti_tgt_name, 0) != 0) { 2189 goto dereg_pdu_error; 2190 } 2191 } 2192 2193 return (pdu_size); 2194 2195 dereg_pdu_error: 2196 kmem_free(*pdu, pdu_size); 2197 *pdu = NULL; 2198 2199 return (0); 2200 } 2201 2202 static size_t 2203 isnst_make_keepalive_pdu(iscsit_isns_svr_t *svr, isns_pdu_t **pdu) 2204 { 2205 size_t pdu_size; 2206 int len; 2207 isns_target_t *src; 2208 2209 ASSERT(svr->svr_registered); 2210 2211 /* 2212 * create DevAttrQuery Message 2213 */ 2214 pdu_size = isnst_create_pdu_header(ISNS_DEV_ATTR_QRY, pdu, 0); 2215 if (pdu_size == 0) { 2216 return (0); 2217 } 2218 2219 /* 2220 * Source attribute - Must be a iscsi target in the same 2221 * network entity. 2222 */ 2223 src = isnst_get_registered_source(svr); 2224 2225 len = strlen(src->target_info->ti_tgt_name) + 1; 2226 if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2227 len, src->target_info->ti_tgt_name, 0) != 0) { 2228 goto keepalive_pdu_error; 2229 } 2230 2231 /* EID */ 2232 len = strlen(isns_eid) + 1; 2233 if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID, 2234 len, isns_eid, 0) != 0) { 2235 goto keepalive_pdu_error; 2236 } 2237 /* Delimiter */ 2238 if (isnst_add_attr(*pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 2239 0, 0, 0) != 0) { 2240 goto keepalive_pdu_error; 2241 } 2242 2243 /* Values to Fetch -- EID */ 2244 if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID, 2245 0, 0, 0) != 0) { 2246 goto keepalive_pdu_error; 2247 } 2248 2249 2250 return (pdu_size); 2251 2252 keepalive_pdu_error: 2253 kmem_free(*pdu, pdu_size); 2254 *pdu = NULL; 2255 2256 return (0); 2257 } 2258 2259 static isns_target_t * 2260 isnst_get_registered_source(iscsit_isns_svr_t *svr) 2261 { 2262 isns_target_t *itarget; 2263 2264 /* 2265 * If svr is registered, then there must be at least one 2266 * target that is registered to that svr. 2267 */ 2268 ASSERT(svr->svr_registered); 2269 ASSERT((avl_numnodes(&svr->svr_target_list) != 0)); 2270 2271 itarget = avl_first(&svr->svr_target_list); 2272 do { 2273 if (itarget->target_registered == B_TRUE) 2274 break; 2275 itarget = AVL_NEXT(&svr->svr_target_list, itarget); 2276 } while (itarget != NULL); 2277 ASSERT(itarget != NULL); 2278 return (itarget); 2279 } 2280 2281 static int 2282 isnst_verify_rsp(iscsit_isns_svr_t *svr, isns_pdu_t *pdu, 2283 isns_pdu_t *rsp, size_t rsp_size) 2284 { 2285 uint16_t func_id; 2286 uint16_t payload_len, rsp_payload_len; 2287 isns_resp_t *resp; 2288 uint8_t *pp; 2289 isns_tlv_t *attr; 2290 uint32_t attr_len, attr_id, esi_interval; 2291 2292 /* 2293 * Ensure we have at least a valid header (don't count the 2294 * "payload" field. 2295 */ 2296 if (rsp_size < offsetof(isns_pdu_t, payload)) { 2297 ISNST_LOG(CE_WARN, "Invalid iSNS PDU header, %d of %d bytes", 2298 (int)rsp_size, (int)offsetof(isns_pdu_t, payload)); 2299 return (-1); 2300 } 2301 2302 /* Make sure we have the amount of data that the header specifies */ 2303 payload_len = ntohs(rsp->payload_len); 2304 if (rsp_size < (payload_len + offsetof(isns_pdu_t, payload))) { 2305 ISNST_LOG(CE_WARN, "Invalid iSNS response, %d of %d bytes", 2306 (int)rsp_size, 2307 (int)(payload_len + offsetof(isns_pdu_t, payload))); 2308 return (-1); 2309 } 2310 2311 /* validate response function id */ 2312 func_id = ntohs(rsp->func_id); 2313 switch (ntohs(pdu->func_id)) { 2314 case ISNS_DEV_ATTR_REG: 2315 if (func_id != ISNS_DEV_ATTR_REG_RSP) { 2316 return (-1); 2317 } 2318 2319 /* 2320 * Get the ESI interval returned by the server. It could 2321 * be different than what we asked for. We never know which 2322 * portal a request may come in on, and any server could demand 2323 * any interval. We'll simply keep track of the largest interval 2324 * for use in monitoring. 2325 */ 2326 2327 rsp_payload_len = isnst_pdu_get_op(rsp, &pp); 2328 attr = (isns_tlv_t *)((void *)pp); 2329 2330 /* 2331 * Make sure isnst_pdu_get_op didn't encounter an error 2332 * in the attributes. 2333 */ 2334 if (pp == NULL) { 2335 return (-1); 2336 } 2337 2338 while (rsp_payload_len) { 2339 attr_len = ntohl(attr->attr_len); 2340 attr_id = ntohl(attr->attr_id); 2341 2342 if (attr_id == ISNS_ESI_INTERVAL_ATTR_ID) { 2343 esi_interval = 2344 ntohl(*((uint32_t *) 2345 ((void *)(&attr->attr_value)))); 2346 2347 if (esi_interval > svr->svr_esi_interval) 2348 svr->svr_esi_interval = esi_interval; 2349 2350 break; 2351 } 2352 2353 rsp_payload_len -= (8 + attr_len); 2354 attr = (isns_tlv_t *) 2355 ((void *)((uint8_t *)attr + attr_len + 8)); 2356 } 2357 2358 break; 2359 case ISNS_DEV_DEREG: 2360 if (func_id != ISNS_DEV_DEREG_RSP) { 2361 return (-1); 2362 } 2363 break; 2364 case ISNS_DEV_ATTR_QRY: 2365 if (func_id != ISNS_DEV_ATTR_QRY_RSP) { 2366 return (-1); 2367 } 2368 break; 2369 2370 2371 default: 2372 ASSERT(0); 2373 break; 2374 } 2375 2376 /* verify response transaction id */ 2377 if (ntohs(rsp->xid) != ntohs(pdu->xid)) { 2378 return (-1); 2379 } 2380 2381 2382 /* check the error code */ 2383 resp = (isns_resp_t *)((void *)&rsp->payload[0]); 2384 2385 /* Update the last time we heard from this server */ 2386 if (resp->status == 0) { 2387 svr->svr_last_msg = ddi_get_lbolt(); 2388 } 2389 2390 return (ntohl(resp->status)); 2391 } 2392 2393 static uint16_t 2394 isnst_pdu_get_op(isns_pdu_t *pdu, uint8_t **pp) 2395 { 2396 uint8_t *payload; 2397 uint16_t payload_len; 2398 isns_resp_t *resp; 2399 isns_tlv_t *attr; 2400 uint32_t attr_id; 2401 uint32_t tlv_len; 2402 2403 /* get payload */ 2404 payload_len = ntohs(pdu->payload_len); 2405 resp = (isns_resp_t *)((void *)&pdu->payload[0]); 2406 2407 /* find the operating attributes */ 2408 if (payload_len < sizeof (resp->status)) { 2409 ISNST_LOG(CE_WARN, "Invalid iSNS response, %d payload bytes", 2410 payload_len); 2411 *pp = NULL; 2412 return (0); 2413 } 2414 2415 payload_len -= sizeof (resp->status); 2416 payload = &resp->data[0]; 2417 2418 while (payload_len >= (sizeof (isns_tlv_t) - 1)) { 2419 attr = (isns_tlv_t *)((void *)payload); 2420 tlv_len = offsetof(isns_tlv_t, attr_value) + 2421 ntohl(attr->attr_len); 2422 if (payload_len >= tlv_len) { 2423 payload += tlv_len; 2424 payload_len -= tlv_len; 2425 attr_id = ntohl(attr->attr_id); 2426 if (attr_id == ISNS_DELIMITER_ATTR_ID) { 2427 break; 2428 } 2429 } else { 2430 /* mal-formed packet */ 2431 payload = NULL; 2432 payload_len = 0; 2433 } 2434 } 2435 2436 *pp = payload; 2437 2438 return (payload_len); 2439 } 2440 2441 static size_t 2442 isnst_create_pdu_header(uint16_t func_id, isns_pdu_t **pdu, uint16_t flags) 2443 { 2444 size_t pdu_size = isns_message_buf_size; 2445 2446 *pdu = (isns_pdu_t *)kmem_zalloc(pdu_size, KM_NOSLEEP); 2447 if (*pdu != NULL) { 2448 (*pdu)->version = htons((uint16_t)ISNSP_VERSION); 2449 (*pdu)->func_id = htons((uint16_t)func_id); 2450 (*pdu)->payload_len = htons(0); 2451 (*pdu)->flags = htons(flags); 2452 2453 (*pdu)->xid = htons(GET_XID()); 2454 (*pdu)->seq = htons(0); 2455 } else { 2456 pdu_size = 0; 2457 } 2458 2459 return (pdu_size); 2460 } 2461 2462 static int 2463 isnst_add_attr(isns_pdu_t *pdu, 2464 size_t max_pdu_size, 2465 uint32_t attr_id, 2466 uint32_t attr_len, 2467 void *attr_data, 2468 uint32_t attr_numeric_data) 2469 { 2470 isns_tlv_t *attr_tlv; 2471 uint8_t *payload_ptr; 2472 uint16_t payload_len; 2473 uint32_t normalized_attr_len; 2474 uint64_t attr_tlv_len; 2475 2476 /* The attribute length must be 4-byte aligned. Section 5.1.3. */ 2477 normalized_attr_len = (attr_len % 4) == 0 ? 2478 (attr_len) : (attr_len + (4 - (attr_len % 4))); 2479 attr_tlv_len = ISNS_TLV_ATTR_ID_LEN + 2480 ISNS_TLV_ATTR_LEN_LEN + normalized_attr_len; 2481 2482 /* Check if we are going to exceed the maximum PDU length. */ 2483 payload_len = ntohs(pdu->payload_len); 2484 if ((payload_len + attr_tlv_len) > max_pdu_size) { 2485 return (1); 2486 } 2487 2488 attr_tlv = (isns_tlv_t *)kmem_zalloc(attr_tlv_len, KM_SLEEP); 2489 2490 attr_tlv->attr_id = htonl(attr_id); 2491 2492 switch (attr_id) { 2493 case ISNS_DELIMITER_ATTR_ID: 2494 break; 2495 2496 case ISNS_PORTAL_IP_ADDR_ATTR_ID: 2497 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: 2498 if (attr_numeric_data == sizeof (in_addr_t)) { 2499 /* IPv4 */ 2500 attr_tlv->attr_value[10] = 0xFF; 2501 attr_tlv->attr_value[11] = 0xFF; 2502 bcopy(attr_data, ((attr_tlv->attr_value) + 12), 2503 sizeof (in_addr_t)); 2504 } else if (attr_numeric_data == sizeof (in6_addr_t)) { 2505 /* IPv6 */ 2506 bcopy(attr_data, attr_tlv->attr_value, 2507 sizeof (in6_addr_t)); 2508 } else if (attr_numeric_data == 0) { 2509 /* EMPTY */ 2510 /* Do nothing */ 2511 } else { 2512 kmem_free(attr_tlv, attr_tlv_len); 2513 attr_tlv = NULL; 2514 return (1); 2515 } 2516 break; 2517 2518 case ISNS_EID_ATTR_ID: 2519 case ISNS_ISCSI_NAME_ATTR_ID: 2520 case ISNS_ISCSI_ALIAS_ATTR_ID: 2521 case ISNS_PG_ISCSI_NAME_ATTR_ID: 2522 if (attr_len && attr_data) { 2523 bcopy((char *)attr_data, 2524 attr_tlv->attr_value, attr_len); 2525 } 2526 break; 2527 2528 default: 2529 if (attr_len == 8) { 2530 *(uint64_t *)((void *)attr_tlv->attr_value) = 2531 BE_64((uint64_t)attr_numeric_data); 2532 } else if (attr_len == 4) { 2533 *(uint32_t *)((void *)attr_tlv->attr_value) = 2534 htonl((uint32_t)attr_numeric_data); 2535 } 2536 break; 2537 } 2538 2539 attr_tlv->attr_len = htonl(normalized_attr_len); 2540 /* 2541 * Convert the network byte ordered payload length to host byte 2542 * ordered for local address calculation. 2543 */ 2544 payload_len = ntohs(pdu->payload_len); 2545 payload_ptr = pdu->payload + payload_len; 2546 bcopy(attr_tlv, payload_ptr, attr_tlv_len); 2547 payload_len += attr_tlv_len; 2548 2549 /* 2550 * Convert the host byte ordered payload length back to network 2551 * byte ordered - it's now ready to be sent on the wire. 2552 */ 2553 pdu->payload_len = htons(payload_len); 2554 2555 kmem_free(attr_tlv, attr_tlv_len); 2556 attr_tlv = NULL; 2557 2558 return (0); 2559 } 2560 2561 static void 2562 isnst_so_timeout(void *so) 2563 { 2564 /* Wake up any sosend or sorecv blocked on this socket */ 2565 idm_soshutdown(so); 2566 } 2567 2568 static int 2569 isnst_send_pdu(void *so, isns_pdu_t *pdu) 2570 { 2571 size_t total_len, payload_len, send_len; 2572 uint8_t *payload; 2573 uint16_t flags, seq; 2574 timeout_id_t send_timer; 2575 iovec_t iov[2]; 2576 int rc; 2577 2578 /* update pdu flags */ 2579 flags = ntohs(pdu->flags); 2580 flags |= ISNS_FLAG_CLIENT; 2581 flags |= ISNS_FLAG_FIRST_PDU; 2582 2583 /* initalize sequence number */ 2584 seq = 0; 2585 2586 payload = pdu->payload; 2587 2588 /* total payload length */ 2589 total_len = ntohs(pdu->payload_len); 2590 2591 /* fill in the pdu header */ 2592 iov[0].iov_base = (void *)pdu; 2593 iov[0].iov_len = ISNSP_HEADER_SIZE; 2594 2595 do { 2596 /* split the payload accordingly */ 2597 if (total_len > ISNSP_MAX_PAYLOAD_SIZE) { 2598 payload_len = ISNSP_MAX_PAYLOAD_SIZE; 2599 } else { 2600 payload_len = total_len; 2601 /* set the last pdu flag */ 2602 flags |= ISNS_FLAG_LAST_PDU; 2603 } 2604 2605 /* set back the pdu flags */ 2606 pdu->flags = htons(flags); 2607 /* set the sequence number */ 2608 pdu->seq = htons(seq); 2609 /* set the payload length */ 2610 pdu->payload_len = htons(payload_len); 2611 2612 /* fill in the payload */ 2613 iov[1].iov_base = (void *)payload; 2614 iov[1].iov_len = payload_len; 2615 2616 DTRACE_PROBE3(isnst__pdu__send, uint16_t, ntohs(pdu->func_id), 2617 uint16_t, ntohs(pdu->payload_len), caddr_t, pdu); 2618 2619 /* send the pdu */ 2620 send_len = ISNSP_HEADER_SIZE + payload_len; 2621 send_timer = timeout(isnst_so_timeout, so, 2622 drv_usectohz(isns_timeout_usec)); 2623 rc = idm_iov_sosend(so, &iov[0], 2, send_len); 2624 (void) untimeout(send_timer); 2625 2626 flags &= ~ISNS_FLAG_FIRST_PDU; 2627 payload += payload_len; 2628 total_len -= payload_len; 2629 2630 /* increase the sequence number */ 2631 seq ++; 2632 2633 } while (rc == 0 && total_len > 0); 2634 2635 return (rc); 2636 } 2637 2638 static size_t 2639 isnst_rcv_pdu(void *so, isns_pdu_t **pdu) 2640 { 2641 size_t total_pdu_len; 2642 size_t total_payload_len; 2643 size_t payload_len; 2644 size_t combined_len; 2645 isns_pdu_t tmp_pdu_hdr; 2646 isns_pdu_t *combined_pdu; 2647 uint8_t *payload; 2648 uint8_t *combined_payload; 2649 timeout_id_t rcv_timer; 2650 uint16_t flags; 2651 uint16_t seq; 2652 2653 *pdu = NULL; 2654 total_pdu_len = total_payload_len = 0; 2655 payload = NULL; 2656 seq = 0; 2657 2658 do { 2659 /* receive the pdu header */ 2660 rcv_timer = timeout(isnst_so_timeout, so, 2661 drv_usectohz(isns_timeout_usec)); 2662 if (idm_sorecv(so, &tmp_pdu_hdr, ISNSP_HEADER_SIZE) != 0 || 2663 ntohs(tmp_pdu_hdr.seq) != seq) { 2664 (void) untimeout(rcv_timer); 2665 goto rcv_error; 2666 } 2667 (void) untimeout(rcv_timer); 2668 2669 /* receive the payload */ 2670 payload_len = ntohs(tmp_pdu_hdr.payload_len); 2671 if (payload_len > ISNST_MAX_MSG_SIZE) { 2672 goto rcv_error; 2673 } 2674 payload = kmem_alloc(payload_len, KM_NOSLEEP); 2675 if (payload == NULL) { 2676 goto rcv_error; 2677 } 2678 rcv_timer = timeout(isnst_so_timeout, so, 2679 drv_usectohz(ISNS_RCV_TIMER_SECONDS * 1000000)); 2680 if (idm_sorecv(so, payload, payload_len) != 0) { 2681 (void) untimeout(rcv_timer); 2682 goto rcv_error; 2683 } 2684 (void) untimeout(rcv_timer); 2685 2686 /* combine the pdu if it is not the first one */ 2687 if (total_pdu_len > 0) { 2688 combined_len = total_pdu_len + payload_len; 2689 combined_pdu = kmem_alloc(combined_len, KM_SLEEP); 2690 if (combined_pdu == NULL) { 2691 goto rcv_error; 2692 } 2693 bcopy(*pdu, combined_pdu, total_pdu_len); 2694 combined_payload = 2695 &combined_pdu->payload[total_payload_len]; 2696 bcopy(payload, combined_payload, payload_len); 2697 kmem_free(*pdu, total_pdu_len); 2698 kmem_free(payload, payload_len); 2699 *pdu = combined_pdu; 2700 total_payload_len += payload_len; 2701 total_pdu_len += payload_len; 2702 (*pdu)->payload_len = htons(total_payload_len); 2703 } else { 2704 total_payload_len = payload_len; 2705 total_pdu_len = ISNSP_HEADER_SIZE + payload_len; 2706 *pdu = kmem_alloc(total_pdu_len, KM_NOSLEEP); 2707 if (*pdu == NULL) { 2708 goto rcv_error; 2709 } 2710 bcopy(&tmp_pdu_hdr, *pdu, ISNSP_HEADER_SIZE); 2711 bcopy(payload, &(*pdu)->payload[0], payload_len); 2712 kmem_free(payload, payload_len); 2713 } 2714 payload = NULL; 2715 2716 /* the flags of pdu which is just received */ 2717 flags = ntohs(tmp_pdu_hdr.flags); 2718 2719 /* increase sequence number by one */ 2720 seq ++; 2721 } while ((flags & ISNS_FLAG_LAST_PDU) == 0); 2722 2723 DTRACE_PROBE3(isnst__pdu__recv, uint16_t, ntohs((*pdu)->func_id), 2724 size_t, total_payload_len, caddr_t, *pdu); 2725 2726 return (total_pdu_len); 2727 2728 rcv_error: 2729 if (*pdu != NULL) { 2730 kmem_free(*pdu, total_pdu_len); 2731 *pdu = NULL; 2732 } 2733 if (payload != NULL) { 2734 kmem_free(payload, payload_len); 2735 } 2736 return (0); 2737 } 2738 2739 static void * 2740 isnst_open_so(struct sockaddr_storage *sa) 2741 { 2742 int sa_sz; 2743 ksocket_t so; 2744 2745 /* determin local IP address */ 2746 if (sa->ss_family == AF_INET) { 2747 /* IPv4 */ 2748 sa_sz = sizeof (struct sockaddr_in); 2749 2750 /* Create socket */ 2751 so = idm_socreate(AF_INET, SOCK_STREAM, 0); 2752 } else { 2753 /* IPv6 */ 2754 sa_sz = sizeof (struct sockaddr_in6); 2755 2756 /* Create socket */ 2757 so = idm_socreate(AF_INET6, SOCK_STREAM, 0); 2758 } 2759 2760 if (so != NULL) { 2761 if (idm_so_timed_socket_connect(so, sa, sa_sz, 2762 isns_timeout_usec) != 0) { 2763 /* not calling isnst_close_so() to */ 2764 /* make dtrace output look clear */ 2765 idm_soshutdown(so); 2766 idm_sodestroy(so); 2767 so = NULL; 2768 } 2769 } 2770 2771 if (so == NULL) { 2772 char server_buf[IDM_SA_NTOP_BUFSIZ]; 2773 ISNST_LOG(CE_WARN, "open iSNS Server %s failed", 2774 idm_sa_ntop(sa, server_buf, 2775 sizeof (server_buf))); 2776 DTRACE_PROBE1(isnst__connect__fail, 2777 struct sockaddr_storage *, sa); 2778 } 2779 2780 return (so); 2781 } 2782 2783 static void 2784 isnst_close_so(void *so) 2785 { 2786 idm_soshutdown(so); 2787 idm_sodestroy(so); 2788 } 2789 2790 /* 2791 * ESI handling 2792 */ 2793 2794 static void 2795 isnst_esi_start(void) 2796 { 2797 if (isns_use_esi == B_FALSE) { 2798 ISNST_LOG(CE_NOTE, "ESI disabled by isns_use_esi=FALSE"); 2799 return; 2800 } 2801 2802 ISNST_LOG(CE_NOTE, "isnst_esi_start"); 2803 2804 mutex_enter(&esi.esi_mutex); 2805 ASSERT(esi.esi_enabled == B_FALSE); 2806 ASSERT(esi.esi_thread_running == B_FALSE); 2807 2808 esi.esi_enabled = B_TRUE; 2809 esi.esi_valid = B_FALSE; 2810 esi.esi_thread = thread_create(NULL, 0, isnst_esi_thread, 2811 (void *)&esi, 0, &p0, TS_RUN, minclsyspri); 2812 2813 /* 2814 * Wait for the thread to start 2815 */ 2816 while (!esi.esi_thread_running) { 2817 cv_wait(&esi.esi_cv, &esi.esi_mutex); 2818 } 2819 mutex_exit(&esi.esi_mutex); 2820 } 2821 2822 static void 2823 isnst_esi_stop() 2824 { 2825 ISNST_LOG(CE_NOTE, "isnst_esi_stop"); 2826 2827 /* Shutdown ESI listening socket, wait for thread to terminate */ 2828 mutex_enter(&esi.esi_mutex); 2829 if (esi.esi_enabled) { 2830 esi.esi_enabled = B_FALSE; 2831 if (esi.esi_valid) { 2832 idm_soshutdown(esi.esi_so); 2833 idm_sodestroy(esi.esi_so); 2834 } 2835 mutex_exit(&esi.esi_mutex); 2836 thread_join(esi.esi_thread_did); 2837 } else { 2838 mutex_exit(&esi.esi_mutex); 2839 } 2840 } 2841 2842 /* 2843 * isnst_esi_thread 2844 * 2845 * This function listens on a socket for incoming connections from an 2846 * iSNS server until told to stop. 2847 */ 2848 2849 /*ARGSUSED*/ 2850 static void 2851 isnst_esi_thread(void *arg) 2852 { 2853 ksocket_t newso; 2854 struct sockaddr_in6 sin6; 2855 socklen_t sin_addrlen; 2856 uint32_t on = 1; 2857 int rc; 2858 isns_pdu_t *pdu; 2859 size_t pl_size; 2860 2861 bzero(&sin6, sizeof (struct sockaddr_in6)); 2862 sin_addrlen = sizeof (struct sockaddr_in6); 2863 2864 esi.esi_thread_did = curthread->t_did; 2865 2866 mutex_enter(&esi.esi_mutex); 2867 2868 /* 2869 * Mark the thread as running and the portal as no longer new. 2870 */ 2871 esi.esi_thread_running = B_TRUE; 2872 cv_signal(&esi.esi_cv); 2873 2874 while (esi.esi_enabled) { 2875 /* 2876 * Create a socket to listen for requests from the iSNS server. 2877 */ 2878 if ((esi.esi_so = idm_socreate(PF_INET6, SOCK_STREAM, 0)) == 2879 NULL) { 2880 ISNST_LOG(CE_WARN, 2881 "isnst_esi_thread: Unable to create socket"); 2882 mutex_exit(&esi.esi_mutex); 2883 delay(drv_usectohz(1000000)); 2884 mutex_enter(&esi.esi_mutex); 2885 continue; 2886 } 2887 2888 /* 2889 * Set options, bind, and listen until we're told to stop 2890 */ 2891 bzero(&sin6, sizeof (sin6)); 2892 sin6.sin6_family = AF_INET6; 2893 sin6.sin6_port = htons(0); 2894 sin6.sin6_addr = in6addr_any; 2895 2896 (void) ksocket_setsockopt(esi.esi_so, SOL_SOCKET, 2897 SO_REUSEADDR, (char *)&on, sizeof (on), CRED()); 2898 2899 if (ksocket_bind(esi.esi_so, (struct sockaddr *)&sin6, 2900 sizeof (sin6), CRED()) != 0) { 2901 ISNST_LOG(CE_WARN, "Unable to bind socket for ESI"); 2902 idm_sodestroy(esi.esi_so); 2903 mutex_exit(&esi.esi_mutex); 2904 delay(drv_usectohz(1000000)); 2905 mutex_enter(&esi.esi_mutex); 2906 continue; 2907 } 2908 2909 /* 2910 * Get the port (sin6 is meaningless at this point) 2911 */ 2912 (void) ksocket_getsockname(esi.esi_so, 2913 (struct sockaddr *)(&sin6), &sin_addrlen, CRED()); 2914 esi.esi_port = 2915 ntohs(((struct sockaddr_in6 *)(&sin6))->sin6_port); 2916 2917 if ((rc = ksocket_listen(esi.esi_so, 5, CRED())) != 0) { 2918 ISNST_LOG(CE_WARN, "isnst_esi_thread: listen " 2919 "failure 0x%x", rc); 2920 idm_sodestroy(esi.esi_so); 2921 mutex_exit(&esi.esi_mutex); 2922 delay(drv_usectohz(1000000)); 2923 mutex_enter(&esi.esi_mutex); 2924 continue; 2925 } 2926 2927 ksocket_hold(esi.esi_so); 2928 esi.esi_valid = B_TRUE; 2929 while (esi.esi_enabled) { 2930 mutex_exit(&esi.esi_mutex); 2931 2932 DTRACE_PROBE3(iscsit__isns__esi__accept__wait, 2933 boolean_t, esi.esi_enabled, 2934 ksocket_t, esi.esi_so, 2935 struct sockaddr_in6, &sin6); 2936 if ((rc = ksocket_accept(esi.esi_so, NULL, NULL, 2937 &newso, CRED())) != 0) { 2938 mutex_enter(&esi.esi_mutex); 2939 DTRACE_PROBE2(iscsit__isns__esi__accept__fail, 2940 int, rc, boolean_t, esi.esi_enabled); 2941 /* 2942 * If we were interrupted with EINTR 2943 * it's not really a failure. 2944 */ 2945 ISNST_LOG(CE_WARN, "isnst_esi_thread: " 2946 "accept failure (0x%x)", rc); 2947 2948 delay(drv_usectohz(100000)); 2949 if (rc == EINTR) { 2950 continue; 2951 } else { 2952 break; 2953 } 2954 } 2955 DTRACE_PROBE2(iscsit__isns__esi__accept, 2956 boolean_t, esi.esi_enabled, 2957 ksocket_t, newso); 2958 2959 pl_size = isnst_rcv_pdu(newso, &pdu); 2960 if (pl_size == 0) { 2961 ISNST_LOG(CE_WARN, "isnst_esi_thread: " 2962 "rcv_pdu failure"); 2963 (void) ksocket_close(newso, CRED()); 2964 2965 mutex_enter(&esi.esi_mutex); 2966 continue; 2967 } 2968 2969 isnst_handle_esi_req(newso, pdu, pl_size); 2970 2971 (void) ksocket_close(newso, CRED()); 2972 2973 mutex_enter(&esi.esi_mutex); 2974 } 2975 2976 idm_soshutdown(esi.esi_so); 2977 ksocket_rele(esi.esi_so); 2978 esi.esi_valid = B_FALSE; 2979 2980 /* 2981 * If we're going to try to re-establish the listener then 2982 * destroy this socket. Otherwise isnst_esi_stop already 2983 * destroyed it. 2984 */ 2985 if (esi.esi_enabled) 2986 idm_sodestroy(esi.esi_so); 2987 } 2988 2989 esi.esi_thread_running = B_FALSE; 2990 cv_signal(&esi.esi_cv); 2991 mutex_exit(&esi.esi_mutex); 2992 esi_thread_exit: 2993 thread_exit(); 2994 } 2995 2996 /* 2997 * Handle an incoming ESI request 2998 */ 2999 3000 static void 3001 isnst_handle_esi_req(ksocket_t ks, isns_pdu_t *pdu, size_t pdu_size) 3002 { 3003 isns_pdu_t *rsp_pdu; 3004 isns_resp_t *rsp; 3005 isns_tlv_t *attr; 3006 uint32_t attr_len, attr_id; 3007 size_t req_pl_len, rsp_size, tlv_len; 3008 struct sockaddr_storage portal_ss; 3009 struct sockaddr_storage server_ss; 3010 struct sockaddr_in6 *portal_addr6; 3011 boolean_t portal_addr_valid = B_FALSE; 3012 boolean_t portal_port_valid = B_FALSE; 3013 uint32_t esi_response = ISNS_RSP_SUCCESSFUL; 3014 isns_portal_t *iportal; 3015 socklen_t sa_len; 3016 3017 3018 if (ntohs(pdu->func_id) != ISNS_ESI) { 3019 ISNST_LOG(CE_WARN, "isnst_handle_esi_req: Unexpected func 0x%x", 3020 pdu->func_id); 3021 kmem_free(pdu, pdu_size); 3022 return; 3023 } 3024 3025 req_pl_len = ntohs(pdu->payload_len); 3026 if (req_pl_len + offsetof(isns_pdu_t, payload) > pdu_size) { 3027 ISNST_LOG(CE_WARN, "isnst_handle_esi_req: " 3028 "payload exceeds PDU size (%d > %d)", 3029 (int)(req_pl_len + offsetof(isns_pdu_t, payload)), 3030 (int)pdu_size); 3031 /* Not all data is present -- ignore */ 3032 kmem_free(pdu, pdu_size); 3033 return; 3034 } 3035 3036 if (req_pl_len + sizeof (uint32_t) > ISNSP_MAX_PAYLOAD_SIZE) { 3037 ISNST_LOG(CE_WARN, 3038 "isnst_handle_esi_req: PDU payload exceeds max (%ld bytes)", 3039 req_pl_len + sizeof (uint32_t)); 3040 kmem_free(pdu, pdu_size); 3041 return; 3042 } 3043 3044 /* 3045 * Check portal in ESI request and make sure it is valid. Return 3046 * esi_response of ISNS_RSP_SUCCESSFUL if valid, otherwise don't 3047 * respond at all. Get IP addr and port. Format of ESI 3048 * is: 3049 * 3050 * ISNS_TIMESTAMP_ATTR_ID, 3051 * ISNS_EID_ATTR_ID, 3052 * ISNS_PORTAL_IP_ADDR_ATTR_ID, 3053 * ISNS_PORTAL_PORT_ATTR_ID 3054 */ 3055 bzero(&portal_ss, sizeof (struct sockaddr_storage)); 3056 portal_ss.ss_family = AF_INET6; 3057 portal_addr6 = (struct sockaddr_in6 *)&portal_ss; 3058 attr = (isns_tlv_t *)((void *)&pdu->payload); 3059 attr_len = ntohl(attr->attr_len); 3060 attr_id = ntohl(attr->attr_id); 3061 tlv_len = attr_len + offsetof(isns_tlv_t, attr_value); 3062 while (tlv_len <= req_pl_len) { 3063 switch (attr_id) { 3064 case ISNS_TIMESTAMP_ATTR_ID: 3065 break; 3066 case ISNS_EID_ATTR_ID: 3067 break; 3068 case ISNS_PORTAL_IP_ADDR_ATTR_ID: 3069 if (attr_len > sizeof (struct in6_addr)) { 3070 /* Bad attribute format */ 3071 esi_response = ISNS_RSP_MSG_FORMAT_ERROR; 3072 } else { 3073 portal_addr6->sin6_family = AF_INET6; 3074 attr_len = min(attr_len, 3075 sizeof (portal_addr6->sin6_addr)); 3076 bcopy(attr->attr_value, 3077 portal_addr6->sin6_addr.s6_addr, attr_len); 3078 portal_addr_valid = B_TRUE; 3079 } 3080 break; 3081 case ISNS_PORTAL_PORT_ATTR_ID: 3082 if (attr_len > sizeof (uint32_t)) { 3083 /* Bad attribute format */ 3084 esi_response = ISNS_RSP_MSG_FORMAT_ERROR; 3085 } else { 3086 portal_addr6->sin6_port = 3087 htons((uint16_t)BE_IN32(attr->attr_value)); 3088 portal_port_valid = B_TRUE; 3089 } 3090 break; 3091 default: 3092 /* Bad request format */ 3093 esi_response = ISNS_RSP_MSG_FORMAT_ERROR; 3094 break; 3095 } 3096 3097 /* If we've set an error then stop processing */ 3098 if (esi_response != ISNS_RSP_SUCCESSFUL) { 3099 break; 3100 } 3101 3102 /* Get next attribute */ 3103 req_pl_len -= tlv_len; 3104 attr = (isns_tlv_t *)((void *)((uint8_t *)attr + tlv_len)); 3105 attr_len = ntohl(attr->attr_len); 3106 attr_id = ntohl(attr->attr_id); 3107 tlv_len = attr_len + offsetof(isns_tlv_t, attr_value); 3108 } 3109 3110 if (!portal_port_valid) 3111 portal_addr6->sin6_port = htons(ISCSI_LISTEN_PORT); 3112 3113 if (!portal_addr_valid) { 3114 esi_response = ISNS_RSP_MSG_FORMAT_ERROR; 3115 } 3116 3117 /* 3118 * If we've detected an error or if the portal does not 3119 * exist then drop the request. The server will eventually 3120 * timeout the portal and eliminate it from the list. 3121 */ 3122 3123 if (esi_response != ISNS_RSP_SUCCESSFUL) { 3124 kmem_free(pdu, pdu_size); 3125 return; 3126 } 3127 3128 /* Get the remote peer's IP address */ 3129 bzero(&server_ss, sizeof (server_ss)); 3130 sa_len = sizeof (server_ss); 3131 if (ksocket_getpeername(ks, (struct sockaddr *)&server_ss, &sa_len, 3132 CRED())) { 3133 return; 3134 } 3135 3136 if (iscsit_isns_logging) { 3137 char server_buf[IDM_SA_NTOP_BUFSIZ]; 3138 char portal_buf[IDM_SA_NTOP_BUFSIZ]; 3139 ISNST_LOG(CE_NOTE, "ESI: svr %s -> portal %s", 3140 idm_sa_ntop(&server_ss, server_buf, 3141 sizeof (server_buf)), 3142 idm_sa_ntop(&portal_ss, portal_buf, 3143 sizeof (portal_buf))); 3144 } 3145 3146 3147 ISNS_GLOBAL_LOCK(); 3148 if (isnst_lookup_portal(&portal_ss) == NULL) { 3149 ISNST_LOG(CE_WARN, "ESI req to non-active portal"); 3150 ISNS_GLOBAL_UNLOCK(); 3151 kmem_free(pdu, pdu_size); 3152 return; 3153 } 3154 3155 /* 3156 * Update the server timestamp of how recently we have 3157 * received an ESI request from this iSNS server. 3158 * We ignore requests from servers we don't know. 3159 */ 3160 if (! isnst_update_server_timestamp(&server_ss)) { 3161 ISNST_LOG(CE_WARN, "ESI req from unknown server"); 3162 kmem_free(pdu, pdu_size); 3163 ISNS_GLOBAL_UNLOCK(); 3164 return; 3165 } 3166 3167 /* 3168 * Update ESI timestamps for all portals with same IP address. 3169 */ 3170 for (iportal = avl_first(&isns_all_portals); 3171 iportal != NULL; 3172 iportal = AVL_NEXT(&isns_all_portals, iportal)) { 3173 if (idm_ss_compare(&iportal->portal_addr, &portal_ss, 3174 B_TRUE, B_FALSE)) { 3175 gethrestime(&iportal->portal_esi_timestamp); 3176 } 3177 } 3178 3179 ISNS_GLOBAL_UNLOCK(); 3180 3181 3182 /* 3183 * Build response validating the portal 3184 */ 3185 rsp_size = isnst_create_pdu_header(ISNS_ESI_RSP, &rsp_pdu, 0); 3186 3187 if (rsp_size == 0) { 3188 ISNST_LOG(CE_WARN, "isnst_handle_esi_req: Can't get rsp pdu"); 3189 kmem_free(pdu, pdu_size); 3190 return; 3191 } 3192 3193 rsp = (isns_resp_t *)((void *)(&rsp_pdu->payload[0])); 3194 3195 /* Use xid from the request pdu */ 3196 rsp_pdu->xid = pdu->xid; 3197 rsp->status = htonl(ISNS_RSP_SUCCESSFUL); 3198 3199 /* Copy original data */ 3200 req_pl_len = ntohs(pdu->payload_len); 3201 bcopy(pdu->payload, rsp->data, req_pl_len); 3202 rsp_pdu->payload_len = htons(req_pl_len + sizeof (uint32_t)); 3203 3204 if (isnst_send_pdu(ks, rsp_pdu) != 0) { 3205 ISNST_LOG(CE_WARN, 3206 "isnst_handle_esi_req: Send response failed"); 3207 } 3208 3209 kmem_free(rsp_pdu, rsp_size); 3210 kmem_free(pdu, pdu_size); 3211 3212 } 3213 3214 static int 3215 isnst_tgt_avl_compare(const void *t1, const void *t2) 3216 { 3217 const isns_target_t *tgt1 = t1; 3218 const isns_target_t *tgt2 = t2; 3219 3220 /* 3221 * Sort by target (pointer to iscsit_tgt_t). 3222 */ 3223 3224 if (tgt1->target < tgt2->target) { 3225 return (-1); 3226 } else if (tgt1->target > tgt2->target) { 3227 return (1); 3228 } 3229 3230 return (0); 3231 } 3232 3233 static void 3234 isnst_set_server_status(iscsit_isns_svr_t *svr, boolean_t registered) 3235 { 3236 isns_target_t *itarget; 3237 3238 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 3239 3240 svr->svr_reset_needed = B_FALSE; 3241 if (registered == B_TRUE) { 3242 svr->svr_registered = B_TRUE; 3243 svr->svr_last_msg = ddi_get_lbolt(); 3244 itarget = avl_first(&svr->svr_target_list); 3245 while (itarget) { 3246 isns_target_t *next_target; 3247 next_target = AVL_NEXT(&svr->svr_target_list, itarget); 3248 if (itarget->target_delete_needed) { 3249 /* All deleted tgts removed */ 3250 isnst_clear_from_target_list(itarget, 3251 &svr->svr_target_list); 3252 } else { 3253 /* Other tgts marked registered */ 3254 itarget->target_registered = B_TRUE; 3255 } 3256 itarget = next_target; 3257 } 3258 ASSERT(avl_numnodes(&svr->svr_target_list) > 0); 3259 } else { 3260 svr->svr_registered = B_FALSE; 3261 isnst_clear_target_list(svr); 3262 } 3263 } 3264 3265 static void 3266 isnst_monitor_default_portal_list(void) 3267 { 3268 idm_addr_list_t *new_portal_list = NULL; 3269 uint32_t new_portal_list_size = 0; 3270 3271 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 3272 ASSERT(mutex_owned(&iscsit_isns_mutex)); 3273 3274 if (default_portal_online) { 3275 new_portal_list_size = idm_get_ipaddr(&new_portal_list); 3276 } 3277 3278 /* 3279 * We compute a new list of portals if 3280 * a) Something in itadm has changed a portal 3281 * b) there are new default portals 3282 * c) the default portal has gone offline 3283 */ 3284 if (isns_portals_changed || 3285 (default_portal_online && 3286 (isnst_find_default_portals(new_portal_list) != 3287 num_default_portals)) || 3288 (! default_portal_online && num_default_portals > 0)) { 3289 3290 isnst_clear_default_portals(); 3291 isnst_copy_portal_list(&isns_tpg_portals, 3292 &isns_all_portals); 3293 num_tpg_portals = avl_numnodes(&isns_all_portals); 3294 if (default_portal_online) { 3295 num_default_portals = 3296 isnst_add_default_portals(new_portal_list); 3297 } 3298 } 3299 3300 /* Catch any case where we miss an update to TPG portals */ 3301 ASSERT(num_tpg_portals == avl_numnodes(&isns_tpg_portals)); 3302 3303 if (new_portal_list != NULL) { 3304 kmem_free(new_portal_list, new_portal_list_size); 3305 } 3306 } 3307 3308 3309 static int 3310 isnst_find_default_portals(idm_addr_list_t *alist) 3311 { 3312 idm_addr_t *dportal; 3313 isns_portal_t *iportal; 3314 struct sockaddr_storage sa; 3315 int aidx; 3316 int num_portals_found = 0; 3317 3318 for (aidx = 0; aidx < alist->al_out_cnt; aidx++) { 3319 dportal = &alist->al_addrs[aidx]; 3320 dportal->a_port = ISCSI_LISTEN_PORT; 3321 idm_addr_to_sa(dportal, &sa); 3322 iportal = isnst_lookup_portal(&sa); 3323 if (iportal == NULL) { 3324 /* Found a non-matching default portal */ 3325 return (-1); 3326 } 3327 if (iportal->portal_default) { 3328 num_portals_found++; 3329 } 3330 } 3331 return (num_portals_found); 3332 } 3333 3334 static void 3335 isnst_clear_default_portals(void) 3336 { 3337 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 3338 3339 isnst_clear_portal_list(&isns_all_portals); 3340 num_tpg_portals = 0; 3341 num_default_portals = 0; 3342 } 3343 3344 static int 3345 isnst_add_default_portals(idm_addr_list_t *alist) 3346 { 3347 idm_addr_t *dportal; 3348 isns_portal_t *iportal; 3349 struct sockaddr_storage sa; 3350 int aidx; 3351 3352 for (aidx = 0; aidx < alist->al_out_cnt; aidx++) { 3353 dportal = &alist->al_addrs[aidx]; 3354 dportal->a_port = ISCSI_LISTEN_PORT; 3355 idm_addr_to_sa(dportal, &sa); 3356 iportal = isnst_add_to_portal_list(&sa, &isns_all_portals); 3357 iportal->portal_default = B_TRUE; 3358 } 3359 return (alist->al_out_cnt); 3360 } 3361 3362 3363 static int 3364 isnst_portal_avl_compare(const void *p1, const void *p2) 3365 { 3366 const isns_portal_t *portal1 = p1; 3367 const isns_portal_t *portal2 = p2; 3368 3369 return (idm_ss_compare(&portal1->portal_addr, &portal2->portal_addr, 3370 B_TRUE /* v4_mapped_as_v4 */, B_TRUE /* compare_ports */)); 3371 } 3372 3373 static void 3374 isnst_clear_portal_list(avl_tree_t *portal_list) 3375 { 3376 isns_portal_t *iportal; 3377 void *cookie = NULL; 3378 3379 while ((iportal = avl_destroy_nodes(portal_list, &cookie)) != NULL) { 3380 kmem_free(iportal, sizeof (isns_portal_t)); 3381 } 3382 } 3383 static void 3384 isnst_copy_portal_list(avl_tree_t *t1, avl_tree_t *t2) 3385 { 3386 isns_portal_t *iportal, *jportal; 3387 3388 iportal = (isns_portal_t *)avl_first(t1); 3389 while (iportal) { 3390 jportal = isnst_add_to_portal_list(&iportal->portal_addr, t2); 3391 jportal->portal_iscsit = iportal->portal_iscsit; 3392 iportal = AVL_NEXT(t1, iportal); 3393 } 3394 } 3395 3396 3397 static isns_portal_t * 3398 isnst_lookup_portal(struct sockaddr_storage *sa) 3399 { 3400 isns_portal_t *iportal, tmp_portal; 3401 ASSERT(ISNS_GLOBAL_LOCK_HELD()); 3402 3403 bcopy(sa, &tmp_portal.portal_addr, sizeof (*sa)); 3404 iportal = avl_find(&isns_all_portals, &tmp_portal, NULL); 3405 return (iportal); 3406 } 3407 3408 static isns_portal_t * 3409 isnst_add_to_portal_list(struct sockaddr_storage *sa, avl_tree_t *portal_list) 3410 { 3411 isns_portal_t *iportal, tmp_portal; 3412 avl_index_t where; 3413 /* 3414 * Make sure this portal isn't already in our list. 3415 */ 3416 3417 bcopy(sa, &tmp_portal.portal_addr, sizeof (*sa)); 3418 3419 if ((iportal = (isns_portal_t *)avl_find(portal_list, 3420 &tmp_portal, &where)) == NULL) { 3421 iportal = kmem_zalloc(sizeof (isns_portal_t), KM_SLEEP); 3422 bcopy(sa, &iportal->portal_addr, sizeof (*sa)); 3423 avl_insert(portal_list, (void *)iportal, where); 3424 } 3425 3426 return (iportal); 3427 } 3428 3429 3430 static void 3431 isnst_remove_from_portal_list(struct sockaddr_storage *sa, 3432 avl_tree_t *portal_list) 3433 { 3434 isns_portal_t *iportal, tmp_portal; 3435 3436 bcopy(sa, &tmp_portal.portal_addr, sizeof (*sa)); 3437 3438 if ((iportal = avl_find(portal_list, &tmp_portal, NULL)) 3439 != NULL) { 3440 avl_remove(portal_list, iportal); 3441 kmem_free(iportal, sizeof (isns_portal_t)); 3442 } 3443 } 3444 3445 /* 3446 * These functions are called by iscsit proper when a portal comes online 3447 * or goes offline. 3448 */ 3449 3450 void 3451 iscsit_isns_portal_online(iscsit_portal_t *portal) 3452 { 3453 isns_portal_t *iportal; 3454 3455 mutex_enter(&iscsit_isns_mutex); 3456 3457 if (portal->portal_default) { 3458 /* Portals should only be onlined once */ 3459 ASSERT(default_portal_online == B_FALSE); 3460 default_portal_online = B_TRUE; 3461 } else { 3462 iportal = isnst_add_to_portal_list( 3463 &portal->portal_addr, &isns_tpg_portals); 3464 iportal->portal_iscsit = portal; 3465 } 3466 isns_portals_changed = B_TRUE; 3467 3468 mutex_exit(&iscsit_isns_mutex); 3469 3470 isnst_monitor_awaken(); 3471 } 3472 3473 void 3474 iscsit_isns_portal_offline(iscsit_portal_t *portal) 3475 { 3476 mutex_enter(&iscsit_isns_mutex); 3477 3478 if (portal->portal_default) { 3479 /* Portals should only be offlined once */ 3480 ASSERT(default_portal_online == B_TRUE); 3481 default_portal_online = B_FALSE; 3482 } else { 3483 isnst_remove_from_portal_list(&portal->portal_addr, 3484 &isns_tpg_portals); 3485 } 3486 isns_portals_changed = B_TRUE; 3487 3488 mutex_exit(&iscsit_isns_mutex); 3489 3490 isnst_monitor_awaken(); 3491 } 3492