1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/conf.h>
26 #include <sys/file.h>
27 #include <sys/ddi.h>
28 #include <sys/sunddi.h>
29 #include <sys/modctl.h>
30 #include <sys/scsi/scsi.h>
31 #include <sys/scsi/impl/scsi_reset_notify.h>
32 #include <sys/disp.h>
33 #include <sys/byteorder.h>
34 #include <sys/atomic.h>
35
36 #include <sys/stmf.h>
37 #include <sys/lpif.h>
38 #include <sys/portif.h>
39 #include <sys/stmf_ioctl.h>
40
41 #include "stmf_impl.h"
42 #include "lun_map.h"
43 #include "stmf_state.h"
44
45 void stmf_update_sessions_per_ve(stmf_view_entry_t *ve,
46 stmf_lu_t *lu, int action);
47 void stmf_add_lus_to_session_per_vemap(stmf_i_local_port_t *ilport,
48 stmf_i_scsi_session_t *iss, stmf_lun_map_t *vemap);
49 stmf_id_data_t *stmf_lookup_group_for_host(uint8_t *ident, uint16_t ident_size);
50 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
stmf_view_init()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
stmf_view_clear_config()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
stmf_session_create_lun_map(stmf_i_local_port_t * ilport,stmf_i_scsi_session_t * iss)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
stmf_session_destroy_lun_map(stmf_i_local_port_t * ilport,stmf_i_scsi_session_t * iss)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_dec_32(&ilu->ilu_ref_cnt);
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 *
stmf_session_prepare_report_lun_data(stmf_lun_map_t * sm)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
stmf_add_lu_to_active_sessions(stmf_lu_t * lu)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
stmf_session_lu_unmapall(stmf_lu_t * lu)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
stmf_add_lu_to_session(stmf_i_local_port_t * ilport,stmf_i_scsi_session_t * iss,stmf_lu_t * lu,uint8_t * lu_nbr)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_inc_32(&ilu->ilu_ref_cnt);
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
stmf_remove_lu_from_session(stmf_i_local_port_t * ilport,stmf_i_scsi_session_t * iss,stmf_lu_t * lu,uint8_t * lu_nbr)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_dec_32(&ilu->ilu_ref_cnt);
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
stmf_update_sessions_per_ve(stmf_view_entry_t * ve,stmf_lu_t * lu,int action)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
stmf_add_lus_to_session_per_vemap(stmf_i_local_port_t * ilport,stmf_i_scsi_session_t * iss,stmf_lun_map_t * vemap)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
stmf_remove_lus_from_session_per_vemap(stmf_i_local_port_t * ilport,stmf_i_scsi_session_t * iss,stmf_lun_map_t * vemap)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 *
stmf_alloc_id(uint16_t id_size,uint16_t type,uint8_t * id_data,uint32_t additional_size)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
stmf_free_id(stmf_id_data_t * id)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 *
stmf_lookup_id(stmf_id_list_t * idlist,uint16_t id_size,uint8_t * data)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 *
stmf_lookup_group_for_target(uint8_t * ident,uint16_t ident_size)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 *
stmf_lookup_group_for_host(uint8_t * ident,uint16_t ident_size)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
stmf_append_id(stmf_id_list_t * idlist,stmf_id_data_t * id)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_inc_32(&idlist->id_count);
688 }
689
690 void
stmf_remove_id(stmf_id_list_t * idlist,stmf_id_data_t * id)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_dec_32(&idlist->id_count);
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 *
stmf_duplicate_ve_map(stmf_lun_map_t * src)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
stmf_destroy_ve_map(stmf_lun_map_t * dst)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
stmf_merge_ve_map(stmf_lun_map_t * src,stmf_lun_map_t * dst,stmf_lun_map_t ** pp_ret_map,stmf_merge_flags_t mf)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
stmf_add_hg(uint8_t * hg_name,uint16_t hg_name_size,int allow_special,uint32_t * err_detail)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
stmf_add_tg(uint8_t * tg_name,uint16_t tg_name_size,int allow_special,uint32_t * err_detail)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
stmf_add_ve_to_luid(stmf_id_data_t * luid,stmf_view_entry_t * ve)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
stmf_add_view_entry(stmf_id_data_t * hg,stmf_id_data_t * tg,uint8_t * lu_guid,uint32_t * ve_id,uint8_t * lun,stmf_view_entry_t ** conflicting,uint32_t * err_detail)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
stmf_add_ent_to_map(stmf_lun_map_t * lm,void * ent,uint8_t * lun)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
stmf_remove_ent_from_map(stmf_lun_map_t * lm,uint8_t * lun)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
stmf_get_next_free_lun(stmf_lun_map_t * sm,uint8_t * lun)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 *
stmf_get_ent_from_map(stmf_lun_map_t * sm,uint16_t lun_num)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
stmf_add_ve(uint8_t * hgname,uint16_t hgname_size,uint8_t * tgname,uint16_t tgname_size,uint8_t * lu_guid,uint32_t * ve_id,uint8_t * luNbr,uint32_t * err_detail)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
stmf_remove_ve_by_id(uint8_t * guid,uint32_t veid,uint32_t * err_detail)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
stmf_add_group(uint8_t * grpname,uint16_t grpname_size,stmf_id_type_t group_type,uint32_t * err_detail)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
stmf_remove_group(uint8_t * grpname,uint16_t grpname_size,stmf_id_type_t group_type,uint32_t * err_detail)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
stmf_add_group_member(uint8_t * grpname,uint16_t grpname_size,uint8_t * entry_ident,uint16_t entry_size,stmf_id_type_t entry_type,uint32_t * err_detail)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
stmf_remove_group_member(uint8_t * grpname,uint16_t grpname_size,uint8_t * entry_ident,uint16_t entry_size,stmf_id_type_t entry_type,uint32_t * err_detail)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 *
stmf_targetident_to_ilport(uint8_t * target_ident,uint16_t ident_size)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 *
stmf_lookup_session_for_hostident(stmf_i_local_port_t * ilport,uint8_t * host_ident,uint16_t ident_size)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 *
stmf_luident_to_ilu(uint8_t * lu_ident)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 *
stmf_get_ve_map_per_ids(stmf_id_data_t * tgid,stmf_id_data_t * hgid)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
stmf_validate_lun_view_entry(stmf_id_data_t * hg,stmf_id_data_t * tg,uint8_t * lun,uint32_t * err_detail)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
stmf_validate_lun_ve(uint8_t * hgname,uint16_t hgname_size,uint8_t * tgname,uint16_t tgname_size,uint8_t * luNbr,uint32_t * err_detail)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