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