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