1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
22*cc7ef495Syi zhang - Sun Microsystems - Beijing China  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23fcf3ce44SJohn Forte  * Use is subject to license terms.
24fcf3ce44SJohn Forte  *
25fcf3ce44SJohn Forte  * iSCSI connection interfaces
26fcf3ce44SJohn Forte  */
27fcf3ce44SJohn Forte 
2830e7468fSPeter Dunlap #define	ISCSI_ICS_NAMES
29fcf3ce44SJohn Forte #include "iscsi.h"
30fcf3ce44SJohn Forte #include "persistent.h"
316cefaae1SJack Meng #include <sys/bootprops.h>
326cefaae1SJack Meng 
336cefaae1SJack Meng extern ib_boot_prop_t   *iscsiboot_prop;
34fcf3ce44SJohn Forte 
3530e7468fSPeter Dunlap static void iscsi_client_notify_task(void *cn_task_void);
36fcf3ce44SJohn Forte 
3730e7468fSPeter Dunlap static void iscsi_conn_flush_active_cmds(iscsi_conn_t *icp);
38fcf3ce44SJohn Forte 
39fcf3ce44SJohn Forte #define	SHUTDOWN_TIMEOUT	180 /* seconds */
40fcf3ce44SJohn Forte 
416cefaae1SJack Meng extern int modrootloaded;
4230e7468fSPeter Dunlap 
4330e7468fSPeter Dunlap boolean_t iscsi_conn_logging = B_FALSE;
4430e7468fSPeter Dunlap 
45*cc7ef495Syi zhang - Sun Microsystems - Beijing China #define	ISCSI_LOGIN_TPGT_NEGO_ERROR(icp) \
46*cc7ef495Syi zhang - Sun Microsystems - Beijing China 	(((icp)->conn_login_state == LOGIN_ERROR) && \
47*cc7ef495Syi zhang - Sun Microsystems - Beijing China 	((icp)->conn_login_status == ISCSI_STATUS_LOGIN_TPGT_NEGO_FAIL))
48*cc7ef495Syi zhang - Sun Microsystems - Beijing China 
49fcf3ce44SJohn Forte /*
50fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
51fcf3ce44SJohn Forte  * | External Connection Interfaces					|
52fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
53fcf3ce44SJohn Forte  */
54fcf3ce44SJohn Forte 
55fcf3ce44SJohn Forte /*
56fcf3ce44SJohn Forte  * iscsi_conn_create - This creates an iscsi connection structure and
57fcf3ce44SJohn Forte  * associates it with a session structure.  The session's sess_conn_list_rwlock
58fcf3ce44SJohn Forte  * should be held as a writer before calling this function.
59fcf3ce44SJohn Forte  */
60fcf3ce44SJohn Forte iscsi_status_t
61fcf3ce44SJohn Forte iscsi_conn_create(struct sockaddr *addr, iscsi_sess_t *isp, iscsi_conn_t **icpp)
62fcf3ce44SJohn Forte {
63fcf3ce44SJohn Forte 	iscsi_conn_t	*icp	= NULL;
64fcf3ce44SJohn Forte 	char		th_name[ISCSI_TH_MAX_NAME_LEN];
65fcf3ce44SJohn Forte 
66fcf3ce44SJohn Forte 	/* See if this connection already exists */
67fcf3ce44SJohn Forte 	for (icp = isp->sess_conn_list; icp; icp = icp->conn_next) {
68fcf3ce44SJohn Forte 
69fcf3ce44SJohn Forte 		/*
70fcf3ce44SJohn Forte 		 * Compare the ioctl information to see if
71fcf3ce44SJohn Forte 		 * its a match for this connection.  (This
72fcf3ce44SJohn Forte 		 * is done by making sure the IPs are of
73fcf3ce44SJohn Forte 		 * the same size and then they are the
74fcf3ce44SJohn Forte 		 * same value.
75fcf3ce44SJohn Forte 		 */
76fcf3ce44SJohn Forte 		if (bcmp(&icp->conn_base_addr, addr,
77fcf3ce44SJohn Forte 		    SIZEOF_SOCKADDR(addr)) == 0) {
78fcf3ce44SJohn Forte 			/* It's a match, record this connection */
79fcf3ce44SJohn Forte 			break;
80fcf3ce44SJohn Forte 		}
81fcf3ce44SJohn Forte 	}
82fcf3ce44SJohn Forte 
83fcf3ce44SJohn Forte 	/* If icp is found return it */
84fcf3ce44SJohn Forte 	if (icp != NULL) {
85fcf3ce44SJohn Forte 		*icpp = icp;
86fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SUCCESS);
87fcf3ce44SJohn Forte 	}
88fcf3ce44SJohn Forte 
89fcf3ce44SJohn Forte 	/* We are creating the connection, allocate, and setup */
90fcf3ce44SJohn Forte 	icp = (iscsi_conn_t *)kmem_zalloc(sizeof (iscsi_conn_t), KM_SLEEP);
91fcf3ce44SJohn Forte 
92fcf3ce44SJohn Forte 	/*
93fcf3ce44SJohn Forte 	 * Setup connection
94fcf3ce44SJohn Forte 	 */
95fcf3ce44SJohn Forte 	icp->conn_sig			= ISCSI_SIG_CONN;
96fcf3ce44SJohn Forte 	icp->conn_state			= ISCSI_CONN_STATE_FREE;
97fcf3ce44SJohn Forte 	mutex_init(&icp->conn_state_mutex, NULL, MUTEX_DRIVER, NULL);
98fcf3ce44SJohn Forte 	cv_init(&icp->conn_state_change, NULL, CV_DRIVER, NULL);
9930e7468fSPeter Dunlap 	mutex_init(&icp->conn_login_mutex, NULL, MUTEX_DRIVER, NULL);
10030e7468fSPeter Dunlap 	cv_init(&icp->conn_login_cv, NULL, CV_DRIVER, NULL);
101fcf3ce44SJohn Forte 	icp->conn_state_destroy		= B_FALSE;
10230e7468fSPeter Dunlap 	idm_sm_audit_init(&icp->conn_state_audit);
103fcf3ce44SJohn Forte 	icp->conn_sess			= isp;
104fcf3ce44SJohn Forte 
105fcf3ce44SJohn Forte 	mutex_enter(&iscsi_oid_mutex);
106fcf3ce44SJohn Forte 	icp->conn_oid = iscsi_oid++;
107fcf3ce44SJohn Forte 	mutex_exit(&iscsi_oid_mutex);
108fcf3ce44SJohn Forte 
10930e7468fSPeter Dunlap 	/*
11030e7468fSPeter Dunlap 	 * IDM CN taskq
11130e7468fSPeter Dunlap 	 */
11230e7468fSPeter Dunlap 
11330e7468fSPeter Dunlap 	if (snprintf(th_name, sizeof (th_name) - 1,
11430e7468fSPeter Dunlap 	    ISCSI_CONN_CN_TASKQ_NAME_FORMAT,
115fcf3ce44SJohn Forte 	    icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid,
116fcf3ce44SJohn Forte 	    icp->conn_oid) >= sizeof (th_name)) {
117fcf3ce44SJohn Forte 		cv_destroy(&icp->conn_state_change);
118fcf3ce44SJohn Forte 		mutex_destroy(&icp->conn_state_mutex);
119fcf3ce44SJohn Forte 		kmem_free(icp, sizeof (iscsi_conn_t));
120fcf3ce44SJohn Forte 		*icpp = NULL;
121fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
122fcf3ce44SJohn Forte 	}
123fcf3ce44SJohn Forte 
12430e7468fSPeter Dunlap 	icp->conn_cn_taskq =
12530e7468fSPeter Dunlap 	    ddi_taskq_create(icp->conn_sess->sess_hba->hba_dip, th_name, 1,
12630e7468fSPeter Dunlap 	    TASKQ_DEFAULTPRI, 0);
12730e7468fSPeter Dunlap 	if (icp->conn_cn_taskq == NULL) {
12830e7468fSPeter Dunlap 		cv_destroy(&icp->conn_state_change);
12930e7468fSPeter Dunlap 		mutex_destroy(&icp->conn_state_mutex);
13030e7468fSPeter Dunlap 		kmem_free(icp, sizeof (iscsi_conn_t));
13130e7468fSPeter Dunlap 		*icpp = NULL;
13230e7468fSPeter Dunlap 		return (ISCSI_STATUS_INTERNAL_ERROR);
13330e7468fSPeter Dunlap 	}
134fcf3ce44SJohn Forte 
135fcf3ce44SJohn Forte 	/* Creation of the transfer thread */
136fcf3ce44SJohn Forte 	if (snprintf(th_name, sizeof (th_name) - 1, ISCSI_CONN_TXTH_NAME_FORMAT,
137fcf3ce44SJohn Forte 	    icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid,
138fcf3ce44SJohn Forte 	    icp->conn_oid) >= sizeof (th_name)) {
139fcf3ce44SJohn Forte 		cv_destroy(&icp->conn_state_change);
140fcf3ce44SJohn Forte 		mutex_destroy(&icp->conn_state_mutex);
141fcf3ce44SJohn Forte 		kmem_free(icp, sizeof (iscsi_conn_t));
14230e7468fSPeter Dunlap 		ddi_taskq_destroy(icp->conn_cn_taskq);
143fcf3ce44SJohn Forte 		*icpp = NULL;
144fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
145fcf3ce44SJohn Forte 	}
146fcf3ce44SJohn Forte 
147fcf3ce44SJohn Forte 	icp->conn_tx_thread = iscsi_thread_create(isp->sess_hba->hba_dip,
148fcf3ce44SJohn Forte 	    th_name, iscsi_tx_thread, icp);
149fcf3ce44SJohn Forte 
150fcf3ce44SJohn Forte 	/* setup connection queues */
151fcf3ce44SJohn Forte 	iscsi_init_queue(&icp->conn_queue_active);
15230e7468fSPeter Dunlap 	iscsi_init_queue(&icp->conn_queue_idm_aborting);
153fcf3ce44SJohn Forte 
154fcf3ce44SJohn Forte 	bcopy(addr, &icp->conn_base_addr, sizeof (icp->conn_base_addr));
155fcf3ce44SJohn Forte 
156fcf3ce44SJohn Forte 	/* Add new connection to the session connection list */
157fcf3ce44SJohn Forte 	icp->conn_cid = isp->sess_conn_next_cid++;
158fcf3ce44SJohn Forte 	if (isp->sess_conn_list == NULL) {
159fcf3ce44SJohn Forte 		isp->sess_conn_list = isp->sess_conn_list_last_ptr = icp;
160fcf3ce44SJohn Forte 	} else {
161fcf3ce44SJohn Forte 		isp->sess_conn_list_last_ptr->conn_next = icp;
162fcf3ce44SJohn Forte 		isp->sess_conn_list_last_ptr = icp;
163fcf3ce44SJohn Forte 	}
164fcf3ce44SJohn Forte 
165fcf3ce44SJohn Forte 	KSTAT_INC_SESS_CNTR_CONN(isp);
166fcf3ce44SJohn Forte 	(void) iscsi_conn_kstat_init(icp);
167fcf3ce44SJohn Forte 
168fcf3ce44SJohn Forte 	*icpp = icp;
169fcf3ce44SJohn Forte 
170fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
171fcf3ce44SJohn Forte }
172fcf3ce44SJohn Forte 
17330e7468fSPeter Dunlap /*
17430e7468fSPeter Dunlap  * iscsi_conn_online - This attempts to take a connection from
17530e7468fSPeter Dunlap  * ISCSI_CONN_STATE_FREE to ISCSI_CONN_STATE_LOGGED_IN.
17630e7468fSPeter Dunlap  */
17730e7468fSPeter Dunlap iscsi_status_t
17830e7468fSPeter Dunlap iscsi_conn_online(iscsi_conn_t *icp)
17930e7468fSPeter Dunlap {
18030e7468fSPeter Dunlap 	iscsi_task_t	*itp;
18130e7468fSPeter Dunlap 	iscsi_status_t	rval;
18230e7468fSPeter Dunlap 
18330e7468fSPeter Dunlap 	ASSERT(icp != NULL);
18430e7468fSPeter Dunlap 	ASSERT(mutex_owned(&icp->conn_state_mutex));
18530e7468fSPeter Dunlap 	ASSERT(icp->conn_state == ISCSI_CONN_STATE_FREE);
18630e7468fSPeter Dunlap 
18730e7468fSPeter Dunlap 	/*
18830e7468fSPeter Dunlap 	 * If we are attempting to connect then for the purposes of the
18930e7468fSPeter Dunlap 	 * other initiator code we are effectively in ISCSI_CONN_STATE_IN_LOGIN.
19030e7468fSPeter Dunlap 	 */
19130e7468fSPeter Dunlap 	iscsi_conn_update_state_locked(icp, ISCSI_CONN_STATE_IN_LOGIN);
19230e7468fSPeter Dunlap 	mutex_exit(&icp->conn_state_mutex);
19330e7468fSPeter Dunlap 
19430e7468fSPeter Dunlap 	/*
19530e7468fSPeter Dunlap 	 * Sync base connection information before login
19630e7468fSPeter Dunlap 	 * A login redirection might have shifted the
19730e7468fSPeter Dunlap 	 * current information from the base.
19830e7468fSPeter Dunlap 	 */
19930e7468fSPeter Dunlap 	bcopy(&icp->conn_base_addr, &icp->conn_curr_addr,
20030e7468fSPeter Dunlap 	    sizeof (icp->conn_curr_addr));
20130e7468fSPeter Dunlap 
20230e7468fSPeter Dunlap 	itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
20330e7468fSPeter Dunlap 	ASSERT(itp != NULL);
20430e7468fSPeter Dunlap 
20530e7468fSPeter Dunlap 	itp->t_arg = icp;
20630e7468fSPeter Dunlap 	itp->t_blocking = B_TRUE;
20730e7468fSPeter Dunlap 	rval = iscsi_login_start(itp);
20830e7468fSPeter Dunlap 	kmem_free(itp, sizeof (iscsi_task_t));
20930e7468fSPeter Dunlap 
21030e7468fSPeter Dunlap 	mutex_enter(&icp->conn_state_mutex);
21130e7468fSPeter Dunlap 
21230e7468fSPeter Dunlap 	return (rval);
21330e7468fSPeter Dunlap }
214fcf3ce44SJohn Forte 
215fcf3ce44SJohn Forte /*
216fcf3ce44SJohn Forte  * iscsi_conn_offline - This attempts to take a connection from
217fcf3ce44SJohn Forte  * any state to ISCSI_CONN_STATE_FREE.
218fcf3ce44SJohn Forte  */
219fcf3ce44SJohn Forte iscsi_status_t
220fcf3ce44SJohn Forte iscsi_conn_offline(iscsi_conn_t *icp)
221fcf3ce44SJohn Forte {
222fcf3ce44SJohn Forte 	clock_t		delay;
223fcf3ce44SJohn Forte 
224fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
225fcf3ce44SJohn Forte 
226fcf3ce44SJohn Forte 	/*
227fcf3ce44SJohn Forte 	 * We can only destroy a connection if its either in
228fcf3ce44SJohn Forte 	 * a state of FREE or LOGGED.  The other states are
229fcf3ce44SJohn Forte 	 * transitionary and its unsafe to perform actions
230fcf3ce44SJohn Forte 	 * on the connection in those states.  Set a flag
231fcf3ce44SJohn Forte 	 * on the connection to influence the transitions
232fcf3ce44SJohn Forte 	 * to quickly complete.  Then wait for a state
233fcf3ce44SJohn Forte 	 * transition.
23430e7468fSPeter Dunlap 	 *
23530e7468fSPeter Dunlap 	 * ISCSI_CONN_STATE_LOGGED_IN is set immediately at the
23630e7468fSPeter Dunlap 	 * start of CN_NOTIFY_FFP processing. icp->conn_state_ffp
23730e7468fSPeter Dunlap 	 * is set to true at the end of ffp processing, at which
23830e7468fSPeter Dunlap 	 * point any session updates are complete.  We don't
23930e7468fSPeter Dunlap 	 * want to start offlining the connection before we're
24030e7468fSPeter Dunlap 	 * done completing the FFP processing since this might
24130e7468fSPeter Dunlap 	 * interrupt the discovery process.
242fcf3ce44SJohn Forte 	 */
243fcf3ce44SJohn Forte 	delay = ddi_get_lbolt() + SEC_TO_TICK(SHUTDOWN_TIMEOUT);
244fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_state_mutex);
245fcf3ce44SJohn Forte 	icp->conn_state_destroy = B_TRUE;
24630e7468fSPeter Dunlap 	while ((((icp->conn_state != ISCSI_CONN_STATE_FREE) &&
24730e7468fSPeter Dunlap 	    (icp->conn_state != ISCSI_CONN_STATE_LOGGED_IN)) ||
24830e7468fSPeter Dunlap 	    ((icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN) &&
24930e7468fSPeter Dunlap 	    !icp->conn_state_ffp)) &&
250fcf3ce44SJohn Forte 	    (ddi_get_lbolt() < delay)) {
251fcf3ce44SJohn Forte 		/* wait for transition */
252fcf3ce44SJohn Forte 		(void) cv_timedwait(&icp->conn_state_change,
253fcf3ce44SJohn Forte 		    &icp->conn_state_mutex, delay);
254fcf3ce44SJohn Forte 	}
255fcf3ce44SJohn Forte 
256fcf3ce44SJohn Forte 	switch (icp->conn_state) {
257fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_FREE:
258fcf3ce44SJohn Forte 		break;
259fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_LOGGED_IN:
26092adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		if (icp->conn_state_ffp) {
26192adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			/* Hold is released in iscsi_handle_logout */
26292adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			idm_conn_hold(icp->conn_ic);
26330e7468fSPeter Dunlap 			(void) iscsi_handle_logout(icp);
26492adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		} else {
26530e7468fSPeter Dunlap 			icp->conn_state_destroy = B_FALSE;
26630e7468fSPeter Dunlap 			mutex_exit(&icp->conn_state_mutex);
26730e7468fSPeter Dunlap 			return (ISCSI_STATUS_INTERNAL_ERROR);
26830e7468fSPeter Dunlap 		}
269fcf3ce44SJohn Forte 		break;
270fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_IN_LOGIN:
271fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_IN_LOGOUT:
272fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_FAILED:
273fcf3ce44SJohn Forte 	case ISCSI_CONN_STATE_POLLING:
274fcf3ce44SJohn Forte 	default:
275fcf3ce44SJohn Forte 		icp->conn_state_destroy = B_FALSE;
276fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
277fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
278fcf3ce44SJohn Forte 	}
279fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_state_mutex);
280fcf3ce44SJohn Forte 
281fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
282fcf3ce44SJohn Forte }
283fcf3ce44SJohn Forte 
284fcf3ce44SJohn Forte /*
285fcf3ce44SJohn Forte  * iscsi_conn_destroy - This destroys an iscsi connection structure
286fcf3ce44SJohn Forte  * and de-associates it with the session.  The connection should
287fcf3ce44SJohn Forte  * already been in the ISCSI_CONN_STATE_FREE when attempting this
288fcf3ce44SJohn Forte  * operation.
289fcf3ce44SJohn Forte  */
290fcf3ce44SJohn Forte iscsi_status_t
291fcf3ce44SJohn Forte iscsi_conn_destroy(iscsi_conn_t *icp)
292fcf3ce44SJohn Forte {
293fcf3ce44SJohn Forte 	iscsi_sess_t	*isp;
294fcf3ce44SJohn Forte 	iscsi_conn_t	*t_icp;
295fcf3ce44SJohn Forte 
296fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
297fcf3ce44SJohn Forte 	isp = icp->conn_sess;
298fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
299fcf3ce44SJohn Forte 
300fcf3ce44SJohn Forte 	if (icp->conn_state != ISCSI_CONN_STATE_FREE) {
301fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
302fcf3ce44SJohn Forte 	}
303fcf3ce44SJohn Forte 
304fcf3ce44SJohn Forte 	/* Destroy transfer thread */
305fcf3ce44SJohn Forte 	iscsi_thread_destroy(icp->conn_tx_thread);
30630e7468fSPeter Dunlap 	ddi_taskq_destroy(icp->conn_cn_taskq);
307fcf3ce44SJohn Forte 
308fcf3ce44SJohn Forte 	/* Terminate connection queues */
30930e7468fSPeter Dunlap 	iscsi_destroy_queue(&icp->conn_queue_idm_aborting);
310fcf3ce44SJohn Forte 	iscsi_destroy_queue(&icp->conn_queue_active);
311fcf3ce44SJohn Forte 
31230e7468fSPeter Dunlap 	cv_destroy(&icp->conn_login_cv);
31330e7468fSPeter Dunlap 	mutex_destroy(&icp->conn_login_mutex);
314fcf3ce44SJohn Forte 	cv_destroy(&icp->conn_state_change);
315fcf3ce44SJohn Forte 	mutex_destroy(&icp->conn_state_mutex);
316fcf3ce44SJohn Forte 
317fcf3ce44SJohn Forte 	/*
318fcf3ce44SJohn Forte 	 * Remove connection from sessions linked list.
319fcf3ce44SJohn Forte 	 */
320fcf3ce44SJohn Forte 	if (isp->sess_conn_list == icp) {
321fcf3ce44SJohn Forte 		/* connection first item in list */
322fcf3ce44SJohn Forte 		isp->sess_conn_list = icp->conn_next;
323fcf3ce44SJohn Forte 		/*
324fcf3ce44SJohn Forte 		 * check if this is also the last item in the list
325fcf3ce44SJohn Forte 		 */
326fcf3ce44SJohn Forte 		if (isp->sess_conn_list_last_ptr == icp) {
327fcf3ce44SJohn Forte 			isp->sess_conn_list_last_ptr = NULL;
328fcf3ce44SJohn Forte 		}
329fcf3ce44SJohn Forte 	} else {
330fcf3ce44SJohn Forte 		/*
331fcf3ce44SJohn Forte 		 * search session list for icp pointing
332fcf3ce44SJohn Forte 		 * to connection being removed.  Then
333fcf3ce44SJohn Forte 		 * update that connections next pointer.
334fcf3ce44SJohn Forte 		 */
335fcf3ce44SJohn Forte 		t_icp = isp->sess_conn_list;
336fcf3ce44SJohn Forte 		while (t_icp->conn_next != NULL) {
337fcf3ce44SJohn Forte 			if (t_icp->conn_next == icp) {
338fcf3ce44SJohn Forte 				break;
339fcf3ce44SJohn Forte 			}
340fcf3ce44SJohn Forte 			t_icp = t_icp->conn_next;
341fcf3ce44SJohn Forte 		}
342fcf3ce44SJohn Forte 		if (t_icp->conn_next == icp) {
343fcf3ce44SJohn Forte 			t_icp->conn_next = icp->conn_next;
344fcf3ce44SJohn Forte 			/*
345fcf3ce44SJohn Forte 			 * if this is the last connection in the list
346fcf3ce44SJohn Forte 			 * update the last_ptr to point to t_icp
347fcf3ce44SJohn Forte 			 */
348fcf3ce44SJohn Forte 			if (isp->sess_conn_list_last_ptr == icp) {
349fcf3ce44SJohn Forte 				isp->sess_conn_list_last_ptr = t_icp;
350fcf3ce44SJohn Forte 			}
351fcf3ce44SJohn Forte 		} else {
352fcf3ce44SJohn Forte 			/* couldn't find session */
353fcf3ce44SJohn Forte 			ASSERT(FALSE);
354fcf3ce44SJohn Forte 		}
355fcf3ce44SJohn Forte 	}
356fcf3ce44SJohn Forte 
357fcf3ce44SJohn Forte 	/* Free this Connections Data */
358fcf3ce44SJohn Forte 	iscsi_conn_kstat_term(icp);
359fcf3ce44SJohn Forte 	kmem_free(icp, sizeof (iscsi_conn_t));
360fcf3ce44SJohn Forte 
361fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
362fcf3ce44SJohn Forte }
363fcf3ce44SJohn Forte 
364fcf3ce44SJohn Forte 
365fcf3ce44SJohn Forte /*
366fcf3ce44SJohn Forte  * iscsi_conn_set_login_min_max - set min/max login window
367fcf3ce44SJohn Forte  *
368fcf3ce44SJohn Forte  * Used to set the min and max login window.  Input values
369fcf3ce44SJohn Forte  * are in seconds.
370fcf3ce44SJohn Forte  */
371fcf3ce44SJohn Forte void
372fcf3ce44SJohn Forte iscsi_conn_set_login_min_max(iscsi_conn_t *icp, int min, int max)
373fcf3ce44SJohn Forte {
374fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
375fcf3ce44SJohn Forte 
376fcf3ce44SJohn Forte 	icp->conn_login_min = ddi_get_lbolt() + SEC_TO_TICK(min);
377fcf3ce44SJohn Forte 	icp->conn_login_max = ddi_get_lbolt() + SEC_TO_TICK(max);
378fcf3ce44SJohn Forte }
379fcf3ce44SJohn Forte 
380fcf3ce44SJohn Forte 
38130e7468fSPeter Dunlap /*
38230e7468fSPeter Dunlap  * Process the idm notifications
38330e7468fSPeter Dunlap  */
38430e7468fSPeter Dunlap idm_status_t
38530e7468fSPeter Dunlap iscsi_client_notify(idm_conn_t *ic, idm_client_notify_t icn, uintptr_t data)
38630e7468fSPeter Dunlap {
38730e7468fSPeter Dunlap 	iscsi_cn_task_t		*cn;
38830e7468fSPeter Dunlap 	iscsi_conn_t		*icp = ic->ic_handle;
38930e7468fSPeter Dunlap 	iscsi_sess_t		*isp;
390fcf3ce44SJohn Forte 
391fcf3ce44SJohn Forte 	/*
39230e7468fSPeter Dunlap 	 * Don't access icp if the notification is CN_CONNECT_DESTROY
39330e7468fSPeter Dunlap 	 * since icp may have already been freed.
394fcf3ce44SJohn Forte 	 *
3955f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	 * In particular, we cannot audit the CN_CONNECT_DESTROY event.
3965f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	 *
3975f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	 * Handle a few cases immediately, the rest in a task queue.
398fcf3ce44SJohn Forte 	 */
39930e7468fSPeter Dunlap 	switch (icn) {
40030e7468fSPeter Dunlap 	case CN_CONNECT_FAIL:
40130e7468fSPeter Dunlap 	case CN_LOGIN_FAIL:
40230e7468fSPeter Dunlap 		/*
40330e7468fSPeter Dunlap 		 * Wakeup any thread waiting for login stuff to happen.
40430e7468fSPeter Dunlap 		 */
40530e7468fSPeter Dunlap 		ASSERT(icp != NULL);
4065f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
4075f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		mutex_enter(&icp->conn_state_mutex);
4085f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		idm_sm_audit_event(&icp->conn_state_audit,
4095f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		    SAS_ISCSI_CONN, icp->conn_state, icn, data);
4105f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		mutex_exit(&icp->conn_state_mutex);
41130e7468fSPeter Dunlap 		iscsi_login_update_state(icp, LOGIN_ERROR);
41230e7468fSPeter Dunlap 		return (IDM_STATUS_SUCCESS);
4135f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
41430e7468fSPeter Dunlap 	case CN_READY_FOR_LOGIN:
41530e7468fSPeter Dunlap 		idm_conn_hold(ic); /* Released in CN_CONNECT_LOST */
4165f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		ASSERT(icp != NULL);
4175f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
41830e7468fSPeter Dunlap 		mutex_enter(&icp->conn_state_mutex);
4195f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		idm_sm_audit_event(&icp->conn_state_audit,
4205f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		    SAS_ISCSI_CONN, icp->conn_state, icn, data);
42130e7468fSPeter Dunlap 		icp->conn_state_idm_connected = B_TRUE;
42230e7468fSPeter Dunlap 		cv_broadcast(&icp->conn_state_change);
42330e7468fSPeter Dunlap 		mutex_exit(&icp->conn_state_mutex);
42430e7468fSPeter Dunlap 
42530e7468fSPeter Dunlap 		iscsi_login_update_state(icp, LOGIN_READY);
42630e7468fSPeter Dunlap 		return (IDM_STATUS_SUCCESS);
4275f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
42830e7468fSPeter Dunlap 	case CN_CONNECT_DESTROY:
42930e7468fSPeter Dunlap 		/*
43030e7468fSPeter Dunlap 		 * We released any dependecies we had on this object in
43130e7468fSPeter Dunlap 		 * either CN_LOGIN_FAIL or CN_CONNECT_LOST so we just need
43230e7468fSPeter Dunlap 		 * to destroy the IDM connection now.
43330e7468fSPeter Dunlap 		 */
43430e7468fSPeter Dunlap 		idm_ini_conn_destroy(ic);
43530e7468fSPeter Dunlap 		return (IDM_STATUS_SUCCESS);
43630e7468fSPeter Dunlap 	}
437fcf3ce44SJohn Forte 
438fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
4395f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	mutex_enter(&icp->conn_state_mutex);
4405f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	idm_sm_audit_event(&icp->conn_state_audit,
4415f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	    SAS_ISCSI_CONN, icp->conn_state, icn, data);
4425f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	mutex_exit(&icp->conn_state_mutex);
44330e7468fSPeter Dunlap 	isp = icp->conn_sess;
444fcf3ce44SJohn Forte 
445fcf3ce44SJohn Forte 	/*
44630e7468fSPeter Dunlap 	 * Dispatch notifications to the taskq since they often require
44730e7468fSPeter Dunlap 	 * long blocking operations.  In the case of CN_CONNECT_DESTROY
44830e7468fSPeter Dunlap 	 * we actually just want to destroy the connection which we
44930e7468fSPeter Dunlap 	 * can't do in the IDM taskq context.
450fcf3ce44SJohn Forte 	 */
45130e7468fSPeter Dunlap 	cn = kmem_alloc(sizeof (*cn), KM_SLEEP);
45230e7468fSPeter Dunlap 
45330e7468fSPeter Dunlap 	cn->ct_ic = ic;
45430e7468fSPeter Dunlap 	cn->ct_icn = icn;
45530e7468fSPeter Dunlap 	cn->ct_data = data;
45630e7468fSPeter Dunlap 
45730e7468fSPeter Dunlap 	idm_conn_hold(ic);
45830e7468fSPeter Dunlap 
45930e7468fSPeter Dunlap 	if (ddi_taskq_dispatch(icp->conn_cn_taskq,
46030e7468fSPeter Dunlap 	    iscsi_client_notify_task, cn, DDI_SLEEP) != DDI_SUCCESS) {
46130e7468fSPeter Dunlap 		idm_conn_rele(ic);
46230e7468fSPeter Dunlap 		cmn_err(CE_WARN, "iscsi connection(%u) failure - "
46330e7468fSPeter Dunlap 		    "unable to schedule notify task", icp->conn_oid);
46430e7468fSPeter Dunlap 		iscsi_conn_update_state(icp, ISCSI_CONN_STATE_FREE);
46530e7468fSPeter Dunlap 		mutex_enter(&isp->sess_state_mutex);
46630e7468fSPeter Dunlap 		iscsi_sess_state_machine(isp,
46730e7468fSPeter Dunlap 		    ISCSI_SESS_EVENT_N6);
46830e7468fSPeter Dunlap 		mutex_exit(&isp->sess_state_mutex);
46930e7468fSPeter Dunlap 	}
47030e7468fSPeter Dunlap 
47130e7468fSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
47230e7468fSPeter Dunlap }
47330e7468fSPeter Dunlap 
47430e7468fSPeter Dunlap static void
47530e7468fSPeter Dunlap iscsi_client_notify_task(void *cn_task_void)
476fcf3ce44SJohn Forte {
47730e7468fSPeter Dunlap 	iscsi_cn_task_t		*cn_task = cn_task_void;
47830e7468fSPeter Dunlap 	iscsi_conn_t		*icp;
47930e7468fSPeter Dunlap 	iscsi_sess_t		*isp;
48030e7468fSPeter Dunlap 	idm_conn_t		*ic;
48130e7468fSPeter Dunlap 	idm_client_notify_t	icn;
48230e7468fSPeter Dunlap 	uintptr_t		data;
48330e7468fSPeter Dunlap 	idm_ffp_disable_t	disable_type;
48430e7468fSPeter Dunlap 	boolean_t		in_login;
48530e7468fSPeter Dunlap 
48630e7468fSPeter Dunlap 	ic = cn_task->ct_ic;
48730e7468fSPeter Dunlap 	icn = cn_task->ct_icn;
48830e7468fSPeter Dunlap 	data = cn_task->ct_data;
48930e7468fSPeter Dunlap 
49030e7468fSPeter Dunlap 	icp = ic->ic_handle;
49130e7468fSPeter Dunlap 	ASSERT(icp != NULL);
49230e7468fSPeter Dunlap 	isp = icp->conn_sess;
49330e7468fSPeter Dunlap 
49430e7468fSPeter Dunlap 	switch (icn) {
49530e7468fSPeter Dunlap 	case CN_FFP_ENABLED:
49630e7468fSPeter Dunlap 		mutex_enter(&icp->conn_state_mutex);
49730e7468fSPeter Dunlap 		icp->conn_async_logout = B_FALSE;
49830e7468fSPeter Dunlap 		icp->conn_state_ffp = B_TRUE;
49930e7468fSPeter Dunlap 		cv_broadcast(&icp->conn_state_change);
50030e7468fSPeter Dunlap 		mutex_exit(&icp->conn_state_mutex);
50130e7468fSPeter Dunlap 
50230e7468fSPeter Dunlap 		/*
50330e7468fSPeter Dunlap 		 * This logic assumes that the IDM login-snooping code
50419944f88Syi zhang - Sun Microsystems - Beijing China 		 * and the initiator login code will agree to go when
50519944f88Syi zhang - Sun Microsystems - Beijing China 		 * the connection is in FFP or final error received.
50619944f88Syi zhang - Sun Microsystems - Beijing China 		 * The reason we do this is that we don't want to process
50719944f88Syi zhang - Sun Microsystems - Beijing China 		 * CN_FFP_DISABLED until CN_FFP_ENABLED has been full handled.
50830e7468fSPeter Dunlap 		 */
50930e7468fSPeter Dunlap 		mutex_enter(&icp->conn_login_mutex);
51019944f88Syi zhang - Sun Microsystems - Beijing China 		while ((icp->conn_login_state != LOGIN_FFP) &&
51119944f88Syi zhang - Sun Microsystems - Beijing China 		    (icp->conn_login_state != LOGIN_ERROR)) {
51230e7468fSPeter Dunlap 			cv_wait(&icp->conn_login_cv, &icp->conn_login_mutex);
51330e7468fSPeter Dunlap 		}
51430e7468fSPeter Dunlap 		mutex_exit(&icp->conn_login_mutex);
51530e7468fSPeter Dunlap 		break;
51630e7468fSPeter Dunlap 	case CN_FFP_DISABLED:
51730e7468fSPeter Dunlap 		disable_type = (idm_ffp_disable_t)data;
51830e7468fSPeter Dunlap 
51930e7468fSPeter Dunlap 		mutex_enter(&icp->conn_state_mutex);
52030e7468fSPeter Dunlap 		switch (disable_type) {
52130e7468fSPeter Dunlap 		case FD_SESS_LOGOUT:
52230e7468fSPeter Dunlap 		case FD_CONN_LOGOUT:
52330e7468fSPeter Dunlap 			if (icp->conn_async_logout) {
52430e7468fSPeter Dunlap 				/*
52530e7468fSPeter Dunlap 				 * Our logout was in response to an
52630e7468fSPeter Dunlap 				 * async logout request so treat this
52730e7468fSPeter Dunlap 				 * like a connection failure (we will
52830e7468fSPeter Dunlap 				 * try to re-establish the connection)
52930e7468fSPeter Dunlap 				 */
53030e7468fSPeter Dunlap 				iscsi_conn_update_state_locked(icp,
53130e7468fSPeter Dunlap 				    ISCSI_CONN_STATE_FAILED);
53230e7468fSPeter Dunlap 			} else {
53330e7468fSPeter Dunlap 				/*
53430e7468fSPeter Dunlap 				 * Logout due to to user config change,
53530e7468fSPeter Dunlap 				 * we will not try to re-establish
53630e7468fSPeter Dunlap 				 * the connection.
53730e7468fSPeter Dunlap 				 */
53830e7468fSPeter Dunlap 				iscsi_conn_update_state_locked(icp,
53930e7468fSPeter Dunlap 				    ISCSI_CONN_STATE_IN_LOGOUT);
54030e7468fSPeter Dunlap 				/*
54130e7468fSPeter Dunlap 				 * Hold off generating the ISCSI_SESS_EVENT_N3
54230e7468fSPeter Dunlap 				 * event until we get the CN_CONNECT_LOST
54330e7468fSPeter Dunlap 				 * notification.  This matches the pre-IDM
54430e7468fSPeter Dunlap 				 * implementation better.
54530e7468fSPeter Dunlap 				 */
54630e7468fSPeter Dunlap 			}
54730e7468fSPeter Dunlap 			break;
54830e7468fSPeter Dunlap 
54930e7468fSPeter Dunlap 		case FD_CONN_FAIL:
550fcf3ce44SJohn Forte 		default:
55119944f88Syi zhang - Sun Microsystems - Beijing China 			if (icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN) {
55219944f88Syi zhang - Sun Microsystems - Beijing China 				iscsi_conn_update_state_locked(icp,
55319944f88Syi zhang - Sun Microsystems - Beijing China 				    ISCSI_CONN_STATE_FREE);
55419944f88Syi zhang - Sun Microsystems - Beijing China 			} else {
55530e7468fSPeter Dunlap 				iscsi_conn_update_state_locked(icp,
55630e7468fSPeter Dunlap 				    ISCSI_CONN_STATE_FAILED);
55719944f88Syi zhang - Sun Microsystems - Beijing China 			}
55830e7468fSPeter Dunlap 			break;
55930e7468fSPeter Dunlap 		}
56030e7468fSPeter Dunlap 
56130e7468fSPeter Dunlap 		icp->conn_state_ffp = B_FALSE;
56230e7468fSPeter Dunlap 		cv_broadcast(&icp->conn_state_change);
56330e7468fSPeter Dunlap 		mutex_exit(&icp->conn_state_mutex);
56430e7468fSPeter Dunlap 
56530e7468fSPeter Dunlap 		break;
56630e7468fSPeter Dunlap 	case CN_CONNECT_LOST:
56730e7468fSPeter Dunlap 		/*
56830e7468fSPeter Dunlap 		 * We only care about CN_CONNECT_LOST if we've logged in.  IDM
56930e7468fSPeter Dunlap 		 * sends a flag as the data payload to indicate whether we
57030e7468fSPeter Dunlap 		 * were trying to login.  The CN_LOGIN_FAIL notification
57130e7468fSPeter Dunlap 		 * gives us what we need to know for login failures and
57230e7468fSPeter Dunlap 		 * otherwise we will need to keep a bunch of state to know
57330e7468fSPeter Dunlap 		 * what CN_CONNECT_LOST means to us.
57430e7468fSPeter Dunlap 		 */
57530e7468fSPeter Dunlap 		in_login = (boolean_t)data;
57619944f88Syi zhang - Sun Microsystems - Beijing China 		if (in_login ||
57719944f88Syi zhang - Sun Microsystems - Beijing China 		    (icp->conn_prev_state == ISCSI_CONN_STATE_IN_LOGIN)) {
57830e7468fSPeter Dunlap 			mutex_enter(&icp->conn_state_mutex);
57930e7468fSPeter Dunlap 
58030e7468fSPeter Dunlap 			icp->conn_state_idm_connected = B_FALSE;
58130e7468fSPeter Dunlap 			cv_broadcast(&icp->conn_state_change);
58230e7468fSPeter Dunlap 			mutex_exit(&icp->conn_state_mutex);
58330e7468fSPeter Dunlap 
58430e7468fSPeter Dunlap 			/* Release connect hold from CN_READY_FOR_LOGIN */
58530e7468fSPeter Dunlap 			idm_conn_rele(ic);
58630e7468fSPeter Dunlap 			break;
58730e7468fSPeter Dunlap 		}
58830e7468fSPeter Dunlap 
58930e7468fSPeter Dunlap 		/* Any remaining commands are never going to finish */
59030e7468fSPeter Dunlap 		iscsi_conn_flush_active_cmds(icp);
59130e7468fSPeter Dunlap 
59230e7468fSPeter Dunlap 		/*
59330e7468fSPeter Dunlap 		 * The connection is no longer active so cleanup any
59430e7468fSPeter Dunlap 		 * references to the connection and release any holds so
59530e7468fSPeter Dunlap 		 * that IDM can finish cleanup.
59630e7468fSPeter Dunlap 		 */
59730e7468fSPeter Dunlap 		mutex_enter(&icp->conn_state_mutex);
59830e7468fSPeter Dunlap 		if (icp->conn_state != ISCSI_CONN_STATE_FAILED) {
59930e7468fSPeter Dunlap 
60030e7468fSPeter Dunlap 			mutex_enter(&isp->sess_state_mutex);
60130e7468fSPeter Dunlap 			iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N3);
60230e7468fSPeter Dunlap 			mutex_exit(&isp->sess_state_mutex);
60330e7468fSPeter Dunlap 
60430e7468fSPeter Dunlap 			iscsi_conn_update_state_locked(icp,
60530e7468fSPeter Dunlap 			    ISCSI_CONN_STATE_FREE);
60630e7468fSPeter Dunlap 		} else {
60730e7468fSPeter Dunlap 
60830e7468fSPeter Dunlap 			mutex_enter(&isp->sess_state_mutex);
60930e7468fSPeter Dunlap 			iscsi_sess_state_machine(isp,
61030e7468fSPeter Dunlap 			    ISCSI_SESS_EVENT_N5);
61130e7468fSPeter Dunlap 			mutex_exit(&isp->sess_state_mutex);
61230e7468fSPeter Dunlap 
61330e7468fSPeter Dunlap 			/*
61430e7468fSPeter Dunlap 			 * If session type is NORMAL, try to reestablish the
61530e7468fSPeter Dunlap 			 * connection.
61630e7468fSPeter Dunlap 			 */
617*cc7ef495Syi zhang - Sun Microsystems - Beijing China 			if ((isp->sess_type == ISCSI_SESS_TYPE_NORMAL) &&
618*cc7ef495Syi zhang - Sun Microsystems - Beijing China 			    !(ISCSI_LOGIN_TPGT_NEGO_ERROR(icp))) {
61930e7468fSPeter Dunlap 				iscsi_conn_retry(isp, icp);
62030e7468fSPeter Dunlap 			} else {
62130e7468fSPeter Dunlap 
62230e7468fSPeter Dunlap 				mutex_enter(&isp->sess_state_mutex);
62330e7468fSPeter Dunlap 				iscsi_sess_state_machine(isp,
62430e7468fSPeter Dunlap 				    ISCSI_SESS_EVENT_N6);
62530e7468fSPeter Dunlap 				mutex_exit(&isp->sess_state_mutex);
62630e7468fSPeter Dunlap 
62730e7468fSPeter Dunlap 				iscsi_conn_update_state_locked(icp,
62830e7468fSPeter Dunlap 				    ISCSI_CONN_STATE_FREE);
629fcf3ce44SJohn Forte 			}
630fcf3ce44SJohn Forte 		}
631fcf3ce44SJohn Forte 
63230e7468fSPeter Dunlap 		(void) iscsi_thread_stop(icp->conn_tx_thread);
63330e7468fSPeter Dunlap 
63430e7468fSPeter Dunlap 		icp->conn_state_idm_connected = B_FALSE;
63530e7468fSPeter Dunlap 		cv_broadcast(&icp->conn_state_change);
63630e7468fSPeter Dunlap 		mutex_exit(&icp->conn_state_mutex);
63730e7468fSPeter Dunlap 
63830e7468fSPeter Dunlap 		/* Release connect hold from CN_READY_FOR_LOGIN */
63930e7468fSPeter Dunlap 		idm_conn_rele(ic);
64030e7468fSPeter Dunlap 		break;
64130e7468fSPeter Dunlap 	default:
64230e7468fSPeter Dunlap 		ISCSI_CONN_LOG(CE_WARN,
64330e7468fSPeter Dunlap 		    "iscsi_client_notify: unknown notification: "
64430e7468fSPeter Dunlap 		    "%x: NOT IMPLEMENTED YET: icp: %p ic: %p ",
64530e7468fSPeter Dunlap 		    icn, (void *)icp, (void *)ic);
64630e7468fSPeter Dunlap 		break;
64730e7468fSPeter Dunlap 	}
64830e7468fSPeter Dunlap 	/* free the task notify structure we allocated in iscsi_client_notify */
64930e7468fSPeter Dunlap 	kmem_free(cn_task, sizeof (*cn_task));
65030e7468fSPeter Dunlap 
65130e7468fSPeter Dunlap 	/* Release the hold we acquired in iscsi_client_notify */
65230e7468fSPeter Dunlap 	idm_conn_rele(ic);
65330e7468fSPeter Dunlap }
654fcf3ce44SJohn Forte 
655fcf3ce44SJohn Forte /*
656fcf3ce44SJohn Forte  * iscsi_conn_sync_params - used to update connection parameters
657fcf3ce44SJohn Forte  *
658fcf3ce44SJohn Forte  * Used to update connection parameters with current configured
659fcf3ce44SJohn Forte  * parameters in the persistent store.  This should be called
660fcf3ce44SJohn Forte  * before starting to make a new iscsi connection in iscsi_login.
661fcf3ce44SJohn Forte  */
662fcf3ce44SJohn Forte iscsi_status_t
663fcf3ce44SJohn Forte iscsi_conn_sync_params(iscsi_conn_t *icp)
664fcf3ce44SJohn Forte {
665fcf3ce44SJohn Forte 	iscsi_sess_t		*isp;
666fcf3ce44SJohn Forte 	iscsi_hba_t		*ihp;
667fcf3ce44SJohn Forte 	int			param_id;
668fcf3ce44SJohn Forte 	persistent_param_t	pp;
669aff4bce5Syi zhang - Sun Microsystems - Beijing China 	persistent_tunable_param_t	ptp;
670fcf3ce44SJohn Forte 	iscsi_config_sess_t	*ics;
671fcf3ce44SJohn Forte 	int			idx, size;
672fcf3ce44SJohn Forte 	char			*name;
673fcf3ce44SJohn Forte 
674fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
675fcf3ce44SJohn Forte 	ASSERT((icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN) ||
676fcf3ce44SJohn Forte 	    (icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
677fcf3ce44SJohn Forte 	    (icp->conn_state == ISCSI_CONN_STATE_POLLING));
678fcf3ce44SJohn Forte 	isp = icp->conn_sess;
679fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
680fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
681fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
682fcf3ce44SJohn Forte 
683fcf3ce44SJohn Forte 	/*
684fcf3ce44SJohn Forte 	 * Check if someone is trying to destroy this
685fcf3ce44SJohn Forte 	 * connection.  If so fail the sync request,
686fcf3ce44SJohn Forte 	 * as a method of fast fail.
687fcf3ce44SJohn Forte 	 */
688fcf3ce44SJohn Forte 	if (icp->conn_state_destroy == B_TRUE) {
689fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SHUTDOWN);
690fcf3ce44SJohn Forte 	}
691fcf3ce44SJohn Forte 
692fcf3ce44SJohn Forte 	bzero(&pp, sizeof (pp));
693fcf3ce44SJohn Forte 
694fcf3ce44SJohn Forte 	/* First get a copy of the HBA params */
695fcf3ce44SJohn Forte 	bcopy(&ihp->hba_params, &icp->conn_params,
696fcf3ce44SJohn Forte 	    sizeof (iscsi_login_params_t));
697aff4bce5Syi zhang - Sun Microsystems - Beijing China 	bcopy(&ihp->hba_tunable_params, &icp->conn_tunable_params,
698aff4bce5Syi zhang - Sun Microsystems - Beijing China 	    sizeof (iscsi_tunable_params_t));
699fcf3ce44SJohn Forte 
700fcf3ce44SJohn Forte 	/*
701fcf3ce44SJohn Forte 	 * Now we need to get the session configured
702fcf3ce44SJohn Forte 	 * values from the persistent store and apply
703fcf3ce44SJohn Forte 	 * them to our connection.
704fcf3ce44SJohn Forte 	 */
705fcf3ce44SJohn Forte 	(void) persistent_param_get((char *)isp->sess_name, &pp);
706fcf3ce44SJohn Forte 	for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM;
707fcf3ce44SJohn Forte 	    param_id++) {
7086cefaae1SJack Meng 		if (iscsiboot_prop && modrootloaded &&
7096cefaae1SJack Meng 		    !iscsi_chk_bootlun_mpxio(ihp) && isp->sess_boot) {
7106cefaae1SJack Meng 			/*
7116cefaae1SJack Meng 			 * iscsi boot with mpxio disabled
7126cefaae1SJack Meng 			 * while iscsi booting target's parameter overriden
7136cefaae1SJack Meng 			 * do no update target's parameters.
7146cefaae1SJack Meng 			 */
7156cefaae1SJack Meng 			if (pp.p_bitmap) {
7166cefaae1SJack Meng 				cmn_err(CE_NOTE, "Adopting "
7176cefaae1SJack Meng 				    " default login parameters in"
7186cefaae1SJack Meng 				    " boot session as MPxIO is disabled");
7196cefaae1SJack Meng 			}
7206cefaae1SJack Meng 			break;
7216cefaae1SJack Meng 		}
722fcf3ce44SJohn Forte 		if (pp.p_bitmap & (1 << param_id)) {
72330e7468fSPeter Dunlap 
724fcf3ce44SJohn Forte 			switch (param_id) {
725fcf3ce44SJohn Forte 			/*
726fcf3ce44SJohn Forte 			 * Boolean parameters
727fcf3ce44SJohn Forte 			 */
728fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER:
729fcf3ce44SJohn Forte 				icp->conn_params.data_pdu_in_order =
730fcf3ce44SJohn Forte 				    pp.p_params.data_pdu_in_order;
731fcf3ce44SJohn Forte 				break;
732fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA:
733fcf3ce44SJohn Forte 				icp->conn_params.immediate_data =
734fcf3ce44SJohn Forte 				    pp.p_params.immediate_data;
735fcf3ce44SJohn Forte 				break;
736fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_INITIAL_R2T:
737fcf3ce44SJohn Forte 				icp->conn_params.initial_r2t =
738fcf3ce44SJohn Forte 				    pp.p_params.initial_r2t;
739fcf3ce44SJohn Forte 				break;
740fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER:
741fcf3ce44SJohn Forte 				icp->conn_params.data_pdu_in_order =
742fcf3ce44SJohn Forte 				    pp.p_params.data_pdu_in_order;
743fcf3ce44SJohn Forte 				break;
744fcf3ce44SJohn Forte 			/*
745fcf3ce44SJohn Forte 			 * Integer parameters
746fcf3ce44SJohn Forte 			 */
747fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_HEADER_DIGEST:
748fcf3ce44SJohn Forte 				icp->conn_params.header_digest =
749fcf3ce44SJohn Forte 				    pp.p_params.header_digest;
750fcf3ce44SJohn Forte 				break;
751fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_DATA_DIGEST:
752fcf3ce44SJohn Forte 				icp->conn_params.data_digest =
753fcf3ce44SJohn Forte 				    pp.p_params.data_digest;
754fcf3ce44SJohn Forte 				break;
755fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN:
756fcf3ce44SJohn Forte 				icp->conn_params.default_time_to_retain =
757fcf3ce44SJohn Forte 				    pp.p_params.default_time_to_retain;
758fcf3ce44SJohn Forte 				break;
759fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT:
760fcf3ce44SJohn Forte 				icp->conn_params.default_time_to_wait =
761fcf3ce44SJohn Forte 				    pp.p_params.default_time_to_wait;
762fcf3ce44SJohn Forte 				break;
763fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH:
764fcf3ce44SJohn Forte 				icp->conn_params.max_recv_data_seg_len =
765fcf3ce44SJohn Forte 				    pp.p_params.max_recv_data_seg_len;
766fcf3ce44SJohn Forte 				break;
767fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH:
768fcf3ce44SJohn Forte 				icp->conn_params.first_burst_length =
769fcf3ce44SJohn Forte 				    pp.p_params.first_burst_length;
770fcf3ce44SJohn Forte 				break;
771fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH:
772fcf3ce44SJohn Forte 				icp->conn_params.max_burst_length =
773fcf3ce44SJohn Forte 				    pp.p_params.max_burst_length;
774fcf3ce44SJohn Forte 				break;
775fcf3ce44SJohn Forte 
776fcf3ce44SJohn Forte 			/*
777fcf3ce44SJohn Forte 			 * Integer parameters which currently are unsettable
778fcf3ce44SJohn Forte 			 */
779fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS:
780fcf3ce44SJohn Forte 				/* FALLTHRU */
781fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T:
782fcf3ce44SJohn Forte 				/* FALLTHRU */
783fcf3ce44SJohn Forte 			case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL:
784fcf3ce44SJohn Forte 				/* FALLTHRU */
785fcf3ce44SJohn Forte 			default:
786fcf3ce44SJohn Forte 				break;
787fcf3ce44SJohn Forte 			}
788fcf3ce44SJohn Forte 		}
789fcf3ce44SJohn Forte 	}
790fcf3ce44SJohn Forte 
791aff4bce5Syi zhang - Sun Microsystems - Beijing China 	if (persistent_get_tunable_param((char *)isp->sess_name, &ptp) ==
792aff4bce5Syi zhang - Sun Microsystems - Beijing China 	    B_TRUE) {
793aff4bce5Syi zhang - Sun Microsystems - Beijing China 		if (ptp.p_bitmap & ISCSI_TUNABLE_PARAM_RX_TIMEOUT_VALUE) {
794aff4bce5Syi zhang - Sun Microsystems - Beijing China 			icp->conn_tunable_params.recv_login_rsp_timeout =
795aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    ptp.p_params.recv_login_rsp_timeout;
796aff4bce5Syi zhang - Sun Microsystems - Beijing China 		}
797aff4bce5Syi zhang - Sun Microsystems - Beijing China 		if (ptp.p_bitmap & ISCSI_TUNABLE_PARAM_CONN_LOGIN_MAX) {
798aff4bce5Syi zhang - Sun Microsystems - Beijing China 			icp->conn_tunable_params.conn_login_max =
799aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    ptp.p_params.conn_login_max;
800aff4bce5Syi zhang - Sun Microsystems - Beijing China 		}
801aff4bce5Syi zhang - Sun Microsystems - Beijing China 		if (ptp.p_bitmap & ISCSI_TUNABLE_PARAM_LOGIN_POLLING_DELAY) {
802aff4bce5Syi zhang - Sun Microsystems - Beijing China 			icp->conn_tunable_params.polling_login_delay =
803aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    ptp.p_params.polling_login_delay;
804aff4bce5Syi zhang - Sun Microsystems - Beijing China 		}
805aff4bce5Syi zhang - Sun Microsystems - Beijing China 	}
806aff4bce5Syi zhang - Sun Microsystems - Beijing China 
807fcf3ce44SJohn Forte 	/* Skip binding checks on discovery sessions */
808fcf3ce44SJohn Forte 	if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) {
809fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SUCCESS);
810fcf3ce44SJohn Forte 	}
811fcf3ce44SJohn Forte 
812fcf3ce44SJohn Forte 	/*
813fcf3ce44SJohn Forte 	 * Now we need to get the current optional connection
814fcf3ce44SJohn Forte 	 * binding information.
815fcf3ce44SJohn Forte 	 */
816fcf3ce44SJohn Forte 	/* setup initial buffer for configured session information */
817fcf3ce44SJohn Forte 	size = sizeof (*ics);
818fcf3ce44SJohn Forte 	ics = kmem_zalloc(size, KM_SLEEP);
819fcf3ce44SJohn Forte 	ics->ics_in = 1;
820fcf3ce44SJohn Forte 
821fcf3ce44SJohn Forte 	/* get configured sessions information */
822fcf3ce44SJohn Forte 	name = (char *)isp->sess_name;
823fcf3ce44SJohn Forte 	if (persistent_get_config_session(name, ics) == B_FALSE) {
824fcf3ce44SJohn Forte 		/*
825fcf3ce44SJohn Forte 		 * If we were unable to get target level information
826fcf3ce44SJohn Forte 		 * then check the initiator level information.
827fcf3ce44SJohn Forte 		 */
828fcf3ce44SJohn Forte 		name = (char *)isp->sess_hba->hba_name;
829fcf3ce44SJohn Forte 		if (persistent_get_config_session(name, ics) == B_FALSE) {
830fcf3ce44SJohn Forte 			/*
831fcf3ce44SJohn Forte 			 * No hba information is found.  So assume default
832fcf3ce44SJohn Forte 			 * one session unbound behavior.
833fcf3ce44SJohn Forte 			 */
834fcf3ce44SJohn Forte 			ics->ics_out = 1;
835fcf3ce44SJohn Forte 			ics->ics_bound = B_FALSE;
836fcf3ce44SJohn Forte 		}
837fcf3ce44SJohn Forte 	}
838fcf3ce44SJohn Forte 
8396cefaae1SJack Meng 	if (iscsiboot_prop && (ics->ics_out > 1) && isp->sess_boot &&
8406cefaae1SJack Meng 	    !iscsi_chk_bootlun_mpxio(ihp)) {
8416cefaae1SJack Meng 		/*
8426cefaae1SJack Meng 		 * iscsi booting session with mpxio disabled,
8436cefaae1SJack Meng 		 * no need set multiple sessions for booting session
8446cefaae1SJack Meng 		 */
8456cefaae1SJack Meng 		ics->ics_out = 1;
8466cefaae1SJack Meng 		ics->ics_bound = B_FALSE;
8476cefaae1SJack Meng 		cmn_err(CE_NOTE, "MPxIO is disabled,"
8486cefaae1SJack Meng 		    " no need to configure multiple boot sessions");
8496cefaae1SJack Meng 	}
8506cefaae1SJack Meng 
851fcf3ce44SJohn Forte 	/*
852fcf3ce44SJohn Forte 	 * Check to make sure this session is still a configured
853fcf3ce44SJohn Forte 	 * session.  The user might have decreased the session
854fcf3ce44SJohn Forte 	 * count. (NOTE: byte 5 of the sess_isid is the session
855fcf3ce44SJohn Forte 	 * count (via MS/T).  This counter starts at 0.)
856fcf3ce44SJohn Forte 	 */
8576cefaae1SJack Meng 
8586cefaae1SJack Meng 
859fcf3ce44SJohn Forte 	idx = isp->sess_isid[5];
8606cefaae1SJack Meng 
8616cefaae1SJack Meng 	if (iscsiboot_prop && (idx == ISCSI_MAX_CONFIG_SESSIONS)) {
8626cefaae1SJack Meng 		/*
8636cefaae1SJack Meng 		 * This is temporary session for boot session propose
8646cefaae1SJack Meng 		 * no need to bound IP for this session
8656cefaae1SJack Meng 		 */
8666cefaae1SJack Meng 		icp->conn_bound = B_FALSE;
8676cefaae1SJack Meng 		kmem_free(ics, sizeof (iscsi_config_sess_t));
8686cefaae1SJack Meng 		return (ISCSI_STATUS_SUCCESS);
8696cefaae1SJack Meng 	}
8706cefaae1SJack Meng 
871fcf3ce44SJohn Forte 	if (ics->ics_out <= idx) {
872fcf3ce44SJohn Forte 		/*
873fcf3ce44SJohn Forte 		 * No longer a configured session.  Return a
874fcf3ce44SJohn Forte 		 * failure so we don't attempt to relogin.
875fcf3ce44SJohn Forte 		 */
876fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SHUTDOWN);
877fcf3ce44SJohn Forte 	}
878fcf3ce44SJohn Forte 
879fcf3ce44SJohn Forte 	/*
880fcf3ce44SJohn Forte 	 * If sessions are unbound set this information on
881fcf3ce44SJohn Forte 	 * the connection and return success.
882fcf3ce44SJohn Forte 	 */
883fcf3ce44SJohn Forte 	if (ics->ics_bound == B_FALSE) {
884fcf3ce44SJohn Forte 		icp->conn_bound = B_FALSE;
885fcf3ce44SJohn Forte 		kmem_free(ics, sizeof (iscsi_config_sess_t));
886fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SUCCESS);
887fcf3ce44SJohn Forte 	}
888fcf3ce44SJohn Forte 
889fcf3ce44SJohn Forte 	/*
890fcf3ce44SJohn Forte 	 * Since the sessions are bound we need to find the matching
891fcf3ce44SJohn Forte 	 * binding information for the session's isid.  If this
892fcf3ce44SJohn Forte 	 * session's isid is > 0 then we need to get more configured
893fcf3ce44SJohn Forte 	 * session information to find the binding info.
894fcf3ce44SJohn Forte 	 */
895fcf3ce44SJohn Forte 	if (idx > 0) {
896fcf3ce44SJohn Forte 		int ics_out;
897fcf3ce44SJohn Forte 
898fcf3ce44SJohn Forte 		ics_out = ics->ics_out;
899fcf3ce44SJohn Forte 		/* record new size and free last buffer */
900fcf3ce44SJohn Forte 		size = ISCSI_SESSION_CONFIG_SIZE(ics_out);
901fcf3ce44SJohn Forte 		kmem_free(ics, sizeof (*ics));
902fcf3ce44SJohn Forte 
903fcf3ce44SJohn Forte 		/* allocate new buffer */
904fcf3ce44SJohn Forte 		ics = kmem_zalloc(size, KM_SLEEP);
905fcf3ce44SJohn Forte 		ics->ics_in = ics_out;
906fcf3ce44SJohn Forte 
907fcf3ce44SJohn Forte 		/* get configured sessions information */
908fcf3ce44SJohn Forte 		if (persistent_get_config_session(name, ics) != B_TRUE) {
909fcf3ce44SJohn Forte 			cmn_err(CE_NOTE, "iscsi session(%d) - "
910fcf3ce44SJohn Forte 			    "unable to get configured session information\n",
911fcf3ce44SJohn Forte 			    isp->sess_oid);
912fcf3ce44SJohn Forte 			kmem_free(ics, size);
913fcf3ce44SJohn Forte 			return (ISCSI_STATUS_SHUTDOWN);
914fcf3ce44SJohn Forte 		}
915fcf3ce44SJohn Forte 	}
916fcf3ce44SJohn Forte 
917fcf3ce44SJohn Forte 	/* Copy correct binding information to the connection */
918fcf3ce44SJohn Forte 	icp->conn_bound = B_TRUE;
919fcf3ce44SJohn Forte 	if (ics->ics_bindings[idx].i_insize == sizeof (struct in_addr)) {
920fcf3ce44SJohn Forte 		bcopy(&ics->ics_bindings[idx].i_addr.in4,
921fcf3ce44SJohn Forte 		    &icp->conn_bound_addr.sin4.sin_addr.s_addr,
922fcf3ce44SJohn Forte 		    sizeof (struct in_addr));
9231050fd6dSJames Moore 		icp->conn_bound_addr.sin4.sin_family = AF_INET;
924fcf3ce44SJohn Forte 	} else {
925fcf3ce44SJohn Forte 		bcopy(&ics->ics_bindings[idx].i_addr.in6,
926fcf3ce44SJohn Forte 		    &icp->conn_bound_addr.sin6.sin6_addr.s6_addr,
927fcf3ce44SJohn Forte 		    sizeof (struct in6_addr));
9281050fd6dSJames Moore 		icp->conn_bound_addr.sin6.sin6_family = AF_INET6;
929fcf3ce44SJohn Forte 	}
930fcf3ce44SJohn Forte 
931fcf3ce44SJohn Forte 	kmem_free(ics, size);
932fcf3ce44SJohn Forte 
933fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
934fcf3ce44SJohn Forte }
935fcf3ce44SJohn Forte 
936fcf3ce44SJohn Forte /*
937fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
938fcf3ce44SJohn Forte  * | Internal Connection Interfaces					|
939fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
940fcf3ce44SJohn Forte  */
941fcf3ce44SJohn Forte 
942fcf3ce44SJohn Forte /*
943fcf3ce44SJohn Forte  * iscsi_conn_flush_active_cmds - flush all active icmdps
944fcf3ce44SJohn Forte  *	for a connection.
945fcf3ce44SJohn Forte  */
946fcf3ce44SJohn Forte static void
947fcf3ce44SJohn Forte iscsi_conn_flush_active_cmds(iscsi_conn_t *icp)
948fcf3ce44SJohn Forte {
949fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp;
950fcf3ce44SJohn Forte 	iscsi_sess_t	*isp;
951fcf3ce44SJohn Forte 	boolean_t	lock_held = B_FALSE;
952fcf3ce44SJohn Forte 
953fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
954fcf3ce44SJohn Forte 	isp = icp->conn_sess;
955fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
956fcf3ce44SJohn Forte 
957fcf3ce44SJohn Forte 	if (mutex_owned(&icp->conn_queue_active.mutex)) {
958fcf3ce44SJohn Forte 		lock_held = B_TRUE;
959fcf3ce44SJohn Forte 	} else {
960fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_queue_active.mutex);
961fcf3ce44SJohn Forte 	}
962fcf3ce44SJohn Forte 
963fcf3ce44SJohn Forte 	/* Flush active queue */
964fcf3ce44SJohn Forte 	icmdp = icp->conn_queue_active.head;
965fcf3ce44SJohn Forte 	while (icmdp != NULL) {
9662b79d384Sbing zhao - Sun Microsystems - Beijing China 
9672b79d384Sbing zhao - Sun Microsystems - Beijing China 		mutex_enter(&icmdp->cmd_mutex);
9682b79d384Sbing zhao - Sun Microsystems - Beijing China 		if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
9692b79d384Sbing zhao - Sun Microsystems - Beijing China 			icmdp->cmd_un.scsi.pkt_stat |= STAT_ABORTED;
9702b79d384Sbing zhao - Sun Microsystems - Beijing China 		}
9712b79d384Sbing zhao - Sun Microsystems - Beijing China 		mutex_exit(&icmdp->cmd_mutex);
9722b79d384Sbing zhao - Sun Microsystems - Beijing China 
973fcf3ce44SJohn Forte 		iscsi_cmd_state_machine(icmdp,
974fcf3ce44SJohn Forte 		    ISCSI_CMD_EVENT_E7, isp);
975fcf3ce44SJohn Forte 		icmdp = icp->conn_queue_active.head;
976fcf3ce44SJohn Forte 	}
977fcf3ce44SJohn Forte 
97830e7468fSPeter Dunlap 	/* Wait for active queue to drain */
97930e7468fSPeter Dunlap 	while (icp->conn_queue_active.count) {
98030e7468fSPeter Dunlap 		mutex_exit(&icp->conn_queue_active.mutex);
98130e7468fSPeter Dunlap 		delay(drv_usectohz(100000));
98230e7468fSPeter Dunlap 		mutex_enter(&icp->conn_queue_active.mutex);
98330e7468fSPeter Dunlap 	}
98430e7468fSPeter Dunlap 
985fcf3ce44SJohn Forte 	if (lock_held == B_FALSE) {
986fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
987fcf3ce44SJohn Forte 	}
98830e7468fSPeter Dunlap 
98930e7468fSPeter Dunlap 	/* Wait for IDM abort queue to drain (if necessary) */
99030e7468fSPeter Dunlap 	mutex_enter(&icp->conn_queue_idm_aborting.mutex);
99130e7468fSPeter Dunlap 	while (icp->conn_queue_idm_aborting.count) {
99230e7468fSPeter Dunlap 		mutex_exit(&icp->conn_queue_idm_aborting.mutex);
99330e7468fSPeter Dunlap 		delay(drv_usectohz(100000));
99430e7468fSPeter Dunlap 		mutex_enter(&icp->conn_queue_idm_aborting.mutex);
995fcf3ce44SJohn Forte 	}
99630e7468fSPeter Dunlap 	mutex_exit(&icp->conn_queue_idm_aborting.mutex);
997fcf3ce44SJohn Forte }
998fcf3ce44SJohn Forte 
999fcf3ce44SJohn Forte /*
1000fcf3ce44SJohn Forte  * iscsi_conn_retry - retry connect/login
1001fcf3ce44SJohn Forte  */
100230e7468fSPeter Dunlap void
1003fcf3ce44SJohn Forte iscsi_conn_retry(iscsi_sess_t *isp, iscsi_conn_t *icp)
1004fcf3ce44SJohn Forte {
1005fcf3ce44SJohn Forte 	iscsi_task_t *itp;
1006fcf3ce44SJohn Forte 
1007fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1008fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1009fcf3ce44SJohn Forte 
1010fcf3ce44SJohn Forte 	/* set login min/max time values */
1011fcf3ce44SJohn Forte 	iscsi_conn_set_login_min_max(icp,
1012fcf3ce44SJohn Forte 	    ISCSI_CONN_DEFAULT_LOGIN_MIN,
1013aff4bce5Syi zhang - Sun Microsystems - Beijing China 	    icp->conn_tunable_params.conn_login_max);
1014fcf3ce44SJohn Forte 
101530e7468fSPeter Dunlap 	ISCSI_CONN_LOG(CE_NOTE, "DEBUG: iscsi_conn_retry: icp: %p icp: %p ",
101630e7468fSPeter Dunlap 	    (void *)icp,
101730e7468fSPeter Dunlap 	    (void *)icp->conn_ic);
101830e7468fSPeter Dunlap 
1019fcf3ce44SJohn Forte 	/*
1020fcf3ce44SJohn Forte 	 * Sync base connection information before login.
1021fcf3ce44SJohn Forte 	 * A login redirection might have shifted the
1022fcf3ce44SJohn Forte 	 * current information from the base.
1023fcf3ce44SJohn Forte 	 */
1024fcf3ce44SJohn Forte 	bcopy(&icp->conn_base_addr, &icp->conn_curr_addr,
1025fcf3ce44SJohn Forte 	    sizeof (icp->conn_curr_addr));
1026fcf3ce44SJohn Forte 
1027fcf3ce44SJohn Forte 	/* schedule login task */
1028fcf3ce44SJohn Forte 	itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
1029fcf3ce44SJohn Forte 	itp->t_arg = icp;
1030fcf3ce44SJohn Forte 	itp->t_blocking = B_FALSE;
1031fcf3ce44SJohn Forte 	if (ddi_taskq_dispatch(isp->sess_taskq,
1032fcf3ce44SJohn Forte 	    (void(*)())iscsi_login_start, itp, DDI_SLEEP) !=
1033fcf3ce44SJohn Forte 	    DDI_SUCCESS) {
1034fcf3ce44SJohn Forte 		kmem_free(itp, sizeof (iscsi_task_t));
103530e7468fSPeter Dunlap 		cmn_err(CE_WARN, "iscsi connection(%u) failure - "
103630e7468fSPeter Dunlap 		    "unable to schedule login task", icp->conn_oid);
1037fcf3ce44SJohn Forte 
103830e7468fSPeter Dunlap 		iscsi_conn_update_state(icp, ISCSI_CONN_STATE_FREE);
1039fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_state_mutex);
1040fcf3ce44SJohn Forte 		iscsi_sess_state_machine(isp,
1041fcf3ce44SJohn Forte 		    ISCSI_SESS_EVENT_N6);
1042fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
1043fcf3ce44SJohn Forte 	}
1044fcf3ce44SJohn Forte }
104530e7468fSPeter Dunlap 
104630e7468fSPeter Dunlap void
104730e7468fSPeter Dunlap iscsi_conn_update_state(iscsi_conn_t *icp, iscsi_conn_state_t
104830e7468fSPeter Dunlap 			    next_state)
104930e7468fSPeter Dunlap {
105030e7468fSPeter Dunlap 	mutex_enter(&icp->conn_state_mutex);
105130e7468fSPeter Dunlap 	(void) iscsi_conn_update_state_locked(icp, next_state);
105230e7468fSPeter Dunlap 	mutex_exit(&icp->conn_state_mutex);
105330e7468fSPeter Dunlap }
105430e7468fSPeter Dunlap 
105530e7468fSPeter Dunlap void
105630e7468fSPeter Dunlap iscsi_conn_update_state_locked(iscsi_conn_t *icp,
105730e7468fSPeter Dunlap 	    iscsi_conn_state_t next_state)
105830e7468fSPeter Dunlap {
105930e7468fSPeter Dunlap 	ASSERT(mutex_owned(&icp->conn_state_mutex));
106030e7468fSPeter Dunlap 	next_state = (next_state > ISCSI_CONN_STATE_MAX) ?
106130e7468fSPeter Dunlap 	    ISCSI_CONN_STATE_MAX : next_state;
106230e7468fSPeter Dunlap 	idm_sm_audit_state_change(&icp->conn_state_audit,
106330e7468fSPeter Dunlap 	    SAS_ISCSI_CONN, icp->conn_state, next_state);
106430e7468fSPeter Dunlap 	switch (next_state) {
106530e7468fSPeter Dunlap 	case ISCSI_CONN_STATE_FREE:
106630e7468fSPeter Dunlap 	case ISCSI_CONN_STATE_IN_LOGIN:
106730e7468fSPeter Dunlap 	case ISCSI_CONN_STATE_LOGGED_IN:
106830e7468fSPeter Dunlap 	case ISCSI_CONN_STATE_IN_LOGOUT:
106930e7468fSPeter Dunlap 	case ISCSI_CONN_STATE_FAILED:
107030e7468fSPeter Dunlap 	case ISCSI_CONN_STATE_POLLING:
107130e7468fSPeter Dunlap 		ISCSI_CONN_LOG(CE_NOTE,
107230e7468fSPeter Dunlap 		    "iscsi_conn_update_state conn %p %s(%d) -> %s(%d)",
107330e7468fSPeter Dunlap 		    (void *)icp,
107430e7468fSPeter Dunlap 		    iscsi_ics_name[icp->conn_state], icp->conn_state,
107530e7468fSPeter Dunlap 		    iscsi_ics_name[next_state], next_state);
107630e7468fSPeter Dunlap 		icp->conn_prev_state = icp->conn_state;
107730e7468fSPeter Dunlap 		icp->conn_state = next_state;
107830e7468fSPeter Dunlap 		cv_broadcast(&icp->conn_state_change);
107930e7468fSPeter Dunlap 		break;
108030e7468fSPeter Dunlap 	default:
108130e7468fSPeter Dunlap 		cmn_err(CE_WARN, "Update state found illegal state: %x "
108230e7468fSPeter Dunlap 		    "prev_state: %x", next_state, icp->conn_prev_state);
108330e7468fSPeter Dunlap 		ASSERT(0);
108430e7468fSPeter Dunlap 	}
108530e7468fSPeter Dunlap }
1086