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 2009 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 
35 #include <sys/socket.h>
36 #include <sys/strsubr.h>
37 #include <sys/door.h>
38 #include <sys/note.h>
39 #include <sys/sdt.h>
40 
41 #include <sys/stmf.h>
42 #include <sys/stmf_ioctl.h>
43 #include <sys/portif.h>
44 #define	PPPT_TGT_SM_STRINGS
45 #include <pppt.h>
46 
47 typedef struct {
48 	list_node_t		te_ctx_node;
49 	pppt_tgt_event_t	te_ctx_event;
50 } tgt_event_ctx_t;
51 
52 static void
53 pppt_tgt_sm_event(pppt_tgt_t *tgt, pppt_tgt_event_t event);
54 
55 static void
56 tgt_sm_event_locked(pppt_tgt_t *tgt, pppt_tgt_event_t event);
57 
58 static void
59 tgt_sm_event_dispatch(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
60 
61 static void
62 tgt_sm_created(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
63 
64 static void
65 tgt_sm_onlining(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
66 
67 static void
68 tgt_sm_online(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
69 
70 static void
71 tgt_sm_stmf_online(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
72 
73 static void
74 tgt_sm_deleting_need_offline(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
75 
76 static void
77 tgt_sm_offlining(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
78 
79 static void
80 tgt_sm_offline(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
81 
82 static void
83 tgt_sm_stmf_offline(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
84 
85 static void
86 tgt_sm_deleting_stmf_dereg(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
87 
88 static void
89 tgt_sm_deleting_stmf_dereg_fail(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
90 
91 static void
92 tgt_sm_deleting(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
93 
94 static void
95 pppt_tgt_dereg_retry(void *arg);
96 
97 static void
98 pppt_tgt_dereg_task(void *arg);
99 
100 static void
101 tgt_sm_new_state(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx,
102     pppt_tgt_state_t new_state);
103 
104 /*ARGSUSED*/
105 void
106 pppt_tgt_sm_ctl(stmf_local_port_t *lport, int cmd, void *arg)
107 {
108 	pppt_tgt_t		*pppt_tgt;
109 
110 	pppt_tgt = (pppt_tgt_t *)lport->lport_port_private;
111 
112 	switch (cmd) {
113 	case STMF_CMD_LPORT_ONLINE:
114 		pppt_tgt_sm_event(pppt_tgt, TE_STMF_ONLINE_REQ);
115 		break;
116 	case STMF_CMD_LPORT_OFFLINE:
117 		pppt_tgt_sm_event(pppt_tgt, TE_STMF_OFFLINE_REQ);
118 		break;
119 	case STMF_ACK_LPORT_ONLINE_COMPLETE:
120 		pppt_tgt_sm_event(pppt_tgt, TE_STMF_ONLINE_COMPLETE_ACK);
121 		break;
122 	case STMF_ACK_LPORT_OFFLINE_COMPLETE:
123 		pppt_tgt_sm_event(pppt_tgt, TE_STMF_OFFLINE_COMPLETE_ACK);
124 		break;
125 
126 	default:
127 		ASSERT(0);
128 		break;
129 	}
130 }
131 
132 pppt_tgt_t *
133 pppt_tgt_create(stmf_ic_reg_port_msg_t *reg_port, stmf_status_t *msg_errcode)
134 {
135 	pppt_tgt_t		*result;
136 	stmf_local_port_t	*lport;
137 	int			total_devid_len;
138 
139 	total_devid_len = sizeof (scsi_devid_desc_t) +
140 	    reg_port->icrp_port_id->ident_length - 1;
141 
142 	/*
143 	 * Each target is an STMF local port.  Allocate an STMF local port
144 	 * including enough space to store a scsi_devid_desc_t for this target.
145 	 */
146 	lport = stmf_alloc(STMF_STRUCT_STMF_LOCAL_PORT,
147 	    sizeof (pppt_tgt_t) + total_devid_len, 0);
148 	if (lport == NULL) {
149 		*msg_errcode = STMF_ALLOC_FAILURE;
150 		return (NULL);
151 	}
152 
153 	result = lport->lport_port_private;
154 	result->target_state = TS_CREATED;
155 	/* Use pointer arithmetic to find scsi_devid_desc_t */
156 	result->target_devid = (scsi_devid_desc_t *)(result + 1);
157 	bcopy(reg_port->icrp_port_id, result->target_devid, total_devid_len);
158 	result->target_devid->piv = 1;
159 	result->target_devid->code_set = CODE_SET_ASCII;
160 	result->target_devid->association = ID_IS_TARGET_PORT;
161 
162 	mutex_init(&result->target_mutex, NULL, MUTEX_DEFAULT, NULL);
163 	cv_init(&result->target_cv, NULL, CV_DEFAULT, NULL);
164 	list_create(&result->target_events, sizeof (tgt_event_ctx_t),
165 	    offsetof(tgt_event_ctx_t, te_ctx_node));
166 	avl_create(&result->target_sess_list, pppt_sess_avl_compare_by_name,
167 	    sizeof (pppt_sess_t), offsetof(pppt_sess_t, ps_target_ln));
168 
169 	lport->lport_abort_timeout = 120; /* seconds */
170 	lport->lport_id = result->target_devid;
171 	lport->lport_pp = pppt_global.global_pp;
172 	lport->lport_ds = pppt_global.global_dbuf_store;
173 	lport->lport_xfer_data = &pppt_lport_xfer_data;
174 	lport->lport_send_status = &pppt_lport_send_status;
175 	lport->lport_task_free = &pppt_lport_task_free;
176 	lport->lport_abort = &pppt_lport_abort;
177 	lport->lport_ctl = &pppt_lport_ctl;
178 	result->target_stmf_lport = lport;
179 
180 	/*
181 	 * Since this is a proxy port we need to do set the relative
182 	 * target port identifier before registering it with STMF.
183 	 */
184 	stmf_set_port_standby(lport, reg_port->icrp_relative_port_id);
185 
186 	/*
187 	 * Register the target with STMF.  STMF may immediately ask us to go
188 	 * online so insure any additional config setup is complete.
189 	 */
190 	if (stmf_register_local_port(lport) != STMF_SUCCESS) {
191 		*msg_errcode = STMF_FAILURE;
192 		pppt_tgt_destroy(result);
193 		return (NULL);
194 	}
195 
196 	return (result);
197 
198 }
199 
200 void
201 pppt_tgt_destroy(pppt_tgt_t *tgt)
202 {
203 	/* Destroy target */
204 	avl_destroy(&tgt->target_sess_list);
205 	list_destroy(&tgt->target_events);
206 	cv_destroy(&tgt->target_cv);
207 	mutex_destroy(&tgt->target_mutex);
208 	stmf_free(tgt->target_stmf_lport); /* Also frees "tgt' */
209 }
210 
211 pppt_tgt_t *
212 pppt_tgt_lookup(scsi_devid_desc_t *tgt_devid)
213 {
214 	pppt_tgt_t	*result;
215 	PPPT_GLOBAL_LOCK();
216 	result = pppt_tgt_lookup_locked(tgt_devid);
217 	PPPT_GLOBAL_UNLOCK();
218 
219 	return (result);
220 }
221 
222 pppt_tgt_t *
223 pppt_tgt_lookup_locked(scsi_devid_desc_t *tgt_devid)
224 {
225 	pppt_tgt_t	*result;
226 	pppt_tgt_t	tmptgt;
227 
228 	bzero(&tmptgt, sizeof (tmptgt));
229 	tmptgt.target_devid = tgt_devid;
230 
231 	result = avl_find(&pppt_global.global_target_list, &tmptgt, NULL);
232 
233 	return (result);
234 }
235 
236 void
237 pppt_tgt_async_delete(pppt_tgt_t *tgt)
238 {
239 	/* Generate TE_DELETE event to target state machine */
240 	pppt_tgt_sm_event(tgt, TE_DELETE);
241 }
242 
243 int
244 pppt_tgt_avl_compare(const void *void_tgt1, const void *void_tgt2)
245 {
246 	const	pppt_tgt_t	*ptgt1 = void_tgt1;
247 	const	pppt_tgt_t	*ptgt2 = void_tgt2;
248 	int			result;
249 
250 	/* Sort by code set then ident */
251 	if (ptgt1->target_devid->code_set <
252 	    ptgt2->target_devid->code_set) {
253 		return (-1);
254 	} else if (ptgt1->target_devid->code_set >
255 	    ptgt2->target_devid->code_set) {
256 		return (1);
257 	}
258 
259 	/* Next by ident length */
260 	if (ptgt1->target_devid->ident_length <
261 	    ptgt2->target_devid->ident_length) {
262 		return (-1);
263 	} else if (ptgt1->target_devid->ident_length >
264 	    ptgt2->target_devid->ident_length) {
265 		return (1);
266 	}
267 
268 	/* Code set and ident length both match, now compare idents */
269 	result = memcmp(ptgt1->target_devid->ident, ptgt2->target_devid->ident,
270 	    ptgt1->target_devid->ident_length);
271 
272 	if (result < 0) {
273 		return (-1);
274 	} else if (result > 0) {
275 		return (1);
276 	}
277 
278 	return (0);
279 }
280 
281 /*
282  * Target state machine
283  */
284 
285 static void
286 pppt_tgt_sm_event(pppt_tgt_t *tgt, pppt_tgt_event_t event)
287 {
288 	mutex_enter(&tgt->target_mutex);
289 	tgt_sm_event_locked(tgt, event);
290 	mutex_exit(&tgt->target_mutex);
291 }
292 
293 static void
294 tgt_sm_event_locked(pppt_tgt_t *tgt, pppt_tgt_event_t event)
295 {
296 	tgt_event_ctx_t *ctx;
297 
298 	tgt->target_refcount++;
299 
300 	ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
301 
302 	ctx->te_ctx_event = event;
303 
304 	list_insert_tail(&tgt->target_events, ctx);
305 
306 	/*
307 	 * Use the target_sm_busy flag to keep the state machine single
308 	 * threaded.  This also serves as recursion avoidance since this
309 	 * flag will always be set if we call pppt_tgt_sm_event from
310 	 * within the state machine code.
311 	 */
312 	if (!tgt->target_sm_busy) {
313 		tgt->target_sm_busy = B_TRUE;
314 		while (!list_is_empty(&tgt->target_events)) {
315 			ctx = list_head(&tgt->target_events);
316 			list_remove(&tgt->target_events, ctx);
317 			mutex_exit(&tgt->target_mutex);
318 			tgt_sm_event_dispatch(tgt, ctx);
319 			mutex_enter(&tgt->target_mutex);
320 		}
321 		tgt->target_sm_busy = B_FALSE;
322 
323 	}
324 
325 	tgt->target_refcount--;
326 	cv_signal(&tgt->target_cv);
327 }
328 
329 static void
330 tgt_sm_event_dispatch(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
331 {
332 	DTRACE_PROBE2(pppt__tgt__event, pppt_tgt_t *, tgt,
333 	    tgt_event_ctx_t *, ctx);
334 
335 	PPPT_LOG(CE_NOTE, "tgt_sm_event_dispatch: tgt %p event %s(%d)",
336 	    (void *)tgt, pppt_te_name[ctx->te_ctx_event], ctx->te_ctx_event);
337 
338 	/* State independent actions */
339 	switch (ctx->te_ctx_event) {
340 	case TE_DELETE:
341 		tgt->target_deleting = B_TRUE;
342 		break;
343 	}
344 
345 	/* State dependent actions */
346 	switch (tgt->target_state) {
347 	case TS_CREATED:
348 		tgt_sm_created(tgt, ctx);
349 		break;
350 	case TS_ONLINING:
351 		tgt_sm_onlining(tgt, ctx);
352 		break;
353 	case TS_ONLINE:
354 		tgt_sm_online(tgt, ctx);
355 		break;
356 	case TS_STMF_ONLINE:
357 		tgt_sm_stmf_online(tgt, ctx);
358 		break;
359 	case TS_DELETING_NEED_OFFLINE:
360 		tgt_sm_deleting_need_offline(tgt, ctx);
361 		break;
362 	case TS_OFFLINING:
363 		tgt_sm_offlining(tgt, ctx);
364 		break;
365 	case TS_OFFLINE:
366 		tgt_sm_offline(tgt, ctx);
367 		break;
368 	case TS_STMF_OFFLINE:
369 		tgt_sm_stmf_offline(tgt, ctx);
370 		break;
371 	case TS_DELETING_STMF_DEREG:
372 		tgt_sm_deleting_stmf_dereg(tgt, ctx);
373 		break;
374 	case TS_DELETING_STMF_DEREG_FAIL:
375 		tgt_sm_deleting_stmf_dereg_fail(tgt, ctx);
376 		break;
377 	case TS_DELETING:
378 		tgt_sm_deleting(tgt, ctx);
379 		break;
380 	default:
381 		ASSERT(0);
382 	}
383 
384 	kmem_free(ctx, sizeof (*ctx));
385 }
386 
387 static void
388 tgt_sm_created(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
389 {
390 	stmf_change_status_t	scs;
391 
392 	switch (ctx->te_ctx_event) {
393 	case TE_STMF_ONLINE_REQ:
394 		tgt_sm_new_state(tgt, ctx, TS_ONLINING);
395 		break;
396 	case TE_DELETE:
397 		tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG);
398 		break;
399 	case TE_STMF_OFFLINE_REQ:
400 		/*
401 		 * We're already offline but update to an equivelant
402 		 * state just to note that STMF talked to us.
403 		 */
404 		scs.st_completion_status = STMF_SUCCESS;
405 		scs.st_additional_info = NULL;
406 		tgt_sm_new_state(tgt, ctx, TS_OFFLINE);
407 		(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
408 		    tgt->target_stmf_lport, &scs);
409 		break;
410 	case TE_STMF_ONLINE_COMPLETE_ACK:
411 	case TE_STMF_OFFLINE_COMPLETE_ACK:
412 		/* Ignore */
413 		break;
414 	default:
415 		ASSERT(0);
416 	}
417 }
418 
419 static void
420 tgt_sm_onlining(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
421 {
422 	stmf_change_status_t	scs;
423 
424 	switch (ctx->te_ctx_event) {
425 	case TE_ONLINE_SUCCESS:
426 		tgt_sm_new_state(tgt, ctx, TS_ONLINE);
427 		break;
428 	case TE_ONLINE_FAIL:
429 		tgt_sm_new_state(tgt, ctx, TS_STMF_OFFLINE);
430 		break;
431 	case TE_DELETE:
432 		/* TE_DELETE is handled in tgt_sm_event_dispatch() */
433 		break;
434 	case TE_STMF_ONLINE_REQ:
435 	case TE_STMF_OFFLINE_REQ:
436 		/*
437 		 * We can't complete STMF's request since we are busy going
438 		 * online.
439 		 */
440 		scs.st_completion_status = STMF_INVALID_ARG;
441 		scs.st_additional_info = NULL;
442 		(void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
443 		    STMF_CMD_LPORT_ONLINE_COMPLETE :
444 		    STMF_CMD_LPORT_OFFLINE_COMPLETE,
445 		    tgt->target_stmf_lport, &scs);
446 		break;
447 	case TE_STMF_ONLINE_COMPLETE_ACK:
448 	case TE_STMF_OFFLINE_COMPLETE_ACK:
449 		/* Ignore */
450 		break;
451 	default:
452 		ASSERT(0);
453 	}
454 }
455 
456 static void
457 tgt_sm_online(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
458 {
459 	stmf_change_status_t	scs;
460 
461 	switch (ctx->te_ctx_event) {
462 	case TE_STMF_ONLINE_COMPLETE_ACK:
463 		if (tgt->target_deleting) {
464 			tgt_sm_new_state(tgt, ctx, TS_DELETING_NEED_OFFLINE);
465 		} else {
466 			tgt_sm_new_state(tgt, ctx, TS_STMF_ONLINE);
467 		}
468 		break;
469 	case TE_DELETE:
470 		/* TE_DELETE is handled in tgt_sm_event_dispatch() */
471 		break;
472 	case TE_STMF_ONLINE_REQ:
473 	case TE_STMF_OFFLINE_REQ:
474 		/*
475 		 * We can't complete STMF's request since we are busy going
476 		 * online (waiting for acknowlegement from STMF)
477 		 */
478 		scs.st_completion_status = STMF_INVALID_ARG;
479 		scs.st_additional_info = NULL;
480 		(void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
481 		    STMF_CMD_LPORT_ONLINE_COMPLETE :
482 		    STMF_CMD_LPORT_OFFLINE_COMPLETE,
483 		    tgt->target_stmf_lport, &scs);
484 		break;
485 	case TE_STMF_OFFLINE_COMPLETE_ACK:
486 		/* Ignore */
487 		break;
488 	default:
489 		ASSERT(0);
490 	}
491 }
492 
493 
494 static void
495 tgt_sm_stmf_online(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
496 {
497 	stmf_change_status_t	scs;
498 
499 	switch (ctx->te_ctx_event) {
500 	case TE_DELETE:
501 		tgt_sm_new_state(tgt, ctx, TS_DELETING_NEED_OFFLINE);
502 		break;
503 	case TE_STMF_OFFLINE_REQ:
504 		tgt_sm_new_state(tgt, ctx, TS_OFFLINING);
505 		break;
506 	case TE_STMF_ONLINE_REQ:
507 		/* Already online */
508 		scs.st_completion_status = STMF_ALREADY;
509 		scs.st_additional_info = NULL;
510 		(void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE,
511 		    tgt->target_stmf_lport, &scs);
512 		break;
513 	case TE_STMF_ONLINE_COMPLETE_ACK:
514 	case TE_STMF_OFFLINE_COMPLETE_ACK:
515 		/* Ignore */
516 		break;
517 	default:
518 		ASSERT(0);
519 	}
520 }
521 
522 
523 static void
524 tgt_sm_deleting_need_offline(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
525 {
526 	stmf_change_status_t	scs;
527 
528 	switch (ctx->te_ctx_event) {
529 	case TE_STMF_OFFLINE_REQ:
530 		tgt_sm_new_state(tgt, ctx, TS_OFFLINING);
531 		break;
532 	case TE_DELETE:
533 		/* TE_DELETE is handled in tgt_sm_event_dispatch() */
534 		break;
535 	case TE_STMF_ONLINE_REQ:
536 		/*
537 		 * We can't complete STMF's request since we need to be offlined
538 		 */
539 		scs.st_completion_status = STMF_INVALID_ARG;
540 		scs.st_additional_info = NULL;
541 		(void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE,
542 		    tgt->target_stmf_lport, &scs);
543 		break;
544 	case TE_STMF_ONLINE_COMPLETE_ACK:
545 	case TE_STMF_OFFLINE_COMPLETE_ACK:
546 		/* Ignore */
547 		break;
548 	default:
549 		ASSERT(0);
550 	}
551 }
552 
553 
554 static void
555 tgt_sm_offlining(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
556 {
557 	stmf_change_status_t	scs;
558 
559 	switch (ctx->te_ctx_event) {
560 	case TE_OFFLINE_COMPLETE:
561 		tgt_sm_new_state(tgt, ctx, TS_OFFLINE);
562 		break;
563 	case TE_DELETE:
564 		/* TE_DELETE is handled in tgt_sm_event_dispatch() */
565 		break;
566 	case TE_STMF_ONLINE_REQ:
567 	case TE_STMF_OFFLINE_REQ:
568 		/*
569 		 * We can't complete STMF's request since we are busy going
570 		 * offline.
571 		 */
572 		scs.st_completion_status = STMF_INVALID_ARG;
573 		scs.st_additional_info = NULL;
574 		(void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
575 		    STMF_CMD_LPORT_ONLINE_COMPLETE :
576 		    STMF_CMD_LPORT_OFFLINE_COMPLETE,
577 		    tgt->target_stmf_lport, &scs);
578 		break;
579 	case TE_STMF_ONLINE_COMPLETE_ACK:
580 	case TE_STMF_OFFLINE_COMPLETE_ACK:
581 		/* Ignore */
582 		break;
583 	default:
584 		ASSERT(0);
585 	}
586 }
587 
588 
589 static void
590 tgt_sm_offline(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
591 {
592 	stmf_change_status_t	scs;
593 
594 	switch (ctx->te_ctx_event) {
595 	case TE_STMF_OFFLINE_COMPLETE_ACK:
596 		if (tgt->target_deleting) {
597 			tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG);
598 		} else {
599 			tgt_sm_new_state(tgt, ctx, TS_STMF_OFFLINE);
600 		}
601 		break;
602 	case TE_DELETE:
603 		/* TE_DELETE is handled in tgt_sm_event_dispatch() */
604 		break;
605 	case TE_STMF_ONLINE_REQ:
606 	case TE_STMF_OFFLINE_REQ:
607 		/*
608 		 * We can't complete STMF's request since we are busy going
609 		 * offline.
610 		 */
611 		scs.st_completion_status = STMF_INVALID_ARG;
612 		scs.st_additional_info = NULL;
613 		(void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
614 		    STMF_CMD_LPORT_ONLINE_COMPLETE :
615 		    STMF_CMD_LPORT_OFFLINE_COMPLETE,
616 		    tgt->target_stmf_lport, &scs);
617 		break;
618 	case TE_STMF_ONLINE_COMPLETE_ACK:
619 		/* Ignore */
620 		break;
621 	default:
622 		ASSERT(0);
623 	}
624 }
625 
626 
627 static void
628 tgt_sm_stmf_offline(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
629 {
630 	stmf_change_status_t	scs;
631 
632 	switch (ctx->te_ctx_event) {
633 	case TE_STMF_ONLINE_REQ:
634 		tgt_sm_new_state(tgt, ctx, TS_ONLINING);
635 		break;
636 	case TE_DELETE:
637 		tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG);
638 		break;
639 	case TE_STMF_OFFLINE_REQ:
640 		/* Already offline */
641 		scs.st_completion_status = STMF_ALREADY;
642 		scs.st_additional_info = NULL;
643 		(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
644 		    tgt->target_stmf_lport, &scs);
645 		break;
646 	case TE_STMF_ONLINE_COMPLETE_ACK:
647 	case TE_STMF_OFFLINE_COMPLETE_ACK:
648 		/* Ignore */
649 		break;
650 	default:
651 		ASSERT(0);
652 	}
653 }
654 
655 
656 static void
657 tgt_sm_deleting_stmf_dereg(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
658 {
659 	stmf_change_status_t	scs;
660 
661 	/* Terminal state, no events */
662 	switch (ctx->te_ctx_event) {
663 	case TE_STMF_ONLINE_REQ:
664 	case TE_STMF_OFFLINE_REQ:
665 		/*
666 		 * We can't complete STMF's request since we are being deleted
667 		 */
668 		scs.st_completion_status = STMF_INVALID_ARG;
669 		scs.st_additional_info = NULL;
670 		(void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
671 		    STMF_CMD_LPORT_ONLINE_COMPLETE :
672 		    STMF_CMD_LPORT_OFFLINE_COMPLETE,
673 		    tgt->target_stmf_lport, &scs);
674 		break;
675 	case TE_STMF_ONLINE_COMPLETE_ACK:
676 	case TE_STMF_OFFLINE_COMPLETE_ACK:
677 		/* Ignore */
678 		break;
679 	case TE_STMF_DEREG_SUCCESS:
680 		tgt_sm_new_state(tgt, ctx, TS_DELETING);
681 		break;
682 	case TE_STMF_DEREG_FAIL:
683 		tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG_FAIL);
684 		break;
685 	default:
686 		ASSERT(0);
687 	}
688 }
689 
690 static void
691 tgt_sm_deleting_stmf_dereg_fail(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
692 {
693 	stmf_change_status_t	scs;
694 
695 	/* Terminal state, no events */
696 	switch (ctx->te_ctx_event) {
697 	case TE_STMF_ONLINE_REQ:
698 	case TE_STMF_OFFLINE_REQ:
699 		/*
700 		 * We can't complete STMF's request since we are being deleted
701 		 */
702 		scs.st_completion_status = STMF_INVALID_ARG;
703 		scs.st_additional_info = NULL;
704 		(void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
705 		    STMF_CMD_LPORT_ONLINE_COMPLETE :
706 		    STMF_CMD_LPORT_OFFLINE_COMPLETE,
707 		    tgt->target_stmf_lport, &scs);
708 		break;
709 	case TE_STMF_ONLINE_COMPLETE_ACK:
710 	case TE_STMF_OFFLINE_COMPLETE_ACK:
711 		/* Ignore */
712 		break;
713 	case TE_STMF_DEREG_RETRY:
714 		tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG);
715 		break;
716 	default:
717 		ASSERT(0);
718 	}
719 }
720 
721 static void
722 tgt_sm_deleting(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
723 {
724 	stmf_change_status_t	scs;
725 
726 	/* Terminal state, no events */
727 	switch (ctx->te_ctx_event) {
728 	case TE_STMF_ONLINE_REQ:
729 	case TE_STMF_OFFLINE_REQ:
730 		/*
731 		 * We can't complete STMF's request since we are being deleted
732 		 */
733 		scs.st_completion_status = STMF_INVALID_ARG;
734 		scs.st_additional_info = NULL;
735 		(void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
736 		    STMF_CMD_LPORT_ONLINE_COMPLETE :
737 		    STMF_CMD_LPORT_OFFLINE_COMPLETE,
738 		    tgt->target_stmf_lport, &scs);
739 		break;
740 	case TE_STMF_ONLINE_COMPLETE_ACK:
741 	case TE_STMF_OFFLINE_COMPLETE_ACK:
742 		/* Ignore */
743 		break;
744 	default:
745 		ASSERT(0);
746 	}
747 }
748 
749 static void
750 pppt_tgt_offline(void *arg)
751 {
752 	pppt_tgt_t		*tgt = arg;
753 	pppt_sess_t		*ps, *next_ps;
754 	stmf_change_status_t	scs;
755 
756 	PPPT_LOG(CE_NOTE, "pppt_tgt_offline %p", (void *)tgt);
757 
758 	PPPT_GLOBAL_LOCK();
759 	mutex_enter(&tgt->target_mutex);
760 	for (ps = avl_first(&tgt->target_sess_list); ps != NULL; ps = next_ps) {
761 		next_ps = AVL_NEXT(&tgt->target_sess_list, ps);
762 		mutex_enter(&ps->ps_mutex);
763 		PPPT_LOG(CE_NOTE, "pppt_tgt_offline closing session %p(%d)",
764 		    (void *)ps, ps->ps_closed);
765 		if (!ps->ps_closed) {
766 			pppt_sess_close_locked(ps);
767 		}
768 		mutex_exit(&ps->ps_mutex);
769 	}
770 	mutex_exit(&tgt->target_mutex);
771 	PPPT_GLOBAL_UNLOCK();
772 
773 	pppt_tgt_sm_event(tgt, TE_OFFLINE_COMPLETE);
774 
775 	scs.st_completion_status = STMF_SUCCESS;
776 	scs.st_additional_info = NULL;
777 	(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
778 	    tgt->target_stmf_lport, &scs);
779 
780 	PPPT_LOG(CE_NOTE, "pppt_tgt_offline complete %p", (void *)tgt);
781 }
782 
783 static void
784 pppt_tgt_dereg_retry(void *arg)
785 {
786 	pppt_tgt_t *tgt = arg;
787 
788 	/*
789 	 * Rather than guaranteeing the target state machine code will not
790 	 * block for long periods of time (tying up this callout thread)
791 	 * we will queue a task on the taskq to send the retry event.
792 	 * If it fails we'll setup another timeout and try again later.
793 	 */
794 	if (taskq_dispatch(pppt_global.global_dispatch_taskq,
795 	    pppt_tgt_dereg_task, tgt, KM_NOSLEEP) == NULL) {
796 		/* Dispatch failed, try again later */
797 		(void) timeout(pppt_tgt_dereg_retry, tgt,
798 		    drv_usectohz(TGT_DEREG_RETRY_SECONDS * 1000000));
799 	}
800 }
801 
802 static void
803 pppt_tgt_dereg_task(void *arg)
804 {
805 	pppt_tgt_t *tgt = arg;
806 
807 	pppt_tgt_sm_event(tgt, TE_STMF_DEREG_RETRY);
808 }
809 
810 /*ARGSUSED*/
811 static void
812 tgt_sm_new_state(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx,
813     pppt_tgt_state_t new_state)
814 {
815 	stmf_local_port_t		*lport = tgt->target_stmf_lport;
816 	stmf_change_status_t		scs;
817 	stmf_state_change_info_t	sci;
818 	stmf_status_t			stmfrc;
819 
820 	scs.st_completion_status = STMF_SUCCESS;
821 	scs.st_additional_info = NULL;
822 
823 	/*
824 	 * Validate new state
825 	 */
826 	ASSERT(new_state != TS_UNDEFINED);
827 	ASSERT3U(new_state, <, TS_MAX_STATE);
828 
829 	new_state = (new_state < TS_MAX_STATE) ?
830 	    new_state : TS_UNDEFINED;
831 
832 	PPPT_LOG(CE_NOTE, "tgt_sm_new_state: tgt %p, %s(%d) --> %s(%d)\n",
833 	    (void *) tgt, pppt_ts_name[tgt->target_state], tgt->target_state,
834 	    pppt_ts_name[new_state], new_state);
835 	DTRACE_PROBE3(pppt__target__state__change,
836 	    pppt_tgt_t *, tgt, tgt_event_ctx_t *, ctx,
837 	    pppt_tgt_state_t, new_state);
838 
839 	mutex_enter(&tgt->target_mutex);
840 	tgt->target_last_state = tgt->target_state;
841 	tgt->target_state = new_state;
842 	cv_signal(&tgt->target_cv);
843 	mutex_exit(&tgt->target_mutex);
844 
845 	switch (tgt->target_state) {
846 	case TS_ONLINING:
847 		pppt_tgt_sm_event(tgt, TE_ONLINE_SUCCESS);
848 
849 		/*
850 		 * Let STMF know the how the online operation completed.
851 		 * STMF will respond with an acknowlege later
852 		 */
853 		(void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, lport, &scs);
854 		break;
855 	case TS_ONLINE:
856 		break;
857 	case TS_STMF_ONLINE:
858 		break;
859 	case TS_DELETING_NEED_OFFLINE:
860 		sci.st_rflags = STMF_RFLAG_STAY_OFFLINED;
861 		sci.st_additional_info = "Offline for delete";
862 		(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE, lport, &sci);
863 		break;
864 	case TS_OFFLINING:
865 		/* Async callback generates completion event */
866 		pppt_tgt_offline(tgt);
867 		break;
868 	case TS_OFFLINE:
869 		break;
870 	case TS_STMF_OFFLINE:
871 		break;
872 	case TS_DELETING_STMF_DEREG:
873 		stmfrc = stmf_deregister_local_port(tgt->target_stmf_lport);
874 		if (stmfrc == STMF_SUCCESS) {
875 			pppt_tgt_sm_event(tgt, TE_STMF_DEREG_SUCCESS);
876 		} else {
877 			pppt_tgt_sm_event(tgt, TE_STMF_DEREG_FAIL);
878 		}
879 		break;
880 	case TS_DELETING_STMF_DEREG_FAIL:
881 		/* Retry dereg in 1 second */
882 		(void) timeout(pppt_tgt_dereg_retry, tgt,
883 		    drv_usectohz(TGT_DEREG_RETRY_SECONDS * 1000000));
884 		break;
885 	case TS_DELETING:
886 		break;
887 	default:
888 		ASSERT(0);
889 	}
890 }
891