1*fcf3ce44SJohn Forte /*
2*fcf3ce44SJohn Forte  * CDDL HEADER START
3*fcf3ce44SJohn Forte  *
4*fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5*fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6*fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7*fcf3ce44SJohn Forte  *
8*fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10*fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11*fcf3ce44SJohn Forte  * and limitations under the License.
12*fcf3ce44SJohn Forte  *
13*fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14*fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16*fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17*fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18*fcf3ce44SJohn Forte  *
19*fcf3ce44SJohn Forte  * CDDL HEADER END
20*fcf3ce44SJohn Forte  */
21*fcf3ce44SJohn Forte /*
22*fcf3ce44SJohn Forte  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*fcf3ce44SJohn Forte  * Use is subject to license terms.
24*fcf3ce44SJohn Forte  *
25*fcf3ce44SJohn Forte  * iSCSI connection interfaces
26*fcf3ce44SJohn Forte  */
27*fcf3ce44SJohn Forte 
28*fcf3ce44SJohn Forte #include "iscsi.h"
29*fcf3ce44SJohn Forte #include "persistent.h"
30*fcf3ce44SJohn Forte 
31*fcf3ce44SJohn Forte /* interface connection interfaces */
32*fcf3ce44SJohn Forte static iscsi_status_t iscsi_conn_state_free(iscsi_conn_t *icp,
33*fcf3ce44SJohn Forte     iscsi_conn_event_t event);
34*fcf3ce44SJohn Forte static void iscsi_conn_state_in_login(iscsi_conn_t *icp,
35*fcf3ce44SJohn Forte     iscsi_conn_event_t event);
36*fcf3ce44SJohn Forte static void iscsi_conn_state_logged_in(iscsi_conn_t *icp,
37*fcf3ce44SJohn Forte     iscsi_conn_event_t event);
38*fcf3ce44SJohn Forte static void iscsi_conn_state_in_logout(iscsi_conn_t *icp,
39*fcf3ce44SJohn Forte     iscsi_conn_event_t event);
40*fcf3ce44SJohn Forte static void iscsi_conn_state_failed(iscsi_conn_t *icp,
41*fcf3ce44SJohn Forte     iscsi_conn_event_t event);
42*fcf3ce44SJohn Forte static void iscsi_conn_state_polling(iscsi_conn_t *icp,
43*fcf3ce44SJohn Forte     iscsi_conn_event_t event);
44*fcf3ce44SJohn Forte static char *iscsi_conn_event_str(iscsi_conn_event_t event);
45*fcf3ce44SJohn Forte static void iscsi_conn_flush_active_cmds(iscsi_conn_t *icp);
46*fcf3ce44SJohn Forte 
47*fcf3ce44SJohn Forte static void iscsi_conn_logged_in(iscsi_sess_t *isp,
48*fcf3ce44SJohn Forte     iscsi_conn_t *icp);
49*fcf3ce44SJohn Forte static void iscsi_conn_retry(iscsi_sess_t *isp,
50*fcf3ce44SJohn Forte     iscsi_conn_t *icp);
51*fcf3ce44SJohn Forte 
52*fcf3ce44SJohn Forte #define	SHUTDOWN_TIMEOUT	180 /* seconds */
53*fcf3ce44SJohn Forte 
54*fcf3ce44SJohn Forte /*
55*fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
56*fcf3ce44SJohn Forte  * | External Connection Interfaces					|
57*fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
58*fcf3ce44SJohn Forte  */
59*fcf3ce44SJohn Forte 
60*fcf3ce44SJohn Forte /*
61*fcf3ce44SJohn Forte  * iscsi_conn_create - This creates an iscsi connection structure and
62*fcf3ce44SJohn Forte  * associates it with a session structure.  The session's sess_conn_list_rwlock
63*fcf3ce44SJohn Forte  * should be held as a writer before calling this function.
64*fcf3ce44SJohn Forte  */
65*fcf3ce44SJohn Forte iscsi_status_t
66*fcf3ce44SJohn Forte iscsi_conn_create(struct sockaddr *addr, iscsi_sess_t *isp, iscsi_conn_t **icpp)
67*fcf3ce44SJohn Forte {
68*fcf3ce44SJohn Forte 	iscsi_conn_t	*icp	= NULL;
69*fcf3ce44SJohn Forte 	char		th_name[ISCSI_TH_MAX_NAME_LEN];
70*fcf3ce44SJohn Forte 
71*fcf3ce44SJohn Forte 	/* See if this connection already exists */
72*fcf3ce44SJohn Forte 	for (icp = isp->sess_conn_list; icp; icp = icp->conn_next) {
73*fcf3ce44SJohn Forte 
74*fcf3ce44SJohn Forte 		/*
75*fcf3ce44SJohn Forte 		 * Compare the ioctl information to see if
76*fcf3ce44SJohn Forte 		 * its a match for this connection.  (This
77*fcf3ce44SJohn Forte 		 * is done by making sure the IPs are of
78*fcf3ce44SJohn Forte 		 * the same size and then they are the
79*fcf3ce44SJohn Forte 		 * same value.
80*fcf3ce44SJohn Forte 		 */
81*fcf3ce44SJohn Forte 		if (bcmp(&icp->conn_base_addr, addr,
82*fcf3ce44SJohn Forte 		    SIZEOF_SOCKADDR(addr)) == 0) {
83*fcf3ce44SJohn Forte 			/* It's a match, record this connection */
84*fcf3ce44SJohn Forte 			break;
85*fcf3ce44SJohn Forte 		}
86*fcf3ce44SJohn Forte 	}
87*fcf3ce44SJohn Forte 
88*fcf3ce44SJohn Forte 	/* If icp is found return it */
89*fcf3ce44SJohn Forte 	if (icp != NULL) {
90*fcf3ce44SJohn Forte 		*icpp = icp;
91*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SUCCESS);
92*fcf3ce44SJohn Forte 	}
93*fcf3ce44SJohn Forte 
94*fcf3ce44SJohn Forte 	/* We are creating the connection, allocate, and setup */
95*fcf3ce44SJohn Forte 	icp = (iscsi_conn_t *)kmem_zalloc(sizeof (iscsi_conn_t), KM_SLEEP);
96*fcf3ce44SJohn Forte 
97*fcf3ce44SJohn Forte 	/*
98*fcf3ce44SJohn Forte 	 * Setup connection
99*fcf3ce44SJohn Forte 	 */
100*fcf3ce44SJohn Forte 	icp->conn_sig			= ISCSI_SIG_CONN;
101*fcf3ce44SJohn Forte 	icp->conn_state			= ISCSI_CONN_STATE_FREE;
102*fcf3ce44SJohn Forte 	mutex_init(&icp->conn_state_mutex, NULL, MUTEX_DRIVER, NULL);
103*fcf3ce44SJohn Forte 	cv_init(&icp->conn_state_change, NULL, CV_DRIVER, NULL);
104*fcf3ce44SJohn Forte 	icp->conn_state_destroy		= B_FALSE;
105*fcf3ce44SJohn Forte 	icp->conn_sess			= isp;
106*fcf3ce44SJohn Forte 	icp->conn_state_lbolt		= ddi_get_lbolt();
107*fcf3ce44SJohn Forte 
108*fcf3ce44SJohn Forte 	mutex_enter(&iscsi_oid_mutex);
109*fcf3ce44SJohn Forte 	icp->conn_oid = iscsi_oid++;
110*fcf3ce44SJohn Forte 	mutex_exit(&iscsi_oid_mutex);
111*fcf3ce44SJohn Forte 
112*fcf3ce44SJohn Forte 	/* Creation of the receive thread */
113*fcf3ce44SJohn Forte 	if (snprintf(th_name, sizeof (th_name) - 1, ISCSI_CONN_RXTH_NAME_FORMAT,
114*fcf3ce44SJohn Forte 	    icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid,
115*fcf3ce44SJohn Forte 	    icp->conn_oid) >= sizeof (th_name)) {
116*fcf3ce44SJohn Forte 		cv_destroy(&icp->conn_state_change);
117*fcf3ce44SJohn Forte 		mutex_destroy(&icp->conn_state_mutex);
118*fcf3ce44SJohn Forte 		kmem_free(icp, sizeof (iscsi_conn_t));
119*fcf3ce44SJohn Forte 		*icpp = NULL;
120*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
121*fcf3ce44SJohn Forte 	}
122*fcf3ce44SJohn Forte 
123*fcf3ce44SJohn Forte 	icp->conn_rx_thread = iscsi_thread_create(isp->sess_hba->hba_dip,
124*fcf3ce44SJohn Forte 	    th_name, iscsi_rx_thread, icp);
125*fcf3ce44SJohn Forte 
126*fcf3ce44SJohn Forte 	/* Creation of the transfer thread */
127*fcf3ce44SJohn Forte 	if (snprintf(th_name, sizeof (th_name) - 1, ISCSI_CONN_TXTH_NAME_FORMAT,
128*fcf3ce44SJohn Forte 	    icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid,
129*fcf3ce44SJohn Forte 	    icp->conn_oid) >= sizeof (th_name)) {
130*fcf3ce44SJohn Forte 		iscsi_thread_destroy(icp->conn_rx_thread);
131*fcf3ce44SJohn Forte 		cv_destroy(&icp->conn_state_change);
132*fcf3ce44SJohn Forte 		mutex_destroy(&icp->conn_state_mutex);
133*fcf3ce44SJohn Forte 		kmem_free(icp, sizeof (iscsi_conn_t));
134*fcf3ce44SJohn Forte 		*icpp = NULL;
135*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
136*fcf3ce44SJohn Forte 	}
137*fcf3ce44SJohn Forte 
138*fcf3ce44SJohn Forte 	icp->conn_tx_thread = iscsi_thread_create(isp->sess_hba->hba_dip,
139*fcf3ce44SJohn Forte 	    th_name, iscsi_tx_thread, icp);
140*fcf3ce44SJohn Forte 
141*fcf3ce44SJohn Forte 	/* setup connection queues */
142*fcf3ce44SJohn Forte 	iscsi_init_queue(&icp->conn_queue_active);
143*fcf3ce44SJohn Forte 
144*fcf3ce44SJohn Forte 	bcopy(addr, &icp->conn_base_addr, sizeof (icp->conn_base_addr));
145*fcf3ce44SJohn Forte 
146*fcf3ce44SJohn Forte 	/* Add new connection to the session connection list */
147*fcf3ce44SJohn Forte 	icp->conn_cid = isp->sess_conn_next_cid++;
148*fcf3ce44SJohn Forte 	if (isp->sess_conn_list == NULL) {
149*fcf3ce44SJohn Forte 		isp->sess_conn_list = isp->sess_conn_list_last_ptr = icp;
150*fcf3ce44SJohn Forte 	} else {
151*fcf3ce44SJohn Forte 		isp->sess_conn_list_last_ptr->conn_next = icp;
152*fcf3ce44SJohn Forte 		isp->sess_conn_list_last_ptr = icp;
153*fcf3ce44SJohn Forte 	}
154*fcf3ce44SJohn Forte 
155*fcf3ce44SJohn Forte 	KSTAT_INC_SESS_CNTR_CONN(isp);
156*fcf3ce44SJohn Forte 	(void) iscsi_conn_kstat_init(icp);
157*fcf3ce44SJohn Forte 
158*fcf3ce44SJohn Forte 	*icpp = icp;
159*fcf3ce44SJohn Forte 
160*fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
161*fcf3ce44SJohn Forte }
162*fcf3ce44SJohn Forte 
163*fcf3ce44SJohn Forte 
164*fcf3ce44SJohn Forte /*
165*fcf3ce44SJohn Forte  * iscsi_conn_offline - This attempts to take a connection from
166*fcf3ce44SJohn Forte  * any state to ISCSI_CONN_STATE_FREE.
167*fcf3ce44SJohn Forte  */
168*fcf3ce44SJohn Forte iscsi_status_t
169*fcf3ce44SJohn Forte iscsi_conn_offline(iscsi_conn_t *icp)
170*fcf3ce44SJohn Forte {
171*fcf3ce44SJohn Forte 	clock_t		delay;
172*fcf3ce44SJohn Forte 
173*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
174*fcf3ce44SJohn Forte 
175*fcf3ce44SJohn Forte 	/*
176*fcf3ce44SJohn Forte 	 * We can only destroy a connection if its either in
177*fcf3ce44SJohn Forte 	 * a state of FREE or LOGGED.  The other states are
178*fcf3ce44SJohn Forte 	 * transitionary and its unsafe to perform actions
179*fcf3ce44SJohn Forte 	 * on the connection in those states.  Set a flag
180*fcf3ce44SJohn Forte 	 * on the connection to influence the transitions
181*fcf3ce44SJohn Forte 	 * to quickly complete.  Then wait for a state
182*fcf3ce44SJohn Forte 	 * transition.
183*fcf3ce44SJohn Forte 	 */
184*fcf3ce44SJohn Forte 	delay = ddi_get_lbolt() + SEC_TO_TICK(SHUTDOWN_TIMEOUT);
185*fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_state_mutex);
186*fcf3ce44SJohn Forte 	icp->conn_state_destroy = B_TRUE;
187*fcf3ce44SJohn Forte 	while ((icp->conn_state != ISCSI_CONN_STATE_FREE) &&
188*fcf3ce44SJohn Forte 	    (icp->conn_state != ISCSI_CONN_STATE_LOGGED_IN) &&
189*fcf3ce44SJohn Forte 	    (ddi_get_lbolt() < delay)) {
190*fcf3ce44SJohn Forte 		/* wait for transition */
191*fcf3ce44SJohn Forte 		(void) cv_timedwait(&icp->conn_state_change,
192*fcf3ce44SJohn Forte 		    &icp->conn_state_mutex, delay);
193*fcf3ce44SJohn Forte 	}
194*fcf3ce44SJohn Forte 
195*fcf3ce44SJohn Forte 	/* Final check whether we can destroy the connection */
196*fcf3ce44SJohn Forte 	switch (icp->conn_state) {
197*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_FREE:
198*fcf3ce44SJohn Forte 		/* Easy case - Connection is dead */
199*fcf3ce44SJohn Forte 		break;
200*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_LOGGED_IN:
201*fcf3ce44SJohn Forte 		/* Hard case - Force connection logout */
202*fcf3ce44SJohn Forte 		(void) iscsi_conn_state_machine(icp,
203*fcf3ce44SJohn Forte 		    ISCSI_CONN_EVENT_T9);
204*fcf3ce44SJohn Forte 		break;
205*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_IN_LOGIN:
206*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_IN_LOGOUT:
207*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_FAILED:
208*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_POLLING:
209*fcf3ce44SJohn Forte 	default:
210*fcf3ce44SJohn Forte 		/* All other cases fail the destroy */
211*fcf3ce44SJohn Forte 		icp->conn_state_destroy = B_FALSE;
212*fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
213*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
214*fcf3ce44SJohn Forte 	}
215*fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_state_mutex);
216*fcf3ce44SJohn Forte 
217*fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
218*fcf3ce44SJohn Forte }
219*fcf3ce44SJohn Forte 
220*fcf3ce44SJohn Forte /*
221*fcf3ce44SJohn Forte  * iscsi_conn_destroy - This destroys an iscsi connection structure
222*fcf3ce44SJohn Forte  * and de-associates it with the session.  The connection should
223*fcf3ce44SJohn Forte  * already been in the ISCSI_CONN_STATE_FREE when attempting this
224*fcf3ce44SJohn Forte  * operation.
225*fcf3ce44SJohn Forte  */
226*fcf3ce44SJohn Forte iscsi_status_t
227*fcf3ce44SJohn Forte iscsi_conn_destroy(iscsi_conn_t *icp)
228*fcf3ce44SJohn Forte {
229*fcf3ce44SJohn Forte 	iscsi_sess_t	*isp;
230*fcf3ce44SJohn Forte 	iscsi_conn_t	*t_icp;
231*fcf3ce44SJohn Forte 
232*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
233*fcf3ce44SJohn Forte 	isp = icp->conn_sess;
234*fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
235*fcf3ce44SJohn Forte 
236*fcf3ce44SJohn Forte 	if (icp->conn_state != ISCSI_CONN_STATE_FREE) {
237*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
238*fcf3ce44SJohn Forte 	}
239*fcf3ce44SJohn Forte 
240*fcf3ce44SJohn Forte 	/* Destroy receive thread */
241*fcf3ce44SJohn Forte 	iscsi_thread_destroy(icp->conn_rx_thread);
242*fcf3ce44SJohn Forte 
243*fcf3ce44SJohn Forte 	/* Destroy transfer thread */
244*fcf3ce44SJohn Forte 	iscsi_thread_destroy(icp->conn_tx_thread);
245*fcf3ce44SJohn Forte 
246*fcf3ce44SJohn Forte 	/* Terminate connection queues */
247*fcf3ce44SJohn Forte 	iscsi_destroy_queue(&icp->conn_queue_active);
248*fcf3ce44SJohn Forte 
249*fcf3ce44SJohn Forte 	cv_destroy(&icp->conn_state_change);
250*fcf3ce44SJohn Forte 	mutex_destroy(&icp->conn_state_mutex);
251*fcf3ce44SJohn Forte 
252*fcf3ce44SJohn Forte 	/*
253*fcf3ce44SJohn Forte 	 * Remove connection from sessions linked list.
254*fcf3ce44SJohn Forte 	 */
255*fcf3ce44SJohn Forte 	if (isp->sess_conn_list == icp) {
256*fcf3ce44SJohn Forte 		/* connection first item in list */
257*fcf3ce44SJohn Forte 		isp->sess_conn_list = icp->conn_next;
258*fcf3ce44SJohn Forte 		/*
259*fcf3ce44SJohn Forte 		 * check if this is also the last item in the list
260*fcf3ce44SJohn Forte 		 */
261*fcf3ce44SJohn Forte 		if (isp->sess_conn_list_last_ptr == icp) {
262*fcf3ce44SJohn Forte 			isp->sess_conn_list_last_ptr = NULL;
263*fcf3ce44SJohn Forte 		}
264*fcf3ce44SJohn Forte 	} else {
265*fcf3ce44SJohn Forte 		/*
266*fcf3ce44SJohn Forte 		 * search session list for icp pointing
267*fcf3ce44SJohn Forte 		 * to connection being removed.  Then
268*fcf3ce44SJohn Forte 		 * update that connections next pointer.
269*fcf3ce44SJohn Forte 		 */
270*fcf3ce44SJohn Forte 		t_icp = isp->sess_conn_list;
271*fcf3ce44SJohn Forte 		while (t_icp->conn_next != NULL) {
272*fcf3ce44SJohn Forte 			if (t_icp->conn_next == icp) {
273*fcf3ce44SJohn Forte 				break;
274*fcf3ce44SJohn Forte 			}
275*fcf3ce44SJohn Forte 			t_icp = t_icp->conn_next;
276*fcf3ce44SJohn Forte 		}
277*fcf3ce44SJohn Forte 		if (t_icp->conn_next == icp) {
278*fcf3ce44SJohn Forte 			t_icp->conn_next = icp->conn_next;
279*fcf3ce44SJohn Forte 			/*
280*fcf3ce44SJohn Forte 			 * if this is the last connection in the list
281*fcf3ce44SJohn Forte 			 * update the last_ptr to point to t_icp
282*fcf3ce44SJohn Forte 			 */
283*fcf3ce44SJohn Forte 			if (isp->sess_conn_list_last_ptr == icp) {
284*fcf3ce44SJohn Forte 				isp->sess_conn_list_last_ptr = t_icp;
285*fcf3ce44SJohn Forte 			}
286*fcf3ce44SJohn Forte 		} else {
287*fcf3ce44SJohn Forte 			/* couldn't find session */
288*fcf3ce44SJohn Forte 			ASSERT(FALSE);
289*fcf3ce44SJohn Forte 		}
290*fcf3ce44SJohn Forte 	}
291*fcf3ce44SJohn Forte 
292*fcf3ce44SJohn Forte 	/* Free this Connections Data */
293*fcf3ce44SJohn Forte 	iscsi_conn_kstat_term(icp);
294*fcf3ce44SJohn Forte 	kmem_free(icp, sizeof (iscsi_conn_t));
295*fcf3ce44SJohn Forte 
296*fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
297*fcf3ce44SJohn Forte }
298*fcf3ce44SJohn Forte 
299*fcf3ce44SJohn Forte 
300*fcf3ce44SJohn Forte /*
301*fcf3ce44SJohn Forte  * iscsi_conn_set_login_min_max - set min/max login window
302*fcf3ce44SJohn Forte  *
303*fcf3ce44SJohn Forte  * Used to set the min and max login window.  Input values
304*fcf3ce44SJohn Forte  * are in seconds.
305*fcf3ce44SJohn Forte  */
306*fcf3ce44SJohn Forte void
307*fcf3ce44SJohn Forte iscsi_conn_set_login_min_max(iscsi_conn_t *icp, int min, int max)
308*fcf3ce44SJohn Forte {
309*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
310*fcf3ce44SJohn Forte 
311*fcf3ce44SJohn Forte 	icp->conn_login_min = ddi_get_lbolt() + SEC_TO_TICK(min);
312*fcf3ce44SJohn Forte 	icp->conn_login_max = ddi_get_lbolt() + SEC_TO_TICK(max);
313*fcf3ce44SJohn Forte }
314*fcf3ce44SJohn Forte 
315*fcf3ce44SJohn Forte 
316*fcf3ce44SJohn Forte 
317*fcf3ce44SJohn Forte /*
318*fcf3ce44SJohn Forte  * iscsi_conn_state_machine - This function is used to drive the
319*fcf3ce44SJohn Forte  * state machine of the iscsi connection.  It takes in a connection
320*fcf3ce44SJohn Forte  * and the associated event effecting the connection.
321*fcf3ce44SJohn Forte  *
322*fcf3ce44SJohn Forte  * 7.1.3  Connection State Diagram for an Initiator
323*fcf3ce44SJohn Forte  *      Symbolic Names for States:
324*fcf3ce44SJohn Forte  *      S1: FREE        - State on instantiation, or after successful
325*fcf3ce44SJohn Forte  *                        connection closure.
326*fcf3ce44SJohn Forte  *      S2: IN_LOGIN    - Waiting for login process to conclude,
327*fcf3ce44SJohn Forte  *                        possibly involving several PDU exchanges.
328*fcf3ce44SJohn Forte  *      S3: LOGGED_IN   - In Full Feature Phase, waiting for all internal,
329*fcf3ce44SJohn Forte  *                        iSCSI, and transport events
330*fcf3ce44SJohn Forte  *      S4: IN_LOGOUT   - Waiting for the Logout repsonse.
331*fcf3ce44SJohn Forte  *      S5: FAILED      - The connection has failed.  Attempting
332*fcf3ce44SJohn Forte  *			  to reconnect.
333*fcf3ce44SJohn Forte  *      S6: POLLING     - The connection reconnect attempts have
334*fcf3ce44SJohn Forte  *                        failed.  Continue to poll at a lower
335*fcf3ce44SJohn Forte  *                        frequency.
336*fcf3ce44SJohn Forte  *
337*fcf3ce44SJohn Forte  *      States S3, S4 constitute the Full Feature Phase
338*fcf3ce44SJohn Forte  *              of the connection.
339*fcf3ce44SJohn Forte  *
340*fcf3ce44SJohn Forte  *      The state diagram is as follows:
341*fcf3ce44SJohn Forte  *                 -------
342*fcf3ce44SJohn Forte  *      +-------->/ S1    \<------------------------------+
343*fcf3ce44SJohn Forte  *      |      +->\       /<---+            /---\         |
344*fcf3ce44SJohn Forte  *      |     /    ---+---     |T7/30     T7|   |         |
345*fcf3ce44SJohn Forte  *      |    +        |        |            \->------     |
346*fcf3ce44SJohn Forte  *      |  T8|        |T1     /      T5       / S6   \--->|
347*fcf3ce44SJohn Forte  *      |    |        |      /     +----------\      /T30 |
348*fcf3ce44SJohn Forte  *      |    |        V     /     /            ------     |
349*fcf3ce44SJohn Forte  *      |    |     ------- /     /               ^        |
350*fcf3ce44SJohn Forte  *      |    |    / S2    \     /   T5           |T7      |
351*fcf3ce44SJohn Forte  *      |    |    \       /    +-------------- --+---     |
352*fcf3ce44SJohn Forte  *      |    |     ---+---    /               / S5   \--->|
353*fcf3ce44SJohn Forte  *      |    |        |      /      T14/T15   \      /T30 |
354*fcf3ce44SJohn Forte  *      |    |        |T5   /  +-------------> ------     |
355*fcf3ce44SJohn Forte  *      |    |        |    /  /                           |
356*fcf3ce44SJohn Forte  *      |    |        |   /  /         T11                |
357*fcf3ce44SJohn Forte  *      |    |        |  /  /         +----+              |
358*fcf3ce44SJohn Forte  *      |    |        V V  /          |    |              |
359*fcf3ce44SJohn Forte  *      |    |      ------+       ----+--  |              |
360*fcf3ce44SJohn Forte  *      |    +-----/ S3    \T9/11/ S4    \<+              |
361*fcf3ce44SJohn Forte  *      +----------\       /---->\       /----------------+
362*fcf3ce44SJohn Forte  *                  -------       -------        T15/T17
363*fcf3ce44SJohn Forte  *
364*fcf3ce44SJohn Forte  * The state transition table is as follows:
365*fcf3ce44SJohn Forte  *
366*fcf3ce44SJohn Forte  *         +-----+---+---+------+------+---+
367*fcf3ce44SJohn Forte  *         |S1   |S2 |S3 |S4    |S5    |S6 |
368*fcf3ce44SJohn Forte  *      ---+-----+---+---+------+------+---+
369*fcf3ce44SJohn Forte  *       S1|T1   |T1 | - | -    | -    |   |
370*fcf3ce44SJohn Forte  *      ---+-----+---+---+------+------+---+
371*fcf3ce44SJohn Forte  *       S2|T7/30|-  |T5 | -    | -    |   |
372*fcf3ce44SJohn Forte  *      ---+-----+---+---+------+------+---+
373*fcf3ce44SJohn Forte  *       S3|T8   |-  | - |T9/11 |T14/15|   |
374*fcf3ce44SJohn Forte  *      ---+-----+---+---+------+------+---+
375*fcf3ce44SJohn Forte  *       S4|     |-  | - |T11   |T15/17|   |
376*fcf3ce44SJohn Forte  *      ---+-----+---+---+------+------+---+
377*fcf3ce44SJohn Forte  *       S5|T30  |   |T5 |      |      |T7 |
378*fcf3ce44SJohn Forte  *      ---+-----+---+---+------+------+---+
379*fcf3ce44SJohn Forte  *       S6|T30  |   |T5 |      |      |T7 |
380*fcf3ce44SJohn Forte  *      ---+-----+---+---+------+------+---+
381*fcf3ce44SJohn Forte  *
382*fcf3ce44SJohn Forte  * Events definitions:
383*fcf3ce44SJohn Forte  *
384*fcf3ce44SJohn Forte  * -T1: Transport connection request was made (e.g., TCP SYN sent).
385*fcf3ce44SJohn Forte  * -T5: The final iSCSI Login response with a Status-Class of zero was
386*fcf3ce44SJohn Forte  *      received.
387*fcf3ce44SJohn Forte  * -T7: One of the following events caused the transition:
388*fcf3ce44SJohn Forte  *      - Login timed out.
389*fcf3ce44SJohn Forte  *      - A transport disconnect indication was received.
390*fcf3ce44SJohn Forte  *      - A transport reset was received.
391*fcf3ce44SJohn Forte  *      - An internal event indicating a transport timeout was
392*fcf3ce44SJohn Forte  *        received.
393*fcf3ce44SJohn Forte  *      - An internal event of receiving a Logout repsonse (success)
394*fcf3ce44SJohn Forte  *        on another connection for a "close the session" Logout
395*fcf3ce44SJohn Forte  *        request was received.
396*fcf3ce44SJohn Forte  *      * In all these cases, the transport connection is closed.
397*fcf3ce44SJohn Forte  * -T8: An internal event of receiving a Logout response (success)
398*fcf3ce44SJohn Forte  *      on another connection for a "close the session" Logout request
399*fcf3ce44SJohn Forte  *      was received, thus closing this connection requiring no further
400*fcf3ce44SJohn Forte  *      cleanup.
401*fcf3ce44SJohn Forte  * -T9: An internal event that indicates the readiness to start the
402*fcf3ce44SJohn Forte  *      Logout process was received, thus prompting an iSCSI Logout to
403*fcf3ce44SJohn Forte  *      be sent by the initiator.
404*fcf3ce44SJohn Forte  * -T11: Async PDU with AsyncEvent "Request Logout" was received.
405*fcf3ce44SJohn Forte  * -T13: An iSCSI Logout response (success) was received, or an internal
406*fcf3ce44SJohn Forte  *      event of receiving a Logout response (success) on another
407*fcf3ce44SJohn Forte  *      connection was received.
408*fcf3ce44SJohn Forte  * -T14: One or more of the following events case this transition:
409*fcf3ce44SJohn Forte  *	- Header Digest Error
410*fcf3ce44SJohn Forte  *	- Protocol Error
411*fcf3ce44SJohn Forte  * -T15: One or more of the following events caused this transition:
412*fcf3ce44SJohn Forte  *      - Internal event that indicates a transport connection timeout
413*fcf3ce44SJohn Forte  *        was received thus prompting transport RESET or transport
414*fcf3ce44SJohn Forte  *        connection closure.
415*fcf3ce44SJohn Forte  *      - A transport RESET
416*fcf3ce44SJohn Forte  *      - A transport disconnect indication.
417*fcf3ce44SJohn Forte  *      - Async PDU with AsyncEvent "Drop connection" (for this CID)
418*fcf3ce44SJohn Forte  *      - Async PDU with AsyncEvent "Drop all connections"
419*fcf3ce44SJohn Forte  * -T17: One or more of the following events caused this transition:
420*fcf3ce44SJohn Forte  *      - Logout response, (failure i.e., a non-zero status) was
421*fcf3ce44SJohn Forte  *      received, or Logout timed out.
422*fcf3ce44SJohn Forte  *      - Any of the events specified for T15.
423*fcf3ce44SJohn Forte  * -T30: One of the following event caused the transition:
424*fcf3ce44SJohn Forte  *	- Thefinal iSCSI Login response was received with a non-zero
425*fcf3ce44SJohn Forte  *	  Status-Class.
426*fcf3ce44SJohn Forte  */
427*fcf3ce44SJohn Forte iscsi_status_t
428*fcf3ce44SJohn Forte iscsi_conn_state_machine(iscsi_conn_t *icp, iscsi_conn_event_t event)
429*fcf3ce44SJohn Forte {
430*fcf3ce44SJohn Forte 	iscsi_status_t	    status = ISCSI_STATUS_SUCCESS;
431*fcf3ce44SJohn Forte 
432*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
433*fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&icp->conn_state_mutex));
434*fcf3ce44SJohn Forte 
435*fcf3ce44SJohn Forte 	DTRACE_PROBE3(event, iscsi_conn_t *, icp,
436*fcf3ce44SJohn Forte 	    char *, iscsi_conn_state_str(icp->conn_state),
437*fcf3ce44SJohn Forte 	    char *, iscsi_conn_event_str(event));
438*fcf3ce44SJohn Forte 
439*fcf3ce44SJohn Forte 	icp->conn_prev_state = icp->conn_state;
440*fcf3ce44SJohn Forte 	icp->conn_state_lbolt = ddi_get_lbolt();
441*fcf3ce44SJohn Forte 
442*fcf3ce44SJohn Forte 	switch (icp->conn_state) {
443*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_FREE:
444*fcf3ce44SJohn Forte 		status = iscsi_conn_state_free(icp, event);
445*fcf3ce44SJohn Forte 		break;
446*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_IN_LOGIN:
447*fcf3ce44SJohn Forte 		iscsi_conn_state_in_login(icp, event);
448*fcf3ce44SJohn Forte 		break;
449*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_LOGGED_IN:
450*fcf3ce44SJohn Forte 		iscsi_conn_state_logged_in(icp, event);
451*fcf3ce44SJohn Forte 		break;
452*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_IN_LOGOUT:
453*fcf3ce44SJohn Forte 		iscsi_conn_state_in_logout(icp, event);
454*fcf3ce44SJohn Forte 		break;
455*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_FAILED:
456*fcf3ce44SJohn Forte 		iscsi_conn_state_failed(icp, event);
457*fcf3ce44SJohn Forte 		break;
458*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_POLLING:
459*fcf3ce44SJohn Forte 		iscsi_conn_state_polling(icp, event);
460*fcf3ce44SJohn Forte 		break;
461*fcf3ce44SJohn Forte 	default:
462*fcf3ce44SJohn Forte 		ASSERT(FALSE);
463*fcf3ce44SJohn Forte 		status = ISCSI_STATUS_INTERNAL_ERROR;
464*fcf3ce44SJohn Forte 	}
465*fcf3ce44SJohn Forte 
466*fcf3ce44SJohn Forte 	cv_broadcast(&icp->conn_state_change);
467*fcf3ce44SJohn Forte 	return (status);
468*fcf3ce44SJohn Forte }
469*fcf3ce44SJohn Forte 
470*fcf3ce44SJohn Forte 
471*fcf3ce44SJohn Forte /*
472*fcf3ce44SJohn Forte  * iscsi_conn_state_str - converts state enum to a string
473*fcf3ce44SJohn Forte  */
474*fcf3ce44SJohn Forte char *
475*fcf3ce44SJohn Forte iscsi_conn_state_str(iscsi_conn_state_t state)
476*fcf3ce44SJohn Forte {
477*fcf3ce44SJohn Forte 	switch (state) {
478*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_FREE:
479*fcf3ce44SJohn Forte 		return ("free");
480*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_IN_LOGIN:
481*fcf3ce44SJohn Forte 		return ("in_login");
482*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_LOGGED_IN:
483*fcf3ce44SJohn Forte 		return ("logged_in");
484*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_IN_LOGOUT:
485*fcf3ce44SJohn Forte 		return ("in_logout");
486*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_FAILED:
487*fcf3ce44SJohn Forte 		return ("failed");
488*fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_POLLING:
489*fcf3ce44SJohn Forte 		return ("polling");
490*fcf3ce44SJohn Forte 	default:
491*fcf3ce44SJohn Forte 		return ("unknown");
492*fcf3ce44SJohn Forte 	}
493*fcf3ce44SJohn Forte }
494*fcf3ce44SJohn Forte 
495*fcf3ce44SJohn Forte 
496*fcf3ce44SJohn Forte /*
497*fcf3ce44SJohn Forte  * iscsi_conn_sync_params - used to update connection parameters
498*fcf3ce44SJohn Forte  *
499*fcf3ce44SJohn Forte  * Used to update connection parameters with current configured
500*fcf3ce44SJohn Forte  * parameters in the persistent store.  This should be called
501*fcf3ce44SJohn Forte  * before starting to make a new iscsi connection in iscsi_login.
502*fcf3ce44SJohn Forte  */
503*fcf3ce44SJohn Forte iscsi_status_t
504*fcf3ce44SJohn Forte iscsi_conn_sync_params(iscsi_conn_t *icp)
505*fcf3ce44SJohn Forte {
506*fcf3ce44SJohn Forte 	iscsi_sess_t		*isp;
507*fcf3ce44SJohn Forte 	iscsi_hba_t		*ihp;
508*fcf3ce44SJohn Forte 	int			param_id;
509*fcf3ce44SJohn Forte 	persistent_param_t	pp;
510*fcf3ce44SJohn Forte 	iscsi_config_sess_t	*ics;
511*fcf3ce44SJohn Forte 	int			idx, size;
512*fcf3ce44SJohn Forte 	char			*name;
513*fcf3ce44SJohn Forte 
514*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
515*fcf3ce44SJohn Forte 	ASSERT((icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN) ||
516*fcf3ce44SJohn Forte 	    (icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
517*fcf3ce44SJohn Forte 	    (icp->conn_state == ISCSI_CONN_STATE_POLLING));
518*fcf3ce44SJohn Forte 	isp = icp->conn_sess;
519*fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
520*fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
521*fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
522*fcf3ce44SJohn Forte 
523*fcf3ce44SJohn Forte 	/*
524*fcf3ce44SJohn Forte 	 * Check if someone is trying to destroy this
525*fcf3ce44SJohn Forte 	 * connection.  If so fail the sync request,
526*fcf3ce44SJohn Forte 	 * as a method of fast fail.
527*fcf3ce44SJohn Forte 	 */
528*fcf3ce44SJohn Forte 	if (icp->conn_state_destroy == B_TRUE) {
529*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SHUTDOWN);
530*fcf3ce44SJohn Forte 	}
531*fcf3ce44SJohn Forte 
532*fcf3ce44SJohn Forte 	bzero(&pp, sizeof (pp));
533*fcf3ce44SJohn Forte 
534*fcf3ce44SJohn Forte 	/* First get a copy of the HBA params */
535*fcf3ce44SJohn Forte 	bcopy(&ihp->hba_params, &icp->conn_params,
536*fcf3ce44SJohn Forte 	    sizeof (iscsi_login_params_t));
537*fcf3ce44SJohn Forte 
538*fcf3ce44SJohn Forte 	/*
539*fcf3ce44SJohn Forte 	 * Now we need to get the session configured
540*fcf3ce44SJohn Forte 	 * values from the persistent store and apply
541*fcf3ce44SJohn Forte 	 * them to our connection.
542*fcf3ce44SJohn Forte 	 */
543*fcf3ce44SJohn Forte 	(void) persistent_param_get((char *)isp->sess_name, &pp);
544*fcf3ce44SJohn Forte 	for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM;
545*fcf3ce44SJohn Forte 	    param_id++) {
546*fcf3ce44SJohn Forte 		if (pp.p_bitmap & (1 << param_id)) {
547*fcf3ce44SJohn Forte 
548*fcf3ce44SJohn Forte 			switch (param_id) {
549*fcf3ce44SJohn Forte 			/*
550*fcf3ce44SJohn Forte 			 * Boolean parameters
551*fcf3ce44SJohn Forte 			 */
552*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER:
553*fcf3ce44SJohn Forte 				icp->conn_params.data_pdu_in_order =
554*fcf3ce44SJohn Forte 				    pp.p_params.data_pdu_in_order;
555*fcf3ce44SJohn Forte 				break;
556*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA:
557*fcf3ce44SJohn Forte 				icp->conn_params.immediate_data =
558*fcf3ce44SJohn Forte 				    pp.p_params.immediate_data;
559*fcf3ce44SJohn Forte 				break;
560*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_INITIAL_R2T:
561*fcf3ce44SJohn Forte 				icp->conn_params.initial_r2t =
562*fcf3ce44SJohn Forte 				    pp.p_params.initial_r2t;
563*fcf3ce44SJohn Forte 				break;
564*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER:
565*fcf3ce44SJohn Forte 				icp->conn_params.data_pdu_in_order =
566*fcf3ce44SJohn Forte 				    pp.p_params.data_pdu_in_order;
567*fcf3ce44SJohn Forte 				break;
568*fcf3ce44SJohn Forte 			/*
569*fcf3ce44SJohn Forte 			 * Integer parameters
570*fcf3ce44SJohn Forte 			 */
571*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_HEADER_DIGEST:
572*fcf3ce44SJohn Forte 				icp->conn_params.header_digest =
573*fcf3ce44SJohn Forte 				    pp.p_params.header_digest;
574*fcf3ce44SJohn Forte 				break;
575*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_DATA_DIGEST:
576*fcf3ce44SJohn Forte 				icp->conn_params.data_digest =
577*fcf3ce44SJohn Forte 				    pp.p_params.data_digest;
578*fcf3ce44SJohn Forte 				break;
579*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN:
580*fcf3ce44SJohn Forte 				icp->conn_params.default_time_to_retain =
581*fcf3ce44SJohn Forte 				    pp.p_params.default_time_to_retain;
582*fcf3ce44SJohn Forte 				break;
583*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT:
584*fcf3ce44SJohn Forte 				icp->conn_params.default_time_to_wait =
585*fcf3ce44SJohn Forte 				    pp.p_params.default_time_to_wait;
586*fcf3ce44SJohn Forte 				break;
587*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH:
588*fcf3ce44SJohn Forte 				icp->conn_params.max_recv_data_seg_len =
589*fcf3ce44SJohn Forte 				    pp.p_params.max_recv_data_seg_len;
590*fcf3ce44SJohn Forte 				break;
591*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH:
592*fcf3ce44SJohn Forte 				icp->conn_params.first_burst_length =
593*fcf3ce44SJohn Forte 				    pp.p_params.first_burst_length;
594*fcf3ce44SJohn Forte 				break;
595*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH:
596*fcf3ce44SJohn Forte 				icp->conn_params.max_burst_length =
597*fcf3ce44SJohn Forte 				    pp.p_params.max_burst_length;
598*fcf3ce44SJohn Forte 				break;
599*fcf3ce44SJohn Forte 
600*fcf3ce44SJohn Forte 			/*
601*fcf3ce44SJohn Forte 			 * Integer parameters which currently are unsettable
602*fcf3ce44SJohn Forte 			 */
603*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS:
604*fcf3ce44SJohn Forte 				/* FALLTHRU */
605*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T:
606*fcf3ce44SJohn Forte 				/* FALLTHRU */
607*fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL:
608*fcf3ce44SJohn Forte 				/* FALLTHRU */
609*fcf3ce44SJohn Forte 			default:
610*fcf3ce44SJohn Forte 				break;
611*fcf3ce44SJohn Forte 			}
612*fcf3ce44SJohn Forte 		}
613*fcf3ce44SJohn Forte 	}
614*fcf3ce44SJohn Forte 
615*fcf3ce44SJohn Forte 	/* Skip binding checks on discovery sessions */
616*fcf3ce44SJohn Forte 	if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) {
617*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SUCCESS);
618*fcf3ce44SJohn Forte 	}
619*fcf3ce44SJohn Forte 
620*fcf3ce44SJohn Forte 	/*
621*fcf3ce44SJohn Forte 	 * Now we need to get the current optional connection
622*fcf3ce44SJohn Forte 	 * binding information.
623*fcf3ce44SJohn Forte 	 */
624*fcf3ce44SJohn Forte 	/* setup initial buffer for configured session information */
625*fcf3ce44SJohn Forte 	size = sizeof (*ics);
626*fcf3ce44SJohn Forte 	ics = kmem_zalloc(size, KM_SLEEP);
627*fcf3ce44SJohn Forte 	ics->ics_in = 1;
628*fcf3ce44SJohn Forte 
629*fcf3ce44SJohn Forte 	/* get configured sessions information */
630*fcf3ce44SJohn Forte 	name = (char *)isp->sess_name;
631*fcf3ce44SJohn Forte 	if (persistent_get_config_session(name, ics) == B_FALSE) {
632*fcf3ce44SJohn Forte 		/*
633*fcf3ce44SJohn Forte 		 * If we were unable to get target level information
634*fcf3ce44SJohn Forte 		 * then check the initiator level information.
635*fcf3ce44SJohn Forte 		 */
636*fcf3ce44SJohn Forte 		name = (char *)isp->sess_hba->hba_name;
637*fcf3ce44SJohn Forte 		if (persistent_get_config_session(name, ics) == B_FALSE) {
638*fcf3ce44SJohn Forte 			/*
639*fcf3ce44SJohn Forte 			 * No hba information is found.  So assume default
640*fcf3ce44SJohn Forte 			 * one session unbound behavior.
641*fcf3ce44SJohn Forte 			 */
642*fcf3ce44SJohn Forte 			ics->ics_out = 1;
643*fcf3ce44SJohn Forte 			ics->ics_bound = B_FALSE;
644*fcf3ce44SJohn Forte 		}
645*fcf3ce44SJohn Forte 	}
646*fcf3ce44SJohn Forte 
647*fcf3ce44SJohn Forte 	/*
648*fcf3ce44SJohn Forte 	 * Check to make sure this session is still a configured
649*fcf3ce44SJohn Forte 	 * session.  The user might have decreased the session
650*fcf3ce44SJohn Forte 	 * count. (NOTE: byte 5 of the sess_isid is the session
651*fcf3ce44SJohn Forte 	 * count (via MS/T).  This counter starts at 0.)
652*fcf3ce44SJohn Forte 	 */
653*fcf3ce44SJohn Forte 	idx = isp->sess_isid[5];
654*fcf3ce44SJohn Forte 	if (ics->ics_out <= idx) {
655*fcf3ce44SJohn Forte 		/*
656*fcf3ce44SJohn Forte 		 * No longer a configured session.  Return a
657*fcf3ce44SJohn Forte 		 * failure so we don't attempt to relogin.
658*fcf3ce44SJohn Forte 		 */
659*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SHUTDOWN);
660*fcf3ce44SJohn Forte 	}
661*fcf3ce44SJohn Forte 
662*fcf3ce44SJohn Forte 	/*
663*fcf3ce44SJohn Forte 	 * If sessions are unbound set this information on
664*fcf3ce44SJohn Forte 	 * the connection and return success.
665*fcf3ce44SJohn Forte 	 */
666*fcf3ce44SJohn Forte 	if (ics->ics_bound == B_FALSE) {
667*fcf3ce44SJohn Forte 		icp->conn_bound = B_FALSE;
668*fcf3ce44SJohn Forte 		kmem_free(ics, sizeof (iscsi_config_sess_t));
669*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SUCCESS);
670*fcf3ce44SJohn Forte 	}
671*fcf3ce44SJohn Forte 
672*fcf3ce44SJohn Forte 	/*
673*fcf3ce44SJohn Forte 	 * Since the sessions are bound we need to find the matching
674*fcf3ce44SJohn Forte 	 * binding information for the session's isid.  If this
675*fcf3ce44SJohn Forte 	 * session's isid is > 0 then we need to get more configured
676*fcf3ce44SJohn Forte 	 * session information to find the binding info.
677*fcf3ce44SJohn Forte 	 */
678*fcf3ce44SJohn Forte 	if (idx > 0) {
679*fcf3ce44SJohn Forte 		int ics_out;
680*fcf3ce44SJohn Forte 
681*fcf3ce44SJohn Forte 		ics_out = ics->ics_out;
682*fcf3ce44SJohn Forte 		/* record new size and free last buffer */
683*fcf3ce44SJohn Forte 		size = ISCSI_SESSION_CONFIG_SIZE(ics_out);
684*fcf3ce44SJohn Forte 		kmem_free(ics, sizeof (*ics));
685*fcf3ce44SJohn Forte 
686*fcf3ce44SJohn Forte 		/* allocate new buffer */
687*fcf3ce44SJohn Forte 		ics = kmem_zalloc(size, KM_SLEEP);
688*fcf3ce44SJohn Forte 		ics->ics_in = ics_out;
689*fcf3ce44SJohn Forte 
690*fcf3ce44SJohn Forte 		/* get configured sessions information */
691*fcf3ce44SJohn Forte 		if (persistent_get_config_session(name, ics) != B_TRUE) {
692*fcf3ce44SJohn Forte 			cmn_err(CE_NOTE, "iscsi session(%d) - "
693*fcf3ce44SJohn Forte 			    "unable to get configured session information\n",
694*fcf3ce44SJohn Forte 			    isp->sess_oid);
695*fcf3ce44SJohn Forte 			kmem_free(ics, size);
696*fcf3ce44SJohn Forte 			return (ISCSI_STATUS_SHUTDOWN);
697*fcf3ce44SJohn Forte 		}
698*fcf3ce44SJohn Forte 	}
699*fcf3ce44SJohn Forte 
700*fcf3ce44SJohn Forte 	/* Copy correct binding information to the connection */
701*fcf3ce44SJohn Forte 	icp->conn_bound = B_TRUE;
702*fcf3ce44SJohn Forte 	if (ics->ics_bindings[idx].i_insize == sizeof (struct in_addr)) {
703*fcf3ce44SJohn Forte 		bcopy(&ics->ics_bindings[idx].i_addr.in4,
704*fcf3ce44SJohn Forte 		    &icp->conn_bound_addr.sin4.sin_addr.s_addr,
705*fcf3ce44SJohn Forte 		    sizeof (struct in_addr));
706*fcf3ce44SJohn Forte 	} else {
707*fcf3ce44SJohn Forte 		bcopy(&ics->ics_bindings[idx].i_addr.in6,
708*fcf3ce44SJohn Forte 		    &icp->conn_bound_addr.sin6.sin6_addr.s6_addr,
709*fcf3ce44SJohn Forte 		    sizeof (struct in6_addr));
710*fcf3ce44SJohn Forte 	}
711*fcf3ce44SJohn Forte 
712*fcf3ce44SJohn Forte 	kmem_free(ics, size);
713*fcf3ce44SJohn Forte 
714*fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
715*fcf3ce44SJohn Forte }
716*fcf3ce44SJohn Forte 
717*fcf3ce44SJohn Forte /*
718*fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
719*fcf3ce44SJohn Forte  * | Internal Connection Interfaces					|
720*fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
721*fcf3ce44SJohn Forte  */
722*fcf3ce44SJohn Forte 
723*fcf3ce44SJohn Forte 
724*fcf3ce44SJohn Forte /*
725*fcf3ce44SJohn Forte  * iscsi_conn_state_free -
726*fcf3ce44SJohn Forte  *
727*fcf3ce44SJohn Forte  * S1: FREE - State on instantiation, or after successful
728*fcf3ce44SJohn Forte  * connection closure.
729*fcf3ce44SJohn Forte  */
730*fcf3ce44SJohn Forte static iscsi_status_t
731*fcf3ce44SJohn Forte iscsi_conn_state_free(iscsi_conn_t *icp, iscsi_conn_event_t event)
732*fcf3ce44SJohn Forte {
733*fcf3ce44SJohn Forte 	iscsi_sess_t		*isp;
734*fcf3ce44SJohn Forte 	iscsi_hba_t		*ihp;
735*fcf3ce44SJohn Forte 	iscsi_task_t		*itp;
736*fcf3ce44SJohn Forte 	iscsi_status_t		status = ISCSI_STATUS_SUCCESS;
737*fcf3ce44SJohn Forte 
738*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
739*fcf3ce44SJohn Forte 	isp = icp->conn_sess;
740*fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
741*fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
742*fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
743*fcf3ce44SJohn Forte 	ASSERT(icp->conn_state == ISCSI_CONN_STATE_FREE);
744*fcf3ce44SJohn Forte 
745*fcf3ce44SJohn Forte 	/* switch on event change */
746*fcf3ce44SJohn Forte 	switch (event) {
747*fcf3ce44SJohn Forte 	/* -T1: Transport connection request was request */
748*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T1:
749*fcf3ce44SJohn Forte 		icp->conn_state = ISCSI_CONN_STATE_IN_LOGIN;
750*fcf3ce44SJohn Forte 
751*fcf3ce44SJohn Forte 		/*
752*fcf3ce44SJohn Forte 		 * Release the connection state mutex cross the
753*fcf3ce44SJohn Forte 		 * the dispatch of the login task.  The login task
754*fcf3ce44SJohn Forte 		 * will reacquire the connection state mutex when
755*fcf3ce44SJohn Forte 		 * it pushes the connection successful or failed.
756*fcf3ce44SJohn Forte 		 */
757*fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
758*fcf3ce44SJohn Forte 
759*fcf3ce44SJohn Forte 		/* start login */
760*fcf3ce44SJohn Forte 		itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
761*fcf3ce44SJohn Forte 		itp->t_arg = icp;
762*fcf3ce44SJohn Forte 		itp->t_blocking = B_TRUE;
763*fcf3ce44SJohn Forte 
764*fcf3ce44SJohn Forte 		/*
765*fcf3ce44SJohn Forte 		 * Sync base connection information before login
766*fcf3ce44SJohn Forte 		 * A login redirection might have shifted the
767*fcf3ce44SJohn Forte 		 * current information from the base.
768*fcf3ce44SJohn Forte 		 */
769*fcf3ce44SJohn Forte 		bcopy(&icp->conn_base_addr, &icp->conn_curr_addr,
770*fcf3ce44SJohn Forte 		    sizeof (icp->conn_curr_addr));
771*fcf3ce44SJohn Forte 
772*fcf3ce44SJohn Forte 		status = iscsi_login_start(itp);
773*fcf3ce44SJohn Forte 		kmem_free(itp, sizeof (iscsi_task_t));
774*fcf3ce44SJohn Forte 
775*fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
776*fcf3ce44SJohn Forte 		break;
777*fcf3ce44SJohn Forte 
778*fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
779*fcf3ce44SJohn Forte 	default:
780*fcf3ce44SJohn Forte 		ASSERT(FALSE);
781*fcf3ce44SJohn Forte 		status = ISCSI_STATUS_INTERNAL_ERROR;
782*fcf3ce44SJohn Forte 	}
783*fcf3ce44SJohn Forte 	return (status);
784*fcf3ce44SJohn Forte }
785*fcf3ce44SJohn Forte 
786*fcf3ce44SJohn Forte /*
787*fcf3ce44SJohn Forte  * iscsi_conn_state_in_login - During this state we are trying to
788*fcf3ce44SJohn Forte  * connect the TCP connection and make a successful login to the
789*fcf3ce44SJohn Forte  * target.  To complete this we have a task queue item that is
790*fcf3ce44SJohn Forte  * trying this processing at this point in time.  When the task
791*fcf3ce44SJohn Forte  * queue completed its processing it will issue either a T5/7
792*fcf3ce44SJohn Forte  * event.
793*fcf3ce44SJohn Forte  */
794*fcf3ce44SJohn Forte static void
795*fcf3ce44SJohn Forte iscsi_conn_state_in_login(iscsi_conn_t *icp, iscsi_conn_event_t event)
796*fcf3ce44SJohn Forte {
797*fcf3ce44SJohn Forte 	iscsi_sess_t	*isp;
798*fcf3ce44SJohn Forte 
799*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
800*fcf3ce44SJohn Forte 	isp = icp->conn_sess;
801*fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
802*fcf3ce44SJohn Forte 	ASSERT(icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN);
803*fcf3ce44SJohn Forte 
804*fcf3ce44SJohn Forte 	/* switch on event change */
805*fcf3ce44SJohn Forte 	switch (event) {
806*fcf3ce44SJohn Forte 	/*
807*fcf3ce44SJohn Forte 	 * -T5: The final iSCSI Login response with a Status-Class of zero
808*fcf3ce44SJohn Forte 	 *	was received.
809*fcf3ce44SJohn Forte 	 */
810*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T5:
811*fcf3ce44SJohn Forte 		iscsi_conn_logged_in(isp, icp);
812*fcf3ce44SJohn Forte 		break;
813*fcf3ce44SJohn Forte 
814*fcf3ce44SJohn Forte 	/*
815*fcf3ce44SJohn Forte 	 * -T30: One of the following event caused the transition:
816*fcf3ce44SJohn Forte 	 *	- Thefinal iSCSI Login response was received with a non-zero
817*fcf3ce44SJohn Forte 	 *	  Status-Class.
818*fcf3ce44SJohn Forte 	 */
819*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T30:
820*fcf3ce44SJohn Forte 		/* FALLTHRU */
821*fcf3ce44SJohn Forte 
822*fcf3ce44SJohn Forte 	/*
823*fcf3ce44SJohn Forte 	 * -T7: One of the following events caused the transition:
824*fcf3ce44SJohn Forte 	 *	- Login timed out.
825*fcf3ce44SJohn Forte 	 *	- A transport disconnect indication was received.
826*fcf3ce44SJohn Forte 	 *	- A transport reset was received.
827*fcf3ce44SJohn Forte 	 *	- An internal event indicating a transport timeout was
828*fcf3ce44SJohn Forte 	 *	  received.
829*fcf3ce44SJohn Forte 	 *	- An internal event of receiving a Logout repsonse (success)
830*fcf3ce44SJohn Forte 	 *	  on another connection for a "close the session" Logout
831*fcf3ce44SJohn Forte 	 *	  request was received.
832*fcf3ce44SJohn Forte 	 *	* In all these cases, the transport connection is closed.
833*fcf3ce44SJohn Forte 	 */
834*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T7:
835*fcf3ce44SJohn Forte 		icp->conn_state = ISCSI_CONN_STATE_FREE;
836*fcf3ce44SJohn Forte 		break;
837*fcf3ce44SJohn Forte 
838*fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
839*fcf3ce44SJohn Forte 	default:
840*fcf3ce44SJohn Forte 		ASSERT(FALSE);
841*fcf3ce44SJohn Forte 	}
842*fcf3ce44SJohn Forte }
843*fcf3ce44SJohn Forte 
844*fcf3ce44SJohn Forte 
845*fcf3ce44SJohn Forte /*
846*fcf3ce44SJohn Forte  * iscsi_conn_state_logged_in -
847*fcf3ce44SJohn Forte  *
848*fcf3ce44SJohn Forte  */
849*fcf3ce44SJohn Forte static void
850*fcf3ce44SJohn Forte iscsi_conn_state_logged_in(iscsi_conn_t *icp, iscsi_conn_event_t event)
851*fcf3ce44SJohn Forte {
852*fcf3ce44SJohn Forte 	iscsi_sess_t		*isp;
853*fcf3ce44SJohn Forte 	iscsi_hba_t		*ihp;
854*fcf3ce44SJohn Forte 
855*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
856*fcf3ce44SJohn Forte 	ASSERT(icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN);
857*fcf3ce44SJohn Forte 	isp = icp->conn_sess;
858*fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
859*fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
860*fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
861*fcf3ce44SJohn Forte 
862*fcf3ce44SJohn Forte 	/* switch on event change */
863*fcf3ce44SJohn Forte 	switch (event) {
864*fcf3ce44SJohn Forte 	/*
865*fcf3ce44SJohn Forte 	 * -T8: An internal event of receiving a Logout response (success)
866*fcf3ce44SJohn Forte 	 *	on another connection for a "close the session" Logout request
867*fcf3ce44SJohn Forte 	 *	was received, thus closing this connection requiring no further
868*fcf3ce44SJohn Forte 	 *	cleanup.
869*fcf3ce44SJohn Forte 	 */
870*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T8:
871*fcf3ce44SJohn Forte 		icp->conn_state = ISCSI_CONN_STATE_FREE;
872*fcf3ce44SJohn Forte 
873*fcf3ce44SJohn Forte 		/* stop tx thread */
874*fcf3ce44SJohn Forte 		(void) iscsi_thread_stop(icp->conn_tx_thread);
875*fcf3ce44SJohn Forte 
876*fcf3ce44SJohn Forte 		/* Disconnect connection */
877*fcf3ce44SJohn Forte 		iscsi_net->close(icp->conn_socket);
878*fcf3ce44SJohn Forte 
879*fcf3ce44SJohn Forte 		/* Notify session that a connection logged out */
880*fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_state_mutex);
881*fcf3ce44SJohn Forte 		iscsi_sess_state_machine(icp->conn_sess, ISCSI_SESS_EVENT_N3);
882*fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
883*fcf3ce44SJohn Forte 		break;
884*fcf3ce44SJohn Forte 
885*fcf3ce44SJohn Forte 	/*
886*fcf3ce44SJohn Forte 	 * -T9: An internal event that indicates the readiness to start the
887*fcf3ce44SJohn Forte 	 *	Logout process was received, thus prompting an iSCSI Logout
888*fcf3ce44SJohn Forte 	 *	to be sent by the initiator.
889*fcf3ce44SJohn Forte 	 */
890*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T9:
891*fcf3ce44SJohn Forte 		/* FALLTHRU */
892*fcf3ce44SJohn Forte 
893*fcf3ce44SJohn Forte 	/*
894*fcf3ce44SJohn Forte 	 * -T11: Aync PDU with AsyncEvent "Request Logout" was recevied
895*fcf3ce44SJohn Forte 	 */
896*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T11:
897*fcf3ce44SJohn Forte 		icp->conn_state = ISCSI_CONN_STATE_IN_LOGOUT;
898*fcf3ce44SJohn Forte 
899*fcf3ce44SJohn Forte 		(void) iscsi_handle_logout(icp);
900*fcf3ce44SJohn Forte 		break;
901*fcf3ce44SJohn Forte 
902*fcf3ce44SJohn Forte 	/*
903*fcf3ce44SJohn Forte 	 * -T14: One or more of the following events case this transition:
904*fcf3ce44SJohn Forte 	 *	- Header Digest Error
905*fcf3ce44SJohn Forte 	 *	- Protocol Error
906*fcf3ce44SJohn Forte 	 */
907*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T14:
908*fcf3ce44SJohn Forte 		icp->conn_state = ISCSI_CONN_STATE_FAILED;
909*fcf3ce44SJohn Forte 
910*fcf3ce44SJohn Forte 		/* stop tx thread */
911*fcf3ce44SJohn Forte 		(void) iscsi_thread_stop(icp->conn_tx_thread);
912*fcf3ce44SJohn Forte 
913*fcf3ce44SJohn Forte 		/*
914*fcf3ce44SJohn Forte 		 * Error Recovery Level 0 states we should drop
915*fcf3ce44SJohn Forte 		 * the connection here.  Then we will fall through
916*fcf3ce44SJohn Forte 		 * and treat this event like a T15.
917*fcf3ce44SJohn Forte 		 */
918*fcf3ce44SJohn Forte 		iscsi_net->close(icp->conn_socket);
919*fcf3ce44SJohn Forte 
920*fcf3ce44SJohn Forte 		/* FALLTHRU */
921*fcf3ce44SJohn Forte 
922*fcf3ce44SJohn Forte 	/*
923*fcf3ce44SJohn Forte 	 * -T15: One or more of the following events caused this transition
924*fcf3ce44SJohn Forte 	 *	- Internal event that indicates a transport connection timeout
925*fcf3ce44SJohn Forte 	 *	  was received thus prompting transport RESET or transport
926*fcf3ce44SJohn Forte 	 *	  connection closure.
927*fcf3ce44SJohn Forte 	 *	- A transport RESET
928*fcf3ce44SJohn Forte 	 *	- A transport disconnect indication.
929*fcf3ce44SJohn Forte 	 *	- Async PDU with AsyncEvent "Drop connection" (for this CID)
930*fcf3ce44SJohn Forte 	 *	- Async PDU with AsyncEvent "Drop all connections"
931*fcf3ce44SJohn Forte 	 */
932*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T15:
933*fcf3ce44SJohn Forte 		icp->conn_state = ISCSI_CONN_STATE_FAILED;
934*fcf3ce44SJohn Forte 
935*fcf3ce44SJohn Forte 		/* stop tx thread, no-op if already done for T14 */
936*fcf3ce44SJohn Forte 		(void) iscsi_thread_stop(icp->conn_tx_thread);
937*fcf3ce44SJohn Forte 
938*fcf3ce44SJohn Forte 		iscsi_conn_flush_active_cmds(icp);
939*fcf3ce44SJohn Forte 
940*fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_state_mutex);
941*fcf3ce44SJohn Forte 		iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N5);
942*fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
943*fcf3ce44SJohn Forte 
944*fcf3ce44SJohn Forte 		/*
945*fcf3ce44SJohn Forte 		 * If session type is NORMAL, create a new login task
946*fcf3ce44SJohn Forte 		 * to get this connection reestablished.
947*fcf3ce44SJohn Forte 		 */
948*fcf3ce44SJohn Forte 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
949*fcf3ce44SJohn Forte 			iscsi_conn_retry(isp, icp);
950*fcf3ce44SJohn Forte 		} else {
951*fcf3ce44SJohn Forte 			icp->conn_state = ISCSI_CONN_STATE_FREE;
952*fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_state_mutex);
953*fcf3ce44SJohn Forte 			iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6);
954*fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_state_mutex);
955*fcf3ce44SJohn Forte 		}
956*fcf3ce44SJohn Forte 		break;
957*fcf3ce44SJohn Forte 
958*fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
959*fcf3ce44SJohn Forte 	default:
960*fcf3ce44SJohn Forte 		ASSERT(FALSE);
961*fcf3ce44SJohn Forte 	}
962*fcf3ce44SJohn Forte }
963*fcf3ce44SJohn Forte 
964*fcf3ce44SJohn Forte 
965*fcf3ce44SJohn Forte /*
966*fcf3ce44SJohn Forte  * iscsi_conn_state_in_logout -
967*fcf3ce44SJohn Forte  *
968*fcf3ce44SJohn Forte  */
969*fcf3ce44SJohn Forte static void
970*fcf3ce44SJohn Forte iscsi_conn_state_in_logout(iscsi_conn_t *icp, iscsi_conn_event_t event)
971*fcf3ce44SJohn Forte {
972*fcf3ce44SJohn Forte 	iscsi_sess_t	*isp	= NULL;
973*fcf3ce44SJohn Forte 
974*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
975*fcf3ce44SJohn Forte 	ASSERT(icp->conn_state == ISCSI_CONN_STATE_IN_LOGOUT);
976*fcf3ce44SJohn Forte 	isp = icp->conn_sess;
977*fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
978*fcf3ce44SJohn Forte 
979*fcf3ce44SJohn Forte 	/* switch on event change */
980*fcf3ce44SJohn Forte 	switch (event) {
981*fcf3ce44SJohn Forte 	/*
982*fcf3ce44SJohn Forte 	 * -T11: Async PDU with AsyncEvent "Request Logout" was received again
983*fcf3ce44SJohn Forte 	 */
984*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T11:
985*fcf3ce44SJohn Forte 		icp->conn_state = ISCSI_CONN_STATE_IN_LOGOUT;
986*fcf3ce44SJohn Forte 
987*fcf3ce44SJohn Forte 		/* Already in LOGOUT ignore the request */
988*fcf3ce44SJohn Forte 		break;
989*fcf3ce44SJohn Forte 
990*fcf3ce44SJohn Forte 	/*
991*fcf3ce44SJohn Forte 	 * -T17: One or more of the following events caused this transition:
992*fcf3ce44SJohn Forte 	 *	- Logout response, (failure i.e., a non-zero status) was
993*fcf3ce44SJohn Forte 	 *	received, or logout timed out.
994*fcf3ce44SJohn Forte 	 *	- Any of the events specified for T15
995*fcf3ce44SJohn Forte 	 *
996*fcf3ce44SJohn Forte 	 * -T14: One or more of the following events case this transition:
997*fcf3ce44SJohn Forte 	 *	- Header Digest Error
998*fcf3ce44SJohn Forte 	 *	- Protocol Error
999*fcf3ce44SJohn Forte 	 *
1000*fcf3ce44SJohn Forte 	 * -T15: One or more of the following events caused this transition
1001*fcf3ce44SJohn Forte 	 *	- Internal event that indicates a transport connection timeout
1002*fcf3ce44SJohn Forte 	 *	  was received thus prompting transport RESET or transport
1003*fcf3ce44SJohn Forte 	 *	  connection closure.
1004*fcf3ce44SJohn Forte 	 *	- A transport RESET
1005*fcf3ce44SJohn Forte 	 *	- A transport disconnect indication.
1006*fcf3ce44SJohn Forte 	 *	- Async PDU with AsyncEvent "Drop connection" (for this CID)
1007*fcf3ce44SJohn Forte 	 *	- Async PDU with AsyncEvent "Drop all connections"
1008*fcf3ce44SJohn Forte 	 */
1009*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T17:
1010*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T14:
1011*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T15:
1012*fcf3ce44SJohn Forte 		icp->conn_state = ISCSI_CONN_STATE_FREE;
1013*fcf3ce44SJohn Forte 
1014*fcf3ce44SJohn Forte 		/* stop tx thread */
1015*fcf3ce44SJohn Forte 		(void) iscsi_thread_stop(icp->conn_tx_thread);
1016*fcf3ce44SJohn Forte 
1017*fcf3ce44SJohn Forte 		/* Disconnect Connection */
1018*fcf3ce44SJohn Forte 		iscsi_net->close(icp->conn_socket);
1019*fcf3ce44SJohn Forte 
1020*fcf3ce44SJohn Forte 		iscsi_conn_flush_active_cmds(icp);
1021*fcf3ce44SJohn Forte 
1022*fcf3ce44SJohn Forte 		/* Notify session of a failed logout */
1023*fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_state_mutex);
1024*fcf3ce44SJohn Forte 		iscsi_sess_state_machine(icp->conn_sess, ISCSI_SESS_EVENT_N3);
1025*fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
1026*fcf3ce44SJohn Forte 		break;
1027*fcf3ce44SJohn Forte 
1028*fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
1029*fcf3ce44SJohn Forte 	default:
1030*fcf3ce44SJohn Forte 		ASSERT(FALSE);
1031*fcf3ce44SJohn Forte 	}
1032*fcf3ce44SJohn Forte }
1033*fcf3ce44SJohn Forte 
1034*fcf3ce44SJohn Forte 
1035*fcf3ce44SJohn Forte /*
1036*fcf3ce44SJohn Forte  * iscsi_conn_state_failed -
1037*fcf3ce44SJohn Forte  *
1038*fcf3ce44SJohn Forte  */
1039*fcf3ce44SJohn Forte static void
1040*fcf3ce44SJohn Forte iscsi_conn_state_failed(iscsi_conn_t *icp, iscsi_conn_event_t event)
1041*fcf3ce44SJohn Forte {
1042*fcf3ce44SJohn Forte 	iscsi_sess_t	*isp;
1043*fcf3ce44SJohn Forte 
1044*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1045*fcf3ce44SJohn Forte 	ASSERT(icp->conn_state == ISCSI_CONN_STATE_FAILED);
1046*fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1047*fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1048*fcf3ce44SJohn Forte 
1049*fcf3ce44SJohn Forte 	/* switch on event change */
1050*fcf3ce44SJohn Forte 	switch (event) {
1051*fcf3ce44SJohn Forte 
1052*fcf3ce44SJohn Forte 	/*
1053*fcf3ce44SJohn Forte 	 * -T5: The final iSCSI Login response with a Status-Class of zero
1054*fcf3ce44SJohn Forte 	 *	was received.
1055*fcf3ce44SJohn Forte 	 */
1056*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T5:
1057*fcf3ce44SJohn Forte 		iscsi_conn_logged_in(isp, icp);
1058*fcf3ce44SJohn Forte 		break;
1059*fcf3ce44SJohn Forte 
1060*fcf3ce44SJohn Forte 	/*
1061*fcf3ce44SJohn Forte 	 * -T30: One of the following event caused the transition:
1062*fcf3ce44SJohn Forte 	 *	- Thefinal iSCSI Login response was received with a non-zero
1063*fcf3ce44SJohn Forte 	 *	  Status-Class.
1064*fcf3ce44SJohn Forte 	 */
1065*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T30:
1066*fcf3ce44SJohn Forte 		icp->conn_state = ISCSI_CONN_STATE_FREE;
1067*fcf3ce44SJohn Forte 
1068*fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_state_mutex);
1069*fcf3ce44SJohn Forte 		iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6);
1070*fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
1071*fcf3ce44SJohn Forte 
1072*fcf3ce44SJohn Forte 		break;
1073*fcf3ce44SJohn Forte 
1074*fcf3ce44SJohn Forte 	/*
1075*fcf3ce44SJohn Forte 	 * -T7: One of the following events caused the transition:
1076*fcf3ce44SJohn Forte 	 *	- Login timed out.
1077*fcf3ce44SJohn Forte 	 *	- A transport disconnect indication was received.
1078*fcf3ce44SJohn Forte 	 *	- A transport reset was received.
1079*fcf3ce44SJohn Forte 	 *	- An internal event indicating a transport timeout was
1080*fcf3ce44SJohn Forte 	 *	  received.
1081*fcf3ce44SJohn Forte 	 *	- An internal event of receiving a Logout repsonse (success)
1082*fcf3ce44SJohn Forte 	 *	  on another connection for a "close the session" Logout
1083*fcf3ce44SJohn Forte 	 *	  request was received.
1084*fcf3ce44SJohn Forte 	 *	* In all these cases, the transport connection is closed.
1085*fcf3ce44SJohn Forte 	 */
1086*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T7:
1087*fcf3ce44SJohn Forte 		icp->conn_state = ISCSI_CONN_STATE_POLLING;
1088*fcf3ce44SJohn Forte 
1089*fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_state_mutex);
1090*fcf3ce44SJohn Forte 		iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6);
1091*fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
1092*fcf3ce44SJohn Forte 
1093*fcf3ce44SJohn Forte 		iscsi_conn_retry(isp, icp);
1094*fcf3ce44SJohn Forte 		break;
1095*fcf3ce44SJohn Forte 
1096*fcf3ce44SJohn Forte 	/* There are no valid transition out of this state. */
1097*fcf3ce44SJohn Forte 	default:
1098*fcf3ce44SJohn Forte 		ASSERT(FALSE);
1099*fcf3ce44SJohn Forte 	}
1100*fcf3ce44SJohn Forte }
1101*fcf3ce44SJohn Forte 
1102*fcf3ce44SJohn Forte /*
1103*fcf3ce44SJohn Forte  * iscsi_conn_state_polling -
1104*fcf3ce44SJohn Forte  *
1105*fcf3ce44SJohn Forte  * S6: POLLING - State on instantiation, or after successful
1106*fcf3ce44SJohn Forte  * connection closure.
1107*fcf3ce44SJohn Forte  */
1108*fcf3ce44SJohn Forte static void
1109*fcf3ce44SJohn Forte iscsi_conn_state_polling(iscsi_conn_t *icp, iscsi_conn_event_t event)
1110*fcf3ce44SJohn Forte {
1111*fcf3ce44SJohn Forte 	iscsi_sess_t *isp = NULL;
1112*fcf3ce44SJohn Forte 
1113*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1114*fcf3ce44SJohn Forte 	ASSERT(icp->conn_state == ISCSI_CONN_STATE_POLLING);
1115*fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1116*fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1117*fcf3ce44SJohn Forte 
1118*fcf3ce44SJohn Forte 	/* switch on event change */
1119*fcf3ce44SJohn Forte 	switch (event) {
1120*fcf3ce44SJohn Forte 	/*
1121*fcf3ce44SJohn Forte 	 * -T5: The final iSCSI Login response with a Status-Class of zero
1122*fcf3ce44SJohn Forte 	 *	was received.
1123*fcf3ce44SJohn Forte 	 */
1124*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T5:
1125*fcf3ce44SJohn Forte 		iscsi_conn_logged_in(isp, icp);
1126*fcf3ce44SJohn Forte 		break;
1127*fcf3ce44SJohn Forte 
1128*fcf3ce44SJohn Forte 	/*
1129*fcf3ce44SJohn Forte 	 * -T30: One of the following event caused the transition:
1130*fcf3ce44SJohn Forte 	 *	- Thefinal iSCSI Login response was received with a non-zero
1131*fcf3ce44SJohn Forte 	 *	  Status-Class.
1132*fcf3ce44SJohn Forte 	 */
1133*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T30:
1134*fcf3ce44SJohn Forte 		icp->conn_state = ISCSI_CONN_STATE_FREE;
1135*fcf3ce44SJohn Forte 
1136*fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_state_mutex);
1137*fcf3ce44SJohn Forte 		iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6);
1138*fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
1139*fcf3ce44SJohn Forte 
1140*fcf3ce44SJohn Forte 		break;
1141*fcf3ce44SJohn Forte 
1142*fcf3ce44SJohn Forte 	/*
1143*fcf3ce44SJohn Forte 	 * -T7: One of the following events caused the transition:
1144*fcf3ce44SJohn Forte 	 *	- Login timed out.
1145*fcf3ce44SJohn Forte 	 *	- A transport disconnect indication was received.
1146*fcf3ce44SJohn Forte 	 *	- A transport reset was received.
1147*fcf3ce44SJohn Forte 	 *	- An internal event indicating a transport timeout was
1148*fcf3ce44SJohn Forte 	 *	  received.
1149*fcf3ce44SJohn Forte 	 *	- An internal event of receiving a Logout repsonse (success)
1150*fcf3ce44SJohn Forte 	 *	  on another connection for a "close the session" Logout
1151*fcf3ce44SJohn Forte 	 *	  request was received.
1152*fcf3ce44SJohn Forte 	 *	* In all these cases, the transport connection is closed.
1153*fcf3ce44SJohn Forte 	 */
1154*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T7:
1155*fcf3ce44SJohn Forte 		/*
1156*fcf3ce44SJohn Forte 		 * If session type is NORMAL, create a new login task
1157*fcf3ce44SJohn Forte 		 * to get this connection reestablished.
1158*fcf3ce44SJohn Forte 		 */
1159*fcf3ce44SJohn Forte 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1160*fcf3ce44SJohn Forte 			iscsi_conn_retry(isp, icp);
1161*fcf3ce44SJohn Forte 		} else {
1162*fcf3ce44SJohn Forte 			icp->conn_state = ISCSI_CONN_STATE_FREE;
1163*fcf3ce44SJohn Forte 		}
1164*fcf3ce44SJohn Forte 		break;
1165*fcf3ce44SJohn Forte 
1166*fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
1167*fcf3ce44SJohn Forte 	default:
1168*fcf3ce44SJohn Forte 		ASSERT(FALSE);
1169*fcf3ce44SJohn Forte 	}
1170*fcf3ce44SJohn Forte }
1171*fcf3ce44SJohn Forte 
1172*fcf3ce44SJohn Forte /*
1173*fcf3ce44SJohn Forte  * iscsi_conn_event_str - converts event enum to a string
1174*fcf3ce44SJohn Forte  */
1175*fcf3ce44SJohn Forte static char *
1176*fcf3ce44SJohn Forte iscsi_conn_event_str(iscsi_conn_event_t event)
1177*fcf3ce44SJohn Forte {
1178*fcf3ce44SJohn Forte 	switch (event) {
1179*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T1:
1180*fcf3ce44SJohn Forte 		return ("T1");
1181*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T5:
1182*fcf3ce44SJohn Forte 		return ("T5");
1183*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T7:
1184*fcf3ce44SJohn Forte 		return ("T7");
1185*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T8:
1186*fcf3ce44SJohn Forte 		return ("T8");
1187*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T9:
1188*fcf3ce44SJohn Forte 		return ("T9");
1189*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T11:
1190*fcf3ce44SJohn Forte 		return ("T11");
1191*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T14:
1192*fcf3ce44SJohn Forte 		return ("T14");
1193*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T15:
1194*fcf3ce44SJohn Forte 		return ("T15");
1195*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T17:
1196*fcf3ce44SJohn Forte 		return ("T17");
1197*fcf3ce44SJohn Forte 	case ISCSI_CONN_EVENT_T30:
1198*fcf3ce44SJohn Forte 		return ("T30");
1199*fcf3ce44SJohn Forte 
1200*fcf3ce44SJohn Forte 	default:
1201*fcf3ce44SJohn Forte 		return ("unknown");
1202*fcf3ce44SJohn Forte 	}
1203*fcf3ce44SJohn Forte }
1204*fcf3ce44SJohn Forte 
1205*fcf3ce44SJohn Forte /*
1206*fcf3ce44SJohn Forte  * iscsi_conn_flush_active_cmds - flush all active icmdps
1207*fcf3ce44SJohn Forte  *	for a connection.
1208*fcf3ce44SJohn Forte  */
1209*fcf3ce44SJohn Forte static void
1210*fcf3ce44SJohn Forte iscsi_conn_flush_active_cmds(iscsi_conn_t *icp)
1211*fcf3ce44SJohn Forte {
1212*fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp;
1213*fcf3ce44SJohn Forte 	iscsi_sess_t	*isp;
1214*fcf3ce44SJohn Forte 	boolean_t	lock_held = B_FALSE;
1215*fcf3ce44SJohn Forte 
1216*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1217*fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1218*fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1219*fcf3ce44SJohn Forte 
1220*fcf3ce44SJohn Forte 	if (mutex_owned(&icp->conn_queue_active.mutex)) {
1221*fcf3ce44SJohn Forte 		lock_held = B_TRUE;
1222*fcf3ce44SJohn Forte 	} else {
1223*fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_queue_active.mutex);
1224*fcf3ce44SJohn Forte 	}
1225*fcf3ce44SJohn Forte 
1226*fcf3ce44SJohn Forte 	/* Flush active queue */
1227*fcf3ce44SJohn Forte 	icmdp = icp->conn_queue_active.head;
1228*fcf3ce44SJohn Forte 	while (icmdp != NULL) {
1229*fcf3ce44SJohn Forte 		iscsi_cmd_state_machine(icmdp,
1230*fcf3ce44SJohn Forte 		    ISCSI_CMD_EVENT_E7, isp);
1231*fcf3ce44SJohn Forte 		icmdp = icp->conn_queue_active.head;
1232*fcf3ce44SJohn Forte 	}
1233*fcf3ce44SJohn Forte 
1234*fcf3ce44SJohn Forte 	if (lock_held == B_FALSE) {
1235*fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
1236*fcf3ce44SJohn Forte 	}
1237*fcf3ce44SJohn Forte }
1238*fcf3ce44SJohn Forte 
1239*fcf3ce44SJohn Forte 
1240*fcf3ce44SJohn Forte /*
1241*fcf3ce44SJohn Forte  * iscsi_conn_logged_in - connection has successfully logged in
1242*fcf3ce44SJohn Forte  */
1243*fcf3ce44SJohn Forte static void
1244*fcf3ce44SJohn Forte iscsi_conn_logged_in(iscsi_sess_t *isp, iscsi_conn_t *icp)
1245*fcf3ce44SJohn Forte {
1246*fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1247*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1248*fcf3ce44SJohn Forte 
1249*fcf3ce44SJohn Forte 	icp->conn_state = ISCSI_CONN_STATE_LOGGED_IN;
1250*fcf3ce44SJohn Forte 	/*
1251*fcf3ce44SJohn Forte 	 * We need to drop the connection state lock
1252*fcf3ce44SJohn Forte 	 * before updating the session state.  On update
1253*fcf3ce44SJohn Forte 	 * of the session state it will enumerate the
1254*fcf3ce44SJohn Forte 	 * target.  If we hold the lock during enumeration
1255*fcf3ce44SJohn Forte 	 * will block the watchdog thread from timing
1256*fcf3ce44SJohn Forte 	 * a scsi_pkt, if required.  This will lead to
1257*fcf3ce44SJohn Forte 	 * a possible hang condition.
1258*fcf3ce44SJohn Forte 	 *
1259*fcf3ce44SJohn Forte 	 * Also the lock is no longer needed once the
1260*fcf3ce44SJohn Forte 	 * connection state was updated.
1261*fcf3ce44SJohn Forte 	 */
1262*fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_state_mutex);
1263*fcf3ce44SJohn Forte 
1264*fcf3ce44SJohn Forte 	/* startup threads */
1265*fcf3ce44SJohn Forte 	(void) iscsi_thread_start(icp->conn_rx_thread);
1266*fcf3ce44SJohn Forte 	(void) iscsi_thread_start(icp->conn_tx_thread);
1267*fcf3ce44SJohn Forte 
1268*fcf3ce44SJohn Forte 	/* Notify the session that a connection is logged in */
1269*fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_state_mutex);
1270*fcf3ce44SJohn Forte 	iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N1);
1271*fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_state_mutex);
1272*fcf3ce44SJohn Forte 
1273*fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_state_mutex);
1274*fcf3ce44SJohn Forte }
1275*fcf3ce44SJohn Forte 
1276*fcf3ce44SJohn Forte /*
1277*fcf3ce44SJohn Forte  * iscsi_conn_retry - retry connect/login
1278*fcf3ce44SJohn Forte  */
1279*fcf3ce44SJohn Forte static void
1280*fcf3ce44SJohn Forte iscsi_conn_retry(iscsi_sess_t *isp, iscsi_conn_t *icp)
1281*fcf3ce44SJohn Forte {
1282*fcf3ce44SJohn Forte 	iscsi_task_t *itp;
1283*fcf3ce44SJohn Forte 
1284*fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1285*fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1286*fcf3ce44SJohn Forte 
1287*fcf3ce44SJohn Forte 	/* set login min/max time values */
1288*fcf3ce44SJohn Forte 	iscsi_conn_set_login_min_max(icp,
1289*fcf3ce44SJohn Forte 	    ISCSI_CONN_DEFAULT_LOGIN_MIN,
1290*fcf3ce44SJohn Forte 	    ISCSI_CONN_DEFAULT_LOGIN_MAX);
1291*fcf3ce44SJohn Forte 
1292*fcf3ce44SJohn Forte 	/*
1293*fcf3ce44SJohn Forte 	 * Sync base connection information before login.
1294*fcf3ce44SJohn Forte 	 * A login redirection might have shifted the
1295*fcf3ce44SJohn Forte 	 * current information from the base.
1296*fcf3ce44SJohn Forte 	 */
1297*fcf3ce44SJohn Forte 	bcopy(&icp->conn_base_addr, &icp->conn_curr_addr,
1298*fcf3ce44SJohn Forte 	    sizeof (icp->conn_curr_addr));
1299*fcf3ce44SJohn Forte 
1300*fcf3ce44SJohn Forte 	/* schedule login task */
1301*fcf3ce44SJohn Forte 	itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
1302*fcf3ce44SJohn Forte 	itp->t_arg = icp;
1303*fcf3ce44SJohn Forte 	itp->t_blocking = B_FALSE;
1304*fcf3ce44SJohn Forte 	if (ddi_taskq_dispatch(isp->sess_taskq,
1305*fcf3ce44SJohn Forte 	    (void(*)())iscsi_login_start, itp, DDI_SLEEP) !=
1306*fcf3ce44SJohn Forte 	    DDI_SUCCESS) {
1307*fcf3ce44SJohn Forte 		kmem_free(itp, sizeof (iscsi_task_t));
1308*fcf3ce44SJohn Forte 		cmn_err(CE_WARN,
1309*fcf3ce44SJohn Forte 		    "iscsi connection(%u) failure - "
1310*fcf3ce44SJohn Forte 		    "unable to schedule login task",
1311*fcf3ce44SJohn Forte 		    icp->conn_oid);
1312*fcf3ce44SJohn Forte 
1313*fcf3ce44SJohn Forte 		icp->conn_state = ISCSI_CONN_STATE_FREE;
1314*fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_state_mutex);
1315*fcf3ce44SJohn Forte 		iscsi_sess_state_machine(isp,
1316*fcf3ce44SJohn Forte 		    ISCSI_SESS_EVENT_N6);
1317*fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
1318*fcf3ce44SJohn Forte 	}
1319*fcf3ce44SJohn Forte }
1320