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 }