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