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