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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/cpuvar.h>
28 #include <sys/ddi.h>
29 #include <sys/sunddi.h>
30 #include <sys/modctl.h>
31 #include <sys/socket.h>
32 #include <sys/strsubr.h>
33 #include <sys/note.h>
34 #include <sys/sdt.h>
35 
36 #define	IDM_CONN_SM_STRINGS
37 #define	IDM_CN_NOTIFY_STRINGS
38 #include <sys/idm/idm.h>
39 
40 boolean_t	idm_sm_logging = B_FALSE;
41 
42 extern idm_global_t	idm; /* Global state */
43 
44 static void
45 idm_conn_event_handler(void *event_ctx_opaque);
46 
47 static void
48 idm_state_s1_free(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
49 
50 static void
51 idm_state_s2_xpt_wait(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
52 
53 static void
54 idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
55 
56 static void
57 idm_state_s4_in_login(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
58 
59 static void
60 idm_state_s5_logged_in(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
61 
62 static void
63 idm_state_s6_in_logout(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
64 
65 static void
66 idm_logout_req_timeout(void *arg);
67 
68 static void
69 idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
70 
71 static void
72 idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
73 
74 static void
75 idm_state_s9_init_error(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
76 
77 static void
78 idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
79 
80 static void
81 idm_state_s11_complete(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
82 
83 static void
84 idm_state_s12_enable_dm(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
85 
86 static void
87 idm_update_state(idm_conn_t *ic, idm_conn_state_t new_state,
88     idm_conn_event_ctx_t *event_ctx);
89 
90 static void
91 idm_conn_unref(void *ic_void);
92 
93 static idm_pdu_event_action_t
94 idm_conn_sm_validate_pdu(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx,
95     idm_pdu_t *pdu);
96 
97 static idm_status_t
98 idm_ffp_enable(idm_conn_t *ic);
99 
100 static void
101 idm_ffp_disable(idm_conn_t *ic, idm_ffp_disable_t disable_type);
102 
103 static void
104 idm_initial_login_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
105 
106 static void
107 idm_login_success_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
108 
109 idm_status_t
110 idm_conn_sm_init(idm_conn_t *ic)
111 {
112 	char taskq_name[32];
113 
114 	/*
115 	 * Caller should have assigned a unique connection ID.  Use this
116 	 * connection ID to create a unique connection name string
117 	 */
118 	ASSERT(ic->ic_internal_cid != 0);
119 	(void) snprintf(taskq_name, sizeof (taskq_name) - 1, "conn_sm%08x",
120 	    ic->ic_internal_cid);
121 
122 	ic->ic_state_taskq = taskq_create(taskq_name, 1, minclsyspri, 4, 16384,
123 	    TASKQ_PREPOPULATE);
124 	if (ic->ic_state_taskq == NULL) {
125 		return (IDM_STATUS_FAIL);
126 	}
127 
128 	idm_sm_audit_init(&ic->ic_state_audit);
129 	mutex_init(&ic->ic_state_mutex, NULL, MUTEX_DEFAULT, NULL);
130 	cv_init(&ic->ic_state_cv, NULL, CV_DEFAULT, NULL);
131 
132 	ic->ic_state = CS_S1_FREE;
133 	ic->ic_last_state = CS_S1_FREE;
134 
135 	return (IDM_STATUS_SUCCESS);
136 }
137 
138 void
139 idm_conn_sm_fini(idm_conn_t *ic)
140 {
141 
142 	/*
143 	 * The connection may only be partially created. If there
144 	 * is no taskq, then the connection SM was not initialized.
145 	 */
146 	if (ic->ic_state_taskq == NULL) {
147 		return;
148 	}
149 
150 	taskq_destroy(ic->ic_state_taskq);
151 
152 	cv_destroy(&ic->ic_state_cv);
153 	/*
154 	 * The thread that generated the event that got us here may still
155 	 * hold the ic_state_mutex. Once it is released we can safely
156 	 * destroy it since there is no way to locate the object now.
157 	 */
158 	mutex_enter(&ic->ic_state_mutex);
159 	mutex_destroy(&ic->ic_state_mutex);
160 }
161 
162 void
163 idm_conn_event(idm_conn_t *ic, idm_conn_event_t event, uintptr_t event_info)
164 {
165 	mutex_enter(&ic->ic_state_mutex);
166 	idm_conn_event_locked(ic, event, event_info, CT_NONE);
167 	mutex_exit(&ic->ic_state_mutex);
168 }
169 
170 
171 idm_status_t
172 idm_conn_reinstate_event(idm_conn_t *old_ic, idm_conn_t *new_ic)
173 {
174 	int result;
175 
176 	mutex_enter(&old_ic->ic_state_mutex);
177 	if (((old_ic->ic_conn_type == CONN_TYPE_INI) &&
178 	    (old_ic->ic_state != CS_S8_CLEANUP)) ||
179 	    ((old_ic->ic_conn_type == CONN_TYPE_TGT) &&
180 	    (old_ic->ic_state < CS_S5_LOGGED_IN))) {
181 		result = IDM_STATUS_FAIL;
182 	} else {
183 		result = IDM_STATUS_SUCCESS;
184 		new_ic->ic_reinstate_conn = old_ic;
185 		idm_conn_event_locked(new_ic->ic_reinstate_conn,
186 		    CE_CONN_REINSTATE, (uintptr_t)new_ic, CT_NONE);
187 	}
188 	mutex_exit(&old_ic->ic_state_mutex);
189 
190 	return (result);
191 }
192 
193 void
194 idm_conn_tx_pdu_event(idm_conn_t *ic, idm_conn_event_t event,
195     uintptr_t event_info)
196 {
197 	ASSERT(mutex_owned(&ic->ic_state_mutex));
198 	ic->ic_pdu_events++;
199 	idm_conn_event_locked(ic, event, event_info, CT_TX_PDU);
200 }
201 
202 void
203 idm_conn_rx_pdu_event(idm_conn_t *ic, idm_conn_event_t event,
204     uintptr_t event_info)
205 {
206 	ASSERT(mutex_owned(&ic->ic_state_mutex));
207 	ic->ic_pdu_events++;
208 	idm_conn_event_locked(ic, event, event_info, CT_RX_PDU);
209 }
210 
211 void
212 idm_conn_event_locked(idm_conn_t *ic, idm_conn_event_t event,
213     uintptr_t event_info, idm_pdu_event_type_t pdu_event_type)
214 {
215 	idm_conn_event_ctx_t	*event_ctx;
216 
217 	idm_sm_audit_event(&ic->ic_state_audit, SAS_IDM_CONN,
218 	    (int)ic->ic_state, (int)event, event_info);
219 
220 	/*
221 	 * It's very difficult to prevent a few straggling events
222 	 * at the end.  For example idm_sorx_thread will generate
223 	 * a CE_TRANSPORT_FAIL event when it exits.  Rather than
224 	 * push complicated restrictions all over the code to
225 	 * prevent this we will simply drop the events (and in
226 	 * the case of PDU events release them appropriately)
227 	 * since they are irrelevant once we are in a terminal state.
228 	 * Of course those threads need to have appropriate holds on
229 	 * the connection otherwise it might disappear.
230 	 */
231 	if ((ic->ic_state == CS_S9_INIT_ERROR) ||
232 	    (ic->ic_state == CS_S11_COMPLETE)) {
233 		if ((pdu_event_type == CT_TX_PDU) ||
234 		    (pdu_event_type == CT_RX_PDU)) {
235 			ic->ic_pdu_events--;
236 			idm_pdu_complete((idm_pdu_t *)event_info,
237 			    IDM_STATUS_SUCCESS);
238 		}
239 		IDM_SM_LOG(CE_NOTE, "*** Dropping event %s (%d) because of"
240 		    "state %s (%d)",
241 		    idm_ce_name[event], event,
242 		    idm_cs_name[ic->ic_state], ic->ic_state);
243 		return;
244 	}
245 
246 	/*
247 	 * Normal event handling
248 	 */
249 	idm_conn_hold(ic);
250 
251 	event_ctx = kmem_zalloc(sizeof (*event_ctx), KM_SLEEP);
252 	event_ctx->iec_ic = ic;
253 	event_ctx->iec_event = event;
254 	event_ctx->iec_info = event_info;
255 	event_ctx->iec_pdu_event_type = pdu_event_type;
256 
257 	(void) taskq_dispatch(ic->ic_state_taskq, &idm_conn_event_handler,
258 	    event_ctx, TQ_SLEEP);
259 }
260 
261 static void
262 idm_conn_event_handler(void *event_ctx_opaque)
263 {
264 	idm_conn_event_ctx_t *event_ctx = event_ctx_opaque;
265 	idm_conn_t *ic = event_ctx->iec_ic;
266 	idm_pdu_t *pdu = (idm_pdu_t *)event_ctx->iec_info;
267 	idm_pdu_event_action_t action;
268 
269 	IDM_SM_LOG(CE_NOTE, "idm_conn_event_handler: conn %p event %s(%d)",
270 	    (void *)ic, idm_ce_name[event_ctx->iec_event],
271 	    event_ctx->iec_event);
272 	DTRACE_PROBE2(conn__event,
273 	    idm_conn_t *, ic, idm_conn_event_ctx_t *, event_ctx);
274 
275 	/*
276 	 * Validate event
277 	 */
278 	ASSERT(event_ctx->iec_event != CE_UNDEFINED);
279 	ASSERT3U(event_ctx->iec_event, <, CE_MAX_EVENT);
280 
281 	/*
282 	 * Validate current state
283 	 */
284 	ASSERT(ic->ic_state != CS_S0_UNDEFINED);
285 	ASSERT3U(ic->ic_state, <, CS_MAX_STATE);
286 
287 	/*
288 	 * Validate PDU-related events against the current state.  If a PDU
289 	 * is not allowed in the current state we change the event to a
290 	 * protocol error.  This simplifies the state-specific event handlers.
291 	 * For example the CS_S2_XPT_WAIT state only needs to handle the
292 	 * CE_TX_PROTOCOL_ERROR and CE_RX_PROTOCOL_ERROR events since
293 	 * no PDU's can be transmitted or received in that state.
294 	 */
295 	event_ctx->iec_pdu_forwarded = B_FALSE;
296 	if (event_ctx->iec_pdu_event_type != CT_NONE) {
297 		ASSERT(pdu != NULL);
298 		action = idm_conn_sm_validate_pdu(ic, event_ctx, pdu);
299 
300 		switch (action) {
301 		case CA_TX_PROTOCOL_ERROR:
302 			/*
303 			 * Change event and forward the PDU
304 			 */
305 			event_ctx->iec_event = CE_TX_PROTOCOL_ERROR;
306 			break;
307 		case CA_RX_PROTOCOL_ERROR:
308 			/*
309 			 * Change event and forward the PDU.
310 			 */
311 			event_ctx->iec_event = CE_RX_PROTOCOL_ERROR;
312 			break;
313 		case CA_FORWARD:
314 			/*
315 			 * Let the state-specific event handlers take
316 			 * care of it.
317 			 */
318 			break;
319 		case CA_DROP:
320 			/*
321 			 * It never even happened
322 			 */
323 			IDM_SM_LOG(CE_NOTE, "*** drop PDU %p", (void *) pdu);
324 			idm_pdu_complete(pdu, IDM_STATUS_FAIL);
325 			break;
326 		default:
327 			ASSERT(0);
328 			break;
329 		}
330 	}
331 
332 	switch (ic->ic_state) {
333 	case CS_S1_FREE:
334 		idm_state_s1_free(ic, event_ctx);
335 		break;
336 	case CS_S2_XPT_WAIT:
337 		idm_state_s2_xpt_wait(ic, event_ctx);
338 		break;
339 	case CS_S3_XPT_UP:
340 		idm_state_s3_xpt_up(ic, event_ctx);
341 		break;
342 	case CS_S4_IN_LOGIN:
343 		idm_state_s4_in_login(ic, event_ctx);
344 		break;
345 	case CS_S5_LOGGED_IN:
346 		idm_state_s5_logged_in(ic, event_ctx);
347 		break;
348 	case CS_S6_IN_LOGOUT:
349 		idm_state_s6_in_logout(ic, event_ctx);
350 		break;
351 	case CS_S7_LOGOUT_REQ:
352 		idm_state_s7_logout_req(ic, event_ctx);
353 		break;
354 	case CS_S8_CLEANUP:
355 		idm_state_s8_cleanup(ic, event_ctx);
356 		break;
357 	case CS_S9_INIT_ERROR:
358 		idm_state_s9_init_error(ic, event_ctx);
359 		break;
360 	case CS_S10_IN_CLEANUP:
361 		idm_state_s10_in_cleanup(ic, event_ctx);
362 		break;
363 	case CS_S11_COMPLETE:
364 		idm_state_s11_complete(ic, event_ctx);
365 		break;
366 	case CS_S12_ENABLE_DM:
367 		idm_state_s12_enable_dm(ic, event_ctx);
368 		break;
369 	default:
370 		ASSERT(0);
371 		break;
372 	}
373 
374 	/*
375 	 * Now that we've updated the state machine, if this was
376 	 * a PDU-related event take the appropriate action on the PDU
377 	 * (transmit it, forward it to the clients RX callback, drop
378 	 * it, etc).
379 	 */
380 	if (event_ctx->iec_pdu_event_type != CT_NONE) {
381 		switch (action) {
382 		case CA_TX_PROTOCOL_ERROR:
383 			idm_pdu_tx_protocol_error(ic, pdu);
384 			break;
385 		case CA_RX_PROTOCOL_ERROR:
386 			idm_pdu_rx_protocol_error(ic, pdu);
387 			break;
388 		case CA_FORWARD:
389 			if (!event_ctx->iec_pdu_forwarded) {
390 				if (event_ctx->iec_pdu_event_type ==
391 				    CT_RX_PDU) {
392 					idm_pdu_rx_forward(ic, pdu);
393 				} else {
394 					idm_pdu_tx_forward(ic, pdu);
395 				}
396 			}
397 			break;
398 		default:
399 			ASSERT(0);
400 			break;
401 		}
402 	}
403 
404 	/*
405 	 * Update outstanding PDU event count (see idm_pdu_tx for
406 	 * how this is used)
407 	 */
408 	if ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ||
409 	    (event_ctx->iec_pdu_event_type == CT_RX_PDU)) {
410 		mutex_enter(&ic->ic_state_mutex);
411 		ic->ic_pdu_events--;
412 		mutex_exit(&ic->ic_state_mutex);
413 	}
414 
415 	idm_conn_rele(ic);
416 	kmem_free(event_ctx, sizeof (*event_ctx));
417 }
418 
419 static void
420 idm_state_s1_free(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
421 {
422 	switch (event_ctx->iec_event) {
423 	case CE_CONNECT_REQ:
424 		/* T1 */
425 		idm_update_state(ic, CS_S2_XPT_WAIT, event_ctx);
426 		break;
427 	case CE_CONNECT_ACCEPT:
428 		/* T3 */
429 		idm_update_state(ic, CS_S3_XPT_UP, event_ctx);
430 		break;
431 	case CE_TX_PROTOCOL_ERROR:
432 	case CE_RX_PROTOCOL_ERROR:
433 		/* This should never happen */
434 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
435 		break;
436 	default:
437 		ASSERT(0);
438 		/*NOTREACHED*/
439 	}
440 }
441 
442 
443 static void
444 idm_state_s2_xpt_wait(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
445 {
446 	switch (event_ctx->iec_event) {
447 	case CE_CONNECT_SUCCESS:
448 		/* T4 */
449 		idm_update_state(ic, CS_S4_IN_LOGIN, event_ctx);
450 		break;
451 	case CE_CONNECT_FAIL:
452 	case CE_LOGOUT_OTHER_CONN_RCV:
453 	case CE_TX_PROTOCOL_ERROR:
454 	case CE_RX_PROTOCOL_ERROR:
455 		/* T2 */
456 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
457 		break;
458 	default:
459 		ASSERT(0);
460 		/*NOTREACHED*/
461 	}
462 }
463 
464 
465 static void
466 idm_login_timeout(void *arg)
467 {
468 	idm_conn_t *ic = arg;
469 
470 	idm_conn_event(ic, CE_LOGIN_TIMEOUT, NULL);
471 }
472 
473 static void
474 idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
475 {
476 	switch (event_ctx->iec_event) {
477 	case CE_LOGIN_RCV:
478 		/* T4 */
479 		idm_initial_login_actions(ic, event_ctx);
480 		idm_update_state(ic, CS_S4_IN_LOGIN, event_ctx);
481 		break;
482 	case CE_LOGIN_TIMEOUT:
483 		/*
484 		 * Don't need to cancel login timer since the timer is
485 		 * presumed to be the source of this event.
486 		 */
487 		(void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
488 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
489 		break;
490 	case CE_CONNECT_REJECT:
491 	case CE_CONNECT_FAIL:
492 	case CE_TRANSPORT_FAIL:
493 	case CE_LOGOUT_OTHER_CONN_SND:
494 		/* T6 */
495 		(void) untimeout(ic->ic_state_timeout);
496 		(void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
497 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
498 		break;
499 	case CE_TX_PROTOCOL_ERROR:
500 	case CE_RX_PROTOCOL_ERROR:
501 		/* Don't care */
502 		break;
503 	default:
504 		ASSERT(0);
505 		/*NOTREACHED*/
506 	}
507 }
508 
509 static void
510 idm_state_s4_in_login_fail_snd_done(idm_pdu_t *pdu, idm_status_t status)
511 {
512 	idm_conn_t		*ic = pdu->isp_ic;
513 
514 	/*
515 	 * This pdu callback can be invoked by the tx thread,
516 	 * so run the disconnect code from another thread.
517 	 */
518 	pdu->isp_status = status;
519 	idm_conn_event(ic, CE_LOGIN_FAIL_SND_DONE, (uintptr_t)pdu);
520 }
521 
522 static void
523 idm_state_s4_in_login(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
524 {
525 	idm_pdu_t *pdu;
526 
527 	/*
528 	 * Login timer should no longer be active after leaving this
529 	 * state.
530 	 */
531 	switch (event_ctx->iec_event) {
532 	case CE_LOGIN_SUCCESS_RCV:
533 	case CE_LOGIN_SUCCESS_SND:
534 		(void) untimeout(ic->ic_state_timeout);
535 		idm_login_success_actions(ic, event_ctx);
536 		if (ic->ic_rdma_extensions) {
537 			/* T19 */
538 			idm_update_state(ic, CS_S12_ENABLE_DM, event_ctx);
539 		} else {
540 			/* T5 */
541 			idm_update_state(ic, CS_S5_LOGGED_IN, event_ctx);
542 		}
543 		break;
544 	case CE_LOGIN_TIMEOUT:
545 		/* T7 */
546 		(void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
547 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
548 		break;
549 	case CE_LOGIN_FAIL_SND_DONE:
550 		(void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
551 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
552 		break;
553 	case CE_LOGIN_FAIL_SND:
554 		/*
555 		 * Allow the logout response pdu to be sent and defer
556 		 * the state machine update until the completion callback.
557 		 * Only 1 level or callback interposition is allowed.
558 		 */
559 		(void) untimeout(ic->ic_state_timeout);
560 		pdu = (idm_pdu_t *)event_ctx->iec_info;
561 		ASSERT(ic->ic_client_callback == NULL);
562 		ic->ic_client_callback = pdu->isp_callback;
563 		pdu->isp_callback =
564 		    idm_state_s4_in_login_fail_snd_done;
565 		break;
566 	case CE_LOGIN_FAIL_RCV:
567 		/*
568 		 * Need to deliver this PDU to the initiator now because after
569 		 * we update the state to CS_S9_INIT_ERROR the initiator will
570 		 * no longer be in an appropriate state.
571 		 */
572 		event_ctx->iec_pdu_forwarded = B_TRUE;
573 		pdu = (idm_pdu_t *)event_ctx->iec_info;
574 		idm_pdu_rx_forward(ic, pdu);
575 		/* FALLTHROUGH */
576 	case CE_TRANSPORT_FAIL:
577 	case CE_LOGOUT_OTHER_CONN_SND:
578 	case CE_LOGOUT_OTHER_CONN_RCV:
579 		/* T7 */
580 		(void) untimeout(ic->ic_state_timeout);
581 		(void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
582 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
583 		break;
584 	case CE_LOGIN_SND:
585 		/*
586 		 * Initiator connections will see initial login PDU
587 		 * in this state.  Target connections see initial
588 		 * login PDU in "xpt up" state.
589 		 */
590 		mutex_enter(&ic->ic_state_mutex);
591 		if (!(ic->ic_state_flags & CF_INITIAL_LOGIN)) {
592 			idm_initial_login_actions(ic, event_ctx);
593 		}
594 		mutex_exit(&ic->ic_state_mutex);
595 		break;
596 	case CE_MISC_TX:
597 	case CE_MISC_RX:
598 	case CE_LOGIN_RCV:
599 	case CE_TX_PROTOCOL_ERROR:
600 	case CE_RX_PROTOCOL_ERROR:
601 		/* Don't care */
602 		break;
603 	default:
604 		ASSERT(0);
605 		/*NOTREACHED*/
606 	}
607 }
608 
609 
610 static void
611 idm_state_s5_logged_in(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
612 {
613 	switch (event_ctx->iec_event) {
614 	case CE_LOGOUT_THIS_CONN_RCV:
615 	case CE_LOGOUT_THIS_CONN_SND:
616 	case CE_LOGOUT_OTHER_CONN_RCV:
617 	case CE_LOGOUT_OTHER_CONN_SND:
618 		/* T9 */
619 		idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */
620 		idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
621 		break;
622 	case CE_LOGOUT_SESSION_RCV:
623 	case CE_LOGOUT_SESSION_SND:
624 		/* T9 */
625 		idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
626 		idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
627 		break;
628 	case CE_LOGOUT_SESSION_SUCCESS:
629 		/* T8 */
630 		idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
631 
632 		/* Close connection */
633 		if (IDM_CONN_ISTGT(ic)) {
634 			ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
635 		} else {
636 			ic->ic_transport_ops->it_ini_conn_disconnect(ic);
637 		}
638 
639 		idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
640 		break;
641 	case CE_ASYNC_LOGOUT_RCV:
642 	case CE_ASYNC_LOGOUT_SND:
643 		/* T11 */
644 		idm_update_state(ic, CS_S7_LOGOUT_REQ, event_ctx);
645 		break;
646 	case CE_TRANSPORT_FAIL:
647 	case CE_ASYNC_DROP_CONN_RCV:
648 	case CE_ASYNC_DROP_CONN_SND:
649 	case CE_ASYNC_DROP_ALL_CONN_RCV:
650 	case CE_ASYNC_DROP_ALL_CONN_SND:
651 		/* T15 */
652 		idm_ffp_disable(ic, FD_CONN_FAIL); /* Implicit logout */
653 		idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
654 		break;
655 	case CE_MISC_TX:
656 	case CE_MISC_RX:
657 	case CE_TX_PROTOCOL_ERROR:
658 	case CE_RX_PROTOCOL_ERROR:
659 		/* Don't care */
660 		break;
661 	default:
662 		ASSERT(0);
663 	}
664 }
665 
666 static void
667 idm_state_s6_in_logout_success_snd_done(idm_pdu_t *pdu, idm_status_t status)
668 {
669 	idm_conn_t		*ic = pdu->isp_ic;
670 
671 	/*
672 	 * This pdu callback can be invoked by the tx thread,
673 	 * so run the disconnect code from another thread.
674 	 */
675 	pdu->isp_status = status;
676 	idm_conn_event(ic, CE_LOGOUT_SUCCESS_SND_DONE, (uintptr_t)pdu);
677 }
678 
679 static void
680 idm_state_s6_in_logout_fail_snd_done(idm_pdu_t *pdu, idm_status_t status)
681 {
682 	idm_conn_t		*ic = pdu->isp_ic;
683 
684 	/*
685 	 * This pdu callback can be invoked by the tx thread,
686 	 * so run the disconnect code from another thread.
687 	 */
688 	pdu->isp_status = status;
689 	idm_conn_event(ic, CE_LOGOUT_FAIL_SND_DONE, (uintptr_t)pdu);
690 }
691 
692 static void
693 idm_state_s6_in_logout(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
694 {
695 	idm_pdu_t *pdu;
696 
697 	switch (event_ctx->iec_event) {
698 	case CE_LOGOUT_SUCCESS_SND_DONE:
699 		pdu = (idm_pdu_t *)event_ctx->iec_info;
700 
701 		/* Close connection (if it's not already closed) */
702 		ASSERT(IDM_CONN_ISTGT(ic));
703 		ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
704 
705 		/* restore client callback */
706 		pdu->isp_callback =  ic->ic_client_callback;
707 		ic->ic_client_callback = NULL;
708 		idm_pdu_complete(pdu, pdu->isp_status);
709 		idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
710 		break;
711 	case CE_LOGOUT_FAIL_SND_DONE:
712 		pdu = (idm_pdu_t *)event_ctx->iec_info;
713 		/* restore client callback */
714 		pdu->isp_callback =  ic->ic_client_callback;
715 		ic->ic_client_callback = NULL;
716 		idm_pdu_complete(pdu, pdu->isp_status);
717 		idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
718 		break;
719 	case CE_LOGOUT_SUCCESS_SND:
720 	case CE_LOGOUT_FAIL_SND:
721 		/*
722 		 * Allow the logout response pdu to be sent and defer
723 		 * the state machine update until the completion callback.
724 		 * Only 1 level or callback interposition is allowed.
725 		 */
726 		pdu = (idm_pdu_t *)event_ctx->iec_info;
727 		ASSERT(ic->ic_client_callback == NULL);
728 		ic->ic_client_callback = pdu->isp_callback;
729 		if (event_ctx->iec_event == CE_LOGOUT_SUCCESS_SND) {
730 			pdu->isp_callback =
731 			    idm_state_s6_in_logout_success_snd_done;
732 		} else {
733 			pdu->isp_callback =
734 			    idm_state_s6_in_logout_fail_snd_done;
735 		}
736 		break;
737 	case CE_LOGOUT_SUCCESS_RCV:
738 		/*
739 		 * Need to deliver this PDU to the initiator now because after
740 		 * we update the state to CS_S11_COMPLETE the initiator will
741 		 * no longer be in an appropriate state.
742 		 */
743 		event_ctx->iec_pdu_forwarded = B_TRUE;
744 		pdu = (idm_pdu_t *)event_ctx->iec_info;
745 		idm_pdu_rx_forward(ic, pdu);
746 		/* FALLTHROUGH */
747 	case CE_LOGOUT_SESSION_SUCCESS:
748 		/* T13 */
749 
750 		/* Close connection (if it's not already closed) */
751 		if (IDM_CONN_ISTGT(ic)) {
752 			ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
753 		} else {
754 			ic->ic_transport_ops->it_ini_conn_disconnect(ic);
755 		}
756 
757 		idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
758 		break;
759 	case CE_ASYNC_LOGOUT_RCV:
760 		/* T14 Do nothing */
761 		break;
762 	case CE_TRANSPORT_FAIL:
763 	case CE_ASYNC_DROP_CONN_RCV:
764 	case CE_ASYNC_DROP_CONN_SND:
765 	case CE_ASYNC_DROP_ALL_CONN_RCV:
766 	case CE_ASYNC_DROP_ALL_CONN_SND:
767 	case CE_LOGOUT_FAIL_RCV:
768 		idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
769 		break;
770 	case CE_TX_PROTOCOL_ERROR:
771 	case CE_RX_PROTOCOL_ERROR:
772 	case CE_MISC_TX:
773 	case CE_MISC_RX:
774 		/* Don't care */
775 		break;
776 	default:
777 		ASSERT(0);
778 	}
779 }
780 
781 
782 static void
783 idm_logout_req_timeout(void *arg)
784 {
785 	idm_conn_t *ic = arg;
786 
787 	idm_conn_event(ic, CE_LOGOUT_TIMEOUT, NULL);
788 }
789 
790 static void
791 idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
792 {
793 	/* Must cancel logout timer before leaving this state */
794 	switch (event_ctx->iec_event) {
795 	case CE_LOGOUT_THIS_CONN_RCV:
796 	case CE_LOGOUT_THIS_CONN_SND:
797 	case CE_LOGOUT_OTHER_CONN_RCV:
798 	case CE_LOGOUT_OTHER_CONN_SND:
799 		/* T10 */
800 		if (IDM_CONN_ISTGT(ic)) {
801 			(void) untimeout(ic->ic_state_timeout);
802 		}
803 		idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */
804 		idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
805 		break;
806 	case CE_LOGOUT_SESSION_RCV:
807 	case CE_LOGOUT_SESSION_SND:
808 		/* T10 */
809 		if (IDM_CONN_ISTGT(ic)) {
810 			(void) untimeout(ic->ic_state_timeout);
811 		}
812 		idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
813 		idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
814 		break;
815 	case CE_ASYNC_LOGOUT_RCV:
816 	case CE_ASYNC_LOGOUT_SND:
817 		/* T12 Do nothing */
818 		break;
819 	case CE_TRANSPORT_FAIL:
820 	case CE_ASYNC_DROP_CONN_RCV:
821 	case CE_ASYNC_DROP_CONN_SND:
822 	case CE_ASYNC_DROP_ALL_CONN_RCV:
823 	case CE_ASYNC_DROP_ALL_CONN_SND:
824 		/* T16 */
825 		if (IDM_CONN_ISTGT(ic)) {
826 			(void) untimeout(ic->ic_state_timeout);
827 		}
828 		/* FALLTHROUGH */
829 	case CE_LOGOUT_TIMEOUT:
830 		idm_ffp_disable(ic, FD_CONN_FAIL); /* Implicit logout */
831 		idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
832 		break;
833 	case CE_LOGOUT_SESSION_SUCCESS:
834 		/* T18 */
835 		if (IDM_CONN_ISTGT(ic)) {
836 			(void) untimeout(ic->ic_state_timeout);
837 		}
838 		idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
839 
840 		/* Close connection (if it's not already closed) */
841 		if (IDM_CONN_ISTGT(ic)) {
842 			ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
843 		} else {
844 			ic->ic_transport_ops->it_ini_conn_disconnect(ic);
845 		}
846 
847 		idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
848 		break;
849 	case CE_TX_PROTOCOL_ERROR:
850 	case CE_RX_PROTOCOL_ERROR:
851 	case CE_MISC_TX:
852 	case CE_MISC_RX:
853 		/* Don't care */
854 		break;
855 	default:
856 		ASSERT(0);
857 	}
858 }
859 
860 
861 static void
862 idm_cleanup_timeout(void *arg)
863 {
864 	idm_conn_t *ic = arg;
865 
866 	idm_conn_event(ic, CE_CLEANUP_TIMEOUT, NULL);
867 }
868 
869 static void
870 idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
871 {
872 	idm_pdu_t *pdu;
873 
874 	/*
875 	 * Need to cancel the cleanup timeout before leaving this state
876 	 * if it hasn't already fired.
877 	 */
878 	switch (event_ctx->iec_event) {
879 	case CE_LOGOUT_SUCCESS_RCV:
880 	case CE_LOGOUT_SUCCESS_SND:
881 	case CE_LOGOUT_SESSION_SUCCESS:
882 		(void) untimeout(ic->ic_state_timeout);
883 		/*FALLTHROUGH*/
884 	case CE_CLEANUP_TIMEOUT:
885 		/* M1 */
886 		idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
887 		break;
888 	case CE_LOGOUT_OTHER_CONN_RCV:
889 	case CE_LOGOUT_OTHER_CONN_SND:
890 		/* M2 */
891 		idm_update_state(ic, CS_S10_IN_CLEANUP, event_ctx);
892 		break;
893 	case CE_LOGOUT_SUCCESS_SND_DONE:
894 	case CE_LOGOUT_FAIL_SND_DONE:
895 		pdu = (idm_pdu_t *)event_ctx->iec_info;
896 		/* restore client callback */
897 		pdu->isp_callback =  ic->ic_client_callback;
898 		ic->ic_client_callback = NULL;
899 		idm_pdu_complete(pdu, pdu->isp_status);
900 		break;
901 	case CE_LOGOUT_SESSION_RCV:
902 	case CE_LOGOUT_SESSION_SND:
903 	case CE_TX_PROTOCOL_ERROR:
904 	case CE_RX_PROTOCOL_ERROR:
905 	case CE_MISC_TX:
906 	case CE_MISC_RX:
907 	case CE_TRANSPORT_FAIL:
908 	case CE_LOGOUT_TIMEOUT:
909 		/* Don't care */
910 		break;
911 	default:
912 		ASSERT(0);
913 	}
914 }
915 
916 /* ARGSUSED */
917 static void
918 idm_state_s9_init_error(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
919 {
920 	if (ic->ic_conn_type == CONN_TYPE_INI) {
921 		mutex_enter(&ic->ic_state_mutex);
922 		ic->ic_state_flags |= CF_ERROR;
923 		ic->ic_conn_sm_status = IDM_STATUS_FAIL;
924 		cv_signal(&ic->ic_state_cv);
925 		mutex_exit(&ic->ic_state_mutex);
926 	}
927 }
928 
929 static void
930 idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
931 {
932 	idm_pdu_t *pdu;
933 
934 	/*
935 	 * Need to cancel the cleanup timeout before leaving this state
936 	 * if it hasn't already fired.
937 	 */
938 	switch (event_ctx->iec_event) {
939 	case CE_LOGOUT_FAIL_RCV:
940 	case CE_LOGOUT_FAIL_SND:
941 		idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
942 		break;
943 	case CE_LOGOUT_SUCCESS_SND:
944 	case CE_LOGOUT_SUCCESS_RCV:
945 	case CE_LOGOUT_SESSION_SUCCESS:
946 		(void) untimeout(ic->ic_state_timeout);
947 		/*FALLTHROUGH*/
948 	case CE_CLEANUP_TIMEOUT:
949 		idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
950 		break;
951 	case CE_LOGOUT_SUCCESS_SND_DONE:
952 	case CE_LOGOUT_FAIL_SND_DONE:
953 		pdu = (idm_pdu_t *)event_ctx->iec_info;
954 		/* restore client callback */
955 		pdu->isp_callback =  ic->ic_client_callback;
956 		ic->ic_client_callback = NULL;
957 		idm_pdu_complete(pdu, pdu->isp_status);
958 		break;
959 	case CE_TX_PROTOCOL_ERROR:
960 	case CE_RX_PROTOCOL_ERROR:
961 	case CE_MISC_TX:
962 	case CE_MISC_RX:
963 	case CE_LOGOUT_TIMEOUT:
964 		/* Don't care */
965 		break;
966 	default:
967 		ASSERT(0);
968 	}
969 }
970 
971 /* ARGSUSED */
972 static void
973 idm_state_s11_complete(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
974 {
975 	idm_pdu_t *pdu;
976 
977 	/*
978 	 * Cleanup logout success/fail completion if it's been delayed
979 	 * until now.
980 	 */
981 	switch (event_ctx->iec_event) {
982 	case CE_LOGOUT_SUCCESS_SND_DONE:
983 	case CE_LOGOUT_FAIL_SND_DONE:
984 		pdu = (idm_pdu_t *)event_ctx->iec_info;
985 		/* restore client callback */
986 		pdu->isp_callback =  ic->ic_client_callback;
987 		ic->ic_client_callback = NULL;
988 		idm_pdu_complete(pdu, pdu->isp_status);
989 		break;
990 	}
991 }
992 
993 static void
994 idm_state_s12_enable_dm(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
995 {
996 	switch (event_ctx->iec_event) {
997 	case CE_ENABLE_DM_SUCCESS:
998 		/* T20 */
999 		idm_update_state(ic, CS_S5_LOGGED_IN, event_ctx);
1000 		break;
1001 	case CE_ENABLE_DM_FAIL:
1002 		/* T21 */
1003 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
1004 		break;
1005 	case CE_TRANSPORT_FAIL:
1006 		/*
1007 		 * We expect to always hear back from the transport layer
1008 		 * once we have an "enable data-mover" request outstanding.
1009 		 * Therefore we'll ignore other events that may occur even
1010 		 * when they clearly indicate a problem and wait for
1011 		 * CE_ENABLE_DM_FAIL.  On a related note this means the
1012 		 * transport must ensure that it eventually completes the
1013 		 * "enable data-mover" operation with either success or
1014 		 * failure -- otherwise we'll be stuck here.
1015 		 */
1016 		break;
1017 	default:
1018 		ASSERT(0);
1019 		break;
1020 	}
1021 }
1022 
1023 static void
1024 idm_update_state(idm_conn_t *ic, idm_conn_state_t new_state,
1025     idm_conn_event_ctx_t *event_ctx)
1026 {
1027 	int rc;
1028 	idm_status_t idm_status;
1029 
1030 	/*
1031 	 * Validate new state
1032 	 */
1033 	ASSERT(new_state != CS_S0_UNDEFINED);
1034 	ASSERT3U(new_state, <, CS_MAX_STATE);
1035 
1036 	/*
1037 	 * Update state in context.  We protect this with a mutex
1038 	 * even though the state machine code is single threaded so that
1039 	 * other threads can check the state value atomically.
1040 	 */
1041 	new_state = (new_state < CS_MAX_STATE) ?
1042 	    new_state : CS_S0_UNDEFINED;
1043 
1044 	IDM_SM_LOG(CE_NOTE, "idm_update_state: conn %p, evt %s(%d), "
1045 	    "%s(%d) --> %s(%d)", (void *)ic,
1046 	    idm_ce_name[event_ctx->iec_event], event_ctx->iec_event,
1047 	    idm_cs_name[ic->ic_state], ic->ic_state,
1048 	    idm_cs_name[new_state], new_state);
1049 
1050 	DTRACE_PROBE2(conn__state__change,
1051 	    idm_conn_t *, ic, idm_conn_state_t, new_state);
1052 
1053 	mutex_enter(&ic->ic_state_mutex);
1054 	idm_sm_audit_state_change(&ic->ic_state_audit, SAS_IDM_CONN,
1055 	    (int)ic->ic_state, (int)new_state);
1056 	ic->ic_last_state = ic->ic_state;
1057 	ic->ic_state = new_state;
1058 	cv_signal(&ic->ic_state_cv);
1059 	mutex_exit(&ic->ic_state_mutex);
1060 
1061 	switch (ic->ic_state) {
1062 	case CS_S1_FREE:
1063 		ASSERT(0); /* Initial state, can't return */
1064 		break;
1065 	case CS_S2_XPT_WAIT:
1066 		if ((rc = idm_ini_conn_finish(ic)) != 0) {
1067 			idm_conn_event(ic, CE_CONNECT_FAIL, NULL);
1068 		} else {
1069 			idm_conn_event(ic, CE_CONNECT_SUCCESS, NULL);
1070 		}
1071 		break;
1072 	case CS_S3_XPT_UP:
1073 		/*
1074 		 * Finish any connection related setup including
1075 		 * waking up the idm_tgt_conn_accept thread.
1076 		 * and starting the login timer.  If the function
1077 		 * fails then we return to "free" state.
1078 		 */
1079 		if ((rc = idm_tgt_conn_finish(ic)) != IDM_STATUS_SUCCESS) {
1080 			switch (rc) {
1081 			case IDM_STATUS_REJECT:
1082 				idm_conn_event(ic, CE_CONNECT_REJECT, NULL);
1083 				break;
1084 			default:
1085 				idm_conn_event(ic, CE_CONNECT_FAIL, NULL);
1086 				break;
1087 			}
1088 		}
1089 
1090 		/*
1091 		 * First login received will cause a transition to
1092 		 * CS_S4_IN_LOGIN.  Start login timer.
1093 		 */
1094 		ic->ic_state_timeout = timeout(idm_login_timeout, ic,
1095 		    drv_usectohz(IDM_LOGIN_SECONDS*1000000));
1096 		break;
1097 	case CS_S4_IN_LOGIN:
1098 		if (ic->ic_conn_type == CONN_TYPE_INI) {
1099 			mutex_enter(&ic->ic_state_mutex);
1100 			ic->ic_state_flags |= CF_LOGIN_READY;
1101 			cv_signal(&ic->ic_state_cv);
1102 			mutex_exit(&ic->ic_state_mutex);
1103 		}
1104 		break;
1105 	case CS_S5_LOGGED_IN:
1106 		ASSERT(!ic->ic_ffp);
1107 		/*
1108 		 * IDM can go to FFP before the initiator but it
1109 		 * needs to go to FFP after the target (IDM target should
1110 		 * go to FFP after notify_ack).
1111 		 */
1112 		idm_status = idm_ffp_enable(ic);
1113 		if (idm_status != IDM_STATUS_SUCCESS) {
1114 			idm_conn_event(ic, CE_TRANSPORT_FAIL, NULL);
1115 		}
1116 
1117 		if (ic->ic_reinstate_conn) {
1118 			/* Connection reinstatement is complete */
1119 			idm_conn_event_locked(ic->ic_reinstate_conn,
1120 			    CE_CONN_REINSTATE_SUCCESS, NULL, CT_NONE);
1121 		}
1122 		break;
1123 	case CS_S6_IN_LOGOUT:
1124 		break;
1125 	case CS_S7_LOGOUT_REQ:
1126 		/* Start logout timer for target connections */
1127 		if (IDM_CONN_ISTGT(ic)) {
1128 			ic->ic_state_timeout = timeout(idm_logout_req_timeout,
1129 			    ic, drv_usectohz(IDM_LOGOUT_SECONDS*1000000));
1130 		}
1131 		break;
1132 	case CS_S8_CLEANUP:
1133 		/* Close connection (if it's not already closed) */
1134 		if (IDM_CONN_ISTGT(ic)) {
1135 			ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
1136 		} else {
1137 			ic->ic_transport_ops->it_ini_conn_disconnect(ic);
1138 		}
1139 
1140 		/* Stop executing active tasks */
1141 		idm_task_abort(ic, NULL, AT_INTERNAL_SUSPEND);
1142 
1143 		/* Start logout timer */
1144 		ic->ic_state_timeout = timeout(idm_cleanup_timeout, ic,
1145 		    drv_usectohz(IDM_CLEANUP_SECONDS*1000000));
1146 		break;
1147 	case CS_S10_IN_CLEANUP:
1148 		break;
1149 	case CS_S9_INIT_ERROR:
1150 		if (IDM_CONN_ISTGT(ic)) {
1151 			ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
1152 		} else {
1153 			mutex_enter(&ic->ic_state_mutex);
1154 			ic->ic_state_flags |= CF_ERROR;
1155 			ic->ic_conn_sm_status = IDM_STATUS_FAIL;
1156 			cv_signal(&ic->ic_state_cv);
1157 			mutex_exit(&ic->ic_state_mutex);
1158 			if (ic->ic_last_state != CS_S1_FREE &&
1159 			    ic->ic_last_state != CS_S2_XPT_WAIT) {
1160 				ic->ic_transport_ops->it_ini_conn_disconnect(
1161 				    ic);
1162 			} else {
1163 				(void) idm_notify_client(ic, CN_CONNECT_FAIL,
1164 				    NULL);
1165 			}
1166 		}
1167 		/*FALLTHROUGH*/
1168 	case CS_S11_COMPLETE:
1169 		/*
1170 		 * No more traffic on this connection.  If this is an
1171 		 * initiator connection and we weren't connected yet
1172 		 * then don't send the "connect lost" event.
1173 		 * It's useful to the initiator to know whether we were
1174 		 * logging in at the time so send that information in the
1175 		 * data field.
1176 		 */
1177 		if (IDM_CONN_ISTGT(ic) ||
1178 		    ((ic->ic_last_state != CS_S1_FREE) &&
1179 		    (ic->ic_last_state != CS_S2_XPT_WAIT))) {
1180 			(void) idm_notify_client(ic, CN_CONNECT_LOST,
1181 			    (uintptr_t)(ic->ic_last_state == CS_S4_IN_LOGIN));
1182 		}
1183 
1184 		/* Abort all tasks */
1185 		idm_task_abort(ic, NULL, AT_INTERNAL_ABORT);
1186 
1187 		/*
1188 		 * Handle terminal state actions on the global taskq so
1189 		 * we can clean up all the connection resources from
1190 		 * a separate thread context.
1191 		 */
1192 		idm_refcnt_async_wait_ref(&ic->ic_refcnt, &idm_conn_unref);
1193 		break;
1194 	case CS_S12_ENABLE_DM:
1195 
1196 		/*
1197 		 * The Enable DM state indicates the initiator to initiate
1198 		 * the hello sequence and the target to get ready to accept
1199 		 * the iSER Hello Message.
1200 		 */
1201 		idm_status = (IDM_CONN_ISINI(ic)) ?
1202 		    ic->ic_transport_ops->it_ini_enable_datamover(ic) :
1203 		    ic->ic_transport_ops->it_tgt_enable_datamover(ic);
1204 
1205 		if (idm_status == IDM_STATUS_SUCCESS) {
1206 			idm_conn_event(ic, CE_ENABLE_DM_SUCCESS, NULL);
1207 		} else {
1208 			idm_conn_event(ic, CE_ENABLE_DM_FAIL, NULL);
1209 		}
1210 
1211 		break;
1212 	}
1213 }
1214 
1215 
1216 static void
1217 idm_conn_unref(void *ic_void)
1218 {
1219 	idm_conn_t *ic = ic_void;
1220 
1221 	/*
1222 	 * Client should not be notified that the connection is destroyed
1223 	 * until all references on the idm connection have been removed.
1224 	 * Otherwise references on the associated client context would need
1225 	 * to be tracked separately which seems like a waste (at least when
1226 	 * there is a one for one correspondence with references on the
1227 	 * IDM connection).
1228 	 */
1229 	if (IDM_CONN_ISTGT(ic)) {
1230 		(void) idm_notify_client(ic, CN_CONNECT_DESTROY, NULL);
1231 		idm_svc_conn_destroy(ic);
1232 	} else {
1233 		/* Initiator may destroy connection during this call */
1234 		(void) idm_notify_client(ic, CN_CONNECT_DESTROY, NULL);
1235 	}
1236 }
1237 
1238 
1239 static idm_pdu_event_action_t
1240 idm_conn_sm_validate_pdu(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx,
1241 	idm_pdu_t *pdu)
1242 {
1243 	char			*reason_string;
1244 	idm_pdu_event_action_t	action;
1245 
1246 	ASSERT((event_ctx->iec_pdu_event_type == CT_RX_PDU) ||
1247 	    (event_ctx->iec_pdu_event_type == CT_TX_PDU));
1248 
1249 	/*
1250 	 * Let's check the simple stuff first.  Make sure if this is a
1251 	 * target connection that the PDU is appropriate for a target
1252 	 * and if this is an initiator connection that the PDU is
1253 	 * appropriate for an initiator.  This code is not in the data
1254 	 * path so organization is more important than performance.
1255 	 */
1256 	switch (IDM_PDU_OPCODE(pdu)) {
1257 	case ISCSI_OP_NOOP_OUT:
1258 	case ISCSI_OP_SCSI_CMD:
1259 	case ISCSI_OP_SCSI_TASK_MGT_MSG:
1260 	case ISCSI_OP_LOGIN_CMD:
1261 	case ISCSI_OP_TEXT_CMD:
1262 	case ISCSI_OP_SCSI_DATA:
1263 	case ISCSI_OP_LOGOUT_CMD:
1264 	case ISCSI_OP_SNACK_CMD:
1265 		/*
1266 		 * Only the initiator should send these PDU's and
1267 		 * only the target should receive them.
1268 		 */
1269 		if (IDM_CONN_ISINI(ic) &&
1270 		    (event_ctx->iec_pdu_event_type == CT_RX_PDU)) {
1271 			reason_string = "Invalid RX PDU for initiator";
1272 			action = CA_RX_PROTOCOL_ERROR;
1273 			goto validate_pdu_done;
1274 		}
1275 
1276 		if (IDM_CONN_ISTGT(ic) &&
1277 		    (event_ctx->iec_pdu_event_type == CT_TX_PDU)) {
1278 			reason_string = "Invalid TX PDU for target";
1279 			action = CA_TX_PROTOCOL_ERROR;
1280 			goto validate_pdu_done;
1281 		}
1282 		break;
1283 	case ISCSI_OP_NOOP_IN:
1284 	case ISCSI_OP_SCSI_RSP:
1285 	case ISCSI_OP_SCSI_TASK_MGT_RSP:
1286 	case ISCSI_OP_LOGIN_RSP:
1287 	case ISCSI_OP_TEXT_RSP:
1288 	case ISCSI_OP_SCSI_DATA_RSP:
1289 	case ISCSI_OP_LOGOUT_RSP:
1290 	case ISCSI_OP_RTT_RSP:
1291 	case ISCSI_OP_ASYNC_EVENT:
1292 	case ISCSI_OP_REJECT_MSG:
1293 		/*
1294 		 * Only the target should send these PDU's and
1295 		 * only the initiator should receive them.
1296 		 */
1297 		if (IDM_CONN_ISTGT(ic) &&
1298 		    (event_ctx->iec_pdu_event_type == CT_RX_PDU)) {
1299 			reason_string = "Invalid RX PDU for target";
1300 			action = CA_RX_PROTOCOL_ERROR;
1301 			goto validate_pdu_done;
1302 		}
1303 
1304 		if (IDM_CONN_ISINI(ic) &&
1305 		    (event_ctx->iec_pdu_event_type == CT_TX_PDU)) {
1306 			reason_string = "Invalid TX PDU for initiator";
1307 			action = CA_TX_PROTOCOL_ERROR;
1308 			goto validate_pdu_done;
1309 		}
1310 		break;
1311 	default:
1312 		reason_string = "Unknown PDU Type";
1313 		action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1314 		    CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1315 		goto validate_pdu_done;
1316 	}
1317 
1318 	/*
1319 	 * Now validate the opcodes against the current state.
1320 	 */
1321 	reason_string = "PDU not allowed in current state";
1322 	switch (IDM_PDU_OPCODE(pdu)) {
1323 	case ISCSI_OP_NOOP_OUT:
1324 	case ISCSI_OP_NOOP_IN:
1325 		/*
1326 		 * Obviously S1-S3 are not allowed since login hasn't started.
1327 		 * S8 is probably out as well since the connection has been
1328 		 * dropped.
1329 		 */
1330 		switch (ic->ic_state) {
1331 		case CS_S4_IN_LOGIN:
1332 		case CS_S5_LOGGED_IN:
1333 		case CS_S6_IN_LOGOUT:
1334 		case CS_S7_LOGOUT_REQ:
1335 			action = CA_FORWARD;
1336 			goto validate_pdu_done;
1337 		case CS_S8_CLEANUP:
1338 		case CS_S10_IN_CLEANUP:
1339 			action = CA_DROP;
1340 			break;
1341 		default:
1342 			action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1343 			    CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1344 			goto validate_pdu_done;
1345 		}
1346 		/*NOTREACHED*/
1347 	case ISCSI_OP_SCSI_CMD:
1348 	case ISCSI_OP_SCSI_RSP:
1349 	case ISCSI_OP_SCSI_TASK_MGT_MSG:
1350 	case ISCSI_OP_SCSI_TASK_MGT_RSP:
1351 	case ISCSI_OP_SCSI_DATA:
1352 	case ISCSI_OP_SCSI_DATA_RSP:
1353 	case ISCSI_OP_RTT_RSP:
1354 	case ISCSI_OP_SNACK_CMD:
1355 	case ISCSI_OP_TEXT_CMD:
1356 	case ISCSI_OP_TEXT_RSP:
1357 		switch (ic->ic_state) {
1358 		case CS_S5_LOGGED_IN:
1359 		case CS_S6_IN_LOGOUT:
1360 		case CS_S7_LOGOUT_REQ:
1361 			action = CA_FORWARD;
1362 			goto validate_pdu_done;
1363 		case CS_S8_CLEANUP:
1364 		case CS_S10_IN_CLEANUP:
1365 			action = CA_DROP;
1366 			break;
1367 		default:
1368 			action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1369 			    CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1370 			goto validate_pdu_done;
1371 		}
1372 		/*NOTREACHED*/
1373 	case ISCSI_OP_LOGOUT_CMD:
1374 	case ISCSI_OP_LOGOUT_RSP:
1375 	case ISCSI_OP_REJECT_MSG:
1376 	case ISCSI_OP_ASYNC_EVENT:
1377 		switch (ic->ic_state) {
1378 		case CS_S5_LOGGED_IN:
1379 		case CS_S6_IN_LOGOUT:
1380 		case CS_S7_LOGOUT_REQ:
1381 			action = CA_FORWARD;
1382 			goto validate_pdu_done;
1383 		case CS_S8_CLEANUP:
1384 		case CS_S10_IN_CLEANUP:
1385 			action = CA_DROP;
1386 			break;
1387 		default:
1388 			action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1389 			    CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1390 			goto validate_pdu_done;
1391 		}
1392 		/*NOTREACHED*/
1393 	case ISCSI_OP_LOGIN_CMD:
1394 	case ISCSI_OP_LOGIN_RSP:
1395 		switch (ic->ic_state) {
1396 		case CS_S3_XPT_UP:
1397 		case CS_S4_IN_LOGIN:
1398 			action = CA_FORWARD;
1399 			goto validate_pdu_done;
1400 		default:
1401 			action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1402 			    CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1403 			goto validate_pdu_done;
1404 		}
1405 		/*NOTREACHED*/
1406 	default:
1407 		/* This should never happen -- we already checked above */
1408 		ASSERT(0);
1409 		/*NOTREACHED*/
1410 	}
1411 
1412 	action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1413 	    CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1414 
1415 validate_pdu_done:
1416 	if (action != CA_FORWARD) {
1417 		DTRACE_PROBE2(idm__int__protocol__error,
1418 		    idm_conn_event_ctx_t *, event_ctx,
1419 		    char *, reason_string);
1420 	}
1421 
1422 	return (action);
1423 }
1424 
1425 /* ARGSUSED */
1426 void
1427 idm_pdu_tx_protocol_error(idm_conn_t *ic, idm_pdu_t *pdu)
1428 {
1429 	/*
1430 	 * Return the PDU to the caller indicating it was a protocol error.
1431 	 * Caller can take appropriate action.
1432 	 */
1433 	idm_pdu_complete(pdu, IDM_STATUS_PROTOCOL_ERROR);
1434 }
1435 
1436 void
1437 idm_pdu_rx_protocol_error(idm_conn_t *ic, idm_pdu_t *pdu)
1438 {
1439 	/*
1440 	 * Forward PDU to caller indicating it is a protocol error.
1441 	 * Caller should take appropriate action.
1442 	 */
1443 	(*ic->ic_conn_ops.icb_rx_error)(ic, pdu, IDM_STATUS_PROTOCOL_ERROR);
1444 }
1445 
1446 idm_status_t
1447 idm_notify_client(idm_conn_t *ic, idm_client_notify_t cn, uintptr_t data)
1448 {
1449 	/*
1450 	 * We may want to make this more complicated at some point but
1451 	 * for now lets just call the client's notify function and return
1452 	 * the status.
1453 	 */
1454 	cn = (cn > CN_MAX) ? CN_MAX : cn;
1455 	IDM_SM_LOG(CE_NOTE, "idm_notify_client: ic=%p %s(%d)\n",
1456 	    (void *)ic, idm_cn_strings[cn], cn);
1457 	return ((*ic->ic_conn_ops.icb_client_notify)(ic, cn, data));
1458 }
1459 
1460 static idm_status_t
1461 idm_ffp_enable(idm_conn_t *ic)
1462 {
1463 	idm_status_t rc;
1464 
1465 	/*
1466 	 * On the initiator side the client will see this notification
1467 	 * before the actual login succes PDU.  This shouldn't be a big
1468 	 * deal since the initiator drives the connection.  It can simply
1469 	 * wait for the login response then start sending SCSI commands.
1470 	 * Kind ugly though compared with the way things work on target
1471 	 * connections.
1472 	 */
1473 	mutex_enter(&ic->ic_state_mutex);
1474 	ic->ic_ffp = B_TRUE;
1475 	mutex_exit(&ic->ic_state_mutex);
1476 
1477 	rc = idm_notify_client(ic, CN_FFP_ENABLED, NULL);
1478 	if (rc != IDM_STATUS_SUCCESS) {
1479 		mutex_enter(&ic->ic_state_mutex);
1480 		ic->ic_ffp = B_FALSE;
1481 		mutex_exit(&ic->ic_state_mutex);
1482 	}
1483 	return (rc);
1484 }
1485 
1486 static void
1487 idm_ffp_disable(idm_conn_t *ic, idm_ffp_disable_t disable_type)
1488 {
1489 	mutex_enter(&ic->ic_state_mutex);
1490 	ic->ic_ffp = B_FALSE;
1491 	mutex_exit(&ic->ic_state_mutex);
1492 
1493 	/* Client can't "fail" CN_FFP_DISABLED */
1494 	(void) idm_notify_client(ic, CN_FFP_DISABLED,
1495 	    (uintptr_t)disable_type);
1496 }
1497 
1498 static void
1499 idm_initial_login_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1500 {
1501 	ASSERT((event_ctx->iec_event == CE_LOGIN_RCV) ||
1502 	    (event_ctx->iec_event == CE_LOGIN_SND));
1503 
1504 	/*
1505 	 * Currently it's not clear what we would do here -- since
1506 	 * we went to the trouble of coding an "initial login" hook
1507 	 * we'll leave it in for now.  Remove before integration if
1508 	 * it's not used for anything.
1509 	 */
1510 	ic->ic_state_flags |= CF_INITIAL_LOGIN;
1511 }
1512 
1513 static void
1514 idm_login_success_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1515 {
1516 	idm_pdu_t		*pdu = (idm_pdu_t *)event_ctx->iec_info;
1517 	iscsi_login_hdr_t	*login_req =
1518 	    (iscsi_login_hdr_t *)pdu->isp_hdr;
1519 
1520 	ASSERT((event_ctx->iec_event == CE_LOGIN_SUCCESS_RCV) ||
1521 	    (event_ctx->iec_event == CE_LOGIN_SUCCESS_SND));
1522 
1523 	/*
1524 	 * Save off CID
1525 	 */
1526 	mutex_enter(&ic->ic_state_mutex);
1527 	ic->ic_login_cid = ntohs(login_req->cid);
1528 	ic->ic_login_info_valid =  B_TRUE;
1529 
1530 	mutex_exit(&ic->ic_state_mutex);
1531 }
1532