Home | History | Annotate | Download | only in iscsit
      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 2010 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     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 
    857 	/*
    858 	 * Each target is an STMF local port.
    859 	 */
    860 	lport = stmf_alloc(STMF_STRUCT_STMF_LOCAL_PORT,
    861 	    sizeof (iscsit_tgt_t) + sizeof (scsi_devid_desc_t) +
    862 	    strnlen(cfg_tgt->tgt_name, MAX_ISCSI_NODENAMELEN) + 1, 0);
    863 	if (lport == NULL) {
    864 		return (NULL);
    865 	}
    866 
    867 	result = lport->lport_port_private;
    868 	result->target_state = TS_CREATED;
    869 	result->target_stmf_lport_registered = 0;
    870 	/* Use pointer arithmetic to find scsi_devid_desc_t */
    871 	result->target_devid = (scsi_devid_desc_t *)(result + 1);
    872 	(void) strcpy((char *)result->target_devid->ident, cfg_tgt->tgt_name);
    873 	result->target_devid->ident_length =
    874 	    strnlen(cfg_tgt->tgt_name, MAX_ISCSI_NODENAMELEN);
    875 	result->target_devid->protocol_id = PROTOCOL_iSCSI;
    876 	result->target_devid->piv = 1;
    877 	result->target_devid->code_set = CODE_SET_ASCII;
    878 	result->target_devid->association = ID_IS_TARGET_PORT;
    879 
    880 	/* Store a shortcut to the target name */
    881 	result->target_name = (char *)result->target_devid->ident;
    882 	idm_sm_audit_init(&result->target_state_audit);
    883 	mutex_init(&result->target_mutex, NULL, MUTEX_DEFAULT, NULL);
    884 	avl_create(&result->target_sess_list, iscsit_sess_avl_compare,
    885 	    sizeof (iscsit_sess_t), offsetof(iscsit_sess_t, ist_tgt_ln));
    886 	avl_create(&result->target_tpgt_list, iscsit_tpgt_avl_compare,
    887 	    sizeof (iscsit_tpgt_t), offsetof(iscsit_tpgt_t, tpgt_tgt_ln));
    888 	list_create(&result->target_events, sizeof (tgt_event_ctx_t),
    889 	    offsetof(tgt_event_ctx_t, te_ctx_node));
    890 	idm_refcnt_init(&result->target_refcnt, result);
    891 	idm_refcnt_init(&result->target_sess_refcnt, result);
    892 
    893 	/* Finish initializing local port */
    894 	/*
    895 	 * Would like infinite timeout, but this is about as long as can
    896 	 * be specified to stmf on a 32 bit kernel.
    897 	 */
    898 	lport->lport_abort_timeout = 2000; /* seconds */
    899 	lport->lport_id = result->target_devid;
    900 	lport->lport_pp = iscsit_global.global_pp;
    901 	lport->lport_ds = iscsit_global.global_dbuf_store;
    902 	lport->lport_xfer_data = &iscsit_xfer_scsi_data;
    903 	lport->lport_send_status = &iscsit_send_scsi_status;
    904 	lport->lport_task_free = &iscsit_lport_task_free;
    905 	lport->lport_abort = &iscsit_abort;
    906 	lport->lport_ctl = &iscsit_ctl;
    907 	result->target_stmf_lport = lport;
    908 
    909 	/*
    910 	 * We need a global hold until the STMF-ONLINE state machine
    911 	 * completes.  Acquire that hold now, in case we need to call
    912 	 * iscsit_tgt_destroy, which will also release the hold.
    913 	 */
    914 	iscsit_global_hold();
    915 
    916 	/*
    917 	 * Additional target modifications from config
    918 	 */
    919 	if (iscsit_tgt_modify(result, cfg_tgt) != IDM_STATUS_SUCCESS) {
    920 		iscsit_tgt_destroy(result);
    921 		return (NULL);
    922 	}
    923 
    924 	/*
    925 	 * Register the target with STMF but not until we have all the
    926 	 * TPGT bindings and any other additional config setup.  STMF
    927 	 * may immediately ask us to go online.
    928 	 */
    929 	if (stmf_register_local_port(lport) != STMF_SUCCESS) {
    930 		iscsit_tgt_destroy(result);
    931 		return (NULL);
    932 	}
    933 	result->target_stmf_lport_registered = 1;
    934 
    935 	return (result);
    936 }
    937 
    938 static idm_status_t
    939 iscsit_tgt_modify(iscsit_tgt_t *tgt, it_tgt_t *cfg_tgt)
    940 {
    941 	idm_status_t	idmrc = IDM_STATUS_SUCCESS;
    942 	list_t		tpgt_del_list;
    943 
    944 	/* Merge TPGT */
    945 	list_create(&tpgt_del_list, sizeof (iscsit_tpgt_t),
    946 	    offsetof(iscsit_tpgt_t, tpgt_delete_ln));
    947 
    948 	mutex_enter(&tgt->target_mutex);
    949 	if (tgt->target_props) {
    950 		nvlist_free(tgt->target_props);
    951 		tgt->target_props = NULL;
    952 	}
    953 	(void) nvlist_dup(cfg_tgt->tgt_properties, &tgt->target_props,
    954 	    KM_SLEEP);
    955 
    956 	if ((idmrc = iscsit_tgt_merge_tpgt(tgt, cfg_tgt, &tpgt_del_list)) !=
    957 	    IDM_STATUS_SUCCESS) {
    958 		/* This should never happen */
    959 		cmn_err(CE_WARN, "Fail to configure TPGTs for "
    960 		    "target %s, the target modification could not be "
    961 		    "completed.", tgt->target_name);
    962 	}
    963 
    964 	mutex_exit(&tgt->target_mutex);
    965 
    966 	iscsit_config_destroy_tpgts(&tpgt_del_list);
    967 
    968 	/*
    969 	 * If the target is truly modified (not newly created),
    970 	 * inform iSNS to update the target registration.
    971 	 */
    972 	if ((tgt->target_generation > 0) &&
    973 	    (cfg_tgt->tgt_generation > tgt->target_generation)) {
    974 		iscsit_isns_target_update(tgt);
    975 	}
    976 
    977 	tgt->target_generation = cfg_tgt->tgt_generation;
    978 
    979 	return (idmrc);
    980 }
    981 
    982 void
    983 iscsit_config_destroy_tpgts(list_t *tpgt_del_list)
    984 {
    985 	iscsit_tpgt_t	*tpgt, *next_tpgt;
    986 
    987 	for (tpgt = list_head(tpgt_del_list);
    988 	    tpgt != NULL;
    989 	    tpgt = next_tpgt) {
    990 		next_tpgt = list_next(tpgt_del_list, tpgt);
    991 
    992 		list_remove(tpgt_del_list, tpgt);
    993 		idm_refcnt_wait_ref(&tpgt->tpgt_refcnt);
    994 		iscsit_tpgt_destroy(tpgt);
    995 	}
    996 }
    997 
    998 void
    999 iscsit_tgt_unref(void *tgt_void)
   1000 {
   1001 	iscsit_tgt_t	*tgt = tgt_void;
   1002 
   1003 	ISCSIT_GLOBAL_LOCK(RW_WRITER);
   1004 	list_remove(&iscsit_global.global_deleted_target_list, tgt);
   1005 	ISCSIT_GLOBAL_UNLOCK();
   1006 	iscsit_tgt_destroy(tgt);
   1007 }
   1008 
   1009 void
   1010 iscsit_tgt_async_wait_ref(iscsit_tgt_t *tgt, idm_refcnt_cb_t *cb_func)
   1011 {
   1012 	idm_refcnt_async_wait_ref(&tgt->target_refcnt, cb_func);
   1013 }
   1014 
   1015 static void
   1016 iscsit_tgt_destroy(iscsit_tgt_t *tgt)
   1017 {
   1018 	iscsit_tpgt_t *tpgt, *next_tpgt;
   1019 
   1020 	ASSERT(tgt->target_state == TS_DELETING ||
   1021 	    (tgt->target_state == TS_CREATED &&
   1022 	    tgt->target_stmf_lport_registered == 0));
   1023 
   1024 	/*
   1025 	 * Destroy all target portal group tags
   1026 	 */
   1027 	mutex_enter(&tgt->target_mutex);
   1028 	for (tpgt = avl_first(&tgt->target_tpgt_list);
   1029 	    tpgt != NULL;
   1030 	    tpgt = next_tpgt) {
   1031 		next_tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt);
   1032 		avl_remove(&tgt->target_tpgt_list, tpgt);
   1033 		iscsit_tpgt_destroy(tpgt);
   1034 	}
   1035 
   1036 	if (tgt->target_props) {
   1037 		nvlist_free(tgt->target_props);
   1038 	}
   1039 	mutex_exit(&tgt->target_mutex);
   1040 
   1041 	/*
   1042 	 * Destroy target
   1043 	 */
   1044 	idm_refcnt_destroy(&tgt->target_sess_refcnt);
   1045 	idm_refcnt_destroy(&tgt->target_refcnt);
   1046 	list_destroy(&tgt->target_events);
   1047 	avl_destroy(&tgt->target_tpgt_list);
   1048 	avl_destroy(&tgt->target_sess_list);
   1049 	mutex_destroy(&tgt->target_mutex);
   1050 	stmf_free(tgt->target_stmf_lport); /* Also frees "tgt' */
   1051 	iscsit_global_rele();
   1052 }
   1053 
   1054 void
   1055 iscsit_tgt_hold(iscsit_tgt_t *tgt)
   1056 {
   1057 	idm_refcnt_hold(&tgt->target_refcnt);
   1058 }
   1059 
   1060 void
   1061 iscsit_tgt_rele(iscsit_tgt_t *tgt)
   1062 {
   1063 	idm_refcnt_rele(&tgt->target_refcnt);
   1064 }
   1065 
   1066 int
   1067 iscsit_tgt_avl_compare(const void *void_tgt1, const void *void_tgt2)
   1068 {
   1069 	const iscsit_tgt_t	*tgt1 = void_tgt1;
   1070 	const iscsit_tgt_t	*tgt2 = void_tgt2;
   1071 	int 			result;
   1072 
   1073 	/*
   1074 	 * Sort by ISID first then TSIH
   1075 	 */
   1076 	result = strcmp(tgt1->target_name, tgt2->target_name);
   1077 	if (result < 0) {
   1078 		return (-1);
   1079 	} else if (result > 0) {
   1080 		return (1);
   1081 	}
   1082 
   1083 	return (0);
   1084 }
   1085 
   1086 
   1087 iscsit_tpgt_t *
   1088 iscsit_tgt_lookup_tpgt(iscsit_tgt_t *tgt, uint16_t tag)
   1089 {
   1090 	iscsit_tpgt_t *result;
   1091 
   1092 	mutex_enter(&tgt->target_mutex);
   1093 	result = iscsit_tgt_lookup_tpgt_locked(tgt, tag);
   1094 	mutex_exit(&tgt->target_mutex);
   1095 
   1096 	return (result);
   1097 }
   1098 
   1099 static iscsit_tpgt_t *
   1100 iscsit_tgt_lookup_tpgt_locked(iscsit_tgt_t *tgt, uint16_t tag)
   1101 {
   1102 	iscsit_tpgt_t	tmp_tpgt;
   1103 	iscsit_tpgt_t	*result;
   1104 
   1105 	/* Caller holds tgt->target_mutex */
   1106 	tmp_tpgt.tpgt_tag = tag;
   1107 	if ((result = avl_find(&tgt->target_tpgt_list, &tmp_tpgt, NULL)) !=
   1108 	    NULL) {
   1109 		iscsit_tpgt_hold(result);
   1110 	}
   1111 
   1112 	return (result);
   1113 }
   1114 
   1115 iscsit_portal_t *
   1116 iscsit_tgt_lookup_portal(iscsit_tgt_t *tgt, struct sockaddr_storage *sa,
   1117     iscsit_tpgt_t **output_tpgt)
   1118 {
   1119 	iscsit_tpgt_t 	*tpgt;
   1120 	iscsit_portal_t	*portal;
   1121 
   1122 	/* Caller holds tgt->target_mutex */
   1123 	ASSERT(mutex_owned(&tgt->target_mutex));
   1124 	for (tpgt = avl_first(&tgt->target_tpgt_list);
   1125 	    tpgt != NULL;
   1126 	    tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt)) {
   1127 		portal = iscsit_tpg_portal_lookup(tpgt->tpgt_tpg, sa);
   1128 		if (portal) {
   1129 			iscsit_tpgt_hold(tpgt);
   1130 			*output_tpgt = tpgt;
   1131 			return (portal);
   1132 		}
   1133 	}
   1134 
   1135 	return (NULL);
   1136 }
   1137 
   1138 
   1139 void
   1140 iscsit_tgt_bind_sess(iscsit_tgt_t *tgt, iscsit_sess_t *sess)
   1141 {
   1142 	if (tgt) {
   1143 		sess->ist_lport = tgt->target_stmf_lport;
   1144 		iscsit_tgt_hold(tgt);
   1145 		idm_refcnt_hold(&tgt->target_sess_refcnt);
   1146 		mutex_enter(&tgt->target_mutex);
   1147 		avl_add(&tgt->target_sess_list, sess);
   1148 		mutex_exit(&tgt->target_mutex);
   1149 	} else {
   1150 		/* Discovery session */
   1151 		sess->ist_lport = NULL;
   1152 		ISCSIT_GLOBAL_LOCK(RW_WRITER);
   1153 		avl_add(&iscsit_global.global_discovery_sessions, sess);
   1154 		ISCSIT_GLOBAL_UNLOCK();
   1155 	}
   1156 }
   1157 
   1158 void
   1159 iscsit_tgt_unbind_sess(iscsit_tgt_t *tgt, iscsit_sess_t *sess)
   1160 {
   1161 	if (tgt) {
   1162 		mutex_enter(&tgt->target_mutex);
   1163 		avl_remove(&tgt->target_sess_list, sess);
   1164 		mutex_exit(&tgt->target_mutex);
   1165 		sess->ist_tgt = (iscsit_tgt_t *)SESS_UNBOUND_FROM_TGT;
   1166 		idm_refcnt_rele(&tgt->target_sess_refcnt);
   1167 		iscsit_tgt_rele(tgt);
   1168 	} else {
   1169 		/* Discovery session */
   1170 		ISCSIT_GLOBAL_LOCK(RW_WRITER);
   1171 		avl_remove(&iscsit_global.global_discovery_sessions, sess);
   1172 		ISCSIT_GLOBAL_UNLOCK();
   1173 	}
   1174 }
   1175 
   1176 #define	LOCK_FOR_SESS_LOOKUP(lookup_tgt) { 			\
   1177 	if ((lookup_tgt) == NULL) {				\
   1178 		ISCSIT_GLOBAL_LOCK(RW_READER);			\
   1179 	} else {						\
   1180 		mutex_enter(&(lookup_tgt)->target_mutex);	\
   1181 	}							\
   1182 }
   1183 
   1184 #define	UNLOCK_FOR_SESS_LOOKUP(lookup_tgt) { 			\
   1185 	if ((lookup_tgt) == NULL) {				\
   1186 		ISCSIT_GLOBAL_UNLOCK();				\
   1187 	} else {					 	\
   1188 		mutex_exit(&(lookup_tgt)->target_mutex); 	\
   1189 	}							\
   1190 }
   1191 
   1192 iscsit_sess_t *
   1193 iscsit_tgt_lookup_sess(iscsit_tgt_t *tgt, char *initiator_name,
   1194     uint8_t *isid, uint16_t tsih, uint16_t tag)
   1195 {
   1196 	iscsit_sess_t	tmp_sess;
   1197 	avl_tree_t	*sess_avl;
   1198 	avl_index_t	where;
   1199 	iscsit_sess_t	*result;
   1200 
   1201 	/*
   1202 	 * If tgt is NULL then we are looking for a discovery session
   1203 	 */
   1204 	if (tgt == NULL) {
   1205 		sess_avl = &iscsit_global.global_discovery_sessions;
   1206 	} else {
   1207 		sess_avl = &tgt->target_sess_list;
   1208 	}
   1209 
   1210 	LOCK_FOR_SESS_LOOKUP(tgt);
   1211 	if (avl_numnodes(sess_avl) == NULL) {
   1212 		UNLOCK_FOR_SESS_LOOKUP(tgt);
   1213 		return (NULL);
   1214 	}
   1215 
   1216 	/*
   1217 	 * We'll try to find a session matching ISID + TSIH first.  If we
   1218 	 * can't find one then we will return the closest match.  If the
   1219 	 * caller needs an exact match it must compare the TSIH after
   1220 	 * the session is returned.
   1221 	 *
   1222 	 * The reason we do this "fuzzy matching" is to allow matching
   1223 	 * sessions with different TSIH values on the same AVL list.  This
   1224 	 * makes session reinstatement much easier since the new session can
   1225 	 * live on the list at the same time as the old session is cleaning up.
   1226 	 */
   1227 	bcopy(isid, tmp_sess.ist_isid, ISCSI_ISID_LEN);
   1228 	tmp_sess.ist_initiator_name = initiator_name;
   1229 	tmp_sess.ist_tsih = tsih;
   1230 	tmp_sess.ist_tpgt_tag = tag;
   1231 
   1232 	result = avl_find(sess_avl, &tmp_sess, &where);
   1233 	if (result != NULL) {
   1234 		iscsit_sess_hold(result);
   1235 		UNLOCK_FOR_SESS_LOOKUP(tgt);
   1236 		return (result);
   1237 	}
   1238 
   1239 	/*
   1240 	 * avl_find_nearest() may return a result with a different ISID so
   1241 	 * we should only return a result if the name and ISID match
   1242 	 */
   1243 	result = avl_nearest(sess_avl, where, AVL_BEFORE);
   1244 	if ((result != NULL) &&
   1245 	    (strcmp(result->ist_initiator_name, initiator_name) == 0) &&
   1246 	    (memcmp(result->ist_isid, isid, ISCSI_ISID_LEN) == 0) &&
   1247 	    (result->ist_tpgt_tag == tag)) {
   1248 		iscsit_sess_hold(result);
   1249 		UNLOCK_FOR_SESS_LOOKUP(tgt);
   1250 		return (result);
   1251 	}
   1252 
   1253 	result = avl_nearest(sess_avl, where, AVL_AFTER);
   1254 	if ((result != NULL) &&
   1255 	    (strcmp(result->ist_initiator_name, initiator_name) == 0) &&
   1256 	    (memcmp(result->ist_isid, isid, ISCSI_ISID_LEN) == 0) &&
   1257 	    (result->ist_tpgt_tag == tag)) {
   1258 		iscsit_sess_hold(result);
   1259 		UNLOCK_FOR_SESS_LOOKUP(tgt);
   1260 		return (result);
   1261 	}
   1262 
   1263 	UNLOCK_FOR_SESS_LOOKUP(tgt);
   1264 
   1265 	return (NULL);
   1266 }
   1267 
   1268 static idm_status_t
   1269 iscsit_tgt_merge_tpgt(iscsit_tgt_t *tgt, it_tgt_t *cfg_tgt,
   1270     list_t *tpgt_del_list)
   1271 {
   1272 	iscsit_tpgt_t	*tpgt, *next_tpgt;
   1273 	it_tpgt_t	*cfg_tpgt;
   1274 	idm_status_t	status = IDM_STATUS_SUCCESS;
   1275 
   1276 	/*
   1277 	 * 1. >> Lock <<
   1278 	 * 2. Removing all objects and place on a temp list
   1279 	 * 3. Add new objects
   1280 	 * 4. >> Unlock <<
   1281 	 * 5. tpgt_del_list contains deleted objects
   1282 	 */
   1283 	ASSERT(avl_is_empty(&tgt->target_tpgt_list) ||
   1284 	    (tpgt_del_list != NULL));
   1285 
   1286 	if (tpgt_del_list) {
   1287 		for (tpgt = avl_first(&tgt->target_tpgt_list);
   1288 		    tpgt != NULL; tpgt = next_tpgt) {
   1289 			next_tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt);
   1290 			avl_remove(&tgt->target_tpgt_list, tpgt);
   1291 			if (tgt->target_state == TS_STMF_ONLINE) {
   1292 				tpgt->tpgt_needs_tpg_offline = B_TRUE;
   1293 			}
   1294 			list_insert_tail(tpgt_del_list, tpgt);
   1295 		}
   1296 	}
   1297 
   1298 	if (cfg_tgt->tgt_tpgt_list != NULL) {
   1299 		/* Add currently defined TPGTs */
   1300 		for (cfg_tpgt = cfg_tgt->tgt_tpgt_list;
   1301 		    cfg_tpgt != NULL;
   1302 		    cfg_tpgt = cfg_tpgt->tpgt_next) {
   1303 			tpgt = iscsit_tpgt_create(cfg_tpgt);
   1304 			if (tpgt == NULL) {
   1305 				/*
   1306 				 * There is a problem in the configuration we
   1307 				 * received from the ioctl -- a missing tpg.
   1308 				 * All the unbind operations have already
   1309 				 * taken place.  To leave the system in a
   1310 				 * non-panic'd state, use the default tpgt.
   1311 				 */
   1312 				status = IDM_STATUS_FAIL;
   1313 				continue;
   1314 			}
   1315 			if (tgt->target_state == TS_STMF_ONLINE) {
   1316 				(void) iscsit_tpg_online(tpgt->tpgt_tpg);
   1317 			}
   1318 			avl_add(&tgt->target_tpgt_list, tpgt);
   1319 		}
   1320 	}
   1321 
   1322 	/* If no TPGTs defined, add the default TPGT */
   1323 	if (avl_numnodes(&tgt->target_tpgt_list) == 0) {
   1324 		tpgt = iscsit_tpgt_create_default();
   1325 		if (tgt->target_state == TS_STMF_ONLINE) {
   1326 			(void) iscsit_tpg_online(tpgt->tpgt_tpg);
   1327 		}
   1328 		avl_add(&tgt->target_tpgt_list, tpgt);
   1329 	}
   1330 
   1331 	return (status);
   1332 }
   1333 
   1334 static iscsit_tpgt_t *
   1335 iscsit_tpgt_create(it_tpgt_t *cfg_tpgt)
   1336 {
   1337 	iscsit_tpg_t	*tpg;
   1338 	iscsit_tpgt_t	*result;
   1339 
   1340 	/* This takes a reference on the TPG */
   1341 	tpg = iscsit_tpg_lookup_locked(cfg_tpgt->tpgt_tpg_name);
   1342 	if (tpg == NULL)
   1343 		return (NULL);
   1344 
   1345 	result = kmem_zalloc(sizeof (*result), KM_SLEEP);
   1346 
   1347 	result->tpgt_tpg = tpg;
   1348 	result->tpgt_tag = cfg_tpgt->tpgt_tag;
   1349 
   1350 	return (result);
   1351 }
   1352 
   1353 iscsit_tpgt_t *
   1354 iscsit_tpgt_create_default()
   1355 {
   1356 	iscsit_tpgt_t	*result;
   1357 
   1358 	result = kmem_zalloc(sizeof (*result), KM_SLEEP);
   1359 
   1360 	result->tpgt_tpg = iscsit_global.global_default_tpg;
   1361 	iscsit_tpg_hold(result->tpgt_tpg);
   1362 	result->tpgt_tag = ISCSIT_DEFAULT_TPGT;
   1363 
   1364 	return (result);
   1365 }
   1366 
   1367 void
   1368 iscsit_tpgt_destroy(iscsit_tpgt_t *tpgt)
   1369 {
   1370 	if (tpgt->tpgt_needs_tpg_offline) {
   1371 		iscsit_tpg_offline(tpgt->tpgt_tpg);
   1372 	}
   1373 	iscsit_tpg_rele(tpgt->tpgt_tpg);
   1374 	kmem_free(tpgt, sizeof (*tpgt));
   1375 }
   1376 
   1377 void
   1378 iscsit_tpgt_hold(iscsit_tpgt_t *tpgt)
   1379 {
   1380 	idm_refcnt_hold(&tpgt->tpgt_refcnt);
   1381 }
   1382 
   1383 void
   1384 iscsit_tpgt_rele(iscsit_tpgt_t *tpgt)
   1385 {
   1386 	idm_refcnt_rele(&tpgt->tpgt_refcnt);
   1387 }
   1388 
   1389 int
   1390 iscsit_tpgt_avl_compare(const void *void_tpgt1, const void *void_tpgt2)
   1391 {
   1392 	const iscsit_tpgt_t	*tpgt1 = void_tpgt1;
   1393 	const iscsit_tpgt_t	*tpgt2 = void_tpgt2;
   1394 
   1395 	if (tpgt1->tpgt_tag < tpgt2->tpgt_tag)
   1396 		return (-1);
   1397 	else if (tpgt1->tpgt_tag > tpgt2->tpgt_tag)
   1398 		return (1);
   1399 
   1400 	return (0);
   1401 }
   1402 
   1403 static idm_status_t
   1404 iscsit_tgt_online(iscsit_tgt_t *tgt)
   1405 {
   1406 	iscsit_tpgt_t 		*tpgt, *tpgt_fail;
   1407 	idm_status_t		rc;
   1408 
   1409 	mutex_enter(&tgt->target_mutex);
   1410 
   1411 	ASSERT(tgt->target_sess_list.avl_numnodes == 0);
   1412 	idm_refcnt_reset(&tgt->target_sess_refcnt);
   1413 	for (tpgt = avl_first(&tgt->target_tpgt_list);
   1414 	    tpgt != NULL;
   1415 	    tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt)) {
   1416 		rc = iscsit_tpg_online(tpgt->tpgt_tpg);
   1417 		if (rc != IDM_STATUS_SUCCESS) {
   1418 			tpgt_fail = tpgt;
   1419 			goto tgt_online_fail;
   1420 		}
   1421 	}
   1422 
   1423 	mutex_exit(&tgt->target_mutex);
   1424 
   1425 	return (IDM_STATUS_SUCCESS);
   1426 
   1427 tgt_online_fail:
   1428 	/* Offline all the tpgs we successfully onlined up to the failure */
   1429 	for (tpgt = avl_first(&tgt->target_tpgt_list);
   1430 	    tpgt != tpgt_fail;
   1431 	    tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt)) {
   1432 		iscsit_tpg_offline(tpgt->tpgt_tpg);
   1433 	}
   1434 	mutex_exit(&tgt->target_mutex);
   1435 	return (rc);
   1436 }
   1437 
   1438 static void
   1439 iscsit_tgt_offline_cb(void *tgt_void)
   1440 {
   1441 	iscsit_tgt_t *tgt = tgt_void;
   1442 	stmf_change_status_t	scs;
   1443 
   1444 	iscsit_tgt_sm_event(tgt, TE_OFFLINE_COMPLETE);
   1445 
   1446 	scs.st_completion_status = STMF_SUCCESS;
   1447 	scs.st_additional_info = NULL;
   1448 	(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
   1449 	    tgt->target_stmf_lport, &scs);
   1450 }
   1451 
   1452 static void
   1453 iscsit_tgt_offline(iscsit_tgt_t *tgt)
   1454 {
   1455 	iscsit_tpgt_t 		*tpgt;
   1456 	iscsit_sess_t		*ist;
   1457 
   1458 	mutex_enter(&tgt->target_mutex);
   1459 
   1460 	/* Offline target portal groups */
   1461 	for (tpgt = avl_first(&tgt->target_tpgt_list);
   1462 	    tpgt != NULL;
   1463 	    tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt)) {
   1464 		iscsit_tpg_offline(tpgt->tpgt_tpg);
   1465 	}
   1466 
   1467 	/* Close any active sessions */
   1468 	for (ist = avl_first(&tgt->target_sess_list);
   1469 	    ist != NULL;
   1470 	    ist = AVL_NEXT(&tgt->target_sess_list, ist)) {
   1471 		/*
   1472 		 * This is not a synchronous operation but after all
   1473 		 * sessions have been cleaned up there will be no
   1474 		 * more session-related holds on the target.
   1475 		 */
   1476 		iscsit_sess_close(ist);
   1477 	}
   1478 
   1479 	mutex_exit(&tgt->target_mutex);
   1480 
   1481 	/*
   1482 	 * Wait for all the sessions to quiesce.
   1483 	 */
   1484 	idm_refcnt_async_wait_ref(&tgt->target_sess_refcnt,
   1485 	    &iscsit_tgt_offline_cb);
   1486 }
   1487 
   1488 it_cfg_status_t
   1489 iscsit_config_merge_tpg(it_config_t *cfg, list_t *tpg_del_list)
   1490 {
   1491 	it_tpg_t	*cfg_tpg;
   1492 	iscsit_tpg_t	*tpg, *next_tpg;
   1493 
   1494 	/*
   1495 	 * 1. >> Lock <<
   1496 	 * 2. Removing deleted objects and place on a temp list
   1497 	 * 3. Add new objects
   1498 	 * 4. >> Unlock <<
   1499 	 * 5. tpg_del_list contains objects to destroy
   1500 	 */
   1501 	for (tpg = avl_first(&iscsit_global.global_tpg_list);
   1502 	    tpg != NULL;
   1503 	    tpg = next_tpg) {
   1504 		next_tpg = AVL_NEXT(&iscsit_global.global_tpg_list, tpg);
   1505 
   1506 		if (it_tpg_lookup(cfg, tpg->tpg_name) == NULL) {
   1507 			/*
   1508 			 * The policy around when to allow a target portal
   1509 			 * group to be deleted is implemented in libiscsit.
   1510 			 * By the time the request gets to the kernel module
   1511 			 * we expect that it conforms to policy so we will
   1512 			 * cleanup all references to TPG and destroy it if it
   1513 			 * is possible to do so.
   1514 			 *
   1515 			 */
   1516 			avl_remove(&iscsit_global.global_tpg_list, tpg);
   1517 			list_insert_tail(tpg_del_list, tpg);
   1518 		}
   1519 	}
   1520 
   1521 	/* Now walk through the list of configured target portal groups */
   1522 	for (cfg_tpg = cfg->config_tpg_list;
   1523 	    cfg_tpg != NULL;
   1524 	    cfg_tpg = cfg_tpg->tpg_next) {
   1525 		/* See if we have an existing target portal group */
   1526 		tpg = iscsit_tpg_lookup_locked(cfg_tpg->tpg_name);
   1527 
   1528 		if (tpg == NULL) {
   1529 			tpg = iscsit_tpg_create(cfg_tpg);
   1530 			ASSERT(tpg != NULL);
   1531 			avl_add(&iscsit_global.global_tpg_list, tpg);
   1532 		} else {
   1533 			mutex_enter(&tpg->tpg_mutex);
   1534 			iscsit_tpg_modify(tpg, cfg_tpg);
   1535 			mutex_exit(&tpg->tpg_mutex);
   1536 			iscsit_tpg_rele(tpg);
   1537 		}
   1538 	}
   1539 
   1540 	return (ITCFG_SUCCESS);
   1541 }
   1542 
   1543 
   1544 void
   1545 iscsit_config_destroy_tpgs(list_t *tpg_del_list)
   1546 {
   1547 	iscsit_tpg_t	*tpg, *next_tpg;
   1548 
   1549 	/* Now finish destroying the target portal groups */
   1550 	for (tpg = list_head(tpg_del_list);
   1551 	    tpg != NULL;
   1552 	    tpg = next_tpg) {
   1553 		next_tpg = list_next(tpg_del_list, tpg);
   1554 		list_remove(tpg_del_list, tpg);
   1555 		idm_refcnt_wait_ref(&tpg->tpg_refcnt);
   1556 
   1557 		/* Kill it */
   1558 		iscsit_tpg_destroy(tpg);
   1559 	}
   1560 }
   1561 
   1562 iscsit_tpg_t *
   1563 iscsit_tpg_lookup(char *tpg_name)
   1564 {
   1565 	iscsit_tpg_t *result;
   1566 
   1567 	ISCSIT_GLOBAL_LOCK(RW_READER);
   1568 	result = iscsit_tpg_lookup_locked(tpg_name);
   1569 	ISCSIT_GLOBAL_UNLOCK();
   1570 
   1571 	return (result);
   1572 }
   1573 
   1574 static iscsit_tpg_t *
   1575 iscsit_tpg_lookup_locked(char *tpg_name)
   1576 {
   1577 	iscsit_tpg_t	tmp_tpg;
   1578 	iscsit_tpg_t	*result;
   1579 
   1580 	(void) strlcpy(tmp_tpg.tpg_name, tpg_name, MAX_ISCSI_NODENAMELEN);
   1581 	if ((result = avl_find(&iscsit_global.global_tpg_list,
   1582 	    &tmp_tpg, NULL)) != NULL) {
   1583 		iscsit_tpg_hold(result);
   1584 	}
   1585 
   1586 	return (result);
   1587 }
   1588 
   1589 iscsit_tpg_t *
   1590 iscsit_tpg_create(it_tpg_t *cfg_tpg)
   1591 {
   1592 	iscsit_tpg_t *tpg;
   1593 
   1594 	tpg = kmem_zalloc(sizeof (*tpg), KM_SLEEP);
   1595 
   1596 	mutex_init(&tpg->tpg_mutex, NULL, MUTEX_DEFAULT, NULL);
   1597 	(void) strlcpy(tpg->tpg_name, cfg_tpg->tpg_name, MAX_TPG_NAMELEN);
   1598 	avl_create(&tpg->tpg_portal_list, iscsit_portal_avl_compare,
   1599 	    sizeof (iscsit_portal_t), offsetof(iscsit_portal_t, portal_tpg_ln));
   1600 	idm_refcnt_init(&tpg->tpg_refcnt, tpg);
   1601 
   1602 	mutex_enter(&tpg->tpg_mutex);
   1603 	iscsit_tpg_modify(tpg, cfg_tpg);
   1604 	mutex_exit(&tpg->tpg_mutex);
   1605 	iscsit_global_hold();
   1606 
   1607 	return (tpg);
   1608 }
   1609 
   1610 static void
   1611 iscsit_tpg_modify(iscsit_tpg_t *tpg, it_tpg_t *cfg_tpg)
   1612 {
   1613 	iscsit_portal_t		*portal, *next_portal;
   1614 	it_portal_t		*cfg_portal;
   1615 
   1616 	/* Update portals */
   1617 	for (portal = avl_first(&tpg->tpg_portal_list);
   1618 	    portal != NULL;
   1619 	    portal = next_portal) {
   1620 		next_portal = AVL_NEXT(&tpg->tpg_portal_list, portal);
   1621 		if (it_portal_lookup(cfg_tpg, &portal->portal_addr) == NULL) {
   1622 			avl_remove(&tpg->tpg_portal_list, portal);
   1623 			iscsit_portal_delete(portal);
   1624 		}
   1625 	}
   1626 
   1627 	for (cfg_portal = cfg_tpg->tpg_portal_list;
   1628 	    cfg_portal != NULL;
   1629 	    cfg_portal = cfg_portal->next) {
   1630 		if ((portal = iscsit_tpg_portal_lookup_locked(tpg,
   1631 		    &cfg_portal->portal_addr)) == NULL) {
   1632 			(void) iscsit_portal_create(tpg,
   1633 			    &cfg_portal->portal_addr);
   1634 		} else {
   1635 			iscsit_portal_rele(portal);
   1636 		}
   1637 	}
   1638 }
   1639 
   1640 void
   1641 iscsit_tpg_destroy(iscsit_tpg_t *tpg)
   1642 {
   1643 	iscsit_portal_t *portal, *next_portal;
   1644 
   1645 	for (portal = avl_first(&tpg->tpg_portal_list);
   1646 	    portal != NULL;
   1647 	    portal = next_portal) {
   1648 		next_portal = AVL_NEXT(&tpg->tpg_portal_list, portal);
   1649 		avl_remove(&tpg->tpg_portal_list, portal);
   1650 		iscsit_portal_delete(portal);
   1651 	}
   1652 
   1653 	idm_refcnt_wait_ref(&tpg->tpg_refcnt);
   1654 	idm_refcnt_destroy(&tpg->tpg_refcnt);
   1655 	avl_destroy(&tpg->tpg_portal_list);
   1656 	mutex_destroy(&tpg->tpg_mutex);
   1657 	kmem_free(tpg, sizeof (*tpg));
   1658 	iscsit_global_rele();
   1659 }
   1660 
   1661 void
   1662 iscsit_tpg_hold(iscsit_tpg_t *tpg)
   1663 {
   1664 	idm_refcnt_hold(&tpg->tpg_refcnt);
   1665 }
   1666 
   1667 void
   1668 iscsit_tpg_rele(iscsit_tpg_t *tpg)
   1669 {
   1670 	idm_refcnt_rele(&tpg->tpg_refcnt);
   1671 }
   1672 
   1673 iscsit_tpg_t *
   1674 iscsit_tpg_createdefault()
   1675 {
   1676 	iscsit_tpg_t *tpg;
   1677 
   1678 	tpg = kmem_zalloc(sizeof (*tpg), KM_SLEEP);
   1679 
   1680 	mutex_init(&tpg->tpg_mutex, NULL, MUTEX_DEFAULT, NULL);
   1681 	(void) strlcpy(tpg->tpg_name, ISCSIT_DEFAULT_TPG, MAX_TPG_NAMELEN);
   1682 	avl_create(&tpg->tpg_portal_list, iscsit_portal_avl_compare,
   1683 	    sizeof (iscsit_portal_t), offsetof(iscsit_portal_t, portal_tpg_ln));
   1684 	idm_refcnt_init(&tpg->tpg_refcnt, tpg);
   1685 
   1686 	/* Now create default portal */
   1687 	if (iscsit_portal_create(tpg, NULL) == NULL) {
   1688 		iscsit_tpg_destroy(tpg);
   1689 		return (NULL);
   1690 	}
   1691 
   1692 	return (tpg);
   1693 }
   1694 
   1695 void
   1696 iscsit_tpg_destroydefault(iscsit_tpg_t *tpg)
   1697 {
   1698 	iscsit_portal_t *portal;
   1699 
   1700 	portal = avl_first(&tpg->tpg_portal_list);
   1701 	ASSERT(portal != NULL);
   1702 	avl_remove(&tpg->tpg_portal_list, portal);
   1703 	iscsit_portal_delete(portal);
   1704 
   1705 	idm_refcnt_wait_ref(&tpg->tpg_refcnt);
   1706 	idm_refcnt_destroy(&tpg->tpg_refcnt);
   1707 	avl_destroy(&tpg->tpg_portal_list);
   1708 	mutex_destroy(&tpg->tpg_mutex);
   1709 	kmem_free(tpg, sizeof (*tpg));
   1710 }
   1711 
   1712 int
   1713 iscsit_tpg_avl_compare(const void *void_tpg1, const void *void_tpg2)
   1714 {
   1715 	const iscsit_tpg_t	*tpg1 = void_tpg1;
   1716 	const iscsit_tpg_t	*tpg2 = void_tpg2;
   1717 	int 			result;
   1718 
   1719 	/*
   1720 	 * Sort by ISID first then TSIH
   1721 	 */
   1722 	result = strcmp(tpg1->tpg_name, tpg2->tpg_name);
   1723 	if (result < 0) {
   1724 		return (-1);
   1725 	} else if (result > 0) {
   1726 		return (1);
   1727 	}
   1728 
   1729 	return (0);
   1730 }
   1731 
   1732 idm_status_t
   1733 iscsit_tpg_online(iscsit_tpg_t *tpg)
   1734 {
   1735 	iscsit_portal_t *portal, *portal_fail;
   1736 	idm_status_t	rc;
   1737 
   1738 	mutex_enter(&tpg->tpg_mutex);
   1739 	if (tpg->tpg_online == 0) {
   1740 		for (portal = avl_first(&tpg->tpg_portal_list);
   1741 		    portal != NULL;
   1742 		    portal = AVL_NEXT(&tpg->tpg_portal_list, portal)) {
   1743 			rc = iscsit_portal_online(portal);
   1744 			if (rc != IDM_STATUS_SUCCESS) {
   1745 				portal_fail = portal;
   1746 				goto tpg_online_fail;
   1747 			}
   1748 		}
   1749 	}
   1750 	tpg->tpg_online++;
   1751 
   1752 	mutex_exit(&tpg->tpg_mutex);
   1753 	return (IDM_STATUS_SUCCESS);
   1754 
   1755 tpg_online_fail:
   1756 	/* Offline all the portals we successfully onlined up to the failure */
   1757 	for (portal = avl_first(&tpg->tpg_portal_list);
   1758 	    portal != portal_fail;
   1759 	    portal = AVL_NEXT(&tpg->tpg_portal_list, portal)) {
   1760 		iscsit_portal_offline(portal);
   1761 	}
   1762 	mutex_exit(&tpg->tpg_mutex);
   1763 	return (rc);
   1764 }
   1765 
   1766 void
   1767 iscsit_tpg_offline(iscsit_tpg_t *tpg)
   1768 {
   1769 	iscsit_portal_t *portal;
   1770 
   1771 	mutex_enter(&tpg->tpg_mutex);
   1772 	tpg->tpg_online--;
   1773 	if (tpg->tpg_online == 0) {
   1774 		for (portal = avl_first(&tpg->tpg_portal_list);
   1775 		    portal != NULL;
   1776 		    portal = AVL_NEXT(&tpg->tpg_portal_list, portal)) {
   1777 			iscsit_portal_offline(portal);
   1778 		}
   1779 	}
   1780 	mutex_exit(&tpg->tpg_mutex);
   1781 }
   1782 
   1783 iscsit_portal_t *
   1784 iscsit_tpg_portal_lookup(iscsit_tpg_t *tpg, struct sockaddr_storage *sa)
   1785 {
   1786 	iscsit_portal_t	*result;
   1787 
   1788 	mutex_enter(&tpg->tpg_mutex);
   1789 	result = iscsit_tpg_portal_lookup_locked(tpg, sa);
   1790 	mutex_exit(&tpg->tpg_mutex);
   1791 
   1792 	return (result);
   1793 }
   1794 
   1795 static iscsit_portal_t *
   1796 iscsit_tpg_portal_lookup_locked(iscsit_tpg_t *tpg,
   1797     struct sockaddr_storage *sa)
   1798 {
   1799 	iscsit_portal_t	tmp_portal;
   1800 	iscsit_portal_t	*result;
   1801 
   1802 	/* Caller holds tpg->tpg_mutex */
   1803 	bcopy(sa, &tmp_portal.portal_addr, sizeof (*sa));
   1804 	if ((result = avl_find(&tpg->tpg_portal_list, &tmp_portal, NULL)) !=
   1805 	    NULL) {
   1806 		iscsit_portal_hold(result);
   1807 	}
   1808 
   1809 	return (result);
   1810 }
   1811 
   1812 iscsit_portal_t *
   1813 iscsit_portal_create(iscsit_tpg_t *tpg, struct sockaddr_storage *sa)
   1814 {
   1815 	iscsit_portal_t *portal;
   1816 
   1817 	portal = kmem_zalloc(sizeof (*portal), KM_SLEEP);
   1818 	/*
   1819 	 * If (sa == NULL) then we are being asked to create the default
   1820 	 * portal -- targets will use this portal when no portals are
   1821 	 * explicitly configured.
   1822 	 */
   1823 	if (sa == NULL) {
   1824 		portal->portal_default = B_TRUE;
   1825 	} else {
   1826 		portal->portal_default = B_FALSE;
   1827 		bcopy(sa, &portal->portal_addr, sizeof (*sa));
   1828 	}
   1829 
   1830 	idm_refcnt_init(&portal->portal_refcnt, portal);
   1831 
   1832 	/*
   1833 	 * Add this portal to the list
   1834 	 */
   1835 	avl_add(&tpg->tpg_portal_list, portal);
   1836 
   1837 	return (portal);
   1838 }
   1839 
   1840 void
   1841 iscsit_portal_delete(iscsit_portal_t *portal)
   1842 {
   1843 	if (portal->portal_online > 0) {
   1844 		iscsit_portal_offline(portal);
   1845 	}
   1846 
   1847 	if (portal->portal_online == 0) {
   1848 		ASSERT(portal->portal_svc == NULL);
   1849 		idm_refcnt_destroy(&portal->portal_refcnt);
   1850 		kmem_free(portal, sizeof (*portal));
   1851 	}
   1852 }
   1853 
   1854 void
   1855 iscsit_portal_hold(iscsit_portal_t *portal)
   1856 {
   1857 	idm_refcnt_hold(&portal->portal_refcnt);
   1858 }
   1859 
   1860 void
   1861 iscsit_portal_rele(iscsit_portal_t *portal)
   1862 {
   1863 	idm_refcnt_rele(&portal->portal_refcnt);
   1864 }
   1865 
   1866 int
   1867 iscsit_portal_avl_compare(const void *void_portal1, const void *void_portal2)
   1868 {
   1869 	const iscsit_portal_t			*portal1 = void_portal1;
   1870 	const iscsit_portal_t			*portal2 = void_portal2;
   1871 	const struct sockaddr_storage		*ss1, *ss2;
   1872 	const struct in_addr			*in1, *in2;
   1873 	const struct in6_addr			*in61, *in62;
   1874 	int i;
   1875 
   1876 	/*
   1877 	 * Compare ports, then address family, then ip address
   1878 	 */
   1879 	ss1 = &portal1->portal_addr;
   1880 	ss2 = &portal2->portal_addr;
   1881 	if (((struct sockaddr_in *)ss1)->sin_port !=
   1882 	    ((struct sockaddr_in *)ss2)->sin_port) {
   1883 		if (((struct sockaddr_in *)ss1)->sin_port >
   1884 		    ((struct sockaddr_in *)ss2)->sin_port)
   1885 			return (1);
   1886 		else
   1887 			return (-1);
   1888 	}
   1889 
   1890 	/*
   1891 	 * ports are the same
   1892 	 */
   1893 	if (ss1->ss_family != ss2->ss_family) {
   1894 		if (ss1->ss_family == AF_INET)
   1895 			return (1);
   1896 		else
   1897 			return (-1);
   1898 	}
   1899 	/*
   1900 	 * address families are the same
   1901 	 */
   1902 	if (ss1->ss_family == AF_INET) {
   1903 		in1 = &((struct sockaddr_in *)ss1)->sin_addr;
   1904 		in2 = &((struct sockaddr_in *)ss2)->sin_addr;
   1905 
   1906 		if (in1->s_addr > in2->s_addr)
   1907 			return (1);
   1908 		else if (in1->s_addr < in2->s_addr)
   1909 			return (-1);
   1910 		else
   1911 			return (0);
   1912 	} else if (ss1->ss_family == AF_INET6) {
   1913 		in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr;
   1914 		in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr;
   1915 
   1916 		for (i = 0; i < 4; i++) {
   1917 			if (in61->s6_addr32[i] > in62->s6_addr32[i])
   1918 				return (1);
   1919 			else if (in61->s6_addr32[i] < in62->s6_addr32[i])
   1920 				return (-1);
   1921 		}
   1922 		return (0);
   1923 	} else
   1924 		cmn_err(CE_WARN,
   1925 		    "iscsit_portal_avl_compare: unknown ss_family %d",
   1926 		    ss1->ss_family);
   1927 
   1928 	return (1);
   1929 }
   1930 
   1931 
   1932 idm_status_t
   1933 iscsit_portal_online(iscsit_portal_t *portal)
   1934 {
   1935 	idm_status_t rc = 0;
   1936 	idm_svc_t	*svc;
   1937 	idm_svc_req_t	sr;
   1938 	uint16_t	port;
   1939 	struct sockaddr_in *sin;
   1940 
   1941 	/* Caller holds parent TPG mutex */
   1942 	if (portal->portal_online == 0) {
   1943 		/*
   1944 		 * If there is no existing IDM service instance for this port,
   1945 		 * create one.  If the service exists, then the lookup,
   1946 		 * creates a reference on the existing service.
   1947 		 */
   1948 		sin = (struct sockaddr_in *)&portal->portal_addr;
   1949 		port = ntohs(sin->sin_port);
   1950 		if (port == 0)
   1951 			port = ISCSI_LISTEN_PORT;
   1952 		ASSERT(portal->portal_svc == NULL);
   1953 		if ((svc = idm_tgt_svc_lookup(port)) == NULL) {
   1954 			sr.sr_port = port;
   1955 			sr.sr_li = iscsit_global.global_li;
   1956 			sr.sr_conn_ops.icb_rx_scsi_cmd = &iscsit_op_scsi_cmd;
   1957 			sr.sr_conn_ops.icb_rx_scsi_rsp = NULL;
   1958 			sr.sr_conn_ops.icb_rx_misc = &iscsit_rx_pdu;
   1959 			sr.sr_conn_ops.icb_rx_error = &iscsit_rx_pdu_error;
   1960 			sr.sr_conn_ops.icb_task_aborted = &iscsit_task_aborted;
   1961 			sr.sr_conn_ops.icb_client_notify =
   1962 			    &iscsit_client_notify;
   1963 			sr.sr_conn_ops.icb_build_hdr = &iscsit_build_hdr;
   1964 			sr.sr_conn_ops.icb_update_statsn =
   1965 			    &iscsit_update_statsn;
   1966 			sr.sr_conn_ops.icb_keepalive = &iscsit_keepalive;
   1967 
   1968 			if (idm_tgt_svc_create(&sr, &svc) !=
   1969 			    IDM_STATUS_SUCCESS) {
   1970 				return (IDM_STATUS_FAIL);
   1971 			}
   1972 
   1973 			/* Get reference on the service we just created */
   1974 			idm_tgt_svc_hold(svc);
   1975 		}
   1976 		if ((rc = idm_tgt_svc_online(svc)) != IDM_STATUS_SUCCESS) {
   1977 			idm_tgt_svc_rele_and_destroy(svc);
   1978 			return (IDM_STATUS_FAIL);
   1979 		}
   1980 		portal->portal_svc = svc;
   1981 
   1982 		/*
   1983 		 * Only call iSNS for first online
   1984 		 */
   1985 		iscsit_isns_portal_online(portal);
   1986 	}
   1987 
   1988 	portal->portal_online++;
   1989 
   1990 	return (rc);
   1991 }
   1992 
   1993 void
   1994 iscsit_portal_offline(iscsit_portal_t *portal)
   1995 {
   1996 	portal->portal_online--;
   1997 
   1998 	if (portal->portal_online == 0) {
   1999 		/*
   2000 		 * Only call iSNS for last offline
   2001 		 */
   2002 		iscsit_isns_portal_offline(portal);
   2003 		idm_tgt_svc_offline(portal->portal_svc);
   2004 		/* If service is unreferenced, destroy it too */
   2005 		idm_tgt_svc_rele_and_destroy(portal->portal_svc);
   2006 		portal->portal_svc = NULL;
   2007 	}
   2008 
   2009 }
   2010 
   2011 it_cfg_status_t
   2012 iscsit_config_merge_ini(it_config_t *cfg)
   2013 {
   2014 	iscsit_ini_t	*ini, *next_ini;
   2015 	it_ini_t	*cfg_ini;
   2016 
   2017 	/*
   2018 	 * Initiator objects are so simple we will just destroy all the current
   2019 	 * objects and build new ones.  Nothing should ever reference an
   2020 	 * initator object.. instead just lookup the initiator object and
   2021 	 * grab the properties while holding the global config lock.
   2022 	 */
   2023 	for (ini = avl_first(&iscsit_global.global_ini_list);
   2024 	    ini != NULL;
   2025 	    ini = next_ini) {
   2026 		next_ini = AVL_NEXT(&iscsit_global.global_ini_list, ini);
   2027 		avl_remove(&iscsit_global.global_ini_list, ini);
   2028 		nvlist_free(ini->ini_props);
   2029 		kmem_free(ini, sizeof (*ini));
   2030 		iscsit_global_rele();
   2031 	}
   2032 
   2033 	for (cfg_ini = cfg->config_ini_list;
   2034 	    cfg_ini != NULL;
   2035 	    cfg_ini = cfg_ini->ini_next) {
   2036 		ini = kmem_zalloc(sizeof (iscsit_ini_t), KM_SLEEP);
   2037 		(void) strlcpy(ini->ini_name, cfg_ini->ini_name,
   2038 		    MAX_ISCSI_NODENAMELEN);
   2039 		(void) nvlist_dup(cfg_ini->ini_properties, &ini->ini_props,
   2040 		    KM_SLEEP);
   2041 		avl_add(&iscsit_global.global_ini_list, ini);
   2042 		iscsit_global_hold();
   2043 	}
   2044 
   2045 	return (ITCFG_SUCCESS);
   2046 }
   2047 
   2048 int
   2049 iscsit_ini_avl_compare(const void *void_ini1, const void *void_ini2)
   2050 {
   2051 	const iscsit_ini_t	*ini1 = void_ini1;
   2052 	const iscsit_ini_t	*ini2 = void_ini2;
   2053 	int 			result;
   2054 
   2055 	/*
   2056 	 * Sort by ISID first then TSIH
   2057 	 */
   2058 	result = strcmp(ini1->ini_name, ini2->ini_name);
   2059 	if (result < 0) {
   2060 		return (-1);
   2061 	} else if (result > 0) {
   2062 		return (1);
   2063 	}
   2064 
   2065 	return (0);
   2066 }
   2067 
   2068 iscsit_ini_t *
   2069 iscsit_ini_lookup_locked(char *ini_name)
   2070 {
   2071 	iscsit_ini_t	tmp_ini;
   2072 	iscsit_ini_t	*result;
   2073 
   2074 	/*
   2075 	 * Use a dummy target for lookup, filling in all fields used in AVL
   2076 	 * comparison.
   2077 	 */
   2078 	(void) strlcpy(tmp_ini.ini_name, ini_name, MAX_ISCSI_NODENAMELEN);
   2079 	result = avl_find(&iscsit_global.global_ini_list, &tmp_ini, NULL);
   2080 
   2081 	return (result);
   2082 }
   2083