1*a6d42e7dSPeter Dunlap /*
2*a6d42e7dSPeter Dunlap  * CDDL HEADER START
3*a6d42e7dSPeter Dunlap  *
4*a6d42e7dSPeter Dunlap  * The contents of this file are subject to the terms of the
5*a6d42e7dSPeter Dunlap  * Common Development and Distribution License (the "License").
6*a6d42e7dSPeter Dunlap  * You may not use this file except in compliance with the License.
7*a6d42e7dSPeter Dunlap  *
8*a6d42e7dSPeter Dunlap  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*a6d42e7dSPeter Dunlap  * or http://www.opensolaris.org/os/licensing.
10*a6d42e7dSPeter Dunlap  * See the License for the specific language governing permissions
11*a6d42e7dSPeter Dunlap  * and limitations under the License.
12*a6d42e7dSPeter Dunlap  *
13*a6d42e7dSPeter Dunlap  * When distributing Covered Code, include this CDDL HEADER in each
14*a6d42e7dSPeter Dunlap  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*a6d42e7dSPeter Dunlap  * If applicable, add the following below this CDDL HEADER, with the
16*a6d42e7dSPeter Dunlap  * fields enclosed by brackets "[]" replaced with your own identifying
17*a6d42e7dSPeter Dunlap  * information: Portions Copyright [yyyy] [name of copyright owner]
18*a6d42e7dSPeter Dunlap  *
19*a6d42e7dSPeter Dunlap  * CDDL HEADER END
20*a6d42e7dSPeter Dunlap  */
21*a6d42e7dSPeter Dunlap /*
22*a6d42e7dSPeter Dunlap  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*a6d42e7dSPeter Dunlap  * Use is subject to license terms.
24*a6d42e7dSPeter Dunlap  */
25*a6d42e7dSPeter Dunlap 
26*a6d42e7dSPeter Dunlap #include <sys/cpuvar.h>
27*a6d42e7dSPeter Dunlap #include <sys/types.h>
28*a6d42e7dSPeter Dunlap #include <sys/conf.h>
29*a6d42e7dSPeter Dunlap #include <sys/file.h>
30*a6d42e7dSPeter Dunlap #include <sys/ddi.h>
31*a6d42e7dSPeter Dunlap #include <sys/sunddi.h>
32*a6d42e7dSPeter Dunlap #include <sys/modctl.h>
33*a6d42e7dSPeter Dunlap #include <sys/sysmacros.h>
34*a6d42e7dSPeter Dunlap 
35*a6d42e7dSPeter Dunlap #include <sys/socket.h>
36*a6d42e7dSPeter Dunlap #include <sys/strsubr.h>
37*a6d42e7dSPeter Dunlap #include <sys/note.h>
38*a6d42e7dSPeter Dunlap #include <sys/sdt.h>
39*a6d42e7dSPeter Dunlap 
40*a6d42e7dSPeter Dunlap #include <sys/stmf.h>
41*a6d42e7dSPeter Dunlap #include <sys/stmf_ioctl.h>
42*a6d42e7dSPeter Dunlap #include <sys/portif.h>
43*a6d42e7dSPeter Dunlap #include <sys/idm/idm.h>
44*a6d42e7dSPeter Dunlap 
45*a6d42e7dSPeter Dunlap #define	ISCSIT_SESS_SM_STRINGS
46*a6d42e7dSPeter Dunlap #include <iscsit.h>
47*a6d42e7dSPeter Dunlap 
48*a6d42e7dSPeter Dunlap 
49*a6d42e7dSPeter Dunlap 
50*a6d42e7dSPeter Dunlap typedef struct {
51*a6d42e7dSPeter Dunlap 	list_node_t		se_ctx_node;
52*a6d42e7dSPeter Dunlap 	iscsit_session_event_t	se_ctx_event;
53*a6d42e7dSPeter Dunlap 	iscsit_conn_t		*se_event_data;
54*a6d42e7dSPeter Dunlap } sess_event_ctx_t;
55*a6d42e7dSPeter Dunlap 
56*a6d42e7dSPeter Dunlap static void
57*a6d42e7dSPeter Dunlap sess_sm_event_locked(iscsit_sess_t *ist, iscsit_session_event_t event,
58*a6d42e7dSPeter Dunlap iscsit_conn_t *ict);
59*a6d42e7dSPeter Dunlap 
60*a6d42e7dSPeter Dunlap static void
61*a6d42e7dSPeter Dunlap sess_sm_event_dispatch(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
62*a6d42e7dSPeter Dunlap 
63*a6d42e7dSPeter Dunlap static void
64*a6d42e7dSPeter Dunlap sess_sm_q1_free(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
65*a6d42e7dSPeter Dunlap 
66*a6d42e7dSPeter Dunlap static void
67*a6d42e7dSPeter Dunlap sess_sm_q2_active(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
68*a6d42e7dSPeter Dunlap 
69*a6d42e7dSPeter Dunlap static void
70*a6d42e7dSPeter Dunlap sess_sm_q3_logged_in(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
71*a6d42e7dSPeter Dunlap 
72*a6d42e7dSPeter Dunlap static void
73*a6d42e7dSPeter Dunlap sess_sm_q4_failed(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
74*a6d42e7dSPeter Dunlap 
75*a6d42e7dSPeter Dunlap static void
76*a6d42e7dSPeter Dunlap sess_sm_q5_continue(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
77*a6d42e7dSPeter Dunlap 
78*a6d42e7dSPeter Dunlap static void
79*a6d42e7dSPeter Dunlap sess_sm_q6_done(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
80*a6d42e7dSPeter Dunlap 
81*a6d42e7dSPeter Dunlap static void
82*a6d42e7dSPeter Dunlap sess_sm_q7_error(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
83*a6d42e7dSPeter Dunlap 
84*a6d42e7dSPeter Dunlap static void
85*a6d42e7dSPeter Dunlap sess_sm_new_state(iscsit_sess_t *ist, sess_event_ctx_t *ctx,
86*a6d42e7dSPeter Dunlap     iscsit_session_state_t new_state);
87*a6d42e7dSPeter Dunlap 
88*a6d42e7dSPeter Dunlap 
89*a6d42e7dSPeter Dunlap static uint16_t
90*a6d42e7dSPeter Dunlap iscsit_tsih_alloc(void)
91*a6d42e7dSPeter Dunlap {
92*a6d42e7dSPeter Dunlap 	uintptr_t result;
93*a6d42e7dSPeter Dunlap 
94*a6d42e7dSPeter Dunlap 	result = (uintptr_t)vmem_alloc(iscsit_global.global_tsih_pool,
95*a6d42e7dSPeter Dunlap 	    1, VM_NOSLEEP | VM_NEXTFIT);
96*a6d42e7dSPeter Dunlap 
97*a6d42e7dSPeter Dunlap 	/* ISCSI_UNSPEC_TSIH (0) indicates failure */
98*a6d42e7dSPeter Dunlap 	if (result > ISCSI_MAX_TSIH) {
99*a6d42e7dSPeter Dunlap 		vmem_free(iscsit_global.global_tsih_pool, (void *)result, 1);
100*a6d42e7dSPeter Dunlap 		result = ISCSI_UNSPEC_TSIH;
101*a6d42e7dSPeter Dunlap 	}
102*a6d42e7dSPeter Dunlap 
103*a6d42e7dSPeter Dunlap 	return ((uint16_t)result);
104*a6d42e7dSPeter Dunlap }
105*a6d42e7dSPeter Dunlap 
106*a6d42e7dSPeter Dunlap static void
107*a6d42e7dSPeter Dunlap iscsit_tsih_free(uint16_t tsih)
108*a6d42e7dSPeter Dunlap {
109*a6d42e7dSPeter Dunlap 	vmem_free(iscsit_global.global_tsih_pool, (void *)(uintptr_t)tsih, 1);
110*a6d42e7dSPeter Dunlap }
111*a6d42e7dSPeter Dunlap 
112*a6d42e7dSPeter Dunlap 
113*a6d42e7dSPeter Dunlap iscsit_sess_t *
114*a6d42e7dSPeter Dunlap iscsit_sess_create(iscsit_tgt_t *tgt, iscsit_conn_t *ict,
115*a6d42e7dSPeter Dunlap     uint32_t cmdsn, uint8_t *isid, uint16_t tag,
116*a6d42e7dSPeter Dunlap     char *initiator_name, char *target_name,
117*a6d42e7dSPeter Dunlap     uint8_t *error_class, uint8_t *error_detail)
118*a6d42e7dSPeter Dunlap {
119*a6d42e7dSPeter Dunlap 	iscsit_sess_t *result;
120*a6d42e7dSPeter Dunlap 
121*a6d42e7dSPeter Dunlap 
122*a6d42e7dSPeter Dunlap 	/*
123*a6d42e7dSPeter Dunlap 	 * Even if this session create "fails" for some reason we still need
124*a6d42e7dSPeter Dunlap 	 * to return a valid session pointer so that we can send the failed
125*a6d42e7dSPeter Dunlap 	 * login response.
126*a6d42e7dSPeter Dunlap 	 */
127*a6d42e7dSPeter Dunlap 	result = kmem_zalloc(sizeof (*result), KM_SLEEP);
128*a6d42e7dSPeter Dunlap 
129*a6d42e7dSPeter Dunlap 	/* Allocate TSIH */
130*a6d42e7dSPeter Dunlap 	if ((result->ist_tsih = iscsit_tsih_alloc()) == ISCSI_UNSPEC_TSIH) {
131*a6d42e7dSPeter Dunlap 		/* Out of TSIH's */
132*a6d42e7dSPeter Dunlap 		*error_class = ISCSI_STATUS_CLASS_TARGET_ERR;
133*a6d42e7dSPeter Dunlap 		*error_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
134*a6d42e7dSPeter Dunlap 		/*
135*a6d42e7dSPeter Dunlap 		 * Continue initializing this session so we can use it
136*a6d42e7dSPeter Dunlap 		 * to complete the login process.
137*a6d42e7dSPeter Dunlap 		 */
138*a6d42e7dSPeter Dunlap 	}
139*a6d42e7dSPeter Dunlap 
140*a6d42e7dSPeter Dunlap 	idm_sm_audit_init(&result->ist_state_audit);
141*a6d42e7dSPeter Dunlap 	rw_init(&result->ist_sn_rwlock, NULL, RW_DRIVER, NULL);
142*a6d42e7dSPeter Dunlap 	mutex_init(&result->ist_mutex, NULL, MUTEX_DEFAULT, NULL);
143*a6d42e7dSPeter Dunlap 	cv_init(&result->ist_cv, NULL, CV_DEFAULT, NULL);
144*a6d42e7dSPeter Dunlap 	list_create(&result->ist_events, sizeof (sess_event_ctx_t),
145*a6d42e7dSPeter Dunlap 	    offsetof(sess_event_ctx_t, se_ctx_node));
146*a6d42e7dSPeter Dunlap 	list_create(&result->ist_conn_list, sizeof (iscsit_conn_t),
147*a6d42e7dSPeter Dunlap 	    offsetof(iscsit_conn_t, ict_sess_ln));
148*a6d42e7dSPeter Dunlap 
149*a6d42e7dSPeter Dunlap 	result->ist_state = SS_Q1_FREE;
150*a6d42e7dSPeter Dunlap 	result->ist_last_state = SS_Q1_FREE;
151*a6d42e7dSPeter Dunlap 	bcopy(isid, result->ist_isid, ISCSI_ISID_LEN);
152*a6d42e7dSPeter Dunlap 	result->ist_tpgt_tag = tag;
153*a6d42e7dSPeter Dunlap 
154*a6d42e7dSPeter Dunlap 	result->ist_tgt = tgt;
155*a6d42e7dSPeter Dunlap 	result->ist_expcmdsn = cmdsn + 1;
156*a6d42e7dSPeter Dunlap 	result->ist_maxcmdsn = result->ist_expcmdsn + 1;
157*a6d42e7dSPeter Dunlap 
158*a6d42e7dSPeter Dunlap 	result->ist_initiator_name =
159*a6d42e7dSPeter Dunlap 	    kmem_alloc(strlen(initiator_name) + 1, KM_SLEEP);
160*a6d42e7dSPeter Dunlap 	(void) strcpy(result->ist_initiator_name, initiator_name);
161*a6d42e7dSPeter Dunlap 	if (target_name) {
162*a6d42e7dSPeter Dunlap 		/* A discovery session might not have a target name */
163*a6d42e7dSPeter Dunlap 		result->ist_target_name =
164*a6d42e7dSPeter Dunlap 		    kmem_alloc(strlen(target_name) + 1, KM_SLEEP);
165*a6d42e7dSPeter Dunlap 		(void) strcpy(result->ist_target_name, target_name);
166*a6d42e7dSPeter Dunlap 	}
167*a6d42e7dSPeter Dunlap 	idm_refcnt_init(&result->ist_refcnt, result);
168*a6d42e7dSPeter Dunlap 
169*a6d42e7dSPeter Dunlap 	/* Login code will fill in ist_stmf_sess if necessary */
170*a6d42e7dSPeter Dunlap 
171*a6d42e7dSPeter Dunlap 	/* Kick session state machine (also binds connection to session) */
172*a6d42e7dSPeter Dunlap 	iscsit_sess_sm_event(result, SE_CONN_IN_LOGIN, ict);
173*a6d42e7dSPeter Dunlap 
174*a6d42e7dSPeter Dunlap 	*error_class = ISCSI_STATUS_CLASS_SUCCESS;
175*a6d42e7dSPeter Dunlap 	/*
176*a6d42e7dSPeter Dunlap 	 * As noted above we must return a session pointer even if something
177*a6d42e7dSPeter Dunlap 	 * failed.  The resources will get freed later.
178*a6d42e7dSPeter Dunlap 	 */
179*a6d42e7dSPeter Dunlap 	return (result);
180*a6d42e7dSPeter Dunlap }
181*a6d42e7dSPeter Dunlap 
182*a6d42e7dSPeter Dunlap static void
183*a6d42e7dSPeter Dunlap iscsit_sess_unref(void *ist_void)
184*a6d42e7dSPeter Dunlap {
185*a6d42e7dSPeter Dunlap 	iscsit_sess_t *ist = ist_void;
186*a6d42e7dSPeter Dunlap 
187*a6d42e7dSPeter Dunlap 	/*
188*a6d42e7dSPeter Dunlap 	 * State machine has run to completion, destroy session
189*a6d42e7dSPeter Dunlap 	 *
190*a6d42e7dSPeter Dunlap 	 * If we have an associated STMF session we should clean it
191*a6d42e7dSPeter Dunlap 	 * up now.
192*a6d42e7dSPeter Dunlap 	 *
193*a6d42e7dSPeter Dunlap 	 * This session is no longer associated with a target at this
194*a6d42e7dSPeter Dunlap 	 * point so don't touch the target.
195*a6d42e7dSPeter Dunlap 	 */
196*a6d42e7dSPeter Dunlap 	mutex_enter(&ist->ist_mutex);
197*a6d42e7dSPeter Dunlap 	ASSERT(ist->ist_conn_count == 0);
198*a6d42e7dSPeter Dunlap 	if (ist->ist_stmf_sess != NULL) {
199*a6d42e7dSPeter Dunlap 		stmf_deregister_scsi_session(ist->ist_lport,
200*a6d42e7dSPeter Dunlap 		    ist->ist_stmf_sess);
201*a6d42e7dSPeter Dunlap 		kmem_free(ist->ist_stmf_sess->ss_rport_id,
202*a6d42e7dSPeter Dunlap 		    sizeof (scsi_devid_desc_t) +
203*a6d42e7dSPeter Dunlap 		    strlen(ist->ist_initiator_name) + 1);
204*a6d42e7dSPeter Dunlap 		stmf_free(ist->ist_stmf_sess);
205*a6d42e7dSPeter Dunlap 	}
206*a6d42e7dSPeter Dunlap 	mutex_exit(&ist->ist_mutex);
207*a6d42e7dSPeter Dunlap 
208*a6d42e7dSPeter Dunlap 	iscsit_sess_destroy(ist);
209*a6d42e7dSPeter Dunlap }
210*a6d42e7dSPeter Dunlap 
211*a6d42e7dSPeter Dunlap void
212*a6d42e7dSPeter Dunlap iscsit_sess_destroy(iscsit_sess_t *ist)
213*a6d42e7dSPeter Dunlap {
214*a6d42e7dSPeter Dunlap 	idm_refcnt_destroy(&ist->ist_refcnt);
215*a6d42e7dSPeter Dunlap 	if (ist->ist_initiator_name)
216*a6d42e7dSPeter Dunlap 		kmem_free(ist->ist_initiator_name,
217*a6d42e7dSPeter Dunlap 		    strlen(ist->ist_initiator_name) + 1);
218*a6d42e7dSPeter Dunlap 	if (ist->ist_initiator_alias)
219*a6d42e7dSPeter Dunlap 		kmem_free(ist->ist_initiator_alias,
220*a6d42e7dSPeter Dunlap 		    strlen(ist->ist_initiator_alias) + 1);
221*a6d42e7dSPeter Dunlap 	if (ist->ist_target_name)
222*a6d42e7dSPeter Dunlap 		kmem_free(ist->ist_target_name,
223*a6d42e7dSPeter Dunlap 		    strlen(ist->ist_target_name) + 1);
224*a6d42e7dSPeter Dunlap 	if (ist->ist_target_alias)
225*a6d42e7dSPeter Dunlap 		kmem_free(ist->ist_target_alias,
226*a6d42e7dSPeter Dunlap 		    strlen(ist->ist_target_alias) + 1);
227*a6d42e7dSPeter Dunlap 	list_destroy(&ist->ist_conn_list);
228*a6d42e7dSPeter Dunlap 	list_destroy(&ist->ist_events);
229*a6d42e7dSPeter Dunlap 	cv_destroy(&ist->ist_cv);
230*a6d42e7dSPeter Dunlap 	mutex_destroy(&ist->ist_mutex);
231*a6d42e7dSPeter Dunlap 	rw_destroy(&ist->ist_sn_rwlock);
232*a6d42e7dSPeter Dunlap 	kmem_free(ist, sizeof (*ist));
233*a6d42e7dSPeter Dunlap }
234*a6d42e7dSPeter Dunlap 
235*a6d42e7dSPeter Dunlap void
236*a6d42e7dSPeter Dunlap iscsit_sess_close(iscsit_sess_t *ist)
237*a6d42e7dSPeter Dunlap {
238*a6d42e7dSPeter Dunlap 	iscsit_conn_t *ict;
239*a6d42e7dSPeter Dunlap 
240*a6d42e7dSPeter Dunlap 	mutex_enter(&ist->ist_mutex);
241*a6d42e7dSPeter Dunlap 	/*
242*a6d42e7dSPeter Dunlap 	 * Note in the session state that we are forcing this session
243*a6d42e7dSPeter Dunlap 	 * to close so that the session state machine can avoid
244*a6d42e7dSPeter Dunlap 	 * pointless delays like transitions to SS_Q4_FAILED state.
245*a6d42e7dSPeter Dunlap 	 */
246*a6d42e7dSPeter Dunlap 	ist->ist_admin_close = B_TRUE;
247*a6d42e7dSPeter Dunlap 	if (ist->ist_state == SS_Q3_LOGGED_IN) {
248*a6d42e7dSPeter Dunlap 		for (ict = list_head(&ist->ist_conn_list);
249*a6d42e7dSPeter Dunlap 		    ict != NULL;
250*a6d42e7dSPeter Dunlap 		    ict = list_next(&ist->ist_conn_list, ict)) {
251*a6d42e7dSPeter Dunlap 			iscsit_send_async_event(ict,
252*a6d42e7dSPeter Dunlap 			    ISCSI_ASYNC_EVENT_REQUEST_LOGOUT);
253*a6d42e7dSPeter Dunlap 		}
254*a6d42e7dSPeter Dunlap 	}
255*a6d42e7dSPeter Dunlap 	mutex_exit(&ist->ist_mutex);
256*a6d42e7dSPeter Dunlap }
257*a6d42e7dSPeter Dunlap 
258*a6d42e7dSPeter Dunlap 
259*a6d42e7dSPeter Dunlap void
260*a6d42e7dSPeter Dunlap iscsit_sess_bind_conn(iscsit_sess_t *ist, iscsit_conn_t *ict)
261*a6d42e7dSPeter Dunlap {
262*a6d42e7dSPeter Dunlap 	iscsit_conn_hold(ict);
263*a6d42e7dSPeter Dunlap 	iscsit_sess_hold(ist);
264*a6d42e7dSPeter Dunlap 	ict->ict_sess = ist;
265*a6d42e7dSPeter Dunlap 	mutex_enter(&ist->ist_mutex);
266*a6d42e7dSPeter Dunlap 	ist->ist_conn_count++;
267*a6d42e7dSPeter Dunlap 	list_insert_tail(&ist->ist_conn_list, ict);
268*a6d42e7dSPeter Dunlap 	mutex_exit(&ist->ist_mutex);
269*a6d42e7dSPeter Dunlap }
270*a6d42e7dSPeter Dunlap 
271*a6d42e7dSPeter Dunlap void
272*a6d42e7dSPeter Dunlap iscsit_sess_unbind_conn(iscsit_sess_t *ist, iscsit_conn_t *ict)
273*a6d42e7dSPeter Dunlap {
274*a6d42e7dSPeter Dunlap 	mutex_enter(&ist->ist_mutex);
275*a6d42e7dSPeter Dunlap 	list_remove(&ist->ist_conn_list, ict);
276*a6d42e7dSPeter Dunlap 	ist->ist_conn_count--;
277*a6d42e7dSPeter Dunlap 	mutex_exit(&ist->ist_mutex);
278*a6d42e7dSPeter Dunlap 	iscsit_sess_rele(ist);
279*a6d42e7dSPeter Dunlap 	iscsit_conn_rele(ict);
280*a6d42e7dSPeter Dunlap }
281*a6d42e7dSPeter Dunlap 
282*a6d42e7dSPeter Dunlap void
283*a6d42e7dSPeter Dunlap iscsit_sess_hold(iscsit_sess_t *ist)
284*a6d42e7dSPeter Dunlap {
285*a6d42e7dSPeter Dunlap 	idm_refcnt_hold(&ist->ist_refcnt);
286*a6d42e7dSPeter Dunlap }
287*a6d42e7dSPeter Dunlap 
288*a6d42e7dSPeter Dunlap void
289*a6d42e7dSPeter Dunlap iscsit_sess_rele(iscsit_sess_t *ist)
290*a6d42e7dSPeter Dunlap {
291*a6d42e7dSPeter Dunlap 	idm_refcnt_rele(&ist->ist_refcnt);
292*a6d42e7dSPeter Dunlap }
293*a6d42e7dSPeter Dunlap 
294*a6d42e7dSPeter Dunlap iscsit_conn_t *
295*a6d42e7dSPeter Dunlap iscsit_sess_lookup_conn(iscsit_sess_t *ist, uint16_t cid)
296*a6d42e7dSPeter Dunlap {
297*a6d42e7dSPeter Dunlap 	iscsit_conn_t *result;
298*a6d42e7dSPeter Dunlap 
299*a6d42e7dSPeter Dunlap 	mutex_enter(&ist->ist_mutex);
300*a6d42e7dSPeter Dunlap 	for (result = list_head(&ist->ist_conn_list);
301*a6d42e7dSPeter Dunlap 	    result != NULL;
302*a6d42e7dSPeter Dunlap 	    result = list_next(&ist->ist_conn_list, result)) {
303*a6d42e7dSPeter Dunlap 		if (result->ict_cid == cid) {
304*a6d42e7dSPeter Dunlap 			iscsit_conn_hold(result);
305*a6d42e7dSPeter Dunlap 			mutex_exit(&ist->ist_mutex);
306*a6d42e7dSPeter Dunlap 			return (result);
307*a6d42e7dSPeter Dunlap 		}
308*a6d42e7dSPeter Dunlap 	}
309*a6d42e7dSPeter Dunlap 	mutex_exit(&ist->ist_mutex);
310*a6d42e7dSPeter Dunlap 
311*a6d42e7dSPeter Dunlap 	return (NULL);
312*a6d42e7dSPeter Dunlap }
313*a6d42e7dSPeter Dunlap 
314*a6d42e7dSPeter Dunlap iscsit_sess_t *
315*a6d42e7dSPeter Dunlap iscsit_sess_reinstate(iscsit_tgt_t *tgt, iscsit_sess_t *ist, iscsit_conn_t *ict,
316*a6d42e7dSPeter Dunlap     uint8_t *error_class, uint8_t *error_detail)
317*a6d42e7dSPeter Dunlap {
318*a6d42e7dSPeter Dunlap 	iscsit_sess_t *new_sess;
319*a6d42e7dSPeter Dunlap 
320*a6d42e7dSPeter Dunlap 	mutex_enter(&ist->ist_mutex);
321*a6d42e7dSPeter Dunlap 
322*a6d42e7dSPeter Dunlap 	/*
323*a6d42e7dSPeter Dunlap 	 * Session reinstatement replaces a current session with a new session.
324*a6d42e7dSPeter Dunlap 	 * The new session will have the same ISID as the existing session.
325*a6d42e7dSPeter Dunlap 	 */
326*a6d42e7dSPeter Dunlap 	new_sess = iscsit_sess_create(tgt, ict, 0,
327*a6d42e7dSPeter Dunlap 	    ist->ist_isid, ist->ist_tpgt_tag,
328*a6d42e7dSPeter Dunlap 	    ist->ist_initiator_name, ist->ist_target_name,
329*a6d42e7dSPeter Dunlap 	    error_class, error_detail);
330*a6d42e7dSPeter Dunlap 	ASSERT(new_sess != NULL);
331*a6d42e7dSPeter Dunlap 
332*a6d42e7dSPeter Dunlap 	/* Copy additional fields from original session */
333*a6d42e7dSPeter Dunlap 	new_sess->ist_expcmdsn = ist->ist_expcmdsn;
334*a6d42e7dSPeter Dunlap 	new_sess->ist_maxcmdsn = ist->ist_expcmdsn + 1;
335*a6d42e7dSPeter Dunlap 
336*a6d42e7dSPeter Dunlap 	if (ist->ist_state != SS_Q6_DONE &&
337*a6d42e7dSPeter Dunlap 	    ist->ist_state != SS_Q7_ERROR) {
338*a6d42e7dSPeter Dunlap 		/*
339*a6d42e7dSPeter Dunlap 		 * Generate reinstate event
340*a6d42e7dSPeter Dunlap 		 */
341*a6d42e7dSPeter Dunlap 		sess_sm_event_locked(ist, SE_SESSION_REINSTATE, NULL);
342*a6d42e7dSPeter Dunlap 	}
343*a6d42e7dSPeter Dunlap 	mutex_exit(&ist->ist_mutex);
344*a6d42e7dSPeter Dunlap 
345*a6d42e7dSPeter Dunlap 	return (new_sess);
346*a6d42e7dSPeter Dunlap }
347*a6d42e7dSPeter Dunlap 
348*a6d42e7dSPeter Dunlap int
349*a6d42e7dSPeter Dunlap iscsit_sess_avl_compare(const void *void_sess1, const void *void_sess2)
350*a6d42e7dSPeter Dunlap {
351*a6d42e7dSPeter Dunlap 	const iscsit_sess_t	*sess1 = void_sess1;
352*a6d42e7dSPeter Dunlap 	const iscsit_sess_t	*sess2 = void_sess2;
353*a6d42e7dSPeter Dunlap 	int 			result;
354*a6d42e7dSPeter Dunlap 
355*a6d42e7dSPeter Dunlap 	/*
356*a6d42e7dSPeter Dunlap 	 * Sort by initiator name, then ISID then portal group tag
357*a6d42e7dSPeter Dunlap 	 */
358*a6d42e7dSPeter Dunlap 	result = strcmp(sess1->ist_initiator_name, sess2->ist_initiator_name);
359*a6d42e7dSPeter Dunlap 	if (result < 0) {
360*a6d42e7dSPeter Dunlap 		return (-1);
361*a6d42e7dSPeter Dunlap 	} else if (result > 0) {
362*a6d42e7dSPeter Dunlap 		return (1);
363*a6d42e7dSPeter Dunlap 	}
364*a6d42e7dSPeter Dunlap 
365*a6d42e7dSPeter Dunlap 	/*
366*a6d42e7dSPeter Dunlap 	 * Initiator names match, compare ISIDs
367*a6d42e7dSPeter Dunlap 	 */
368*a6d42e7dSPeter Dunlap 	result = memcmp(sess1->ist_isid, sess2->ist_isid, ISCSI_ISID_LEN);
369*a6d42e7dSPeter Dunlap 	if (result < 0) {
370*a6d42e7dSPeter Dunlap 		return (-1);
371*a6d42e7dSPeter Dunlap 	} else if (result > 0) {
372*a6d42e7dSPeter Dunlap 		return (1);
373*a6d42e7dSPeter Dunlap 	}
374*a6d42e7dSPeter Dunlap 
375*a6d42e7dSPeter Dunlap 	/*
376*a6d42e7dSPeter Dunlap 	 * ISIDs match, compare portal group tags
377*a6d42e7dSPeter Dunlap 	 */
378*a6d42e7dSPeter Dunlap 	if (sess1->ist_tpgt_tag < sess2->ist_tpgt_tag) {
379*a6d42e7dSPeter Dunlap 		return (-1);
380*a6d42e7dSPeter Dunlap 	} else if (sess1->ist_tpgt_tag > sess2->ist_tpgt_tag) {
381*a6d42e7dSPeter Dunlap 		return (1);
382*a6d42e7dSPeter Dunlap 	}
383*a6d42e7dSPeter Dunlap 
384*a6d42e7dSPeter Dunlap 	/*
385*a6d42e7dSPeter Dunlap 	 * Portal group tags match, compare TSIHs
386*a6d42e7dSPeter Dunlap 	 */
387*a6d42e7dSPeter Dunlap 	if (sess1->ist_tsih < sess2->ist_tsih) {
388*a6d42e7dSPeter Dunlap 		return (-1);
389*a6d42e7dSPeter Dunlap 	} else if (sess1->ist_tsih > sess2->ist_tsih) {
390*a6d42e7dSPeter Dunlap 		return (1);
391*a6d42e7dSPeter Dunlap 	}
392*a6d42e7dSPeter Dunlap 
393*a6d42e7dSPeter Dunlap 	/*
394*a6d42e7dSPeter Dunlap 	 * Sessions match
395*a6d42e7dSPeter Dunlap 	 */
396*a6d42e7dSPeter Dunlap 	return (0);
397*a6d42e7dSPeter Dunlap }
398*a6d42e7dSPeter Dunlap 
399*a6d42e7dSPeter Dunlap 
400*a6d42e7dSPeter Dunlap /*
401*a6d42e7dSPeter Dunlap  * State machine
402*a6d42e7dSPeter Dunlap  */
403*a6d42e7dSPeter Dunlap 
404*a6d42e7dSPeter Dunlap void
405*a6d42e7dSPeter Dunlap iscsit_sess_sm_event(iscsit_sess_t *ist, iscsit_session_event_t event,
406*a6d42e7dSPeter Dunlap     iscsit_conn_t *ict)
407*a6d42e7dSPeter Dunlap {
408*a6d42e7dSPeter Dunlap 	mutex_enter(&ist->ist_mutex);
409*a6d42e7dSPeter Dunlap 	sess_sm_event_locked(ist, event, ict);
410*a6d42e7dSPeter Dunlap 	mutex_exit(&ist->ist_mutex);
411*a6d42e7dSPeter Dunlap }
412*a6d42e7dSPeter Dunlap 
413*a6d42e7dSPeter Dunlap static void
414*a6d42e7dSPeter Dunlap sess_sm_event_locked(iscsit_sess_t *ist, iscsit_session_event_t event,
415*a6d42e7dSPeter Dunlap     iscsit_conn_t *ict)
416*a6d42e7dSPeter Dunlap {
417*a6d42e7dSPeter Dunlap 	sess_event_ctx_t *ctx;
418*a6d42e7dSPeter Dunlap 
419*a6d42e7dSPeter Dunlap 	iscsit_sess_hold(ist);
420*a6d42e7dSPeter Dunlap 
421*a6d42e7dSPeter Dunlap 	ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
422*a6d42e7dSPeter Dunlap 
423*a6d42e7dSPeter Dunlap 	ctx->se_ctx_event = event;
424*a6d42e7dSPeter Dunlap 	ctx->se_event_data = ict;
425*a6d42e7dSPeter Dunlap 
426*a6d42e7dSPeter Dunlap 	list_insert_tail(&ist->ist_events, ctx);
427*a6d42e7dSPeter Dunlap 	/*
428*a6d42e7dSPeter Dunlap 	 * Use the icl_busy flag to keep the state machine single threaded.
429*a6d42e7dSPeter Dunlap 	 * This also serves as recursion avoidance since this flag will
430*a6d42e7dSPeter Dunlap 	 * always be set if we call login_sm_event from within the
431*a6d42e7dSPeter Dunlap 	 * state machine code.
432*a6d42e7dSPeter Dunlap 	 */
433*a6d42e7dSPeter Dunlap 	if (!ist->ist_sm_busy) {
434*a6d42e7dSPeter Dunlap 		ist->ist_sm_busy = B_TRUE;
435*a6d42e7dSPeter Dunlap 		while (!list_is_empty(&ist->ist_events)) {
436*a6d42e7dSPeter Dunlap 			ctx = list_head(&ist->ist_events);
437*a6d42e7dSPeter Dunlap 			list_remove(&ist->ist_events, ctx);
438*a6d42e7dSPeter Dunlap 			idm_sm_audit_event(&ist->ist_state_audit,
439*a6d42e7dSPeter Dunlap 			    SAS_ISCSIT_SESS, (int)ist->ist_state,
440*a6d42e7dSPeter Dunlap 			    (int)ctx->se_ctx_event, (uintptr_t)ict);
441*a6d42e7dSPeter Dunlap 			mutex_exit(&ist->ist_mutex);
442*a6d42e7dSPeter Dunlap 			sess_sm_event_dispatch(ist, ctx);
443*a6d42e7dSPeter Dunlap 			mutex_enter(&ist->ist_mutex);
444*a6d42e7dSPeter Dunlap 		}
445*a6d42e7dSPeter Dunlap 		ist->ist_sm_busy = B_FALSE;
446*a6d42e7dSPeter Dunlap 
447*a6d42e7dSPeter Dunlap 	}
448*a6d42e7dSPeter Dunlap 
449*a6d42e7dSPeter Dunlap 	iscsit_sess_rele(ist);
450*a6d42e7dSPeter Dunlap }
451*a6d42e7dSPeter Dunlap 
452*a6d42e7dSPeter Dunlap static void
453*a6d42e7dSPeter Dunlap sess_sm_event_dispatch(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
454*a6d42e7dSPeter Dunlap {
455*a6d42e7dSPeter Dunlap 	iscsit_conn_t	*ict;
456*a6d42e7dSPeter Dunlap 
457*a6d42e7dSPeter Dunlap 	DTRACE_PROBE2(session__event, iscsit_sess_t *, ist,
458*a6d42e7dSPeter Dunlap 	    sess_event_ctx_t *, ctx);
459*a6d42e7dSPeter Dunlap 
460*a6d42e7dSPeter Dunlap 	IDM_SM_LOG(CE_NOTE, "sess_sm_event_dispatch: sess %p event %s(%d)",
461*a6d42e7dSPeter Dunlap 	    (void *)ist, iscsit_se_name[ctx->se_ctx_event], ctx->se_ctx_event);
462*a6d42e7dSPeter Dunlap 
463*a6d42e7dSPeter Dunlap 	/* State independent actions */
464*a6d42e7dSPeter Dunlap 	switch (ctx->se_ctx_event) {
465*a6d42e7dSPeter Dunlap 	case SE_CONN_IN_LOGIN:
466*a6d42e7dSPeter Dunlap 		ict = ctx->se_event_data;
467*a6d42e7dSPeter Dunlap 		iscsit_sess_bind_conn(ist, ict);
468*a6d42e7dSPeter Dunlap 		break;
469*a6d42e7dSPeter Dunlap 	case SE_CONN_FAIL:
470*a6d42e7dSPeter Dunlap 		ict = ctx->se_event_data;
471*a6d42e7dSPeter Dunlap 		iscsit_sess_unbind_conn(ist, ict);
472*a6d42e7dSPeter Dunlap 		break;
473*a6d42e7dSPeter Dunlap 	}
474*a6d42e7dSPeter Dunlap 
475*a6d42e7dSPeter Dunlap 	/* State dependent actions */
476*a6d42e7dSPeter Dunlap 	switch (ist->ist_state) {
477*a6d42e7dSPeter Dunlap 	case SS_Q1_FREE:
478*a6d42e7dSPeter Dunlap 		sess_sm_q1_free(ist, ctx);
479*a6d42e7dSPeter Dunlap 		break;
480*a6d42e7dSPeter Dunlap 	case SS_Q2_ACTIVE:
481*a6d42e7dSPeter Dunlap 		sess_sm_q2_active(ist, ctx);
482*a6d42e7dSPeter Dunlap 		break;
483*a6d42e7dSPeter Dunlap 	case SS_Q3_LOGGED_IN:
484*a6d42e7dSPeter Dunlap 		sess_sm_q3_logged_in(ist, ctx);
485*a6d42e7dSPeter Dunlap 		break;
486*a6d42e7dSPeter Dunlap 	case SS_Q4_FAILED:
487*a6d42e7dSPeter Dunlap 		sess_sm_q4_failed(ist, ctx);
488*a6d42e7dSPeter Dunlap 		break;
489*a6d42e7dSPeter Dunlap 	case SS_Q5_CONTINUE:
490*a6d42e7dSPeter Dunlap 		sess_sm_q5_continue(ist, ctx);
491*a6d42e7dSPeter Dunlap 		break;
492*a6d42e7dSPeter Dunlap 	case SS_Q6_DONE:
493*a6d42e7dSPeter Dunlap 		sess_sm_q6_done(ist, ctx);
494*a6d42e7dSPeter Dunlap 		break;
495*a6d42e7dSPeter Dunlap 	case SS_Q7_ERROR:
496*a6d42e7dSPeter Dunlap 		sess_sm_q7_error(ist, ctx);
497*a6d42e7dSPeter Dunlap 		break;
498*a6d42e7dSPeter Dunlap 	default:
499*a6d42e7dSPeter Dunlap 		ASSERT(0);
500*a6d42e7dSPeter Dunlap 		break;
501*a6d42e7dSPeter Dunlap 	}
502*a6d42e7dSPeter Dunlap 
503*a6d42e7dSPeter Dunlap 	kmem_free(ctx, sizeof (*ctx));
504*a6d42e7dSPeter Dunlap }
505*a6d42e7dSPeter Dunlap 
506*a6d42e7dSPeter Dunlap static void
507*a6d42e7dSPeter Dunlap sess_sm_q1_free(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
508*a6d42e7dSPeter Dunlap {
509*a6d42e7dSPeter Dunlap 	switch (ctx->se_ctx_event) {
510*a6d42e7dSPeter Dunlap 	case SE_CONN_IN_LOGIN:
511*a6d42e7dSPeter Dunlap 		/* N1 */
512*a6d42e7dSPeter Dunlap 		sess_sm_new_state(ist, ctx, SS_Q2_ACTIVE);
513*a6d42e7dSPeter Dunlap 		break;
514*a6d42e7dSPeter Dunlap 	default:
515*a6d42e7dSPeter Dunlap 		ASSERT(0);
516*a6d42e7dSPeter Dunlap 		break;
517*a6d42e7dSPeter Dunlap 	}
518*a6d42e7dSPeter Dunlap }
519*a6d42e7dSPeter Dunlap 
520*a6d42e7dSPeter Dunlap 
521*a6d42e7dSPeter Dunlap static void
522*a6d42e7dSPeter Dunlap sess_sm_q2_active(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
523*a6d42e7dSPeter Dunlap {
524*a6d42e7dSPeter Dunlap 	switch (ctx->se_ctx_event) {
525*a6d42e7dSPeter Dunlap 	case SE_CONN_LOGGED_IN:
526*a6d42e7dSPeter Dunlap 		/* N2 track FFP connections */
527*a6d42e7dSPeter Dunlap 		ist->ist_ffp_conn_count++;
528*a6d42e7dSPeter Dunlap 		sess_sm_new_state(ist, ctx, SS_Q3_LOGGED_IN);
529*a6d42e7dSPeter Dunlap 		break;
530*a6d42e7dSPeter Dunlap 	case SE_CONN_IN_LOGIN:
531*a6d42e7dSPeter Dunlap 		/* N2.1, don't care stay in this state */
532*a6d42e7dSPeter Dunlap 		break;
533*a6d42e7dSPeter Dunlap 	case SE_CONN_FAIL:
534*a6d42e7dSPeter Dunlap 		/* N9 */
535*a6d42e7dSPeter Dunlap 		sess_sm_new_state(ist, ctx, SS_Q7_ERROR);
536*a6d42e7dSPeter Dunlap 		break;
537*a6d42e7dSPeter Dunlap 	case SE_SESSION_REINSTATE:
538*a6d42e7dSPeter Dunlap 		/* N11 */
539*a6d42e7dSPeter Dunlap 		sess_sm_new_state(ist, ctx, SS_Q6_DONE);
540*a6d42e7dSPeter Dunlap 		break;
541*a6d42e7dSPeter Dunlap 	default:
542*a6d42e7dSPeter Dunlap 		ASSERT(0);
543*a6d42e7dSPeter Dunlap 		break;
544*a6d42e7dSPeter Dunlap 	}
545*a6d42e7dSPeter Dunlap }
546*a6d42e7dSPeter Dunlap 
547*a6d42e7dSPeter Dunlap static void
548*a6d42e7dSPeter Dunlap sess_sm_q3_logged_in(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
549*a6d42e7dSPeter Dunlap {
550*a6d42e7dSPeter Dunlap 	iscsit_conn_t *ict;
551*a6d42e7dSPeter Dunlap 
552*a6d42e7dSPeter Dunlap 	switch (ctx->se_ctx_event) {
553*a6d42e7dSPeter Dunlap 	case SE_CONN_IN_LOGIN:
554*a6d42e7dSPeter Dunlap 	case SE_CONN_FAIL:
555*a6d42e7dSPeter Dunlap 		/* N2.2, don't care */
556*a6d42e7dSPeter Dunlap 		break;
557*a6d42e7dSPeter Dunlap 	case SE_CONN_LOGGED_IN:
558*a6d42e7dSPeter Dunlap 		/* N2.2, track FFP connections */
559*a6d42e7dSPeter Dunlap 		ist->ist_ffp_conn_count++;
560*a6d42e7dSPeter Dunlap 		break;
561*a6d42e7dSPeter Dunlap 	case SE_CONN_FFP_FAIL:
562*a6d42e7dSPeter Dunlap 	case SE_CONN_FFP_DISABLE:
563*a6d42e7dSPeter Dunlap 		/*
564*a6d42e7dSPeter Dunlap 		 * Event data from event context is the associated connection
565*a6d42e7dSPeter Dunlap 		 * which in this case happens to be the last FFP connection
566*a6d42e7dSPeter Dunlap 		 * for the session.  In certain cases we need to refer
567*a6d42e7dSPeter Dunlap 		 * to this last valid connection (i.e. RFC3720 section 12.16)
568*a6d42e7dSPeter Dunlap 		 * so we'll save off a pointer here for later use.
569*a6d42e7dSPeter Dunlap 		 */
570*a6d42e7dSPeter Dunlap 		ASSERT(ist->ist_ffp_conn_count >= 1);
571*a6d42e7dSPeter Dunlap 		ist->ist_failed_conn = (iscsit_conn_t *)ctx->se_event_data;
572*a6d42e7dSPeter Dunlap 		ist->ist_ffp_conn_count--;
573*a6d42e7dSPeter Dunlap 		if (ist->ist_ffp_conn_count == 0) {
574*a6d42e7dSPeter Dunlap 			/*
575*a6d42e7dSPeter Dunlap 			 * N5(fail) or N3(disable)
576*a6d42e7dSPeter Dunlap 			 *
577*a6d42e7dSPeter Dunlap 			 * If the event is SE_CONN_FFP_FAIL but we are
578*a6d42e7dSPeter Dunlap 			 * in the midst of an administrative session close
579*a6d42e7dSPeter Dunlap 			 * because of a service or target offline then
580*a6d42e7dSPeter Dunlap 			 * there is no need to go to "failed" state.
581*a6d42e7dSPeter Dunlap 			 */
582*a6d42e7dSPeter Dunlap 			sess_sm_new_state(ist, ctx,
583*a6d42e7dSPeter Dunlap 			    ((ctx->se_ctx_event == SE_CONN_FFP_DISABLE) ||
584*a6d42e7dSPeter Dunlap 			    (ist->ist_admin_close)) ?
585*a6d42e7dSPeter Dunlap 			    SS_Q6_DONE : SS_Q4_FAILED);
586*a6d42e7dSPeter Dunlap 		}
587*a6d42e7dSPeter Dunlap 		break;
588*a6d42e7dSPeter Dunlap 	case SE_SESSION_CLOSE:
589*a6d42e7dSPeter Dunlap 	case SE_SESSION_REINSTATE:
590*a6d42e7dSPeter Dunlap 		/* N3 */
591*a6d42e7dSPeter Dunlap 		mutex_enter(&ist->ist_mutex);
592*a6d42e7dSPeter Dunlap 		if (ctx->se_ctx_event == SE_SESSION_CLOSE) {
593*a6d42e7dSPeter Dunlap 			ASSERT(ist->ist_ffp_conn_count >= 1);
594*a6d42e7dSPeter Dunlap 			ist->ist_ffp_conn_count--;
595*a6d42e7dSPeter Dunlap 		}
596*a6d42e7dSPeter Dunlap 		for (ict = list_head(&ist->ist_conn_list);
597*a6d42e7dSPeter Dunlap 		    ict != NULL;
598*a6d42e7dSPeter Dunlap 		    ict = list_next(&ist->ist_conn_list, ict)) {
599*a6d42e7dSPeter Dunlap 			if ((ctx->se_ctx_event == SE_SESSION_CLOSE) &&
600*a6d42e7dSPeter Dunlap 			    ((iscsit_conn_t *)ctx->se_event_data == ict)) {
601*a6d42e7dSPeter Dunlap 				/*
602*a6d42e7dSPeter Dunlap 				 * Skip this connection since it will
603*a6d42e7dSPeter Dunlap 				 * see the logout response
604*a6d42e7dSPeter Dunlap 				 */
605*a6d42e7dSPeter Dunlap 				continue;
606*a6d42e7dSPeter Dunlap 			}
607*a6d42e7dSPeter Dunlap 			idm_conn_event(ict->ict_ic, CE_LOGOUT_SESSION_SUCCESS,
608*a6d42e7dSPeter Dunlap 			    NULL);
609*a6d42e7dSPeter Dunlap 		}
610*a6d42e7dSPeter Dunlap 		mutex_exit(&ist->ist_mutex);
611*a6d42e7dSPeter Dunlap 
612*a6d42e7dSPeter Dunlap 		sess_sm_new_state(ist, ctx, SS_Q6_DONE);
613*a6d42e7dSPeter Dunlap 		break;
614*a6d42e7dSPeter Dunlap 	default:
615*a6d42e7dSPeter Dunlap 		ASSERT(0);
616*a6d42e7dSPeter Dunlap 		break;
617*a6d42e7dSPeter Dunlap 	}
618*a6d42e7dSPeter Dunlap }
619*a6d42e7dSPeter Dunlap 
620*a6d42e7dSPeter Dunlap static void
621*a6d42e7dSPeter Dunlap sess_sm_timeout(void *arg)
622*a6d42e7dSPeter Dunlap {
623*a6d42e7dSPeter Dunlap 	iscsit_sess_t *ist = arg;
624*a6d42e7dSPeter Dunlap 
625*a6d42e7dSPeter Dunlap 	iscsit_sess_sm_event(ist, SE_SESSION_TIMEOUT, NULL);
626*a6d42e7dSPeter Dunlap }
627*a6d42e7dSPeter Dunlap 
628*a6d42e7dSPeter Dunlap static void
629*a6d42e7dSPeter Dunlap sess_sm_q4_failed(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
630*a6d42e7dSPeter Dunlap {
631*a6d42e7dSPeter Dunlap 	/* Session timer must not be running when we leave this event */
632*a6d42e7dSPeter Dunlap 	switch (ctx->se_ctx_event) {
633*a6d42e7dSPeter Dunlap 	case SE_CONN_IN_LOGIN:
634*a6d42e7dSPeter Dunlap 		/* N7 */
635*a6d42e7dSPeter Dunlap 		sess_sm_new_state(ist, ctx, SS_Q5_CONTINUE);
636*a6d42e7dSPeter Dunlap 		break;
637*a6d42e7dSPeter Dunlap 	case SE_SESSION_REINSTATE:
638*a6d42e7dSPeter Dunlap 		/* N6 */
639*a6d42e7dSPeter Dunlap 		(void) untimeout(ist->ist_state_timeout);
640*a6d42e7dSPeter Dunlap 		/*FALLTHROUGH*/
641*a6d42e7dSPeter Dunlap 	case SE_SESSION_TIMEOUT:
642*a6d42e7dSPeter Dunlap 		/* N6 */
643*a6d42e7dSPeter Dunlap 		sess_sm_new_state(ist, ctx, SS_Q6_DONE);
644*a6d42e7dSPeter Dunlap 		break;
645*a6d42e7dSPeter Dunlap 	case SE_CONN_FAIL:
646*a6d42e7dSPeter Dunlap 		/* Don't care */
647*a6d42e7dSPeter Dunlap 		break;
648*a6d42e7dSPeter Dunlap 	default:
649*a6d42e7dSPeter Dunlap 		ASSERT(0);
650*a6d42e7dSPeter Dunlap 		break;
651*a6d42e7dSPeter Dunlap 	}
652*a6d42e7dSPeter Dunlap }
653*a6d42e7dSPeter Dunlap 
654*a6d42e7dSPeter Dunlap static void
655*a6d42e7dSPeter Dunlap sess_sm_q5_continue(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
656*a6d42e7dSPeter Dunlap {
657*a6d42e7dSPeter Dunlap 	switch (ctx->se_ctx_event) {
658*a6d42e7dSPeter Dunlap 	case SE_CONN_FAIL:
659*a6d42e7dSPeter Dunlap 		/* N5 */
660*a6d42e7dSPeter Dunlap 		sess_sm_new_state(ist, ctx, SS_Q4_FAILED);
661*a6d42e7dSPeter Dunlap 		break;
662*a6d42e7dSPeter Dunlap 	case SE_CONN_LOGGED_IN:
663*a6d42e7dSPeter Dunlap 		/* N10 */
664*a6d42e7dSPeter Dunlap 		sess_sm_new_state(ist, ctx, SS_Q3_LOGGED_IN);
665*a6d42e7dSPeter Dunlap 		break;
666*a6d42e7dSPeter Dunlap 	case SE_SESSION_REINSTATE:
667*a6d42e7dSPeter Dunlap 		/* N11 */
668*a6d42e7dSPeter Dunlap 		sess_sm_new_state(ist, ctx, SS_Q6_DONE);
669*a6d42e7dSPeter Dunlap 		break;
670*a6d42e7dSPeter Dunlap 	default:
671*a6d42e7dSPeter Dunlap 		ASSERT(0);
672*a6d42e7dSPeter Dunlap 		break;
673*a6d42e7dSPeter Dunlap 	}
674*a6d42e7dSPeter Dunlap }
675*a6d42e7dSPeter Dunlap 
676*a6d42e7dSPeter Dunlap static void
677*a6d42e7dSPeter Dunlap sess_sm_q6_done(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
678*a6d42e7dSPeter Dunlap {
679*a6d42e7dSPeter Dunlap 	/* Terminal state */
680*a6d42e7dSPeter Dunlap 	switch (ctx->se_ctx_event) {
681*a6d42e7dSPeter Dunlap 	case SE_CONN_FFP_FAIL:
682*a6d42e7dSPeter Dunlap 	case SE_CONN_FFP_DISABLE:
683*a6d42e7dSPeter Dunlap 		ASSERT(ist->ist_ffp_conn_count >= 1);
684*a6d42e7dSPeter Dunlap 		ist->ist_ffp_conn_count--;
685*a6d42e7dSPeter Dunlap 		break;
686*a6d42e7dSPeter Dunlap 	case SE_CONN_FAIL:
687*a6d42e7dSPeter Dunlap 		if (ist->ist_conn_count == 0) {
688*a6d42e7dSPeter Dunlap 			idm_refcnt_async_wait_ref(&ist->ist_refcnt,
689*a6d42e7dSPeter Dunlap 			    &iscsit_sess_unref);
690*a6d42e7dSPeter Dunlap 		}
691*a6d42e7dSPeter Dunlap 		break;
692*a6d42e7dSPeter Dunlap 	default:
693*a6d42e7dSPeter Dunlap 		break;
694*a6d42e7dSPeter Dunlap 	}
695*a6d42e7dSPeter Dunlap }
696*a6d42e7dSPeter Dunlap 
697*a6d42e7dSPeter Dunlap static void
698*a6d42e7dSPeter Dunlap sess_sm_q7_error(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
699*a6d42e7dSPeter Dunlap {
700*a6d42e7dSPeter Dunlap 	/* Terminal state */
701*a6d42e7dSPeter Dunlap 	switch (ctx->se_ctx_event) {
702*a6d42e7dSPeter Dunlap 	case SE_CONN_FAIL:
703*a6d42e7dSPeter Dunlap 		if (ist->ist_conn_count == 0) {
704*a6d42e7dSPeter Dunlap 			idm_refcnt_async_wait_ref(&ist->ist_refcnt,
705*a6d42e7dSPeter Dunlap 			    &iscsit_sess_unref);
706*a6d42e7dSPeter Dunlap 		}
707*a6d42e7dSPeter Dunlap 		break;
708*a6d42e7dSPeter Dunlap 	default:
709*a6d42e7dSPeter Dunlap 		break;
710*a6d42e7dSPeter Dunlap 	}
711*a6d42e7dSPeter Dunlap }
712*a6d42e7dSPeter Dunlap 
713*a6d42e7dSPeter Dunlap static void
714*a6d42e7dSPeter Dunlap sess_sm_new_state(iscsit_sess_t *ist, sess_event_ctx_t *ctx,
715*a6d42e7dSPeter Dunlap     iscsit_session_state_t new_state)
716*a6d42e7dSPeter Dunlap {
717*a6d42e7dSPeter Dunlap 	int t2r_secs;
718*a6d42e7dSPeter Dunlap 
719*a6d42e7dSPeter Dunlap 	/*
720*a6d42e7dSPeter Dunlap 	 * Validate new state
721*a6d42e7dSPeter Dunlap 	 */
722*a6d42e7dSPeter Dunlap 	ASSERT(new_state != SS_UNDEFINED);
723*a6d42e7dSPeter Dunlap 	ASSERT3U(new_state, <, SS_MAX_STATE);
724*a6d42e7dSPeter Dunlap 
725*a6d42e7dSPeter Dunlap 	new_state = (new_state < SS_MAX_STATE) ?
726*a6d42e7dSPeter Dunlap 	    new_state : SS_UNDEFINED;
727*a6d42e7dSPeter Dunlap 
728*a6d42e7dSPeter Dunlap 	IDM_SM_LOG(CE_NOTE, "sess_sm_new_state: sess %p, evt %s(%d), "
729*a6d42e7dSPeter Dunlap 	    "%s(%d) --> %s(%d)\n", (void *) ist,
730*a6d42e7dSPeter Dunlap 	    iscsit_se_name[ctx->se_ctx_event], ctx->se_ctx_event,
731*a6d42e7dSPeter Dunlap 	    iscsit_ss_name[ist->ist_state], ist->ist_state,
732*a6d42e7dSPeter Dunlap 	    iscsit_ss_name[new_state], new_state);
733*a6d42e7dSPeter Dunlap 
734*a6d42e7dSPeter Dunlap 	DTRACE_PROBE3(sess__state__change,
735*a6d42e7dSPeter Dunlap 	    iscsit_sess_t *, ist, sess_event_ctx_t *, ctx,
736*a6d42e7dSPeter Dunlap 	    iscsit_session_state_t, new_state);
737*a6d42e7dSPeter Dunlap 
738*a6d42e7dSPeter Dunlap 	mutex_enter(&ist->ist_mutex);
739*a6d42e7dSPeter Dunlap 	idm_sm_audit_state_change(&ist->ist_state_audit, SAS_ISCSIT_SESS,
740*a6d42e7dSPeter Dunlap 	    (int)ist->ist_state, (int)new_state);
741*a6d42e7dSPeter Dunlap 	ist->ist_last_state = ist->ist_state;
742*a6d42e7dSPeter Dunlap 	ist->ist_state = new_state;
743*a6d42e7dSPeter Dunlap 	mutex_exit(&ist->ist_mutex);
744*a6d42e7dSPeter Dunlap 
745*a6d42e7dSPeter Dunlap 	switch (ist->ist_state) {
746*a6d42e7dSPeter Dunlap 	case SS_Q1_FREE:
747*a6d42e7dSPeter Dunlap 		break;
748*a6d42e7dSPeter Dunlap 	case SS_Q2_ACTIVE:
749*a6d42e7dSPeter Dunlap 		iscsit_tgt_bind_sess(ist->ist_tgt, ist);
750*a6d42e7dSPeter Dunlap 		break;
751*a6d42e7dSPeter Dunlap 	case SS_Q3_LOGGED_IN:
752*a6d42e7dSPeter Dunlap 		break;
753*a6d42e7dSPeter Dunlap 	case SS_Q4_FAILED:
754*a6d42e7dSPeter Dunlap 		t2r_secs =
755*a6d42e7dSPeter Dunlap 		    ist->ist_failed_conn->ict_op.op_default_time_2_retain;
756*a6d42e7dSPeter Dunlap 		ist->ist_state_timeout = timeout(sess_sm_timeout, ist,
757*a6d42e7dSPeter Dunlap 		    drv_usectohz(t2r_secs*1000000));
758*a6d42e7dSPeter Dunlap 		break;
759*a6d42e7dSPeter Dunlap 	case SS_Q5_CONTINUE:
760*a6d42e7dSPeter Dunlap 		break;
761*a6d42e7dSPeter Dunlap 	case SS_Q6_DONE:
762*a6d42e7dSPeter Dunlap 	case SS_Q7_ERROR:
763*a6d42e7dSPeter Dunlap 		/*
764*a6d42e7dSPeter Dunlap 		 * We won't need our TSIH anymore and it represents an
765*a6d42e7dSPeter Dunlap 		 * implicit reference to the global TSIH pool.  Get rid
766*a6d42e7dSPeter Dunlap 		 * of it.
767*a6d42e7dSPeter Dunlap 		 */
768*a6d42e7dSPeter Dunlap 		if (ist->ist_tsih != ISCSI_UNSPEC_TSIH) {
769*a6d42e7dSPeter Dunlap 			iscsit_tsih_free(ist->ist_tsih);
770*a6d42e7dSPeter Dunlap 		}
771*a6d42e7dSPeter Dunlap 
772*a6d42e7dSPeter Dunlap 		/*
773*a6d42e7dSPeter Dunlap 		 * We don't want this session to show up anymore so unbind
774*a6d42e7dSPeter Dunlap 		 * it now.  After this call this session cannot have any
775*a6d42e7dSPeter Dunlap 		 * references outside itself (implicit or explicit).
776*a6d42e7dSPeter Dunlap 		 */
777*a6d42e7dSPeter Dunlap 		iscsit_tgt_unbind_sess(ist->ist_tgt, ist);
778*a6d42e7dSPeter Dunlap 
779*a6d42e7dSPeter Dunlap 		/*
780*a6d42e7dSPeter Dunlap 		 * If we have more connections bound then more events
781*a6d42e7dSPeter Dunlap 		 * are comming so don't wait for idle yet.
782*a6d42e7dSPeter Dunlap 		 */
783*a6d42e7dSPeter Dunlap 		if (ist->ist_conn_count == 0) {
784*a6d42e7dSPeter Dunlap 			idm_refcnt_async_wait_ref(&ist->ist_refcnt,
785*a6d42e7dSPeter Dunlap 			    &iscsit_sess_unref);
786*a6d42e7dSPeter Dunlap 		}
787*a6d42e7dSPeter Dunlap 		break;
788*a6d42e7dSPeter Dunlap 	default:
789*a6d42e7dSPeter Dunlap 		ASSERT(0);
790*a6d42e7dSPeter Dunlap 		/*NOTREACHED*/
791*a6d42e7dSPeter Dunlap 	}
792*a6d42e7dSPeter Dunlap }
793