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