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