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 } 1752