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