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