1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25#include <sys/conf.h>
26#include <sys/file.h>
27#include <sys/ddi.h>
28#include <sys/sunddi.h>
29#include <sys/modctl.h>
30#include <sys/scsi/scsi.h>
31#include <sys/scsi/impl/scsi_reset_notify.h>
32#include <sys/disp.h>
33#include <sys/byteorder.h>
34#include <sys/atomic.h>
35
36#include <sys/stmf.h>
37#include <sys/lpif.h>
38#include <sys/portif.h>
39#include <sys/stmf_ioctl.h>
40
41#include "stmf_impl.h"
42#include "lun_map.h"
43#include "stmf_state.h"
44
45void stmf_update_sessions_per_ve(stmf_view_entry_t *ve,
46		stmf_lu_t *lu, int action);
47void 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);
49stmf_id_data_t *stmf_lookup_group_for_host(uint8_t *ident, uint16_t ident_size);
50stmf_status_t stmf_add_ent_to_map(stmf_lun_map_t *sm, void *ent, uint8_t *lun);
51stmf_status_t stmf_remove_ent_from_map(stmf_lun_map_t *sm, uint8_t *lun);
52uint16_t stmf_get_next_free_lun(stmf_lun_map_t *sm, uint8_t *lun);
53stmf_status_t stmf_add_tg(uint8_t *tg_name, uint16_t tg_name_size,
54		int allow_special, uint32_t *err_detail);
55stmf_status_t stmf_add_hg(uint8_t *hg_name, uint16_t hg_name_size,
56		int allow_special, uint32_t *err_detail);
57stmf_i_local_port_t *stmf_targetident_to_ilport(uint8_t *target_ident,
58		uint16_t ident_size);
59stmf_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);
62stmf_i_lu_t *stmf_luident_to_ilu(uint8_t *lu_ident);
63stmf_lun_map_t *stmf_get_ve_map_per_ids(stmf_id_data_t *tgid,
64		stmf_id_data_t *hgid);
65stmf_lun_map_t *stmf_duplicate_ve_map(stmf_lun_map_t *src);
66int 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);
68void stmf_destroy_ve_map(stmf_lun_map_t *dst);
69void stmf_free_id(stmf_id_data_t *id);
70
71
72/*
73 * Init the view
74 */
75void
76stmf_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 */
86void
87stmf_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 */
183stmf_status_t
184stmf_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 */
242stmf_status_t
243stmf_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 */
286stmf_xfer_data_t *
287stmf_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 */
335void
336stmf_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 */
361void
362stmf_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 */
394stmf_status_t
395stmf_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 */
439stmf_status_t
440stmf_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 */
474void
475stmf_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 */
541void
542stmf_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 */
566void
567stmf_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
591stmf_id_data_t *
592stmf_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
616void
617stmf_free_id(stmf_id_data_t *id)
618{
619	kmem_free(id, id->id_total_alloc_size);
620}
621
622
623stmf_id_data_t *
624stmf_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 */
638stmf_id_data_t *
639stmf_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 */
657stmf_id_data_t *
658stmf_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
676void
677stmf_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
690void
691stmf_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 */
714stmf_lun_map_t *
715stmf_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
736void
737stmf_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
745int
746stmf_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 */
817stmf_status_t
818stmf_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 */
842stmf_status_t
843stmf_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 */
872stmf_status_t
873stmf_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 */
921stmf_status_t
922stmf_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);
1060add_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
1069stmf_status_t
1070stmf_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);
1077try_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
1101stmf_status_t
1102stmf_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
1138uint16_t
1139stmf_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
1161void *
1162stmf_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
1174int
1175stmf_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
1214int
1215stmf_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
1318int
1319stmf_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 */
1349int
1350stmf_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
1412int
1413stmf_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
1510int
1511stmf_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 */
1598stmf_i_local_port_t *
1599stmf_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
1617stmf_i_scsi_session_t *
1618stmf_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
1636stmf_i_lu_t *
1637stmf_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 */
1656stmf_lun_map_t *
1657stmf_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
1683stmf_status_t
1684stmf_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
1735int
1736stmf_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