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