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