xref: /illumos-gate/usr/src/uts/common/io/comstar/port/iscsit/iscsit_isns.c (revision 1b8adde7ba7d5e04395c141c5400dc2cffd7d809)
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 2008 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 
46 /* local defines */
47 #define	MAX_XID			(2^16)
48 #define	ISNS_IDLE_TIME		60
49 #define	MAX_RETRY		(3)
50 
51 #define	VALID_NAME(NAME, LEN)	\
52 ((LEN) > 0 && (NAME)[0] != 0 && (NAME)[(LEN) - 1] == 0)
53 
54 static kmutex_t		isns_mutex;
55 static kthread_t	*isns_monitor_thr_id;
56 
57 static kcondvar_t	isns_idle_cv;
58 static boolean_t	isns_idle;
59 
60 static uint16_t		xid;
61 #define	GET_XID()	atomic_inc_16_nv(&xid)
62 
63 static clock_t		monitor_idle_interval;
64 
65 #define	ISNS_GLOBAL_LOCK() \
66 	mutex_enter(&iscsit_global.global_isns_cfg.isns_mutex)
67 
68 #define	ISNS_GLOBAL_LOCK_HELD() \
69 	MUTEX_HELD(&iscsit_global.global_isns_cfg.isns_mutex)
70 
71 #define	ISNS_GLOBAL_UNLOCK() \
72 	mutex_exit(&iscsit_global.global_isns_cfg.isns_mutex)
73 
74 /*
75  * iSNS ESI thread state
76  */
77 
78 static kmutex_t		isns_esi_mutex;
79 static kcondvar_t	isns_esi_cv;
80 static list_t		esi_list;
81 static uint32_t		isns_esi_max_interval = 0;
82 
83 /*
84  * List of portals.
85  */
86 
87 static list_t		portal_list;
88 static uint32_t		portal_list_count = 0;
89 
90 /* How many of our portals are not "default"? */
91 static uint32_t		nondefault_portals = 0;
92 
93 /*
94  * Our entity identifier (fully-qualified hostname)
95  */
96 static char		*isns_eid = NULL;
97 
98 /*
99  * Our list of targets
100  */
101 static avl_tree_t	isns_target_list;
102 
103 static void
104 isnst_start();
105 
106 static void
107 isnst_stop();
108 
109 static void
110 iscsit_set_isns(boolean_t state);
111 
112 static int
113 iscsit_add_isns(it_portal_t *cfg_svr);
114 
115 static void
116 iscsit_delete_isns(iscsit_isns_svr_t *svr);
117 
118 static iscsit_isns_svr_t *
119 iscsit_isns_svr_lookup(struct sockaddr_storage *sa);
120 
121 static void
122 isnst_monitor(void *arg);
123 
124 static int
125 isnst_monitor_one_server(iscsit_isns_svr_t *svr, boolean_t enabled);
126 
127 static int
128 isnst_update_target(iscsit_tgt_t *target, isns_reg_type_t reg);
129 
130 static  int
131 isnst_update_one_server(iscsit_isns_svr_t *svr, iscsit_tgt_t *target,
132     isns_reg_type_t reg);
133 
134 static int isnst_register(iscsit_isns_svr_t *svr, iscsit_tgt_t *target,
135     isns_reg_type_t regtype);
136 static int isnst_deregister(iscsit_isns_svr_t *svr, char *node);
137 
138 static size_t
139 isnst_make_dereg_pdu(isns_pdu_t **pdu, char *node);
140 
141 static int
142 isnst_verify_rsp(isns_pdu_t *pdu, isns_pdu_t *rsp);
143 
144 static uint16_t
145 isnst_pdu_get_op(isns_pdu_t *pdu, uint8_t **pp);
146 
147 static size_t
148 isnst_make_reg_pdu(isns_pdu_t **pdu, iscsit_tgt_t *target,
149     boolean_t svr_registered, isns_reg_type_t regtype);
150 
151 static size_t
152 isnst_create_pdu_header(uint16_t func_id, isns_pdu_t **pdu, uint16_t flags);
153 
154 static int
155 isnst_add_attr(isns_pdu_t *pdu,
156     size_t max_pdu_size,
157     uint32_t attr_id,
158     uint32_t attr_len,
159     void *attr_data,
160     uint32_t attr_numeric_data);
161 
162 static int
163 isnst_send_pdu(void *so, isns_pdu_t *pdu);
164 
165 static size_t
166 isnst_rcv_pdu(void *so, isns_pdu_t **pdu);
167 
168 static void *
169 isnst_open_so(struct sockaddr_storage *sa);
170 
171 static void
172 isnst_close_so(void *);
173 
174 static void
175 isnst_esi_thread(void *arg);
176 
177 static boolean_t
178 isnst_handle_esi_req(struct sonode *so, isns_pdu_t *pdu, size_t pl_size);
179 
180 static void isnst_esi_start(isns_portal_list_t *portal);
181 static void isnst_esi_stop();
182 static void isnst_esi_stop_thread(isns_esi_tinfo_t *tinfop);
183 static void isnst_esi_check();
184 static void isnst_esi_start_thread(isns_esi_tinfo_t *tinfop);
185 static isns_target_t *isnst_add_to_target_list(iscsit_tgt_t *target);
186 int isnst_tgt_avl_compare(const void *t1, const void *t2);
187 static void isnst_get_target_list(void);
188 static void isnst_set_server_status(iscsit_isns_svr_t *svr,
189     boolean_t registered);
190 static void isnst_wakeup_monitor(void);
191 static void isns_remove_portal(isns_portal_list_t *p);
192 static void isnst_add_default_portals();
193 static int isnst_add_default_portal_attrs(isns_pdu_t *pdu, size_t pdu_size);
194 static void isnst_remove_default_portals();
195 static boolean_t isnst_retry_registration(int rsp_status_code);
196 
197 it_cfg_status_t
198 isnst_config_merge(it_config_t *cfg)
199 {
200 	boolean_t		new_isns_state = B_FALSE;
201 	iscsit_isns_svr_t	*isns_svr, *next_isns_svr;
202 	it_portal_t		*cfg_isns_svr;
203 
204 	/*
205 	 * Determine whether iSNS is enabled in the new config.
206 	 * Isns property may not be set up yet.
207 	 */
208 	(void) nvlist_lookup_boolean_value(cfg->config_global_properties,
209 	    PROP_ISNS_ENABLED, &new_isns_state);
210 
211 	ISNS_GLOBAL_LOCK();
212 
213 	/* Delete iSNS servers that are no longer part of the config */
214 	for (isns_svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
215 	    isns_svr != NULL;
216 	    isns_svr = next_isns_svr) {
217 		next_isns_svr = list_next(
218 		    &iscsit_global.global_isns_cfg.isns_svrs, isns_svr);
219 		if (it_sns_svr_lookup(cfg, &isns_svr->svr_sa) == NULL)
220 			iscsit_delete_isns(isns_svr);
221 	}
222 
223 	/* Add new iSNS servers */
224 	for (cfg_isns_svr = cfg->config_isns_svr_list;
225 	    cfg_isns_svr != NULL;
226 	    cfg_isns_svr = cfg_isns_svr->next) {
227 		isns_svr = iscsit_isns_svr_lookup(&cfg_isns_svr->portal_addr);
228 		if (isns_svr == NULL) {
229 			if (iscsit_add_isns(cfg_isns_svr) != 0) {
230 				/* Shouldn't happen */
231 				ISNS_GLOBAL_UNLOCK();
232 				return (ITCFG_MISC_ERR);
233 			}
234 		}
235 	}
236 
237 	/* Start/Stop iSNS if necessary */
238 	if (iscsit_global.global_isns_cfg.isns_state != new_isns_state) {
239 		iscsit_set_isns(new_isns_state);
240 	}
241 
242 	ISNS_GLOBAL_UNLOCK();
243 
244 	/*
245 	 * There is no "modify case" since the user specifies a complete
246 	 * server list each time.  A modify is the same as a remove+add.
247 	 */
248 
249 	return (0);
250 }
251 
252 int
253 iscsit_isns_init(iscsit_hostinfo_t *hostinfo)
254 {
255 	mutex_init(&iscsit_global.global_isns_cfg.isns_mutex, NULL,
256 	    MUTEX_DEFAULT, NULL);
257 
258 	ISNS_GLOBAL_LOCK();
259 	iscsit_global.global_isns_cfg.isns_state = B_FALSE;
260 	list_create(&iscsit_global.global_isns_cfg.isns_svrs,
261 	    sizeof (iscsit_isns_svr_t), offsetof(iscsit_isns_svr_t, svr_ln));
262 	list_create(&portal_list, sizeof (isns_portal_list_t),
263 	    offsetof(isns_portal_list_t, portal_ln));
264 	list_create(&esi_list, sizeof (isns_esi_tinfo_t),
265 	    offsetof(isns_esi_tinfo_t, esi_ln));
266 	portal_list_count = 0;
267 	isns_eid = kmem_alloc(hostinfo->length, KM_SLEEP);
268 	if (hostinfo->length > ISCSIT_MAX_HOSTNAME_LEN)
269 		hostinfo->length = ISCSIT_MAX_HOSTNAME_LEN;
270 	(void) strlcpy(isns_eid, hostinfo->fqhn, hostinfo->length);
271 	avl_create(&isns_target_list, isnst_tgt_avl_compare,
272 	    sizeof (isns_target_t), offsetof(isns_target_t, target_node));
273 	/*
274 	 * The iscsi global lock is not held here, but it is held when
275 	 * isnst_start is called, so we need to acquire it only in this
276 	 * case.
277 	 */
278 	ISCSIT_GLOBAL_LOCK(RW_READER);
279 	isnst_get_target_list();
280 	ISCSIT_GLOBAL_UNLOCK();
281 
282 	/* initialize isns client */
283 	mutex_init(&isns_mutex, NULL, MUTEX_DEFAULT, NULL);
284 	mutex_init(&isns_esi_mutex, NULL, MUTEX_DEFAULT, NULL);
285 	isns_monitor_thr_id = NULL;
286 	monitor_idle_interval = ISNS_IDLE_TIME * drv_usectohz(1000000);
287 	cv_init(&isns_idle_cv, NULL, CV_DEFAULT, NULL);
288 	cv_init(&isns_esi_cv, NULL, CV_DEFAULT, NULL);
289 	isns_idle = B_TRUE;
290 	xid = 0;
291 	ISNS_GLOBAL_UNLOCK();
292 
293 	return (0);
294 }
295 
296 static void
297 isnst_esi_stop_thread(isns_esi_tinfo_t *tinfop)
298 {
299 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
300 	ASSERT(mutex_owned(&isns_esi_mutex));
301 
302 	list_remove(&esi_list, tinfop);
303 
304 	/*
305 	 * The only way to break a thread waiting in soaccept() is to signal
306 	 * it with EINTR.  See idm_so_tgt_svc_offline for more detail.
307 	 */
308 	tinfop->esi_so->so_error = EINTR;
309 	cv_signal(&tinfop->esi_so->so_connind_cv);
310 
311 	/*
312 	 * Must also drop the global lock in case the esi thread is running
313 	 * and trying to update the server timestamps.
314 	 */
315 	mutex_exit(&isns_esi_mutex);
316 	ISNS_GLOBAL_UNLOCK();
317 	thread_join(tinfop->esi_thread_did);
318 	ISNS_GLOBAL_LOCK();
319 	mutex_enter(&isns_esi_mutex);
320 
321 	tinfop->esi_portal->portal_esi = NULL;
322 	kmem_free(tinfop, sizeof (isns_esi_tinfo_t));
323 }
324 
325 static void
326 isnst_esi_stop()
327 {
328 	/*
329 	 * Basically, we just wait for all the threads to stop.  They
330 	 * should already be in the process of shutting down.
331 	 */
332 
333 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
334 
335 	ISNS_GLOBAL_UNLOCK();
336 	mutex_enter(&isns_esi_mutex);
337 	while (!list_is_empty(&esi_list)) {
338 		cv_wait(&isns_esi_cv, &isns_esi_mutex);
339 	}
340 	mutex_exit(&isns_esi_mutex);
341 	ISNS_GLOBAL_LOCK();
342 }
343 
344 void
345 iscsit_isns_fini()
346 {
347 	ISNS_GLOBAL_LOCK();
348 	iscsit_set_isns(B_FALSE);
349 	ISNS_GLOBAL_UNLOCK();
350 
351 	mutex_enter(&isns_mutex);
352 	while (isns_monitor_thr_id != NULL) {
353 		cv_wait(&isns_idle_cv, &isns_mutex);
354 	}
355 	mutex_exit(&isns_mutex);
356 
357 	ISNS_GLOBAL_LOCK();
358 	mutex_destroy(&isns_mutex);
359 	cv_destroy(&isns_idle_cv);
360 	list_destroy(&esi_list);
361 	mutex_destroy(&isns_esi_mutex);
362 	cv_destroy(&isns_esi_cv);
363 
364 	/*
365 	 * Free our EID and target list.
366 	 */
367 
368 	if (isns_eid) {
369 		kmem_free(isns_eid, strlen(isns_eid) + 1);
370 		isns_eid = NULL;
371 	}
372 
373 	iscsit_global.global_isns_cfg.isns_state = B_FALSE;
374 	avl_destroy(&isns_target_list);
375 	list_destroy(&iscsit_global.global_isns_cfg.isns_svrs);
376 	list_destroy(&portal_list);
377 	portal_list_count = 0;
378 	ISNS_GLOBAL_UNLOCK();
379 
380 	mutex_destroy(&iscsit_global.global_isns_cfg.isns_mutex);
381 }
382 
383 static void
384 iscsit_set_isns(boolean_t state)
385 {
386 	iscsit_isns_svr_t	*svr;
387 
388 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
389 
390 	/* reset retry count for all servers */
391 	for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
392 	    svr != NULL;
393 	    svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, svr)) {
394 		svr->svr_retry_count = 0;
395 	}
396 
397 	/*
398 	 * Update state and isns stop flag
399 	 */
400 	iscsit_global.global_isns_cfg.isns_state = state;
401 
402 	if (state) {
403 		isnst_start();
404 	} else {
405 		isnst_stop();
406 	}
407 }
408 
409 int
410 iscsit_add_isns(it_portal_t *cfg_svr)
411 {
412 	iscsit_isns_svr_t *svr;
413 
414 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
415 
416 	svr = kmem_zalloc(sizeof (iscsit_isns_svr_t), KM_SLEEP);
417 	bcopy(&cfg_svr->portal_addr, &svr->svr_sa,
418 	    sizeof (struct sockaddr_storage));
419 
420 	/* put it on the global isns server list */
421 	list_insert_tail(&iscsit_global.global_isns_cfg.isns_svrs, svr);
422 
423 	/*
424 	 * Register targets with this server if iSNS is enabled.
425 	 */
426 
427 	if (iscsit_global.global_isns_cfg.isns_state &&
428 	    (isnst_update_one_server(svr, NULL, ISNS_REGISTER_ALL) == 0)) {
429 		isnst_set_server_status(svr, B_TRUE);
430 	}
431 
432 	return (0);
433 }
434 
435 void
436 iscsit_delete_isns(iscsit_isns_svr_t *svr)
437 {
438 	boolean_t	need_dereg;
439 
440 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
441 
442 	list_remove(&iscsit_global.global_isns_cfg.isns_svrs, svr);
443 
444 	/* talk to this server if isns monitor is running */
445 	mutex_enter(&isns_mutex);
446 	if (isns_monitor_thr_id != NULL) {
447 		need_dereg = B_TRUE;
448 	} else {
449 		need_dereg = B_FALSE;
450 	}
451 	mutex_exit(&isns_mutex);
452 
453 	if (need_dereg) {
454 		(void) isnst_monitor_one_server(svr, B_FALSE);
455 	}
456 
457 	/* free the memory */
458 	kmem_free(svr, sizeof (*svr));
459 }
460 
461 static iscsit_isns_svr_t *
462 iscsit_isns_svr_lookup(struct sockaddr_storage *sa)
463 {
464 	iscsit_isns_svr_t	*svr;
465 	it_portal_t		portal1;
466 
467 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
468 
469 	bcopy(sa, &portal1.portal_addr, sizeof (struct sockaddr_storage));
470 
471 	for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
472 	    svr != NULL;
473 	    svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, svr)) {
474 		if (it_sa_compare(&svr->svr_sa, sa) == 0)
475 			return (svr);
476 	}
477 
478 	return (NULL);
479 }
480 
481 int
482 iscsit_isns_register(iscsit_tgt_t *target)
483 {
484 	int rc = 0;
485 
486 	ISNS_GLOBAL_LOCK();
487 
488 	(void) isnst_add_to_target_list(target);
489 
490 	if (iscsit_global.global_isns_cfg.isns_state == B_FALSE) {
491 		ISNS_GLOBAL_UNLOCK();
492 		return (rc);
493 	}
494 
495 	rc = isnst_update_target(target, ISNS_REGISTER_TARGET);
496 
497 	ISNS_GLOBAL_UNLOCK();
498 
499 	return (rc);
500 }
501 
502 int
503 iscsit_isns_deregister(iscsit_tgt_t *target)
504 {
505 	void				*itarget;
506 	isns_target_t			tmptgt;
507 	iscsit_isns_svr_t		*svr;
508 	list_t				*global;
509 
510 	ISNS_GLOBAL_LOCK();
511 
512 	if (iscsit_global.global_isns_cfg.isns_state == B_FALSE) {
513 		tmptgt.target = target;
514 
515 		if ((itarget = avl_find(&isns_target_list, &tmptgt, NULL))
516 		    != NULL) {
517 			avl_remove(&isns_target_list, itarget);
518 			kmem_free(itarget, sizeof (isns_target_t));
519 		}
520 
521 		ISNS_GLOBAL_UNLOCK();
522 		return (0);
523 	}
524 
525 	/*
526 	 * Don't worry about dereg failures.
527 	 */
528 	(void) isnst_update_target(target, ISNS_DEREGISTER_TARGET);
529 
530 	/*
531 	 * Remove the target from the list regardless of the status.
532 	 */
533 
534 	tmptgt.target = target;
535 	if ((itarget = avl_find(&isns_target_list, &tmptgt, NULL)) != NULL) {
536 		avl_remove(&isns_target_list, itarget);
537 		kmem_free(itarget, sizeof (isns_target_t));
538 	}
539 
540 	/*
541 	 * If there are no more targets, mark the server as
542 	 * unregistered.
543 	 */
544 
545 	if (avl_numnodes(&isns_target_list) == 0) {
546 		global = &iscsit_global.global_isns_cfg.isns_svrs;
547 		for (svr = list_head(global); svr != NULL;
548 		    svr = list_next(global, svr)) {
549 			isnst_set_server_status(svr, B_FALSE);
550 		}
551 	}
552 
553 	ISNS_GLOBAL_UNLOCK();
554 
555 	return (0);
556 }
557 
558 /*
559  * This function is called by iscsit when a target's configuration
560  * has changed.
561  */
562 
563 void
564 iscsit_isns_target_update(iscsit_tgt_t *target)
565 {
566 	ISNS_GLOBAL_LOCK();
567 
568 	if (iscsit_global.global_isns_cfg.isns_state == B_FALSE) {
569 		ISNS_GLOBAL_UNLOCK();
570 		return;
571 	}
572 
573 	(void) isnst_update_target(target, ISNS_UPDATE_TARGET);
574 
575 	ISNS_GLOBAL_UNLOCK();
576 }
577 
578 static void
579 isnst_start()
580 {
581 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
582 
583 	/*
584 	 * Get target and portal lists, then start ESI threads for each portal.
585 	 */
586 
587 	isnst_get_target_list();
588 	isnst_add_default_portals();
589 
590 	/*
591 	 * Create a thread for monitoring server communications
592 	 */
593 	mutex_enter(&isns_mutex);
594 	if (isns_monitor_thr_id == NULL) {
595 		isns_monitor_thr_id = thread_create(NULL, 0,
596 		    isnst_monitor, NULL, 0, &p0, TS_RUN, minclsyspri);
597 	}
598 	mutex_exit(&isns_mutex);
599 }
600 
601 static void
602 isnst_wakeup_monitor(void)
603 {
604 	mutex_enter(&isns_mutex);
605 	isns_idle = B_FALSE;
606 	cv_signal(&isns_idle_cv);
607 	mutex_exit(&isns_mutex);
608 }
609 
610 static void
611 isnst_stop()
612 {
613 	isns_target_t *itarget;
614 
615 	while ((itarget = avl_first(&isns_target_list)) != NULL) {
616 		avl_remove(&isns_target_list, itarget);
617 		kmem_free(itarget, sizeof (isns_target_t));
618 	}
619 
620 	isnst_remove_default_portals();
621 	isnst_esi_stop();
622 	isnst_wakeup_monitor();
623 }
624 
625 /*
626  * isnst_update_server_timestamp
627  *
628  * When we receive an ESI request, update the timestamp for the server.
629  * If we don't receive one for the specified period of time, we'll attempt
630  * to re-register.
631  */
632 
633 static void
634 isnst_update_server_timestamp(struct sonode *so)
635 {
636 	iscsit_isns_svr_t	*svr;
637 	struct in_addr		*sin = NULL, *svr_in;
638 	struct in6_addr		*sin6 = NULL, *svr_in6;
639 
640 	if (so->so_faddr_sa->sa_family == AF_INET) {
641 		sin = &((struct sockaddr_in *)
642 		    ((void *)so->so_faddr_sa))->sin_addr;
643 	} else {
644 		sin6 = &((struct sockaddr_in6 *)
645 		    ((void *)so->so_faddr_sa))->sin6_addr;
646 	}
647 
648 	/*
649 	 * Find the server and update the timestamp
650 	 */
651 
652 	ISNS_GLOBAL_LOCK();
653 	for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
654 	    svr != NULL;
655 	    svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, svr)) {
656 		if (sin6 == NULL) {
657 			if (svr->svr_sa.ss_family == AF_INET) {
658 				svr_in = &((struct sockaddr_in *)&svr->svr_sa)->
659 				    sin_addr;
660 				if (bcmp(svr_in, sin, sizeof (in_addr_t))
661 				    == 0) {
662 					break;
663 				}
664 			}
665 		} else {
666 			if (svr->svr_sa.ss_family == AF_INET6) {
667 				svr_in6 = &((struct sockaddr_in6 *)
668 				    &svr->svr_sa)->sin6_addr;
669 				if (bcmp(svr_in6, sin6,
670 				    sizeof (in6_addr_t)) == 0) {
671 					break;
672 				}
673 			}
674 		}
675 	}
676 
677 	if (svr != NULL) {
678 		svr->svr_last_msg = ddi_get_lbolt();
679 	}
680 	ISNS_GLOBAL_UNLOCK();
681 }
682 
683 /*
684  * isnst_monitor
685  *
686  * This function monitors registration status for each server.
687  */
688 
689 /*ARGSUSED*/
690 static void
691 isnst_monitor(void *arg)
692 {
693 	iscsit_isns_svr_t	*svr;
694 	list_t			*svr_list;
695 	boolean_t		enabled;
696 
697 	svr_list = &iscsit_global.global_isns_cfg.isns_svrs;
698 
699 	do {
700 		ISNS_GLOBAL_LOCK();
701 		enabled = iscsit_global.global_isns_cfg.isns_state;
702 		for (svr = list_head(svr_list); svr != NULL;
703 		    svr = list_next(svr_list, svr)) {
704 			if (isnst_monitor_one_server(svr, enabled) != 0) {
705 				svr->svr_retry_count++;
706 			} else {
707 				svr->svr_retry_count = 0;
708 			}
709 		}
710 
711 		/*
712 		 * Attempted registrations, especially to unreachable
713 		 * servers, can take time.  Thus, we check the isns_state
714 		 * again here.
715 		 */
716 		enabled = iscsit_global.global_isns_cfg.isns_state;
717 		ISNS_GLOBAL_UNLOCK();
718 
719 		/*
720 		 * Keep the while loop running while isns is enabled.
721 		 * If isns_idle is FALSE, we have more work to do, so
722 		 * no waiting.
723 		 */
724 
725 		mutex_enter(&isns_mutex);
726 
727 		if (enabled && isns_idle) {
728 			(void) cv_timedwait(&isns_idle_cv, &isns_mutex,
729 			    ddi_get_lbolt() + monitor_idle_interval);
730 		}
731 
732 		isns_idle = B_TRUE;
733 		mutex_exit(&isns_mutex);
734 	} while (enabled);
735 
736 	mutex_enter(&isns_mutex);
737 	isns_monitor_thr_id = NULL;
738 	cv_signal(&isns_idle_cv);
739 	mutex_exit(&isns_mutex);
740 
741 	/* terminate the thread at the last */
742 	thread_exit();
743 }
744 
745 static int
746 isnst_monitor_one_server(iscsit_isns_svr_t *svr, boolean_t enabled)
747 {
748 	int		rc = 0;
749 	struct sonode	*so;
750 
751 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
752 
753 	/*
754 	 * First, take care of the case where iSNS is no longer enabled.
755 	 *
756 	 * If we're still registered, deregister.  Regardless, mark the
757 	 * server as not registered.
758 	 */
759 
760 	if (enabled == B_FALSE) {
761 		if (svr->svr_registered == B_TRUE) {
762 			/*
763 			 * Doesn't matter if this fails.  We're disabled.
764 			 */
765 			so = isnst_open_so(&svr->svr_sa);
766 			if (so != NULL) {
767 				(void) isnst_update_one_server(svr, NULL,
768 				    ISNS_DEREGISTER_ALL);
769 				isnst_close_so(so);
770 			}
771 		}
772 
773 		isnst_set_server_status(svr, B_FALSE);
774 		return (0);
775 	}
776 
777 	/*
778 	 * If there are no targets, we're done.
779 	 */
780 
781 	if (avl_numnodes(&isns_target_list) == 0) {
782 		return (0);
783 	}
784 
785 	/*
786 	 * At this point, we know iSNS is enabled.
787 	 *
788 	 * If we've received an ESI request from the server recently
789 	 * (within MAX_ESI_INTERVALS * the max interval length),
790 	 * no need to continue.
791 	 */
792 
793 	if (svr->svr_registered == B_TRUE) {
794 		if (ddi_get_lbolt() < (svr->svr_last_msg +
795 		    drv_usectohz(isns_esi_max_interval * 1000000 *
796 		    MAX_ESI_INTERVALS))) {
797 			return (0);
798 		}
799 	} else {
800 		/*
801 		 * We're not registered... Try to register now.
802 		 */
803 		if ((rc = isnst_update_one_server(svr, NULL,
804 		    ISNS_REGISTER_ALL)) == 0) {
805 			isnst_set_server_status(svr, B_TRUE);
806 		}
807 	}
808 
809 	return (rc);
810 }
811 
812 static int
813 isnst_update_target(iscsit_tgt_t *target, isns_reg_type_t reg)
814 {
815 	iscsit_isns_svr_t	*svr;
816 	int			rc = 0, curr_rc;
817 
818 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
819 	ASSERT(iscsit_global.global_isns_cfg.isns_state == B_TRUE);
820 
821 	for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
822 	    svr != NULL;
823 	    svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, svr)) {
824 		/*
825 		 * Only return success if they all succeed.  Let the caller
826 		 * deal with any failure.
827 		 */
828 
829 		curr_rc = isnst_update_one_server(svr, target, reg);
830 
831 		if (curr_rc == 0) {
832 			if (reg == ISNS_REGISTER_TARGET) {
833 				isnst_set_server_status(svr, B_TRUE);
834 			}
835 		} else if (rc == 0) {
836 			rc = curr_rc;
837 		}
838 	}
839 
840 	return (rc);
841 }
842 
843 static int
844 isnst_update_one_server(iscsit_isns_svr_t *svr, iscsit_tgt_t *target,
845     isns_reg_type_t reg)
846 {
847 	int rc = 0;
848 
849 	switch (reg) {
850 	case ISNS_DEREGISTER_TARGET:
851 		rc = isnst_deregister(svr, target->target_name);
852 		break;
853 
854 	case ISNS_DEREGISTER_ALL:
855 		rc = isnst_deregister(svr, NULL);
856 		break;
857 
858 	case ISNS_UPDATE_TARGET:
859 	case ISNS_REGISTER_TARGET:
860 		rc = isnst_register(svr, target, reg);
861 		break;
862 
863 	case ISNS_REGISTER_ALL:
864 		rc = isnst_register(svr, NULL, reg);
865 		break;
866 
867 	default:
868 		ASSERT(0);
869 		/* NOTREACHED */
870 	}
871 
872 	return (rc);
873 }
874 
875 /*
876  * isnst_retry_registration
877  *
878  * This function checks the return value from a registration pdu and
879  * determines whether or not we should retry this request.  If the
880  * request is retried, it will do so as an "update", which means we
881  * re-register everything.
882  */
883 
884 static boolean_t
885 isnst_retry_registration(int rsp_status_code)
886 {
887 	boolean_t retry;
888 
889 	/*
890 	 * Currently, we will attempt to retry for "Invalid Registration",
891 	 * "Source Unauthorized", or "Busy" errors.  Any other errors should
892 	 * be handled by the caller if necessary.
893 	 */
894 
895 	switch (rsp_status_code) {
896 	case ISNS_RSP_INVALID_REGIS:
897 	case ISNS_RSP_SRC_UNAUTHORIZED:
898 	case ISNS_RSP_BUSY:
899 		retry = B_TRUE;
900 		break;
901 	default:
902 		retry = B_FALSE;
903 		break;
904 	}
905 
906 	return (retry);
907 }
908 
909 static int
910 isnst_register(iscsit_isns_svr_t *svr, iscsit_tgt_t *target,
911     isns_reg_type_t regtype)
912 {
913 	struct sonode	*so;
914 	int		rc = 0;
915 	isns_pdu_t	*pdu, *rsp;
916 	size_t		pdu_size, rsp_size;
917 	isns_target_t	*itarget, tmptgt;
918 	boolean_t	retry_reg = B_TRUE;
919 
920 	/*
921 	 * Registration is a tricky thing.  In order to keep things simple,
922 	 * we don't want to keep track of which targets are registered to
923 	 * which server.  We rely on the target state machine to tell us
924 	 * when a target is online or offline, which prompts us to either
925 	 * register or deregister that target.
926 	 *
927 	 * When iscsit_isns_init is called, get a list of targets.  Those that
928 	 * are online will need to be registered.  In this case, target
929 	 * will be NULL.
930 	 *
931 	 * What this means is that if svr_registered == B_FALSE, that's
932 	 * when we'll register the network entity as well.
933 	 */
934 
935 	if ((avl_numnodes(&isns_target_list) == 0) && (target == NULL)) {
936 		return (0);
937 	}
938 
939 	/*
940 	 * If the target is already registered and we're not doing an
941 	 * update registration, just return.
942 	 */
943 
944 	if (target != NULL) {
945 		tmptgt.target = target;
946 		itarget = avl_find(&isns_target_list, &tmptgt, NULL);
947 		ASSERT(itarget);
948 		if ((itarget->target_registered == B_TRUE) &&
949 		    (regtype != ISNS_UPDATE_TARGET)) {
950 			return (0);
951 		}
952 	}
953 
954 	isnst_esi_check();
955 
956 	/* create TCP connection to the isns server */
957 	so = isnst_open_so(&svr->svr_sa);
958 
959 	if (so == NULL) {
960 		isnst_set_server_status(svr, B_FALSE);
961 		return (-1);
962 	}
963 
964 	while (retry_reg) {
965 		pdu_size = isnst_make_reg_pdu(&pdu, target, svr->svr_registered,
966 		    regtype);
967 		if (pdu_size == 0) {
968 			isnst_close_so(so);
969 			return (-1);
970 		}
971 
972 		rc = isnst_send_pdu(so, pdu);
973 		if (rc != 0) {
974 			kmem_free(pdu, pdu_size);
975 			isnst_close_so(so);
976 			return (rc);
977 		}
978 
979 		rsp_size = isnst_rcv_pdu(so, &rsp);
980 		if (rsp_size == 0) {
981 			kmem_free(pdu, pdu_size);
982 			isnst_close_so(so);
983 			return (-1);
984 		}
985 
986 		rc = isnst_verify_rsp(pdu, rsp);
987 
988 		/*
989 		 * If we got a registration error, the server may be out of
990 		 * sync.  In this case, we may re-try the registration as
991 		 * a "target update", which causes us to re-register everything.
992 		 */
993 
994 		if ((retry_reg = isnst_retry_registration(rc)) == B_TRUE) {
995 			if (regtype == ISNS_UPDATE_TARGET) {
996 				/*
997 				 * If registration failed on an update, there
998 				 * is something terribly wrong, possibly with
999 				 * the server.
1000 				 */
1001 				rc = -1;
1002 				retry_reg = B_FALSE;
1003 				isnst_set_server_status(svr, B_FALSE);
1004 			} else {
1005 				regtype = ISNS_UPDATE_TARGET;
1006 			}
1007 		}
1008 
1009 		kmem_free(pdu, pdu_size);
1010 		kmem_free(rsp, rsp_size);
1011 	}
1012 
1013 	isnst_close_so(so);
1014 
1015 	/*
1016 	 * If it succeeded, mark all registered targets as such
1017 	 */
1018 	if (rc == 0) {
1019 		if ((target != NULL) && (regtype != ISNS_UPDATE_TARGET)) {
1020 			/* itarget initialized above */
1021 			itarget->target_registered = B_TRUE;
1022 		} else {
1023 			itarget = avl_first(&isns_target_list);
1024 			while (itarget) {
1025 				itarget->target_registered = B_TRUE;
1026 				itarget = AVL_NEXT(&isns_target_list, itarget);
1027 			}
1028 		}
1029 	}
1030 
1031 	return (rc);
1032 }
1033 
1034 static isns_portal_list_t *
1035 isns_lookup_portal(struct sockaddr_storage *p)
1036 {
1037 	isns_portal_list_t *portal;
1038 
1039 	portal = list_head(&portal_list);
1040 
1041 	while (portal != NULL) {
1042 		if (bcmp(p, &portal->portal_addr,
1043 		    sizeof (struct sockaddr_storage)) == 0) {
1044 			return (portal);
1045 		}
1046 		portal = list_next(&portal_list, portal);
1047 	}
1048 
1049 	return (NULL);
1050 }
1051 
1052 static void
1053 isns_remove_portal(isns_portal_list_t *p)
1054 {
1055 	list_remove(&portal_list, p);
1056 	kmem_free(p, sizeof (isns_portal_list_t));
1057 	portal_list_count--;
1058 }
1059 
1060 static isns_target_t *
1061 isnst_add_to_target_list(iscsit_tgt_t *target)
1062 {
1063 	isns_target_t *itarget, tmptgt;
1064 
1065 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
1066 
1067 	/*
1068 	 * Make sure this target isn't already in our list.  If it is,
1069 	 * perhaps it has just moved from offline to online.
1070 	 */
1071 
1072 	tmptgt.target = target;
1073 	if ((itarget = (isns_target_t *)avl_find(&isns_target_list,
1074 	    &tmptgt, NULL)) == NULL) {
1075 		itarget = kmem_zalloc(sizeof (isns_target_t), KM_NOSLEEP);
1076 
1077 		/*
1078 		 * If we can't get memory, we're not going to be able to
1079 		 * register this target.  This needs to be fixed up.
1080 		 */
1081 		if (itarget == NULL)
1082 			return (NULL);
1083 
1084 		itarget->target = target;
1085 		avl_add(&isns_target_list, itarget);
1086 	}
1087 
1088 	return (itarget);
1089 }
1090 
1091 static int
1092 isnst_add_default_portal_attrs(isns_pdu_t *pdu, size_t pdu_size)
1093 {
1094 	isns_portal_list_t	*portal;
1095 	struct sockaddr_in	*in;
1096 	struct sockaddr_in6	*in6;
1097 	int			idx = 0;
1098 	uint32_t		attr_data;
1099 	void			*inaddrp;
1100 
1101 	portal = list_head(&portal_list);
1102 
1103 	while (portal) {
1104 		if (idx == nondefault_portals) {
1105 			break;
1106 		}
1107 
1108 		if (portal->portal_iscsit == NULL) {
1109 			in = (struct sockaddr_in *)&portal->portal_addr;
1110 
1111 			if (in->sin_family == AF_INET) {
1112 				attr_data = sizeof (in_addr_t);
1113 				inaddrp = (void *)&in->sin_addr;
1114 			} else if (in->sin_family == AF_INET6) {
1115 				in6 = (struct sockaddr_in6 *)
1116 				    &portal->portal_addr;
1117 				attr_data = sizeof (in6_addr_t);
1118 				inaddrp = (void *)&in6->sin6_addr;
1119 			} else {
1120 				return (-1);
1121 			}
1122 
1123 			if (isnst_add_attr(pdu, pdu_size,
1124 			    ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, 16, inaddrp,
1125 			    attr_data) != 0) {
1126 				return (-1);
1127 			}
1128 
1129 			/* Portal Group Portal Port */
1130 			if (isnst_add_attr(pdu, pdu_size,
1131 			    ISNS_PG_PORTAL_PORT_ATTR_ID, 4, 0,
1132 			    ntohs(in->sin_port)) != 0) {
1133 				return (-1);
1134 			}
1135 
1136 			idx++;
1137 		}
1138 
1139 		portal = list_next(&portal_list, portal);
1140 	}
1141 
1142 	return (0);
1143 }
1144 
1145 static size_t
1146 isnst_make_reg_pdu(isns_pdu_t **pdu, iscsit_tgt_t *target,
1147     boolean_t svr_registered, isns_reg_type_t regtype)
1148 {
1149 	size_t			pdu_size;
1150 	iscsit_tpgt_t		*tpgt;
1151 	iscsit_tpg_t		*tpg;
1152 	iscsit_portal_t		*tp;
1153 	char			*str;
1154 	int			len;
1155 	isns_portal_list_t	*portal;
1156 	isns_esi_tinfo_t	*tinfop;
1157 	isns_target_t		*itarget;
1158 	iscsit_tgt_t		*src;
1159 	boolean_t		reg_all = B_FALSE;
1160 	uint16_t		flags = 0;
1161 
1162 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
1163 
1164 	/*
1165 	 * Find a source attribute for this registration.
1166 	 *
1167 	 * If we're already registered, registering for the first time, or
1168 	 * updating a target, we'll use the target_name of the first target
1169 	 * in our list.
1170 	 *
1171 	 * The alternate case is that we're registering for the first time,
1172 	 * but target is non-NULL.  In that case, we have no targets in our
1173 	 * list yet, so we use the passed in target's name.
1174 	 */
1175 
1176 	if (svr_registered || (target == NULL) ||
1177 	    (regtype == ISNS_UPDATE_TARGET)) {
1178 		ASSERT(avl_numnodes(&isns_target_list) != 0);
1179 		itarget = (isns_target_t *)avl_first(&isns_target_list);
1180 		src = itarget->target;
1181 	} else {
1182 		src = target;
1183 	}
1184 
1185 	/*
1186 	 * No target means we're registering everything.  A regtype of
1187 	 * ISNS_UPDATE_TARGET means we're re-registering everything.
1188 	 * Whether we're registering or re-registering depends on if
1189 	 * we're already registered.
1190 	 */
1191 
1192 	if ((target == NULL) || (regtype == ISNS_UPDATE_TARGET)) {
1193 		reg_all = B_TRUE;
1194 		target = src;	/* This will be the 1st tgt in our list */
1195 
1196 		/*
1197 		 * If we're already registered, this will be a replacement
1198 		 * registration.  In this case, we need to make sure our
1199 		 * source attribute is an already registered target.
1200 		 */
1201 		if (svr_registered) {
1202 			flags = ISNS_FLAG_REPLACE_REG;
1203 			while (itarget->target_registered == B_FALSE) {
1204 				itarget = AVL_NEXT(&isns_target_list,
1205 				    itarget);
1206 			}
1207 			src = itarget->target;
1208 			/* Reset itarget to the beginning of our list */
1209 			itarget = (isns_target_t *)avl_first(&isns_target_list);
1210 		}
1211 	}
1212 
1213 	pdu_size = isnst_create_pdu_header(ISNS_DEV_ATTR_REG, pdu, flags);
1214 	if (pdu_size == 0) {
1215 		return (0);
1216 	}
1217 
1218 	len = strlen(src->target_name) + 1;
1219 	if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1220 	    len, src->target_name, 0) != 0) {
1221 		goto pdu_error;
1222 	}
1223 
1224 	/*
1225 	 * Message Key Attributes - EID
1226 	 */
1227 	len = strlen(isns_eid) + 1;
1228 
1229 	if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID,
1230 	    len, isns_eid, 0) != 0) {
1231 		goto pdu_error;
1232 	}
1233 
1234 	/* Delimiter */
1235 	if (isnst_add_attr(*pdu, pdu_size, ISNS_DELIMITER_ATTR_ID,
1236 	    0, 0, 0) != 0) {
1237 		goto pdu_error;
1238 	}
1239 
1240 	/*
1241 	 * Operating Attributes
1242 	 */
1243 	if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID, len,
1244 	    isns_eid, 0) != 0) {
1245 		goto pdu_error;
1246 	}
1247 
1248 	/* ENTITY Protocol - Section 6.2.2 */
1249 	if (isnst_add_attr(*pdu, pdu_size, ISNS_ENTITY_PROTOCOL_ATTR_ID,
1250 	    4, 0, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) {
1251 		goto pdu_error;
1252 	}
1253 
1254 	/*
1255 	 * Network entity portal information - only on the first registration.
1256 	 */
1257 
1258 	if (svr_registered == B_FALSE) {
1259 		struct sockaddr_in *sin;
1260 		int addrsize;
1261 
1262 		portal = list_head(&portal_list);
1263 
1264 		while (portal != NULL) {
1265 			sin = (struct sockaddr_in *)&portal->portal_addr;
1266 			tinfop = portal->portal_esi;
1267 
1268 			if (portal->portal_iscsit == NULL) {
1269 				if (sin->sin_family == AF_INET) {
1270 					addrsize = sizeof (struct in_addr);
1271 				} else {
1272 					addrsize = sizeof (struct in6_addr);
1273 				}
1274 
1275 				/* Portal IP Address */
1276 				if (isnst_add_attr(*pdu, pdu_size,
1277 				    ISNS_PORTAL_IP_ADDR_ATTR_ID, 16,
1278 				    &sin->sin_addr, addrsize) != 0) {
1279 					goto pdu_error;
1280 				}
1281 
1282 				/* Portal Port */
1283 				if (isnst_add_attr(*pdu, pdu_size,
1284 				    ISNS_PORTAL_PORT_ATTR_ID, 4, 0,
1285 				    ntohs(sin->sin_port)) != 0) {
1286 					goto pdu_error;
1287 				}
1288 
1289 				if (tinfop && tinfop->esi_port) {
1290 					/* ESI interval and port */
1291 					if (isnst_add_attr(*pdu, pdu_size,
1292 					    ISNS_ESI_INTERVAL_ATTR_ID, 4,
1293 					    NULL, 20) != 0) {
1294 						goto pdu_error;
1295 					}
1296 
1297 					if (isnst_add_attr(*pdu, pdu_size,
1298 					    ISNS_ESI_PORT_ATTR_ID, 4, NULL,
1299 					    tinfop->esi_port) != 0) {
1300 						goto pdu_error;
1301 					}
1302 				}
1303 			}
1304 
1305 			portal = list_next(&portal_list, portal);
1306 		}
1307 	}
1308 
1309 	do {
1310 		/* Hold the target mutex */
1311 		mutex_enter(&target->target_mutex);
1312 
1313 		/* iSCSI Name - Section 6.4.1 */
1314 		str = target->target_name;
1315 		len = strlen(str) + 1;
1316 		if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1317 		    len, str, 0) != 0) {
1318 			mutex_exit(&target->target_mutex);
1319 			goto pdu_error;
1320 		}
1321 
1322 		/* iSCSI Node Type */
1323 		if (isnst_add_attr(*pdu, pdu_size,
1324 		    ISNS_ISCSI_NODE_TYPE_ATTR_ID, 4, 0,
1325 		    ISNS_TARGET_NODE_TYPE) != 0) {
1326 			mutex_exit(&target->target_mutex);
1327 			goto pdu_error;
1328 		}
1329 
1330 		/* iSCSI Alias */
1331 #if 0
1332 		str = target->target_alias;
1333 #else
1334 		str = "Solaris iSCSI Target";
1335 #endif
1336 		if (str != NULL) {
1337 			len = strlen(str) + 1;
1338 			if (isnst_add_attr(*pdu, pdu_size,
1339 			    ISNS_ISCSI_ALIAS_ATTR_ID, len, str, 0) != 0) {
1340 				mutex_exit(&target->target_mutex);
1341 				goto pdu_error;
1342 			}
1343 		}
1344 
1345 		/* for each target portal group (start)... */
1346 		tpgt = avl_first(&target->target_tpgt_list);
1347 		ASSERT(tpgt != NULL);
1348 		do {
1349 			/* no need to explicitly register default PG */
1350 			if ((tpgt->tpgt_tag == ISCSIT_DEFAULT_TPGT) &&
1351 			    (avl_numnodes(&target->target_tpgt_list) == 1)) {
1352 				tpgt = AVL_NEXT(&target->target_tpgt_list,
1353 				    tpgt);
1354 				continue;
1355 			}
1356 
1357 			tpg = tpgt->tpgt_tpg;
1358 			mutex_enter(&tpg->tpg_mutex);
1359 
1360 			tp = avl_first(&tpg->tpg_portal_list);
1361 
1362 			/* Portal Group Tag */
1363 			if (isnst_add_attr(*pdu, pdu_size,
1364 			    ISNS_PG_TAG_ATTR_ID, 4, 0, tpgt->tpgt_tag) != 0) {
1365 				mutex_exit(&tpg->tpg_mutex);
1366 				mutex_exit(&target->target_mutex);
1367 				goto pdu_error;
1368 			}
1369 
1370 			ASSERT(tp != NULL);
1371 			do {
1372 				struct sockaddr_storage	*ss;
1373 				struct sockaddr_in	*in;
1374 				struct sockaddr_in6	*in6;
1375 				uint32_t attr_numeric_data;
1376 				void *inaddrp;
1377 
1378 				ss = &tp->portal_addr;
1379 				in = (struct sockaddr_in *)ss;
1380 				in6 = (struct sockaddr_in6 *)ss;
1381 
1382 				if (ss->ss_family == AF_INET) {
1383 					attr_numeric_data = sizeof (in_addr_t);
1384 					inaddrp = (void *)&in->sin_addr;
1385 				} else if (ss->ss_family == AF_INET6) {
1386 					attr_numeric_data = sizeof (in6_addr_t);
1387 					inaddrp = (void *)&in6->sin6_addr;
1388 				} else if (ss->ss_family == 0) {
1389 					/*
1390 					 * Need to add all default portals
1391 					 */
1392 					attr_numeric_data = 0;
1393 				} else {
1394 					cmn_err(CE_WARN, "Unknown address "
1395 					    "family for portal %p", (void *)tp);
1396 					mutex_exit(&tpg->tpg_mutex);
1397 					mutex_exit(&target->target_mutex);
1398 					goto pdu_error;
1399 				}
1400 
1401 				if (attr_numeric_data == 0) {
1402 					if (isnst_add_default_portal_attrs(*pdu,
1403 					    pdu_size) != 0) {
1404 						mutex_exit(&tpg->tpg_mutex);
1405 						mutex_exit(&target->
1406 						    target_mutex);
1407 						goto pdu_error;
1408 					}
1409 				} else {
1410 					/* Portal Group Portal IP Address */
1411 					if (isnst_add_attr(*pdu, pdu_size,
1412 					    ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, 16,
1413 					    inaddrp, attr_numeric_data) != 0) {
1414 						mutex_exit(&tpg->tpg_mutex);
1415 						mutex_exit(&target->
1416 						    target_mutex);
1417 						goto pdu_error;
1418 					}
1419 
1420 					/* Portal Group Portal Port */
1421 					if (isnst_add_attr(*pdu, pdu_size,
1422 					    ISNS_PG_PORTAL_PORT_ATTR_ID,
1423 					    4, 0, ntohs(in->sin_port)) != 0) {
1424 						mutex_exit(&tpg->tpg_mutex);
1425 						mutex_exit(&target->
1426 						    target_mutex);
1427 						goto pdu_error;
1428 					}
1429 				}
1430 
1431 				tp = AVL_NEXT(&tpg->tpg_portal_list, tp);
1432 			} while (tp != NULL);
1433 
1434 			mutex_exit(&tpg->tpg_mutex);
1435 			tpgt = AVL_NEXT(&target->target_tpgt_list, tpgt);
1436 		} while (tpgt != NULL);
1437 		/* for each target portal group (end)... */
1438 
1439 		mutex_exit(&target->target_mutex);
1440 
1441 		if (reg_all) {
1442 			itarget = AVL_NEXT(&isns_target_list, itarget);
1443 			if (itarget) {
1444 				target = itarget->target;
1445 			} else {
1446 				target = NULL;
1447 			}
1448 		}
1449 	} while ((reg_all == B_TRUE) && (target != NULL));
1450 
1451 	return (pdu_size);
1452 
1453 pdu_error:
1454 	/* packet too large, no memory */
1455 	kmem_free(*pdu, pdu_size);
1456 	*pdu = NULL;
1457 
1458 	return (0);
1459 }
1460 
1461 static int
1462 isnst_deregister(iscsit_isns_svr_t *svr, char *node)
1463 {
1464 	int		rc;
1465 	isns_pdu_t	*pdu, *rsp;
1466 	size_t		pdu_size, rsp_size;
1467 	struct sonode	*so;
1468 
1469 	if ((svr->svr_registered == B_FALSE) ||
1470 	    (avl_numnodes(&isns_target_list) == 0)) {
1471 		return (0);
1472 	}
1473 
1474 	so = isnst_open_so(&svr->svr_sa);
1475 
1476 	if (so == NULL) {
1477 		return (-1);
1478 	}
1479 
1480 	pdu_size = isnst_make_dereg_pdu(&pdu, node);
1481 	if (pdu_size == 0) {
1482 		isnst_close_so(so);
1483 		return (-1);
1484 	}
1485 
1486 	rc = isnst_send_pdu(so, pdu);
1487 	if (rc != 0) {
1488 		isnst_close_so(so);
1489 		kmem_free(pdu, pdu_size);
1490 		return (rc);
1491 	}
1492 
1493 	rsp_size = isnst_rcv_pdu(so, &rsp);
1494 	if (rsp_size == 0) {
1495 		isnst_close_so(so);
1496 		kmem_free(pdu, pdu_size);
1497 		return (-1);
1498 	}
1499 
1500 	rc = isnst_verify_rsp(pdu, rsp);
1501 
1502 	isnst_close_so(so);
1503 	kmem_free(pdu, pdu_size);
1504 	kmem_free(rsp, rsp_size);
1505 
1506 	return (rc);
1507 }
1508 
1509 static size_t
1510 isnst_make_dereg_pdu(isns_pdu_t **pdu, char *node)
1511 {
1512 	size_t		pdu_size;
1513 	int		len;
1514 	isns_target_t	*itarget;
1515 	iscsit_tgt_t	*target;
1516 	int		num_targets;
1517 
1518 	/*
1519 	 * create DevDereg Message with all of target nodes
1520 	 */
1521 	pdu_size = isnst_create_pdu_header(ISNS_DEV_DEREG, pdu, 0);
1522 	if (pdu_size == 0) {
1523 		return (0);
1524 	}
1525 
1526 	/*
1527 	 * Source attribute - Must be a storage node in the same
1528 	 * network entity.  We'll just grab the first one in the list.
1529 	 * If it's the only online target, we turn this into a total
1530 	 * deregistration regardless of the value of "node".
1531 	 */
1532 
1533 	num_targets = avl_numnodes(&isns_target_list);
1534 	itarget = avl_first(&isns_target_list);
1535 	target = itarget->target;
1536 
1537 	len = strlen(target->target_name) + 1;
1538 	if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1539 	    len, target->target_name, 0) != 0) {
1540 		goto dereg_pdu_error;
1541 	}
1542 
1543 	/* Delimiter */
1544 	if (isnst_add_attr(*pdu, pdu_size, ISNS_DELIMITER_ATTR_ID,
1545 	    0, 0, 0) != 0) {
1546 		goto dereg_pdu_error;
1547 	}
1548 
1549 	/*
1550 	 * Operating attributes
1551 	 */
1552 	if ((node == NULL) || (num_targets == 1)) {
1553 		/* dereg everything */
1554 		len = strlen(isns_eid) + 1;
1555 		if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID,
1556 		    len, isns_eid, 0) != 0) {
1557 			goto dereg_pdu_error;
1558 		}
1559 	} else {
1560 		/* dereg one target only */
1561 		len = strlen(node) + 1;
1562 		if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1563 		    len, node, 0) != 0) {
1564 			goto dereg_pdu_error;
1565 		}
1566 	}
1567 
1568 	return (pdu_size);
1569 
1570 dereg_pdu_error:
1571 	kmem_free(*pdu, pdu_size);
1572 	*pdu = NULL;
1573 
1574 	return (0);
1575 }
1576 
1577 static int
1578 isnst_verify_rsp(isns_pdu_t *pdu, isns_pdu_t *rsp)
1579 {
1580 	uint16_t	func_id;
1581 	uint16_t	payload_len, rsp_payload_len;
1582 	isns_resp_t	*resp;
1583 	uint8_t		*pp;
1584 	isns_tlv_t	*attr;
1585 	uint32_t	attr_len, attr_id, esi_interval;
1586 
1587 	/* validate response function id */
1588 	func_id = ntohs(rsp->func_id);
1589 	switch (ntohs(pdu->func_id)) {
1590 	case ISNS_DEV_ATTR_REG:
1591 		if (func_id != ISNS_DEV_ATTR_REG_RSP) {
1592 			return (-1);
1593 		}
1594 
1595 		/*
1596 		 * Get the ESI interval returned by the server.  It could
1597 		 * be different than what we asked for.  We never know which
1598 		 * portal a request may come in on, and any server could demand
1599 		 * any interval. We'll simply keep track of the largest interval
1600 		 * for use in monitoring.
1601 		 */
1602 
1603 		rsp_payload_len = isnst_pdu_get_op(rsp, &pp);
1604 		attr = (isns_tlv_t *)((void *)pp);
1605 
1606 		while (rsp_payload_len) {
1607 			attr_len = ntohl(attr->attr_len);
1608 			attr_id = ntohl(attr->attr_id);
1609 
1610 			if (attr_id == ISNS_ESI_INTERVAL_ATTR_ID) {
1611 				esi_interval =
1612 				    ntohl(*((uint32_t *)
1613 				    ((void *)(&attr->attr_value))));
1614 
1615 				if (esi_interval > isns_esi_max_interval)
1616 					isns_esi_max_interval = esi_interval;
1617 
1618 				break;
1619 			}
1620 
1621 			rsp_payload_len -= (8 + attr_len);
1622 			attr = (isns_tlv_t *)
1623 			    ((void *)((uint8_t *)attr + attr_len + 8));
1624 		}
1625 
1626 		break;
1627 	case ISNS_DEV_DEREG:
1628 		if (func_id != ISNS_DEV_DEREG_RSP) {
1629 			return (-1);
1630 		}
1631 		break;
1632 	default:
1633 		ASSERT(0);
1634 		break;
1635 	}
1636 
1637 	/* verify response transaction id */
1638 	if (ntohs(rsp->xid) != ntohs(pdu->xid)) {
1639 		return (-1);
1640 	}
1641 
1642 	/* check the error code */
1643 	payload_len = ntohs(rsp->payload_len);
1644 	resp = (isns_resp_t *)((void *)&rsp->payload[0]);
1645 	if (payload_len < 4) {
1646 		return (-1);
1647 	}
1648 
1649 	return (ntohl(resp->status));
1650 }
1651 
1652 static uint16_t
1653 isnst_pdu_get_op(isns_pdu_t *pdu, uint8_t **pp)
1654 {
1655 	uint8_t		*payload;
1656 	uint16_t	payload_len;
1657 	isns_resp_t	*resp;
1658 	isns_tlv_t	*attr;
1659 	uint32_t	attr_id;
1660 	uint32_t	tlv_len;
1661 
1662 	/* get payload */
1663 	payload_len = ntohs(pdu->payload_len);
1664 	resp = (isns_resp_t *)((void *)&pdu->payload[0]);
1665 
1666 	/* find the operating attributes */
1667 	ASSERT(payload_len >= 4);
1668 	payload_len -= 4;
1669 	payload = &resp->data[0];
1670 
1671 	while (payload_len >= 8) {
1672 		attr = (isns_tlv_t *)((void *)payload);
1673 		tlv_len = 8 + ntohl(attr->attr_len);
1674 		if (payload_len >= tlv_len) {
1675 			payload += tlv_len;
1676 			payload_len -= tlv_len;
1677 			attr_id = ntohl(attr->attr_id);
1678 			if (attr_id == ISNS_DELIMITER_ATTR_ID) {
1679 				break;
1680 			}
1681 		} else {
1682 			/* mal-formed packet */
1683 			payload = NULL;
1684 			payload_len = 0;
1685 		}
1686 	}
1687 
1688 	*pp = payload;
1689 
1690 	return (payload_len);
1691 }
1692 
1693 static size_t
1694 isnst_create_pdu_header(uint16_t func_id, isns_pdu_t **pdu, uint16_t flags)
1695 {
1696 	size_t	pdu_size = ISNSP_MAX_PDU_SIZE;
1697 
1698 	*pdu = (isns_pdu_t *)kmem_zalloc(pdu_size, KM_NOSLEEP);
1699 	if (*pdu != NULL) {
1700 		(*pdu)->version = htons((uint16_t)ISNSP_VERSION);
1701 		(*pdu)->func_id = htons((uint16_t)func_id);
1702 		(*pdu)->payload_len = htons(0);
1703 		(*pdu)->flags = htons(flags);
1704 
1705 		(*pdu)->xid = htons(GET_XID());
1706 		(*pdu)->seq = htons(0);
1707 	} else {
1708 		pdu_size = 0;
1709 	}
1710 
1711 	return (pdu_size);
1712 }
1713 
1714 static int
1715 isnst_add_attr(isns_pdu_t *pdu,
1716     size_t max_pdu_size,
1717     uint32_t attr_id,
1718     uint32_t attr_len,
1719     void *attr_data,
1720     uint32_t attr_numeric_data)
1721 {
1722 	isns_tlv_t	*attr_tlv;
1723 	uint8_t		*payload_ptr;
1724 	uint16_t	payload_len;
1725 	uint32_t	normalized_attr_len;
1726 	uint64_t	attr_tlv_len;
1727 
1728 	/* The attribute length must be 4-byte aligned. Section 5.1.3. */
1729 	normalized_attr_len = (attr_len % 4) == 0 ?
1730 	    (attr_len) : (attr_len + (4 - (attr_len % 4)));
1731 	attr_tlv_len = ISNS_TLV_ATTR_ID_LEN +
1732 	    ISNS_TLV_ATTR_LEN_LEN + normalized_attr_len;
1733 
1734 	/* Check if we are going to exceed the maximum PDU length. */
1735 	payload_len = ntohs(pdu->payload_len);
1736 	if ((payload_len + attr_tlv_len) > max_pdu_size) {
1737 		return (1);
1738 	}
1739 
1740 	attr_tlv = (isns_tlv_t *)kmem_zalloc(attr_tlv_len, KM_SLEEP);
1741 
1742 	attr_tlv->attr_id = htonl(attr_id);
1743 
1744 	switch (attr_id) {
1745 	case ISNS_DELIMITER_ATTR_ID:
1746 		break;
1747 
1748 	case ISNS_PORTAL_IP_ADDR_ATTR_ID:
1749 	case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
1750 		if (attr_numeric_data == sizeof (in_addr_t)) {
1751 			/* IPv4 */
1752 			attr_tlv->attr_value[10] = 0xFF;
1753 			attr_tlv->attr_value[11] = 0xFF;
1754 			bcopy(attr_data, ((attr_tlv->attr_value) + 12),
1755 			    sizeof (in_addr_t));
1756 		} else if (attr_numeric_data == sizeof (in6_addr_t)) {
1757 			/* IPv6 */
1758 			bcopy(attr_data, attr_tlv->attr_value,
1759 			    sizeof (in6_addr_t));
1760 		} else if (attr_numeric_data == 0) {
1761 			/* EMPTY */
1762 			/* Do nothing */
1763 		} else {
1764 			kmem_free(attr_tlv, attr_tlv_len);
1765 			attr_tlv = NULL;
1766 			return (1);
1767 		}
1768 		break;
1769 
1770 	case ISNS_EID_ATTR_ID:
1771 	case ISNS_ISCSI_NAME_ATTR_ID:
1772 	case ISNS_ISCSI_ALIAS_ATTR_ID:
1773 	case ISNS_PG_ISCSI_NAME_ATTR_ID:
1774 		if (attr_len && attr_data) {
1775 			bcopy((char *)attr_data,
1776 			    attr_tlv->attr_value, attr_len);
1777 		}
1778 		break;
1779 
1780 	default:
1781 		if (attr_len == 8) {
1782 			*(uint64_t *)((void *)attr_tlv->attr_value) =
1783 			    BE_64((uint64_t)attr_numeric_data);
1784 		} else if (attr_len == 4) {
1785 			*(uint32_t *)((void *)attr_tlv->attr_value) =
1786 			    htonl((uint32_t)attr_numeric_data);
1787 		}
1788 		break;
1789 	}
1790 
1791 	attr_tlv->attr_len = htonl(normalized_attr_len);
1792 	/*
1793 	 * Convert the network byte ordered payload length to host byte
1794 	 * ordered for local address calculation.
1795 	 */
1796 	payload_len = ntohs(pdu->payload_len);
1797 	payload_ptr = pdu->payload + payload_len;
1798 	bcopy(attr_tlv, payload_ptr, attr_tlv_len);
1799 	payload_len += attr_tlv_len;
1800 
1801 	/*
1802 	 * Convert the host byte ordered payload length back to network
1803 	 * byte ordered - it's now ready to be sent on the wire.
1804 	 */
1805 	pdu->payload_len = htons(payload_len);
1806 
1807 	kmem_free(attr_tlv, attr_tlv_len);
1808 	attr_tlv = NULL;
1809 
1810 	return (0);
1811 }
1812 
1813 static int
1814 isnst_send_pdu(void *so, isns_pdu_t *pdu)
1815 {
1816 	size_t		total_len, payload_len, send_len;
1817 	uint8_t		*payload;
1818 	uint16_t	flags, seq;
1819 
1820 	iovec_t		iov[2];
1821 	int		rc;
1822 
1823 	/* update pdu flags */
1824 	flags  = ntohs(pdu->flags);
1825 	flags |= ISNS_FLAG_CLIENT;
1826 	flags |= ISNS_FLAG_FIRST_PDU;
1827 
1828 	/* initalize sequence number */
1829 	seq = 0;
1830 
1831 	payload = pdu->payload;
1832 
1833 	/* total payload length */
1834 	total_len = ntohs(pdu->payload_len);
1835 
1836 	/* fill in the pdu header */
1837 	iov[0].iov_base = (void *)pdu;
1838 	iov[0].iov_len = ISNSP_HEADER_SIZE;
1839 
1840 	do {
1841 		/* split the payload accordingly */
1842 		if (total_len > ISNSP_MAX_PAYLOAD_SIZE) {
1843 			payload_len = ISNSP_MAX_PAYLOAD_SIZE;
1844 		} else {
1845 			payload_len = total_len;
1846 			/* set the last pdu flag */
1847 			flags |= ISNS_FLAG_LAST_PDU;
1848 		}
1849 
1850 		/* set back the pdu flags */
1851 		pdu->flags = htons(flags);
1852 		/* set the sequence number */
1853 		pdu->seq = htons(seq);
1854 		/* set the payload length */
1855 		pdu->payload_len = htons(payload_len);
1856 
1857 		/* fill in the payload */
1858 		iov[1].iov_base = (void *)payload;
1859 		iov[1].iov_len = payload_len;
1860 
1861 		DTRACE_PROBE3(isnst__pdu__send, uint16_t, ntohs(pdu->func_id),
1862 		    uint16_t, ntohs(pdu->payload_len), caddr_t, pdu);
1863 
1864 		/* send the pdu */
1865 		send_len = ISNSP_HEADER_SIZE + payload_len;
1866 		rc = idm_iov_sosend(so, &iov[0], 2, send_len);
1867 
1868 		flags &= ~ISNS_FLAG_FIRST_PDU;
1869 		payload += payload_len;
1870 		total_len -= payload_len;
1871 
1872 		/* increase the sequence number */
1873 		seq ++;
1874 
1875 	} while (rc == 0 && total_len > 0);
1876 
1877 	return (rc);
1878 }
1879 
1880 static size_t
1881 isnst_rcv_pdu(void *so, isns_pdu_t **pdu)
1882 {
1883 	size_t		total_pdu_len;
1884 	size_t		total_payload_len;
1885 	size_t		payload_len;
1886 	size_t		combined_len;
1887 	isns_pdu_t	tmp_pdu_hdr;
1888 	isns_pdu_t	*combined_pdu;
1889 	uint8_t		*payload;
1890 	uint8_t		*combined_payload;
1891 
1892 	uint16_t	flags;
1893 	uint16_t	seq;
1894 
1895 	*pdu = NULL;
1896 	total_pdu_len = total_payload_len = 0;
1897 	payload = NULL;
1898 	seq = 0;
1899 
1900 	do {
1901 		/* receive the pdu header */
1902 		if (idm_sorecv(so, &tmp_pdu_hdr, ISNSP_HEADER_SIZE) != 0 ||
1903 		    ntohs(tmp_pdu_hdr.seq) != seq) {
1904 			goto rcv_error;
1905 		}
1906 
1907 		/* receive the payload */
1908 		payload_len = ntohs(tmp_pdu_hdr.payload_len);
1909 		payload = kmem_alloc(payload_len, KM_SLEEP);
1910 		if (idm_sorecv(so, payload, payload_len) != 0) {
1911 			goto rcv_error;
1912 		}
1913 
1914 		/* combine the pdu if it is not the first one */
1915 		if (total_pdu_len > 0) {
1916 			combined_len = total_pdu_len + payload_len;
1917 			combined_pdu = kmem_alloc(combined_len, KM_SLEEP);
1918 			bcopy(*pdu, combined_pdu, total_pdu_len);
1919 			combined_payload =
1920 			    &combined_pdu->payload[total_payload_len];
1921 			bcopy(payload, combined_payload, payload_len);
1922 			kmem_free(*pdu, total_pdu_len);
1923 			kmem_free(payload, payload_len);
1924 			*pdu = combined_pdu;
1925 			total_payload_len += payload_len;
1926 			total_pdu_len += payload_len;
1927 			(*pdu)->payload_len = htons(total_payload_len);
1928 		} else {
1929 			total_payload_len = payload_len;
1930 			total_pdu_len = ISNSP_HEADER_SIZE + payload_len;
1931 			*pdu = kmem_alloc(total_pdu_len, KM_SLEEP);
1932 			bcopy(&tmp_pdu_hdr, *pdu, ISNSP_HEADER_SIZE);
1933 			bcopy(payload, &(*pdu)->payload[0], payload_len);
1934 			kmem_free(payload, payload_len);
1935 		}
1936 		payload = NULL;
1937 
1938 		/* the flags of pdu which is just received */
1939 		flags = ntohs(tmp_pdu_hdr.flags);
1940 
1941 		/* increase sequence number by one */
1942 		seq ++;
1943 	} while ((flags & ISNS_FLAG_LAST_PDU) == 0);
1944 
1945 	DTRACE_PROBE3(isnst__pdu__recv, uint16_t, ntohs((*pdu)->func_id),
1946 	    size_t, total_payload_len, caddr_t, *pdu);
1947 
1948 	return (total_pdu_len);
1949 
1950 rcv_error:
1951 	if (*pdu != NULL) {
1952 		kmem_free(*pdu, total_pdu_len);
1953 		*pdu = NULL;
1954 	}
1955 	if (payload != NULL) {
1956 		kmem_free(payload, payload_len);
1957 	}
1958 	return (0);
1959 }
1960 
1961 static void *
1962 isnst_open_so(struct sockaddr_storage *sa)
1963 {
1964 	int sa_sz;
1965 	struct sonode *so;
1966 
1967 	/* determin local IP address */
1968 	if (sa->ss_family == AF_INET) {
1969 		/* IPv4 */
1970 		sa_sz = sizeof (struct sockaddr_in);
1971 
1972 		/* Create socket */
1973 		so = idm_socreate(AF_INET, SOCK_STREAM, 0);
1974 	} else {
1975 		/* IPv6 */
1976 		sa_sz = sizeof (struct sockaddr_in6);
1977 
1978 		/* Create socket */
1979 		so = idm_socreate(AF_INET6, SOCK_STREAM, 0);
1980 	}
1981 
1982 	if (so != NULL) {
1983 		if (soconnect(so, (struct sockaddr *)sa, sa_sz, 0, 0) != 0) {
1984 			/* not calling isnst_close_so() to */
1985 			/* make dtrace output look clear */
1986 			idm_soshutdown(so);
1987 			idm_sodestroy(so);
1988 			so = NULL;
1989 		}
1990 	}
1991 
1992 	if (so == NULL) {
1993 		struct sockaddr_in *sin;
1994 		struct sockaddr_in6 *sin6;
1995 		char s[INET6_ADDRSTRLEN];
1996 		void *ip;
1997 		uint16_t port;
1998 		sin = (struct sockaddr_in *)sa;
1999 		port = ntohs(sin->sin_port);
2000 		if (sa->ss_family == AF_INET) {
2001 			ip = (void *)&sin->sin_addr.s_addr;
2002 			(void) inet_ntop(AF_INET, ip, s, sizeof (s));
2003 		} else {
2004 			sin6 = (struct sockaddr_in6 *)sa;
2005 			ip = (void *)&sin6->sin6_addr.s6_addr;
2006 			(void) inet_ntop(AF_INET6, ip, s, sizeof (s));
2007 		}
2008 		cmn_err(CE_WARN, "open iSNS Server %s:%u failed", s, port);
2009 	}
2010 
2011 	return (so);
2012 }
2013 
2014 static void
2015 isnst_close_so(void *so)
2016 {
2017 	idm_soshutdown(so);
2018 	idm_sodestroy(so);
2019 }
2020 
2021 
2022 /*
2023  * ESI handling
2024  */
2025 
2026 static void
2027 isnst_esi_start_thread(isns_esi_tinfo_t *tinfop)
2028 {
2029 	tinfop->esi_thread_running = B_FALSE;
2030 	tinfop->esi_thread_failed = B_FALSE;
2031 	tinfop->esi_registered = B_FALSE;
2032 	tinfop->esi_thread = thread_create(NULL, 0, isnst_esi_thread,
2033 	    (void *)tinfop, 0, &p0, TS_RUN, minclsyspri);
2034 
2035 	mutex_enter(&isns_esi_mutex);
2036 	list_insert_tail(&esi_list, tinfop);
2037 
2038 	/*
2039 	 * Wait for the thread to start
2040 	 */
2041 
2042 	while (!tinfop->esi_thread_running && !tinfop->esi_thread_failed) {
2043 		cv_wait(&isns_esi_cv, &isns_esi_mutex);
2044 	}
2045 
2046 	mutex_exit(&isns_esi_mutex);
2047 }
2048 
2049 static void
2050 isnst_esi_start(isns_portal_list_t *portal)
2051 {
2052 	isns_esi_tinfo_t	*tinfop;
2053 
2054 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
2055 
2056 	/*
2057 	 * Allocate our ESI thread info structure
2058 	 */
2059 
2060 	tinfop = (isns_esi_tinfo_t *)
2061 	    kmem_zalloc(sizeof (isns_esi_tinfo_t), KM_NOSLEEP);
2062 
2063 	if (tinfop == NULL) {
2064 		cmn_err(CE_WARN, "isnst_esi_start: Cant alloc ESI");
2065 		return;
2066 	}
2067 
2068 	tinfop->esi_portal = portal;
2069 	portal->portal_esi = tinfop;
2070 	isnst_esi_start_thread(tinfop);
2071 }
2072 
2073 /*
2074  * isnst_esi_check
2075  *
2076  * Verify that all the ESI threads are running and try to restart any that
2077  * failed for any reason.
2078  */
2079 
2080 static void
2081 isnst_esi_check()
2082 {
2083 	isns_portal_list_t	*portal;
2084 	isns_esi_tinfo_t	*tinfop;
2085 
2086 	/*
2087 	 * Now, threads for new portals or those which stopped for some other
2088 	 * reason will be started.
2089 	 */
2090 
2091 	portal = list_head(&portal_list);
2092 
2093 	while (portal) {
2094 		tinfop = portal->portal_esi;
2095 
2096 		if (tinfop && (!tinfop->esi_thread_running ||
2097 		    tinfop->esi_thread_failed)) {
2098 			isnst_esi_start_thread(tinfop);
2099 		}
2100 
2101 		portal = list_next(&portal_list, portal);
2102 	}
2103 }
2104 
2105 /*
2106  * isnst_esi_thread
2107  *
2108  * This function listens on a socket for incoming connections from an
2109  * iSNS server until told to stop.
2110  */
2111 
2112 static void
2113 isnst_esi_thread(void *arg)
2114 {
2115 	isns_esi_tinfo_t	*tinfop;
2116 	struct sonode		*newso;
2117 	struct sockaddr_in	sin;
2118 	struct sockaddr_in6	sin6;
2119 	uint32_t		on;
2120 	int			rc;
2121 	isns_pdu_t		*pdu;
2122 	size_t			pl_size;
2123 	int			family;
2124 
2125 	tinfop = (isns_esi_tinfo_t *)arg;
2126 	tinfop->esi_thread_did = curthread->t_did;
2127 
2128 	/*
2129 	 * Create a socket to listen for requests from the iSNS server.
2130 	 */
2131 
2132 	if (tinfop->esi_portal->portal_addr.ss_family == AF_INET) {
2133 		family = AF_INET;
2134 	} else {
2135 		family = AF_INET6;
2136 	}
2137 
2138 
2139 	if ((tinfop->esi_so =
2140 	    idm_socreate(family, SOCK_STREAM, 0)) == NULL) {
2141 		cmn_err(CE_WARN,
2142 		    "isnst_esi_thread: Unable to create socket");
2143 		tinfop->esi_thread_failed = B_TRUE;
2144 		mutex_enter(&isns_esi_mutex);
2145 		cv_signal(&isns_esi_cv);
2146 		mutex_exit(&isns_esi_mutex);
2147 		thread_exit();
2148 	}
2149 
2150 	/*
2151 	 * Set options, bind, and listen until we're told to stop
2152 	 */
2153 
2154 	switch (family) {
2155 	case AF_INET:
2156 		bzero(&sin, sizeof (sin));
2157 		sin.sin_family = AF_INET;
2158 		sin.sin_port = htons(0);
2159 		bcopy(((caddr_t)&tinfop->esi_portal->portal_addr +
2160 		    offsetof(struct sockaddr_in, sin_addr)),
2161 		    &sin.sin_addr.s_addr, sizeof (in_addr_t));
2162 		on = 1;
2163 
2164 		(void) sosetsockopt(tinfop->esi_so, SOL_SOCKET, SO_REUSEADDR,
2165 		    (char *)&on, sizeof (on));
2166 
2167 		if (sobind(tinfop->esi_so, (struct sockaddr *)&sin,
2168 		    sizeof (sin), 0, 0) != 0) {
2169 			idm_sodestroy(tinfop->esi_so);
2170 			tinfop->esi_so = NULL;
2171 			tinfop->esi_thread_failed = B_TRUE;
2172 		} else {
2173 			tinfop->esi_port = ntohs(((struct sockaddr_in *)
2174 			    ((void *)tinfop->esi_so->so_laddr_sa))->sin_port);
2175 		}
2176 
2177 		break;
2178 
2179 	case AF_INET6:
2180 		bzero(&sin6, sizeof (sin6));
2181 		sin6.sin6_family = AF_INET6;
2182 		sin6.sin6_port = htons(0);
2183 		bcopy(((caddr_t)&tinfop->esi_portal->portal_addr +
2184 		    offsetof(struct sockaddr_in6, sin6_addr)),
2185 		    &sin6.sin6_addr.s6_addr, sizeof (in6_addr_t));
2186 		on = 1;
2187 
2188 		(void) sosetsockopt(tinfop->esi_so, SOL_SOCKET,
2189 		    SO_REUSEADDR, (char *)&on, sizeof (on));
2190 
2191 		if (sobind(tinfop->esi_so, (struct sockaddr *)&sin6,
2192 		    sizeof (sin6), 0, 0) != 0) {
2193 			idm_sodestroy(tinfop->esi_so);
2194 			tinfop->esi_so = NULL;
2195 			tinfop->esi_thread_failed = B_TRUE;
2196 		} else {
2197 			tinfop->esi_port = ntohs(((struct sockaddr_in6 *)
2198 			    ((void *)tinfop->esi_so->so_laddr_sa))->sin6_port);
2199 		}
2200 
2201 		break;
2202 	}
2203 
2204 	if (tinfop->esi_thread_failed) {
2205 		cmn_err(CE_WARN, "Unable to bind socket for ESI");
2206 		goto esi_thread_exit;
2207 	}
2208 
2209 	if ((rc = solisten(tinfop->esi_so, 5)) != 0) {
2210 		cmn_err(CE_WARN, "isnst_esi_thread: listen failure 0x%x", rc);
2211 		goto esi_thread_exit;
2212 	}
2213 
2214 	mutex_enter(&isns_esi_mutex);
2215 	/*
2216 	 * Mark the thread as running and the portal as no longer new.
2217 	 */
2218 	tinfop->esi_thread_running = B_TRUE;
2219 	cv_signal(&isns_esi_cv);
2220 
2221 	while (tinfop->esi_thread_running && !tinfop->esi_thread_failed) {
2222 		mutex_exit(&isns_esi_mutex);
2223 
2224 		if ((rc = soaccept(tinfop->esi_so, 0, &newso)) != 0) {
2225 			mutex_enter(&isns_esi_mutex);
2226 			/*
2227 			 * If we were interrupted with EINTR, it's not
2228 			 * really a failure.
2229 			 */
2230 			if (rc != EINTR) {
2231 				cmn_err(CE_WARN, "isnst_esi_thread: "
2232 				    "accept failure (0x%x)", rc);
2233 				tinfop->esi_thread_failed = B_TRUE;
2234 			}
2235 
2236 			tinfop->esi_thread_running = B_FALSE;
2237 			continue;
2238 		}
2239 
2240 		mutex_enter(&isns_esi_mutex);
2241 
2242 		pl_size = isnst_rcv_pdu(newso, &pdu);
2243 
2244 		if (pl_size == 0) {
2245 			cmn_err(CE_WARN, "isnst_esi_thread: rcv_pdu failure");
2246 			tinfop->esi_thread_failed = B_TRUE;
2247 			continue;
2248 		}
2249 
2250 		if (isnst_handle_esi_req(newso, pdu, pl_size) == B_TRUE) {
2251 			tinfop->esi_registered = B_TRUE;
2252 		}
2253 
2254 		(void) soshutdown(newso, SHUT_RDWR);
2255 
2256 		/*
2257 		 * Do not hold the esi mutex during server timestamp
2258 		 * update.  It requires the isns global lock, which may
2259 		 * be held during other functions that also require
2260 		 * the esi_mutex (potential deadlock).
2261 		 */
2262 		mutex_exit(&isns_esi_mutex);
2263 		isnst_update_server_timestamp(newso);
2264 		mutex_enter(&isns_esi_mutex);
2265 	}
2266 	mutex_exit(&isns_esi_mutex);
2267 esi_thread_exit:
2268 	idm_soshutdown(tinfop->esi_so);
2269 	idm_sodestroy(tinfop->esi_so);
2270 	mutex_enter(&isns_esi_mutex);
2271 	tinfop->esi_thread_running = B_FALSE;
2272 	tinfop->esi_so = NULL;
2273 	tinfop->esi_port = 0;
2274 	tinfop->esi_registered = B_FALSE;
2275 	cv_signal(&isns_esi_cv);
2276 	mutex_exit(&isns_esi_mutex);
2277 	thread_exit();
2278 }
2279 
2280 /*
2281  * Handle an incoming ESI request
2282  */
2283 
2284 static boolean_t
2285 isnst_handle_esi_req(struct sonode *so, isns_pdu_t *pdu, size_t pl_size)
2286 {
2287 	isns_pdu_t	*rsp_pdu;
2288 	isns_resp_t	*rsp;
2289 	size_t		pl_len, rsp_size;
2290 	boolean_t	esirv = B_TRUE;
2291 
2292 	if (ntohs(pdu->func_id) != ISNS_ESI) {
2293 		cmn_err(CE_WARN, "isnst_handle_esi_req: Unexpected func 0x%x",
2294 		    pdu->func_id);
2295 		kmem_free(pdu, pl_size);
2296 		return (B_FALSE);
2297 	}
2298 
2299 	pl_len = ntohs(pdu->payload_len) + 4 /* ISNS_STATUS_SZ */;
2300 
2301 	if (pl_len > ISNSP_MAX_PAYLOAD_SIZE) {
2302 		cmn_err(CE_WARN, "isnst_handle_esi_req: PDU payload too large "
2303 		    " (%ld bytes)", pl_len);
2304 		kmem_free(pdu, pl_size);
2305 		return (B_FALSE);
2306 	}
2307 
2308 	rsp_size = isnst_create_pdu_header(ISNS_ESI_RSP, &rsp_pdu, 0);
2309 
2310 	if (rsp_size == 0) {
2311 		cmn_err(CE_WARN, "isnst_handle_esi_req: Can't get rsp pdu");
2312 		kmem_free(pdu, pl_size);
2313 		return (B_FALSE);
2314 	}
2315 
2316 	rsp = (isns_resp_t *)((void *)(&rsp_pdu->payload[0]));
2317 
2318 	/* Use xid from the request pdu */
2319 	rsp_pdu->xid = pdu->xid;
2320 	rsp->status = htonl(ISNS_RSP_SUCCESSFUL);
2321 
2322 	/* Copy original data */
2323 	bcopy(pdu->payload, rsp->data, pl_len - 4);
2324 	rsp_pdu->payload_len = htons(pl_len);
2325 
2326 	if (isnst_send_pdu(so, rsp_pdu) != 0) {
2327 		cmn_err(CE_WARN, "isnst_handle_esi_req: Send response failed");
2328 		esirv = B_FALSE;
2329 	}
2330 
2331 	kmem_free(rsp_pdu, rsp_size);
2332 	kmem_free(pdu, pl_size);
2333 
2334 	return (esirv);
2335 }
2336 
2337 int
2338 isnst_tgt_avl_compare(const void *t1, const void *t2)
2339 {
2340 	const isns_target_t	*tgt1 = t1;
2341 	const isns_target_t	*tgt2 = t2;
2342 
2343 	/*
2344 	 * Sort by target (pointer to iscsit_tgt_t).
2345 	 */
2346 
2347 	if (tgt1->target < tgt2->target) {
2348 		return (-1);
2349 	} else if (tgt1->target > tgt2->target) {
2350 		return (1);
2351 	}
2352 
2353 	return (0);
2354 }
2355 
2356 static void
2357 isnst_get_target_list(void)
2358 {
2359 	iscsit_tgt_t	*tgt, *next_tgt;
2360 
2361 	/*
2362 	 * Initialize our list of targets with those from the global
2363 	 * list that are online.
2364 	 */
2365 
2366 	for (tgt = avl_first(&iscsit_global.global_target_list); tgt != NULL;
2367 	    tgt = next_tgt) {
2368 		next_tgt = AVL_NEXT(&iscsit_global.global_target_list, tgt);
2369 		if (tgt->target_state == TS_STMF_ONLINE) {
2370 			(void) isnst_add_to_target_list(tgt);
2371 		}
2372 	}
2373 }
2374 
2375 static void
2376 isnst_set_server_status(iscsit_isns_svr_t *svr, boolean_t registered)
2377 {
2378 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
2379 
2380 	if (registered == B_TRUE) {
2381 		svr->svr_registered = B_TRUE;
2382 		svr->svr_last_msg = ddi_get_lbolt();
2383 	} else {
2384 		svr->svr_registered = B_FALSE;
2385 	}
2386 }
2387 
2388 static void
2389 isnst_add_default_portals()
2390 {
2391 	idm_addr_list_t		*default_portal_list;
2392 	idm_addr_t		*dportal;
2393 	isns_portal_list_t	*portal;
2394 	struct sockaddr_in	*sin;
2395 	struct sockaddr_in6	*sin6;
2396 	uint32_t		dpl_size, idx;
2397 
2398 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
2399 
2400 	dpl_size = idm_get_ipaddr(&default_portal_list);
2401 
2402 	if (dpl_size == 0) {
2403 		cmn_err(CE_WARN, "isnst_add_default_portals: "
2404 		    "No default portals");
2405 		return;
2406 	}
2407 
2408 	for (idx = 0; idx < default_portal_list->al_out_cnt; idx++) {
2409 		dportal = &default_portal_list->al_addrs[idx];
2410 
2411 		if (dportal->a_addr.i_insize == 0) {
2412 			continue;
2413 		}
2414 
2415 		portal = kmem_zalloc(sizeof (isns_portal_list_t), KM_SLEEP);
2416 		portal->portal_iscsit = NULL;	/* Default portal */
2417 
2418 		if (dportal->a_addr.i_insize == sizeof (struct in_addr)) {
2419 			sin = (struct sockaddr_in *)&portal->portal_addr;
2420 			sin->sin_family = AF_INET;
2421 			sin->sin_port = htons(ISCSI_LISTEN_PORT);
2422 			sin->sin_addr = dportal->a_addr.i_addr.in4;
2423 		} else {
2424 			sin6 = (struct sockaddr_in6 *)&portal->portal_addr;
2425 			sin->sin_family = AF_INET6;
2426 			sin6->sin6_port = htons(ISCSI_LISTEN_PORT);
2427 			sin6->sin6_addr = dportal->a_addr.i_addr.in6;
2428 		}
2429 
2430 		list_insert_tail(&portal_list, portal);
2431 		isnst_esi_start(portal);
2432 	}
2433 
2434 	kmem_free(default_portal_list, dpl_size);
2435 }
2436 
2437 static void
2438 isnst_remove_default_portals()
2439 {
2440 	isns_portal_list_t	*portal, *next;
2441 
2442 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
2443 
2444 	portal = list_head(&portal_list);
2445 
2446 	while (portal) {
2447 		next = list_next(&portal_list, portal);
2448 
2449 		if (portal->portal_iscsit == NULL) {
2450 			mutex_enter(&isns_esi_mutex);
2451 			isnst_esi_stop_thread(portal->portal_esi);
2452 			mutex_exit(&isns_esi_mutex);
2453 			isns_remove_portal(portal);
2454 		}
2455 
2456 		portal = next;
2457 	}
2458 }
2459 
2460 /*
2461  * These functions are called by iscsit proper when a portal comes online
2462  * or goes offline.
2463  */
2464 
2465 void
2466 iscsit_isns_portal_online(iscsit_portal_t *portal)
2467 {
2468 	isns_portal_list_t	*iportal, *new_portal;
2469 	struct sockaddr_in	*sin;
2470 
2471 	ISNS_GLOBAL_LOCK();
2472 
2473 	iportal = isns_lookup_portal(&portal->portal_addr);
2474 	sin = (struct sockaddr_in *)&portal->portal_addr;
2475 
2476 	/*
2477 	 * If sin_family is 0, it's a "default" portal.  It's possible
2478 	 * sin_family may be non-zero, so check portal_iscsit.  If it's NULL,
2479 	 * it's a default portal as well.
2480 	 */
2481 
2482 	if ((sin->sin_family == 0) ||
2483 	    (iportal && (iportal->portal_iscsit == NULL))) {
2484 		ISNS_GLOBAL_UNLOCK();
2485 		return;
2486 	}
2487 
2488 	ASSERT(iportal == NULL);
2489 
2490 	new_portal = kmem_zalloc(sizeof (isns_portal_list_t), KM_SLEEP);
2491 	new_portal->portal_addr = portal->portal_addr;
2492 	sin = (struct sockaddr_in *)&new_portal->portal_addr;
2493 	new_portal->portal_iscsit = portal;
2494 	list_insert_tail(&portal_list, new_portal);
2495 	portal_list_count++;
2496 	nondefault_portals++;
2497 
2498 	ISNS_GLOBAL_UNLOCK();
2499 }
2500 
2501 void
2502 iscsit_isns_portal_offline(iscsit_portal_t *portal)
2503 {
2504 	isns_portal_list_t	*iportal = NULL;
2505 	struct sockaddr_in	*sin;
2506 	boolean_t		default_portals = B_FALSE;
2507 
2508 	ISNS_GLOBAL_LOCK();
2509 
2510 	/*
2511 	 * Stop the ESI thread for this portal
2512 	 */
2513 
2514 	iportal = isns_lookup_portal(&portal->portal_addr);
2515 	sin = (struct sockaddr_in *)&portal->portal_addr;
2516 
2517 	if ((sin->sin_family == 0) ||
2518 	    (iportal && (iportal->portal_iscsit == NULL))) {
2519 		default_portals = B_TRUE;
2520 	} else {
2521 		iportal = isns_lookup_portal(&portal->portal_addr);
2522 		ASSERT(iportal);
2523 	}
2524 
2525 	if (!default_portals) {
2526 		isns_remove_portal(iportal);
2527 		nondefault_portals--;
2528 	}
2529 
2530 	ISNS_GLOBAL_UNLOCK();
2531 }
2532