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 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 #include <sys/cpuvar.h> 27 #include <sys/types.h> 28 #include <sys/conf.h> 29 #include <sys/file.h> 30 #include <sys/ddi.h> 31 #include <sys/sunddi.h> 32 #include <sys/modctl.h> 33 #include <sys/sysmacros.h> 34 #include <sys/sdt.h> 35 36 #include <sys/socket.h> 37 #include <sys/strsubr.h> 38 39 #include <sys/stmf.h> 40 #include <sys/stmf_ioctl.h> 41 #include <sys/portif.h> 42 #include <sys/idm/idm.h> 43 44 #define ISCSIT_TGT_SM_STRINGS 45 #include "iscsit.h" 46 #include "iscsit_isns.h" 47 48 typedef struct { 49 list_node_t te_ctx_node; 50 iscsit_tgt_event_t te_ctx_event; 51 } tgt_event_ctx_t; 52 53 static void 54 tgt_sm_event_dispatch(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx); 55 56 static void 57 tgt_sm_created(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx); 58 59 static void 60 tgt_sm_onlining(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx); 61 62 static void 63 tgt_sm_online(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx); 64 65 static void 66 tgt_sm_stmf_online(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx); 67 68 static void 69 tgt_sm_deleting_need_offline(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx); 70 71 static void 72 tgt_sm_offlining(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx); 73 74 static void 75 tgt_sm_offline(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx); 76 77 static void 78 tgt_sm_stmf_offline(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx); 79 80 static void 81 tgt_sm_deleting_stmf_dereg(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx); 82 83 static void 84 tgt_sm_deleting_stmf_dereg_fail(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx); 85 86 static void 87 tgt_sm_deleting(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx); 88 89 static void 90 iscsit_tgt_dereg_retry(void *arg); 91 92 static void 93 iscsit_tgt_dereg_task(void *arg); 94 95 static void 96 tgt_sm_new_state(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx, 97 iscsit_tgt_state_t new_state); 98 99 100 static iscsit_tgt_t * 101 iscsit_tgt_create(it_tgt_t *cfg_tgt); 102 103 static void 104 iscsit_tgt_unref(void *tgt); 105 106 static void 107 iscsit_tgt_async_wait_ref(iscsit_tgt_t *tgt, idm_refcnt_cb_t *cb_func); 108 109 static void 110 iscsit_tgt_destroy(iscsit_tgt_t *tgt); 111 112 static iscsit_tpgt_t * 113 iscsit_tgt_lookup_tpgt_locked(iscsit_tgt_t *tgt, uint16_t tag); 114 115 static iscsit_tpg_t * 116 iscsit_tpg_lookup_locked(char *tpg_name); 117 118 static iscsit_portal_t * 119 iscsit_tpg_portal_lookup_locked(iscsit_tpg_t *tpg, 120 struct sockaddr_storage *sa); 121 122 static idm_status_t 123 iscsit_tgt_online(iscsit_tgt_t *tgt); 124 125 static void 126 iscsit_tgt_offline(iscsit_tgt_t *tgt); 127 128 static idm_status_t 129 iscsit_tgt_modify(iscsit_tgt_t *tgt, it_tgt_t *cfg_tgt); 130 131 static idm_status_t 132 iscsit_tgt_merge_tpgt(iscsit_tgt_t *tgt, it_tgt_t *cfg_tgt, 133 list_t *tpgt_del_list); 134 135 static iscsit_tpgt_t * 136 iscsit_tpgt_create(it_tpgt_t *cfg_tpgt); 137 138 static iscsit_tpgt_t * 139 iscsit_tpgt_create_default(); 140 141 static void 142 iscsit_tpgt_destroy(iscsit_tpgt_t *tpgt); 143 144 static iscsit_tpg_t * 145 iscsit_tpg_create(it_tpg_t *tpg); 146 147 static void 148 iscsit_tpg_modify(iscsit_tpg_t *tpg, it_tpg_t *cfg_tpg); 149 150 static void 151 iscsit_tpg_destroy(iscsit_tpg_t *tpg); 152 153 static iscsit_portal_t * 154 iscsit_portal_create(iscsit_tpg_t *tpg, struct sockaddr_storage *sa); 155 156 static void 157 iscsit_portal_delete(iscsit_portal_t *portal); 158 159 static idm_status_t 160 iscsit_portal_online(iscsit_portal_t *portal); 161 162 static void 163 iscsit_portal_offline(iscsit_portal_t *portal); 164 165 166 167 /* 168 * Target state machine 169 */ 170 171 void 172 iscsit_tgt_sm_event(iscsit_tgt_t *tgt, iscsit_tgt_event_t event) 173 { 174 mutex_enter(&tgt->target_mutex); 175 tgt_sm_event_locked(tgt, event); 176 mutex_exit(&tgt->target_mutex); 177 } 178 179 void 180 tgt_sm_event_locked(iscsit_tgt_t *tgt, iscsit_tgt_event_t event) 181 { 182 tgt_event_ctx_t *ctx; 183 184 iscsit_tgt_hold(tgt); 185 186 ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP); 187 188 ctx->te_ctx_event = event; 189 190 list_insert_tail(&tgt->target_events, ctx); 191 /* 192 * Use the target_sm_busy flag to keep the state machine single 193 * threaded. This also serves as recursion avoidance since this 194 * flag will always be set if we call iscsit_tgt_sm_event from 195 * within the state machine code. 196 */ 197 if (!tgt->target_sm_busy) { 198 tgt->target_sm_busy = B_TRUE; 199 while (!list_is_empty(&tgt->target_events)) { 200 ctx = list_head(&tgt->target_events); 201 list_remove(&tgt->target_events, ctx); 202 idm_sm_audit_event(&tgt->target_state_audit, 203 SAS_ISCSIT_TGT, (int)tgt->target_state, 204 (int)ctx->te_ctx_event, 0); 205 mutex_exit(&tgt->target_mutex); 206 tgt_sm_event_dispatch(tgt, ctx); 207 mutex_enter(&tgt->target_mutex); 208 } 209 tgt->target_sm_busy = B_FALSE; 210 211 } 212 213 iscsit_tgt_rele(tgt); 214 } 215 216 static void 217 tgt_sm_event_dispatch(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx) 218 { 219 DTRACE_PROBE2(tgt__event, iscsit_tgt_t *, tgt, 220 tgt_event_ctx_t *, ctx); 221 222 IDM_SM_LOG(CE_NOTE, "tgt_sm_event_dispatch: tgt %p event %s(%d)", 223 (void *)tgt, iscsit_te_name[ctx->te_ctx_event], ctx->te_ctx_event); 224 225 /* State independent actions */ 226 switch (ctx->te_ctx_event) { 227 case TE_DELETE: 228 tgt->target_deleting = B_TRUE; 229 break; 230 } 231 232 /* State dependent actions */ 233 switch (tgt->target_state) { 234 case TS_CREATED: 235 tgt_sm_created(tgt, ctx); 236 break; 237 case TS_ONLINING: 238 tgt_sm_onlining(tgt, ctx); 239 break; 240 case TS_ONLINE: 241 tgt_sm_online(tgt, ctx); 242 break; 243 case TS_STMF_ONLINE: 244 tgt_sm_stmf_online(tgt, ctx); 245 break; 246 case TS_DELETING_NEED_OFFLINE: 247 tgt_sm_deleting_need_offline(tgt, ctx); 248 break; 249 case TS_OFFLINING: 250 tgt_sm_offlining(tgt, ctx); 251 break; 252 case TS_OFFLINE: 253 tgt_sm_offline(tgt, ctx); 254 break; 255 case TS_STMF_OFFLINE: 256 tgt_sm_stmf_offline(tgt, ctx); 257 break; 258 case TS_DELETING_STMF_DEREG: 259 tgt_sm_deleting_stmf_dereg(tgt, ctx); 260 break; 261 case TS_DELETING_STMF_DEREG_FAIL: 262 tgt_sm_deleting_stmf_dereg_fail(tgt, ctx); 263 break; 264 case TS_DELETING: 265 tgt_sm_deleting(tgt, ctx); 266 break; 267 default: 268 ASSERT(0); 269 } 270 271 kmem_free(ctx, sizeof (*ctx)); 272 } 273 274 static void 275 tgt_sm_created(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx) 276 { 277 stmf_change_status_t scs; 278 279 switch (ctx->te_ctx_event) { 280 case TE_STMF_ONLINE_REQ: 281 tgt_sm_new_state(tgt, ctx, TS_ONLINING); 282 break; 283 case TE_DELETE: 284 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG); 285 break; 286 case TE_STMF_OFFLINE_REQ: 287 /* 288 * We're already offline but update to an equivelant 289 * state just to note that STMF talked to us. 290 */ 291 scs.st_completion_status = STMF_SUCCESS; 292 scs.st_additional_info = NULL; 293 tgt_sm_new_state(tgt, ctx, TS_OFFLINE); 294 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE, 295 tgt->target_stmf_lport, &scs); 296 break; 297 case TE_STMF_ONLINE_COMPLETE_ACK: 298 case TE_STMF_OFFLINE_COMPLETE_ACK: 299 /* Ignore */ 300 break; 301 default: 302 ASSERT(0); 303 } 304 } 305 306 static void 307 tgt_sm_onlining(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx) 308 { 309 stmf_change_status_t scs; 310 311 switch (ctx->te_ctx_event) { 312 case TE_ONLINE_SUCCESS: 313 tgt_sm_new_state(tgt, ctx, TS_ONLINE); 314 break; 315 case TE_ONLINE_FAIL: 316 tgt_sm_new_state(tgt, ctx, TS_STMF_OFFLINE); 317 break; 318 case TE_DELETE: 319 /* TE_DELETE is handled in tgt_sm_event_dispatch() */ 320 break; 321 case TE_STMF_ONLINE_REQ: 322 case TE_STMF_OFFLINE_REQ: 323 /* 324 * We can't complete STMF's request since we are busy going 325 * online. 326 */ 327 scs.st_completion_status = STMF_INVALID_ARG; 328 scs.st_additional_info = NULL; 329 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ? 330 STMF_CMD_LPORT_ONLINE_COMPLETE : 331 STMF_CMD_LPORT_OFFLINE_COMPLETE, 332 tgt->target_stmf_lport, &scs); 333 break; 334 case TE_STMF_ONLINE_COMPLETE_ACK: 335 case TE_STMF_OFFLINE_COMPLETE_ACK: 336 /* Ignore */ 337 break; 338 default: 339 ASSERT(0); 340 } 341 } 342 343 static void 344 tgt_sm_online(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx) 345 { 346 stmf_change_status_t scs; 347 348 switch (ctx->te_ctx_event) { 349 case TE_STMF_ONLINE_COMPLETE_ACK: 350 if (tgt->target_deleting) { 351 tgt_sm_new_state(tgt, ctx, TS_DELETING_NEED_OFFLINE); 352 } else { 353 tgt_sm_new_state(tgt, ctx, TS_STMF_ONLINE); 354 } 355 break; 356 case TE_DELETE: 357 /* TE_DELETE is handled in tgt_sm_event_dispatch() */ 358 break; 359 case TE_STMF_ONLINE_REQ: 360 case TE_STMF_OFFLINE_REQ: 361 /* 362 * We can't complete STMF's request since we are busy going 363 * online (waiting for acknowlegement from STMF) 364 */ 365 scs.st_completion_status = STMF_INVALID_ARG; 366 scs.st_additional_info = NULL; 367 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ? 368 STMF_CMD_LPORT_ONLINE_COMPLETE : 369 STMF_CMD_LPORT_OFFLINE_COMPLETE, 370 tgt->target_stmf_lport, &scs); 371 break; 372 case TE_STMF_OFFLINE_COMPLETE_ACK: 373 /* Ignore */ 374 break; 375 default: 376 ASSERT(0); 377 } 378 } 379 380 381 static void 382 tgt_sm_stmf_online(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx) 383 { 384 stmf_change_status_t scs; 385 386 /* Deregister target with iSNS whenever we leave this state */ 387 388 switch (ctx->te_ctx_event) { 389 case TE_DELETE: 390 (void) iscsit_isns_deregister(tgt); 391 tgt_sm_new_state(tgt, ctx, TS_DELETING_NEED_OFFLINE); 392 break; 393 case TE_STMF_OFFLINE_REQ: 394 (void) iscsit_isns_deregister(tgt); 395 tgt_sm_new_state(tgt, ctx, TS_OFFLINING); 396 break; 397 case TE_STMF_ONLINE_REQ: 398 /* Already online */ 399 scs.st_completion_status = STMF_ALREADY; 400 scs.st_additional_info = NULL; 401 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, 402 tgt->target_stmf_lport, &scs); 403 break; 404 case TE_STMF_ONLINE_COMPLETE_ACK: 405 case TE_STMF_OFFLINE_COMPLETE_ACK: 406 /* Ignore */ 407 break; 408 default: 409 ASSERT(0); 410 } 411 } 412 413 414 static void 415 tgt_sm_deleting_need_offline(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx) 416 { 417 stmf_change_status_t scs; 418 419 switch (ctx->te_ctx_event) { 420 case TE_STMF_OFFLINE_REQ: 421 tgt_sm_new_state(tgt, ctx, TS_OFFLINING); 422 break; 423 case TE_DELETE: 424 /* TE_DELETE is handled in tgt_sm_event_dispatch() */ 425 break; 426 case TE_STMF_ONLINE_REQ: 427 /* 428 * We can't complete STMF's request since we need to be offlined 429 */ 430 scs.st_completion_status = STMF_INVALID_ARG; 431 scs.st_additional_info = NULL; 432 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, 433 tgt->target_stmf_lport, &scs); 434 break; 435 case TE_STMF_ONLINE_COMPLETE_ACK: 436 case TE_STMF_OFFLINE_COMPLETE_ACK: 437 /* Ignore */ 438 break; 439 default: 440 ASSERT(0); 441 } 442 } 443 444 445 static void 446 tgt_sm_offlining(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx) 447 { 448 stmf_change_status_t scs; 449 450 switch (ctx->te_ctx_event) { 451 case TE_OFFLINE_COMPLETE: 452 tgt_sm_new_state(tgt, ctx, TS_OFFLINE); 453 break; 454 case TE_DELETE: 455 /* TE_DELETE is handled in tgt_sm_event_dispatch() */ 456 break; 457 case TE_STMF_ONLINE_REQ: 458 case TE_STMF_OFFLINE_REQ: 459 /* 460 * We can't complete STMF's request since we are busy going 461 * offline. 462 */ 463 scs.st_completion_status = STMF_INVALID_ARG; 464 scs.st_additional_info = NULL; 465 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ? 466 STMF_CMD_LPORT_ONLINE_COMPLETE : 467 STMF_CMD_LPORT_OFFLINE_COMPLETE, 468 tgt->target_stmf_lport, &scs); 469 break; 470 case TE_STMF_ONLINE_COMPLETE_ACK: 471 case TE_STMF_OFFLINE_COMPLETE_ACK: 472 /* Ignore */ 473 break; 474 default: 475 ASSERT(0); 476 } 477 } 478 479 480 static void 481 tgt_sm_offline(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx) 482 { 483 stmf_change_status_t scs; 484 485 switch (ctx->te_ctx_event) { 486 case TE_STMF_OFFLINE_COMPLETE_ACK: 487 if (tgt->target_deleting) { 488 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG); 489 } else { 490 tgt_sm_new_state(tgt, ctx, TS_STMF_OFFLINE); 491 } 492 break; 493 case TE_DELETE: 494 /* TE_DELETE is handled in tgt_sm_event_dispatch() */ 495 break; 496 case TE_STMF_ONLINE_REQ: 497 case TE_STMF_OFFLINE_REQ: 498 /* 499 * We can't complete STMF's request since we are busy going 500 * offline. 501 */ 502 scs.st_completion_status = STMF_INVALID_ARG; 503 scs.st_additional_info = NULL; 504 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ? 505 STMF_CMD_LPORT_ONLINE_COMPLETE : 506 STMF_CMD_LPORT_OFFLINE_COMPLETE, 507 tgt->target_stmf_lport, &scs); 508 break; 509 case TE_STMF_ONLINE_COMPLETE_ACK: 510 /* Ignore */ 511 break; 512 default: 513 ASSERT(0); 514 } 515 } 516 517 518 static void 519 tgt_sm_stmf_offline(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx) 520 { 521 stmf_change_status_t scs; 522 523 switch (ctx->te_ctx_event) { 524 case TE_STMF_ONLINE_REQ: 525 tgt_sm_new_state(tgt, ctx, TS_ONLINING); 526 break; 527 case TE_DELETE: 528 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG); 529 break; 530 case TE_STMF_OFFLINE_REQ: 531 /* Already offline */ 532 scs.st_completion_status = STMF_ALREADY; 533 scs.st_additional_info = NULL; 534 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE, 535 tgt->target_stmf_lport, &scs); 536 break; 537 case TE_STMF_ONLINE_COMPLETE_ACK: 538 case TE_STMF_OFFLINE_COMPLETE_ACK: 539 /* Ignore */ 540 break; 541 default: 542 ASSERT(0); 543 } 544 } 545 546 547 static void 548 tgt_sm_deleting_stmf_dereg(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx) 549 { 550 stmf_change_status_t scs; 551 552 /* Terminal state, no events */ 553 switch (ctx->te_ctx_event) { 554 case TE_STMF_ONLINE_REQ: 555 case TE_STMF_OFFLINE_REQ: 556 /* 557 * We can't complete STMF's request since we are being deleted 558 */ 559 scs.st_completion_status = STMF_INVALID_ARG; 560 scs.st_additional_info = NULL; 561 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ? 562 STMF_CMD_LPORT_ONLINE_COMPLETE : 563 STMF_CMD_LPORT_OFFLINE_COMPLETE, 564 tgt->target_stmf_lport, &scs); 565 break; 566 case TE_STMF_ONLINE_COMPLETE_ACK: 567 case TE_STMF_OFFLINE_COMPLETE_ACK: 568 /* Ignore */ 569 break; 570 case TE_STMF_DEREG_SUCCESS: 571 tgt_sm_new_state(tgt, ctx, TS_DELETING); 572 break; 573 case TE_STMF_DEREG_FAIL: 574 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG_FAIL); 575 break; 576 default: 577 ASSERT(0); 578 } 579 } 580 581 static void 582 tgt_sm_deleting_stmf_dereg_fail(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx) 583 { 584 stmf_change_status_t scs; 585 586 /* Terminal state, no events */ 587 switch (ctx->te_ctx_event) { 588 case TE_STMF_ONLINE_REQ: 589 case TE_STMF_OFFLINE_REQ: 590 /* 591 * We can't complete STMF's request since we are being deleted 592 */ 593 scs.st_completion_status = STMF_INVALID_ARG; 594 scs.st_additional_info = NULL; 595 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ? 596 STMF_CMD_LPORT_ONLINE_COMPLETE : 597 STMF_CMD_LPORT_OFFLINE_COMPLETE, 598 tgt->target_stmf_lport, &scs); 599 break; 600 case TE_STMF_ONLINE_COMPLETE_ACK: 601 case TE_STMF_OFFLINE_COMPLETE_ACK: 602 /* Ignore */ 603 break; 604 case TE_STMF_DEREG_RETRY: 605 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG); 606 break; 607 default: 608 ASSERT(0); 609 } 610 } 611 612 static void 613 tgt_sm_deleting(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx) 614 { 615 stmf_change_status_t scs; 616 617 /* Terminal state, no events */ 618 switch (ctx->te_ctx_event) { 619 case TE_STMF_ONLINE_REQ: 620 case TE_STMF_OFFLINE_REQ: 621 /* 622 * We can't complete STMF's request since we are being deleted 623 */ 624 scs.st_completion_status = STMF_INVALID_ARG; 625 scs.st_additional_info = NULL; 626 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ? 627 STMF_CMD_LPORT_ONLINE_COMPLETE : 628 STMF_CMD_LPORT_OFFLINE_COMPLETE, 629 tgt->target_stmf_lport, &scs); 630 break; 631 case TE_STMF_ONLINE_COMPLETE_ACK: 632 case TE_STMF_OFFLINE_COMPLETE_ACK: 633 /* Ignore */ 634 break; 635 default: 636 ASSERT(0); 637 } 638 } 639 640 641 static void 642 iscsit_tgt_dereg_retry(void *arg) 643 { 644 iscsit_tgt_t *tgt = arg; 645 646 /* 647 * Rather than guaranteeing the target state machine code will not 648 * block for long periods of time (tying up this callout thread) 649 * we will queue a task on the taskq to send the retry event. 650 * If it fails we'll setup another timeout and try again later. 651 */ 652 if (taskq_dispatch(iscsit_global.global_dispatch_taskq, 653 iscsit_tgt_dereg_task, tgt, DDI_NOSLEEP) == NULL) { 654 /* Dispatch failed, try again later */ 655 (void) timeout(iscsit_tgt_dereg_retry, tgt, 656 drv_usectohz(TGT_DEREG_RETRY_SECONDS * 1000000)); 657 } 658 } 659 660 static void 661 iscsit_tgt_dereg_task(void *arg) 662 { 663 iscsit_tgt_t *tgt = arg; 664 665 iscsit_tgt_sm_event(tgt, TE_STMF_DEREG_RETRY); 666 } 667 668 static void 669 tgt_sm_new_state(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx, 670 iscsit_tgt_state_t new_state) 671 { 672 stmf_local_port_t *lport = tgt->target_stmf_lport; 673 stmf_change_status_t scs; 674 stmf_state_change_info_t sci; 675 idm_status_t idmrc; 676 stmf_status_t stmfrc; 677 678 scs.st_completion_status = STMF_SUCCESS; 679 scs.st_additional_info = NULL; 680 681 /* 682 * Validate new state 683 */ 684 ASSERT(new_state != TS_UNDEFINED); 685 ASSERT3U(new_state, <, TS_MAX_STATE); 686 687 new_state = (new_state < TS_MAX_STATE) ? 688 new_state : TS_UNDEFINED; 689 690 IDM_SM_LOG(CE_NOTE, "tgt_sm_new_state: tgt %p, %s(%d) --> %s(%d)\n", 691 (void *) tgt, iscsit_ts_name[tgt->target_state], tgt->target_state, 692 iscsit_ts_name[new_state], new_state); 693 DTRACE_PROBE3(target__state__change, 694 iscsit_tgt_t *, tgt, tgt_event_ctx_t *, ctx, 695 iscsit_tgt_state_t, new_state); 696 697 mutex_enter(&tgt->target_mutex); 698 idm_sm_audit_state_change(&tgt->target_state_audit, SAS_ISCSIT_TGT, 699 (int)tgt->target_state, (int)new_state); 700 tgt->target_last_state = tgt->target_state; 701 tgt->target_state = new_state; 702 mutex_exit(&tgt->target_mutex); 703 704 switch (tgt->target_state) { 705 case TS_ONLINING: 706 idmrc = iscsit_tgt_online(tgt); 707 if (idmrc != IDM_STATUS_SUCCESS) { 708 scs.st_completion_status = STMF_TARGET_FAILURE; 709 iscsit_tgt_sm_event(tgt, TE_ONLINE_FAIL); 710 } else { 711 iscsit_tgt_sm_event(tgt, TE_ONLINE_SUCCESS); 712 } 713 /* 714 * Let STMF know the how the online operation completed. 715 * STMF will respond with an acknowlege later 716 */ 717 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, lport, &scs); 718 break; 719 case TS_ONLINE: 720 break; 721 case TS_STMF_ONLINE: 722 (void) iscsit_isns_register(tgt); 723 break; 724 case TS_DELETING_NEED_OFFLINE: 725 sci.st_rflags = STMF_RFLAG_STAY_OFFLINED; 726 sci.st_additional_info = "Offline for delete"; 727 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE, lport, &sci); 728 break; 729 case TS_OFFLINING: 730 /* Async callback generates completion event */ 731 iscsit_tgt_offline(tgt); 732 break; 733 case TS_OFFLINE: 734 break; 735 case TS_STMF_OFFLINE: 736 break; 737 case TS_DELETING_STMF_DEREG: 738 stmfrc = stmf_deregister_local_port(tgt->target_stmf_lport); 739 if (stmfrc == STMF_SUCCESS) { 740 iscsit_tgt_sm_event(tgt, TE_STMF_DEREG_SUCCESS); 741 } else { 742 iscsit_tgt_sm_event(tgt, TE_STMF_DEREG_FAIL); 743 } 744 break; 745 case TS_DELETING_STMF_DEREG_FAIL: 746 /* Retry dereg in 1 second */ 747 (void) timeout(iscsit_tgt_dereg_retry, tgt, 748 drv_usectohz(TGT_DEREG_RETRY_SECONDS * 1000000)); 749 break; 750 case TS_DELETING: 751 iscsit_tgt_async_wait_ref(tgt, iscsit_tgt_unref); 752 break; 753 default: 754 ASSERT(0); 755 } 756 } 757 758 759 /* 760 * Target, TPGT, TPG utility functions 761 */ 762 763 it_cfg_status_t 764 iscsit_config_merge_tgt(it_config_t *cfg) 765 { 766 it_tgt_t *cfg_tgt; 767 iscsit_tgt_t *tgt, *next_tgt; 768 it_cfg_status_t itrc = ITCFG_SUCCESS; 769 770 771 /* 772 * 1. >> Lock << 773 * 2. Removing deleted objects 774 * 3. Add deleted targets to global delete list 775 * 4. "delete" event to target state machine 776 * 5. >> Unlock << 777 * 6. Create new targets, update modified targets 778 */ 779 for (tgt = avl_first(&iscsit_global.global_target_list); 780 tgt != NULL; 781 tgt = next_tgt) { 782 next_tgt = AVL_NEXT(&iscsit_global.global_target_list, tgt); 783 784 if (it_tgt_lookup(cfg, tgt->target_name) == NULL) { 785 avl_remove(&iscsit_global.global_target_list, tgt); 786 list_insert_tail( 787 &iscsit_global.global_deleted_target_list, tgt); 788 iscsit_tgt_sm_event(tgt, TE_DELETE); 789 } 790 } 791 792 /* Now walk through the list of configured targets */ 793 for (cfg_tgt = cfg->config_tgt_list; 794 cfg_tgt != NULL; 795 cfg_tgt = cfg_tgt->tgt_next) { 796 /* See if we have an existing target */ 797 tgt = iscsit_tgt_lookup_locked(cfg_tgt->tgt_name); 798 799 if (tgt == NULL) { 800 tgt = iscsit_tgt_create(cfg_tgt); 801 if (tgt == NULL) 802 return (ITCFG_TGT_CREATE_ERR); 803 avl_add(&iscsit_global.global_target_list, tgt); 804 } else { 805 if (iscsit_tgt_modify(tgt, cfg_tgt) != 806 IDM_STATUS_SUCCESS) 807 itrc = ITCFG_MISC_ERR; 808 iscsit_tgt_rele(tgt); 809 } 810 } 811 812 /* 813 * Targets on the iscsit_global.global_deleted_target_list will remove 814 * and destroy themselves when their associated state machines reach 815 * the TS_DELETED state and all references are released. 816 */ 817 return (itrc); 818 } 819 820 iscsit_tgt_t * 821 iscsit_tgt_lookup(char *target_name) 822 { 823 iscsit_tgt_t *result; 824 825 ISCSIT_GLOBAL_LOCK(RW_READER); 826 result = iscsit_tgt_lookup_locked(target_name); 827 ISCSIT_GLOBAL_UNLOCK(); 828 829 return (result); 830 } 831 832 iscsit_tgt_t * 833 iscsit_tgt_lookup_locked(char *target_name) 834 { 835 iscsit_tgt_t tmp_tgt; 836 iscsit_tgt_t *result; 837 838 /* 839 * Use a dummy target for lookup, filling in all fields used in AVL 840 * comparison. 841 */ 842 tmp_tgt.target_name = target_name; 843 if ((result = avl_find(&iscsit_global.global_target_list, 844 &tmp_tgt, NULL)) != NULL) { 845 iscsit_tgt_hold(result); 846 } 847 848 return (result); 849 } 850 851 iscsit_tgt_t * 852 iscsit_tgt_create(it_tgt_t *cfg_tgt) 853 { 854 iscsit_tgt_t *result; 855 stmf_local_port_t *lport; 856 char *alias; 857 858 /* 859 * Each target is an STMF local port. 860 */ 861 lport = stmf_alloc(STMF_STRUCT_STMF_LOCAL_PORT, 862 sizeof (iscsit_tgt_t) + sizeof (scsi_devid_desc_t) + 863 strnlen(cfg_tgt->tgt_name, MAX_ISCSI_NODENAMELEN) + 1, 0); 864 if (lport == NULL) { 865 return (NULL); 866 } 867 868 result = lport->lport_port_private; 869 result->target_state = TS_CREATED; 870 result->target_stmf_lport_registered = 0; 871 /* Use pointer arithmetic to find scsi_devid_desc_t */ 872 result->target_devid = (scsi_devid_desc_t *)(result + 1); 873 (void) strcpy((char *)result->target_devid->ident, cfg_tgt->tgt_name); 874 result->target_devid->ident_length = 875 strnlen(cfg_tgt->tgt_name, MAX_ISCSI_NODENAMELEN); 876 result->target_devid->protocol_id = PROTOCOL_iSCSI; 877 result->target_devid->piv = 1; 878 result->target_devid->code_set = CODE_SET_ASCII; 879 result->target_devid->association = ID_IS_TARGET_PORT; 880 881 /* Store a shortcut to the target name */ 882 result->target_name = (char *)result->target_devid->ident; 883 idm_sm_audit_init(&result->target_state_audit); 884 mutex_init(&result->target_mutex, NULL, MUTEX_DEFAULT, NULL); 885 avl_create(&result->target_sess_list, iscsit_sess_avl_compare, 886 sizeof (iscsit_sess_t), offsetof(iscsit_sess_t, ist_tgt_ln)); 887 avl_create(&result->target_tpgt_list, iscsit_tpgt_avl_compare, 888 sizeof (iscsit_tpgt_t), offsetof(iscsit_tpgt_t, tpgt_tgt_ln)); 889 list_create(&result->target_events, sizeof (tgt_event_ctx_t), 890 offsetof(tgt_event_ctx_t, te_ctx_node)); 891 idm_refcnt_init(&result->target_refcnt, result); 892 idm_refcnt_init(&result->target_sess_refcnt, result); 893 894 /* Set target alias */ 895 if (nvlist_lookup_string(cfg_tgt->tgt_properties, "alias", &alias) == 0) 896 lport->lport_alias = strdup(alias); 897 898 /* Finish initializing local port */ 899 /* 900 * Would like infinite timeout, but this is about as long as can 901 * be specified to stmf on a 32 bit kernel. 902 */ 903 lport->lport_abort_timeout = 2000; /* seconds */ 904 lport->lport_id = result->target_devid; 905 lport->lport_pp = iscsit_global.global_pp; 906 lport->lport_ds = iscsit_global.global_dbuf_store; 907 lport->lport_xfer_data = &iscsit_xfer_scsi_data; 908 lport->lport_send_status = &iscsit_send_scsi_status; 909 lport->lport_task_free = &iscsit_lport_task_free; 910 lport->lport_abort = &iscsit_abort; 911 lport->lport_ctl = &iscsit_ctl; 912 result->target_stmf_lport = lport; 913 914 /* 915 * We need a global hold until the STMF-ONLINE state machine 916 * completes. Acquire that hold now, in case we need to call 917 * iscsit_tgt_destroy, which will also release the hold. 918 */ 919 iscsit_global_hold(); 920 921 /* 922 * Additional target modifications from config 923 */ 924 if (iscsit_tgt_modify(result, cfg_tgt) != IDM_STATUS_SUCCESS) { 925 iscsit_tgt_destroy(result); 926 return (NULL); 927 } 928 929 /* 930 * Register the target with STMF but not until we have all the 931 * TPGT bindings and any other additional config setup. STMF 932 * may immediately ask us to go online. 933 */ 934 if (stmf_register_local_port(lport) != STMF_SUCCESS) { 935 iscsit_tgt_destroy(result); 936 return (NULL); 937 } 938 result->target_stmf_lport_registered = 1; 939 940 return (result); 941 } 942 943 static idm_status_t 944 iscsit_tgt_modify(iscsit_tgt_t *tgt, it_tgt_t *cfg_tgt) 945 { 946 idm_status_t idmrc = IDM_STATUS_SUCCESS; 947 list_t tpgt_del_list; 948 char *alias; 949 950 /* Merge TPGT */ 951 list_create(&tpgt_del_list, sizeof (iscsit_tpgt_t), 952 offsetof(iscsit_tpgt_t, tpgt_delete_ln)); 953 954 mutex_enter(&tgt->target_mutex); 955 if (tgt->target_props) { 956 nvlist_free(tgt->target_props); 957 tgt->target_props = NULL; 958 } 959 (void) nvlist_dup(cfg_tgt->tgt_properties, &tgt->target_props, 960 KM_SLEEP); 961 962 /* Update alias */ 963 if (tgt->target_stmf_lport->lport_alias) { 964 strfree(tgt->target_stmf_lport->lport_alias); 965 tgt->target_stmf_lport->lport_alias = NULL; 966 } 967 if (nvlist_lookup_string(tgt->target_props, "alias", &alias) == 0) 968 tgt->target_stmf_lport->lport_alias = strdup(alias); 969 970 if ((idmrc = iscsit_tgt_merge_tpgt(tgt, cfg_tgt, &tpgt_del_list)) != 971 IDM_STATUS_SUCCESS) { 972 /* This should never happen */ 973 cmn_err(CE_WARN, "Fail to configure TPGTs for " 974 "target %s, the target modification could not be " 975 "completed.", tgt->target_name); 976 } 977 978 mutex_exit(&tgt->target_mutex); 979 980 iscsit_config_destroy_tpgts(&tpgt_del_list); 981 982 /* 983 * If the target is truly modified (not newly created), 984 * inform iSNS to update the target registration. 985 */ 986 if ((tgt->target_generation > 0) && 987 (cfg_tgt->tgt_generation > tgt->target_generation)) { 988 iscsit_isns_target_update(tgt); 989 } 990 991 tgt->target_generation = cfg_tgt->tgt_generation; 992 993 return (idmrc); 994 } 995 996 void 997 iscsit_config_destroy_tpgts(list_t *tpgt_del_list) 998 { 999 iscsit_tpgt_t *tpgt, *next_tpgt; 1000 1001 for (tpgt = list_head(tpgt_del_list); 1002 tpgt != NULL; 1003 tpgt = next_tpgt) { 1004 next_tpgt = list_next(tpgt_del_list, tpgt); 1005 1006 list_remove(tpgt_del_list, tpgt); 1007 idm_refcnt_wait_ref(&tpgt->tpgt_refcnt); 1008 iscsit_tpgt_destroy(tpgt); 1009 } 1010 } 1011 1012 void 1013 iscsit_tgt_unref(void *tgt_void) 1014 { 1015 iscsit_tgt_t *tgt = tgt_void; 1016 1017 ISCSIT_GLOBAL_LOCK(RW_WRITER); 1018 list_remove(&iscsit_global.global_deleted_target_list, tgt); 1019 ISCSIT_GLOBAL_UNLOCK(); 1020 iscsit_tgt_destroy(tgt); 1021 } 1022 1023 void 1024 iscsit_tgt_async_wait_ref(iscsit_tgt_t *tgt, idm_refcnt_cb_t *cb_func) 1025 { 1026 idm_refcnt_async_wait_ref(&tgt->target_refcnt, cb_func); 1027 } 1028 1029 static void 1030 iscsit_tgt_destroy(iscsit_tgt_t *tgt) 1031 { 1032 iscsit_tpgt_t *tpgt, *next_tpgt; 1033 1034 ASSERT(tgt->target_state == TS_DELETING || 1035 (tgt->target_state == TS_CREATED && 1036 tgt->target_stmf_lport_registered == 0)); 1037 1038 /* 1039 * Destroy all target portal group tags 1040 */ 1041 mutex_enter(&tgt->target_mutex); 1042 for (tpgt = avl_first(&tgt->target_tpgt_list); 1043 tpgt != NULL; 1044 tpgt = next_tpgt) { 1045 next_tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt); 1046 avl_remove(&tgt->target_tpgt_list, tpgt); 1047 iscsit_tpgt_destroy(tpgt); 1048 } 1049 1050 if (tgt->target_props) { 1051 nvlist_free(tgt->target_props); 1052 } 1053 mutex_exit(&tgt->target_mutex); 1054 1055 /* 1056 * Destroy target 1057 */ 1058 idm_refcnt_destroy(&tgt->target_sess_refcnt); 1059 idm_refcnt_destroy(&tgt->target_refcnt); 1060 list_destroy(&tgt->target_events); 1061 avl_destroy(&tgt->target_tpgt_list); 1062 avl_destroy(&tgt->target_sess_list); 1063 mutex_destroy(&tgt->target_mutex); 1064 if (tgt->target_stmf_lport->lport_alias) 1065 strfree(tgt->target_stmf_lport->lport_alias); 1066 stmf_free(tgt->target_stmf_lport); /* Also frees "tgt' */ 1067 iscsit_global_rele(); 1068 } 1069 1070 void 1071 iscsit_tgt_hold(iscsit_tgt_t *tgt) 1072 { 1073 idm_refcnt_hold(&tgt->target_refcnt); 1074 } 1075 1076 void 1077 iscsit_tgt_rele(iscsit_tgt_t *tgt) 1078 { 1079 idm_refcnt_rele(&tgt->target_refcnt); 1080 } 1081 1082 int 1083 iscsit_tgt_avl_compare(const void *void_tgt1, const void *void_tgt2) 1084 { 1085 const iscsit_tgt_t *tgt1 = void_tgt1; 1086 const iscsit_tgt_t *tgt2 = void_tgt2; 1087 int result; 1088 1089 /* 1090 * Sort by ISID first then TSIH 1091 */ 1092 result = strcmp(tgt1->target_name, tgt2->target_name); 1093 if (result < 0) { 1094 return (-1); 1095 } else if (result > 0) { 1096 return (1); 1097 } 1098 1099 return (0); 1100 } 1101 1102 1103 iscsit_tpgt_t * 1104 iscsit_tgt_lookup_tpgt(iscsit_tgt_t *tgt, uint16_t tag) 1105 { 1106 iscsit_tpgt_t *result; 1107 1108 mutex_enter(&tgt->target_mutex); 1109 result = iscsit_tgt_lookup_tpgt_locked(tgt, tag); 1110 mutex_exit(&tgt->target_mutex); 1111 1112 return (result); 1113 } 1114 1115 static iscsit_tpgt_t * 1116 iscsit_tgt_lookup_tpgt_locked(iscsit_tgt_t *tgt, uint16_t tag) 1117 { 1118 iscsit_tpgt_t tmp_tpgt; 1119 iscsit_tpgt_t *result; 1120 1121 /* Caller holds tgt->target_mutex */ 1122 tmp_tpgt.tpgt_tag = tag; 1123 if ((result = avl_find(&tgt->target_tpgt_list, &tmp_tpgt, NULL)) != 1124 NULL) { 1125 iscsit_tpgt_hold(result); 1126 } 1127 1128 return (result); 1129 } 1130 1131 iscsit_portal_t * 1132 iscsit_tgt_lookup_portal(iscsit_tgt_t *tgt, struct sockaddr_storage *sa, 1133 iscsit_tpgt_t **output_tpgt) 1134 { 1135 iscsit_tpgt_t *tpgt; 1136 iscsit_portal_t *portal; 1137 1138 /* Caller holds tgt->target_mutex */ 1139 ASSERT(mutex_owned(&tgt->target_mutex)); 1140 for (tpgt = avl_first(&tgt->target_tpgt_list); 1141 tpgt != NULL; 1142 tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt)) { 1143 portal = iscsit_tpg_portal_lookup(tpgt->tpgt_tpg, sa); 1144 if (portal) { 1145 iscsit_tpgt_hold(tpgt); 1146 *output_tpgt = tpgt; 1147 return (portal); 1148 } 1149 } 1150 1151 return (NULL); 1152 } 1153 1154 1155 void 1156 iscsit_tgt_bind_sess(iscsit_tgt_t *tgt, iscsit_sess_t *sess) 1157 { 1158 if (tgt) { 1159 sess->ist_lport = tgt->target_stmf_lport; 1160 iscsit_tgt_hold(tgt); 1161 idm_refcnt_hold(&tgt->target_sess_refcnt); 1162 mutex_enter(&tgt->target_mutex); 1163 avl_add(&tgt->target_sess_list, sess); 1164 mutex_exit(&tgt->target_mutex); 1165 } else { 1166 /* Discovery session */ 1167 sess->ist_lport = NULL; 1168 ISCSIT_GLOBAL_LOCK(RW_WRITER); 1169 avl_add(&iscsit_global.global_discovery_sessions, sess); 1170 ISCSIT_GLOBAL_UNLOCK(); 1171 } 1172 } 1173 1174 void 1175 iscsit_tgt_unbind_sess(iscsit_tgt_t *tgt, iscsit_sess_t *sess) 1176 { 1177 if (tgt) { 1178 mutex_enter(&tgt->target_mutex); 1179 avl_remove(&tgt->target_sess_list, sess); 1180 mutex_exit(&tgt->target_mutex); 1181 sess->ist_tgt = (iscsit_tgt_t *)SESS_UNBOUND_FROM_TGT; 1182 idm_refcnt_rele(&tgt->target_sess_refcnt); 1183 iscsit_tgt_rele(tgt); 1184 } else { 1185 /* Discovery session */ 1186 ISCSIT_GLOBAL_LOCK(RW_WRITER); 1187 avl_remove(&iscsit_global.global_discovery_sessions, sess); 1188 ISCSIT_GLOBAL_UNLOCK(); 1189 } 1190 } 1191 1192 #define LOCK_FOR_SESS_LOOKUP(lookup_tgt) { \ 1193 if ((lookup_tgt) == NULL) { \ 1194 ISCSIT_GLOBAL_LOCK(RW_READER); \ 1195 } else { \ 1196 mutex_enter(&(lookup_tgt)->target_mutex); \ 1197 } \ 1198 } 1199 1200 #define UNLOCK_FOR_SESS_LOOKUP(lookup_tgt) { \ 1201 if ((lookup_tgt) == NULL) { \ 1202 ISCSIT_GLOBAL_UNLOCK(); \ 1203 } else { \ 1204 mutex_exit(&(lookup_tgt)->target_mutex); \ 1205 } \ 1206 } 1207 1208 iscsit_sess_t * 1209 iscsit_tgt_lookup_sess(iscsit_tgt_t *tgt, char *initiator_name, 1210 uint8_t *isid, uint16_t tsih, uint16_t tag) 1211 { 1212 iscsit_sess_t tmp_sess; 1213 avl_tree_t *sess_avl; 1214 avl_index_t where; 1215 iscsit_sess_t *result; 1216 1217 /* 1218 * If tgt is NULL then we are looking for a discovery session 1219 */ 1220 if (tgt == NULL) { 1221 sess_avl = &iscsit_global.global_discovery_sessions; 1222 } else { 1223 sess_avl = &tgt->target_sess_list; 1224 } 1225 1226 LOCK_FOR_SESS_LOOKUP(tgt); 1227 if (avl_numnodes(sess_avl) == NULL) { 1228 UNLOCK_FOR_SESS_LOOKUP(tgt); 1229 return (NULL); 1230 } 1231 1232 /* 1233 * We'll try to find a session matching ISID + TSIH first. If we 1234 * can't find one then we will return the closest match. If the 1235 * caller needs an exact match it must compare the TSIH after 1236 * the session is returned. 1237 * 1238 * The reason we do this "fuzzy matching" is to allow matching 1239 * sessions with different TSIH values on the same AVL list. This 1240 * makes session reinstatement much easier since the new session can 1241 * live on the list at the same time as the old session is cleaning up. 1242 */ 1243 bcopy(isid, tmp_sess.ist_isid, ISCSI_ISID_LEN); 1244 tmp_sess.ist_initiator_name = initiator_name; 1245 tmp_sess.ist_tsih = tsih; 1246 tmp_sess.ist_tpgt_tag = tag; 1247 1248 result = avl_find(sess_avl, &tmp_sess, &where); 1249 if (result != NULL) { 1250 goto found_result; 1251 } 1252 1253 /* 1254 * avl_find_nearest() may return a result with a different ISID so 1255 * we should only return a result if the name and ISID match 1256 */ 1257 result = avl_nearest(sess_avl, where, AVL_BEFORE); 1258 if ((result != NULL) && 1259 (strcmp(result->ist_initiator_name, initiator_name) == 0) && 1260 (memcmp(result->ist_isid, isid, ISCSI_ISID_LEN) == 0) && 1261 (result->ist_tpgt_tag == tag)) { 1262 goto found_result; 1263 } 1264 1265 result = avl_nearest(sess_avl, where, AVL_AFTER); 1266 if ((result != NULL) && 1267 (strcmp(result->ist_initiator_name, initiator_name) == 0) && 1268 (memcmp(result->ist_isid, isid, ISCSI_ISID_LEN) == 0) && 1269 (result->ist_tpgt_tag == tag)) { 1270 goto found_result; 1271 } 1272 1273 result = NULL; 1274 1275 found_result: 1276 if ((result != NULL) && 1277 (iscsit_sess_check_hold(result) != IDM_STATUS_SUCCESS)) { 1278 result = NULL; 1279 } 1280 UNLOCK_FOR_SESS_LOOKUP(tgt); 1281 return (result); 1282 } 1283 1284 static idm_status_t 1285 iscsit_tgt_merge_tpgt(iscsit_tgt_t *tgt, it_tgt_t *cfg_tgt, 1286 list_t *tpgt_del_list) 1287 { 1288 iscsit_tpgt_t *tpgt, *next_tpgt; 1289 it_tpgt_t *cfg_tpgt; 1290 idm_status_t status = IDM_STATUS_SUCCESS; 1291 1292 /* 1293 * 1. >> Lock << 1294 * 2. Removing all objects and place on a temp list 1295 * 3. Add new objects 1296 * 4. >> Unlock << 1297 * 5. tpgt_del_list contains deleted objects 1298 */ 1299 ASSERT(avl_is_empty(&tgt->target_tpgt_list) || 1300 (tpgt_del_list != NULL)); 1301 1302 if (tpgt_del_list) { 1303 for (tpgt = avl_first(&tgt->target_tpgt_list); 1304 tpgt != NULL; tpgt = next_tpgt) { 1305 next_tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt); 1306 avl_remove(&tgt->target_tpgt_list, tpgt); 1307 if (tgt->target_state == TS_STMF_ONLINE) { 1308 tpgt->tpgt_needs_tpg_offline = B_TRUE; 1309 } 1310 list_insert_tail(tpgt_del_list, tpgt); 1311 } 1312 } 1313 1314 if (cfg_tgt->tgt_tpgt_list != NULL) { 1315 /* Add currently defined TPGTs */ 1316 for (cfg_tpgt = cfg_tgt->tgt_tpgt_list; 1317 cfg_tpgt != NULL; 1318 cfg_tpgt = cfg_tpgt->tpgt_next) { 1319 tpgt = iscsit_tpgt_create(cfg_tpgt); 1320 if (tpgt == NULL) { 1321 /* 1322 * There is a problem in the configuration we 1323 * received from the ioctl -- a missing tpg. 1324 * All the unbind operations have already 1325 * taken place. To leave the system in a 1326 * non-panic'd state, use the default tpgt. 1327 */ 1328 status = IDM_STATUS_FAIL; 1329 continue; 1330 } 1331 if (tgt->target_state == TS_STMF_ONLINE) { 1332 (void) iscsit_tpg_online(tpgt->tpgt_tpg); 1333 } 1334 avl_add(&tgt->target_tpgt_list, tpgt); 1335 } 1336 } 1337 1338 /* If no TPGTs defined, add the default TPGT */ 1339 if (avl_numnodes(&tgt->target_tpgt_list) == 0) { 1340 tpgt = iscsit_tpgt_create_default(); 1341 if (tgt->target_state == TS_STMF_ONLINE) { 1342 (void) iscsit_tpg_online(tpgt->tpgt_tpg); 1343 } 1344 avl_add(&tgt->target_tpgt_list, tpgt); 1345 } 1346 1347 return (status); 1348 } 1349 1350 static iscsit_tpgt_t * 1351 iscsit_tpgt_create(it_tpgt_t *cfg_tpgt) 1352 { 1353 iscsit_tpg_t *tpg; 1354 iscsit_tpgt_t *result; 1355 1356 /* This takes a reference on the TPG */ 1357 tpg = iscsit_tpg_lookup_locked(cfg_tpgt->tpgt_tpg_name); 1358 if (tpg == NULL) 1359 return (NULL); 1360 1361 result = kmem_zalloc(sizeof (*result), KM_SLEEP); 1362 1363 result->tpgt_tpg = tpg; 1364 result->tpgt_tag = cfg_tpgt->tpgt_tag; 1365 1366 return (result); 1367 } 1368 1369 iscsit_tpgt_t * 1370 iscsit_tpgt_create_default() 1371 { 1372 iscsit_tpgt_t *result; 1373 1374 result = kmem_zalloc(sizeof (*result), KM_SLEEP); 1375 1376 result->tpgt_tpg = iscsit_global.global_default_tpg; 1377 iscsit_tpg_hold(result->tpgt_tpg); 1378 result->tpgt_tag = ISCSIT_DEFAULT_TPGT; 1379 1380 return (result); 1381 } 1382 1383 void 1384 iscsit_tpgt_destroy(iscsit_tpgt_t *tpgt) 1385 { 1386 if (tpgt->tpgt_needs_tpg_offline) { 1387 iscsit_tpg_offline(tpgt->tpgt_tpg); 1388 } 1389 iscsit_tpg_rele(tpgt->tpgt_tpg); 1390 kmem_free(tpgt, sizeof (*tpgt)); 1391 } 1392 1393 void 1394 iscsit_tpgt_hold(iscsit_tpgt_t *tpgt) 1395 { 1396 idm_refcnt_hold(&tpgt->tpgt_refcnt); 1397 } 1398 1399 void 1400 iscsit_tpgt_rele(iscsit_tpgt_t *tpgt) 1401 { 1402 idm_refcnt_rele(&tpgt->tpgt_refcnt); 1403 } 1404 1405 int 1406 iscsit_tpgt_avl_compare(const void *void_tpgt1, const void *void_tpgt2) 1407 { 1408 const iscsit_tpgt_t *tpgt1 = void_tpgt1; 1409 const iscsit_tpgt_t *tpgt2 = void_tpgt2; 1410 1411 if (tpgt1->tpgt_tag < tpgt2->tpgt_tag) 1412 return (-1); 1413 else if (tpgt1->tpgt_tag > tpgt2->tpgt_tag) 1414 return (1); 1415 1416 return (0); 1417 } 1418 1419 static idm_status_t 1420 iscsit_tgt_online(iscsit_tgt_t *tgt) 1421 { 1422 iscsit_tpgt_t *tpgt, *tpgt_fail; 1423 idm_status_t rc; 1424 1425 mutex_enter(&tgt->target_mutex); 1426 1427 ASSERT(tgt->target_sess_list.avl_numnodes == 0); 1428 idm_refcnt_reset(&tgt->target_sess_refcnt); 1429 for (tpgt = avl_first(&tgt->target_tpgt_list); 1430 tpgt != NULL; 1431 tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt)) { 1432 rc = iscsit_tpg_online(tpgt->tpgt_tpg); 1433 if (rc != IDM_STATUS_SUCCESS) { 1434 tpgt_fail = tpgt; 1435 goto tgt_online_fail; 1436 } 1437 } 1438 1439 mutex_exit(&tgt->target_mutex); 1440 1441 return (IDM_STATUS_SUCCESS); 1442 1443 tgt_online_fail: 1444 /* Offline all the tpgs we successfully onlined up to the failure */ 1445 for (tpgt = avl_first(&tgt->target_tpgt_list); 1446 tpgt != tpgt_fail; 1447 tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt)) { 1448 iscsit_tpg_offline(tpgt->tpgt_tpg); 1449 } 1450 mutex_exit(&tgt->target_mutex); 1451 return (rc); 1452 } 1453 1454 static void 1455 iscsit_tgt_offline_cb(void *tgt_void) 1456 { 1457 iscsit_tgt_t *tgt = tgt_void; 1458 stmf_change_status_t scs; 1459 1460 iscsit_tgt_sm_event(tgt, TE_OFFLINE_COMPLETE); 1461 1462 scs.st_completion_status = STMF_SUCCESS; 1463 scs.st_additional_info = NULL; 1464 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE, 1465 tgt->target_stmf_lport, &scs); 1466 } 1467 1468 static void 1469 iscsit_tgt_offline(iscsit_tgt_t *tgt) 1470 { 1471 iscsit_tpgt_t *tpgt; 1472 iscsit_sess_t *ist; 1473 1474 mutex_enter(&tgt->target_mutex); 1475 1476 /* Offline target portal groups */ 1477 for (tpgt = avl_first(&tgt->target_tpgt_list); 1478 tpgt != NULL; 1479 tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt)) { 1480 iscsit_tpg_offline(tpgt->tpgt_tpg); 1481 } 1482 1483 /* Close any active sessions */ 1484 for (ist = avl_first(&tgt->target_sess_list); 1485 ist != NULL; 1486 ist = AVL_NEXT(&tgt->target_sess_list, ist)) { 1487 /* 1488 * This is not a synchronous operation but after all 1489 * sessions have been cleaned up there will be no 1490 * more session-related holds on the target. 1491 */ 1492 iscsit_sess_close(ist); 1493 } 1494 1495 mutex_exit(&tgt->target_mutex); 1496 1497 /* 1498 * Wait for all the sessions to quiesce. 1499 */ 1500 idm_refcnt_async_wait_ref(&tgt->target_sess_refcnt, 1501 &iscsit_tgt_offline_cb); 1502 } 1503 1504 it_cfg_status_t 1505 iscsit_config_merge_tpg(it_config_t *cfg, list_t *tpg_del_list) 1506 { 1507 it_tpg_t *cfg_tpg; 1508 iscsit_tpg_t *tpg, *next_tpg; 1509 1510 /* 1511 * 1. >> Lock << 1512 * 2. Removing deleted objects and place on a temp list 1513 * 3. Add new objects 1514 * 4. >> Unlock << 1515 * 5. tpg_del_list contains objects to destroy 1516 */ 1517 for (tpg = avl_first(&iscsit_global.global_tpg_list); 1518 tpg != NULL; 1519 tpg = next_tpg) { 1520 next_tpg = AVL_NEXT(&iscsit_global.global_tpg_list, tpg); 1521 1522 if (it_tpg_lookup(cfg, tpg->tpg_name) == NULL) { 1523 /* 1524 * The policy around when to allow a target portal 1525 * group to be deleted is implemented in libiscsit. 1526 * By the time the request gets to the kernel module 1527 * we expect that it conforms to policy so we will 1528 * cleanup all references to TPG and destroy it if it 1529 * is possible to do so. 1530 * 1531 */ 1532 avl_remove(&iscsit_global.global_tpg_list, tpg); 1533 list_insert_tail(tpg_del_list, tpg); 1534 } 1535 } 1536 1537 /* Now walk through the list of configured target portal groups */ 1538 for (cfg_tpg = cfg->config_tpg_list; 1539 cfg_tpg != NULL; 1540 cfg_tpg = cfg_tpg->tpg_next) { 1541 /* See if we have an existing target portal group */ 1542 tpg = iscsit_tpg_lookup_locked(cfg_tpg->tpg_name); 1543 1544 if (tpg == NULL) { 1545 tpg = iscsit_tpg_create(cfg_tpg); 1546 ASSERT(tpg != NULL); 1547 avl_add(&iscsit_global.global_tpg_list, tpg); 1548 } else { 1549 mutex_enter(&tpg->tpg_mutex); 1550 iscsit_tpg_modify(tpg, cfg_tpg); 1551 mutex_exit(&tpg->tpg_mutex); 1552 iscsit_tpg_rele(tpg); 1553 } 1554 } 1555 1556 return (ITCFG_SUCCESS); 1557 } 1558 1559 1560 void 1561 iscsit_config_destroy_tpgs(list_t *tpg_del_list) 1562 { 1563 iscsit_tpg_t *tpg, *next_tpg; 1564 1565 /* Now finish destroying the target portal groups */ 1566 for (tpg = list_head(tpg_del_list); 1567 tpg != NULL; 1568 tpg = next_tpg) { 1569 next_tpg = list_next(tpg_del_list, tpg); 1570 list_remove(tpg_del_list, tpg); 1571 idm_refcnt_wait_ref(&tpg->tpg_refcnt); 1572 1573 /* Kill it */ 1574 iscsit_tpg_destroy(tpg); 1575 } 1576 } 1577 1578 iscsit_tpg_t * 1579 iscsit_tpg_lookup(char *tpg_name) 1580 { 1581 iscsit_tpg_t *result; 1582 1583 ISCSIT_GLOBAL_LOCK(RW_READER); 1584 result = iscsit_tpg_lookup_locked(tpg_name); 1585 ISCSIT_GLOBAL_UNLOCK(); 1586 1587 return (result); 1588 } 1589 1590 static iscsit_tpg_t * 1591 iscsit_tpg_lookup_locked(char *tpg_name) 1592 { 1593 iscsit_tpg_t tmp_tpg; 1594 iscsit_tpg_t *result; 1595 1596 (void) strlcpy(tmp_tpg.tpg_name, tpg_name, MAX_ISCSI_NODENAMELEN); 1597 if ((result = avl_find(&iscsit_global.global_tpg_list, 1598 &tmp_tpg, NULL)) != NULL) { 1599 iscsit_tpg_hold(result); 1600 } 1601 1602 return (result); 1603 } 1604 1605 iscsit_tpg_t * 1606 iscsit_tpg_create(it_tpg_t *cfg_tpg) 1607 { 1608 iscsit_tpg_t *tpg; 1609 1610 tpg = kmem_zalloc(sizeof (*tpg), KM_SLEEP); 1611 1612 mutex_init(&tpg->tpg_mutex, NULL, MUTEX_DEFAULT, NULL); 1613 (void) strlcpy(tpg->tpg_name, cfg_tpg->tpg_name, MAX_TPG_NAMELEN); 1614 avl_create(&tpg->tpg_portal_list, iscsit_portal_avl_compare, 1615 sizeof (iscsit_portal_t), offsetof(iscsit_portal_t, portal_tpg_ln)); 1616 idm_refcnt_init(&tpg->tpg_refcnt, tpg); 1617 1618 mutex_enter(&tpg->tpg_mutex); 1619 iscsit_tpg_modify(tpg, cfg_tpg); 1620 mutex_exit(&tpg->tpg_mutex); 1621 iscsit_global_hold(); 1622 1623 return (tpg); 1624 } 1625 1626 static void 1627 iscsit_tpg_modify(iscsit_tpg_t *tpg, it_tpg_t *cfg_tpg) 1628 { 1629 iscsit_portal_t *portal, *next_portal; 1630 it_portal_t *cfg_portal; 1631 1632 /* Update portals */ 1633 for (portal = avl_first(&tpg->tpg_portal_list); 1634 portal != NULL; 1635 portal = next_portal) { 1636 next_portal = AVL_NEXT(&tpg->tpg_portal_list, portal); 1637 if (it_portal_lookup(cfg_tpg, &portal->portal_addr) == NULL) { 1638 avl_remove(&tpg->tpg_portal_list, portal); 1639 iscsit_portal_delete(portal); 1640 /* 1641 * If the last portal is deleted from the target 1642 * portal group, then the tpg->tpg_online count 1643 * must be decremented. The other two callers of 1644 * iscsit_portal_delete() destroy the target portal 1645 * after deleting the portal so it is not necessary 1646 * to decrement the tpg->tpg_online count. 1647 */ 1648 if (avl_is_empty(&tpg->tpg_portal_list)) { 1649 tpg->tpg_online--; 1650 } 1651 } 1652 } 1653 1654 for (cfg_portal = cfg_tpg->tpg_portal_list; 1655 cfg_portal != NULL; 1656 cfg_portal = cfg_portal->portal_next) { 1657 if ((portal = iscsit_tpg_portal_lookup_locked(tpg, 1658 &cfg_portal->portal_addr)) == NULL) { 1659 (void) iscsit_portal_create(tpg, 1660 &cfg_portal->portal_addr); 1661 } else { 1662 iscsit_portal_rele(portal); 1663 } 1664 } 1665 } 1666 1667 void 1668 iscsit_tpg_destroy(iscsit_tpg_t *tpg) 1669 { 1670 iscsit_portal_t *portal, *next_portal; 1671 1672 for (portal = avl_first(&tpg->tpg_portal_list); 1673 portal != NULL; 1674 portal = next_portal) { 1675 next_portal = AVL_NEXT(&tpg->tpg_portal_list, portal); 1676 avl_remove(&tpg->tpg_portal_list, portal); 1677 iscsit_portal_delete(portal); 1678 } 1679 1680 idm_refcnt_wait_ref(&tpg->tpg_refcnt); 1681 idm_refcnt_destroy(&tpg->tpg_refcnt); 1682 avl_destroy(&tpg->tpg_portal_list); 1683 mutex_destroy(&tpg->tpg_mutex); 1684 kmem_free(tpg, sizeof (*tpg)); 1685 iscsit_global_rele(); 1686 } 1687 1688 void 1689 iscsit_tpg_hold(iscsit_tpg_t *tpg) 1690 { 1691 idm_refcnt_hold(&tpg->tpg_refcnt); 1692 } 1693 1694 void 1695 iscsit_tpg_rele(iscsit_tpg_t *tpg) 1696 { 1697 idm_refcnt_rele(&tpg->tpg_refcnt); 1698 } 1699 1700 iscsit_tpg_t * 1701 iscsit_tpg_createdefault() 1702 { 1703 iscsit_tpg_t *tpg; 1704 1705 tpg = kmem_zalloc(sizeof (*tpg), KM_SLEEP); 1706 1707 mutex_init(&tpg->tpg_mutex, NULL, MUTEX_DEFAULT, NULL); 1708 (void) strlcpy(tpg->tpg_name, ISCSIT_DEFAULT_TPG, MAX_TPG_NAMELEN); 1709 avl_create(&tpg->tpg_portal_list, iscsit_portal_avl_compare, 1710 sizeof (iscsit_portal_t), offsetof(iscsit_portal_t, portal_tpg_ln)); 1711 idm_refcnt_init(&tpg->tpg_refcnt, tpg); 1712 1713 /* Now create default portal */ 1714 if (iscsit_portal_create(tpg, NULL) == NULL) { 1715 iscsit_tpg_destroy(tpg); 1716 return (NULL); 1717 } 1718 1719 return (tpg); 1720 } 1721 1722 void 1723 iscsit_tpg_destroydefault(iscsit_tpg_t *tpg) 1724 { 1725 iscsit_portal_t *portal; 1726 1727 portal = avl_first(&tpg->tpg_portal_list); 1728 ASSERT(portal != NULL); 1729 avl_remove(&tpg->tpg_portal_list, portal); 1730 iscsit_portal_delete(portal); 1731 1732 idm_refcnt_wait_ref(&tpg->tpg_refcnt); 1733 idm_refcnt_destroy(&tpg->tpg_refcnt); 1734 avl_destroy(&tpg->tpg_portal_list); 1735 mutex_destroy(&tpg->tpg_mutex); 1736 kmem_free(tpg, sizeof (*tpg)); 1737 } 1738 1739 int 1740 iscsit_tpg_avl_compare(const void *void_tpg1, const void *void_tpg2) 1741 { 1742 const iscsit_tpg_t *tpg1 = void_tpg1; 1743 const iscsit_tpg_t *tpg2 = void_tpg2; 1744 int result; 1745 1746 /* 1747 * Sort by ISID first then TSIH 1748 */ 1749 result = strcmp(tpg1->tpg_name, tpg2->tpg_name); 1750 if (result < 0) { 1751 return (-1); 1752 } else if (result > 0) { 1753 return (1); 1754 } 1755 1756 return (0); 1757 } 1758 1759 idm_status_t 1760 iscsit_tpg_online(iscsit_tpg_t *tpg) 1761 { 1762 iscsit_portal_t *portal, *portal_fail; 1763 idm_status_t rc; 1764 1765 mutex_enter(&tpg->tpg_mutex); 1766 if (tpg->tpg_online == 0) { 1767 for (portal = avl_first(&tpg->tpg_portal_list); 1768 portal != NULL; 1769 portal = AVL_NEXT(&tpg->tpg_portal_list, portal)) { 1770 rc = iscsit_portal_online(portal); 1771 if (rc != IDM_STATUS_SUCCESS) { 1772 portal_fail = portal; 1773 goto tpg_online_fail; 1774 } 1775 } 1776 } 1777 tpg->tpg_online++; 1778 1779 mutex_exit(&tpg->tpg_mutex); 1780 return (IDM_STATUS_SUCCESS); 1781 1782 tpg_online_fail: 1783 /* Offline all the portals we successfully onlined up to the failure */ 1784 for (portal = avl_first(&tpg->tpg_portal_list); 1785 portal != portal_fail; 1786 portal = AVL_NEXT(&tpg->tpg_portal_list, portal)) { 1787 iscsit_portal_offline(portal); 1788 } 1789 mutex_exit(&tpg->tpg_mutex); 1790 return (rc); 1791 } 1792 1793 void 1794 iscsit_tpg_offline(iscsit_tpg_t *tpg) 1795 { 1796 iscsit_portal_t *portal; 1797 1798 mutex_enter(&tpg->tpg_mutex); 1799 tpg->tpg_online--; 1800 if (tpg->tpg_online == 0) { 1801 for (portal = avl_first(&tpg->tpg_portal_list); 1802 portal != NULL; 1803 portal = AVL_NEXT(&tpg->tpg_portal_list, portal)) { 1804 iscsit_portal_offline(portal); 1805 } 1806 } 1807 mutex_exit(&tpg->tpg_mutex); 1808 } 1809 1810 iscsit_portal_t * 1811 iscsit_tpg_portal_lookup(iscsit_tpg_t *tpg, struct sockaddr_storage *sa) 1812 { 1813 iscsit_portal_t *result; 1814 1815 mutex_enter(&tpg->tpg_mutex); 1816 result = iscsit_tpg_portal_lookup_locked(tpg, sa); 1817 mutex_exit(&tpg->tpg_mutex); 1818 1819 return (result); 1820 } 1821 1822 static iscsit_portal_t * 1823 iscsit_tpg_portal_lookup_locked(iscsit_tpg_t *tpg, 1824 struct sockaddr_storage *sa) 1825 { 1826 iscsit_portal_t tmp_portal; 1827 iscsit_portal_t *result; 1828 1829 /* Caller holds tpg->tpg_mutex */ 1830 bcopy(sa, &tmp_portal.portal_addr, sizeof (*sa)); 1831 if ((result = avl_find(&tpg->tpg_portal_list, &tmp_portal, NULL)) != 1832 NULL) { 1833 iscsit_portal_hold(result); 1834 } 1835 1836 return (result); 1837 } 1838 1839 iscsit_portal_t * 1840 iscsit_portal_create(iscsit_tpg_t *tpg, struct sockaddr_storage *sa) 1841 { 1842 iscsit_portal_t *portal; 1843 1844 portal = kmem_zalloc(sizeof (*portal), KM_SLEEP); 1845 /* 1846 * If (sa == NULL) then we are being asked to create the default 1847 * portal -- targets will use this portal when no portals are 1848 * explicitly configured. 1849 */ 1850 if (sa == NULL) { 1851 portal->portal_default = B_TRUE; 1852 } else { 1853 portal->portal_default = B_FALSE; 1854 bcopy(sa, &portal->portal_addr, sizeof (*sa)); 1855 } 1856 1857 idm_refcnt_init(&portal->portal_refcnt, portal); 1858 1859 /* 1860 * Add this portal to the list 1861 */ 1862 avl_add(&tpg->tpg_portal_list, portal); 1863 1864 return (portal); 1865 } 1866 1867 void 1868 iscsit_portal_delete(iscsit_portal_t *portal) 1869 { 1870 if (portal->portal_online > 0) { 1871 iscsit_portal_offline(portal); 1872 } 1873 1874 if (portal->portal_online == 0) { 1875 ASSERT(portal->portal_svc == NULL); 1876 idm_refcnt_destroy(&portal->portal_refcnt); 1877 kmem_free(portal, sizeof (*portal)); 1878 } 1879 } 1880 1881 void 1882 iscsit_portal_hold(iscsit_portal_t *portal) 1883 { 1884 idm_refcnt_hold(&portal->portal_refcnt); 1885 } 1886 1887 void 1888 iscsit_portal_rele(iscsit_portal_t *portal) 1889 { 1890 idm_refcnt_rele(&portal->portal_refcnt); 1891 } 1892 1893 int 1894 iscsit_portal_avl_compare(const void *void_portal1, const void *void_portal2) 1895 { 1896 const iscsit_portal_t *portal1 = void_portal1; 1897 const iscsit_portal_t *portal2 = void_portal2; 1898 const struct sockaddr_storage *ss1, *ss2; 1899 const struct in_addr *in1, *in2; 1900 const struct in6_addr *in61, *in62; 1901 int i; 1902 1903 /* 1904 * Compare ports, then address family, then ip address 1905 */ 1906 ss1 = &portal1->portal_addr; 1907 ss2 = &portal2->portal_addr; 1908 if (((struct sockaddr_in *)ss1)->sin_port != 1909 ((struct sockaddr_in *)ss2)->sin_port) { 1910 if (((struct sockaddr_in *)ss1)->sin_port > 1911 ((struct sockaddr_in *)ss2)->sin_port) 1912 return (1); 1913 else 1914 return (-1); 1915 } 1916 1917 /* 1918 * ports are the same 1919 */ 1920 if (ss1->ss_family != ss2->ss_family) { 1921 if (ss1->ss_family == AF_INET) 1922 return (1); 1923 else 1924 return (-1); 1925 } 1926 /* 1927 * address families are the same 1928 */ 1929 if (ss1->ss_family == AF_INET) { 1930 in1 = &((struct sockaddr_in *)ss1)->sin_addr; 1931 in2 = &((struct sockaddr_in *)ss2)->sin_addr; 1932 1933 if (in1->s_addr > in2->s_addr) 1934 return (1); 1935 else if (in1->s_addr < in2->s_addr) 1936 return (-1); 1937 else 1938 return (0); 1939 } else if (ss1->ss_family == AF_INET6) { 1940 in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr; 1941 in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr; 1942 1943 for (i = 0; i < 4; i++) { 1944 if (in61->s6_addr32[i] > in62->s6_addr32[i]) 1945 return (1); 1946 else if (in61->s6_addr32[i] < in62->s6_addr32[i]) 1947 return (-1); 1948 } 1949 return (0); 1950 } else 1951 cmn_err(CE_WARN, 1952 "iscsit_portal_avl_compare: unknown ss_family %d", 1953 ss1->ss_family); 1954 1955 return (1); 1956 } 1957 1958 1959 idm_status_t 1960 iscsit_portal_online(iscsit_portal_t *portal) 1961 { 1962 idm_status_t rc = 0; 1963 idm_svc_t *svc; 1964 idm_svc_req_t sr; 1965 uint16_t port; 1966 struct sockaddr_in *sin; 1967 1968 /* Caller holds parent TPG mutex */ 1969 if (portal->portal_online == 0) { 1970 /* 1971 * If there is no existing IDM service instance for this port, 1972 * create one. If the service exists, then the lookup, 1973 * creates a reference on the existing service. 1974 */ 1975 sin = (struct sockaddr_in *)&portal->portal_addr; 1976 port = ntohs(sin->sin_port); 1977 if (port == 0) 1978 port = ISCSI_LISTEN_PORT; 1979 ASSERT(portal->portal_svc == NULL); 1980 if ((svc = idm_tgt_svc_lookup(port)) == NULL) { 1981 sr.sr_port = port; 1982 sr.sr_li = iscsit_global.global_li; 1983 sr.sr_conn_ops.icb_rx_scsi_cmd = &iscsit_op_scsi_cmd; 1984 sr.sr_conn_ops.icb_rx_scsi_rsp = NULL; 1985 sr.sr_conn_ops.icb_rx_misc = &iscsit_rx_pdu; 1986 sr.sr_conn_ops.icb_rx_error = &iscsit_rx_pdu_error; 1987 sr.sr_conn_ops.icb_task_aborted = &iscsit_task_aborted; 1988 sr.sr_conn_ops.icb_client_notify = 1989 &iscsit_client_notify; 1990 sr.sr_conn_ops.icb_build_hdr = &iscsit_build_hdr; 1991 sr.sr_conn_ops.icb_update_statsn = 1992 &iscsit_update_statsn; 1993 sr.sr_conn_ops.icb_keepalive = &iscsit_keepalive; 1994 1995 if (idm_tgt_svc_create(&sr, &svc) != 1996 IDM_STATUS_SUCCESS) { 1997 return (IDM_STATUS_FAIL); 1998 } 1999 2000 /* Get reference on the service we just created */ 2001 idm_tgt_svc_hold(svc); 2002 } 2003 if ((rc = idm_tgt_svc_online(svc)) != IDM_STATUS_SUCCESS) { 2004 idm_tgt_svc_rele_and_destroy(svc); 2005 return (IDM_STATUS_FAIL); 2006 } 2007 portal->portal_svc = svc; 2008 2009 /* 2010 * Only call iSNS for first online 2011 */ 2012 iscsit_isns_portal_online(portal); 2013 } 2014 2015 portal->portal_online++; 2016 2017 return (rc); 2018 } 2019 2020 void 2021 iscsit_portal_offline(iscsit_portal_t *portal) 2022 { 2023 portal->portal_online--; 2024 2025 if (portal->portal_online == 0) { 2026 /* 2027 * Only call iSNS for last offline 2028 */ 2029 iscsit_isns_portal_offline(portal); 2030 idm_tgt_svc_offline(portal->portal_svc); 2031 /* If service is unreferenced, destroy it too */ 2032 idm_tgt_svc_rele_and_destroy(portal->portal_svc); 2033 portal->portal_svc = NULL; 2034 } 2035 2036 } 2037 2038 it_cfg_status_t 2039 iscsit_config_merge_ini(it_config_t *cfg) 2040 { 2041 iscsit_ini_t *ini, *next_ini; 2042 it_ini_t *cfg_ini; 2043 2044 /* 2045 * Initiator objects are so simple we will just destroy all the current 2046 * objects and build new ones. Nothing should ever reference an 2047 * initator object.. instead just lookup the initiator object and 2048 * grab the properties while holding the global config lock. 2049 */ 2050 for (ini = avl_first(&iscsit_global.global_ini_list); 2051 ini != NULL; 2052 ini = next_ini) { 2053 next_ini = AVL_NEXT(&iscsit_global.global_ini_list, ini); 2054 avl_remove(&iscsit_global.global_ini_list, ini); 2055 nvlist_free(ini->ini_props); 2056 kmem_free(ini, sizeof (*ini)); 2057 iscsit_global_rele(); 2058 } 2059 2060 for (cfg_ini = cfg->config_ini_list; 2061 cfg_ini != NULL; 2062 cfg_ini = cfg_ini->ini_next) { 2063 ini = kmem_zalloc(sizeof (iscsit_ini_t), KM_SLEEP); 2064 (void) strlcpy(ini->ini_name, cfg_ini->ini_name, 2065 MAX_ISCSI_NODENAMELEN); 2066 (void) nvlist_dup(cfg_ini->ini_properties, &ini->ini_props, 2067 KM_SLEEP); 2068 avl_add(&iscsit_global.global_ini_list, ini); 2069 iscsit_global_hold(); 2070 } 2071 2072 return (ITCFG_SUCCESS); 2073 } 2074 2075 int 2076 iscsit_ini_avl_compare(const void *void_ini1, const void *void_ini2) 2077 { 2078 const iscsit_ini_t *ini1 = void_ini1; 2079 const iscsit_ini_t *ini2 = void_ini2; 2080 int result; 2081 2082 /* 2083 * Sort by ISID first then TSIH 2084 */ 2085 result = strcmp(ini1->ini_name, ini2->ini_name); 2086 if (result < 0) { 2087 return (-1); 2088 } else if (result > 0) { 2089 return (1); 2090 } 2091 2092 return (0); 2093 } 2094 2095 iscsit_ini_t * 2096 iscsit_ini_lookup_locked(char *ini_name) 2097 { 2098 iscsit_ini_t tmp_ini; 2099 iscsit_ini_t *result; 2100 2101 /* 2102 * Use a dummy target for lookup, filling in all fields used in AVL 2103 * comparison. 2104 */ 2105 (void) strlcpy(tmp_ini.ini_name, ini_name, MAX_ISCSI_NODENAMELEN); 2106 result = avl_find(&iscsit_global.global_ini_list, &tmp_ini, NULL); 2107 2108 return (result); 2109 } 2110