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