xref: /illumos-gate/usr/src/cmd/isns/isnsd/dd.c (revision edb348833aaacfa1176e502ad38875fd0b2717ab)
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 
31 #include "isns_server.h"
32 #include "isns_msgq.h"
33 #include "isns_htab.h"
34 #include "isns_dd.h"
35 #include "isns_cache.h"
36 #include "isns_obj.h"
37 #include "isns_pdu.h"
38 #include "isns_dseng.h"
39 #include "isns_scn.h"
40 #include "isns_utils.h"
41 
42 /*
43  * extern global variables
44  */
45 extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE];
46 
47 extern msg_queue_t *sys_q;
48 extern msg_queue_t *scn_q;
49 
50 extern int cache_flag;
51 
52 /*
53  * extern functions.
54  */
55 
56 /*
57  * global variables
58  */
59 
60 /*
61  * local variables
62  */
63 
64 /*
65  * local functions.
66  */
67 static matrix_t *new_matrix(uint32_t, uint32_t);
68 
69 static int
70 cb_update_ds_attr(
71 	void *p1,
72 	void *p2
73 )
74 {
75 	int ec = 0;
76 
77 	isns_obj_t *obj = (isns_obj_t *)p1;
78 	lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2;
79 	uint32_t tag = lcp->id[1];
80 	uint32_t which;
81 	isns_attr_t *attr;
82 
83 	uint32_t len;
84 	uchar_t *name;
85 	lookup_ctrl_t lc;
86 	uint32_t uid;
87 
88 	switch (tag) {
89 	case ISNS_DD_NAME_ATTR_ID:
90 		which = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID);
91 		break;
92 	case ISNS_DD_FEATURES_ATTR_ID:
93 		which = ATTR_INDEX_DD(ISNS_DD_FEATURES_ATTR_ID);
94 		break;
95 	case ISNS_DD_SET_NAME_ATTR_ID:
96 		which = ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID);
97 		break;
98 	case ISNS_DD_SET_STATUS_ATTR_ID:
99 		which = ATTR_INDEX_DDS(ISNS_DD_SET_STATUS_ATTR_ID);
100 		break;
101 	default:
102 		ASSERT(0);
103 		break;
104 	}
105 
106 	attr = &obj->attrs[which];
107 
108 	switch (tag) {
109 	case ISNS_DD_NAME_ATTR_ID:
110 	case ISNS_DD_SET_NAME_ATTR_ID:
111 		len = lcp->data[1].ui;
112 		name = lcp->data[2].ptr;
113 		lc.type = lcp->type;
114 		lc.curr_uid = 0;
115 		lc.id[0] = which;
116 		lc.op[0] = OP_STRING;
117 		lc.data[0].ptr = name;
118 		lc.op[1] = 0;
119 		/* check if the name is in use */
120 		uid = is_obj_there(&lc);
121 		if (uid != 0) {
122 			if (uid != get_obj_uid(obj)) {
123 				ec = ERR_NAME_IN_USE;
124 			}
125 			return (ec);
126 		}
127 		if (len > attr->len) {
128 			uchar_t *tmp = (uchar_t *)malloc(len);
129 			if (tmp != NULL) {
130 				free(attr->value.ptr);
131 				attr->value.ptr = tmp;
132 			} else {
133 				/* memory exhausted */
134 				return (ISNS_RSP_INTERNAL_ERROR);
135 			}
136 		}
137 		(void) strcpy((char *)attr->value.ptr, (char *)name);
138 		attr->len = len;
139 		break;
140 	case ISNS_DD_FEATURES_ATTR_ID:
141 	case ISNS_DD_SET_STATUS_ATTR_ID:
142 		if (attr->tag != tag ||
143 		    attr->value.ui != lcp->data[1].ui) {
144 			attr->tag = tag;
145 			attr->len = 4;
146 			attr->value.ui = lcp->data[1].ui;
147 		} else {
148 			return (ec);
149 		}
150 		break;
151 	}
152 
153 	/* cache has been updated, set the flag */
154 	SET_CACHE_UPDATED();
155 
156 	/* update data store */
157 	if (sys_q != NULL) {
158 		ec = write_data(DATA_UPDATE, obj);
159 	}
160 
161 	return (ec);
162 }
163 
164 static isns_obj_t *
165 make_member_node(
166 	const uint32_t uid,
167 	isns_attr_t *attr1
168 )
169 {
170 	isns_obj_t *obj = NULL;
171 	isns_attr_t *attr;
172 	isns_attr_t tmp;
173 
174 	switch (attr1->tag) {
175 	case ISNS_DD_ISCSI_NAME_ATTR_ID:
176 		obj = obj_calloc(OBJ_ISCSI);
177 		attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)];
178 		tmp.tag = ISNS_ISCSI_NAME_ATTR_ID;
179 		tmp.len = attr1->len;
180 		tmp.value.ptr = attr1->value.ptr;
181 		if (assign_attr(attr, &tmp) != 0) {
182 			free_object(obj);
183 			obj = NULL;
184 		} else if (uid != 0) {
185 			(void) set_obj_uid(obj, uid);
186 		}
187 		break;
188 	default:
189 		ASSERT(0);
190 		break;
191 	}
192 
193 	return (obj);
194 }
195 
196 static isns_obj_t *
197 make_member_dd(
198 	const uint32_t uid
199 )
200 {
201 	isns_obj_t *obj = NULL;
202 	isns_attr_t name = { 0 };
203 
204 	obj = obj_calloc(OBJ_DD);
205 	if (obj != NULL) {
206 		(void) set_obj_uid(obj, uid);
207 		name.tag = ISNS_DD_NAME_ATTR_ID;
208 		if (assign_attr(
209 		    &obj->attrs[ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID)],
210 		    &name) != 0) {
211 			free_object(obj);
212 			obj = NULL;
213 		}
214 	}
215 
216 	return (obj);
217 }
218 
219 static int
220 get_member_info(
221 	isns_obj_t *assoc,
222 	uint32_t *m_type,
223 	uint32_t *m_id,
224 	int flag
225 )
226 {
227 	int ec = 0;
228 	lookup_ctrl_t lc = { 0 };
229 
230 	isns_obj_t *obj;
231 	isns_attr_t *attr1, *attr2;
232 	uint32_t tmp_id = 0;
233 	int i = 0;
234 
235 	*m_type = 0;
236 	*m_id = 0;
237 
238 	attr1 = &assoc->attrs[ATTR_INDEX_ASSOC_ISCSI(
239 	    ISNS_DD_ISCSI_INDEX_ATTR_ID)];
240 	attr2 = &assoc->attrs[ATTR_INDEX_ASSOC_ISCSI(
241 	    ISNS_DD_ISCSI_NAME_ATTR_ID)];
242 
243 	lc.type = OBJ_ISCSI;
244 	if (attr1->tag != 0 && attr1->value.ui != 0) {
245 		*m_id = attr1->value.ui;
246 		lc.id[i] = UID_ATTR_INDEX[OBJ_ISCSI];
247 		lc.op[i] = OP_INTEGER;
248 		lc.data[i].ui = *m_id;
249 		i ++;
250 	}
251 	if (attr2->tag != 0) {
252 		lc.id[i] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID);
253 		lc.op[i] = OP_STRING;
254 		lc.data[i].ptr = attr2->value.ptr;
255 		i ++;
256 	} else if (scn_q != NULL || sys_q != NULL) {
257 		lc.id[i] = ISNS_ISCSI_NAME_ATTR_ID;
258 	}
259 
260 	/* a member id or member name is required */
261 	if (i == 0) {
262 		if (flag != 0) {
263 			/* add member */
264 			return (ISNS_RSP_INVALID_REGIS);
265 		} else {
266 			/* remove member (isnsp msg request only) */
267 			return (0);
268 		}
269 	}
270 
271 	ec = cache_lookup(&lc, &tmp_id, cb_clone_attrs);
272 
273 	if (ec == 0 && tmp_id == 0) {
274 		if (flag != 0) {
275 			/* add member */
276 			if (attr1->tag == 0 || sys_q == NULL) {
277 				/* object does not exist, create one */
278 				obj = make_member_node(*m_id, attr2);
279 				if (obj == NULL) {
280 					ec = ISNS_RSP_INTERNAL_ERROR;
281 				} else {
282 					ec = register_assoc(obj, &tmp_id);
283 					if (ec != 0) {
284 						free_object(obj);
285 					}
286 				}
287 			} else {
288 				/* don't create it if uid is specified */
289 				ec = ISNS_RSP_NO_SUCH_ENTRY;
290 			}
291 		} else {
292 			/* remove member */
293 			ec = ERR_NO_SUCH_ASSOCIATION;
294 		}
295 	}
296 
297 	if (attr1->tag == 0) {
298 		attr1->tag = ISNS_DD_ISCSI_INDEX_ATTR_ID;
299 		attr1->len = 4;
300 		attr1->value.ui = tmp_id;
301 	} else if (attr2->tag == 0) {
302 		attr2->tag = ISNS_DD_ISCSI_NAME_ATTR_ID;
303 		attr2->len = strlen((char *)lc.data[1].ptr);
304 		attr2->len += 4 - (attr2->len % 4);
305 		attr2->value.ptr = lc.data[1].ptr;
306 	}
307 
308 	*m_type = OBJ_ISCSI;
309 	*m_id = tmp_id;
310 
311 	return (ec);
312 }
313 
314 static int
315 get_dds_member_info(
316 	uint32_t m_id
317 )
318 {
319 	int ec = 0;
320 	lookup_ctrl_t lc;
321 
322 	isns_obj_t *obj;
323 	uint32_t tmp_id;
324 
325 	if (m_id != 0) {
326 		SET_UID_LCP(&lc, OBJ_DD, m_id);
327 	} else {
328 		return (ISNS_RSP_INVALID_REGIS);
329 	}
330 
331 	tmp_id = is_obj_there(&lc);
332 
333 	if (tmp_id == 0) {
334 		/* object does not exist, create one */
335 		obj = make_member_dd(m_id);
336 		if (obj != NULL) {
337 			ec = register_object(obj, NULL, NULL);
338 		} else {
339 			/* no memory */
340 			ec = ISNS_RSP_INTERNAL_ERROR;
341 		}
342 	}
343 
344 	return (ec);
345 }
346 
347 static int
348 update_matrix(
349 	matrix_t *matrix,
350 	const uchar_t op,
351 	const uint32_t puid,
352 	const uint32_t m_id,
353 	int ddd_flag
354 )
355 {
356 	int ec = 0;
357 
358 	uint32_t new_x = 0, new_y = 0;
359 	matrix_t *tmp_matrix;
360 
361 	uint32_t i, j, k = 0;
362 	uint32_t x_info;
363 	bmp_t *bmp, *tmp_bmp;
364 
365 	uint32_t primary = GET_PRIMARY(m_id);
366 	uint32_t second = GET_SECOND(m_id);
367 
368 	if (primary >= matrix->x) {
369 		if (op == '-') {
370 			ec = ERR_NO_SUCH_ASSOCIATION;
371 			goto update_matrix_done;
372 		}
373 		/* enlarge the matrix on x axis */
374 		if (primary >= matrix->x * 2) {
375 			new_x = primary + 1;
376 		} else {
377 			new_x = matrix->x * 2;
378 		}
379 	}
380 
381 	i = 0;
382 	while (i < matrix->y) {
383 		bmp = MATRIX_X_UNIT(matrix, i);
384 		x_info = MATRIX_X_INFO(bmp);
385 		if (x_info == puid) {
386 			break;
387 		} else if (x_info == 0 && k == 0) {
388 			/* the first available slot */
389 			k = i;
390 		}
391 		i ++;
392 	}
393 	if (i == matrix->y) {
394 		if (op == '-') {
395 			ec = ERR_NO_SUCH_ASSOCIATION;
396 			goto update_matrix_done;
397 		} else if (k == 0) {
398 			new_y = matrix->y * 2;
399 		} else {
400 			i = k;
401 		}
402 	}
403 
404 	/*
405 	 * enlarge the matrix.
406 	 */
407 	if (new_x != 0 || new_y != 0) {
408 		if (new_x == 0) {
409 			new_x = matrix->x;
410 		}
411 		if (new_y == 0) {
412 			new_y = matrix->y;
413 		}
414 		tmp_matrix = new_matrix(new_x, new_y);
415 		if (tmp_matrix != NULL) {
416 			j = 0;
417 			while (j < matrix->y) {
418 				bmp = MATRIX_X_UNIT(matrix, j);
419 				x_info = MATRIX_X_INFO(bmp);
420 				if (x_info != 0) {
421 					tmp_bmp = MATRIX_X_UNIT(tmp_matrix, j);
422 					(void) memcpy((void *)tmp_bmp,
423 					    (void *)bmp, SIZEOF_X_UNIT(matrix));
424 				}
425 				j ++;
426 			}
427 			free(matrix->m);
428 			matrix->x = tmp_matrix->x;
429 			matrix->y = tmp_matrix->y;
430 			matrix->m = tmp_matrix->m;
431 			free(tmp_matrix);
432 		} else {
433 			ec = ISNS_RSP_INTERNAL_ERROR;
434 			goto update_matrix_done;
435 		}
436 	}
437 
438 	bmp = MATRIX_X_UNIT(matrix, i);
439 
440 	MATRIX_X_INFO(bmp) = puid;
441 	if (op == '+') {
442 		if (TEST_MEMBERSHIP(bmp, primary, second) == 0) {
443 			SET_MEMBERSHIP(bmp, primary, second);
444 			SET_CACHE_UPDATED();
445 			if (ddd_flag != 0) {
446 				bmp = MATRIX_X_UNIT(matrix, 0);
447 				ASSERT(MATRIX_X_INFO(bmp) ==
448 				    ISNS_DEFAULT_DD_ID);
449 				CLEAR_MEMBERSHIP(bmp, primary, second);
450 			}
451 		} else {
452 			ec = ERR_ALREADY_ASSOCIATED;
453 		}
454 	} else if (op == '-') {
455 		if (TEST_MEMBERSHIP(bmp, primary, second) != 0) {
456 			CLEAR_MEMBERSHIP(bmp, primary, second);
457 			SET_CACHE_UPDATED();
458 			if (ddd_flag != 0) {
459 				i = 1;
460 				while (i < matrix->y) {
461 					bmp = MATRIX_X_UNIT(matrix, i);
462 					x_info = MATRIX_X_INFO(bmp);
463 					if (x_info != 0 &&
464 					    TEST_MEMBERSHIP(bmp,
465 					    primary, second) != 0) {
466 						break;
467 					}
468 					i ++;
469 				}
470 				if (i == matrix->y) {
471 					bmp = MATRIX_X_UNIT(matrix, 0);
472 					ASSERT(MATRIX_X_INFO(bmp) ==
473 					    ISNS_DEFAULT_DD_ID);
474 					SET_MEMBERSHIP(bmp, primary, second);
475 				}
476 			}
477 		} else {
478 			ec = ERR_NO_SUCH_ASSOCIATION;
479 		}
480 	}
481 
482 update_matrix_done:
483 	return (ec);
484 }
485 
486 /*ARGSUSED*/
487 static int
488 update_dd_matrix(
489 	const uchar_t op,
490 	const uint32_t dd_id,
491 	const uint32_t m_type,
492 	const uint32_t m_id
493 )
494 {
495 	matrix_t *matrix;
496 
497 	ASSERT(m_type == OBJ_ISCSI);
498 
499 	matrix = cache_get_matrix(OBJ_DD);
500 
501 	return (update_matrix(matrix, op, dd_id, m_id, 1));
502 }
503 
504 static int
505 update_dds_matrix(
506 	const uchar_t op,
507 	const uint32_t dds_id,
508 	const uint32_t m_id
509 )
510 {
511 	matrix_t *dds_matrix = cache_get_matrix(OBJ_DDS);
512 
513 	return (update_matrix(dds_matrix, op, dds_id, m_id, 0));
514 }
515 
516 static int
517 clear_matrix(
518 	matrix_t *matrix,
519 	const uint32_t uid,
520 	bmp_t **p,
521 	uint32_t *n,
522 	int ddd_flag
523 )
524 {
525 	int ec = 0;
526 	bmp_t *bmp;
527 	uint32_t x_info;
528 	int i, j;
529 
530 	uint32_t primary;
531 	uint32_t second;
532 
533 	if (p != NULL) {
534 		*p = NULL;
535 		*n = 0;
536 	}
537 
538 	i = 0;
539 	while (i < matrix->y) {
540 		bmp = MATRIX_X_UNIT(matrix, i);
541 		x_info = MATRIX_X_INFO(bmp);
542 		if (x_info == uid) {
543 			if (p != NULL) {
544 				/* dup it for caller */
545 				*n = matrix->x;
546 				*p = (bmp_t *)malloc(*n * sizeof (bmp_t));
547 				if (*p != NULL) {
548 					(void) memcpy(*p, &bmp[MATRIX_X_HEADER],
549 					    *n * sizeof (bmp_t));
550 				} else {
551 					ec = ISNS_RSP_INTERNAL_ERROR;
552 				}
553 			}
554 			/* clean it */
555 			(void) memset(bmp, 0, SIZEOF_X_UNIT(matrix));
556 			break;
557 		}
558 		i ++;
559 	}
560 
561 	if (ddd_flag != 0 && p != NULL) {
562 		bmp = MATRIX_X_UNIT(matrix, 0);
563 		ASSERT(MATRIX_X_INFO(bmp) == ISNS_DEFAULT_DD_ID);
564 		/* Test the membership for each node which is a */
565 		/* member in the dd that is being deleted. */
566 		FOR_EACH_MEMBER(*p, *n, i, {
567 			j = get_dd_id(i, 0);
568 			if (j == 0) {
569 				/* put it to the default dd */
570 				primary = GET_PRIMARY(i);
571 				second = GET_SECOND(i);
572 				SET_MEMBERSHIP(bmp, primary, second);
573 			}
574 		});
575 	}
576 
577 	return (ec);
578 }
579 
580 static int
581 get_matrix(
582 	matrix_t *matrix,
583 	const uint32_t uid,
584 	bmp_t **p,
585 	uint32_t *n
586 )
587 {
588 	int ec = 0;
589 	bmp_t *bmp;
590 	uint32_t x_info;
591 	int i;
592 
593 	*n = 0;
594 	*p = NULL;
595 
596 	i = 0;
597 	while (i < matrix->y) {
598 		bmp = MATRIX_X_UNIT(matrix, i);
599 		x_info = MATRIX_X_INFO(bmp);
600 		if (x_info == uid) {
601 			/* dup it for caller */
602 			*n = matrix->x;
603 			*p = (bmp_t *)malloc(*n * sizeof (bmp_t));
604 			if (*p != NULL) {
605 				(void) memcpy(*p, &bmp[MATRIX_X_HEADER],
606 				    *n * sizeof (bmp_t));
607 			} else {
608 				*n = 0;
609 				ec = ISNS_RSP_INTERNAL_ERROR;
610 			}
611 			break;
612 		}
613 		i ++;
614 	}
615 
616 	return (ec);
617 }
618 
619 static int
620 clear_dd_matrix(
621 	const uint32_t dd_id,
622 	bmp_t **p,
623 	uint32_t *n
624 )
625 {
626 	matrix_t *matrix = cache_get_matrix(OBJ_DD);
627 
628 	return (clear_matrix(matrix, dd_id, p, n, 1));
629 }
630 
631 static int
632 clear_dds_matrix(
633 	const uint32_t dds_id
634 )
635 {
636 	matrix_t *matrix = cache_get_matrix(OBJ_DDS);
637 
638 	return (clear_matrix(matrix, dds_id, NULL, NULL, 0));
639 }
640 
641 int
642 get_dd_matrix(
643 	const uint32_t dd_id,
644 	bmp_t **p,
645 	uint32_t *n
646 )
647 {
648 	matrix_t *matrix = cache_get_matrix(OBJ_DD);
649 
650 	return (get_matrix(matrix, dd_id, p, n));
651 }
652 
653 int
654 get_dds_matrix(
655 	const uint32_t dds_id,
656 	bmp_t **p,
657 	uint32_t *n
658 )
659 {
660 	matrix_t *matrix = cache_get_matrix(OBJ_DDS);
661 
662 	return (get_matrix(matrix, dds_id, p, n));
663 }
664 
665 /*ARGSUSED*/
666 static int
667 cb_get_dds_status(
668 	void *p1,
669 	void *p2
670 )
671 {
672 	isns_obj_t *obj = (isns_obj_t *)p1;
673 
674 	isns_attr_t *attr = &obj->attrs[
675 	    ATTR_INDEX_DDS(ISNS_DD_SET_STATUS_ATTR_ID)];
676 
677 	return (DDS_ENABLED(attr->value.ui) ? 1 : 0);
678 }
679 
680 static int
681 get_dds_status(
682 	uint32_t dds_id
683 )
684 {
685 	lookup_ctrl_t lc;
686 
687 	if (dds_id == 0) {
688 		return (0);
689 	}
690 
691 	SET_UID_LCP(&lc, OBJ_DDS, dds_id);
692 
693 	return (cache_lookup(&lc, NULL, cb_get_dds_status));
694 }
695 
696 int
697 is_dd_active(
698 	uint32_t dd_id
699 )
700 {
701 	int active = 0;
702 
703 	matrix_t *dds_matrix;
704 	uint32_t primary;
705 	uint32_t second;
706 	uint32_t x_info;
707 	bmp_t *bmp;
708 	int i;
709 
710 	if (dd_id == 0) {
711 		return (active);
712 	}
713 
714 	dds_matrix = cache_get_matrix(OBJ_DDS);
715 	primary = GET_PRIMARY(dd_id);
716 	second = GET_SECOND(dd_id);
717 
718 	if (primary < dds_matrix->x) {
719 		i = 0;
720 		while (i < dds_matrix->y) {
721 			bmp = MATRIX_X_UNIT(dds_matrix, i);
722 			x_info = MATRIX_X_INFO(bmp);
723 			if (x_info != 0 &&
724 			    TEST_MEMBERSHIP(bmp, primary, second) != 0) {
725 				if (get_dds_status(x_info) != 0) {
726 					active = 1;
727 					break;
728 				}
729 			}
730 			i ++;
731 		}
732 	}
733 
734 	return (active);
735 }
736 
737 int
738 get_scope(
739 	uchar_t *node_name,
740 	bmp_t **p,
741 	uint32_t *n
742 )
743 {
744 	int ec = 0;
745 
746 	lookup_ctrl_t lc;
747 	uint32_t uid;
748 
749 	matrix_t *dd_matrix;
750 	uint32_t primary;
751 	uint32_t second;
752 	uint32_t x_info;
753 	bmp_t *bmp;
754 	int i, j;
755 
756 	bmp_t *tmp_p;
757 	uint32_t tmp_n;
758 
759 	bmp_t *short_p;
760 	uint32_t short_n;
761 
762 	/* clear it */
763 	*p = NULL;
764 	*n = 0;
765 
766 	/* get the source object uid */
767 	lc.curr_uid = 0;
768 	lc.type = OBJ_ISCSI;
769 	lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID);
770 	lc.op[0] = OP_STRING;
771 	lc.data[0].ptr = node_name;
772 	lc.op[1] = 0;
773 
774 	uid = is_obj_there(&lc);
775 
776 	/* no such object */
777 	if (uid == 0) {
778 		return (ec);
779 	}
780 
781 	dd_matrix = cache_get_matrix(OBJ_DD);
782 	primary = GET_PRIMARY(uid);
783 	second = GET_SECOND(uid);
784 
785 	if (primary < dd_matrix->x) {
786 		i = 0;
787 		while (i < dd_matrix->y) {
788 			bmp = MATRIX_X_UNIT(dd_matrix, i);
789 			x_info = MATRIX_X_INFO(bmp);
790 			if (ec == 0 && x_info != 0 &&
791 			    TEST_MEMBERSHIP(bmp, primary, second) != 0) {
792 				if (is_dd_active(x_info) != 0 &&
793 				    (ec = get_dd_matrix(x_info,
794 				    &tmp_p, &tmp_n)) == 0) {
795 					if (*p == NULL) {
796 						*p = tmp_p;
797 						*n = tmp_n;
798 					} else {
799 						if (*n >= tmp_n) {
800 							short_p = tmp_p;
801 							short_n = tmp_n;
802 						} else {
803 							short_p = *p;
804 							short_n = *n;
805 							*p = tmp_p;
806 							*n = tmp_n;
807 						}
808 						j = 0;
809 						while (j < short_n) {
810 							(*p)[j] |= short_p[j];
811 							j ++;
812 						}
813 						free(short_p);
814 					}
815 				}
816 			}
817 			i ++;
818 		}
819 	}
820 
821 	primary ++;
822 	if (ec == 0 && *p == NULL) {
823 		*p = (bmp_t *)calloc(primary, sizeof (bmp_t));
824 		if (*p != NULL) {
825 			*n = primary;
826 		} else {
827 			*n = 0;
828 			ec = ISNS_RSP_INTERNAL_ERROR;
829 		}
830 	}
831 
832 	if (*p != NULL) {
833 		(*p)[primary - 1] |= (1 << second);
834 	}
835 
836 	return (ec);
837 }
838 
839 int
840 cb_clone_attrs(
841 	void *p1,
842 	void *p2
843 )
844 {
845 	int ec = 0;
846 
847 	isns_obj_t *obj = (isns_obj_t *)p1;
848 	lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2;
849 
850 	isns_attr_t *attr;
851 
852 	int i = 1;
853 
854 	while (i < MAX_LOOKUP_CTRL &&
855 	    lcp->op[i] != 0) {
856 		i ++;
857 	}
858 
859 	while (ec == 0 &&
860 	    i < MAX_LOOKUP_CTRL &&
861 	    lcp->id[i] != 0) {
862 		switch (lcp->id[i]) {
863 		case ISNS_ISCSI_NAME_ATTR_ID:
864 			attr = &obj->attrs[ATTR_INDEX_ISCSI(
865 			    ISNS_ISCSI_NAME_ATTR_ID)];
866 			lcp->data[i].ptr = (uchar_t *)malloc(attr->len);
867 			if (lcp->data[i].ptr != NULL) {
868 				(void) strcpy((char *)lcp->data[i].ptr,
869 				    (char *)attr->value.ptr);
870 			} else {
871 				/* memory exhausted */
872 				ec = ISNS_RSP_INTERNAL_ERROR;
873 			}
874 			break;
875 		case ISNS_ISCSI_NODE_TYPE_ATTR_ID:
876 			attr = &obj->attrs[ATTR_INDEX_ISCSI(
877 			    ISNS_ISCSI_NODE_TYPE_ATTR_ID)];
878 			lcp->data[i].ui = attr->value.ui;
879 			break;
880 		case ISNS_PG_ISCSI_NAME_ATTR_ID:
881 			attr = &obj->attrs[ATTR_INDEX_PG(
882 			    ISNS_PG_ISCSI_NAME_ATTR_ID)];
883 			lcp->data[i].ptr = (uchar_t *)malloc(attr->len);
884 			if (lcp->data[i].ptr != NULL) {
885 				(void) strcpy((char *)lcp->data[i].ptr,
886 				    (char *)attr->value.ptr);
887 			} else {
888 				/* memory exhausted */
889 				ec = ISNS_RSP_INTERNAL_ERROR;
890 			}
891 			break;
892 		case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
893 			attr = &obj->attrs[ATTR_INDEX_PG(
894 			    ISNS_PG_PORTAL_IP_ADDR_ATTR_ID)];
895 			lcp->data[i].ip = (in6_addr_t *)malloc(attr->len);
896 			if (lcp->data[i].ip != NULL) {
897 				(void) memcpy(lcp->data[i].ip,
898 				    attr->value.ip, attr->len);
899 			} else {
900 				/* memory exhausted */
901 				ec = ISNS_RSP_INTERNAL_ERROR;
902 			}
903 			break;
904 		case ISNS_PG_PORTAL_PORT_ATTR_ID:
905 			attr = &obj->attrs[ATTR_INDEX_PG(
906 			    ISNS_PG_PORTAL_PORT_ATTR_ID)];
907 			lcp->data[i].ui = attr->value.ui;
908 			break;
909 		case ISNS_PORTAL_IP_ADDR_ATTR_ID:
910 			attr = &obj->attrs[ATTR_INDEX_PORTAL(
911 			    ISNS_PORTAL_IP_ADDR_ATTR_ID)];
912 			lcp->data[i].ip = (in6_addr_t *)malloc(attr->len);
913 			if (lcp->data[i].ip != NULL) {
914 				(void) memcpy(lcp->data[i].ip,
915 				    attr->value.ip, attr->len);
916 			} else {
917 				/* memory exhausted */
918 				ec = ISNS_RSP_INTERNAL_ERROR;
919 			}
920 			break;
921 		case ISNS_PORTAL_PORT_ATTR_ID:
922 		case ISNS_ESI_PORT_ATTR_ID:
923 			attr = &obj->attrs[ATTR_INDEX_PORTAL(lcp->id[i])];
924 			if (attr->tag != 0 && attr->value.ui != 0) {
925 				lcp->data[i].ui = attr->value.ui;
926 			} else {
927 				lcp->data[i].ui = 0;
928 			}
929 			break;
930 		default:
931 			ASSERT(0);
932 			lcp->data[i].ui = 0;
933 			break;
934 		}
935 		i ++;
936 	}
937 
938 	return (ec);
939 }
940 
941 static matrix_t *
942 new_matrix(
943 	uint32_t x,
944 	uint32_t y
945 )
946 {
947 	matrix_t *matrix;
948 
949 	matrix = (matrix_t *)malloc(sizeof (matrix_t));
950 	if (matrix != NULL) {
951 		matrix->x = x;
952 		matrix->y = y;
953 		matrix->m = (bmp_t *)calloc(y, SIZEOF_X_UNIT(matrix));
954 		if (matrix->m == NULL) {
955 			free(matrix);
956 			matrix = NULL;
957 		}
958 	}
959 
960 	return (matrix);
961 }
962 
963 int
964 dd_matrix_init(
965 	struct cache *c
966 )
967 {
968 	matrix_t *x;
969 	bmp_t *bmp;
970 	uint32_t primary;
971 	uint32_t second;
972 
973 	/*
974 	 * allocate an array of pointer for dd and dd-set matrix.
975 	 */
976 	c->x = (matrix_t **)calloc(2, sizeof (matrix_t *));
977 	if (c->x == NULL) {
978 		return (1);
979 	}
980 
981 	/*
982 	 * create dd matrix.
983 	 */
984 	x = new_matrix(8, 64);
985 	if (x != NULL) {
986 		x->c = c;
987 		c->x[0] = x;
988 	} else {
989 		return (1);
990 	}
991 
992 	/*
993 	 * Mark the first array on the y axis for Default DD.
994 	 */
995 	bmp = MATRIX_X_UNIT(x, 0);
996 	MATRIX_X_INFO(bmp) = ISNS_DEFAULT_DD_ID;
997 
998 	/*
999 	 * create dd set matrix.
1000 	 */
1001 	x = new_matrix(2, 16);
1002 	if (x != NULL) {
1003 		x->c = c;
1004 		c->x[1] = x;
1005 	} else {
1006 		return (1);
1007 	}
1008 
1009 	/*
1010 	 * Mark the first array on the y axis for Default DD-set.
1011 	 */
1012 	bmp = MATRIX_X_UNIT(x, 0);
1013 	MATRIX_X_INFO(bmp) = ISNS_DEFAULT_DD_SET_ID;
1014 
1015 	/*
1016 	 * Add Default DD as a member of Default DD-set.
1017 	 */
1018 	primary = GET_PRIMARY(ISNS_DEFAULT_DD_ID);
1019 	second = GET_SECOND(ISNS_DEFAULT_DD_ID);
1020 	SET_MEMBERSHIP(bmp, primary, second);
1021 
1022 	return (0);
1023 }
1024 
1025 static uint32_t
1026 get_ds_id(
1027 	matrix_t *matrix,
1028 	uint32_t m_id,
1029 	uint32_t curr_id
1030 )
1031 {
1032 	bmp_t *bmp;
1033 	uint32_t primary = GET_PRIMARY(m_id);
1034 	uint32_t second = GET_SECOND(m_id);
1035 	uint32_t dd_id = 0;
1036 	uint32_t uid;
1037 	int i = 0;
1038 
1039 	if (matrix->x > primary) {
1040 		while (i < matrix->y) {
1041 			bmp = MATRIX_X_UNIT(matrix, i);
1042 			uid = MATRIX_X_INFO(bmp);
1043 			if (uid > curr_id &&
1044 			    TEST_MEMBERSHIP(bmp, primary, second) != 0) {
1045 				if (dd_id == 0 || uid < dd_id) {
1046 					dd_id = uid;
1047 				}
1048 			}
1049 			i ++;
1050 		}
1051 	}
1052 
1053 	return (dd_id);
1054 }
1055 
1056 uint32_t
1057 get_common_dd(
1058 	uint32_t m_id1,
1059 	uint32_t m_id2,
1060 	uint32_t curr_id
1061 )
1062 {
1063 	matrix_t *matrix;
1064 
1065 	bmp_t *bmp;
1066 	uint32_t primary1 = GET_PRIMARY(m_id1);
1067 	uint32_t second1 = GET_SECOND(m_id1);
1068 	uint32_t primary2 = GET_PRIMARY(m_id2);
1069 	uint32_t second2 = GET_SECOND(m_id2);
1070 	uint32_t dd_id = 0;
1071 	int i = 0;
1072 
1073 	matrix = cache_get_matrix(OBJ_DD);
1074 
1075 	if (matrix->x > primary1 && matrix->x > primary2) {
1076 		while (i < matrix->y) {
1077 			bmp = MATRIX_X_UNIT(matrix, i);
1078 			if (MATRIX_X_INFO(bmp) > curr_id &&
1079 			    TEST_MEMBERSHIP(bmp, primary1, second1) != 0 &&
1080 			    TEST_MEMBERSHIP(bmp, primary2, second2) != 0) {
1081 				dd_id = MATRIX_X_INFO(bmp);
1082 				break;
1083 			}
1084 			i ++;
1085 		}
1086 	}
1087 
1088 	return (dd_id);
1089 }
1090 
1091 uint32_t
1092 get_dd_id(
1093 	uint32_t m_id,
1094 	uint32_t curr_id
1095 )
1096 {
1097 	matrix_t *matrix = cache_get_matrix(OBJ_DD);
1098 
1099 	return (get_ds_id(matrix, m_id, curr_id));
1100 }
1101 
1102 uint32_t
1103 get_dds_id(
1104 	uint32_t m_id,
1105 	uint32_t curr_id
1106 )
1107 {
1108 	matrix_t *matrix = cache_get_matrix(OBJ_DDS);
1109 
1110 	return (get_ds_id(matrix, m_id, curr_id));
1111 }
1112 
1113 static int
1114 create_ds_object(
1115 	isns_type_t type,
1116 	isns_obj_t **ds_p,
1117 	isns_attr_t *name_attr,
1118 	isns_attr_t *uid_attr,
1119 	isns_attr_t *status_attr
1120 )
1121 {
1122 	int ec = 0;
1123 
1124 	isns_obj_t *obj;
1125 	int id1, id2, id3;
1126 
1127 	if (type == OBJ_DD) {
1128 		id1 = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID);
1129 		id2 = ATTR_INDEX_DD(ISNS_DD_ID_ATTR_ID);
1130 		id3 = ATTR_INDEX_DD(ISNS_DD_FEATURES_ATTR_ID);
1131 	} else {
1132 		ASSERT(type == OBJ_DDS);
1133 		id1 = ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID);
1134 		id2 = ATTR_INDEX_DDS(ISNS_DD_SET_ID_ATTR_ID);
1135 		id3 = ATTR_INDEX_DDS(ISNS_DD_SET_STATUS_ATTR_ID);
1136 	}
1137 
1138 	obj = obj_calloc(type);
1139 	if (obj != NULL &&
1140 	    (name_attr != NULL && name_attr->tag != 0 &&
1141 	    assign_attr(&obj->attrs[id1], name_attr) == 0) &&
1142 	    (uid_attr == NULL || uid_attr->value.ui == 0 ||
1143 	    assign_attr(&obj->attrs[id2], uid_attr) == 0) &&
1144 	    (status_attr == NULL || status_attr->value.ui == 0 ||
1145 	    assign_attr(&obj->attrs[id3], status_attr) == 0)) {
1146 		*ds_p = obj;
1147 	} else {
1148 		/* no memory */
1149 		free_object(obj);
1150 		ec = ISNS_RSP_INTERNAL_ERROR;
1151 	}
1152 
1153 	return (ec);
1154 }
1155 
1156 int
1157 create_dd_object(
1158 	isns_tlv_t *op,
1159 	uint16_t op_len,
1160 	isns_obj_t **dd_p
1161 )
1162 {
1163 	int ec = 0;
1164 	uint8_t *value;
1165 	isns_attr_t name = { 0 };
1166 	isns_attr_t dd_id = { 0 }, features = { 0 };
1167 
1168 	name.tag = ISNS_DD_NAME_ATTR_ID;
1169 
1170 	while (op_len > 8 && ec == 0) {
1171 		value = &op->attr_value[0];
1172 		switch (op->attr_id) {
1173 		case ISNS_DD_ID_ATTR_ID:
1174 			if (op->attr_len == 4) {
1175 				dd_id.tag = ISNS_DD_ID_ATTR_ID;
1176 				dd_id.len = 4;
1177 				dd_id.value.ui = ntohl(*(uint32_t *)value);
1178 			} else if (op->attr_len != 0) {
1179 				ec = ISNS_RSP_MSG_FORMAT_ERROR;
1180 			}
1181 			break;
1182 		case ISNS_DD_NAME_ATTR_ID:
1183 			if (op->attr_len > 0 &&
1184 			    op->attr_len <= 256) {
1185 				name.len = op->attr_len;
1186 				name.value.ptr = (uchar_t *)value;
1187 			} else if (op->attr_len != 0) {
1188 				ec = ISNS_RSP_MSG_FORMAT_ERROR;
1189 			}
1190 			break;
1191 		case ISNS_DD_ISCSI_INDEX_ATTR_ID:
1192 		case ISNS_DD_ISCSI_NAME_ATTR_ID:
1193 			break;
1194 		case ISNS_DD_FC_PORT_NAME_ATTR_ID:
1195 		case ISNS_DD_PORTAL_INDEX_ATTR_ID:
1196 		case ISNS_DD_PORTAL_IP_ADDR_ATTR_ID:
1197 		case ISNS_DD_PORTAL_PORT_ATTR_ID:
1198 			ec = ISNS_RSP_REGIS_NOT_SUPPORTED;
1199 			break;
1200 		case ISNS_DD_FEATURES_ATTR_ID:
1201 			if (op->attr_len == 4) {
1202 				features.tag = ISNS_DD_FEATURES_ATTR_ID;
1203 				features.len = op->attr_len;
1204 				features.value.ui = ntohl(*(uint32_t *)value);
1205 			} else if (op->attr_len != 0) {
1206 				ec = ISNS_RSP_MSG_FORMAT_ERROR;
1207 			}
1208 			break;
1209 		default:
1210 			ec = ISNS_RSP_INVALID_REGIS;
1211 			break;
1212 		}
1213 		NEXT_TLV(op, op_len);
1214 	}
1215 
1216 	if (ec == 0) {
1217 		ec = create_ds_object(OBJ_DD, dd_p,
1218 		    &name, &dd_id, &features);
1219 	}
1220 
1221 	return (ec);
1222 }
1223 
1224 int
1225 create_dds_object(
1226 	isns_tlv_t *op,
1227 	uint16_t op_len,
1228 	isns_obj_t **dds_p
1229 )
1230 {
1231 	int ec = 0;
1232 	uint8_t *value;
1233 	isns_attr_t name = { 0 };
1234 	isns_attr_t dds_id = { 0 }, code = { 0 };
1235 
1236 	name.tag = ISNS_DD_SET_NAME_ATTR_ID;
1237 
1238 	while (op_len > 8 && ec == 0) {
1239 		value = &op->attr_value[0];
1240 		switch (op->attr_id) {
1241 		case ISNS_DD_SET_ID_ATTR_ID:
1242 			if (op->attr_len == 4) {
1243 				dds_id.tag = ISNS_DD_ID_ATTR_ID;
1244 				dds_id.len = 4;
1245 				dds_id.value.ui = ntohl(*(uint32_t *)value);
1246 			} else if (op->attr_len != 0) {
1247 				ec = ISNS_RSP_MSG_FORMAT_ERROR;
1248 			}
1249 			break;
1250 		case ISNS_DD_SET_NAME_ATTR_ID:
1251 			if (op->attr_len > 0 &&
1252 			    op->attr_len <= 256) {
1253 				name.len = op->attr_len;
1254 				name.value.ptr = (uchar_t *)value;
1255 			} else if (op->attr_len != 0) {
1256 				ec = ISNS_RSP_MSG_FORMAT_ERROR;
1257 			}
1258 			break;
1259 		case ISNS_DD_SET_STATUS_ATTR_ID:
1260 			if (op->attr_len == 4) {
1261 				code.tag = ISNS_DD_SET_STATUS_ATTR_ID;
1262 				code.len = op->attr_len;
1263 				code.value.ui = ntohl(*(uint32_t *)value);
1264 			} else if (op->attr_len != 0) {
1265 				ec = ISNS_RSP_MSG_FORMAT_ERROR;
1266 			}
1267 			break;
1268 		case ISNS_DD_ID_ATTR_ID:
1269 			break;
1270 		default:
1271 			ec = ISNS_RSP_INVALID_REGIS;
1272 			break;
1273 		}
1274 		NEXT_TLV(op, op_len);
1275 	}
1276 
1277 	if (ec == 0) {
1278 		ec = create_ds_object(OBJ_DDS, dds_p,
1279 		    &name, &dds_id, &code);
1280 	}
1281 
1282 	return (ec);
1283 }
1284 
1285 int
1286 adm_create_dd(
1287 	isns_obj_t **dd_p,
1288 	uchar_t *name,
1289 	uint32_t uid,
1290 	uint32_t features
1291 )
1292 {
1293 	uint32_t len;
1294 	isns_attr_t name_attr = { 0 };
1295 	isns_attr_t uid_attr = { 0 };
1296 	isns_attr_t features_attr = { 0 };
1297 
1298 	name_attr.tag = ISNS_DD_NAME_ATTR_ID;
1299 	if (name != NULL) {
1300 		/* need to include the null terminator */
1301 		/* and be on 4 bytes aligned */
1302 		len = strlen((char *)name) + 1;
1303 		len += 4 - (len % 4);
1304 		name_attr.len = len;
1305 		name_attr.value.ptr = name;
1306 	}
1307 
1308 	uid_attr.tag = ISNS_DD_ID_ATTR_ID;
1309 	uid_attr.len = 4;
1310 	uid_attr.value.ui = uid;
1311 
1312 	features_attr.tag = ISNS_DD_FEATURES_ATTR_ID;
1313 	features_attr.len = 4;
1314 	features_attr.value.ui = features;
1315 
1316 	return (create_ds_object(OBJ_DD, dd_p,
1317 	    &name_attr, &uid_attr, &features_attr));
1318 }
1319 
1320 int
1321 adm_create_dds(
1322 	isns_obj_t **dds_p,
1323 	uchar_t *name,
1324 	uint32_t uid,
1325 	uint32_t code
1326 )
1327 {
1328 	uint32_t len;
1329 	isns_attr_t name_attr = { 0 };
1330 	isns_attr_t uid_attr = { 0 };
1331 	isns_attr_t code_attr = { 0 };
1332 
1333 	name_attr.tag = ISNS_DD_SET_NAME_ATTR_ID;
1334 	if (name != NULL) {
1335 		/* need to include the null terminator */
1336 		/* and be on 4 bytes aligned */
1337 		len = strlen((char *)name) + 1;
1338 		len += 4 - (len % 4);
1339 		name_attr.len = len;
1340 		name_attr.value.ptr = name;
1341 	}
1342 
1343 	uid_attr.tag = ISNS_DD_SET_ID_ATTR_ID;
1344 	uid_attr.len = 4;
1345 	uid_attr.value.ui = uid;
1346 
1347 	code_attr.tag = ISNS_DD_SET_STATUS_ATTR_ID;
1348 	code_attr.len = 4;
1349 	code_attr.value.ui = code;
1350 
1351 	return (create_ds_object(OBJ_DDS, dds_p,
1352 	    &name_attr, &uid_attr, &code_attr));
1353 }
1354 
1355 static int
1356 update_ds_name(
1357 	isns_type_t type,
1358 	uint32_t uid,
1359 	uint32_t tag,
1360 	uint32_t len,
1361 	uchar_t *name
1362 )
1363 {
1364 	int ec = 0;
1365 
1366 	lookup_ctrl_t lc;
1367 
1368 	SET_UID_LCP(&lc, type, uid);
1369 
1370 	lc.id[1] = tag;
1371 	lc.data[1].ui = len;
1372 	lc.data[2].ptr = name;
1373 
1374 	ec = cache_rekey(&lc, &uid, cb_update_ds_attr);
1375 	if (uid == 0) {
1376 		ec = ISNS_RSP_INVALID_REGIS;
1377 	}
1378 
1379 	return (ec);
1380 }
1381 
1382 int
1383 update_dd_name(
1384 	uint32_t uid,
1385 	uint32_t len,
1386 	uchar_t *name
1387 )
1388 {
1389 	/*
1390 	 * We do now allow changing the default DD and DD-set name.
1391 	 */
1392 	if (uid == ISNS_DEFAULT_DD_ID) {
1393 		return (ISNS_RSP_OPTION_NOT_UNDERSTOOD);
1394 	}
1395 
1396 	return (update_ds_name(OBJ_DD, uid, ISNS_DD_NAME_ATTR_ID, len, name));
1397 }
1398 
1399 int
1400 update_dds_name(
1401 	uint32_t uid,
1402 	uint32_t len,
1403 	uchar_t *name
1404 )
1405 {
1406 	/*
1407 	 * We do now allow changing the default DD and DD-set name.
1408 	 */
1409 	if (uid == ISNS_DEFAULT_DD_ID) {
1410 		return (ISNS_RSP_OPTION_NOT_UNDERSTOOD);
1411 	}
1412 
1413 	return (update_ds_name(OBJ_DDS, uid,
1414 	    ISNS_DD_SET_NAME_ATTR_ID, len, name));
1415 }
1416 
1417 static int
1418 update_ds_uint32(
1419 	isns_type_t type,
1420 	uint32_t uid,
1421 	uint32_t tag,
1422 	uint32_t value
1423 )
1424 {
1425 	int ec = 0;
1426 
1427 	lookup_ctrl_t lc;
1428 
1429 	SET_UID_LCP(&lc, type, uid);
1430 
1431 	lc.id[1] = tag;
1432 	lc.data[1].ui = value;
1433 
1434 	ec = cache_lookup(&lc, &uid, cb_update_ds_attr);
1435 	if (uid == 0) {
1436 		ec = ISNS_RSP_INVALID_REGIS;
1437 	}
1438 
1439 	return (ec);
1440 }
1441 
1442 int
1443 update_dd_features(
1444 	uint32_t uid,
1445 	uint32_t features
1446 )
1447 {
1448 	return (update_ds_uint32(OBJ_DD, uid,
1449 	    ISNS_DD_FEATURES_ATTR_ID, features));
1450 }
1451 
1452 int
1453 update_dds_status(
1454 	uint32_t uid,
1455 	uint32_t enabled
1456 )
1457 {
1458 	return (update_ds_uint32(OBJ_DDS, uid,
1459 	    ISNS_DD_SET_STATUS_ATTR_ID, enabled));
1460 }
1461 
1462 int
1463 add_dd_member(
1464 	isns_obj_t *assoc
1465 )
1466 {
1467 	int ec = 0;
1468 
1469 	uint32_t dd_id;
1470 	uint32_t m_id, m_type;
1471 
1472 	dd_id = get_parent_uid(assoc);
1473 	/*
1474 	 * We do now allow placing any node to the default DD explicitly.
1475 	 */
1476 	if (dd_id == ISNS_DEFAULT_DD_ID) {
1477 		return (ISNS_RSP_OPTION_NOT_UNDERSTOOD);
1478 	}
1479 
1480 	ec = get_member_info(assoc, &m_type, &m_id, 1);
1481 	if (ec == 0) {
1482 		ec = update_dd_matrix(
1483 		    '+', /* add member */
1484 		    dd_id,
1485 		    m_type,
1486 		    m_id);
1487 	}
1488 
1489 	if (ec == 0) {
1490 		if (sys_q != NULL) {
1491 			/* add the membership to data store */
1492 			ec = write_data(DATA_ADD, assoc);
1493 		}
1494 
1495 		/* trigger a management scn */
1496 		if (ec == 0 && scn_q != NULL) {
1497 			(void) make_scn(ISNS_MEMBER_ADDED, assoc);
1498 		}
1499 	}
1500 
1501 	return (ec);
1502 }
1503 
1504 int
1505 add_dds_member(
1506 	isns_obj_t *assoc
1507 )
1508 {
1509 	int ec = 0;
1510 
1511 	uint32_t m_id = assoc->attrs[ATTR_INDEX_ASSOC_DD(
1512 	    ISNS_DD_ID_ATTR_ID)].value.ui;
1513 	uint32_t dds_id;
1514 
1515 	dds_id = get_parent_uid(assoc);
1516 	/*
1517 	 * We do now allow changing the membership of the default DD
1518 	 * and DD-set.
1519 	 */
1520 	if (dds_id == ISNS_DEFAULT_DD_SET_ID ||
1521 	    m_id == ISNS_DEFAULT_DD_ID) {
1522 		return (ISNS_RSP_OPTION_NOT_UNDERSTOOD);
1523 	}
1524 
1525 	ec = get_dds_member_info(m_id);
1526 	if (ec == 0) {
1527 		ec = update_dds_matrix(
1528 		    '+', /* add member */
1529 		    dds_id,
1530 		    m_id);
1531 	}
1532 
1533 	if (ec == 0) {
1534 		if (sys_q != NULL) {
1535 			/* add the membership to data store */
1536 			ec = write_data(DATA_ADD, assoc);
1537 		}
1538 
1539 		/* trigger a management scn */
1540 		if (ec == 0 && scn_q != NULL) {
1541 			(void) make_scn(ISNS_MEMBER_ADDED, assoc);
1542 		}
1543 	}
1544 
1545 	return (ec);
1546 }
1547 
1548 int
1549 remove_dd_member(
1550 	isns_obj_t *assoc
1551 )
1552 {
1553 	int ec = 0;
1554 
1555 	uint32_t dd_id;
1556 	uint32_t m_type;
1557 	uint32_t m_id;
1558 
1559 	lookup_ctrl_t lc;
1560 
1561 	dd_id = get_parent_uid(assoc);
1562 	/*
1563 	 * We do now allow removing the member from default DD explicitly.
1564 	 */
1565 	if (dd_id == ISNS_DEFAULT_DD_ID) {
1566 		return (ISNS_RSP_OPTION_NOT_UNDERSTOOD);
1567 	}
1568 
1569 	ec = get_member_info(assoc, &m_type, &m_id, 0);
1570 	if (ec == 0) {
1571 		ec = update_dd_matrix(
1572 		    '-', /* remove member */
1573 		    dd_id,
1574 		    m_type,
1575 		    m_id);
1576 		if (ec == 0) {
1577 			/* update data store */
1578 			if (sys_q != NULL) {
1579 				/* remove it from data store */
1580 				ec = write_data(
1581 				    DATA_DELETE_ASSOC, assoc);
1582 			}
1583 
1584 			/* trigger a management scn */
1585 			if (ec == 0 && scn_q != NULL) {
1586 				(void) make_scn(ISNS_MEMBER_REMOVED, assoc);
1587 			}
1588 
1589 			/* remove it from object container if */
1590 			/* it is not a registered object */
1591 			if (ec == 0) {
1592 				SET_UID_LCP(&lc, m_type, m_id);
1593 				ec = dereg_assoc(&lc);
1594 			}
1595 		}
1596 	}
1597 
1598 	return (ec);
1599 }
1600 
1601 int
1602 remove_dds_member(
1603 	uint32_t dds_id,
1604 	uint32_t m_id
1605 )
1606 {
1607 	int ec = 0;
1608 
1609 	isns_obj_t *clone;
1610 
1611 	/*
1612 	 * We do now allow removing the member from default DD-set.
1613 	 */
1614 	if (dds_id == ISNS_DEFAULT_DD_SET_ID) {
1615 		return (ISNS_RSP_OPTION_NOT_UNDERSTOOD);
1616 	}
1617 
1618 	if (m_id != 0) {
1619 		ec = update_dds_matrix(
1620 		    '-', /* remove member */
1621 		    dds_id,
1622 		    m_id);
1623 		if (ec == 0) {
1624 			clone = obj_calloc(OBJ_ASSOC_DD);
1625 			if (clone != NULL) {
1626 				(void) set_obj_uid((void *)clone, m_id);
1627 				(void) set_parent_obj(clone, dds_id);
1628 			}
1629 			/* update data store */
1630 			if (sys_q != NULL) {
1631 				if (clone != NULL) {
1632 					/* remove it from data store */
1633 					ec = write_data(
1634 					    DATA_DELETE_ASSOC, clone);
1635 				} else {
1636 					ec = ISNS_RSP_INTERNAL_ERROR;
1637 				}
1638 			}
1639 
1640 			/* trigger a management scn */
1641 			if (ec == 0 &&
1642 			    scn_q != NULL &&
1643 			    clone != NULL) {
1644 				(void) make_scn(ISNS_MEMBER_REMOVED, clone);
1645 			}
1646 			free_object(clone);
1647 		}
1648 	}
1649 
1650 	return (ec);
1651 }
1652 
1653 static int
1654 remove_member_wildchar(
1655 	matrix_t *matrix,
1656 	uint32_t m_id
1657 )
1658 {
1659 	int ec = 0;
1660 
1661 	bmp_t *bmp;
1662 	uint32_t x_info;
1663 	int i;
1664 
1665 	uint32_t primary = GET_PRIMARY(m_id);
1666 	uint32_t second = GET_SECOND(m_id);
1667 
1668 	isns_obj_t *clone;
1669 
1670 	if (primary >= matrix->x) {
1671 		return (ec);
1672 	}
1673 
1674 	i = 0;
1675 	while (ec == 0 && i < matrix->y) {
1676 		bmp = MATRIX_X_UNIT(matrix, i);
1677 		x_info = MATRIX_X_INFO(bmp);
1678 		if (x_info != 0 &&
1679 		    TEST_MEMBERSHIP(bmp, primary, second) != 0) {
1680 			/* clean the membership */
1681 			CLEAR_MEMBERSHIP(bmp, primary, second);
1682 			/* update data store */
1683 			if (sys_q != NULL) {
1684 				clone = obj_calloc(OBJ_ASSOC_DD);
1685 				if (clone != NULL) {
1686 					(void) set_obj_uid((void *)clone, m_id);
1687 					(void) set_parent_obj(clone, x_info);
1688 					/* remove it from data store */
1689 					ec = write_data(
1690 					    DATA_DELETE_ASSOC, clone);
1691 					free_object(clone);
1692 				} else {
1693 					ec = ISNS_RSP_INTERNAL_ERROR;
1694 				}
1695 			}
1696 		}
1697 		i ++;
1698 	}
1699 
1700 	return (ec);
1701 }
1702 
1703 int
1704 remove_dd_object(
1705 	uint32_t dd_id
1706 )
1707 {
1708 	matrix_t *dds_matrix;
1709 
1710 	bmp_t *p;
1711 	uint32_t n;
1712 	int ec;
1713 
1714 	lookup_ctrl_t lc;
1715 	uint32_t uid;
1716 
1717 	/*
1718 	 * We do now allow removing the default DD.
1719 	 */
1720 	if (dd_id == ISNS_DEFAULT_DD_ID) {
1721 		return (ISNS_RSP_OPTION_NOT_UNDERSTOOD);
1722 	}
1723 
1724 	SET_UID_LCP(&lc, OBJ_DD, dd_id);
1725 
1726 	/* de-register the object at first */
1727 	ec = dereg_object(&lc, 0);
1728 
1729 	/* clear it from all of dd-set */
1730 	dds_matrix = cache_get_matrix(OBJ_DDS);
1731 	(void) remove_member_wildchar(dds_matrix, dd_id);
1732 
1733 	/* clear its member bitmap */
1734 	(void) clear_dd_matrix(dd_id, &p, &n);
1735 
1736 	/* deregister the member nodes which are not-registered node */
1737 	/* and have no longer membership in other DD(s). */
1738 	if (p != NULL) {
1739 		SET_UID_LCP(&lc, OBJ_ISCSI, 0);
1740 		FOR_EACH_MEMBER(p, n, uid, {
1741 			lc.data[0].ui = uid;
1742 			(void) dereg_assoc(&lc);
1743 		});
1744 		free(p);
1745 	}
1746 
1747 	return (ec);
1748 }
1749 
1750 int
1751 remove_dds_object(
1752 	uint32_t dds_id
1753 )
1754 {
1755 	int ec;
1756 
1757 	lookup_ctrl_t lc;
1758 
1759 	/*
1760 	 * We do now allow removing the default DD-set.
1761 	 */
1762 	if (dds_id == ISNS_DEFAULT_DD_SET_ID) {
1763 		return (ISNS_RSP_OPTION_NOT_UNDERSTOOD);
1764 	}
1765 
1766 	(void) clear_dds_matrix(dds_id);
1767 
1768 	SET_UID_LCP(&lc, OBJ_DDS, dds_id);
1769 
1770 	ec = dereg_object(&lc, 0);
1771 
1772 	return (ec);
1773 }
1774 
1775 int
1776 update_ddd(
1777 	void *p,
1778 	const uchar_t op
1779 )
1780 {
1781 	isns_obj_t *obj;
1782 	uint32_t uid;
1783 
1784 	matrix_t *matrix;
1785 
1786 	obj = (isns_obj_t *)p;
1787 	if (obj->type != OBJ_ISCSI) {
1788 		return (0);
1789 	}
1790 
1791 	matrix = cache_get_matrix(OBJ_DD);
1792 	uid = get_obj_uid(obj);
1793 
1794 	return (update_matrix(matrix, op, ISNS_DEFAULT_DD_ID, uid, 0));
1795 }
1796 
1797 int
1798 verify_ddd(
1799 )
1800 {
1801 	int ec = 0;
1802 
1803 	lookup_ctrl_t lc;
1804 	isns_obj_t *obj;
1805 
1806 	uchar_t *name;
1807 	uint32_t uid;
1808 	uint32_t features;
1809 	uint32_t code;
1810 
1811 	/* Ensure the Default DD is registered. */
1812 	uid = ISNS_DEFAULT_DD_ID;
1813 
1814 	SET_UID_LCP(&lc, OBJ_DD, uid);
1815 
1816 	(void) cache_lock_write();
1817 
1818 	if (is_obj_there(&lc) == 0) {
1819 		name = (uchar_t *)DEFAULT_DD_NAME;
1820 		features = DEFAULT_DD_FEATURES;
1821 		ec = adm_create_dd(&obj, name, uid, features);
1822 		if (ec == 0) {
1823 			ec = register_object(obj, NULL, NULL);
1824 			if (ec != 0) {
1825 				free_object(obj);
1826 				goto verify_done;
1827 			}
1828 		} else {
1829 			goto verify_done;
1830 		}
1831 	}
1832 
1833 	/* Ensure the Default DD-set is registered. */
1834 	uid = ISNS_DEFAULT_DD_SET_ID;
1835 
1836 	SET_UID_LCP(&lc, OBJ_DDS, uid);
1837 
1838 	if (is_obj_there(&lc) == 0) {
1839 		name = (uchar_t *)DEFAULT_DD_SET_NAME;
1840 		code = DEFAULT_DD_SET_STATUS;
1841 		ec = adm_create_dds(&obj, name, uid, code);
1842 		if (ec == 0) {
1843 			ec = register_object(obj, NULL, NULL);
1844 			if (ec != 0) {
1845 				free_object(obj);
1846 			}
1847 		}
1848 	}
1849 
1850 verify_done:
1851 
1852 	ec = cache_unlock_sync(ec);
1853 
1854 	return (ec);
1855 }
1856