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