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