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