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