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