xref: /illumos-gate/usr/src/uts/common/io/comstar/stmf/lun_map.c (revision f34e64d88f694155255ac1c93990904dbfa28af3)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <sys/conf.h>
26 #include <sys/file.h>
27 #include <sys/ddi.h>
28 #include <sys/sunddi.h>
29 #include <sys/modctl.h>
30 #include <sys/scsi/scsi.h>
31 #include <sys/scsi/impl/scsi_reset_notify.h>
32 #include <sys/disp.h>
33 #include <sys/byteorder.h>
34 #include <sys/atomic.h>
35 
36 #include <sys/stmf.h>
37 #include <sys/lpif.h>
38 #include <sys/portif.h>
39 #include <sys/stmf_ioctl.h>
40 
41 #include "stmf_impl.h"
42 #include "lun_map.h"
43 #include "stmf_state.h"
44 
45 void stmf_update_sessions_per_ve(stmf_view_entry_t *ve,
46 		stmf_lu_t *lu, int action);
47 void stmf_add_lus_to_session_per_vemap(stmf_i_local_port_t *ilport,
48 		stmf_i_scsi_session_t *iss, stmf_lun_map_t *vemap);
49 stmf_id_data_t *stmf_lookup_group_for_host(uint8_t *ident, uint16_t ident_size);
50 static stmf_status_t stmf_add_ent_to_map(stmf_lun_map_t *sm, void *ent,
51     uint8_t *lun);
52 static stmf_status_t stmf_remove_ent_from_map(stmf_lun_map_t *sm, uint8_t *lun);
53 uint16_t stmf_get_next_free_lun(stmf_lun_map_t *sm, uint8_t *lun);
54 stmf_status_t stmf_add_tg(uint8_t *tg_name, uint16_t tg_name_size,
55 		int allow_special, uint32_t *err_detail);
56 stmf_status_t stmf_add_hg(uint8_t *hg_name, uint16_t hg_name_size,
57 		int allow_special, uint32_t *err_detail);
58 stmf_i_local_port_t *stmf_targetident_to_ilport(uint8_t *target_ident,
59 		uint16_t ident_size);
60 stmf_i_scsi_session_t *stmf_lookup_session_for_hostident(
61 		stmf_i_local_port_t *ilport, uint8_t *host_ident,
62 		uint16_t ident_size);
63 stmf_i_lu_t *stmf_luident_to_ilu(uint8_t *lu_ident);
64 stmf_lun_map_t *stmf_get_ve_map_per_ids(stmf_id_data_t *tgid,
65 		stmf_id_data_t *hgid);
66 stmf_lun_map_t *stmf_duplicate_ve_map(stmf_lun_map_t *src);
67 int stmf_merge_ve_map(stmf_lun_map_t *src, stmf_lun_map_t *dst,
68 		stmf_lun_map_t **pp_ret_map, stmf_merge_flags_t mf);
69 void stmf_destroy_ve_map(stmf_lun_map_t *dst);
70 void stmf_free_id(stmf_id_data_t *id);
71 
72 
73 /*
74  * Init the view
75  */
76 void
77 stmf_view_init()
78 {
79 	uint8_t grpname_forall = '*';
80 	(void) stmf_add_hg(&grpname_forall, 1, 1, NULL);
81 	(void) stmf_add_tg(&grpname_forall, 1, 1, NULL);
82 }
83 
84 /*
85  * Clear config database here
86  */
87 void
88 stmf_view_clear_config()
89 {
90 	stmf_id_data_t *idgrp, *idgrp_next, *idmemb, *idmemb_next;
91 	stmf_ver_tg_t *vtg, *vtg_next;
92 	stmf_ver_hg_t *vhg, *vhg_next;
93 	stmf_view_entry_t *ve, *ve_next;
94 	stmf_i_lu_t	*ilu;
95 	stmf_id_list_t	*idlist;
96 	stmf_i_local_port_t *ilport;
97 
98 	for (vtg = stmf_state.stmf_ver_tg_head; vtg; vtg = vtg_next) {
99 		for (vhg = vtg->vert_verh_list; vhg; vhg = vhg_next) {
100 			if (vhg->verh_ve_map.lm_nentries) {
101 				kmem_free(vhg->verh_ve_map.lm_plus,
102 				    vhg->verh_ve_map.lm_nentries *
103 				    sizeof (void *));
104 			}
105 			vhg_next = vhg->verh_next;
106 			kmem_free(vhg, sizeof (stmf_ver_hg_t));
107 		}
108 		vtg_next = vtg->vert_next;
109 		kmem_free(vtg, sizeof (stmf_ver_tg_t));
110 	}
111 	stmf_state.stmf_ver_tg_head = NULL;
112 
113 	if (stmf_state.stmf_luid_list.id_count) {
114 		/* clear the views for lus */
115 		for (idmemb = stmf_state.stmf_luid_list.idl_head;
116 		    idmemb; idmemb = idmemb_next) {
117 			for (ve = (stmf_view_entry_t *)idmemb->id_impl_specific;
118 			    ve; ve = ve_next) {
119 				ve_next = ve->ve_next;
120 				ve->ve_hg->id_refcnt--;
121 				ve->ve_tg->id_refcnt--;
122 				kmem_free(ve, sizeof (stmf_view_entry_t));
123 			}
124 			if (idmemb->id_pt_to_object) {
125 				ilu = (stmf_i_lu_t *)(idmemb->id_pt_to_object);
126 				ilu->ilu_luid = NULL;
127 			}
128 			idmemb_next = idmemb->id_next;
129 			stmf_free_id(idmemb);
130 		}
131 		stmf_state.stmf_luid_list.id_count = 0;
132 		stmf_state.stmf_luid_list.idl_head =
133 		    stmf_state.stmf_luid_list.idl_tail = NULL;
134 	}
135 
136 	if (stmf_state.stmf_hg_list.id_count) {
137 		/* free all the host group */
138 		for (idgrp = stmf_state.stmf_hg_list.idl_head;
139 		    idgrp; idgrp = idgrp_next) {
140 			idlist = (stmf_id_list_t *)(idgrp->id_impl_specific);
141 			if (idlist->id_count) {
142 				for (idmemb = idlist->idl_head; idmemb;
143 				    idmemb = idmemb_next) {
144 					idmemb_next = idmemb->id_next;
145 					stmf_free_id(idmemb);
146 				}
147 			}
148 			idgrp_next = idgrp->id_next;
149 			stmf_free_id(idgrp);
150 		}
151 		stmf_state.stmf_hg_list.id_count = 0;
152 		stmf_state.stmf_hg_list.idl_head =
153 		    stmf_state.stmf_hg_list.idl_tail = NULL;
154 	}
155 	if (stmf_state.stmf_tg_list.id_count) {
156 		/* free all the target group */
157 		for (idgrp = stmf_state.stmf_tg_list.idl_head;
158 		    idgrp; idgrp = idgrp_next) {
159 			idlist = (stmf_id_list_t *)(idgrp->id_impl_specific);
160 			if (idlist->id_count) {
161 				for (idmemb = idlist->idl_head; idmemb;
162 				    idmemb = idmemb_next) {
163 					idmemb_next = idmemb->id_next;
164 					stmf_free_id(idmemb);
165 				}
166 			}
167 			idgrp_next = idgrp->id_next;
168 			stmf_free_id(idgrp);
169 		}
170 		stmf_state.stmf_tg_list.id_count = 0;
171 		stmf_state.stmf_tg_list.idl_head =
172 		    stmf_state.stmf_tg_list.idl_tail = NULL;
173 	}
174 
175 	for (ilport = stmf_state.stmf_ilportlist; ilport;
176 	    ilport = ilport->ilport_next) {
177 		ilport->ilport_tg = NULL;
178 	}
179 }
180 
181 /*
182  * Create luns map for session based on the view
183  * iss_lockp is held
184  */
185 stmf_status_t
186 stmf_session_create_lun_map(stmf_i_local_port_t *ilport,
187     stmf_i_scsi_session_t *iss)
188 {
189 	stmf_id_data_t *tg;
190 	stmf_id_data_t *hg;
191 	stmf_ver_tg_t	*vertg;
192 	char *phg_data, *ptg_data;
193 	stmf_ver_hg_t	*verhg;
194 	stmf_lun_map_t	*ve_map;
195 
196 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
197 
198 	tg = ilport->ilport_tg;
199 	hg = stmf_lookup_group_for_host(iss->iss_ss->ss_rport_id->ident,
200 	    iss->iss_ss->ss_rport_id->ident_length);
201 	iss->iss_hg = hg;
202 
203 	/*
204 	 * get the view entry map,
205 	 * take all host/target group into consideration
206 	 */
207 	ve_map = stmf_duplicate_ve_map(0);
208 	for (vertg = stmf_state.stmf_ver_tg_head; vertg != NULL;
209 	    vertg = vertg->vert_next) {
210 		ptg_data = (char *)vertg->vert_tg_ref->id_data;
211 		if ((ptg_data[0] != '*') && (!tg ||
212 		    ((tg->id_data[0] != '*') &&
213 		    (vertg->vert_tg_ref != tg)))) {
214 			continue;
215 		}
216 		for (verhg = vertg->vert_verh_list; verhg != NULL;
217 		    verhg = verhg->verh_next) {
218 			phg_data = (char *)verhg->verh_hg_ref->id_data;
219 			if ((phg_data[0] != '*') && (!hg ||
220 			    ((hg->id_data[0] != '*') &&
221 			    (verhg->verh_hg_ref != hg)))) {
222 				continue;
223 			}
224 			(void) stmf_merge_ve_map(&verhg->verh_ve_map, ve_map,
225 			    &ve_map, 0);
226 		}
227 	}
228 
229 
230 	if (ve_map->lm_nluns) {
231 		stmf_add_lus_to_session_per_vemap(ilport, iss, ve_map);
232 	}
233 	/* not configured, cannot access any luns for now */
234 
235 	stmf_destroy_ve_map(ve_map);
236 
237 	return (STMF_SUCCESS);
238 }
239 
240 /*
241  * Expects the session lock to be held.
242  * iss_lockp is held
243  */
244 stmf_xfer_data_t *
245 stmf_session_prepare_report_lun_data(stmf_lun_map_t *sm)
246 {
247 	stmf_xfer_data_t *xd;
248 	uint16_t nluns, ent;
249 	uint32_t alloc_size, data_size;
250 	int i;
251 
252 	nluns = sm->lm_nluns;
253 
254 	data_size = 8 + (((uint32_t)nluns) << 3);
255 	if (nluns == 0) {
256 		data_size += 8;
257 	}
258 	alloc_size = data_size + sizeof (stmf_xfer_data_t) - 4;
259 
260 	xd = (stmf_xfer_data_t *)kmem_zalloc(alloc_size, KM_NOSLEEP);
261 
262 	if (xd == NULL)
263 		return (NULL);
264 
265 	xd->alloc_size = alloc_size;
266 	xd->size_left = data_size;
267 
268 	*((uint32_t *)xd->buf) = BE_32(data_size - 8);
269 	if (nluns == 0) {
270 		return (xd);
271 	}
272 
273 	ent = 0;
274 
275 	for (i = 0; ((i < sm->lm_nentries) && (ent < nluns)); i++) {
276 		if (sm->lm_plus[i] == NULL)
277 			continue;
278 		/* Fill in the entry */
279 		xd->buf[8 + (ent << 3) + 1] = (uchar_t)i;
280 		xd->buf[8 + (ent << 3) + 0] = ((uchar_t)(i >> 8));
281 		ent++;
282 	}
283 
284 	ASSERT(ent == nluns);
285 
286 	return (xd);
287 }
288 
289 /*
290  * Add a lu to active sessions based on LUN inventory.
291  * Only invoked when the lu is onlined
292  */
293 void
294 stmf_add_lu_to_active_sessions(stmf_lu_t *lu)
295 {
296 	stmf_id_data_t *luid;
297 	stmf_view_entry_t	*ve;
298 	stmf_i_lu_t *ilu;
299 
300 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
301 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
302 	ASSERT(ilu->ilu_state == STMF_STATE_ONLINE);
303 
304 	luid = ((stmf_i_lu_t *)lu->lu_stmf_private)->ilu_luid;
305 
306 	if (!luid) {
307 		/* we did not configure view for this lun, so just return */
308 		return;
309 	}
310 
311 	for (ve = (stmf_view_entry_t *)luid->id_impl_specific;
312 	    ve; ve = ve->ve_next) {
313 		stmf_update_sessions_per_ve(ve, lu, 1);
314 	}
315 }
316 /*
317  * Unmap a lun from all sessions
318  */
319 void
320 stmf_session_lu_unmapall(stmf_lu_t *lu)
321 {
322 	stmf_i_lu_t *ilu;
323 	stmf_id_data_t *luid;
324 	stmf_view_entry_t *ve;
325 
326 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
327 
328 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
329 
330 	if (ilu->ilu_ref_cnt == 0)
331 		return;
332 
333 	luid = ((stmf_i_lu_t *)lu->lu_stmf_private)->ilu_luid;
334 	if (!luid) {
335 		/*
336 		 * we did not configure view for this lun, this should be
337 		 * an error
338 		 */
339 		return;
340 	}
341 
342 	for (ve = (stmf_view_entry_t *)luid->id_impl_specific;
343 	    ve; ve = ve->ve_next) {
344 		stmf_update_sessions_per_ve(ve, lu, 0);
345 		if (ilu->ilu_ref_cnt == 0)
346 			break;
347 	}
348 }
349 /*
350  * add lu to a session, stmf_lock is already held
351  * iss_lockp/ilport_lock already held
352  */
353 static stmf_status_t
354 stmf_add_lu_to_session(stmf_i_local_port_t *ilport,
355     stmf_i_scsi_session_t *iss,
356     stmf_lu_t *lu,
357     uint8_t *lu_nbr)
358 {
359 	stmf_lun_map_t *sm = iss->iss_sm;
360 	stmf_status_t ret;
361 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
362 	stmf_lun_map_ent_t *lun_map_ent;
363 	uint32_t new_flags = 0;
364 	uint16_t luNbr =
365 	    ((uint16_t)lu_nbr[1] | (((uint16_t)(lu_nbr[0] & 0x3F)) << 8));
366 
367 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
368 	ASSERT(!stmf_get_ent_from_map(sm, luNbr));
369 
370 	if ((sm->lm_nluns == 0) &&
371 	    ((iss->iss_flags & ISS_BEING_CREATED) == 0)) {
372 		new_flags = ISS_GOT_INITIAL_LUNS;
373 		atomic_or_32(&ilport->ilport_flags, ILPORT_SS_GOT_INITIAL_LUNS);
374 		stmf_state.stmf_process_initial_luns = 1;
375 	}
376 
377 	lun_map_ent = (stmf_lun_map_ent_t *)
378 	    kmem_zalloc(sizeof (stmf_lun_map_ent_t), KM_SLEEP);
379 	lun_map_ent->ent_lu = lu;
380 	ret = stmf_add_ent_to_map(sm, (void *)lun_map_ent, lu_nbr);
381 	ASSERT(ret == STMF_SUCCESS);
382 	atomic_inc_32(&ilu->ilu_ref_cnt);
383 	/*
384 	 * do not set lun inventory flag for standby port
385 	 * as this would be handled from peer
386 	 */
387 	if (ilport->ilport_standby == 0) {
388 		new_flags |= ISS_LUN_INVENTORY_CHANGED;
389 	}
390 	atomic_or_32(&iss->iss_flags, new_flags);
391 	return (STMF_SUCCESS);
392 }
393 
394 /*
395  * remvoe lu from a session, stmf_lock is already held
396  * iss_lockp held
397  */
398 static void
399 stmf_remove_lu_from_session(stmf_i_scsi_session_t *iss,
400     stmf_lu_t *lu, uint8_t *lu_nbr)
401 {
402 	stmf_status_t ret;
403 	stmf_i_lu_t *ilu;
404 	stmf_lun_map_t *sm = iss->iss_sm;
405 	stmf_lun_map_ent_t *lun_map_ent;
406 	uint16_t luNbr =
407 	    ((uint16_t)lu_nbr[1] | (((uint16_t)(lu_nbr[0] & 0x3F)) << 8));
408 
409 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
410 	lun_map_ent = stmf_get_ent_from_map(sm, luNbr);
411 	ASSERT(lun_map_ent->ent_lu == lu);
412 	if (lun_map_ent == NULL) {
413 		return;
414 	}
415 
416 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
417 
418 	ret = stmf_remove_ent_from_map(sm, lu_nbr);
419 	ASSERT(ret == STMF_SUCCESS);
420 	atomic_dec_32(&ilu->ilu_ref_cnt);
421 	iss->iss_flags |= ISS_LUN_INVENTORY_CHANGED;
422 	if (lun_map_ent->ent_itl_datap) {
423 		stmf_do_itl_dereg(lu, lun_map_ent->ent_itl_datap,
424 		    STMF_ITL_REASON_USER_REQUEST);
425 	}
426 	kmem_free((void *)lun_map_ent, sizeof (stmf_lun_map_ent_t));
427 }
428 
429 /*
430  * add or remove lu from all related sessions based on view entry,
431  * action is 0 for delete, 1 for add
432  */
433 void
434 stmf_update_sessions_per_ve(stmf_view_entry_t *ve,
435     stmf_lu_t *lu, int action)
436 {
437 	stmf_i_lu_t *ilu_tmp;
438 	stmf_lu_t *lu_to_add;
439 	stmf_i_local_port_t *ilport;
440 	stmf_i_scsi_session_t *iss;
441 	stmf_id_list_t	*hostlist;
442 	stmf_id_list_t	*targetlist;
443 	int all_hg = 0, all_tg = 0;
444 
445 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
446 
447 	if (!lu) {
448 		ilu_tmp = (stmf_i_lu_t *)ve->ve_luid->id_pt_to_object;
449 		if (!ilu_tmp)
450 			return;
451 		lu_to_add = ilu_tmp->ilu_lu;
452 	} else {
453 		lu_to_add = lu;
454 		ilu_tmp = (stmf_i_lu_t *)lu->lu_stmf_private;
455 	}
456 
457 	if (ve->ve_hg->id_data[0] == '*')
458 		all_hg = 1;
459 	if (ve->ve_tg->id_data[0] == '*')
460 		all_tg = 1;
461 	hostlist = (stmf_id_list_t *)ve->ve_hg->id_impl_specific;
462 	targetlist = (stmf_id_list_t *)ve->ve_tg->id_impl_specific;
463 
464 	if ((!all_hg && !hostlist->idl_head) ||
465 	    (!all_tg && !targetlist->idl_head))
466 		/* No sessions to be updated */
467 		return;
468 
469 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
470 	    ilport = ilport->ilport_next) {
471 		if (!all_tg && ilport->ilport_tg != ve->ve_tg)
472 			continue;
473 		/* This ilport belongs to the target group */
474 		rw_enter(&ilport->ilport_lock, RW_WRITER);
475 		for (iss = ilport->ilport_ss_list; iss != NULL;
476 		    iss = iss->iss_next) {
477 			if (!all_hg && iss->iss_hg != ve->ve_hg)
478 				continue;
479 			/* This host belongs to the host group */
480 			if (action == 0) { /* to remove */
481 				stmf_remove_lu_from_session(iss, lu_to_add,
482 				    ve->ve_lun);
483 				if (ilu_tmp->ilu_ref_cnt == 0) {
484 					rw_exit(&ilport->ilport_lock);
485 					return;
486 				}
487 			} else {
488 				(void) stmf_add_lu_to_session(ilport, iss,
489 				    lu_to_add, ve->ve_lun);
490 			}
491 		}
492 		rw_exit(&ilport->ilport_lock);
493 	}
494 }
495 
496 /*
497  * add luns in view entry map to a session,
498  * and stmf_lock is already held
499  */
500 void
501 stmf_add_lus_to_session_per_vemap(stmf_i_local_port_t *ilport,
502     stmf_i_scsi_session_t *iss,
503     stmf_lun_map_t *vemap)
504 {
505 	stmf_lu_t *lu;
506 	stmf_i_lu_t *ilu;
507 	stmf_view_entry_t *ve;
508 	uint32_t	i;
509 
510 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
511 	for (i = 0; i < vemap->lm_nentries; i++) {
512 		ve = (stmf_view_entry_t *)vemap->lm_plus[i];
513 		if (!ve)
514 			continue;
515 		ilu = (stmf_i_lu_t *)ve->ve_luid->id_pt_to_object;
516 		if (ilu && ilu->ilu_state == STMF_STATE_ONLINE) {
517 			lu = ilu->ilu_lu;
518 			(void) stmf_add_lu_to_session(ilport, iss, lu,
519 			    ve->ve_lun);
520 		}
521 	}
522 }
523 /*
524  * remove luns in view entry map from a session
525  * iss_lockp held
526  */
527 void
528 stmf_remove_lus_from_session_per_vemap(stmf_i_scsi_session_t *iss,
529     stmf_lun_map_t *vemap)
530 {
531 	stmf_lu_t *lu;
532 	stmf_i_lu_t *ilu;
533 	stmf_view_entry_t *ve;
534 	uint32_t i;
535 
536 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
537 
538 	for (i = 0; i < vemap->lm_nentries; i++) {
539 		ve = (stmf_view_entry_t *)vemap->lm_plus[i];
540 		if (!ve)
541 			continue;
542 		ilu = (stmf_i_lu_t *)ve->ve_luid->id_pt_to_object;
543 		if (ilu && ilu->ilu_state == STMF_STATE_ONLINE) {
544 			lu = ilu->ilu_lu;
545 			stmf_remove_lu_from_session(iss, lu, ve->ve_lun);
546 		}
547 	}
548 }
549 
550 stmf_id_data_t *
551 stmf_alloc_id(uint16_t id_size, uint16_t type, uint8_t *id_data,
552     uint32_t additional_size)
553 {
554 	stmf_id_data_t *id;
555 	int struct_size, total_size, real_id_size;
556 
557 	real_id_size = ((uint32_t)id_size + 7) & (~7);
558 	struct_size = (sizeof (*id) + 7) & (~7);
559 	total_size = ((additional_size + 7) & (~7)) + struct_size +
560 	    real_id_size;
561 	id = (stmf_id_data_t *)kmem_zalloc(total_size, KM_SLEEP);
562 	id->id_type = type;
563 	id->id_data_size = id_size;
564 	id->id_data = ((uint8_t *)id) + struct_size;
565 	id->id_total_alloc_size = total_size;
566 	if (additional_size) {
567 		id->id_impl_specific = ((uint8_t *)id) + struct_size +
568 		    real_id_size;
569 	}
570 	bcopy(id_data, id->id_data, id_size);
571 
572 	return (id);
573 }
574 
575 void
576 stmf_free_id(stmf_id_data_t *id)
577 {
578 	kmem_free(id, id->id_total_alloc_size);
579 }
580 
581 
582 stmf_id_data_t *
583 stmf_lookup_id(stmf_id_list_t *idlist, uint16_t id_size, uint8_t *data)
584 {
585 	stmf_id_data_t *id;
586 
587 	for (id = idlist->idl_head; id != NULL; id = id->id_next) {
588 		if ((id->id_data_size == id_size) &&
589 		    (bcmp(id->id_data, data, id_size) == 0)) {
590 			return (id);
591 		}
592 	}
593 
594 	return (NULL);
595 }
596 /* Return the target group which a target belong to */
597 stmf_id_data_t *
598 stmf_lookup_group_for_target(uint8_t *ident, uint16_t ident_size)
599 {
600 	stmf_id_data_t *tgid;
601 	stmf_id_data_t *target;
602 
603 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
604 
605 	for (tgid = stmf_state.stmf_tg_list.idl_head; tgid;
606 	    tgid = tgid->id_next) {
607 		target = stmf_lookup_id(
608 		    (stmf_id_list_t *)tgid->id_impl_specific,
609 		    ident_size, ident);
610 		if (target)
611 			return (tgid);
612 	}
613 	return (NULL);
614 }
615 /* Return the host group which a host belong to */
616 stmf_id_data_t *
617 stmf_lookup_group_for_host(uint8_t *ident, uint16_t ident_size)
618 {
619 	stmf_id_data_t *hgid;
620 	stmf_id_data_t *host;
621 
622 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
623 
624 	for (hgid = stmf_state.stmf_hg_list.idl_head; hgid;
625 	    hgid = hgid->id_next) {
626 		host = stmf_lookup_id(
627 		    (stmf_id_list_t *)hgid->id_impl_specific,
628 		    ident_size, ident);
629 		if (host)
630 			return (hgid);
631 	}
632 	return (NULL);
633 }
634 
635 void
636 stmf_append_id(stmf_id_list_t *idlist, stmf_id_data_t *id)
637 {
638 	id->id_next = NULL;
639 
640 	if ((id->id_prev = idlist->idl_tail) == NULL) {
641 		idlist->idl_head = idlist->idl_tail = id;
642 	} else {
643 		idlist->idl_tail->id_next = id;
644 		idlist->idl_tail = id;
645 	}
646 	atomic_inc_32(&idlist->id_count);
647 }
648 
649 void
650 stmf_remove_id(stmf_id_list_t *idlist, stmf_id_data_t *id)
651 {
652 	if (id->id_next) {
653 		id->id_next->id_prev = id->id_prev;
654 	} else {
655 		idlist->idl_tail = id->id_prev;
656 	}
657 
658 	if (id->id_prev) {
659 		id->id_prev->id_next = id->id_next;
660 	} else {
661 		idlist->idl_head = id->id_next;
662 	}
663 	atomic_dec_32(&idlist->id_count);
664 }
665 
666 
667 /*
668  * The refcnts of objects in a view entry are updated when then entry
669  * is successfully added. ve_map is just another representation of the
670  * view enrtries in a LU. Duplicating or merging a ve map does not
671  * affect any refcnts.
672  * stmf_state.stmf_lock held
673  */
674 stmf_lun_map_t *
675 stmf_duplicate_ve_map(stmf_lun_map_t *src)
676 {
677 	stmf_lun_map_t *dst;
678 	int i;
679 
680 	dst = (stmf_lun_map_t *)kmem_zalloc(sizeof (*dst), KM_SLEEP);
681 
682 	if (src == NULL)
683 		return (dst);
684 
685 	if (src->lm_nentries) {
686 		dst->lm_plus = kmem_zalloc(dst->lm_nentries *
687 		    sizeof (void *), KM_SLEEP);
688 		for (i = 0; i < dst->lm_nentries; i++) {
689 			dst->lm_plus[i] = src->lm_plus[i];
690 		}
691 	}
692 
693 	return (dst);
694 }
695 
696 void
697 stmf_destroy_ve_map(stmf_lun_map_t *dst)
698 {
699 	if (dst->lm_nentries) {
700 		kmem_free(dst->lm_plus, dst->lm_nentries * sizeof (void *));
701 	}
702 	kmem_free(dst, sizeof (*dst));
703 }
704 
705 /*
706  * stmf_state.stmf_lock held. Operations are stmf global in nature and
707  * not session level.
708  */
709 int
710 stmf_merge_ve_map(stmf_lun_map_t *src, stmf_lun_map_t *dst,
711     stmf_lun_map_t **pp_ret_map, stmf_merge_flags_t mf)
712 {
713 	int i;
714 	int nentries;
715 	int to_create_space = 0;
716 
717 	if (dst == NULL) {
718 		*pp_ret_map = stmf_duplicate_ve_map(src);
719 		return (1);
720 	}
721 
722 	if (src == NULL || src->lm_nluns == 0) {
723 		if (mf & MERGE_FLAG_RETURN_NEW_MAP)
724 			*pp_ret_map = stmf_duplicate_ve_map(dst);
725 		else
726 			*pp_ret_map = dst;
727 		return (1);
728 	}
729 
730 	if (mf & MERGE_FLAG_RETURN_NEW_MAP) {
731 		*pp_ret_map = stmf_duplicate_ve_map(NULL);
732 		nentries = max(dst->lm_nentries, src->lm_nentries);
733 		to_create_space = 1;
734 	} else {
735 		*pp_ret_map = dst;
736 		/* If there is not enough space in dst map */
737 		if (dst->lm_nentries < src->lm_nentries) {
738 			nentries = src->lm_nentries;
739 			to_create_space = 1;
740 		}
741 	}
742 	if (to_create_space) {
743 		void **p;
744 		p = (void **)kmem_zalloc(nentries * sizeof (void *), KM_SLEEP);
745 		if (dst->lm_nentries) {
746 			bcopy(dst->lm_plus, p,
747 			    dst->lm_nentries * sizeof (void *));
748 		}
749 		if (mf & (MERGE_FLAG_RETURN_NEW_MAP == 0))
750 			kmem_free(dst->lm_plus,
751 			    dst->lm_nentries * sizeof (void *));
752 		(*pp_ret_map)->lm_plus = p;
753 		(*pp_ret_map)->lm_nentries = nentries;
754 	}
755 
756 	for (i = 0; i < src->lm_nentries; i++) {
757 		if (src->lm_plus[i] == NULL)
758 			continue;
759 		if (dst->lm_plus[i] != NULL) {
760 			if (mf & MERGE_FLAG_NO_DUPLICATE) {
761 				if (mf & MERGE_FLAG_RETURN_NEW_MAP) {
762 					stmf_destroy_ve_map(*pp_ret_map);
763 					*pp_ret_map = NULL;
764 				}
765 				return (0);
766 			}
767 		} else {
768 			dst->lm_plus[i] = src->lm_plus[i];
769 			dst->lm_nluns++;
770 		}
771 	}
772 
773 	return (1);
774 }
775 
776 /*
777  * add host group, id_impl_specific point to a list of hosts,
778  * on return, if error happened, err_detail may be assigned if
779  * the pointer is not NULL
780  */
781 stmf_status_t
782 stmf_add_hg(uint8_t *hg_name, uint16_t hg_name_size,
783     int allow_special, uint32_t *err_detail)
784 {
785 	stmf_id_data_t *id;
786 
787 	if (!allow_special) {
788 		if (hg_name[0] == '*')
789 			return (STMF_INVALID_ARG);
790 	}
791 
792 	if (stmf_lookup_id(&stmf_state.stmf_hg_list,
793 	    hg_name_size, (uint8_t *)hg_name)) {
794 		if (err_detail)
795 			*err_detail = STMF_IOCERR_HG_EXISTS;
796 		return (STMF_ALREADY);
797 	}
798 	id = stmf_alloc_id(hg_name_size, STMF_ID_TYPE_HOST_GROUP,
799 	    (uint8_t *)hg_name, sizeof (stmf_id_list_t));
800 	stmf_append_id(&stmf_state.stmf_hg_list, id);
801 
802 	return (STMF_SUCCESS);
803 }
804 
805 /* add target group */
806 stmf_status_t
807 stmf_add_tg(uint8_t *tg_name, uint16_t tg_name_size,
808     int allow_special, uint32_t *err_detail)
809 {
810 	stmf_id_data_t *id;
811 
812 	if (!allow_special) {
813 		if (tg_name[0] == '*')
814 			return (STMF_INVALID_ARG);
815 	}
816 
817 
818 	if (stmf_lookup_id(&stmf_state.stmf_tg_list, tg_name_size,
819 	    (uint8_t *)tg_name)) {
820 		if (err_detail)
821 			*err_detail = STMF_IOCERR_TG_EXISTS;
822 		return (STMF_ALREADY);
823 	}
824 	id = stmf_alloc_id(tg_name_size, STMF_ID_TYPE_TARGET_GROUP,
825 	    (uint8_t *)tg_name, sizeof (stmf_id_list_t));
826 	stmf_append_id(&stmf_state.stmf_tg_list, id);
827 
828 	return (STMF_SUCCESS);
829 }
830 
831 /*
832  * insert view entry into list for a luid, if ve->ve_id is 0xffffffff,
833  * pick up a smallest available veid for it, and return the veid in ve->ve_id.
834  * The view entries list is sorted based on veid.
835  */
836 stmf_status_t
837 stmf_add_ve_to_luid(stmf_id_data_t *luid, stmf_view_entry_t *ve)
838 {
839 	stmf_view_entry_t *ve_tmp = NULL;
840 	stmf_view_entry_t *ve_prev = NULL;
841 
842 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
843 
844 	ve_tmp = (stmf_view_entry_t *)luid->id_impl_specific;
845 
846 	if (ve->ve_id != 0xffffffff) {
847 		for (; ve_tmp; ve_tmp = ve_tmp->ve_next) {
848 			if (ve_tmp->ve_id > ve->ve_id) {
849 				break;
850 			} else if (ve_tmp->ve_id == ve->ve_id) {
851 				return (STMF_ALREADY);
852 			}
853 			ve_prev = ve_tmp;
854 		}
855 	} else {
856 		uint32_t veid = 0;
857 		/* search the smallest available veid */
858 		for (; ve_tmp; ve_tmp = ve_tmp->ve_next) {
859 			ASSERT(ve_tmp->ve_id >= veid);
860 			if (ve_tmp->ve_id != veid)
861 				break;
862 			veid++;
863 			if (veid == 0xffffffff)
864 				return (STMF_NOT_SUPPORTED);
865 			ve_prev = ve_tmp;
866 		}
867 		ve->ve_id = veid;
868 	}
869 
870 	/* insert before ve_tmp if it exist */
871 	ve->ve_next = ve_tmp;
872 	ve->ve_prev = ve_prev;
873 	if (ve_tmp) {
874 		ve_tmp->ve_prev = ve;
875 	}
876 	if (ve_prev) {
877 		ve_prev->ve_next = ve;
878 	} else {
879 		luid->id_impl_specific = (void *)ve;
880 	}
881 	return (STMF_SUCCESS);
882 }
883 
884 /* stmf_lock is already held, err_detail may be assigned if error happens */
885 stmf_status_t
886 stmf_add_view_entry(stmf_id_data_t *hg, stmf_id_data_t *tg,
887     uint8_t *lu_guid, uint32_t *ve_id, uint8_t *lun,
888     stmf_view_entry_t **conflicting, uint32_t *err_detail)
889 {
890 	stmf_id_data_t *luid;
891 	stmf_view_entry_t *ve;
892 	char *phg, *ptg;
893 	stmf_lun_map_t *ve_map = NULL;
894 	stmf_ver_hg_t *verhg = NULL, *verhg_ex = NULL;
895 	stmf_ver_tg_t *vertg = NULL, *vertg_ex = NULL;
896 	char luid_new;
897 	uint16_t lun_num;
898 	stmf_i_lu_t *ilu;
899 	stmf_status_t ret;
900 
901 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
902 
903 	lun_num = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
904 
905 	luid = stmf_lookup_id(&stmf_state.stmf_luid_list, 16, lu_guid);
906 	if (luid == NULL) {
907 		luid = stmf_alloc_id(16, STMF_ID_TYPE_LU_GUID, lu_guid, 0);
908 		ilu = stmf_luident_to_ilu(lu_guid);
909 		if (ilu) {
910 			ilu->ilu_luid = luid;
911 			luid->id_pt_to_object = (void *)ilu;
912 		}
913 		luid_new = 1;
914 	} else {
915 		luid_new = 0;
916 		ilu = (stmf_i_lu_t *)luid->id_pt_to_object;
917 	}
918 
919 	/* The view entry won't be added if there is any confilict */
920 	phg = (char *)hg->id_data; ptg = (char *)tg->id_data;
921 	for (ve = (stmf_view_entry_t *)luid->id_impl_specific; ve != NULL;
922 	    ve = ve->ve_next) {
923 		if (((phg[0] == '*') || (ve->ve_hg->id_data[0] == '*') ||
924 		    (hg == ve->ve_hg)) && ((ptg[0] == '*') ||
925 		    (ve->ve_tg->id_data[0] == '*') || (tg == ve->ve_tg))) {
926 			*conflicting = ve;
927 			*err_detail = STMF_IOCERR_VIEW_ENTRY_CONFLICT;
928 			ret = STMF_ALREADY;
929 			goto add_ve_err_ret;
930 		}
931 	}
932 
933 	ve_map = stmf_duplicate_ve_map(0);
934 	for (vertg = stmf_state.stmf_ver_tg_head; vertg != NULL;
935 	    vertg = vertg->vert_next) {
936 		ptg = (char *)vertg->vert_tg_ref->id_data;
937 		if ((ptg[0] != '*') && (tg->id_data[0] != '*') &&
938 		    (vertg->vert_tg_ref != tg)) {
939 			continue;
940 		}
941 		if (vertg->vert_tg_ref == tg)
942 			vertg_ex = vertg;
943 		for (verhg = vertg->vert_verh_list; verhg != NULL;
944 		    verhg = verhg->verh_next) {
945 			phg = (char *)verhg->verh_hg_ref->id_data;
946 			if ((phg[0] != '*') && (hg->id_data[0] != '*') &&
947 			    (verhg->verh_hg_ref != hg)) {
948 				continue;
949 			}
950 			if ((vertg_ex == vertg) && (verhg->verh_hg_ref == hg))
951 				verhg_ex = verhg;
952 			(void) stmf_merge_ve_map(&verhg->verh_ve_map, ve_map,
953 			    &ve_map, 0);
954 		}
955 	}
956 
957 	if (lun[2] == 0xFF) {
958 		/* Pick a LUN number */
959 		lun_num = stmf_get_next_free_lun(ve_map, lun);
960 		if (lun_num > 0x3FFF) {
961 			stmf_destroy_ve_map(ve_map);
962 			ret = STMF_NOT_SUPPORTED;
963 			goto add_ve_err_ret;
964 		}
965 	} else {
966 		if ((*conflicting = stmf_get_ent_from_map(ve_map, lun_num))
967 		    != NULL) {
968 			stmf_destroy_ve_map(ve_map);
969 			*err_detail = STMF_IOCERR_LU_NUMBER_IN_USE;
970 			ret = STMF_LUN_TAKEN;
971 			goto add_ve_err_ret;
972 		}
973 	}
974 	stmf_destroy_ve_map(ve_map);
975 
976 	/* All is well, do the actual addition now */
977 	ve = (stmf_view_entry_t *)kmem_zalloc(sizeof (*ve), KM_SLEEP);
978 	ve->ve_id = *ve_id;
979 	ve->ve_lun[0] = lun[0];
980 	ve->ve_lun[1] = lun[1];
981 
982 	if ((ret = stmf_add_ve_to_luid(luid, ve)) != STMF_SUCCESS) {
983 		kmem_free(ve, sizeof (stmf_view_entry_t));
984 		goto add_ve_err_ret;
985 	}
986 	ve->ve_hg = hg; hg->id_refcnt++;
987 	ve->ve_tg = tg; tg->id_refcnt++;
988 	ve->ve_luid = luid; luid->id_refcnt++;
989 
990 	*ve_id = ve->ve_id;
991 
992 	if (luid_new) {
993 		stmf_append_id(&stmf_state.stmf_luid_list, luid);
994 	}
995 
996 	if (vertg_ex == NULL) {
997 		vertg_ex = (stmf_ver_tg_t *)kmem_zalloc(sizeof (stmf_ver_tg_t),
998 		    KM_SLEEP);
999 		vertg_ex->vert_next = stmf_state.stmf_ver_tg_head;
1000 		stmf_state.stmf_ver_tg_head = vertg_ex;
1001 		vertg_ex->vert_tg_ref = tg;
1002 		verhg_ex = vertg_ex->vert_verh_list =
1003 		    (stmf_ver_hg_t *)kmem_zalloc(sizeof (stmf_ver_hg_t),
1004 		    KM_SLEEP);
1005 		verhg_ex->verh_hg_ref = hg;
1006 	}
1007 	if (verhg_ex == NULL) {
1008 		verhg_ex = (stmf_ver_hg_t *)kmem_zalloc(sizeof (stmf_ver_hg_t),
1009 		    KM_SLEEP);
1010 		verhg_ex->verh_next = vertg_ex->vert_verh_list;
1011 		vertg_ex->vert_verh_list = verhg_ex;
1012 		verhg_ex->verh_hg_ref = hg;
1013 	}
1014 	ret = stmf_add_ent_to_map(&verhg_ex->verh_ve_map, ve, ve->ve_lun);
1015 	ASSERT(ret == STMF_SUCCESS);
1016 
1017 	/* we need to update the affected session */
1018 	if (stmf_state.stmf_service_running) {
1019 		if (ilu && ilu->ilu_state == STMF_STATE_ONLINE)
1020 			stmf_update_sessions_per_ve(ve, ilu->ilu_lu, 1);
1021 	}
1022 
1023 	return (STMF_SUCCESS);
1024 add_ve_err_ret:
1025 	if (luid_new) {
1026 		if (ilu)
1027 			ilu->ilu_luid = NULL;
1028 		stmf_free_id(luid);
1029 	}
1030 	return (ret);
1031 }
1032 
1033 /*
1034  * protected by stmf_state.stmf_lock when working on global lun map.
1035  * iss_lockp when working at the session level.
1036  */
1037 static stmf_status_t
1038 stmf_add_ent_to_map(stmf_lun_map_t *lm, void *ent, uint8_t *lun)
1039 {
1040 	uint16_t n;
1041 	if (((lun[0] & 0xc0) >> 6) != 0)
1042 		return (STMF_FAILURE);
1043 
1044 	n = (uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8);
1045 try_again_to_add:
1046 	if (lm->lm_nentries && (n < lm->lm_nentries)) {
1047 		if (lm->lm_plus[n] == NULL) {
1048 			lm->lm_plus[n] = ent;
1049 			lm->lm_nluns++;
1050 			return (STMF_SUCCESS);
1051 		} else {
1052 			return (STMF_LUN_TAKEN);
1053 		}
1054 	} else {
1055 		void **pplu;
1056 		uint16_t m = n + 1;
1057 		m = ((m + 7) & ~7) & 0x7FFF;
1058 		pplu = (void **)kmem_zalloc(m * sizeof (void *), KM_SLEEP);
1059 		bcopy(lm->lm_plus, pplu,
1060 		    lm->lm_nentries * sizeof (void *));
1061 		kmem_free(lm->lm_plus, lm->lm_nentries * sizeof (void *));
1062 		lm->lm_plus = pplu;
1063 		lm->lm_nentries = m;
1064 		goto try_again_to_add;
1065 	}
1066 }
1067 
1068 
1069 /*
1070  * iss_lockp held when working on a session.
1071  * stmf_state.stmf_lock is held when working on the global views.
1072  */
1073 static stmf_status_t
1074 stmf_remove_ent_from_map(stmf_lun_map_t *lm, uint8_t *lun)
1075 {
1076 	uint16_t n, i;
1077 	uint8_t lutype = (lun[0] & 0xc0) >> 6;
1078 	if (lutype != 0)
1079 		return (STMF_FAILURE);
1080 
1081 	n = (uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8);
1082 
1083 	if (n >= lm->lm_nentries)
1084 		return (STMF_NOT_FOUND);
1085 	if (lm->lm_plus[n] == NULL)
1086 		return (STMF_NOT_FOUND);
1087 
1088 	lm->lm_plus[n] = NULL;
1089 	lm->lm_nluns--;
1090 
1091 	for (i = 0; i < lm->lm_nentries; i++) {
1092 		if (lm->lm_plus[lm->lm_nentries - 1 - i] != NULL)
1093 			break;
1094 	}
1095 	i &= ~15;
1096 	if (i >= 16) {
1097 		void **pplu;
1098 		uint16_t m;
1099 		m = lm->lm_nentries - i;
1100 		pplu = (void **)kmem_zalloc(m * sizeof (void *), KM_SLEEP);
1101 		bcopy(lm->lm_plus, pplu, m * sizeof (void *));
1102 		kmem_free(lm->lm_plus, lm->lm_nentries * sizeof (void *));
1103 		lm->lm_plus = pplu;
1104 		lm->lm_nentries = m;
1105 	}
1106 
1107 	return (STMF_SUCCESS);
1108 }
1109 
1110 /*
1111  * stmf_state.stmf_lock held
1112  */
1113 uint16_t
1114 stmf_get_next_free_lun(stmf_lun_map_t *sm, uint8_t *lun)
1115 {
1116 	uint16_t luNbr;
1117 
1118 
1119 	if (sm->lm_nluns < 0x4000) {
1120 		for (luNbr = 0; luNbr < sm->lm_nentries; luNbr++) {
1121 			if (sm->lm_plus[luNbr] == NULL)
1122 				break;
1123 		}
1124 	} else {
1125 		return (0xFFFF);
1126 	}
1127 	if (lun) {
1128 		bzero(lun, 8);
1129 		lun[1] = luNbr & 0xff;
1130 		lun[0] = (luNbr >> 8) & 0xff;
1131 	}
1132 
1133 	return (luNbr);
1134 }
1135 
1136 /*
1137  * stmf_state.stmf_lock is held when working on global view map
1138  * iss_lockp (RW_WRITER) is held when working on session map.
1139  */
1140 void *
1141 stmf_get_ent_from_map(stmf_lun_map_t *sm, uint16_t lun_num)
1142 {
1143 	if ((lun_num & 0xC000) == 0) {
1144 		if (sm->lm_nentries > lun_num)
1145 			return (sm->lm_plus[lun_num & 0x3FFF]);
1146 		else
1147 			return (NULL);
1148 	}
1149 
1150 	return (NULL);
1151 }
1152 
1153 int
1154 stmf_add_ve(uint8_t *hgname, uint16_t hgname_size,
1155     uint8_t *tgname, uint16_t tgname_size,
1156     uint8_t *lu_guid, uint32_t *ve_id,
1157     uint8_t *luNbr, uint32_t *err_detail)
1158 {
1159 	stmf_id_data_t *hg;
1160 	stmf_id_data_t *tg;
1161 	stmf_view_entry_t *conflictve;
1162 	stmf_status_t ret;
1163 
1164 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
1165 
1166 	hg = stmf_lookup_id(&stmf_state.stmf_hg_list, hgname_size,
1167 	    (uint8_t *)hgname);
1168 	if (!hg) {
1169 		*err_detail = STMF_IOCERR_INVALID_HG;
1170 		return (ENOENT); /* could not find group */
1171 	}
1172 	tg = stmf_lookup_id(&stmf_state.stmf_tg_list, tgname_size,
1173 	    (uint8_t *)tgname);
1174 	if (!tg) {
1175 		*err_detail = STMF_IOCERR_INVALID_TG;
1176 		return (ENOENT); /* could not find group */
1177 	}
1178 	ret = stmf_add_view_entry(hg, tg, lu_guid, ve_id, luNbr,
1179 	    &conflictve, err_detail);
1180 
1181 	if (ret == STMF_ALREADY) {
1182 		return (EALREADY);
1183 	} else if (ret == STMF_LUN_TAKEN) {
1184 		return (EEXIST);
1185 	} else if (ret == STMF_NOT_SUPPORTED) {
1186 		return (E2BIG);
1187 	} else if (ret != STMF_SUCCESS) {
1188 		return (EINVAL);
1189 	}
1190 	return (0);
1191 }
1192 
1193 int
1194 stmf_remove_ve_by_id(uint8_t *guid, uint32_t veid, uint32_t *err_detail)
1195 {
1196 	stmf_id_data_t *luid;
1197 	stmf_view_entry_t	*ve;
1198 	stmf_ver_tg_t *vtg;
1199 	stmf_ver_hg_t *vhg;
1200 	stmf_ver_tg_t *prev_vtg = NULL;
1201 	stmf_ver_hg_t *prev_vhg = NULL;
1202 	int found = 0;
1203 	stmf_i_lu_t *ilu;
1204 
1205 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
1206 	luid = stmf_lookup_id(&stmf_state.stmf_luid_list, 16, guid);
1207 	if (luid == NULL) {
1208 		*err_detail = STMF_IOCERR_INVALID_LU_ID;
1209 		return (ENODEV);
1210 	}
1211 	ilu = (stmf_i_lu_t *)luid->id_pt_to_object;
1212 
1213 	for (ve = (stmf_view_entry_t *)luid->id_impl_specific;
1214 	    ve; ve = ve->ve_next) {
1215 		if (ve->ve_id == veid) {
1216 			break;
1217 		}
1218 	}
1219 	if (!ve) {
1220 		*err_detail = STMF_IOCERR_INVALID_VE_ID;
1221 		return (ENODEV);
1222 	}
1223 	/* remove the ve */
1224 	if (ve->ve_next)
1225 		ve->ve_next->ve_prev = ve->ve_prev;
1226 	if (ve->ve_prev)
1227 		ve->ve_prev->ve_next = ve->ve_next;
1228 	else {
1229 		luid->id_impl_specific = (void *)ve->ve_next;
1230 		if (!luid->id_impl_specific) {
1231 			/* don't have any view entries related to this lu */
1232 			stmf_remove_id(&stmf_state.stmf_luid_list, luid);
1233 			if (ilu)
1234 				ilu->ilu_luid = NULL;
1235 			stmf_free_id(luid);
1236 		}
1237 	}
1238 
1239 	/* we need to update ver_hg->verh_ve_map */
1240 	for (vtg = stmf_state.stmf_ver_tg_head; vtg; vtg = vtg->vert_next) {
1241 		if (vtg->vert_tg_ref == ve->ve_tg) {
1242 			found = 1;
1243 			break;
1244 		}
1245 		prev_vtg = vtg;
1246 	}
1247 	ASSERT(found);
1248 	found = 0;
1249 	for (vhg = vtg->vert_verh_list; vhg; vhg = vhg->verh_next) {
1250 		if (vhg->verh_hg_ref == ve->ve_hg) {
1251 			found = 1;
1252 			break;
1253 		}
1254 		prev_vhg = vhg;
1255 	}
1256 	ASSERT(found);
1257 
1258 	(void) stmf_remove_ent_from_map(&vhg->verh_ve_map, ve->ve_lun);
1259 
1260 	/* free verhg if it don't have any ve entries related */
1261 	if (!vhg->verh_ve_map.lm_nluns) {
1262 		/* we don't have any view entry related */
1263 		if (prev_vhg)
1264 			prev_vhg->verh_next = vhg->verh_next;
1265 		else
1266 			vtg->vert_verh_list = vhg->verh_next;
1267 
1268 		/* Free entries in case the map still has memory */
1269 		if (vhg->verh_ve_map.lm_nentries) {
1270 			kmem_free(vhg->verh_ve_map.lm_plus,
1271 			    vhg->verh_ve_map.lm_nentries *
1272 			    sizeof (void *));
1273 		}
1274 		kmem_free(vhg, sizeof (stmf_ver_hg_t));
1275 		if (!vtg->vert_verh_list) {
1276 			/* we don't have any ve related */
1277 			if (prev_vtg)
1278 				prev_vtg->vert_next = vtg->vert_next;
1279 			else
1280 				stmf_state.stmf_ver_tg_head = vtg->vert_next;
1281 			kmem_free(vtg, sizeof (stmf_ver_tg_t));
1282 		}
1283 	}
1284 
1285 	if (stmf_state.stmf_service_running && ilu &&
1286 	    ilu->ilu_state == STMF_STATE_ONLINE) {
1287 		stmf_update_sessions_per_ve(ve, ilu->ilu_lu, 0);
1288 	}
1289 
1290 	ve->ve_hg->id_refcnt--;
1291 	ve->ve_tg->id_refcnt--;
1292 
1293 	kmem_free(ve, sizeof (stmf_view_entry_t));
1294 	return (0);
1295 }
1296 
1297 int
1298 stmf_add_group(uint8_t *grpname, uint16_t grpname_size,
1299     stmf_id_type_t group_type, uint32_t *err_detail)
1300 {
1301 	stmf_status_t status;
1302 
1303 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
1304 
1305 	if (group_type == STMF_ID_TYPE_HOST_GROUP)
1306 		status = stmf_add_hg(grpname, grpname_size, 0, err_detail);
1307 	else if (group_type == STMF_ID_TYPE_TARGET_GROUP)
1308 		status = stmf_add_tg(grpname, grpname_size, 0, err_detail);
1309 	else {
1310 		return (EINVAL);
1311 	}
1312 	switch (status) {
1313 	case STMF_SUCCESS:
1314 		return (0);
1315 	case STMF_INVALID_ARG:
1316 		return (EINVAL);
1317 	case STMF_ALREADY:
1318 		return (EEXIST);
1319 	default:
1320 		return (EIO);
1321 	}
1322 }
1323 
1324 /*
1325  * Group can only be removed only when it does not have
1326  * any view entry related
1327  */
1328 int
1329 stmf_remove_group(uint8_t *grpname, uint16_t grpname_size,
1330     stmf_id_type_t group_type, uint32_t *err_detail)
1331 {
1332 	stmf_id_data_t *id;
1333 	stmf_id_data_t *idmemb;
1334 	stmf_id_list_t *grp_memblist;
1335 	stmf_i_scsi_session_t *iss;
1336 	stmf_i_local_port_t *ilport;
1337 
1338 	if (grpname[0] == '*')
1339 		return (EINVAL);
1340 
1341 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
1342 
1343 	if (group_type == STMF_ID_TYPE_HOST_GROUP)
1344 		id = stmf_lookup_id(&stmf_state.stmf_hg_list,
1345 		    grpname_size, grpname);
1346 	else if (group_type == STMF_ID_TYPE_TARGET_GROUP)
1347 		id = stmf_lookup_id(&stmf_state.stmf_tg_list,
1348 		    grpname_size, grpname);
1349 	if (!id) {
1350 		*err_detail = (group_type == STMF_ID_TYPE_HOST_GROUP)?
1351 		    STMF_IOCERR_INVALID_HG:STMF_IOCERR_INVALID_TG;
1352 		return (ENODEV); /* no such grp */
1353 	}
1354 	if (id->id_refcnt) {
1355 		/* fail, still have viewentry related to it */
1356 		*err_detail = (group_type == STMF_ID_TYPE_HOST_GROUP)?
1357 		    STMF_IOCERR_HG_IN_USE:STMF_IOCERR_TG_IN_USE;
1358 		return (EBUSY);
1359 	}
1360 	grp_memblist = (stmf_id_list_t *)id->id_impl_specific;
1361 	while ((idmemb = grp_memblist->idl_head) != NULL) {
1362 		stmf_remove_id(grp_memblist, idmemb);
1363 		stmf_free_id(idmemb);
1364 	}
1365 
1366 	ASSERT(!grp_memblist->id_count);
1367 	if (id->id_type == STMF_ID_TYPE_TARGET_GROUP) {
1368 		for (ilport = stmf_state.stmf_ilportlist; ilport;
1369 		    ilport = ilport->ilport_next) {
1370 			if (ilport->ilport_tg == (void *)id) {
1371 				ilport->ilport_tg = NULL;
1372 			}
1373 		}
1374 		stmf_remove_id(&stmf_state.stmf_tg_list, id);
1375 	} else {
1376 		for (ilport = stmf_state.stmf_ilportlist; ilport;
1377 		    ilport = ilport->ilport_next) {
1378 			for (iss = ilport->ilport_ss_list; iss;
1379 			    iss = iss->iss_next) {
1380 				if (iss->iss_hg == (void *)id)
1381 					iss->iss_hg = NULL;
1382 			}
1383 		}
1384 		stmf_remove_id(&stmf_state.stmf_hg_list, id);
1385 	}
1386 	stmf_free_id(id);
1387 	return (0);
1388 
1389 }
1390 
1391 int
1392 stmf_add_group_member(uint8_t *grpname, uint16_t grpname_size,
1393     uint8_t *entry_ident, uint16_t entry_size,
1394     stmf_id_type_t entry_type, uint32_t *err_detail)
1395 {
1396 	stmf_id_data_t	*id_grp, *id_alltgt;
1397 	stmf_id_data_t	*id_member;
1398 	stmf_id_data_t	*id_grp_tmp;
1399 	stmf_i_scsi_session_t *iss;
1400 	stmf_i_local_port_t *ilport;
1401 	stmf_lun_map_t *vemap, *vemap_alltgt;
1402 	uint8_t grpname_forall = '*';
1403 
1404 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
1405 	ASSERT(grpname[0] != '*');
1406 
1407 	if (entry_type == STMF_ID_TYPE_HOST) {
1408 		id_grp = stmf_lookup_id(&stmf_state.stmf_hg_list,
1409 		    grpname_size, grpname);
1410 		id_grp_tmp = stmf_lookup_group_for_host(entry_ident,
1411 		    entry_size);
1412 	} else {
1413 		id_grp = stmf_lookup_id(&stmf_state.stmf_tg_list,
1414 		    grpname_size, grpname);
1415 		id_grp_tmp = stmf_lookup_group_for_target(entry_ident,
1416 		    entry_size);
1417 	}
1418 	if (id_grp == NULL) {
1419 		*err_detail = (entry_type == STMF_ID_TYPE_HOST)?
1420 		    STMF_IOCERR_INVALID_HG:STMF_IOCERR_INVALID_TG;
1421 		return (ENODEV); /* not found */
1422 	}
1423 
1424 	/* Check whether this member already bound to a group */
1425 	if (id_grp_tmp) {
1426 		if (id_grp_tmp != id_grp) {
1427 			*err_detail = (entry_type == STMF_ID_TYPE_HOST)?
1428 			    STMF_IOCERR_HG_ENTRY_EXISTS:
1429 			    STMF_IOCERR_TG_ENTRY_EXISTS;
1430 			return (EEXIST); /* already added into another grp */
1431 		}
1432 		else
1433 			return (0);
1434 	}
1435 
1436 	/* verify target is offline */
1437 	if (entry_type == STMF_ID_TYPE_TARGET) {
1438 		ilport = stmf_targetident_to_ilport(entry_ident, entry_size);
1439 		if (ilport && ilport->ilport_state != STMF_STATE_OFFLINE) {
1440 			*err_detail = STMF_IOCERR_TG_NEED_TG_OFFLINE;
1441 			return (EBUSY);
1442 		}
1443 	}
1444 
1445 	id_member = stmf_alloc_id(entry_size, entry_type,
1446 	    entry_ident, 0);
1447 	stmf_append_id((stmf_id_list_t *)id_grp->id_impl_specific, id_member);
1448 
1449 	if (entry_type == STMF_ID_TYPE_TARGET) {
1450 		ilport = stmf_targetident_to_ilport(entry_ident, entry_size);
1451 		if (ilport)
1452 			ilport->ilport_tg = (void *)id_grp;
1453 		return (0);
1454 	}
1455 	/* For host group member, update the session if needed */
1456 	if (!stmf_state.stmf_service_running)
1457 		return (0);
1458 	/* Need to consider all target group + this host group */
1459 	id_alltgt = stmf_lookup_id(&stmf_state.stmf_tg_list,
1460 	    1, &grpname_forall);
1461 	vemap_alltgt = stmf_get_ve_map_per_ids(id_alltgt, id_grp);
1462 
1463 	/* check whether there are sessions may be affected */
1464 	for (ilport = stmf_state.stmf_ilportlist; ilport;
1465 	    ilport = ilport->ilport_next) {
1466 		if (ilport->ilport_state != STMF_STATE_ONLINE)
1467 			continue;
1468 		iss = stmf_lookup_session_for_hostident(ilport,
1469 		    entry_ident, entry_size);
1470 		if (iss) {
1471 			stmf_id_data_t *tgid;
1472 			iss->iss_hg = (void *)id_grp;
1473 			tgid = ilport->ilport_tg;
1474 			rw_enter(iss->iss_lockp, RW_WRITER);
1475 			if (tgid) {
1476 				vemap = stmf_get_ve_map_per_ids(tgid, id_grp);
1477 				if (vemap)
1478 					stmf_add_lus_to_session_per_vemap(
1479 					    ilport, iss, vemap);
1480 			}
1481 			if (vemap_alltgt)
1482 				stmf_add_lus_to_session_per_vemap(ilport,
1483 				    iss, vemap_alltgt);
1484 			rw_exit(iss->iss_lockp);
1485 		}
1486 	}
1487 
1488 	return (0);
1489 }
1490 
1491 int
1492 stmf_remove_group_member(uint8_t *grpname, uint16_t grpname_size,
1493     uint8_t *entry_ident, uint16_t entry_size,
1494     stmf_id_type_t entry_type, uint32_t *err_detail)
1495 {
1496 	stmf_id_data_t	*id_grp, *id_alltgt;
1497 	stmf_id_data_t	*id_member;
1498 	stmf_lun_map_t *vemap,  *vemap_alltgt;
1499 	uint8_t grpname_forall = '*';
1500 	stmf_i_local_port_t *ilport;
1501 	stmf_i_scsi_session_t *iss;
1502 
1503 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
1504 	ASSERT(grpname[0] != '*');
1505 
1506 	if (entry_type == STMF_ID_TYPE_HOST) {
1507 		id_grp = stmf_lookup_id(&stmf_state.stmf_hg_list,
1508 		    grpname_size, grpname);
1509 	} else {
1510 		id_grp = stmf_lookup_id(&stmf_state.stmf_tg_list,
1511 		    grpname_size, grpname);
1512 	}
1513 	if (id_grp == NULL) {
1514 		*err_detail = (entry_type == STMF_ID_TYPE_HOST)?
1515 		    STMF_IOCERR_INVALID_HG:STMF_IOCERR_INVALID_TG;
1516 		return (ENODEV); /* no such group */
1517 	}
1518 	id_member = stmf_lookup_id((stmf_id_list_t *)id_grp->id_impl_specific,
1519 	    entry_size, entry_ident);
1520 	if (!id_member) {
1521 		*err_detail = (entry_type == STMF_ID_TYPE_HOST)?
1522 		    STMF_IOCERR_INVALID_HG_ENTRY:STMF_IOCERR_INVALID_TG_ENTRY;
1523 		return (ENODEV); /* no such member */
1524 	}
1525 	/* verify target is offline */
1526 	if (entry_type == STMF_ID_TYPE_TARGET) {
1527 		ilport = stmf_targetident_to_ilport(entry_ident, entry_size);
1528 		if (ilport && ilport->ilport_state != STMF_STATE_OFFLINE) {
1529 			*err_detail = STMF_IOCERR_TG_NEED_TG_OFFLINE;
1530 			return (EBUSY);
1531 		}
1532 	}
1533 
1534 	stmf_remove_id((stmf_id_list_t *)id_grp->id_impl_specific, id_member);
1535 	stmf_free_id(id_member);
1536 
1537 	if (entry_type == STMF_ID_TYPE_TARGET) {
1538 		ilport = stmf_targetident_to_ilport(entry_ident, entry_size);
1539 		if (ilport)
1540 			ilport->ilport_tg = NULL;
1541 		return (0);
1542 	}
1543 	/* For host group member, update the session */
1544 	if (!stmf_state.stmf_service_running)
1545 		return (0);
1546 
1547 	/* Need to consider all target group + this host group */
1548 	id_alltgt = stmf_lookup_id(&stmf_state.stmf_tg_list,
1549 	    1, &grpname_forall);
1550 	vemap_alltgt = stmf_get_ve_map_per_ids(id_alltgt, id_grp);
1551 
1552 	/* check if there are session related, if so, update it */
1553 	for (ilport = stmf_state.stmf_ilportlist; ilport;
1554 	    ilport = ilport->ilport_next) {
1555 		if (ilport->ilport_state != STMF_STATE_ONLINE)
1556 			continue;
1557 		iss = stmf_lookup_session_for_hostident(ilport,
1558 		    entry_ident, entry_size);
1559 		if (iss) {
1560 			stmf_id_data_t *tgid;
1561 			rw_enter(iss->iss_lockp, RW_WRITER);
1562 			iss->iss_hg = NULL;
1563 			tgid = ilport->ilport_tg;
1564 			if (tgid) {
1565 				vemap = stmf_get_ve_map_per_ids(tgid, id_grp);
1566 				if (vemap)
1567 					stmf_remove_lus_from_session_per_vemap(
1568 					    iss, vemap);
1569 			}
1570 			if (vemap_alltgt)
1571 				stmf_remove_lus_from_session_per_vemap(iss,
1572 				    vemap_alltgt);
1573 			rw_exit(iss->iss_lockp);
1574 		}
1575 	}
1576 
1577 	return (0);
1578 }
1579 
1580 /* Assert stmf_lock is already held */
1581 stmf_i_local_port_t *
1582 stmf_targetident_to_ilport(uint8_t *target_ident, uint16_t ident_size)
1583 {
1584 	stmf_i_local_port_t *ilport;
1585 	uint8_t *id;
1586 
1587 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
1588 
1589 	for (ilport = stmf_state.stmf_ilportlist; ilport;
1590 	    ilport = ilport->ilport_next) {
1591 		id = (uint8_t *)ilport->ilport_lport->lport_id;
1592 		if ((id[3] == ident_size) &&
1593 		    bcmp(id + 4, target_ident, ident_size) == 0) {
1594 			return (ilport);
1595 		}
1596 	}
1597 	return (NULL);
1598 }
1599 
1600 stmf_i_scsi_session_t *
1601 stmf_lookup_session_for_hostident(stmf_i_local_port_t *ilport,
1602     uint8_t *host_ident, uint16_t ident_size)
1603 {
1604 	stmf_i_scsi_session_t *iss;
1605 	uint8_t *id;
1606 
1607 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
1608 
1609 	for (iss = ilport->ilport_ss_list; iss; iss = iss->iss_next) {
1610 		id = (uint8_t *)iss->iss_ss->ss_rport_id;
1611 		if ((id[3] == ident_size) &&
1612 		    bcmp(id + 4, host_ident, ident_size) == 0) {
1613 			return (iss);
1614 		}
1615 	}
1616 	return (NULL);
1617 }
1618 
1619 stmf_i_lu_t *
1620 stmf_luident_to_ilu(uint8_t *lu_ident)
1621 {
1622 	stmf_i_lu_t *ilu;
1623 
1624 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
1625 
1626 	for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
1627 		if (bcmp(&ilu->ilu_lu->lu_id->ident[0], lu_ident, 16) == 0)
1628 			return (ilu);
1629 	}
1630 
1631 	return (NULL);
1632 }
1633 
1634 /*
1635  * Assert stmf_lock is already held,
1636  * Just get the view map for the specific target group and host group
1637  * tgid and hgid can not be NULL
1638  */
1639 stmf_lun_map_t *
1640 stmf_get_ve_map_per_ids(stmf_id_data_t *tgid, stmf_id_data_t *hgid)
1641 {
1642 	int found = 0;
1643 	stmf_ver_tg_t *vertg;
1644 	stmf_ver_hg_t *verhg;
1645 
1646 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
1647 
1648 	for (vertg = stmf_state.stmf_ver_tg_head;
1649 	    vertg; vertg = vertg->vert_next) {
1650 		if (vertg->vert_tg_ref == tgid) {
1651 			found = 1;
1652 			break;
1653 		}
1654 	}
1655 	if (!found)
1656 		return (NULL);
1657 
1658 	for (verhg = vertg->vert_verh_list; verhg; verhg = verhg->verh_next) {
1659 		if (verhg->verh_hg_ref == hgid) {
1660 			return (&verhg->verh_ve_map);
1661 		}
1662 	}
1663 	return (NULL);
1664 }
1665 
1666 stmf_status_t
1667 stmf_validate_lun_view_entry(stmf_id_data_t *hg, stmf_id_data_t *tg,
1668     uint8_t *lun, uint32_t *err_detail)
1669 {
1670 	char			*phg, *ptg;
1671 	stmf_lun_map_t		*ve_map = NULL;
1672 	stmf_ver_hg_t		*verhg = NULL;
1673 	stmf_ver_tg_t		*vertg = NULL;
1674 	uint16_t		lun_num;
1675 	stmf_status_t		ret = STMF_SUCCESS;
1676 
1677 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
1678 
1679 	ve_map = stmf_duplicate_ve_map(0);
1680 	for (vertg = stmf_state.stmf_ver_tg_head; vertg != NULL;
1681 	    vertg = vertg->vert_next) {
1682 		ptg = (char *)vertg->vert_tg_ref->id_data;
1683 		if ((ptg[0] != '*') && (tg->id_data[0] != '*') &&
1684 		    (vertg->vert_tg_ref != tg)) {
1685 			continue;
1686 		}
1687 		for (verhg = vertg->vert_verh_list; verhg != NULL;
1688 		    verhg = verhg->verh_next) {
1689 			phg = (char *)verhg->verh_hg_ref->id_data;
1690 			if ((phg[0] != '*') && (hg->id_data[0] != '*') &&
1691 			    (verhg->verh_hg_ref != hg)) {
1692 				continue;
1693 			}
1694 			(void) stmf_merge_ve_map(&verhg->verh_ve_map, ve_map,
1695 			    &ve_map, 0);
1696 		}
1697 	}
1698 
1699 	ret = STMF_SUCCESS;
1700 	/* Return an available lun number */
1701 	if (lun[2] == 0xFF) {
1702 		/* Pick a LUN number */
1703 		lun_num = stmf_get_next_free_lun(ve_map, lun);
1704 		if (lun_num > 0x3FFF)
1705 			ret = STMF_NOT_SUPPORTED;
1706 	} else {
1707 		lun_num = (uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8);
1708 		if (stmf_get_ent_from_map(ve_map, lun_num) != NULL) {
1709 			*err_detail = STMF_IOCERR_LU_NUMBER_IN_USE;
1710 			ret = STMF_LUN_TAKEN;
1711 		}
1712 	}
1713 	stmf_destroy_ve_map(ve_map);
1714 
1715 	return (ret);
1716 }
1717 
1718 int
1719 stmf_validate_lun_ve(uint8_t *hgname, uint16_t hgname_size,
1720     uint8_t *tgname, uint16_t tgname_size,
1721     uint8_t *luNbr, uint32_t *err_detail)
1722 {
1723 	stmf_id_data_t		*hg;
1724 	stmf_id_data_t		*tg;
1725 	stmf_status_t		ret;
1726 
1727 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
1728 
1729 	hg = stmf_lookup_id(&stmf_state.stmf_hg_list, hgname_size,
1730 	    (uint8_t *)hgname);
1731 	if (!hg) {
1732 		*err_detail = STMF_IOCERR_INVALID_HG;
1733 		return (ENOENT); /* could not find group */
1734 	}
1735 	tg = stmf_lookup_id(&stmf_state.stmf_tg_list, tgname_size,
1736 	    (uint8_t *)tgname);
1737 	if (!tg) {
1738 		*err_detail = STMF_IOCERR_INVALID_TG;
1739 		return (ENOENT); /* could not find group */
1740 	}
1741 	ret = stmf_validate_lun_view_entry(hg, tg, luNbr, err_detail);
1742 
1743 	if (ret == STMF_LUN_TAKEN) {
1744 		return (EEXIST);
1745 	} else if (ret == STMF_NOT_SUPPORTED) {
1746 		return (E2BIG);
1747 	} else if (ret != STMF_SUCCESS) {
1748 		return (EINVAL);
1749 	}
1750 	return (0);
1751 }
1752