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