xref: /illumos-gate/usr/src/cmd/isns/isnsd/scn.c (revision 9b40c3052b9b0d91120c568df0c5211c131c8da1)
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 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 
32 #include "isns_server.h"
33 #include "isns_msgq.h"
34 #include "isns_cache.h"
35 #include "isns_cfg.h"
36 #include "isns_obj.h"
37 #include "isns_dseng.h"
38 #include "isns_log.h"
39 #include "isns_scn.h"
40 #include "isns_pdu.h"
41 
42 /*
43  * global variables.
44  */
45 
46 /*
47  * local variables.
48  */
49 static scn_registry_t *scn_registry = NULL;
50 static int scn_dispatched = 0;
51 
52 /*
53  * external variables.
54  */
55 extern uint8_t mgmt_scn;
56 extern msg_queue_t *sys_q;
57 extern msg_queue_t *scn_q;
58 extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE];
59 
60 #ifdef DEBUG
61 extern void dump_pdu1(isns_pdu_t *);
62 #endif
63 
64 static int sf_gen(scn_raw_t *);
65 static int sf_error(scn_raw_t *);
66 
67 static scn_raw_t *make_raw_entity(isns_obj_t *);
68 static scn_raw_t *make_raw_iscsi(isns_obj_t *);
69 static scn_raw_t *make_raw_portal(isns_obj_t *);
70 static scn_raw_t *make_raw_assoc_iscsi(isns_obj_t *);
71 static scn_raw_t *make_raw_assoc_dd(isns_obj_t *);
72 static scn_raw_t *(*const make_raw[MAX_OBJ_TYPE_FOR_SIZE])(isns_obj_t *) = {
73 	NULL,
74 	&make_raw_entity,
75 	&make_raw_iscsi,
76 	&make_raw_portal,
77 	NULL,			/* OBJ_PG */
78 	NULL,			/* OBJ_DD */
79 	NULL,			/* OBJ_DDS */
80 	NULL,			/* MAX_OBJ_TYPE */
81 	NULL,			/* OBJ_DUMMY1 */
82 	NULL,			/* OBJ_DUMMY2 */
83 	NULL,			/* OBJ_DUMMY3 */
84 	NULL,			/* OBJ_DUMMY4 */
85 	&make_raw_assoc_iscsi,
86 	&make_raw_assoc_dd
87 };
88 
89 static scn_text_t *scn_gen_entity(scn_raw_t *);
90 static scn_text_t *scn_gen_iscsi(scn_raw_t *);
91 static scn_text_t *scn_gen_portal(scn_raw_t *);
92 static scn_text_t *scn_gen_assoc_dd(scn_raw_t *);
93 static scn_text_t *(*const scn_gen[MAX_OBJ_TYPE_FOR_SIZE])(scn_raw_t *) = {
94 	NULL,
95 	&scn_gen_entity,
96 	&scn_gen_iscsi,
97 	&scn_gen_portal,
98 	NULL,			/* OBJ_PG */
99 	NULL,			/* OBJ_DD */
100 	NULL,			/* OBJ_DDS */
101 	NULL,			/* MAX_OBJ_TYPE */
102 	NULL,			/* OBJ_DUMMY1 */
103 	NULL,			/* OBJ_DUMMY2 */
104 	NULL,			/* OBJ_DUMMY3 */
105 	NULL,			/* OBJ_DUMMY4 */
106 	&scn_gen_iscsi,
107 	&scn_gen_assoc_dd
108 };
109 
110 #define	SCN_TEST(E, BITMAP, UID1, UID2, NT) \
111 	(((E) & (BITMAP)) && \
112 	(!((BITMAP) & (ISNS_INIT_SELF_INFO_ONLY | \
113 			ISNS_TARGET_SELF_INFO_ONLY)) || \
114 		((UID1) == (UID2)) || \
115 		(((BITMAP) & ISNS_INIT_SELF_INFO_ONLY) && \
116 			((NT) & ISNS_INITIATOR_NODE_TYPE)) || \
117 		(((BITMAP) & ISNS_TARGET_SELF_INFO_ONLY) && \
118 			((NT) & ISNS_TARGET_NODE_TYPE))))
119 
120 /*
121  * local functions.
122  */
123 
124 /*
125  * ****************************************************************************
126  *
127  * free_portal_1:
128  *	Free one SCN portal or decrease the reference count if the portal
129  *	is referenced by other SCN entry(s).
130  *
131  * p	- the portal.
132  *
133  * ****************************************************************************
134  */
135 static void
136 free_portal_1(
137 	scn_portal_t *p
138 )
139 {
140 	if (p->ref <= 1) {
141 		if (p->sz == sizeof (in6_addr_t)) {
142 			free(p->ip.in6);
143 		}
144 		free(p);
145 	} else {
146 		p->ref --;
147 	}
148 }
149 
150 /*
151  * ****************************************************************************
152  *
153  * free_portal:
154  *	Free the unused portals, which are extracted for new SCN entry,
155  *	after the new SCN entry is added.
156  *
157  * p	- the portal.
158  *
159  * ****************************************************************************
160  */
161 static void
162 free_portal(
163 	scn_portal_t *p
164 )
165 {
166 	scn_portal_t *n;
167 
168 	while (p != NULL) {
169 		n = p->next;
170 		free_portal_1(p);
171 		p = n;
172 	}
173 }
174 
175 /*
176  * ****************************************************************************
177  *
178  * free_portal_list:
179  *	Free the list of portals while a SCN entry is being destroyed.
180  *
181  * l	- the portal list.
182  *
183  * ****************************************************************************
184  */
185 static void
186 free_portal_list(
187 	scn_list_t *l
188 )
189 {
190 	scn_list_t *n;
191 	scn_portal_t *p;
192 
193 	while (l != NULL) {
194 		n = l->next;
195 		p = l->data.portal;
196 		free_portal_1(p);
197 		free(l);
198 		l = n;
199 	}
200 }
201 
202 /*
203  * ****************************************************************************
204  *
205  * free_scn_text:
206  *	Free one SCN or decrease the ref count after the SCN is emitted.
207  *
208  * text	- the SCN.
209  *
210  * ****************************************************************************
211  */
212 static void
213 free_scn_text(
214 	scn_text_t *text
215 )
216 {
217 	if (text->ref <= 1) {
218 		free(text->iscsi);
219 		free(text);
220 	} else {
221 		text->ref --;
222 	}
223 }
224 
225 /*
226  * ****************************************************************************
227  *
228  * free_scn_list:
229  *	Free the the list of SCN.
230  *
231  * scn	- the list.
232  *
233  * ****************************************************************************
234  */
235 static void
236 free_scn_list(
237 	scn_t *scn
238 )
239 {
240 	scn_t *next_scn;
241 	scn_list_t *list;
242 	scn_list_t *next_list;
243 
244 	while (scn != NULL) {
245 		next_scn = scn->next;
246 		list = scn->data.list;
247 		while (list != NULL) {
248 			next_list = list->next;
249 			free_scn_text(list->data.text);
250 			free(list);
251 			list = next_list;
252 		}
253 		free(scn);
254 		scn = next_scn;
255 	}
256 }
257 
258 /*
259  * ****************************************************************************
260  *
261  * free_scn:
262  *	Free all of SCNs which are dispatched to every entry.
263  *
264  * ****************************************************************************
265  */
266 static void
267 free_scn(
268 )
269 {
270 	scn_registry_t *p;
271 
272 	p = scn_registry;
273 
274 	while (p != NULL) {
275 		free_scn_list(p->scn);
276 		p->scn = NULL;
277 		p = p->next;
278 	}
279 }
280 
281 /*
282  * ****************************************************************************
283  *
284  * free_entry:
285  *	Free one SCN entry.
286  *
287  * e	- the SCN entry.
288  *
289  * ****************************************************************************
290  */
291 static void
292 free_entry(
293 	scn_registry_t *e
294 )
295 {
296 	free_scn_list(e->scn);
297 	free_portal_list(e->portal.l);
298 	free(e->name);
299 	free(e);
300 }
301 
302 /*
303  * ****************************************************************************
304  *
305  * free_raw:
306  *	Free the raw data after the SCN is generated from it.
307  *
308  * raw	- the raw SCN data.
309  *
310  * ****************************************************************************
311  */
312 static void
313 free_raw(
314 	scn_raw_t *raw
315 )
316 {
317 	if (raw->ref == 0) {
318 		free(raw->iscsi);
319 	}
320 	if (raw->ip != NULL) {
321 		free(raw->ip);
322 	}
323 	free(raw);
324 }
325 
326 /*
327  * ****************************************************************************
328  *
329  * scn_add_portal:
330  *	Add portals to the portal list of a SCN entry.
331  *
332  * e	- the SCN entry.
333  * p	- the portals.
334  * return - 0: successful, otherwise failed.
335  *
336  * ****************************************************************************
337  */
338 static int
339 scn_add_portal(
340 	scn_registry_t *e,
341 	scn_portal_t *p
342 )
343 {
344 	scn_portal_t *x;
345 	scn_list_t *l, *m;
346 
347 	scn_list_t **lp;
348 
349 	int found_it;
350 
351 	lp = &e->portal.l;
352 	while (p != NULL) {
353 		m = (scn_list_t *)malloc(sizeof (scn_list_t));
354 		if (m == NULL) {
355 			return (1);
356 		}
357 		found_it = 0;
358 		e = scn_registry;
359 		while (e && !found_it) {
360 			l = e->portal.l;
361 			while (l && !found_it) {
362 				x = l->data.portal;
363 				if (x->uid == p->uid) {
364 					found_it = 1;
365 				}
366 				l = l->next;
367 			}
368 			e = e->next;
369 		}
370 
371 		if (!found_it) {
372 			x = p;
373 		}
374 		m->data.portal = x;
375 		x->ref ++;
376 		m->next = *lp;
377 		*lp = m;
378 
379 		p = p->next;
380 	}
381 
382 	return (0);
383 }
384 
385 /*
386  * ****************************************************************************
387  *
388  * scn_remove_portal:
389  *	Remove a portal from the portal list of every SCN entry.
390  *
391  * uid	- the portal object uid.
392  * return - always successful (0).
393  *
394  * ****************************************************************************
395  */
396 static int
397 scn_remove_portal(
398 	uint32_t uid
399 )
400 {
401 	scn_registry_t **ep, *e;
402 
403 	scn_portal_t *x;
404 	scn_list_t **lp, *l;
405 
406 	ep = &scn_registry;
407 	e = *ep;
408 
409 	while (e != NULL) {
410 		lp = &e->portal.l;
411 		l = *lp;
412 		while (l != NULL) {
413 			x = l->data.portal;
414 			if (x->uid == uid) {
415 				/* remove it */
416 				*lp = l->next;
417 				free_portal_1(x);
418 				free(l);
419 			} else {
420 				lp = &l->next;
421 			}
422 			l = *lp;
423 		}
424 
425 		if (e->portal.l == NULL) {
426 			/* no portal for this entry, destroy it */
427 			*ep = e->next;
428 			free_entry(e);
429 		} else {
430 			ep = &e->next;
431 		}
432 		e = *ep;
433 	}
434 
435 	return (0);
436 }
437 
438 /*
439  * ****************************************************************************
440  *
441  * scn_list_add:
442  *	Add one SCN entry to the SCN entry list.
443  *
444  * e	- the SCN entry.
445  * return - always successful (0).
446  *
447  * ****************************************************************************
448  */
449 static int
450 scn_list_add(
451 	scn_registry_t *e
452 )
453 {
454 	scn_registry_t **pp;
455 	scn_portal_t *p;
456 
457 	p = e->portal.p;
458 	e->portal.l = NULL;
459 
460 	pp = &scn_registry;
461 	while (*pp) {
462 		if ((*pp)->uid == e->uid) {
463 			/* replace the bitmap */
464 			(*pp)->bitmap = e->bitmap;
465 			free_portal(p);
466 			free_entry(e);
467 			return (0);
468 		} else if ((*pp)->uid < e->uid) {
469 			break;
470 		}
471 		pp = &(*pp)->next;
472 	}
473 
474 	(void) scn_add_portal(e, p);
475 
476 	if (e->portal.l != NULL || sys_q == NULL) {
477 		/* insert it to the list */
478 		e->next = *pp;
479 		*pp = e;
480 	} else {
481 		/* no portal, ignore it */
482 		free_entry(e);
483 	}
484 
485 	/* free the unused portal(s) */
486 	free_portal(p);
487 
488 	return (0);
489 }
490 
491 /*
492  * ****************************************************************************
493  *
494  * scn_list_remove:
495  *	Remove one SCN entry from the SCN entry list.
496  *
497  * uid	- the SCN entry unique ID.
498  * return - always successful (0).
499  *
500  * ****************************************************************************
501  */
502 static int
503 scn_list_remove(
504 	uint32_t uid
505 )
506 {
507 	scn_registry_t **ep, *e;
508 
509 	ep = &scn_registry;
510 	e = *ep;
511 	while (e) {
512 		if (e->uid == uid) {
513 			/* destroy it */
514 			*ep = e->next;
515 			free_entry(e);
516 			break;
517 		} else if (e->uid < uid) {
518 			break;
519 		}
520 		ep = &e->next;
521 		e = *ep;
522 	}
523 
524 	return (0);
525 }
526 
527 /*
528  * ****************************************************************************
529  *
530  * cb_get_scn_port:
531  *	The callback function which returns the SCN port of a portal object.
532  *
533  * p1	- the portal object.
534  * p2	- the lookup control data.
535  * return - the SCN port number.
536  *
537  * ****************************************************************************
538  */
539 static int
540 cb_get_scn_port(
541 	void *p1,
542 	/*ARGSUSED*/
543 	void *p2
544 )
545 {
546 	isns_obj_t *obj = (isns_obj_t *)p1;
547 
548 	isns_attr_t *attr = &obj->attrs[
549 	    ATTR_INDEX_PORTAL(ISNS_SCN_PORT_ATTR_ID)];
550 
551 	int port = 0;
552 
553 	if (attr->tag != 0 && attr->value.ui != 0) {
554 		port = (int)attr->value.ui;
555 	}
556 
557 	return (port);
558 }
559 
560 /*
561  * ****************************************************************************
562  *
563  * new_scn_portal:
564  *	Make a new SCN portal.
565  *
566  * ref	- the ref count.
567  * uid	- the portal object UID.
568  * ip	- the ip address.
569  * port	- the port number.
570  * return - the SCN portal.
571  *
572  * ****************************************************************************
573  */
574 static scn_portal_t *
575 new_scn_portal(
576 	uint32_t ref,
577 	uint32_t uid,
578 	in6_addr_t *ip,
579 	uint32_t port
580 )
581 {
582 	scn_portal_t *p;
583 
584 	p = (scn_portal_t *)malloc(sizeof (scn_portal_t));
585 	if (p != NULL) {
586 		p->uid = uid;
587 		/* convert the ipv6 to ipv4 */
588 		if (((int *)ip)[0] == 0x00 &&
589 		    ((int *)ip)[1] == 0x00 &&
590 		    ((uchar_t *)ip)[8] == 0x00 &&
591 		    ((uchar_t *)ip)[9] == 0x00 &&
592 		    ((uchar_t *)ip)[10] == 0xFF &&
593 		    ((uchar_t *)ip)[11] == 0xFF) {
594 			p->sz = sizeof (in_addr_t);
595 			p->ip.in = ((uint32_t *)ip)[3];
596 			free(ip);
597 		} else {
598 			p->sz = sizeof (in6_addr_t);
599 			p->ip.in6 = ip;
600 		}
601 		p->port = port;
602 		p->ref = ref;
603 		p->so = 0;
604 		p->next = NULL;
605 	}
606 
607 	return (p);
608 }
609 
610 /*
611  * ****************************************************************************
612  *
613  * extract scn_portal:
614  *	Extract the SCN portal(s) for a storage node.
615  *
616  * name	- the storage node name.
617  * return - the SCN portal list.
618  *
619  * ****************************************************************************
620  */
621 static scn_portal_t *
622 extract_scn_portal(
623 	uchar_t *name
624 )
625 {
626 	scn_portal_t *list = NULL;
627 	scn_portal_t *p;
628 
629 	lookup_ctrl_t lc_pg, lc_p;
630 	uint32_t pg_uid, uid;
631 
632 	in6_addr_t *ip;
633 	uint32_t port;
634 
635 	lc_pg.type = OBJ_PG;
636 	lc_pg.curr_uid = 0;
637 	lc_pg.id[0] = ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID);
638 	lc_pg.op[0] = OP_STRING;
639 	lc_pg.data[0].ptr = name;
640 	lc_pg.op[1] = 0;
641 
642 	lc_pg.id[1] = ISNS_PG_PORTAL_IP_ADDR_ATTR_ID;
643 	lc_pg.id[2] = ISNS_PG_PORTAL_PORT_ATTR_ID;
644 
645 	lc_p.type = OBJ_PORTAL;
646 	lc_p.curr_uid = 0;
647 	lc_p.id[0] = ATTR_INDEX_PORTAL(ISNS_PORTAL_IP_ADDR_ATTR_ID);
648 	lc_p.op[0] = OP_MEMORY_IP6;
649 	lc_p.id[1] = ATTR_INDEX_PORTAL(ISNS_PORTAL_PORT_ATTR_ID);
650 	lc_p.op[1] = OP_INTEGER;
651 	lc_p.op[2] = 0;
652 
653 	while (cache_lookup(&lc_pg, &pg_uid, cb_clone_attrs) == 0 &&
654 	    pg_uid != 0) {
655 		ip = lc_pg.data[1].ip;
656 		port = lc_pg.data[2].ui;
657 		if (ip != NULL) {
658 			lc_p.data[0].ip = ip;
659 			lc_p.data[1].ui = port;
660 			port = cache_lookup(&lc_p, &uid, cb_get_scn_port);
661 			if (port != 0 && uid != 0) {
662 				/* ref starts from 1 */
663 				p = new_scn_portal(1, uid, ip, port);
664 				if (p != NULL) {
665 					p->next = list;
666 					list = p;
667 				} else {
668 					free(ip);
669 					free(p);
670 				}
671 			} else {
672 				/* portal not registered or no scn port */
673 				free(ip);
674 			}
675 		}
676 		lc_pg.curr_uid = pg_uid;
677 	}
678 
679 	return (list);
680 }
681 
682 /*
683  * ****************************************************************************
684  *
685  * cb_update_scn_bitmap:
686  *	The callback function which updates the SCN Bitmap attribute of
687  *	a storage node object.
688  *
689  * p1	- the storage node object.
690  * p2	- the lookup control data.
691  * return - error code.
692  *
693  * ****************************************************************************
694  */
695 static int
696 cb_update_scn_bitmap(
697 	void *p1,
698 	void *p2
699 )
700 {
701 	int ec = 0;
702 
703 	isns_obj_t *obj = (isns_obj_t *)p1;
704 	lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2;
705 
706 	int id = ATTR_INDEX_ISCSI(ISNS_ISCSI_SCN_BITMAP_ATTR_ID);
707 	isns_attr_t *attr = &obj->attrs[id];
708 
709 	uint32_t bitmap = lcp->data[2].ui;
710 
711 	if (bitmap != 0) {
712 		attr->tag = ISNS_ISCSI_SCN_BITMAP_ATTR_ID;
713 		attr->len = 4;
714 	} else if (attr->tag == 0) {
715 		return (ec);
716 	} else {
717 		attr->tag = 0;
718 		attr->len = 0;
719 	}
720 	attr->value.ui = bitmap;
721 
722 	if (sys_q != NULL) {
723 		ec = write_data(DATA_UPDATE, obj);
724 	}
725 
726 	return (ec);
727 }
728 
729 /*
730  * ****************************************************************************
731  *
732  * cb_get_node_type:
733  *	The callback function which returns the node type attribute of
734  *	a storage node object.
735  *
736  * p1	- the storage node object.
737  * p2	- the lookup control data.
738  * return - error code.
739  *
740  * ****************************************************************************
741  */
742 static int
743 cb_get_node_type(
744 	void *p1,
745 	/* LINTED E_FUNC_ARG_UNUSED */
746 	void *p2
747 )
748 {
749 	isns_obj_t *obj = (isns_obj_t *)p1;
750 	isns_attr_t *attr = &obj->attrs[
751 	    ATTR_INDEX_ISCSI(ISNS_ISCSI_NODE_TYPE_ATTR_ID)];
752 	int nt = (int)attr->value.ui;
753 
754 	return (nt);
755 }
756 
757 /*
758  * ****************************************************************************
759  *
760  * cb_get_node_type:
761  *	The callback function which returns the storage node object UID
762  *	from a portal group object.
763  *
764  * p1	- the pg object.
765  * p2	- the lookup control data.
766  * return - the storage node object UID.
767  *
768  * ****************************************************************************
769  */
770 static int
771 cb_pg_node(
772 	void *p1,
773 	/* LINTED E_FUNC_ARG_UNUSED */
774 	void *p2
775 )
776 {
777 	uint32_t ref;
778 
779 	ref = get_ref_t(p1, OBJ_ISCSI);
780 
781 	return ((int)ref);
782 }
783 
784 /*
785  * ****************************************************************************
786  *
787  * make_raw_entity:
788  *	Make raw SCN data with a Network Entity object.
789  *
790  * obj	- the network entity object.
791  * return - the raw SCN data.
792  *
793  * ****************************************************************************
794  */
795 static scn_raw_t *
796 make_raw_entity(
797 	/*ARGSUSED*/
798 	isns_obj_t *obj
799 )
800 {
801 	scn_raw_t *raw;
802 
803 	raw = (scn_raw_t *)malloc(sizeof (scn_raw_t));
804 	if (raw != NULL) {
805 		raw->type = obj->type;
806 		raw->uid = get_obj_uid(obj);
807 		raw->iscsi = NULL;
808 		raw->ref = 0;
809 		raw->ilen = 0;
810 		raw->nt = 0;
811 		raw->ip = NULL;
812 		raw->dd_id = 0;
813 		raw->dds_id = 0;
814 	} else {
815 		isnslog(LOG_DEBUG, "make_raw_entity", "malloc failed.");
816 	}
817 
818 	return (raw);
819 }
820 
821 /*
822  * ****************************************************************************
823  *
824  * make_raw_iscsi:
825  *	Make raw SCN data with a Storage Node object.
826  *
827  * obj	- the storage node object.
828  * return - the raw SCN data.
829  *
830  * ****************************************************************************
831  */
832 static scn_raw_t *
833 make_raw_iscsi(
834 	isns_obj_t *obj
835 )
836 {
837 	uint32_t uid;
838 	uint32_t nt;
839 	uchar_t *iscsi;
840 	uint32_t ilen;
841 
842 	isns_attr_t *attr;
843 
844 	scn_raw_t *raw;
845 
846 	uid = get_obj_uid(obj);
847 	attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NODE_TYPE_ATTR_ID)];
848 	nt = attr->value.ui;
849 	attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)];
850 
851 	raw = (scn_raw_t *)malloc(sizeof (scn_raw_t));
852 	ilen = attr->len;
853 	iscsi = (uchar_t *)malloc(ilen);
854 	if (raw != NULL && iscsi != NULL) {
855 		/* copy the iscsi storage node name */
856 		(void) strcpy((char *)iscsi, (char *)attr->value.ptr);
857 
858 		raw->type = obj->type;
859 		raw->uid = uid;
860 		raw->iscsi = iscsi;
861 		raw->ref = 0;
862 		raw->ilen = ilen;
863 		raw->nt = nt;
864 		raw->ip = NULL;
865 		raw->dd_id = 0;
866 		raw->dds_id = 0;
867 	} else {
868 		free(raw);
869 		free(iscsi);
870 		raw = NULL;
871 		isnslog(LOG_DEBUG, "make_raw_iscsi", "malloc failed.");
872 	}
873 
874 	return (raw);
875 }
876 
877 /*
878  * ****************************************************************************
879  *
880  * make_raw_portal:
881  *	Make raw SCN data with a Portal object.
882  *
883  * obj	- the portal object.
884  * return - the raw SCN data.
885  *
886  * ****************************************************************************
887  */
888 static scn_raw_t *
889 make_raw_portal(
890 	isns_obj_t *obj
891 )
892 {
893 	isns_attr_t *attr;
894 	in6_addr_t *ip;
895 	uint32_t port;
896 
897 	scn_raw_t *raw;
898 
899 	raw = (scn_raw_t *)malloc(sizeof (scn_raw_t));
900 	ip = (in6_addr_t *)malloc(sizeof (in6_addr_t));
901 	if (raw != NULL && ip != NULL) {
902 		attr = &obj->attrs[
903 		    ATTR_INDEX_PORTAL(ISNS_PORTAL_IP_ADDR_ATTR_ID)];
904 		(void) memcpy(ip, attr->value.ip, sizeof (in6_addr_t));
905 		attr = &obj->attrs[
906 		    ATTR_INDEX_PORTAL(ISNS_PORTAL_PORT_ATTR_ID)];
907 		port = attr->value.ui;
908 
909 		raw->type = obj->type;
910 		raw->uid = 0;
911 		raw->iscsi = NULL;
912 		raw->ref = 0;
913 		raw->ilen = 0;
914 		raw->nt = 0;
915 		raw->ip = ip;
916 		raw->port = port;
917 		raw->dd_id = 0;
918 		raw->dds_id = 0;
919 	} else {
920 		free(ip);
921 		free(raw);
922 		raw = NULL;
923 		isnslog(LOG_DEBUG, "make_raw_portal", "malloc failed.");
924 	}
925 
926 	return (raw);
927 }
928 
929 /*
930  * ****************************************************************************
931  *
932  * make_raw_assoc_iscsi:
933  *	Make raw SCN data with a Discovery Domain member association.
934  *
935  * obj	- the member association object.
936  * return - the raw SCN data.
937  *
938  * ****************************************************************************
939  */
940 static scn_raw_t *
941 make_raw_assoc_iscsi(
942 	isns_obj_t *obj
943 )
944 {
945 	uint32_t uid;
946 	uint32_t dd_id;
947 	uint32_t nt;
948 
949 	lookup_ctrl_t lc;
950 	isns_attr_t *attr;
951 
952 	scn_raw_t *raw;
953 	uchar_t *iscsi;
954 	uint32_t ilen;
955 
956 	uid = get_obj_uid(obj);
957 	dd_id = get_parent_uid(obj);
958 
959 	SET_UID_LCP(&lc, OBJ_ISCSI, uid);
960 
961 	nt = cache_lookup(&lc, NULL, cb_get_node_type);
962 
963 	attr = &obj->attrs[ATTR_INDEX_ASSOC_ISCSI(ISNS_DD_ISCSI_NAME_ATTR_ID)];
964 
965 	raw = (scn_raw_t *)malloc(sizeof (scn_raw_t));
966 	ilen = attr->len;
967 	iscsi = (uchar_t *)malloc(ilen);
968 	if (raw != NULL && iscsi != NULL) {
969 		/* copy the iscsi storage node name */
970 		(void) strcpy((char *)iscsi, (char *)attr->value.ptr);
971 
972 		raw->type = obj->type;
973 		raw->uid = uid;
974 		raw->iscsi = iscsi;
975 		raw->ref = 0;
976 		raw->ilen = ilen;
977 		raw->nt = nt;
978 		raw->ip = NULL;
979 		raw->dd_id = dd_id;
980 		raw->dds_id = 0;
981 	} else {
982 		free(raw);
983 		free(iscsi);
984 		raw = NULL;
985 		isnslog(LOG_DEBUG, "make_raw_assoc_iscsi", "malloc failed.");
986 	}
987 
988 	return (raw);
989 }
990 
991 /*
992  * ****************************************************************************
993  *
994  * make_raw_assoc_dd:
995  *	Make raw SCN data with a Discovery Domain Set member association.
996  *
997  * obj	- the member association object.
998  * return - the raw SCN data.
999  *
1000  * ****************************************************************************
1001  */
1002 static scn_raw_t *
1003 make_raw_assoc_dd(
1004 	isns_obj_t *obj
1005 )
1006 {
1007 	scn_raw_t *raw;
1008 
1009 	raw = (scn_raw_t *)malloc(sizeof (scn_raw_t));
1010 	if (raw != NULL) {
1011 		raw->type = obj->type;
1012 		raw->uid = 0;
1013 		raw->iscsi = NULL;
1014 		raw->ref = 0;
1015 		raw->ilen = 0;
1016 		raw->nt = 0;
1017 		raw->ip = NULL;
1018 		raw->dd_id = get_obj_uid(obj);
1019 		raw->dds_id = get_parent_uid(obj);
1020 	} else {
1021 		isnslog(LOG_DEBUG, "make_raw_assoc_dd", "malloc failed.");
1022 	}
1023 
1024 	return (raw);
1025 }
1026 
1027 /*
1028  * ****************************************************************************
1029  *
1030  * scn_gen_entity:
1031  *	Generate SCN with the raw SCN data from a Network Entity object.
1032  *
1033  * raw	- the raw SCN data.
1034  * return - the SCN.
1035  *
1036  * ****************************************************************************
1037  */
1038 static scn_text_t *
1039 scn_gen_entity(
1040 	/* LINTED E_FUNC_ARG_UNUSED */
1041 	scn_raw_t *raw
1042 )
1043 {
1044 	return (NULL);
1045 }
1046 
1047 /*
1048  * ****************************************************************************
1049  *
1050  * scn_gen_iscsi:
1051  *	Generate SCN with the raw SCN data from a Storage Node object.
1052  *
1053  * raw	- the raw SCN data.
1054  * return - the SCN.
1055  *
1056  * ****************************************************************************
1057  */
1058 static scn_text_t *
1059 scn_gen_iscsi(
1060 	scn_raw_t *raw
1061 )
1062 {
1063 	scn_text_t *text;
1064 
1065 	text = (scn_text_t *)malloc(sizeof (scn_text_t));
1066 	if (text != NULL) {
1067 		text->flag = 0;
1068 		text->ref = 1; /* start with 1 */
1069 		text->uid = raw->uid;
1070 		text->iscsi = raw->iscsi;
1071 		raw->ref ++;
1072 		text->ilen = raw->ilen;
1073 		text->nt = raw->nt;
1074 		text->dd_id = raw->dd_id;
1075 		text->dds_id = raw->dds_id;
1076 		text->next = NULL;
1077 	} else {
1078 		isnslog(LOG_DEBUG, "scn_gen_iscsi", "malloc failed.");
1079 	}
1080 	return (text);
1081 }
1082 
1083 /*
1084  * ****************************************************************************
1085  *
1086  * scn_gen_portal:
1087  *	Generate SCN with the raw SCN data from a Portal object.
1088  *
1089  * raw	- the raw SCN data.
1090  * return - the SCN.
1091  *
1092  * ****************************************************************************
1093  */
1094 static scn_text_t *
1095 scn_gen_portal(
1096 	scn_raw_t *raw
1097 )
1098 {
1099 	in6_addr_t *ip;
1100 	uint32_t port;
1101 
1102 	uint32_t pg_uid, uid;
1103 	lookup_ctrl_t pg_lc, lc;
1104 
1105 	uint32_t nt;
1106 	uchar_t *name;
1107 	int ilen;
1108 
1109 	scn_text_t *text, *l = NULL;
1110 
1111 	ip = raw->ip;
1112 	port = raw->port;
1113 
1114 	pg_lc.curr_uid = 0;
1115 	pg_lc.type = OBJ_PG;
1116 	pg_lc.id[0] = ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID);
1117 	pg_lc.op[0] = OP_MEMORY_IP6;
1118 	pg_lc.data[0].ip = ip;
1119 	pg_lc.id[1] = ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID);
1120 	pg_lc.op[1] = OP_INTEGER;
1121 	pg_lc.data[1].ui = port;
1122 	pg_lc.op[2] = 0;
1123 
1124 	SET_UID_LCP(&lc, OBJ_ISCSI, 0);
1125 
1126 	lc.id[1] = ISNS_ISCSI_NAME_ATTR_ID;
1127 	lc.id[2] = ISNS_ISCSI_NODE_TYPE_ATTR_ID;
1128 	lc.data[1].ptr = NULL;
1129 
1130 	/* get a pg which is associated to the portal */
1131 	uid = cache_lookup(&pg_lc, &pg_uid, cb_pg_node);
1132 	while (pg_uid != 0) {
1133 		if (uid != 0) {
1134 			lc.data[0].ui = uid;
1135 			(void) cache_lookup(&lc, NULL, cb_clone_attrs);
1136 			name = lc.data[1].ptr;
1137 			if (name != NULL) {
1138 				nt = lc.data[2].ui;
1139 				text = (scn_text_t *)malloc(
1140 				    sizeof (scn_text_t));
1141 				if (text != NULL) {
1142 					text->flag = 0;
1143 					text->ref = 1; /* start with 1 */
1144 					text->uid = uid;
1145 					text->iscsi = name;
1146 					ilen = strlen((char *)name);
1147 					ilen += 4 - (ilen % 4);
1148 					text->ilen = ilen;
1149 					text->nt = nt;
1150 					text->dd_id = 0;
1151 					text->dds_id = 0;
1152 					text->next = l;
1153 					l = text;
1154 				} else {
1155 					free(name);
1156 					isnslog(LOG_DEBUG, "scn_gen_portal",
1157 					    "malloc failed.");
1158 				}
1159 				lc.data[1].ptr = NULL;
1160 			} else {
1161 				isnslog(LOG_WARNING, "scn_gen_portal",
1162 				    "cannot get node name.");
1163 			}
1164 		}
1165 
1166 		/* get the next pg */
1167 		pg_lc.curr_uid = pg_uid;
1168 		uid = cache_lookup(&pg_lc, &pg_uid, cb_pg_node);
1169 	}
1170 
1171 	/* update the iscsi storage node object */
1172 	raw->event = ISNS_OBJECT_UPDATED;
1173 
1174 	return (l);
1175 }
1176 
1177 /*
1178  * ****************************************************************************
1179  *
1180  * scn_gen_assoc_dd:
1181  *	Generate SCN with the raw SCN data from a DD membership object.
1182  *
1183  * raw	- the raw SCN data.
1184  * return - the SCN.
1185  *
1186  * ****************************************************************************
1187  */
1188 static scn_text_t *
1189 scn_gen_assoc_dd(
1190 	/* LINTED E_FUNC_ARG_UNUSED */
1191 	scn_raw_t *raw
1192 )
1193 {
1194 	return (NULL);
1195 }
1196 
1197 /*
1198  * ****************************************************************************
1199  *
1200  * make_scn:
1201  *	Make a SCN with an event and an object.
1202  *
1203  * event - the event.
1204  * obj	 - the object.
1205  * return - always successful (0).
1206  *
1207  * ****************************************************************************
1208  */
1209 int
1210 make_scn(
1211 	uint32_t event,
1212 	isns_obj_t *obj
1213 )
1214 {
1215 	scn_raw_t *raw = NULL;
1216 
1217 	scn_raw_t *(*f)(isns_obj_t *) = make_raw[obj->type];
1218 
1219 	if (f != NULL) {
1220 		/* make raw scn data */
1221 		raw = f(obj);
1222 	}
1223 	if (raw != NULL) {
1224 		/* trigger an scn event */
1225 		raw->event = event;
1226 		(void) queue_msg_set(scn_q, SCN_SET, (void *)raw);
1227 	}
1228 
1229 	return (0);
1230 }
1231 
1232 /*
1233  * data structure of the SCN state transition table.
1234  */
1235 typedef struct scn_tbl {
1236 	int state;
1237 	uint32_t event;
1238 	isns_type_t type;
1239 	int (*sf)(scn_raw_t *);
1240 	int next_state;
1241 } scn_tbl_t;
1242 
1243 /*
1244  * the SCN state transition table.
1245  */
1246 static const scn_tbl_t stbl[] = {
1247 	{ -1, 0, OBJ_PG, NULL, 0 },
1248 	{ -1, 0, OBJ_DD, NULL, 0 },
1249 	{ -1, 0, OBJ_DDS, NULL, 0 },
1250 
1251 	{ 0, ISNS_OBJECT_ADDED, OBJ_ENTITY, NULL, 1 },
1252 	{ 1, ISNS_OBJECT_ADDED, OBJ_ISCSI, sf_gen, 1 },
1253 	{ 1, ISNS_OBJECT_ADDED, 0, NULL, 1 },
1254 
1255 	{ 0, ISNS_OBJECT_UPDATED, OBJ_ENTITY, sf_gen, 2 },
1256 	{ 2, ISNS_OBJECT_UPDATED, 0, NULL, 2 },
1257 	{ 2, ISNS_OBJECT_ADDED, OBJ_ISCSI, sf_gen, 2 },
1258 	{ 2, ISNS_OBJECT_ADDED, 0, NULL, 2 },
1259 
1260 	{ 0, ISNS_OBJECT_REMOVED, OBJ_ENTITY, NULL, 3 },
1261 	{ 0, ISNS_OBJECT_REMOVED, 0, sf_gen, 4 },
1262 	{ 3, ISNS_OBJECT_REMOVED, OBJ_ISCSI, sf_gen, 3 },
1263 	{ 3, ISNS_OBJECT_REMOVED, 0, NULL, 3 },
1264 	{ 4, ISNS_OBJECT_REMOVED, 0, sf_gen, 4 },
1265 
1266 	{ 0, ISNS_MEMBER_ADDED, OBJ_ASSOC_ISCSI, sf_gen, 5 },
1267 	{ 5, ISNS_MEMBER_ADDED, OBJ_ASSOC_ISCSI, sf_gen, 5 },
1268 
1269 	{ 0, ISNS_MEMBER_ADDED, OBJ_ASSOC_DD, sf_gen, 6 },
1270 	{ 6, ISNS_MEMBER_ADDED, OBJ_ASSOC_DD, sf_gen, 6 },
1271 
1272 	{ 0, ISNS_MEMBER_REMOVED, OBJ_ASSOC_ISCSI, sf_gen, 7 },
1273 	{ 7, ISNS_MEMBER_REMOVED, OBJ_ASSOC_ISCSI, sf_gen, 7 },
1274 
1275 	{ 0, ISNS_MEMBER_REMOVED, OBJ_ASSOC_DD, sf_gen, 8 },
1276 	{ 8, ISNS_MEMBER_REMOVED, OBJ_ASSOC_DD, sf_gen, 8 },
1277 
1278 	{ -1, 0, 0, sf_error, -1 }
1279 };
1280 
1281 /*
1282  * ****************************************************************************
1283  *
1284  * scn_disp1:
1285  *	Dispatch one SCN to one SCN entry.
1286  *
1287  * event - the event.
1288  * p	 - the SCN entry.
1289  * t	 - the SCN.
1290  * return - always successful (0).
1291  *
1292  * ****************************************************************************
1293  */
1294 static int
1295 scn_disp1(
1296 	uint32_t event,
1297 	scn_registry_t *p,
1298 	scn_text_t *t
1299 )
1300 {
1301 	scn_t *s, *r = NULL;
1302 	scn_list_t *l, **lp;
1303 
1304 	s = p->scn;
1305 
1306 	while (s != NULL) {
1307 		if (s->event == event) {
1308 			l = s->data.list;
1309 			do {
1310 				if (l->data.text->uid == t->uid) {
1311 					/* duplicated */
1312 					return (0);
1313 				}
1314 				lp = &l->next;
1315 				l = *lp;
1316 			} while (l != NULL);
1317 			break;
1318 		}
1319 		r = s;
1320 		s = s->next;
1321 	}
1322 
1323 	l = (scn_list_t *)malloc(sizeof (scn_list_t));
1324 	if (l != NULL) {
1325 		if (s == NULL) {
1326 			s = (scn_t *)malloc(sizeof (scn_t));
1327 			if (s != NULL) {
1328 				s->event = event;
1329 				s->next = NULL;
1330 				if (r != NULL) {
1331 					r->next = s;
1332 				} else {
1333 					p->scn = s;
1334 				}
1335 				lp = &s->data.list;
1336 			} else {
1337 				free(l);
1338 				isnslog(LOG_DEBUG, "scn_disp1",
1339 				    "malloc scn failed.\n");
1340 				return (0);
1341 			}
1342 		}
1343 
1344 		t->ref ++;
1345 		l->data.text = t;
1346 		l->next = NULL;
1347 		*lp = l;
1348 	} else {
1349 		isnslog(LOG_DEBUG, "scn_disp1",
1350 		    "malloc list failed.\n");
1351 	}
1352 
1353 	return (0);
1354 }
1355 
1356 /*
1357  * ****************************************************************************
1358  *
1359  * scn_disp1:
1360  *	Dispatch one SCN to every SCN entry and update the dispatch status.
1361  *
1362  * event - the event.
1363  * text	 - the SCN.
1364  * return - always successful (0).
1365  *
1366  * ****************************************************************************
1367  */
1368 static int
1369 scn_disp(
1370 	uint32_t event,
1371 	scn_text_t *text
1372 )
1373 {
1374 	scn_registry_t *registry, *p;
1375 	uint32_t dd_id = 0;
1376 
1377 	scn_text_t *t;
1378 
1379 	uint32_t e;
1380 
1381 	registry = scn_registry;
1382 
1383 	t = text;
1384 	while (t != NULL) {
1385 		e = event;
1386 		if (t->flag == 0) {
1387 			if (e & ISNS_MEMBER_ADDED) {
1388 				e |= ISNS_OBJECT_ADDED;
1389 			} else if (e & ISNS_MEMBER_REMOVED) {
1390 				e |= ISNS_OBJECT_REMOVED;
1391 			}
1392 		}
1393 		p = registry;
1394 		while (p != NULL) {
1395 			if (SCN_TEST(e, p->bitmap, p->uid, t->uid, t->nt)) {
1396 				if (p->bitmap & ISNS_MGMT_REG) {
1397 					/* management scn are not bound */
1398 					/* by discovery domain service. */
1399 					dd_id = 1;
1400 				} else {
1401 					dd_id = 0;
1402 					/* lock the cache for reading */
1403 					(void) cache_lock_read();
1404 					/* verify common dd */
1405 					do {
1406 						dd_id = get_common_dd(
1407 						    p->uid,
1408 						    t->uid,
1409 						    dd_id);
1410 					} while (dd_id > 0 &&
1411 					    is_dd_active(dd_id) == 0);
1412 					/* unlock the cache */
1413 					(void) cache_unlock_nosync();
1414 				}
1415 				if (dd_id != 0) {
1416 					(void) scn_disp1(e, p, t);
1417 				}
1418 			}
1419 			p = p->next;
1420 		}
1421 		t = t->next;
1422 	}
1423 
1424 	while (text != NULL) {
1425 		t = text->next;
1426 		/* clean up the scn text(s) which nobody cares about. */
1427 		free_scn_text(text);
1428 		text = t;
1429 	}
1430 
1431 	if (dd_id != 0) {
1432 		/* scn(s) are dispatched. */
1433 		scn_dispatched = 1;
1434 	}
1435 
1436 	return (0);
1437 }
1438 
1439 /*
1440  * ****************************************************************************
1441  *
1442  * sf_gen:
1443  *	State transition function which generates and dispatches SCN(s).
1444  *
1445  * raw	- the raw SCN data.
1446  * return - always successful (0).
1447  *
1448  * ****************************************************************************
1449  */
1450 static int
1451 sf_gen(
1452 	scn_raw_t *raw
1453 )
1454 {
1455 	uint32_t event;
1456 
1457 	scn_text_t *(*gen)(scn_raw_t *);
1458 	scn_text_t *text = NULL;
1459 
1460 	gen = scn_gen[raw->type];
1461 	if (gen != NULL) {
1462 		text = gen(raw);
1463 	}
1464 
1465 	event = raw->event;
1466 	if (text != NULL) {
1467 		(void) scn_disp(event, text);
1468 	}
1469 
1470 	return (0);
1471 }
1472 
1473 /*
1474  * ****************************************************************************
1475  *
1476  * sf_error:
1477  *	State transition function for an error state. It free any SCN(s)
1478  *	which have been generated and dispatched previously.
1479  *
1480  * raw	- the raw SCN data.
1481  * return - always successful (0).
1482  *
1483  * ****************************************************************************
1484  */
1485 static int
1486 sf_error(
1487 	/* LINTED E_FUNC_ARG_UNUSED */
1488 	scn_raw_t *raw
1489 )
1490 {
1491 	free_scn();
1492 
1493 	return (0);
1494 }
1495 
1496 /*
1497  * ****************************************************************************
1498  *
1499  * scn_transition:
1500  *	Performs the state transition when a SCN event occurs.
1501  *
1502  * state - the previous state.
1503  * raw	 - the raw SCN data.
1504  * return - the next state.
1505  *
1506  * ****************************************************************************
1507  */
1508 static int
1509 scn_transition(
1510 	int state,
1511 	scn_raw_t *raw
1512 )
1513 {
1514 	uint32_t event = raw->event;
1515 	isns_type_t type = raw->type;
1516 
1517 	int new_state = state;
1518 
1519 	const scn_tbl_t *tbl;
1520 
1521 	tbl = &stbl[0];
1522 	for (;;) {
1523 		if ((tbl->state == -1 || tbl->state == state) &&
1524 		    (tbl->event == 0 || tbl->event == event) &&
1525 		    (tbl->type == 0 || tbl->type == type)) {
1526 			if (tbl->next_state != 0) {
1527 				new_state = tbl->next_state;
1528 			}
1529 			if (tbl->sf != NULL) {
1530 				tbl->sf(raw);
1531 			}
1532 			break;
1533 		}
1534 		tbl ++;
1535 	}
1536 
1537 	if (new_state == -1) {
1538 		isnslog(LOG_DEBUG, "scn_transition",
1539 		    "prev state: %d new event: 0x%x new object: %d.\n",
1540 		    state, event, type);
1541 		new_state = 0;
1542 	}
1543 
1544 	state = new_state;
1545 
1546 	return (state);
1547 }
1548 
1549 /*
1550  * ****************************************************************************
1551  *
1552  * connect_to:
1553  *	Create socket connection with peer network portal.
1554  *
1555  * sz	- the size of the ip addr.
1556  * in	- the ipv4 address.
1557  * in6	- the ipv6 address.
1558  * port2- the port info.
1559  * return - the socket descriptor.
1560  *
1561  * ****************************************************************************
1562  */
1563 int
1564 connect_to(
1565 	int sz,
1566 	in_addr_t in,
1567 	/* LINTED E_FUNC_ARG_UNUSED */
1568 	in6_addr_t *in6,
1569 	uint32_t port2
1570 )
1571 {
1572 	int so = -1;
1573 
1574 	union {
1575 		struct sockaddr sin;
1576 		struct sockaddr_in in;
1577 		struct sockaddr_in6 in6;
1578 	} ca = { 0 };
1579 
1580 	int tcp;
1581 	uint16_t port;
1582 
1583 	tcp = (port2 & 0x10000) == 0 ? 1 : 0;
1584 	port = (uint16_t)(port2 & 0xFFFF);
1585 	if (sz == sizeof (in_addr_t)) {
1586 		if (tcp != 0) {
1587 			so = socket(AF_INET, SOCK_STREAM, 0);
1588 			if (so != -1) {
1589 				ca.in.sin_family = AF_INET;
1590 				ca.in.sin_port = htons(port);
1591 				ca.in.sin_addr.s_addr = in;
1592 				if (connect(so, &ca.sin, sizeof (ca.in)) !=
1593 				    0) {
1594 					isnslog(LOG_DEBUG, "connect_to",
1595 					    "connect() failed %%m.");
1596 					(void) close(so);
1597 					so = -1;
1598 				}
1599 			} else {
1600 				isnslog(LOG_DEBUG, "connect_to",
1601 				    "socket() failed %%m.");
1602 			}
1603 		} else {
1604 			/* FIXME: UDP support */
1605 			isnslog(LOG_DEBUG, "connect_to", "No UDP support.");
1606 		}
1607 	} else {
1608 		/* FIXME: IPv6 support */
1609 		isnslog(LOG_DEBUG, "connect_to", "No IPv6 support.");
1610 	}
1611 
1612 	return (so);
1613 }
1614 
1615 /*
1616  * ****************************************************************************
1617  *
1618  * emit_scn:
1619  *	Emit the SCN to any portal of the peer storage node.
1620  *
1621  * list	- the list of portal.
1622  * pdu	- the SCN packet.
1623  * pl	- the SCN packet payload length.
1624  * return - always successful (0).
1625  *
1626  * ****************************************************************************
1627  */
1628 static int
1629 emit_scn(
1630 	scn_list_t *list,
1631 	isns_pdu_t *pdu,
1632 	size_t pl
1633 )
1634 {
1635 	int so = 0;
1636 	scn_list_t *l;
1637 	scn_portal_t *p;
1638 
1639 	isns_pdu_t *rsp = NULL;
1640 	size_t rsp_sz;
1641 
1642 	pdu->version = htons((uint16_t)ISNSP_VERSION);
1643 	pdu->func_id = htons((uint16_t)ISNS_SCN);
1644 	pdu->xid = htons(get_server_xid());
1645 
1646 	l = list;
1647 	while (l != NULL) {
1648 		p = l->data.portal;
1649 		so = connect_to(p->sz, p->ip.in, p->ip.in6, p->port);
1650 		if (so != -1) {
1651 			if (isns_send_pdu(so, pdu, pl) == 0) {
1652 				/* This may help Solaris iSCSI Initiator */
1653 				/* not to panic frequently. */
1654 				(void) isns_rcv_pdu(so, &rsp, &rsp_sz,
1655 				    ISNS_RCV_SHORT_TIMEOUT);
1656 			} else {
1657 				isnslog(LOG_DEBUG, "emit_scn",
1658 				    "sending packet failed.");
1659 			}
1660 			(void) close(so);
1661 			/* p->so = so; */
1662 			break;
1663 		}
1664 		l = l->next;
1665 	}
1666 
1667 	if (rsp != NULL) {
1668 #ifdef DEBUG
1669 		dump_pdu1(rsp);
1670 #endif
1671 		free(rsp);
1672 	}
1673 
1674 	return (0);
1675 }
1676 
1677 /*
1678  * ****************************************************************************
1679  *
1680  * scn_trigger1:
1681  *	Trigger one SCN for one SCN entry.
1682  *
1683  * t	- the time that SCN is being triggered.
1684  * p	- the SCN entry.
1685  * return - always successful (0).
1686  *
1687  * ****************************************************************************
1688  */
1689 static int
1690 scn_trigger1(
1691 	time_t t,
1692 	scn_registry_t *p
1693 )
1694 {
1695 	int ec;
1696 
1697 	isns_pdu_t *pdu = NULL;
1698 	size_t sz;
1699 	size_t pl;
1700 
1701 	scn_t *s;
1702 	scn_list_t *l;
1703 	scn_text_t *x;
1704 
1705 	union {
1706 		uint32_t i32;
1707 		uint64_t i64;
1708 	} u;
1709 
1710 #ifdef DEBUG
1711 	char buff[1024] = { 0 };
1712 	char *logbuff = buff;
1713 #endif
1714 
1715 	ec = pdu_reset_scn(&pdu, &pl, &sz);
1716 	if (pdu == NULL) {
1717 		goto scn_done;
1718 	}
1719 
1720 	/* add destination attribute */
1721 	ec = pdu_add_tlv(&pdu, &pl, &sz,
1722 	    ISNS_ISCSI_NAME_ATTR_ID,
1723 	    p->nlen,
1724 	    (void *)p->name, 0);
1725 	if (ec != 0) {
1726 		goto scn_done;
1727 	}
1728 
1729 #ifdef DEBUG
1730 	sprintf(logbuff, "==>%s ", p->name);
1731 	logbuff += strlen(logbuff);
1732 #endif
1733 
1734 	/* add timestamp */
1735 	u.i64 = BE_64((uint64_t)t);
1736 	ec = pdu_add_tlv(&pdu, &pl, &sz,
1737 	    ISNS_TIMESTAMP_ATTR_ID,
1738 	    8,
1739 	    (void *)&u.i64, 1);
1740 
1741 	s = p->scn;
1742 	while (s != NULL && ec == 0) {
1743 		u.i32 = htonl(s->event);
1744 		ec = pdu_add_tlv(&pdu, &pl, &sz,
1745 		    ISNS_ISCSI_SCN_BITMAP_ATTR_ID,
1746 		    4,
1747 		    (void *)&u.i32, 1);
1748 #ifdef DEBUG
1749 		sprintf(logbuff, "EVENT [%d] ", s->event);
1750 		logbuff += strlen(logbuff);
1751 #endif
1752 		l = s->data.list;
1753 		while (l != NULL && ec == 0) {
1754 			x = l->data.text;
1755 			if (x->flag == 0) {
1756 				ec = pdu_add_tlv(&pdu, &pl, &sz,
1757 				    ISNS_ISCSI_NAME_ATTR_ID,
1758 				    x->ilen, (void *)x->iscsi, 0);
1759 #ifdef DEBUG
1760 				sprintf(logbuff, "FROM [%s] ", x->iscsi);
1761 				logbuff += strlen(logbuff);
1762 #endif
1763 				if (ec == 0 &&
1764 				    (p->bitmap &
1765 				    (ISNS_MEMBER_ADDED |
1766 				    ISNS_MEMBER_REMOVED))) {
1767 					/* management SCN */
1768 					u.i32 = htonl(x->dd_id);
1769 					ec = pdu_add_tlv(&pdu, &pl, &sz,
1770 					    ISNS_DD_ID_ATTR_ID,
1771 					    4, (void *)&u.i32, 1);
1772 #ifdef DEBUG
1773 					sprintf(logbuff, "IN DD [%d] ",
1774 					    x->dd_id);
1775 					logbuff += strlen(logbuff);
1776 #endif
1777 				}
1778 			} else {
1779 				/* add(remove) dd to(from) dd-set */
1780 				u.i32 = htonl(x->dd_id);
1781 				ec = pdu_add_tlv(&pdu, &pl, &sz,
1782 				    ISNS_DD_ID_ATTR_ID,
1783 				    4, (void *)&u.i32, 1);
1784 				u.i32 = htonl(x->dds_id);
1785 				if (ec == 0) {
1786 					ec = pdu_add_tlv(&pdu, &pl, &sz,
1787 					    ISNS_DD_ID_ATTR_ID,
1788 					    4, (void *)&u.i32, 1);
1789 				}
1790 #ifdef DEBUG
1791 				sprintf(logbuff, "FROM [%d] ", x->dd_id);
1792 				logbuff += strlen(logbuff);
1793 				sprintf(logbuff, "IN [%d] ", x->dds_id);
1794 				logbuff += strlen(logbuff);
1795 #endif
1796 			}
1797 			l = l->next;
1798 		}
1799 		s = s->next;
1800 	}
1801 
1802 scn_done:
1803 	if (ec == 0) {
1804 #ifdef DEBUG
1805 		isnslog(LOG_DEBUG, "scn_trigger1", buff);
1806 #endif
1807 		ec = emit_scn(p->portal.l, pdu, pl);
1808 	} else {
1809 		isnslog(LOG_DEBUG, "scn_trigger1", " failed.\n");
1810 	}
1811 
1812 	free(pdu);
1813 
1814 	return (0);
1815 }
1816 
1817 /*
1818  * ****************************************************************************
1819  *
1820  * scn_trigger:
1821  *	Trigger one SCN for every SCN entry.
1822  *
1823  * return - always successful (0).
1824  *
1825  * ****************************************************************************
1826  */
1827 static int
1828 scn_trigger(
1829 )
1830 {
1831 	time_t t;
1832 	scn_registry_t *p;
1833 
1834 	t = time(NULL);
1835 
1836 	p = scn_registry;
1837 	while (p != NULL) {
1838 		if (p->scn != NULL) {
1839 			(void) scn_trigger1(t, p);
1840 		}
1841 		p = p->next;
1842 	}
1843 
1844 	return (0);
1845 }
1846 
1847 /*
1848  * global functions.
1849  */
1850 
1851 /*
1852  * ****************************************************************************
1853  *
1854  * scn_list_load:
1855  *	Load one SCN entry and add it to the SCN entry list.
1856  *
1857  * uid	- the Storage Node object UID.
1858  * node	- the Storage Node name.
1859  * nlen	- the length of the name.
1860  * bitmap - the SCN bitmap.
1861  * return - error code.
1862  *
1863  * ****************************************************************************
1864  */
1865 int
1866 scn_list_load(
1867 	uint32_t uid,
1868 	uchar_t *node,
1869 	uint32_t nlen,
1870 	uint32_t bitmap
1871 )
1872 {
1873 	int ec = 0;
1874 
1875 	scn_registry_t *list;
1876 	uchar_t *name;
1877 
1878 	list = (scn_registry_t *)malloc(sizeof (scn_registry_t));
1879 	name = (uchar_t *)malloc(nlen);
1880 
1881 	if (list != NULL && name != NULL) {
1882 		list->uid = uid;
1883 		(void) strcpy((char *)name, (char *)node);
1884 		list->name = name;
1885 		list->nlen = nlen;
1886 		list->bitmap = bitmap;
1887 		list->portal.l = NULL;
1888 		list->scn = NULL;
1889 		list->next = NULL;
1890 		ASSERT(scn_q == NULL);
1891 		(void) scn_list_add(list);
1892 	} else {
1893 		free(list);
1894 		free(name);
1895 		ec = ISNS_RSP_INTERNAL_ERROR;
1896 	}
1897 
1898 	return (ec);
1899 }
1900 
1901 /*
1902  * ****************************************************************************
1903  *
1904  * verify_scn_portal:
1905  *	Extract and verify portals for every SCN entry(s) after they are
1906  *	loaded from data store, for those which do not have a SCN portal,
1907  *	remove it from the SCN entry list.
1908  *
1909  * return - 1: error occurs, otherwise 0.
1910  *
1911  * ****************************************************************************
1912  */
1913 int
1914 verify_scn_portal(
1915 )
1916 {
1917 	scn_registry_t **pp, *e;
1918 	scn_portal_t *p;
1919 
1920 	pp = &scn_registry;
1921 	while (*pp != NULL) {
1922 		e = *pp;
1923 		p = extract_scn_portal(e->name);
1924 		if (p != NULL) {
1925 			if (scn_add_portal(e, p) != 0) {
1926 				return (1);
1927 			}
1928 		}
1929 		if (e->portal.l != NULL) {
1930 			pp = &e->next;
1931 		} else {
1932 			/* remove this entry */
1933 			*pp = e->next;
1934 			free_entry(e);
1935 		}
1936 		/* free the unused portal(s) */
1937 		free_portal(p);
1938 	}
1939 
1940 	return (0);
1941 }
1942 
1943 /*
1944  * ****************************************************************************
1945  *
1946  * add_scn_entry:
1947  *	Add a SCN entry.
1948  *
1949  * node	- the Storage Node name.
1950  * nlen	- the length of the name.
1951  * bitmap - the SCN bitmap.
1952  * return - error code.
1953  *
1954  * ****************************************************************************
1955  */
1956 int
1957 add_scn_entry(
1958 	uchar_t *node,
1959 	uint32_t nlen,
1960 	uint32_t bitmap
1961 )
1962 {
1963 	int ec = 0;
1964 
1965 	uint32_t mgmt;
1966 	scn_portal_t *p;
1967 
1968 	lookup_ctrl_t lc;
1969 	uint32_t uid;
1970 	scn_registry_t *e;
1971 	uchar_t *name;
1972 
1973 	mgmt = bitmap & (
1974 	    ISNS_MGMT_REG |
1975 	    ISNS_MEMBER_REMOVED |
1976 	    ISNS_MEMBER_ADDED);
1977 
1978 	if ((mgmt > 0 &&
1979 	    (mgmt_scn == 0 ||
1980 	    mgmt < ISNS_MGMT_REG ||
1981 	    is_control_node(node) == 0)) ||
1982 	    (p = extract_scn_portal(node)) == NULL) {
1983 		return (ISNS_RSP_SCN_REGIS_REJECTED);
1984 	}
1985 
1986 	e = (scn_registry_t *)malloc(sizeof (scn_registry_t));
1987 	name = (uchar_t *)malloc(nlen);
1988 	if (e != NULL && name != NULL) {
1989 		lc.type = OBJ_ISCSI;
1990 		lc.curr_uid = 0;
1991 		lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID);
1992 		lc.data[0].ptr = node;
1993 		lc.op[0] = OP_STRING;
1994 		lc.op[1] = 0;
1995 		lc.data[2].ui = bitmap;
1996 		ec = cache_lookup(&lc, &uid, cb_update_scn_bitmap);
1997 		if (uid == 0) {
1998 			ec = ISNS_RSP_SCN_REGIS_REJECTED;
1999 		}
2000 		if (ec == 0) {
2001 			e->uid = uid;
2002 			(void) strcpy((char *)name, (char *)node);
2003 			e->name = name;
2004 			e->nlen = nlen;
2005 			e->bitmap = bitmap;
2006 			e->portal.p = p;
2007 			e->scn = NULL;
2008 			e->next = NULL;
2009 			(void) queue_msg_set(scn_q, SCN_ADD, (void *)e);
2010 		}
2011 	} else {
2012 		ec = ISNS_RSP_INTERNAL_ERROR;
2013 	}
2014 
2015 	if (ec != 0) {
2016 		free(e);
2017 		free(name);
2018 		free_portal(p);
2019 	}
2020 
2021 	return (ec);
2022 }
2023 
2024 /*
2025  * ****************************************************************************
2026  *
2027  * remove_scn_entry:
2028  *	Remove a SCN entry.
2029  *
2030  * node	- the Storage Node name.
2031  * return - error code.
2032  *
2033  * ****************************************************************************
2034  */
2035 int
2036 remove_scn_entry(
2037 	uchar_t *node
2038 )
2039 {
2040 	int ec = 0;
2041 
2042 	lookup_ctrl_t lc;
2043 	uint32_t uid;
2044 
2045 	lc.type = OBJ_ISCSI;
2046 	lc.curr_uid = 0;
2047 	lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID);
2048 	lc.data[0].ptr = node;
2049 	lc.op[0] = OP_STRING;
2050 	lc.op[1] = 0;
2051 	lc.data[2].ui = 0;
2052 	ec = cache_lookup(&lc, &uid, cb_update_scn_bitmap);
2053 	if (ec == 0 && uid != 0) {
2054 		(void) queue_msg_set(scn_q, SCN_REMOVE, (void *)uid);
2055 	}
2056 
2057 	return (ec);
2058 }
2059 
2060 /*
2061  * ****************************************************************************
2062  *
2063  * remove_scn_portal:
2064  *	Remove a portal from every SCN entry.
2065  *
2066  * uid	- the Portal object UID.
2067  * return - alrays successful (0).
2068  *
2069  * ****************************************************************************
2070  */
2071 int
2072 remove_scn_portal(
2073 	uint32_t uid
2074 )
2075 {
2076 	(void) queue_msg_set(scn_q, SCN_REMOVE_P, (void *)uid);
2077 
2078 	return (0);
2079 }
2080 
2081 /*
2082  * ****************************************************************************
2083  *
2084  * scn_proc:
2085  *	The entry point of the SCN thread. It listens on the SCN message
2086  *	queue and process every SCN related stuff.
2087  *
2088  * arg	- nothing.
2089  * return - NULL.
2090  *
2091  * ****************************************************************************
2092  */
2093 void *
2094 scn_proc(
2095 	/* LINTED E_FUNC_ARG_UNUSED */
2096 	void *arg
2097 )
2098 {
2099 	int state = 0;
2100 
2101 	scn_raw_t *raw;
2102 	msg_text_t *msg;
2103 
2104 	for (;;) {
2105 		msg = queue_msg_get(scn_q);
2106 		switch (msg->id) {
2107 		case SCN_ADD:
2108 			(void) scn_list_add((scn_registry_t *)msg->data);
2109 			break;
2110 		case SCN_REMOVE:
2111 			(void) scn_list_remove((uint32_t)msg->data);
2112 			break;
2113 		case SCN_REMOVE_P:
2114 			(void) scn_remove_portal((uint32_t)msg->data);
2115 			break;
2116 		case SCN_SET:
2117 			raw = (scn_raw_t *)msg->data;
2118 			state = scn_transition(state, raw);
2119 			/* free the raw data */
2120 			free_raw(raw);
2121 			break;
2122 		case SCN_TRIGGER:
2123 			if (scn_dispatched != 0) {
2124 				(void) scn_trigger();
2125 			}
2126 			/* FALLTHROUGH */
2127 		case SCN_IGNORE:
2128 			/* clean the scn(s) */
2129 			free_scn();
2130 			/* reset the state */
2131 			state = 0;
2132 			/* reset the scn_dispatched flag */
2133 			scn_dispatched = 0;
2134 			break;
2135 		case SCN_STOP:
2136 			queue_msg_free(msg);
2137 			return (NULL);
2138 		default:
2139 			break;
2140 		}
2141 		queue_msg_free(msg);
2142 	}
2143 }
2144