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