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 /*
22904e51f6SJack Meng  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23fcf3ce44SJohn Forte  *
24fcf3ce44SJohn Forte  * iSCSI session interfaces
25fcf3ce44SJohn Forte  */
26fcf3ce44SJohn Forte 
276cefaae1SJack Meng #include <sys/bootprops.h>
28fcf3ce44SJohn Forte #include "iscsi.h"
29fcf3ce44SJohn Forte #include "persistent.h"
30fcf3ce44SJohn Forte #include "iscsi_targetparam.h"
31fcf3ce44SJohn Forte 
32fcf3ce44SJohn Forte #define	ISCSI_SESS_ENUM_TIMEOUT_DEFAULT	60
33fcf3ce44SJohn Forte #define	SCSI_INQUIRY_PQUAL_MASK 0xE0
34fcf3ce44SJohn Forte 
3530e7468fSPeter Dunlap boolean_t iscsi_sess_logging = B_FALSE;
36fcf3ce44SJohn Forte /*
37fcf3ce44SJohn Forte  * used to store report lun information found
38fcf3ce44SJohn Forte  *
39fcf3ce44SJohn Forte  * lun_valid:	if TRUE means the entry contains a valid entry
40fcf3ce44SJohn Forte  * lun_found:	if TRUE means the lun has been found in the sess_lun_list
41fcf3ce44SJohn Forte  * lun_num:	contains the lun_number
42904e51f6SJack Meng  * lun_addr_type:	indicates lun's type of addressing
43fcf3ce44SJohn Forte  */
44fcf3ce44SJohn Forte typedef	struct replun_data {
45fcf3ce44SJohn Forte 	boolean_t	lun_valid;
46fcf3ce44SJohn Forte 	boolean_t	lun_found;
47fcf3ce44SJohn Forte 	uint16_t	lun_num;
48904e51f6SJack Meng 	uint8_t		lun_addr_type;
49fcf3ce44SJohn Forte } replun_data_t;
50fcf3ce44SJohn Forte 
51fcf3ce44SJohn Forte int	iscsi_sess_enum_timeout = ISCSI_SESS_ENUM_TIMEOUT_DEFAULT;
52fcf3ce44SJohn Forte 
53fcf3ce44SJohn Forte /*
54fcf3ce44SJohn Forte  * The following private tunable, settable via
55fcf3ce44SJohn Forte  *      set iscsi:iscsi_sess_max_delay = 64
56fcf3ce44SJohn Forte  * in /etc/system, provides customer relief for configurations max interval in
57fcf3ce44SJohn Forte  * seconds of retry for a unreachable target during the login.
58fcf3ce44SJohn Forte  */
59fcf3ce44SJohn Forte int	iscsi_sess_max_delay = ISCSI_DEFAULT_MAX_STORM_DELAY;
60fcf3ce44SJohn Forte 
61904e51f6SJack Meng /*
62904e51f6SJack Meng  * Warning messages for the session scsi enumeration
63904e51f6SJack Meng  */
64904e51f6SJack Meng static const char *iscsi_sess_enum_warn_msgs[] = {
65904e51f6SJack Meng 	"completed",
66904e51f6SJack Meng 	"partially successful",
67904e51f6SJack Meng 	"IO failures",
68904e51f6SJack Meng 	"submitted",
69904e51f6SJack Meng 	"unable to submit the enumeration",
70904e51f6SJack Meng 	"session is gone",
71904e51f6SJack Meng 	"test unit ready failed"
72904e51f6SJack Meng };
73904e51f6SJack Meng 
74fcf3ce44SJohn Forte /* internal interfaces */
75fcf3ce44SJohn Forte /* LINTED E_STATIC_UNUSED */
76fcf3ce44SJohn Forte static iscsi_sess_t *iscsi_sess_alloc(iscsi_hba_t *ihp, iscsi_sess_type_t type);
77fcf3ce44SJohn Forte static char *iscsi_sess_event_str(iscsi_sess_event_t event);
78fcf3ce44SJohn Forte static iscsi_status_t iscsi_sess_threads_create(iscsi_sess_t *isp);
79fcf3ce44SJohn Forte static void iscsi_sess_flush(iscsi_sess_t *isp);
80fcf3ce44SJohn Forte static void iscsi_sess_offline_luns(iscsi_sess_t *isp);
81fcf3ce44SJohn Forte static iscsi_status_t retrieve_lundata(uint32_t lun_count, unsigned char *buf,
82fcf3ce44SJohn Forte 	iscsi_sess_t *isp, uint16_t *lun_data, uint8_t *lun_addr_type);
83fcf3ce44SJohn Forte 
84fcf3ce44SJohn Forte /* internal state machine interfaces */
85fcf3ce44SJohn Forte static void iscsi_sess_state_free(iscsi_sess_t *isp,
86904e51f6SJack Meng     iscsi_sess_event_t event, uint32_t event_count);
87fcf3ce44SJohn Forte static void iscsi_sess_state_logged_in(iscsi_sess_t *isp,
88904e51f6SJack Meng     iscsi_sess_event_t event, uint32_t event_count);
89fcf3ce44SJohn Forte static void iscsi_sess_state_failed(iscsi_sess_t *isp,
90904e51f6SJack Meng     iscsi_sess_event_t event, uint32_t event_count);
91fcf3ce44SJohn Forte static void iscsi_sess_state_in_flush(iscsi_sess_t *isp,
92904e51f6SJack Meng     iscsi_sess_event_t event, uint32_t event_count);
93fcf3ce44SJohn Forte static void iscsi_sess_state_flushed(iscsi_sess_t *isp,
94904e51f6SJack Meng     iscsi_sess_event_t event, uint32_t event_count);
95fcf3ce44SJohn Forte 
96fcf3ce44SJohn Forte /* internal enumeration interfaces */
97fcf3ce44SJohn Forte static void iscsi_sess_enumeration(void *arg);
98904e51f6SJack Meng static iscsi_status_t iscsi_sess_testunitready(iscsi_sess_t *isp,
99904e51f6SJack Meng     uint32_t event_count);
100904e51f6SJack Meng static iscsi_status_t iscsi_sess_reportluns(iscsi_sess_t *isp,
101904e51f6SJack Meng     uint32_t event_count);
102fcf3ce44SJohn Forte static void iscsi_sess_inquiry(iscsi_sess_t *isp, uint16_t lun_num,
103904e51f6SJack Meng     uint8_t lun_addr_type, uint32_t event_count, iscsi_lun_t *ilp);
1042b79d384Sbing zhao - Sun Microsystems - Beijing China static void iscsi_sess_update_busy_luns(iscsi_sess_t *isp, boolean_t clear);
105904e51f6SJack Meng static void iscsi_sess_enum_warn(iscsi_sess_t *isp, iscsi_enum_result_t r);
106fcf3ce44SJohn Forte 
107fcf3ce44SJohn Forte /*
108fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
109fcf3ce44SJohn Forte  * | External Session Interfaces					|
110fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
111fcf3ce44SJohn Forte  */
112fcf3ce44SJohn Forte iscsi_sess_t *
iscsi_sess_create(iscsi_hba_t * ihp,iSCSIDiscoveryMethod_t method,struct sockaddr * addr_dsc,char * target_name,int tpgt,uchar_t isid_lsb,iscsi_sess_type_t type,uint32_t * oid)113fcf3ce44SJohn Forte iscsi_sess_create(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method,
114fcf3ce44SJohn Forte     struct sockaddr *addr_dsc, char *target_name, int tpgt, uchar_t isid_lsb,
115fcf3ce44SJohn Forte     iscsi_sess_type_t type, uint32_t *oid)
116fcf3ce44SJohn Forte {
117fcf3ce44SJohn Forte 	iscsi_sess_t	*isp		= NULL;
118fcf3ce44SJohn Forte 	int		len		= 0;
119fcf3ce44SJohn Forte 	char		*tq_name;
120fcf3ce44SJohn Forte 	char		*th_name;
12108f26845Sbing zhao - Sun Microsystems - Beijing China 	iscsi_status_t	status;
122fcf3ce44SJohn Forte 
123fcf3ce44SJohn Forte 	len = strlen(target_name);
124fcf3ce44SJohn Forte 
12517342e82SJack Meng clean_failed_sess:
12617342e82SJack Meng 	if (isp != NULL) {
12717342e82SJack Meng 		(void) iscsi_sess_destroy(isp);
12817342e82SJack Meng 	}
12917342e82SJack Meng 
130fcf3ce44SJohn Forte 	for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
131fcf3ce44SJohn Forte 		/* Match target name and LSB ISID */
132fcf3ce44SJohn Forte 		if ((strcmp((char *)isp->sess_name, target_name) == 0) &&
133fcf3ce44SJohn Forte 		    (isp->sess_isid[5] == isid_lsb)) {
134fcf3ce44SJohn Forte 
135fcf3ce44SJohn Forte 			/* Match TPGT */
136fcf3ce44SJohn Forte 			if (isp->sess_tpgt_conf == tpgt) {
137fcf3ce44SJohn Forte 				/* Found mathing session, return oid/ptr */
138fcf3ce44SJohn Forte 				*oid = isp->sess_oid;
13908f26845Sbing zhao - Sun Microsystems - Beijing China 				if (isp->sess_wd_thread != NULL &&
14008f26845Sbing zhao - Sun Microsystems - Beijing China 				    isp->sess_ic_thread != NULL) {
14117342e82SJack Meng 					return (isp);
14217342e82SJack Meng 				}
14308f26845Sbing zhao - Sun Microsystems - Beijing China 
14417342e82SJack Meng 				if (isp->sess_wd_thread == NULL) {
14508f26845Sbing zhao - Sun Microsystems - Beijing China 					/*
14608f26845Sbing zhao - Sun Microsystems - Beijing China 					 * Under rare cases wd thread is already
14708f26845Sbing zhao - Sun Microsystems - Beijing China 					 * freed, create it if so.
14808f26845Sbing zhao - Sun Microsystems - Beijing China 					 */
14908f26845Sbing zhao - Sun Microsystems - Beijing China 					th_name = kmem_zalloc(
15008f26845Sbing zhao - Sun Microsystems - Beijing China 					    ISCSI_TH_MAX_NAME_LEN, KM_SLEEP);
15108f26845Sbing zhao - Sun Microsystems - Beijing China 					if (snprintf(th_name,
15208f26845Sbing zhao - Sun Microsystems - Beijing China 					    (ISCSI_TH_MAX_NAME_LEN - 1),
15308f26845Sbing zhao - Sun Microsystems - Beijing China 					    ISCSI_SESS_WD_NAME_FORMAT,
15408f26845Sbing zhao - Sun Microsystems - Beijing China 					    ihp->hba_oid, isp->sess_oid) <
15508f26845Sbing zhao - Sun Microsystems - Beijing China 					    ISCSI_TH_MAX_NAME_LEN) {
15608f26845Sbing zhao - Sun Microsystems - Beijing China 						isp->sess_wd_thread =
15708f26845Sbing zhao - Sun Microsystems - Beijing China 						    iscsi_thread_create(
15808f26845Sbing zhao - Sun Microsystems - Beijing China 						    ihp->hba_dip,
15908f26845Sbing zhao - Sun Microsystems - Beijing China 						    th_name,
16008f26845Sbing zhao - Sun Microsystems - Beijing China 						    iscsi_wd_thread,
16108f26845Sbing zhao - Sun Microsystems - Beijing China 						    isp);
16208f26845Sbing zhao - Sun Microsystems - Beijing China 						(void) iscsi_thread_start(
16308f26845Sbing zhao - Sun Microsystems - Beijing China 						    isp->sess_wd_thread);
16408f26845Sbing zhao - Sun Microsystems - Beijing China 					}
16508f26845Sbing zhao - Sun Microsystems - Beijing China 					kmem_free(th_name,
16608f26845Sbing zhao - Sun Microsystems - Beijing China 					    ISCSI_TH_MAX_NAME_LEN);
16708f26845Sbing zhao - Sun Microsystems - Beijing China 					if (isp->sess_wd_thread == NULL) {
16808f26845Sbing zhao - Sun Microsystems - Beijing China 						/* No way to save it */
16908f26845Sbing zhao - Sun Microsystems - Beijing China 						goto clean_failed_sess;
17008f26845Sbing zhao - Sun Microsystems - Beijing China 					}
17108f26845Sbing zhao - Sun Microsystems - Beijing China 				}
17208f26845Sbing zhao - Sun Microsystems - Beijing China 
17308f26845Sbing zhao - Sun Microsystems - Beijing China 				if (isp->sess_ic_thread == NULL) {
17408f26845Sbing zhao - Sun Microsystems - Beijing China 					status = iscsi_sess_threads_create(isp);
17508f26845Sbing zhao - Sun Microsystems - Beijing China 					if (status != ISCSI_STATUS_SUCCESS) {
17608f26845Sbing zhao - Sun Microsystems - Beijing China 						goto clean_failed_sess;
17708f26845Sbing zhao - Sun Microsystems - Beijing China 					}
17817342e82SJack Meng 				}
179fcf3ce44SJohn Forte 				return (isp);
180fcf3ce44SJohn Forte 			}
181fcf3ce44SJohn Forte 
182fcf3ce44SJohn Forte 			/*
183fcf3ce44SJohn Forte 			 * Also protect against creating duplicate
184fcf3ce44SJohn Forte 			 * sessions with different configured tpgt
185fcf3ce44SJohn Forte 			 * values.  default vs. defined.
186fcf3ce44SJohn Forte 			 */
187fcf3ce44SJohn Forte 			if ((((isp->sess_tpgt_conf == ISCSI_DEFAULT_TPGT) &&
188fcf3ce44SJohn Forte 			    (tpgt != ISCSI_DEFAULT_TPGT)) ||
189fcf3ce44SJohn Forte 			    ((isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) &&
190fcf3ce44SJohn Forte 			    (tpgt == ISCSI_DEFAULT_TPGT)))) {
191fcf3ce44SJohn Forte 				/* Dangerous configuration.  Fail Request */
192fcf3ce44SJohn Forte 				return (NULL);
193fcf3ce44SJohn Forte 			}
194fcf3ce44SJohn Forte 		}
195fcf3ce44SJohn Forte 	}
196fcf3ce44SJohn Forte 
197fcf3ce44SJohn Forte 	isp = (iscsi_sess_t *)kmem_zalloc(sizeof (iscsi_sess_t), KM_SLEEP);
198fcf3ce44SJohn Forte 	/*
199fcf3ce44SJohn Forte 	 * If this session is not a Send Targets session, set the target
200fcf3ce44SJohn Forte 	 * that this session is associated with.
201fcf3ce44SJohn Forte 	 */
202fcf3ce44SJohn Forte 	if (strncmp(target_name, SENDTARGETS_DISCOVERY,
203fcf3ce44SJohn Forte 	    strlen(SENDTARGETS_DISCOVERY))) {
204fcf3ce44SJohn Forte 		isp->sess_target_oid = iscsi_targetparam_get_oid(
205fcf3ce44SJohn Forte 		    (uchar_t *)target_name);
206fcf3ce44SJohn Forte 	}
207fcf3ce44SJohn Forte 
2086cefaae1SJack Meng 	if (method & iSCSIDiscoveryMethodBoot) {
2096cefaae1SJack Meng 		/* This is boot session. */
2106cefaae1SJack Meng 		isp->sess_boot = B_TRUE;
2116cefaae1SJack Meng 	} else {
2126cefaae1SJack Meng 		isp->sess_boot = B_FALSE;
2136cefaae1SJack Meng 	}
2146cefaae1SJack Meng 
215fcf3ce44SJohn Forte 	/* Associate session with this discovery method */
2166cefaae1SJack Meng 	method = method & ~(iSCSIDiscoveryMethodBoot);
2176cefaae1SJack Meng 
218fcf3ce44SJohn Forte 	isp->sess_discovered_by = method;
219fcf3ce44SJohn Forte 	if (addr_dsc == NULL) {
220fcf3ce44SJohn Forte 		bzero(&isp->sess_discovered_addr,
221fcf3ce44SJohn Forte 		    sizeof (isp->sess_discovered_addr));
222fcf3ce44SJohn Forte 	} else {
223fcf3ce44SJohn Forte 		bcopy(addr_dsc, &isp->sess_discovered_addr,
224fcf3ce44SJohn Forte 		    SIZEOF_SOCKADDR(addr_dsc));
225fcf3ce44SJohn Forte 	}
226fcf3ce44SJohn Forte 
227fcf3ce44SJohn Forte 	/* assign unique key for the session */
228fcf3ce44SJohn Forte 	mutex_enter(&iscsi_oid_mutex);
229fcf3ce44SJohn Forte 	isp->sess_oid = iscsi_oid++;
230fcf3ce44SJohn Forte 	*oid = isp->sess_oid;
231fcf3ce44SJohn Forte 	mutex_exit(&iscsi_oid_mutex);
232fcf3ce44SJohn Forte 
233fcf3ce44SJohn Forte 	/* setup session parameters */
234fcf3ce44SJohn Forte 	isp->sess_name_length		= 0;
235fcf3ce44SJohn Forte 	isp->sess_sig			= ISCSI_SIG_SESS;
236fcf3ce44SJohn Forte 	isp->sess_state			= ISCSI_SESS_STATE_FREE;
237904e51f6SJack Meng 	rw_init(&isp->sess_state_rwlock, NULL, RW_DRIVER, NULL);
2382b79d384Sbing zhao - Sun Microsystems - Beijing China 	mutex_init(&isp->sess_reset_mutex, NULL, MUTEX_DRIVER, NULL);
239fcf3ce44SJohn Forte 	isp->sess_hba			= ihp;
240fcf3ce44SJohn Forte 
241fcf3ce44SJohn Forte 	isp->sess_isid[0]		= ISCSI_SUN_ISID_0;
242fcf3ce44SJohn Forte 	isp->sess_isid[1]		= ISCSI_SUN_ISID_1;
243fcf3ce44SJohn Forte 	isp->sess_isid[2]		= ISCSI_SUN_ISID_2;
244fcf3ce44SJohn Forte 	isp->sess_isid[3]		= ISCSI_SUN_ISID_3;
245fcf3ce44SJohn Forte 	isp->sess_isid[4]		= 0;
246fcf3ce44SJohn Forte 	isp->sess_isid[5]		= isid_lsb;
247fcf3ce44SJohn Forte 
248fcf3ce44SJohn Forte 	isp->sess_cmdsn			= 1;
249fcf3ce44SJohn Forte 	isp->sess_expcmdsn		= 1;
250fcf3ce44SJohn Forte 	isp->sess_maxcmdsn		= 1;
251fcf3ce44SJohn Forte 	isp->sess_last_err		= NoError;
252fcf3ce44SJohn Forte 	isp->sess_tsid			= 0;
253fcf3ce44SJohn Forte 	isp->sess_type			= type;
2542b79d384Sbing zhao - Sun Microsystems - Beijing China 	isp->sess_reset_in_progress	= B_FALSE;
255bbe72583SJack Meng 	isp->sess_boot_nic_reset	= B_FALSE;
25630e7468fSPeter Dunlap 	idm_sm_audit_init(&isp->sess_state_audit);
257fcf3ce44SJohn Forte 
258fcf3ce44SJohn Forte 	/* copy default driver login parameters */
259fcf3ce44SJohn Forte 	bcopy(&ihp->hba_params, &isp->sess_params,
260fcf3ce44SJohn Forte 	    sizeof (iscsi_login_params_t));
261fcf3ce44SJohn Forte 
262fcf3ce44SJohn Forte 	/* copy target name into session */
263fcf3ce44SJohn Forte 	bcopy((char *)target_name, isp->sess_name, len);
264fcf3ce44SJohn Forte 	isp->sess_name_length	= len;
265fcf3ce44SJohn Forte 	isp->sess_tpgt_conf	= tpgt;
266fcf3ce44SJohn Forte 	isp->sess_tpgt_nego	= ISCSI_DEFAULT_TPGT;
267fcf3ce44SJohn Forte 
268fcf3ce44SJohn Forte 	/* initialize pending and completion queues */
269fcf3ce44SJohn Forte 	iscsi_init_queue(&isp->sess_queue_pending);
270fcf3ce44SJohn Forte 	iscsi_init_queue(&isp->sess_queue_completion);
271fcf3ce44SJohn Forte 
272fcf3ce44SJohn Forte 	/* setup sessions lun list */
273fcf3ce44SJohn Forte 	isp->sess_lun_list = NULL;
274fcf3ce44SJohn Forte 	rw_init(&isp->sess_lun_list_rwlock, NULL, RW_DRIVER, NULL);
275fcf3ce44SJohn Forte 
276fcf3ce44SJohn Forte 	/* setup sessions connection list */
277fcf3ce44SJohn Forte 	isp->sess_conn_act = NULL;
278fcf3ce44SJohn Forte 	isp->sess_conn_list = NULL;
279fcf3ce44SJohn Forte 	rw_init(&isp->sess_conn_list_rwlock, NULL, RW_DRIVER, NULL);
280fcf3ce44SJohn Forte 
281fcf3ce44SJohn Forte 	mutex_init(&isp->sess_cmdsn_mutex, NULL, MUTEX_DRIVER, NULL);
282fcf3ce44SJohn Forte 
283fcf3ce44SJohn Forte 	/* create the session task queue */
284fcf3ce44SJohn Forte 	tq_name = kmem_zalloc(ISCSI_TH_MAX_NAME_LEN, KM_SLEEP);
285fcf3ce44SJohn Forte 	if (snprintf(tq_name, (ISCSI_TH_MAX_NAME_LEN - 1),
286fcf3ce44SJohn Forte 	    ISCSI_SESS_LOGIN_TASKQ_NAME_FORMAT, ihp->hba_oid, isp->sess_oid) <
287fcf3ce44SJohn Forte 	    ISCSI_TH_MAX_NAME_LEN) {
288904e51f6SJack Meng 		isp->sess_login_taskq = ddi_taskq_create(ihp->hba_dip,
289fcf3ce44SJohn Forte 		    tq_name, 1, TASKQ_DEFAULTPRI, 0);
290fcf3ce44SJohn Forte 	}
291904e51f6SJack Meng 	if (isp->sess_login_taskq == NULL) {
292904e51f6SJack Meng 		kmem_free(tq_name, ISCSI_TH_MAX_NAME_LEN);
293fcf3ce44SJohn Forte 		goto iscsi_sess_cleanup2;
294fcf3ce44SJohn Forte 	}
295fcf3ce44SJohn Forte 
296904e51f6SJack Meng 	if (snprintf(tq_name, (ISCSI_TH_MAX_NAME_LEN - 1),
297904e51f6SJack Meng 	    ISCSI_SESS_ENUM_TASKQ_NAME_FORMAT, ihp->hba_oid, isp->sess_oid) <
298904e51f6SJack Meng 	    ISCSI_TH_MAX_NAME_LEN) {
299904e51f6SJack Meng 		isp->sess_enum_taskq = ddi_taskq_create(ihp->hba_dip,
300904e51f6SJack Meng 		    tq_name, 1, TASKQ_DEFAULTPRI, 0);
301904e51f6SJack Meng 	}
302904e51f6SJack Meng 	kmem_free(tq_name, ISCSI_TH_MAX_NAME_LEN);
303904e51f6SJack Meng 	if (isp->sess_enum_taskq == NULL) {
304904e51f6SJack Meng 		goto iscsi_sess_cleanup1;
305904e51f6SJack Meng 	}
306fcf3ce44SJohn Forte 	/* startup watchdog */
307fcf3ce44SJohn Forte 	th_name = kmem_zalloc(ISCSI_TH_MAX_NAME_LEN, KM_SLEEP);
308fcf3ce44SJohn Forte 	if (snprintf(th_name, (ISCSI_TH_MAX_NAME_LEN - 1),
309fcf3ce44SJohn Forte 	    ISCSI_SESS_WD_NAME_FORMAT, ihp->hba_oid, isp->sess_oid) <
310fcf3ce44SJohn Forte 	    ISCSI_TH_MAX_NAME_LEN) {
311fcf3ce44SJohn Forte 		isp->sess_wd_thread = iscsi_thread_create(ihp->hba_dip,
312fcf3ce44SJohn Forte 		    th_name, iscsi_wd_thread, isp);
313fcf3ce44SJohn Forte 		(void) iscsi_thread_start(isp->sess_wd_thread);
314fcf3ce44SJohn Forte 	}
31508f26845Sbing zhao - Sun Microsystems - Beijing China 
316fcf3ce44SJohn Forte 	kmem_free(th_name, ISCSI_TH_MAX_NAME_LEN);
317fcf3ce44SJohn Forte 	if (isp->sess_wd_thread == NULL) {
318904e51f6SJack Meng 		goto iscsi_sess_cleanup0;
319fcf3ce44SJohn Forte 	}
320fcf3ce44SJohn Forte 
32108f26845Sbing zhao - Sun Microsystems - Beijing China 	status = iscsi_sess_threads_create(isp);
32208f26845Sbing zhao - Sun Microsystems - Beijing China 	if (status != ISCSI_STATUS_SUCCESS) {
32308f26845Sbing zhao - Sun Microsystems - Beijing China 		goto iscsi_sess_cleanup1;
32408f26845Sbing zhao - Sun Microsystems - Beijing China 	}
32508f26845Sbing zhao - Sun Microsystems - Beijing China 
326fcf3ce44SJohn Forte 	/* Add new target to the hba target list */
327fcf3ce44SJohn Forte 	if (ihp->hba_sess_list == NULL) {
328fcf3ce44SJohn Forte 		ihp->hba_sess_list = isp;
329fcf3ce44SJohn Forte 	} else {
330fcf3ce44SJohn Forte 		isp->sess_next = ihp->hba_sess_list;
331fcf3ce44SJohn Forte 		ihp->hba_sess_list = isp;
332fcf3ce44SJohn Forte 	}
333fcf3ce44SJohn Forte 	KSTAT_INC_HBA_CNTR_SESS(ihp);
334fcf3ce44SJohn Forte 
335fcf3ce44SJohn Forte 	(void) iscsi_sess_kstat_init(isp);
336fcf3ce44SJohn Forte 
337904e51f6SJack Meng 	if (type == ISCSI_SESS_TYPE_NORMAL) {
338904e51f6SJack Meng 		isp->sess_enum_status = ISCSI_SESS_ENUM_FREE;
339904e51f6SJack Meng 		isp->sess_enum_result = ISCSI_SESS_ENUM_COMPLETE;
340904e51f6SJack Meng 		isp->sess_enum_result_count = 0;
341904e51f6SJack Meng 		mutex_init(&isp->sess_enum_lock, NULL, MUTEX_DRIVER, NULL);
342904e51f6SJack Meng 		cv_init(&isp->sess_enum_cv, NULL, CV_DRIVER, NULL);
343904e51f6SJack Meng 	}
344904e51f6SJack Meng 
345904e51f6SJack Meng 	mutex_init(&isp->sess_state_wmutex, NULL, MUTEX_DRIVER, NULL);
346904e51f6SJack Meng 	cv_init(&isp->sess_state_wcv, NULL, CV_DRIVER, NULL);
347904e51f6SJack Meng 	isp->sess_state_hasw = B_FALSE;
348fcf3ce44SJohn Forte 
349904e51f6SJack Meng 	isp->sess_state_event_count = 0;
350904e51f6SJack Meng 
351904e51f6SJack Meng 	return (isp);
352904e51f6SJack Meng iscsi_sess_cleanup0:
353904e51f6SJack Meng 	ddi_taskq_destroy(isp->sess_enum_taskq);
354fcf3ce44SJohn Forte iscsi_sess_cleanup1:
355904e51f6SJack Meng 	ddi_taskq_destroy(isp->sess_login_taskq);
356fcf3ce44SJohn Forte iscsi_sess_cleanup2:
35708f26845Sbing zhao - Sun Microsystems - Beijing China 	if (isp->sess_wd_thread != NULL) {
35808f26845Sbing zhao - Sun Microsystems - Beijing China 		iscsi_thread_destroy(isp->sess_wd_thread);
35908f26845Sbing zhao - Sun Microsystems - Beijing China 		isp->sess_wd_thread  = NULL;
36008f26845Sbing zhao - Sun Microsystems - Beijing China 	}
36108f26845Sbing zhao - Sun Microsystems - Beijing China 	if (isp->sess_ic_thread != NULL) {
36208f26845Sbing zhao - Sun Microsystems - Beijing China 		iscsi_thread_destroy(isp->sess_ic_thread);
36308f26845Sbing zhao - Sun Microsystems - Beijing China 		isp->sess_ic_thread = NULL;
36408f26845Sbing zhao - Sun Microsystems - Beijing China 	}
365fcf3ce44SJohn Forte 	mutex_destroy(&isp->sess_cmdsn_mutex);
366fcf3ce44SJohn Forte 	rw_destroy(&isp->sess_conn_list_rwlock);
367fcf3ce44SJohn Forte 	rw_destroy(&isp->sess_lun_list_rwlock);
368fcf3ce44SJohn Forte 	iscsi_destroy_queue(&isp->sess_queue_completion);
369fcf3ce44SJohn Forte 	iscsi_destroy_queue(&isp->sess_queue_pending);
370904e51f6SJack Meng 	rw_destroy(&isp->sess_state_rwlock);
3712b79d384Sbing zhao - Sun Microsystems - Beijing China 	mutex_destroy(&isp->sess_reset_mutex);
372fcf3ce44SJohn Forte 	kmem_free(isp, sizeof (iscsi_sess_t));
373fcf3ce44SJohn Forte 
374fcf3ce44SJohn Forte 	return (NULL);
375fcf3ce44SJohn Forte }
376fcf3ce44SJohn Forte 
377fcf3ce44SJohn Forte /*
378fcf3ce44SJohn Forte  * iscsi_sess_get - return the session structure for based on a
379fcf3ce44SJohn Forte  * passed in oid and hba instance.
380fcf3ce44SJohn Forte  */
381fcf3ce44SJohn Forte int
iscsi_sess_get(uint32_t oid,iscsi_hba_t * ihp,iscsi_sess_t ** ispp)382fcf3ce44SJohn Forte iscsi_sess_get(uint32_t oid, iscsi_hba_t *ihp, iscsi_sess_t **ispp)
383fcf3ce44SJohn Forte {
384fcf3ce44SJohn Forte 	int		rval		= 0;
385fcf3ce44SJohn Forte 	iscsi_sess_t	*isp		= NULL;
386fcf3ce44SJohn Forte 
387fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
388fcf3ce44SJohn Forte 	ASSERT(ispp != NULL);
389fcf3ce44SJohn Forte 
390fcf3ce44SJohn Forte 	/* See if we already created this session */
391fcf3ce44SJohn Forte 	for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
392fcf3ce44SJohn Forte 		/* compare target name as the unique identifier */
393fcf3ce44SJohn Forte 		if (isp->sess_oid == oid) {
394fcf3ce44SJohn Forte 			/* Found matching session */
395fcf3ce44SJohn Forte 			break;
396fcf3ce44SJohn Forte 		}
397fcf3ce44SJohn Forte 	}
398fcf3ce44SJohn Forte 
399fcf3ce44SJohn Forte 	/* If not null this session is already available */
400fcf3ce44SJohn Forte 	if (isp != NULL) {
401fcf3ce44SJohn Forte 		/* Existing session, return it */
402fcf3ce44SJohn Forte 		*ispp = isp;
403fcf3ce44SJohn Forte 	} else {
404fcf3ce44SJohn Forte 		rval = EFAULT;
405fcf3ce44SJohn Forte 	}
406fcf3ce44SJohn Forte 	return (rval);
407fcf3ce44SJohn Forte }
408fcf3ce44SJohn Forte 
409fcf3ce44SJohn Forte /*
410fcf3ce44SJohn Forte  * iscsi_sess_online - initiate online of sessions connections
411fcf3ce44SJohn Forte  */
412fcf3ce44SJohn Forte void
iscsi_sess_online(void * arg)413a9ccff55Sbing zhao - Sun Microsystems - Beijing China iscsi_sess_online(void *arg)
414fcf3ce44SJohn Forte {
415a9ccff55Sbing zhao - Sun Microsystems - Beijing China 	iscsi_sess_t	*isp;
416fcf3ce44SJohn Forte 	iscsi_hba_t	*ihp;
417fcf3ce44SJohn Forte 	iscsi_conn_t	*icp;
418fcf3ce44SJohn Forte 	int		idx;
419904e51f6SJack Meng 	uint32_t	event_count;
420fcf3ce44SJohn Forte 
421a9ccff55Sbing zhao - Sun Microsystems - Beijing China 	isp = (iscsi_sess_t *)arg;
422a9ccff55Sbing zhao - Sun Microsystems - Beijing China 
423fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
424fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
425fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
426fcf3ce44SJohn Forte 
427fcf3ce44SJohn Forte 	/*
428fcf3ce44SJohn Forte 	 * Stale /dev links can cause us to get floods
429fcf3ce44SJohn Forte 	 * of config requests. To prevent these repeated
430fcf3ce44SJohn Forte 	 * requests from causing unneeded login to the
431fcf3ce44SJohn Forte 	 * unreachable target, we won't try it during
432fcf3ce44SJohn Forte 	 * the delay.
433fcf3ce44SJohn Forte 	 */
434fcf3ce44SJohn Forte 	if (ddi_get_lbolt() < isp->sess_failure_lbolt +
435fcf3ce44SJohn Forte 	    SEC_TO_TICK(isp->sess_storm_delay)) {
436fcf3ce44SJohn Forte 		return;
437fcf3ce44SJohn Forte 	}
438fcf3ce44SJohn Forte 
439fcf3ce44SJohn Forte 	/*
440fcf3ce44SJohn Forte 	 * Perform a crude version of round robin to
441fcf3ce44SJohn Forte 	 * determine which connection to use for
442fcf3ce44SJohn Forte 	 * this session. Since byte 5 in session ID
443fcf3ce44SJohn Forte 	 * is overridden for full feature session,
444fcf3ce44SJohn Forte 	 * the connection to be selected depends on
445fcf3ce44SJohn Forte 	 * the result of sess_isid[5] devided by the
446fcf3ce44SJohn Forte 	 * next connection ID.
447fcf3ce44SJohn Forte 	 * If MS/T is enabled and there are multiple
448fcf3ce44SJohn Forte 	 * IPs are available on the target, we can
449fcf3ce44SJohn Forte 	 * select different IPs to connect in this
450fcf3ce44SJohn Forte 	 * way.
451fcf3ce44SJohn Forte 	 */
452fcf3ce44SJohn Forte 	icp = isp->sess_conn_act;
453fcf3ce44SJohn Forte 	if (icp == NULL) {
454fcf3ce44SJohn Forte 		icp = isp->sess_conn_list;
455fcf3ce44SJohn Forte 		for (idx = 0; idx < (isp->sess_isid[5] %
456fcf3ce44SJohn Forte 		    isp->sess_conn_next_cid); idx++) {
457fcf3ce44SJohn Forte 			ASSERT(icp->conn_next != NULL);
458fcf3ce44SJohn Forte 			icp = icp->conn_next;
459fcf3ce44SJohn Forte 		}
460fcf3ce44SJohn Forte 		isp->sess_conn_act = icp;
461fcf3ce44SJohn Forte 	}
462fcf3ce44SJohn Forte 
463fcf3ce44SJohn Forte 	if (icp == NULL) {
464fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "iscsi session(%d) - "
465fcf3ce44SJohn Forte 		    "no connection assigned", isp->sess_oid);
466fcf3ce44SJohn Forte 		return;
467fcf3ce44SJohn Forte 	}
468fcf3ce44SJohn Forte 
469fcf3ce44SJohn Forte 	/*
470fcf3ce44SJohn Forte 	 * If connection is in free state, start
471fcf3ce44SJohn Forte 	 * login.  If already logged in, try to
472fcf3ce44SJohn Forte 	 * re-enumerate LUs on the session.
473fcf3ce44SJohn Forte 	 */
474fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_state_mutex);
475fcf3ce44SJohn Forte 	if (icp->conn_state == ISCSI_CONN_STATE_FREE) {
476fcf3ce44SJohn Forte 		/*
477fcf3ce44SJohn Forte 		 * attempt to login into the first connection in our connection
478fcf3ce44SJohn Forte 		 * list.  If this fails, we will try the next connection
479fcf3ce44SJohn Forte 		 * in our list until end of the list.
480fcf3ce44SJohn Forte 		 */
481fcf3ce44SJohn Forte 		while (icp != NULL) {
48230e7468fSPeter Dunlap 			if (iscsi_conn_online(icp) == ISCSI_STATUS_SUCCESS) {
483fcf3ce44SJohn Forte 				mutex_exit(&icp->conn_state_mutex);
484fcf3ce44SJohn Forte 				break;
485fcf3ce44SJohn Forte 			} else {
486fcf3ce44SJohn Forte 				mutex_exit(&icp->conn_state_mutex);
487fcf3ce44SJohn Forte 				icp = icp->conn_next;
488fcf3ce44SJohn Forte 				if (icp != NULL) {
489fcf3ce44SJohn Forte 					mutex_enter(&icp->conn_state_mutex);
490fcf3ce44SJohn Forte 				}
491fcf3ce44SJohn Forte 			}
492fcf3ce44SJohn Forte 		}
493fcf3ce44SJohn Forte 		isp->sess_conn_act = icp;
494fcf3ce44SJohn Forte 		if (icp == NULL) {
495fcf3ce44SJohn Forte 		/* the target for this session is unreachable */
496fcf3ce44SJohn Forte 			isp->sess_failure_lbolt = ddi_get_lbolt();
497fcf3ce44SJohn Forte 			if (isp->sess_storm_delay == 0) {
498fcf3ce44SJohn Forte 				isp->sess_storm_delay++;
499fcf3ce44SJohn Forte 			} else {
500fcf3ce44SJohn Forte 
501fcf3ce44SJohn Forte 				if ((isp->sess_storm_delay * 2) <
502fcf3ce44SJohn Forte 				    iscsi_sess_max_delay) {
503fcf3ce44SJohn Forte 					isp->sess_storm_delay =
504fcf3ce44SJohn Forte 					    isp->sess_storm_delay * 2;
505fcf3ce44SJohn Forte 				} else {
506fcf3ce44SJohn Forte 					isp->sess_storm_delay =
507fcf3ce44SJohn Forte 					    iscsi_sess_max_delay;
508fcf3ce44SJohn Forte 				}
509fcf3ce44SJohn Forte 			}
510fcf3ce44SJohn Forte 
511fcf3ce44SJohn Forte 		} else {
512fcf3ce44SJohn Forte 			isp->sess_storm_delay = 0;
513fcf3ce44SJohn Forte 			isp->sess_failure_lbolt = 0;
514fcf3ce44SJohn Forte 		}
515fcf3ce44SJohn Forte 	} else if (icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN) {
516fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
517904e51f6SJack Meng 		event_count = atomic_inc_32_nv(&isp->sess_state_event_count);
518904e51f6SJack Meng 		iscsi_sess_enter_state_zone(isp);
519fcf3ce44SJohn Forte 		iscsi_sess_state_machine(isp,
520904e51f6SJack Meng 		    ISCSI_SESS_EVENT_N1, event_count);
521904e51f6SJack Meng 		iscsi_sess_exit_state_zone(isp);
522fcf3ce44SJohn Forte 	} else {
523fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
524fcf3ce44SJohn Forte 	}
525fcf3ce44SJohn Forte }
526fcf3ce44SJohn Forte 
527fcf3ce44SJohn Forte /*
528fcf3ce44SJohn Forte  * iscsi_sess_destroy - Destroys a iscsi session structure
529fcf3ce44SJohn Forte  * and de-associates it from the hba.
530fcf3ce44SJohn Forte  */
531fcf3ce44SJohn Forte iscsi_status_t
iscsi_sess_destroy(iscsi_sess_t * isp)532fcf3ce44SJohn Forte iscsi_sess_destroy(iscsi_sess_t *isp)
533fcf3ce44SJohn Forte {
534fcf3ce44SJohn Forte 	iscsi_status_t	rval	= ISCSI_STATUS_SUCCESS;
5350349feabSyu, larry liu - Sun Microsystems - Beijing China 	iscsi_status_t	tmprval = ISCSI_STATUS_SUCCESS;
536fcf3ce44SJohn Forte 	iscsi_hba_t	*ihp;
537fcf3ce44SJohn Forte 	iscsi_sess_t	*t_isp;
538fcf3ce44SJohn Forte 	iscsi_lun_t	*ilp;
539fcf3ce44SJohn Forte 	iscsi_conn_t	*icp;
540fcf3ce44SJohn Forte 
541fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
542fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
543fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
544fcf3ce44SJohn Forte 
545fcf3ce44SJohn Forte 	/*
546fcf3ce44SJohn Forte 	 * The first step in tearing down the session
547fcf3ce44SJohn Forte 	 * has to be offlining all the LUNs.  This will
548fcf3ce44SJohn Forte 	 * ensure there is no outstanding IO by upper
549fcf3ce44SJohn Forte 	 * level drivers.  If this fails then we are
550fcf3ce44SJohn Forte 	 * unable to destroy the session.
5510349feabSyu, larry liu - Sun Microsystems - Beijing China 	 *
5520349feabSyu, larry liu - Sun Microsystems - Beijing China 	 * Try all luns and continue upon failure
5530349feabSyu, larry liu - Sun Microsystems - Beijing China 	 * to remove what is removable before returning
5540349feabSyu, larry liu - Sun Microsystems - Beijing China 	 * the last error.
555fcf3ce44SJohn Forte 	 */
556fcf3ce44SJohn Forte 	rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
557fcf3ce44SJohn Forte 	ilp = isp->sess_lun_list;
558fcf3ce44SJohn Forte 	while (ilp != NULL) {
5590349feabSyu, larry liu - Sun Microsystems - Beijing China 		iscsi_lun_t	*ilp_next = ilp->lun_next;
5600349feabSyu, larry liu - Sun Microsystems - Beijing China 
5610349feabSyu, larry liu - Sun Microsystems - Beijing China 		tmprval = iscsi_lun_destroy(ihp, ilp);
5620349feabSyu, larry liu - Sun Microsystems - Beijing China 		if (!ISCSI_SUCCESS(tmprval)) {
5630349feabSyu, larry liu - Sun Microsystems - Beijing China 			rval = tmprval;
564fcf3ce44SJohn Forte 		}
5650349feabSyu, larry liu - Sun Microsystems - Beijing China 		ilp = ilp_next;
566fcf3ce44SJohn Forte 	}
567fcf3ce44SJohn Forte 	rw_exit(&isp->sess_lun_list_rwlock);
568fcf3ce44SJohn Forte 
5690349feabSyu, larry liu - Sun Microsystems - Beijing China 	if (!ISCSI_SUCCESS(rval)) {
5700349feabSyu, larry liu - Sun Microsystems - Beijing China 		return (rval);
5710349feabSyu, larry liu - Sun Microsystems - Beijing China 	}
5720349feabSyu, larry liu - Sun Microsystems - Beijing China 
573fcf3ce44SJohn Forte 	/* The next step is to logout of the connections. */
57430e7468fSPeter Dunlap 	rw_enter(&isp->sess_conn_list_rwlock, RW_WRITER);
575fcf3ce44SJohn Forte 	icp = isp->sess_conn_list;
576fcf3ce44SJohn Forte 	while (icp != NULL) {
577fcf3ce44SJohn Forte 		rval = iscsi_conn_offline(icp);
578fcf3ce44SJohn Forte 		if (ISCSI_SUCCESS(rval)) {
579fcf3ce44SJohn Forte 			/* Succes, Continue processing... */
580fcf3ce44SJohn Forte 			icp = icp->conn_next;
581fcf3ce44SJohn Forte 		} else {
582fcf3ce44SJohn Forte 			/* Failure, Stop processing... */
583fcf3ce44SJohn Forte 			rw_exit(&isp->sess_conn_list_rwlock);
584fcf3ce44SJohn Forte 			return (rval);
585fcf3ce44SJohn Forte 		}
586fcf3ce44SJohn Forte 	}
58730e7468fSPeter Dunlap 	rw_exit(&isp->sess_conn_list_rwlock);
588fcf3ce44SJohn Forte 
589fcf3ce44SJohn Forte 	/*
590fcf3ce44SJohn Forte 	 * At this point all connections should be in
591fcf3ce44SJohn Forte 	 * a FREE state which will have pushed the session
592fcf3ce44SJohn Forte 	 * to a FREE state.
593fcf3ce44SJohn Forte 	 */
59430e7468fSPeter Dunlap 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FREE ||
59530e7468fSPeter Dunlap 	    isp->sess_state == ISCSI_SESS_STATE_FAILED);
596fcf3ce44SJohn Forte 
597fcf3ce44SJohn Forte 	/* Stop watchdog before destroying connections */
59817342e82SJack Meng 	if (isp->sess_wd_thread) {
59917342e82SJack Meng 		iscsi_thread_destroy(isp->sess_wd_thread);
60017342e82SJack Meng 		isp->sess_wd_thread = NULL;
60117342e82SJack Meng 	}
602fcf3ce44SJohn Forte 
603fcf3ce44SJohn Forte 	/* Destroy connections */
604fcf3ce44SJohn Forte 	rw_enter(&isp->sess_conn_list_rwlock, RW_WRITER);
605fcf3ce44SJohn Forte 	icp = isp->sess_conn_list;
606fcf3ce44SJohn Forte 	while (icp != NULL) {
607fcf3ce44SJohn Forte 		rval = iscsi_conn_destroy(icp);
608fcf3ce44SJohn Forte 		if (!ISCSI_SUCCESS(rval)) {
609fcf3ce44SJohn Forte 			rw_exit(&isp->sess_conn_list_rwlock);
610fcf3ce44SJohn Forte 			return (rval);
611fcf3ce44SJohn Forte 		}
612fcf3ce44SJohn Forte 		icp = isp->sess_conn_list;
613fcf3ce44SJohn Forte 	}
614fcf3ce44SJohn Forte 	rw_exit(&isp->sess_conn_list_rwlock);
615fcf3ce44SJohn Forte 
61608f26845Sbing zhao - Sun Microsystems - Beijing China 	/* Destroy Session ic thread */
61708f26845Sbing zhao - Sun Microsystems - Beijing China 	if (isp->sess_ic_thread != NULL) {
61808f26845Sbing zhao - Sun Microsystems - Beijing China 		iscsi_thread_destroy(isp->sess_ic_thread);
61908f26845Sbing zhao - Sun Microsystems - Beijing China 		isp->sess_ic_thread = NULL;
62008f26845Sbing zhao - Sun Microsystems - Beijing China 	}
62108f26845Sbing zhao - Sun Microsystems - Beijing China 
622fcf3ce44SJohn Forte 	/* Destroy session task queue */
623904e51f6SJack Meng 	ddi_taskq_destroy(isp->sess_enum_taskq);
624904e51f6SJack Meng 	ddi_taskq_destroy(isp->sess_login_taskq);
625fcf3ce44SJohn Forte 
626fcf3ce44SJohn Forte 	/* destroy pending and completion queues */
627fcf3ce44SJohn Forte 	iscsi_destroy_queue(&isp->sess_queue_pending);
628fcf3ce44SJohn Forte 	iscsi_destroy_queue(&isp->sess_queue_completion);
629fcf3ce44SJohn Forte 
630fcf3ce44SJohn Forte 	/* Remove session from ihp */
631fcf3ce44SJohn Forte 	if (ihp->hba_sess_list == isp) {
632fcf3ce44SJohn Forte 		/* session first item in list */
633fcf3ce44SJohn Forte 		ihp->hba_sess_list = isp->sess_next;
634fcf3ce44SJohn Forte 	} else {
635fcf3ce44SJohn Forte 		/*
636fcf3ce44SJohn Forte 		 * search hba list for isp pointing
637fcf3ce44SJohn Forte 		 * to session being removed.  Then
638fcf3ce44SJohn Forte 		 * update that sessions next pointer.
639fcf3ce44SJohn Forte 		 */
640fcf3ce44SJohn Forte 		t_isp = ihp->hba_sess_list;
641fcf3ce44SJohn Forte 		while (t_isp->sess_next != NULL) {
642fcf3ce44SJohn Forte 			if (t_isp->sess_next == isp) {
643fcf3ce44SJohn Forte 				break;
644fcf3ce44SJohn Forte 			}
645fcf3ce44SJohn Forte 			t_isp = t_isp->sess_next;
646fcf3ce44SJohn Forte 		}
647fcf3ce44SJohn Forte 		if (t_isp->sess_next == isp) {
648fcf3ce44SJohn Forte 			t_isp->sess_next = isp->sess_next;
649fcf3ce44SJohn Forte 		} else {
650fcf3ce44SJohn Forte 			/* couldn't find session */
651fcf3ce44SJohn Forte 			ASSERT(FALSE);
652fcf3ce44SJohn Forte 		}
653fcf3ce44SJohn Forte 	}
654fcf3ce44SJohn Forte 
655904e51f6SJack Meng 	if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
656904e51f6SJack Meng 		/* Wait for all enum requests complete */
657904e51f6SJack Meng 		mutex_enter(&isp->sess_enum_lock);
658904e51f6SJack Meng 		while (isp->sess_enum_result_count > 0) {
659904e51f6SJack Meng 			cv_wait(&isp->sess_enum_cv, &isp->sess_enum_lock);
660904e51f6SJack Meng 		}
661904e51f6SJack Meng 		mutex_exit(&isp->sess_enum_lock);
662904e51f6SJack Meng 	}
663904e51f6SJack Meng 
664fcf3ce44SJohn Forte 	/* Destroy this Sessions Data */
665fcf3ce44SJohn Forte 	(void) iscsi_sess_kstat_term(isp);
666fcf3ce44SJohn Forte 	rw_destroy(&isp->sess_lun_list_rwlock);
667fcf3ce44SJohn Forte 	rw_destroy(&isp->sess_conn_list_rwlock);
668fcf3ce44SJohn Forte 	mutex_destroy(&isp->sess_cmdsn_mutex);
669904e51f6SJack Meng 	rw_destroy(&isp->sess_state_rwlock);
6702b79d384Sbing zhao - Sun Microsystems - Beijing China 	mutex_destroy(&isp->sess_reset_mutex);
671904e51f6SJack Meng 	if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
672904e51f6SJack Meng 		mutex_destroy(&isp->sess_enum_lock);
673904e51f6SJack Meng 		cv_destroy(&isp->sess_enum_cv);
674904e51f6SJack Meng 	}
675904e51f6SJack Meng 	mutex_destroy(&isp->sess_state_wmutex);
676904e51f6SJack Meng 	cv_destroy(&isp->sess_state_wcv);
677fcf3ce44SJohn Forte 	kmem_free(isp, sizeof (iscsi_sess_t));
678fcf3ce44SJohn Forte 	return (rval);
679fcf3ce44SJohn Forte }
680fcf3ce44SJohn Forte 
6816cefaae1SJack Meng extern ib_boot_prop_t   *iscsiboot_prop;
682fcf3ce44SJohn Forte /*
683fcf3ce44SJohn Forte  * static iscsi_sess_set_auth -
684fcf3ce44SJohn Forte  *
685fcf3ce44SJohn Forte  */
686fcf3ce44SJohn Forte boolean_t
iscsi_sess_set_auth(iscsi_sess_t * isp)687fcf3ce44SJohn Forte iscsi_sess_set_auth(iscsi_sess_t *isp)
688fcf3ce44SJohn Forte {
689fcf3ce44SJohn Forte 	char			*init_name;
690fcf3ce44SJohn Forte 	iscsi_chap_props_t	*chap = NULL;
691fcf3ce44SJohn Forte 	iscsi_auth_props_t	*auth = NULL;
6926cefaae1SJack Meng 	uchar_t			*tmp  = NULL;
693fcf3ce44SJohn Forte 
694fcf3ce44SJohn Forte 	if (isp == (iscsi_sess_t *)NULL) {
695fcf3ce44SJohn Forte 		return (B_FALSE);
696fcf3ce44SJohn Forte 	}
697fcf3ce44SJohn Forte 
698fcf3ce44SJohn Forte 	/* Obtain initiator's name */
699fcf3ce44SJohn Forte 	if (isp->sess_hba == (iscsi_hba_t *)NULL) {
700fcf3ce44SJohn Forte 		return (B_FALSE);
701fcf3ce44SJohn Forte 	}
7026cefaae1SJack Meng 
703fcf3ce44SJohn Forte 	init_name = (char *)isp->sess_hba->hba_name;
704fcf3ce44SJohn Forte 
7056cefaae1SJack Meng 	/* Zero out the session authentication structure */
7066cefaae1SJack Meng 	bzero(&isp->sess_auth, sizeof (iscsi_auth_t));
7076cefaae1SJack Meng 
7086cefaae1SJack Meng 	if (isp->sess_boot == B_FALSE) {
7096cefaae1SJack Meng 
7106cefaae1SJack Meng 		auth = (iscsi_auth_props_t *)kmem_zalloc
7116cefaae1SJack Meng 		    (sizeof (iscsi_auth_props_t), KM_SLEEP);
7126cefaae1SJack Meng 		/* Obtain target's authentication settings. */
7136cefaae1SJack Meng 		if (persistent_auth_get((char *)isp->sess_name, auth)
7146cefaae1SJack Meng 		    != B_TRUE) {
7156cefaae1SJack Meng 			/*
7166cefaae1SJack Meng 			 * If no target authentication settings found,
7176cefaae1SJack Meng 			 * try to obtain system wide configuration
7186cefaae1SJack Meng 			 * (from the initiator).
7196cefaae1SJack Meng 			 */
720fcf3ce44SJohn Forte 			bzero(auth, sizeof (*auth));
7216cefaae1SJack Meng 			if (persistent_auth_get(init_name, auth) != B_TRUE) {
7226cefaae1SJack Meng 				bzero(auth, sizeof (*auth));
7236cefaae1SJack Meng 				auth->a_auth_method = authMethodNone;
7246cefaae1SJack Meng 			}
725fcf3ce44SJohn Forte 
7266cefaae1SJack Meng 			/*
7276cefaae1SJack Meng 			 * We do not support system wide bi-directional
7286cefaae1SJack Meng 			 * auth flag.
7296cefaae1SJack Meng 			 */
7306cefaae1SJack Meng 			auth->a_bi_auth = B_FALSE;
7316cefaae1SJack Meng 		}
732fcf3ce44SJohn Forte 
7336cefaae1SJack Meng 		chap = (iscsi_chap_props_t *)kmem_zalloc
7346cefaae1SJack Meng 		    (sizeof (iscsi_chap_props_t), KM_SLEEP);
735fcf3ce44SJohn Forte 
7366cefaae1SJack Meng 		/*
7376cefaae1SJack Meng 		 * Initialize the target-side chap name to the session name
7386cefaae1SJack Meng 		 * if no chap settings have been saved for the current session.
7396cefaae1SJack Meng 		 */
7406cefaae1SJack Meng 		if (persistent_chap_get((char *)isp->sess_name, chap)
7416cefaae1SJack Meng 		    == B_FALSE) {
7426cefaae1SJack Meng 			int name_len = strlen((char *)isp->sess_name);
7436cefaae1SJack Meng 			bcopy((char *)isp->sess_name, chap->c_user, name_len);
7446cefaae1SJack Meng 			chap->c_user_len = name_len;
7456cefaae1SJack Meng 			(void) (persistent_chap_set((char *)isp->sess_name,
7466cefaae1SJack Meng 			    chap));
7476cefaae1SJack Meng 			bzero(chap, sizeof (*chap));
7486cefaae1SJack Meng 		}
749fcf3ce44SJohn Forte 
7506cefaae1SJack Meng 		if (auth->a_auth_method & authMethodCHAP) {
7516cefaae1SJack Meng 			/* Obtain initiator's CHAP settings. */
7526cefaae1SJack Meng 			if (persistent_chap_get(init_name, chap) == B_FALSE) {
7536cefaae1SJack Meng 				/* No initiator secret defined. */
7546cefaae1SJack Meng 				kmem_free(chap, sizeof (iscsi_chap_props_t));
7556cefaae1SJack Meng 				/* Set authentication method to NONE */
7566cefaae1SJack Meng 				isp->sess_auth.password_length = 0;
7576cefaae1SJack Meng 				kmem_free(auth, sizeof (iscsi_auth_props_t));
7586cefaae1SJack Meng 				return (B_FALSE);
7596cefaae1SJack Meng 			}
760fcf3ce44SJohn Forte 
7616cefaae1SJack Meng 			bcopy(chap->c_user, isp->sess_auth.username,
7626cefaae1SJack Meng 			    sizeof (chap->c_user));
7636cefaae1SJack Meng 			bcopy(chap->c_secret, isp->sess_auth.password,
7646cefaae1SJack Meng 			    sizeof (chap->c_secret));
7656cefaae1SJack Meng 			isp->sess_auth.password_length = chap->c_secret_len;
7666cefaae1SJack Meng 		} else {
767fcf3ce44SJohn Forte 			/* Set authentication method to NONE */
768fcf3ce44SJohn Forte 			isp->sess_auth.password_length = 0;
7696cefaae1SJack Meng 		}
7706cefaae1SJack Meng 
7716cefaae1SJack Meng 		/*
7726cefaae1SJack Meng 		 * Consider enabling bidirectional authentication only if
7736cefaae1SJack Meng 		 * authentication method is not NONE.
7746cefaae1SJack Meng 		 */
7756cefaae1SJack Meng 		if (auth->a_auth_method & authMethodCHAP &&
7766cefaae1SJack Meng 		    auth->a_bi_auth == B_TRUE) {
7776cefaae1SJack Meng 			/* Enable bi-directional authentication. */
7786cefaae1SJack Meng 			isp->sess_auth.bidirectional_auth = 1;
7796cefaae1SJack Meng 
7806cefaae1SJack Meng 			bzero(chap, sizeof (*chap));
7816cefaae1SJack Meng 			/* Obtain target's CHAP settings. */
7826cefaae1SJack Meng 			if (persistent_chap_get((char *)isp->sess_name, chap)
7836cefaae1SJack Meng 			    == B_TRUE) {
7846cefaae1SJack Meng 				bcopy(chap->c_secret,
7856cefaae1SJack Meng 				    isp->sess_auth.password_in,
7866cefaae1SJack Meng 				    sizeof (chap->c_secret));
7876cefaae1SJack Meng 				bcopy(chap->c_user, isp->sess_auth.username_in,
7886cefaae1SJack Meng 				    strlen((char *)chap->c_user));
7896cefaae1SJack Meng 				isp->sess_auth.password_length_in =
7906cefaae1SJack Meng 				    chap->c_secret_len;
7916cefaae1SJack Meng 			} else {
7926cefaae1SJack Meng 				/*
7936cefaae1SJack Meng 				 * No target secret defined.
7946cefaae1SJack Meng 				 * RADIUS server should have been enabled.
7956cefaae1SJack Meng 				 */
7966cefaae1SJack Meng 				/* EMPTY */
7976cefaae1SJack Meng 			}
7986cefaae1SJack Meng 		} else {
7996cefaae1SJack Meng 			/* Disable bi-directional authentication */
8006cefaae1SJack Meng 			isp->sess_auth.bidirectional_auth = 0;
8016cefaae1SJack Meng 		}
8026cefaae1SJack Meng 
8036cefaae1SJack Meng 		if (auth != NULL) {
804fcf3ce44SJohn Forte 			kmem_free(auth, sizeof (iscsi_auth_props_t));
8056cefaae1SJack Meng 		}
8066cefaae1SJack Meng 		if (chap != NULL) {
8076cefaae1SJack Meng 			kmem_free(chap, sizeof (iscsi_chap_props_t));
8086cefaae1SJack Meng 		}
8096cefaae1SJack Meng 	} else {
8106cefaae1SJack Meng 		/*
8116cefaae1SJack Meng 		 * This session is boot session. We will use the CHAP and
8126cefaae1SJack Meng 		 * the user name got from the boot property structure instead
8136cefaae1SJack Meng 		 * of persistent sotre.
8146cefaae1SJack Meng 		 */
8156cefaae1SJack Meng 		if (iscsiboot_prop == NULL) {
816fcf3ce44SJohn Forte 			return (B_FALSE);
817fcf3ce44SJohn Forte 		}
818fcf3ce44SJohn Forte 
8196cefaae1SJack Meng 		if (iscsiboot_prop->boot_init.ini_chap_sec == NULL) {
8206cefaae1SJack Meng 			return (B_FALSE);
8216cefaae1SJack Meng 		}
822fcf3ce44SJohn Forte 
8236cefaae1SJack Meng 		/* CHAP secret */
8246cefaae1SJack Meng 		(void) bcopy(iscsiboot_prop->boot_init.ini_chap_sec,
8256cefaae1SJack Meng 		    isp->sess_auth.password,
8266cefaae1SJack Meng 		    strlen((char *)iscsiboot_prop->boot_init.ini_chap_sec));
8276cefaae1SJack Meng 
8286cefaae1SJack Meng 		/*
8296cefaae1SJack Meng 		 * If chap name is not set,
8306cefaae1SJack Meng 		 * we will use initiator name instead.
8316cefaae1SJack Meng 		 */
8326cefaae1SJack Meng 		if (iscsiboot_prop->boot_init.ini_chap_name == NULL) {
8336cefaae1SJack Meng 			(void) bcopy(init_name, isp->sess_auth.username,
8346cefaae1SJack Meng 			    strlen(init_name));
835fcf3ce44SJohn Forte 		} else {
8366cefaae1SJack Meng 			tmp = iscsiboot_prop->boot_init.ini_chap_name;
8376cefaae1SJack Meng 			(void) bcopy(tmp,
8386cefaae1SJack Meng 			    isp->sess_auth.username, strlen((char *)tmp));
8396cefaae1SJack Meng 		}
8406cefaae1SJack Meng 
8416cefaae1SJack Meng 		isp->sess_auth.password_length =
8426cefaae1SJack Meng 		    strlen((char *)iscsiboot_prop->boot_init.ini_chap_sec);
8436cefaae1SJack Meng 
8446cefaae1SJack Meng 		if (iscsiboot_prop->boot_tgt.tgt_chap_sec != NULL) {
845fcf3ce44SJohn Forte 			/*
8466cefaae1SJack Meng 			 * Bidirectional authentication is required.
847fcf3ce44SJohn Forte 			 */
8486cefaae1SJack Meng 			tmp = iscsiboot_prop->boot_tgt.tgt_chap_sec;
8496cefaae1SJack Meng 			(void) bcopy(tmp,
8506cefaae1SJack Meng 			    isp->sess_auth.password_in, strlen((char *)tmp));
851fcf3ce44SJohn Forte 
8526cefaae1SJack Meng 			/*
8536cefaae1SJack Meng 			 * If the target's chap name is not set, we will use
8546cefaae1SJack Meng 			 * session name instead.
8556cefaae1SJack Meng 			 */
8566cefaae1SJack Meng 			if (iscsiboot_prop->boot_tgt.tgt_chap_name == NULL) {
8576cefaae1SJack Meng 				(void) bcopy(isp->sess_name,
8586cefaae1SJack Meng 				    isp->sess_auth.username_in,
8596cefaae1SJack Meng 				    isp->sess_name_length);
8606cefaae1SJack Meng 			} else {
8616cefaae1SJack Meng 				tmp = iscsiboot_prop->boot_tgt.tgt_chap_name;
8626cefaae1SJack Meng 				(void) bcopy(tmp,
8636cefaae1SJack Meng 				    isp->sess_auth.username_in,
8646cefaae1SJack Meng 				    strlen((char *)tmp));
8656cefaae1SJack Meng 			}
8666cefaae1SJack Meng 			tmp = iscsiboot_prop->boot_tgt.tgt_chap_sec;
8676cefaae1SJack Meng 			isp->sess_auth.password_length_in =
8686cefaae1SJack Meng 			    strlen((char *)tmp);
8696cefaae1SJack Meng 			isp->sess_auth.bidirectional_auth = 1;
8706cefaae1SJack Meng 		}
871fcf3ce44SJohn Forte 	}
872fcf3ce44SJohn Forte 
873fcf3ce44SJohn Forte 	/* Set up authentication buffers only if configured */
874fcf3ce44SJohn Forte 	if ((isp->sess_auth.password_length != 0) ||
875fcf3ce44SJohn Forte 	    (isp->sess_auth.password_length_in != 0)) {
876fcf3ce44SJohn Forte 		isp->sess_auth.num_auth_buffers = 5;
877fcf3ce44SJohn Forte 		isp->sess_auth.auth_buffers[0].address =
878fcf3ce44SJohn Forte 		    &(isp->sess_auth.auth_client_block);
879fcf3ce44SJohn Forte 		isp->sess_auth.auth_buffers[0].length =
880fcf3ce44SJohn Forte 		    sizeof (isp->sess_auth.auth_client_block);
881fcf3ce44SJohn Forte 		isp->sess_auth.auth_buffers[1].address =
882fcf3ce44SJohn Forte 		    &(isp->sess_auth.auth_recv_string_block);
883fcf3ce44SJohn Forte 		isp->sess_auth.auth_buffers[1].length =
884fcf3ce44SJohn Forte 		    sizeof (isp->sess_auth.auth_recv_string_block);
885fcf3ce44SJohn Forte 		isp->sess_auth.auth_buffers[2].address =
886fcf3ce44SJohn Forte 		    &(isp->sess_auth.auth_send_string_block);
887fcf3ce44SJohn Forte 		isp->sess_auth.auth_buffers[2].length =
888fcf3ce44SJohn Forte 		    sizeof (isp->sess_auth.auth_send_string_block);
889fcf3ce44SJohn Forte 		isp->sess_auth.auth_buffers[3].address =
890fcf3ce44SJohn Forte 		    &(isp->sess_auth.auth_recv_binary_block);
891fcf3ce44SJohn Forte 		isp->sess_auth.auth_buffers[3].length =
892fcf3ce44SJohn Forte 		    sizeof (isp->sess_auth.auth_recv_binary_block);
893fcf3ce44SJohn Forte 		isp->sess_auth.auth_buffers[4].address =
894fcf3ce44SJohn Forte 		    &(isp->sess_auth.auth_send_binary_block);
895fcf3ce44SJohn Forte 		isp->sess_auth.auth_buffers[4].length =
896fcf3ce44SJohn Forte 		    sizeof (isp->sess_auth.auth_send_binary_block);
897fcf3ce44SJohn Forte 	}
898fcf3ce44SJohn Forte 
899fcf3ce44SJohn Forte 	return (B_TRUE);
900fcf3ce44SJohn Forte }
901fcf3ce44SJohn Forte 
90230e7468fSPeter Dunlap /*
90330e7468fSPeter Dunlap  * iscsi_sess_reserve_itt - Used to reserve an ITT hash slot
90430e7468fSPeter Dunlap  */
90530e7468fSPeter Dunlap iscsi_status_t
iscsi_sess_reserve_scsi_itt(iscsi_cmd_t * icmdp)90630e7468fSPeter Dunlap iscsi_sess_reserve_scsi_itt(iscsi_cmd_t *icmdp)
90730e7468fSPeter Dunlap {
90830e7468fSPeter Dunlap 	idm_task_t *itp;
90930e7468fSPeter Dunlap 	iscsi_conn_t *icp = icmdp->cmd_conn;
91030e7468fSPeter Dunlap 	itp = idm_task_alloc(icp->conn_ic);
91130e7468fSPeter Dunlap 	if (itp == NULL)
91230e7468fSPeter Dunlap 		return (ISCSI_STATUS_INTERNAL_ERROR);
91330e7468fSPeter Dunlap 	itp->idt_private = icmdp;
91430e7468fSPeter Dunlap 	icmdp->cmd_itp = itp;
91530e7468fSPeter Dunlap 	icmdp->cmd_itt = itp->idt_tt;
91630e7468fSPeter Dunlap 	return (ISCSI_STATUS_SUCCESS);
91730e7468fSPeter Dunlap }
91830e7468fSPeter Dunlap 
91930e7468fSPeter Dunlap /*
92030e7468fSPeter Dunlap  * iscsi_sess_release_scsi_itt - Used to release ITT hash slot
92130e7468fSPeter Dunlap  */
92230e7468fSPeter Dunlap void
iscsi_sess_release_scsi_itt(iscsi_cmd_t * icmdp)92330e7468fSPeter Dunlap iscsi_sess_release_scsi_itt(iscsi_cmd_t *icmdp)
92430e7468fSPeter Dunlap {
92530e7468fSPeter Dunlap 	idm_task_free(icmdp->cmd_itp);
92630e7468fSPeter Dunlap }
927fcf3ce44SJohn Forte 
928fcf3ce44SJohn Forte /*
929fcf3ce44SJohn Forte  * iscsi_sess_reserve_itt - Used to reserve an ITT hash slot
930fcf3ce44SJohn Forte  */
931fcf3ce44SJohn Forte iscsi_status_t
iscsi_sess_reserve_itt(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)932fcf3ce44SJohn Forte iscsi_sess_reserve_itt(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
933fcf3ce44SJohn Forte {
934fcf3ce44SJohn Forte 	/* If no more slots are open fail reservation */
935fcf3ce44SJohn Forte 	if (isp->sess_cmd_table_count >= ISCSI_CMD_TABLE_SIZE) {
936fcf3ce44SJohn Forte 		return (ISCSI_STATUS_ITT_TABLE_FULL);
937fcf3ce44SJohn Forte 	}
938fcf3ce44SJohn Forte 
93930e7468fSPeter Dunlap 	/*
94030e7468fSPeter Dunlap 	 * Keep itt values out of the range used by IDM
94130e7468fSPeter Dunlap 	 */
94230e7468fSPeter Dunlap 	if (isp->sess_itt < IDM_TASKIDS_MAX)
94330e7468fSPeter Dunlap 		isp->sess_itt = IDM_TASKIDS_MAX;
94430e7468fSPeter Dunlap 
945fcf3ce44SJohn Forte 	/*
946fcf3ce44SJohn Forte 	 * Find the next available slot.  Normally its the
947fcf3ce44SJohn Forte 	 * slot pointed to by the session's sess_itt value.
948fcf3ce44SJohn Forte 	 * If this is not true the table has become fragmented.
949fcf3ce44SJohn Forte 	 * Fragmentation can occur during max loads and IOs
950fcf3ce44SJohn Forte 	 * are completed out of order.  Defragmentation will
951fcf3ce44SJohn Forte 	 * occur when IO slows down and ITT slots are released.
952fcf3ce44SJohn Forte 	 */
953fcf3ce44SJohn Forte 	while (isp->sess_cmd_table[isp->sess_itt %
954fcf3ce44SJohn Forte 	    ISCSI_CMD_TABLE_SIZE] != NULL) {
955fcf3ce44SJohn Forte 		isp->sess_itt++;
956fcf3ce44SJohn Forte 	}
957fcf3ce44SJohn Forte 
958fcf3ce44SJohn Forte 	/* reserve slot and update counters */
959fcf3ce44SJohn Forte 	icmdp->cmd_itt = isp->sess_itt;
96030e7468fSPeter Dunlap 	isp->sess_cmd_table[isp->sess_itt %
961fcf3ce44SJohn Forte 	    ISCSI_CMD_TABLE_SIZE] = icmdp;
962fcf3ce44SJohn Forte 	isp->sess_cmd_table_count++;
963fcf3ce44SJohn Forte 	isp->sess_itt++;
964fcf3ce44SJohn Forte 
965fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
966fcf3ce44SJohn Forte }
967fcf3ce44SJohn Forte 
968fcf3ce44SJohn Forte /*
969fcf3ce44SJohn Forte  * iscsi_sess_release_itt - Used to release ITT hash slot
970fcf3ce44SJohn Forte  */
971fcf3ce44SJohn Forte void
iscsi_sess_release_itt(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)972fcf3ce44SJohn Forte iscsi_sess_release_itt(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
973fcf3ce44SJohn Forte {
974fcf3ce44SJohn Forte 	int hash_index = (icmdp->cmd_itt % ISCSI_CMD_TABLE_SIZE);
975fcf3ce44SJohn Forte 
976fcf3ce44SJohn Forte 	ASSERT(isp->sess_cmd_table[hash_index] != NULL);
977fcf3ce44SJohn Forte 
978fcf3ce44SJohn Forte 	/* release slot and update counters */
979fcf3ce44SJohn Forte 	isp->sess_cmd_table[hash_index] = NULL;
980fcf3ce44SJohn Forte 	isp->sess_cmd_table_count--;
981fcf3ce44SJohn Forte }
982fcf3ce44SJohn Forte 
983fcf3ce44SJohn Forte /*
984fcf3ce44SJohn Forte  * iscsi_sess_redrive_io - Used to redrive IO on connections in
985fcf3ce44SJohn Forte  * a full feature state.
986fcf3ce44SJohn Forte  */
987fcf3ce44SJohn Forte void
iscsi_sess_redrive_io(iscsi_sess_t * isp)988fcf3ce44SJohn Forte iscsi_sess_redrive_io(iscsi_sess_t *isp)
989fcf3ce44SJohn Forte {
990fcf3ce44SJohn Forte 	iscsi_conn_t	*icp;
991fcf3ce44SJohn Forte 
992fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
993fcf3ce44SJohn Forte 
994fcf3ce44SJohn Forte 	icp = isp->sess_conn_list;
995fcf3ce44SJohn Forte 	while (icp != NULL) {
996fcf3ce44SJohn Forte 		if (ISCSI_CONN_STATE_FULL_FEATURE(
997fcf3ce44SJohn Forte 		    icp->conn_state)) {
99849311b35SJack Meng 			(void) iscsi_thread_send_wakeup(
999fcf3ce44SJohn Forte 			    icp->conn_tx_thread);
1000fcf3ce44SJohn Forte 		}
1001fcf3ce44SJohn Forte 		icp = icp->conn_next;
1002fcf3ce44SJohn Forte 	}
1003fcf3ce44SJohn Forte }
1004fcf3ce44SJohn Forte 
1005fcf3ce44SJohn Forte /*
1006fcf3ce44SJohn Forte  * iscsi_sess_state_machine -
1007fcf3ce44SJohn Forte  *
1008fcf3ce44SJohn Forte  * 7.3.1  Session State Diagram for an Initiator
1009fcf3ce44SJohn Forte  *
1010fcf3ce44SJohn Forte  *      Symbolic Names for States:
1011fcf3ce44SJohn Forte  *        Q1: FREE      - State on instantiation of after cleanup
1012fcf3ce44SJohn Forte  *        Q3: LOGGED_IN - Waiting for all session events.
1013fcf3ce44SJohn Forte  *        Q4: FAILED    - Waiting for session recovery or session cont.
1014fcf3ce44SJohn Forte  *        Q5: IN_FLUSH	- A login parameter has changed.  We are in the
1015fcf3ce44SJohn Forte  *			  process of flushing active, aborting, and
1016fcf3ce44SJohn Forte  *			  completed queues. Once flushed the iscsi_ic_thread()
1017fcf3ce44SJohn Forte  *			  will drop of drop connections (T14) and reconnect
1018fcf3ce44SJohn Forte  *			  to the target with new values.
1019fcf3ce44SJohn Forte  *	  Q6: FLUSHED	- Active, Aborting and Completed Queues flushed.
1020fcf3ce44SJohn Forte  *			  Awaiting reconnect or failure. iscsi_tx/ic_threads
1021fcf3ce44SJohn Forte  *			  are still running and might be timing-out IOs.
1022fcf3ce44SJohn Forte  *      State Q3/4 represent the Full Feature Phase operation of the session.
1023fcf3ce44SJohn Forte  *
1024fcf3ce44SJohn Forte  *      The state diagram is as follows:
1025fcf3ce44SJohn Forte  *
1026cc7ef495Syi zhang - Sun Microsystems - Beijing China  *                                ------ (N5/6/7 == NOOP)
1027cc7ef495Syi zhang - Sun Microsystems - Beijing China  *                               / Q1    \
1028cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    +------------------------->\       /<-------------+
1029cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    |                           ---+---               |
1030cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    |                     N5       |N1                |
1031cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    |  +------+   +-------------+  |                  |
1032cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    |  |      V   V             |  V                  |
1033cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    |  |      ----+--           -----+                |
1034cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    |N6|N5/7 / Q4    \         / Q3   \(N6 == NOOP)   |
1035cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    +--+-----\       /----+--->\      /-----+---------+
1036cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    |         -------    /N1    -+----      |       N3|
1037cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    |  (N7 == NOOP)     /      N7|  ^ N1/3/5|         |
1038cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    |                  /         |  +-------+         |
1039cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    |  +-------+      /          |                    |
1040cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    |  |       V     /           v                    |
1041cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    |  |      -------           -+----                |
1042cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    |N6|N6   / Q6    \    N5   / Q5   \               |
1043cc7ef495Syi zhang - Sun Microsystems - Beijing China  *    +--+-----\       /<--------\      /-----+---------+
1044cc7ef495Syi zhang - Sun Microsystems - Beijing China  *              -------           ------      |       N3
1045cc7ef495Syi zhang - Sun Microsystems - Beijing China  *            (N7 == NOOP)            ^ N1/3/5|
1046cc7ef495Syi zhang - Sun Microsystems - Beijing China  *                                    +-------+
1047fcf3ce44SJohn Forte  *
1048fcf3ce44SJohn Forte  * The state transition table is as follows:
1049fcf3ce44SJohn Forte  *
1050cc7ef495Syi zhang - Sun Microsystems - Beijing China  *            +------+------+----+--------+----+
1051cc7ef495Syi zhang - Sun Microsystems - Beijing China  *            |Q1    |Q3    |Q4  |Q5      |Q6  |
1052cc7ef495Syi zhang - Sun Microsystems - Beijing China  *       -----+------+------+----+--------+----+
1053cc7ef495Syi zhang - Sun Microsystems - Beijing China  *        Q1  |N5/6/7|N1    | -  |        |    |
1054cc7ef495Syi zhang - Sun Microsystems - Beijing China  *       -----+------+------+----+--------+----+
1055cc7ef495Syi zhang - Sun Microsystems - Beijing China  *        Q3  |N3    |N1/3/5|N5  |N7      |    |
1056cc7ef495Syi zhang - Sun Microsystems - Beijing China  *       -----+------+------+----+--------+----+
1057cc7ef495Syi zhang - Sun Microsystems - Beijing China  *        Q4  |N6    |N1    |N5/7|        |    |
1058cc7ef495Syi zhang - Sun Microsystems - Beijing China  *       -----+------+------+----+--------+----+
1059cc7ef495Syi zhang - Sun Microsystems - Beijing China  *        Q5  |N3    |      |    |N1/3/5/7|N6  |
1060cc7ef495Syi zhang - Sun Microsystems - Beijing China  *       -----+------+------+----+--------+----+
1061cc7ef495Syi zhang - Sun Microsystems - Beijing China  *        Q6  |N6    |N1    |N6/7|        |    |
1062cc7ef495Syi zhang - Sun Microsystems - Beijing China  *       -----+------+------+----+--------+----+
1063fcf3ce44SJohn Forte  *
1064fcf3ce44SJohn Forte  * Event definitions:
1065fcf3ce44SJohn Forte  *
1066fcf3ce44SJohn Forte  * -N1: A connection logged in
1067fcf3ce44SJohn Forte  * -N3: A connection logged out
1068fcf3ce44SJohn Forte  * -N5: A connection failed
1069fcf3ce44SJohn Forte  * -N6: Session state timeout occurred, or a session
1070fcf3ce44SJohn Forte  *      reinstatement cleared this session instance.  This results in
1071fcf3ce44SJohn Forte  *      the freeing of all associated resources and the session state
1072fcf3ce44SJohn Forte  *      is discarded.
1073fcf3ce44SJohn Forte  * -N7: Login parameters for session have changed.
1074fcf3ce44SJohn Forte  *	Re-negeotation required.
1075904e51f6SJack Meng  *
1076904e51f6SJack Meng  * Any caller to the state machine (and so as a state writer) must
1077904e51f6SJack Meng  * enter the state zone before calling this function, and vice versa
1078904e51f6SJack Meng  * any caller that doesn't change the state machine shouldn't enter
1079904e51f6SJack Meng  * the zone, and should act as a reader for a better performance.
1080904e51f6SJack Meng  *
1081904e51f6SJack Meng  * The handler of state transition shouldn't try to enter the state
1082904e51f6SJack Meng  * zone in the same thread or dead lock will occur.
1083fcf3ce44SJohn Forte  */
1084fcf3ce44SJohn Forte void
iscsi_sess_state_machine(iscsi_sess_t * isp,iscsi_sess_event_t event,uint32_t event_count)1085904e51f6SJack Meng iscsi_sess_state_machine(iscsi_sess_t *isp, iscsi_sess_event_t event,
1086904e51f6SJack Meng     uint32_t event_count)
1087fcf3ce44SJohn Forte {
1088fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1089904e51f6SJack Meng 	ASSERT(rw_read_locked(&isp->sess_state_rwlock) == 0);
1090fcf3ce44SJohn Forte 
1091fcf3ce44SJohn Forte 	DTRACE_PROBE3(event, iscsi_sess_t *, isp,
1092fcf3ce44SJohn Forte 	    char *, iscsi_sess_state_str(isp->sess_state),
1093fcf3ce44SJohn Forte 	    char *, iscsi_sess_event_str(event));
1094fcf3ce44SJohn Forte 
109530e7468fSPeter Dunlap 	/* Audit event */
109630e7468fSPeter Dunlap 	idm_sm_audit_event(&isp->sess_state_audit,
1097*811eca55SToomas Soome 	    SAS_ISCSI_SESS, isp->sess_state, event, 0);
109830e7468fSPeter Dunlap 
1099fcf3ce44SJohn Forte 	isp->sess_prev_state = isp->sess_state;
1100fcf3ce44SJohn Forte 	isp->sess_state_lbolt = ddi_get_lbolt();
1101fcf3ce44SJohn Forte 
110230e7468fSPeter Dunlap 	ISCSI_SESS_LOG(CE_NOTE,
1103904e51f6SJack Meng 	    "DEBUG: sess_state: isp: %p state: %d event: %d event count: %d",
1104904e51f6SJack Meng 	    (void *)isp, isp->sess_state, event, event_count);
1105fcf3ce44SJohn Forte 	switch (isp->sess_state) {
1106fcf3ce44SJohn Forte 	case ISCSI_SESS_STATE_FREE:
1107904e51f6SJack Meng 		iscsi_sess_state_free(isp, event, event_count);
1108fcf3ce44SJohn Forte 		break;
1109fcf3ce44SJohn Forte 	case ISCSI_SESS_STATE_LOGGED_IN:
1110904e51f6SJack Meng 		iscsi_sess_state_logged_in(isp, event, event_count);
1111fcf3ce44SJohn Forte 		break;
1112fcf3ce44SJohn Forte 	case ISCSI_SESS_STATE_FAILED:
1113904e51f6SJack Meng 		iscsi_sess_state_failed(isp, event, event_count);
1114fcf3ce44SJohn Forte 		break;
1115fcf3ce44SJohn Forte 	case ISCSI_SESS_STATE_IN_FLUSH:
1116904e51f6SJack Meng 		iscsi_sess_state_in_flush(isp, event, event_count);
1117fcf3ce44SJohn Forte 		break;
1118fcf3ce44SJohn Forte 	case ISCSI_SESS_STATE_FLUSHED:
1119904e51f6SJack Meng 		iscsi_sess_state_flushed(isp, event, event_count);
1120fcf3ce44SJohn Forte 		break;
1121fcf3ce44SJohn Forte 	default:
1122fcf3ce44SJohn Forte 		ASSERT(FALSE);
1123fcf3ce44SJohn Forte 	}
112430e7468fSPeter Dunlap 
112530e7468fSPeter Dunlap 	/* Audit state change */
112630e7468fSPeter Dunlap 	if (isp->sess_prev_state != isp->sess_state) {
112730e7468fSPeter Dunlap 		idm_sm_audit_state_change(&isp->sess_state_audit,
112830e7468fSPeter Dunlap 		    SAS_ISCSI_SESS, isp->sess_prev_state, isp->sess_state);
112930e7468fSPeter Dunlap 	}
1130fcf3ce44SJohn Forte }
1131fcf3ce44SJohn Forte 
1132fcf3ce44SJohn Forte 
1133fcf3ce44SJohn Forte /*
1134fcf3ce44SJohn Forte  * iscsi_sess_state_str -
1135fcf3ce44SJohn Forte  *
1136fcf3ce44SJohn Forte  */
1137fcf3ce44SJohn Forte char *
iscsi_sess_state_str(iscsi_sess_state_t state)1138fcf3ce44SJohn Forte iscsi_sess_state_str(iscsi_sess_state_t state)
1139fcf3ce44SJohn Forte {
1140fcf3ce44SJohn Forte 	switch (state) {
1141fcf3ce44SJohn Forte 	case ISCSI_SESS_STATE_FREE:
1142fcf3ce44SJohn Forte 		return ("free");
1143fcf3ce44SJohn Forte 	case ISCSI_SESS_STATE_LOGGED_IN:
1144fcf3ce44SJohn Forte 		return ("logged_in");
1145fcf3ce44SJohn Forte 	case ISCSI_SESS_STATE_FAILED:
1146fcf3ce44SJohn Forte 		return ("failed");
1147fcf3ce44SJohn Forte 	case ISCSI_SESS_STATE_IN_FLUSH:
1148fcf3ce44SJohn Forte 		return ("in_flush");
1149fcf3ce44SJohn Forte 	case ISCSI_SESS_STATE_FLUSHED:
1150fcf3ce44SJohn Forte 		return ("flushed");
1151fcf3ce44SJohn Forte 	default:
1152fcf3ce44SJohn Forte 		return ("unknown");
1153fcf3ce44SJohn Forte 	}
1154fcf3ce44SJohn Forte }
1155fcf3ce44SJohn Forte 
1156fcf3ce44SJohn Forte 
1157fcf3ce44SJohn Forte /*
1158fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
1159fcf3ce44SJohn Forte  * | Internal Session Interfaces					|
1160fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
1161fcf3ce44SJohn Forte  */
1162fcf3ce44SJohn Forte 
1163fcf3ce44SJohn Forte 
1164fcf3ce44SJohn Forte /*
1165fcf3ce44SJohn Forte  * iscsi_sess_state_free -
1166fcf3ce44SJohn Forte  *
1167fcf3ce44SJohn Forte  */
1168fcf3ce44SJohn Forte static void
iscsi_sess_state_free(iscsi_sess_t * isp,iscsi_sess_event_t event,uint32_t event_count)1169904e51f6SJack Meng iscsi_sess_state_free(iscsi_sess_t *isp, iscsi_sess_event_t event,
1170904e51f6SJack Meng     uint32_t event_count)
1171fcf3ce44SJohn Forte {
1172fcf3ce44SJohn Forte 	iscsi_hba_t		*ihp;
1173904e51f6SJack Meng 	iscsi_enum_result_t	enum_result;
1174fcf3ce44SJohn Forte 
1175fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1176fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
1177fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
1178fcf3ce44SJohn Forte 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FREE);
1179fcf3ce44SJohn Forte 
1180fcf3ce44SJohn Forte 	/* switch on event change */
1181fcf3ce44SJohn Forte 	switch (event) {
1182fcf3ce44SJohn Forte 	/*
1183fcf3ce44SJohn Forte 	 * -N1: A connection logged in
1184fcf3ce44SJohn Forte 	 */
1185fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N1:
118608f26845Sbing zhao - Sun Microsystems - Beijing China 		isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN;
1187904e51f6SJack Meng 		rw_downgrade(&isp->sess_state_rwlock);
118808f26845Sbing zhao - Sun Microsystems - Beijing China 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
118908f26845Sbing zhao - Sun Microsystems - Beijing China 			cmn_err(CE_NOTE,
119008f26845Sbing zhao - Sun Microsystems - Beijing China 			    "!iscsi session(%u) %s online\n",
119108f26845Sbing zhao - Sun Microsystems - Beijing China 			    isp->sess_oid, isp->sess_name);
1192904e51f6SJack Meng 			enum_result =
1193904e51f6SJack Meng 			    iscsi_sess_enum_request(isp, B_TRUE,
1194904e51f6SJack Meng 			    event_count);
1195904e51f6SJack Meng 			if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
1196904e51f6SJack Meng 				enum_result =
1197904e51f6SJack Meng 				    iscsi_sess_enum_query(isp);
1198904e51f6SJack Meng 			}
1199904e51f6SJack Meng 			if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
1200904e51f6SJack Meng 				iscsi_sess_enum_warn(isp, enum_result);
1201fcf3ce44SJohn Forte 			}
1202fcf3ce44SJohn Forte 		}
1203fcf3ce44SJohn Forte 		break;
1204fcf3ce44SJohn Forte 
1205cc7ef495Syi zhang - Sun Microsystems - Beijing China 	/*
1206cc7ef495Syi zhang - Sun Microsystems - Beijing China 	 * -N5: A connection failed
1207cc7ef495Syi zhang - Sun Microsystems - Beijing China 	 */
1208cc7ef495Syi zhang - Sun Microsystems - Beijing China 	case ISCSI_SESS_EVENT_N5:
1209cc7ef495Syi zhang - Sun Microsystems - Beijing China 		/* NOOP - not connected */
1210cc7ef495Syi zhang - Sun Microsystems - Beijing China 		break;
1211cc7ef495Syi zhang - Sun Microsystems - Beijing China 
1212fcf3ce44SJohn Forte 	/*
1213fcf3ce44SJohn Forte 	 * -N6: Session state timeout occurred, or a session
1214fcf3ce44SJohn Forte 	 *	reinstatement cleared this session instance.  This results in
1215fcf3ce44SJohn Forte 	 *	the freeing of all associated resources and the session state
1216fcf3ce44SJohn Forte 	 *	is discarded.
1217fcf3ce44SJohn Forte 	 */
1218fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N6:
1219fcf3ce44SJohn Forte 		/* FALLTHRU */
1220fcf3ce44SJohn Forte 
1221fcf3ce44SJohn Forte 	/*
1222fcf3ce44SJohn Forte 	 * -N7: Login parameters for session have changed.
1223fcf3ce44SJohn Forte 	 *	Re-negeotation required.
1224fcf3ce44SJohn Forte 	 */
1225fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N7:
1226fcf3ce44SJohn Forte 		/* NOOP - not connected */
1227fcf3ce44SJohn Forte 		break;
1228fcf3ce44SJohn Forte 
1229fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
1230fcf3ce44SJohn Forte 	default:
1231fcf3ce44SJohn Forte 		ASSERT(FALSE);
1232fcf3ce44SJohn Forte 	}
1233fcf3ce44SJohn Forte }
1234fcf3ce44SJohn Forte 
1235fcf3ce44SJohn Forte 
1236fcf3ce44SJohn Forte /*
1237fcf3ce44SJohn Forte  * iscsi_sess_logged_in -
1238fcf3ce44SJohn Forte  *
1239fcf3ce44SJohn Forte  */
1240fcf3ce44SJohn Forte static void
iscsi_sess_state_logged_in(iscsi_sess_t * isp,iscsi_sess_event_t event,uint32_t event_count)1241904e51f6SJack Meng iscsi_sess_state_logged_in(iscsi_sess_t *isp, iscsi_sess_event_t event,
1242904e51f6SJack Meng     uint32_t event_count)
1243fcf3ce44SJohn Forte {
1244904e51f6SJack Meng 	iscsi_enum_result_t	enum_result;
1245fcf3ce44SJohn Forte 
1246fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1247fcf3ce44SJohn Forte 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_LOGGED_IN);
1248fcf3ce44SJohn Forte 
1249fcf3ce44SJohn Forte 	/* switch on event change */
1250fcf3ce44SJohn Forte 	switch (event) {
1251fcf3ce44SJohn Forte 	/*
1252fcf3ce44SJohn Forte 	 * -N1: At least one transport connection reached the
1253fcf3ce44SJohn Forte 	 * LOGGED_IN state
1254fcf3ce44SJohn Forte 	 */
1255fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N1:
1256fcf3ce44SJohn Forte 		/*
1257fcf3ce44SJohn Forte 		 * A different connection already logged in.  If the
1258fcf3ce44SJohn Forte 		 * session is NORMAL, just re-enumerate the session.
1259fcf3ce44SJohn Forte 		 */
1260904e51f6SJack Meng 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1261904e51f6SJack Meng 			rw_downgrade(&isp->sess_state_rwlock);
1262904e51f6SJack Meng 			enum_result =
1263904e51f6SJack Meng 			    iscsi_sess_enum_request(isp, B_TRUE, event_count);
1264904e51f6SJack Meng 			if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
1265904e51f6SJack Meng 				enum_result = iscsi_sess_enum_query(isp);
1266904e51f6SJack Meng 			}
1267904e51f6SJack Meng 			if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
1268904e51f6SJack Meng 				iscsi_sess_enum_warn(isp, enum_result);
1269904e51f6SJack Meng 			}
1270fcf3ce44SJohn Forte 		}
1271fcf3ce44SJohn Forte 		break;
1272fcf3ce44SJohn Forte 
1273fcf3ce44SJohn Forte 	/*
1274fcf3ce44SJohn Forte 	 * -N3: A connection logged out.
1275fcf3ce44SJohn Forte 	 */
1276fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N3:
1277fcf3ce44SJohn Forte 		/* FALLTHRU */
1278fcf3ce44SJohn Forte 
1279fcf3ce44SJohn Forte 	/*
1280fcf3ce44SJohn Forte 	 * -N5: A connection failed
1281fcf3ce44SJohn Forte 	 */
1282fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N5:
1283fcf3ce44SJohn Forte 		/*
1284fcf3ce44SJohn Forte 		 * MC/S: If this is the last connection to
1285fcf3ce44SJohn Forte 		 * fail then move the the failed state.
1286fcf3ce44SJohn Forte 		 */
1287fcf3ce44SJohn Forte 		if (event == ISCSI_SESS_EVENT_N3) {
1288fcf3ce44SJohn Forte 			isp->sess_state = ISCSI_SESS_STATE_FREE;
1289fcf3ce44SJohn Forte 		} else {
1290fcf3ce44SJohn Forte 			isp->sess_state = ISCSI_SESS_STATE_FAILED;
1291fcf3ce44SJohn Forte 		}
1292904e51f6SJack Meng 		rw_downgrade(&isp->sess_state_rwlock);
1293fcf3ce44SJohn Forte 
1294fcf3ce44SJohn Forte 		/* no longer connected reset nego tpgt */
1295fcf3ce44SJohn Forte 		isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT;
1296fcf3ce44SJohn Forte 
1297fcf3ce44SJohn Forte 		iscsi_sess_flush(isp);
1298fcf3ce44SJohn Forte 
1299fcf3ce44SJohn Forte 		if (event == ISCSI_SESS_EVENT_N3) {
1300fcf3ce44SJohn Forte 			if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1301fcf3ce44SJohn Forte 				cmn_err(CE_NOTE,
1302fcf3ce44SJohn Forte 				    "!iscsi session(%u) %s offline\n",
1303fcf3ce44SJohn Forte 				    isp->sess_oid, isp->sess_name);
1304fcf3ce44SJohn Forte 			}
130555364d2bSJack Meng 			/*
130655364d2bSJack Meng 			 * During the process of offlining the LUNs
130755364d2bSJack Meng 			 * our ic thread might be calling back into
130855364d2bSJack Meng 			 * the driver via a target driver failure
130955364d2bSJack Meng 			 * path to do a reset or something
131055364d2bSJack Meng 			 * we need to release the sess_state_mutex
131155364d2bSJack Meng 			 * while we are killing these threads so
131255364d2bSJack Meng 			 * they don't get deadlocked.
131355364d2bSJack Meng 			 */
1314fcf3ce44SJohn Forte 			iscsi_sess_offline_luns(isp);
1315fcf3ce44SJohn Forte 		}
1316fcf3ce44SJohn Forte 
13172b79d384Sbing zhao - Sun Microsystems - Beijing China 		mutex_enter(&isp->sess_reset_mutex);
13182b79d384Sbing zhao - Sun Microsystems - Beijing China 		isp->sess_reset_in_progress = B_FALSE;
13192b79d384Sbing zhao - Sun Microsystems - Beijing China 		mutex_exit(&isp->sess_reset_mutex);
13202b79d384Sbing zhao - Sun Microsystems - Beijing China 		/* update busy luns if needed */
13212b79d384Sbing zhao - Sun Microsystems - Beijing China 		iscsi_sess_update_busy_luns(isp, B_TRUE);
13222b79d384Sbing zhao - Sun Microsystems - Beijing China 
1323fcf3ce44SJohn Forte 		break;
1324fcf3ce44SJohn Forte 
1325fcf3ce44SJohn Forte 	/*
1326fcf3ce44SJohn Forte 	 * -N6: Session state timeout occurred, or a session
1327fcf3ce44SJohn Forte 	 *	reinstatement cleared this session instance.  This results in
1328fcf3ce44SJohn Forte 	 *	the freeing of all associated resources and the session state
1329fcf3ce44SJohn Forte 	 *	is discarded.
1330fcf3ce44SJohn Forte 	 */
1331fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N6:
1332fcf3ce44SJohn Forte 		/* NOOP - Not last connection */
1333fcf3ce44SJohn Forte 		break;
1334fcf3ce44SJohn Forte 
1335fcf3ce44SJohn Forte 	/*
1336fcf3ce44SJohn Forte 	 * -N7: Login parameters for session have changed.
1337fcf3ce44SJohn Forte 	 *	Re-negeotation required.
1338fcf3ce44SJohn Forte 	 */
1339fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N7:
1340fcf3ce44SJohn Forte 		isp->sess_state = ISCSI_SESS_STATE_IN_FLUSH;
1341fcf3ce44SJohn Forte 		break;
1342fcf3ce44SJohn Forte 
1343fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
1344fcf3ce44SJohn Forte 	default:
1345fcf3ce44SJohn Forte 		ASSERT(FALSE);
1346fcf3ce44SJohn Forte 	}
1347fcf3ce44SJohn Forte }
1348fcf3ce44SJohn Forte 
1349fcf3ce44SJohn Forte 
1350fcf3ce44SJohn Forte /*
1351fcf3ce44SJohn Forte  * iscsi_sess_state_failed -
1352fcf3ce44SJohn Forte  *
1353fcf3ce44SJohn Forte  */
1354fcf3ce44SJohn Forte static void
iscsi_sess_state_failed(iscsi_sess_t * isp,iscsi_sess_event_t event,uint32_t event_count)1355904e51f6SJack Meng iscsi_sess_state_failed(iscsi_sess_t *isp, iscsi_sess_event_t event,
1356904e51f6SJack Meng     uint32_t event_count)
1357fcf3ce44SJohn Forte {
1358fcf3ce44SJohn Forte 	iscsi_hba_t		*ihp;
1359904e51f6SJack Meng 	iscsi_enum_result_t	enum_result;
1360fcf3ce44SJohn Forte 
1361fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1362fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
1363fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
1364fcf3ce44SJohn Forte 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FAILED);
1365fcf3ce44SJohn Forte 
1366fcf3ce44SJohn Forte 	/* switch on event change */
1367fcf3ce44SJohn Forte 	switch (event) {
1368fcf3ce44SJohn Forte 	/* -N1: A session continuation attempt succeeded */
1369fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N1:
137008f26845Sbing zhao - Sun Microsystems - Beijing China 		isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN;
1371904e51f6SJack Meng 		rw_downgrade(&isp->sess_state_rwlock);
1372904e51f6SJack Meng 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1373904e51f6SJack Meng 			enum_result =
1374904e51f6SJack Meng 			    iscsi_sess_enum_request(isp, B_TRUE,
1375904e51f6SJack Meng 			    event_count);
1376904e51f6SJack Meng 			if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
1377904e51f6SJack Meng 				enum_result =
1378904e51f6SJack Meng 				    iscsi_sess_enum_query(isp);
1379904e51f6SJack Meng 			}
1380904e51f6SJack Meng 			if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
1381904e51f6SJack Meng 				iscsi_sess_enum_warn(isp, enum_result);
1382fcf3ce44SJohn Forte 			}
1383fcf3ce44SJohn Forte 		}
1384fcf3ce44SJohn Forte 		break;
1385fcf3ce44SJohn Forte 
1386cc7ef495Syi zhang - Sun Microsystems - Beijing China 	/*
1387cc7ef495Syi zhang - Sun Microsystems - Beijing China 	 * -N5: A connection failed
1388cc7ef495Syi zhang - Sun Microsystems - Beijing China 	 */
1389cc7ef495Syi zhang - Sun Microsystems - Beijing China 	case ISCSI_SESS_EVENT_N5:
1390cc7ef495Syi zhang - Sun Microsystems - Beijing China 		/* NOOP - not connected */
1391cc7ef495Syi zhang - Sun Microsystems - Beijing China 		break;
1392cc7ef495Syi zhang - Sun Microsystems - Beijing China 
1393fcf3ce44SJohn Forte 	/*
1394fcf3ce44SJohn Forte 	 * -N6: Session state timeout occurred, or a session
1395fcf3ce44SJohn Forte 	 *	reinstatement cleared this session instance.  This results in
1396fcf3ce44SJohn Forte 	 *	the freeing of all associated resources and the session state
1397fcf3ce44SJohn Forte 	 *	is discarded.
1398fcf3ce44SJohn Forte 	 */
1399fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N6:
1400fcf3ce44SJohn Forte 		isp->sess_state = ISCSI_SESS_STATE_FREE;
1401fcf3ce44SJohn Forte 
1402fcf3ce44SJohn Forte 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1403fcf3ce44SJohn Forte 			cmn_err(CE_NOTE, "!iscsi session(%u) %s offline\n",
1404fcf3ce44SJohn Forte 			    isp->sess_oid, isp->sess_name);
1405fcf3ce44SJohn Forte 		}
1406fcf3ce44SJohn Forte 
1407904e51f6SJack Meng 		rw_downgrade(&isp->sess_state_rwlock);
1408fcf3ce44SJohn Forte 		iscsi_sess_offline_luns(isp);
1409fcf3ce44SJohn Forte 		break;
1410fcf3ce44SJohn Forte 
1411fcf3ce44SJohn Forte 	/*
1412fcf3ce44SJohn Forte 	 * -N7: Login parameters for session have changed.
1413fcf3ce44SJohn Forte 	 *	Re-negeotation required.
1414fcf3ce44SJohn Forte 	 */
1415fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N7:
1416fcf3ce44SJohn Forte 		/* NOOP - not connected */
1417fcf3ce44SJohn Forte 		break;
1418fcf3ce44SJohn Forte 
1419fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
1420fcf3ce44SJohn Forte 	default:
1421fcf3ce44SJohn Forte 		ASSERT(FALSE);
1422fcf3ce44SJohn Forte 	}
1423fcf3ce44SJohn Forte }
1424fcf3ce44SJohn Forte 
1425fcf3ce44SJohn Forte /*
1426fcf3ce44SJohn Forte  * iscsi_sess_state_in_flush -
1427fcf3ce44SJohn Forte  *
1428fcf3ce44SJohn Forte  */
1429904e51f6SJack Meng /* ARGSUSED */
1430fcf3ce44SJohn Forte static void
iscsi_sess_state_in_flush(iscsi_sess_t * isp,iscsi_sess_event_t event,uint32_t event_count)1431904e51f6SJack Meng iscsi_sess_state_in_flush(iscsi_sess_t *isp, iscsi_sess_event_t event,
1432904e51f6SJack Meng     uint32_t event_count)
1433fcf3ce44SJohn Forte {
1434fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1435fcf3ce44SJohn Forte 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_IN_FLUSH);
1436fcf3ce44SJohn Forte 
1437fcf3ce44SJohn Forte 	/* switch on event change */
1438fcf3ce44SJohn Forte 	switch (event) {
1439fcf3ce44SJohn Forte 	/* -N1: A session continuation attempt succeeded */
1440fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N1:
1441fcf3ce44SJohn Forte 		/* NOOP - connections already online */
1442fcf3ce44SJohn Forte 		break;
1443fcf3ce44SJohn Forte 
1444fcf3ce44SJohn Forte 	/*
1445fcf3ce44SJohn Forte 	 * -N3: A connection logged out.
1446fcf3ce44SJohn Forte 	 */
1447fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N3:
1448fcf3ce44SJohn Forte 		/* FALLTHRU */
1449fcf3ce44SJohn Forte 
1450fcf3ce44SJohn Forte 	/*
1451fcf3ce44SJohn Forte 	 * -N5: A connection failed
1452fcf3ce44SJohn Forte 	 */
1453fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N5:
1454fcf3ce44SJohn Forte 		/*
1455fcf3ce44SJohn Forte 		 * MC/S: If this is the last connection to
1456fcf3ce44SJohn Forte 		 * fail then move the the failed state.
1457fcf3ce44SJohn Forte 		 */
1458fcf3ce44SJohn Forte 		if (event == ISCSI_SESS_EVENT_N3) {
1459fcf3ce44SJohn Forte 			isp->sess_state = ISCSI_SESS_STATE_FREE;
1460fcf3ce44SJohn Forte 		} else {
1461fcf3ce44SJohn Forte 			isp->sess_state = ISCSI_SESS_STATE_FLUSHED;
1462fcf3ce44SJohn Forte 		}
1463904e51f6SJack Meng 		rw_downgrade(&isp->sess_state_rwlock);
1464fcf3ce44SJohn Forte 
1465fcf3ce44SJohn Forte 		/* no longer connected reset nego tpgt */
1466fcf3ce44SJohn Forte 		isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT;
1467fcf3ce44SJohn Forte 		iscsi_sess_flush(isp);
1468fcf3ce44SJohn Forte 
1469fcf3ce44SJohn Forte 		if (event == ISCSI_SESS_EVENT_N3) {
1470fcf3ce44SJohn Forte 			if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1471fcf3ce44SJohn Forte 				cmn_err(CE_NOTE,
1472fcf3ce44SJohn Forte 				    "!iscsi session(%u) %s offline\n",
1473fcf3ce44SJohn Forte 				    isp->sess_oid, isp->sess_name);
1474fcf3ce44SJohn Forte 			}
147555364d2bSJack Meng 			/*
147655364d2bSJack Meng 			 * During the process of offlining the LUNs
147755364d2bSJack Meng 			 * our ic thread might be calling back into
147855364d2bSJack Meng 			 * the driver via a target driver failure
147955364d2bSJack Meng 			 * path to do a reset or something
148055364d2bSJack Meng 			 * we need to release the sess_state_mutex
148155364d2bSJack Meng 			 * while we are killing these threads so
148255364d2bSJack Meng 			 * they don't get deadlocked.
148355364d2bSJack Meng 			 */
1484fcf3ce44SJohn Forte 			iscsi_sess_offline_luns(isp);
1485fcf3ce44SJohn Forte 		}
1486fcf3ce44SJohn Forte 
14872b79d384Sbing zhao - Sun Microsystems - Beijing China 		mutex_enter(&isp->sess_reset_mutex);
14882b79d384Sbing zhao - Sun Microsystems - Beijing China 		isp->sess_reset_in_progress = B_FALSE;
14892b79d384Sbing zhao - Sun Microsystems - Beijing China 		mutex_exit(&isp->sess_reset_mutex);
14902b79d384Sbing zhao - Sun Microsystems - Beijing China 		/* update busy luns if needed */
14912b79d384Sbing zhao - Sun Microsystems - Beijing China 		iscsi_sess_update_busy_luns(isp, B_TRUE);
14922b79d384Sbing zhao - Sun Microsystems - Beijing China 
1493fcf3ce44SJohn Forte 		break;
1494fcf3ce44SJohn Forte 
1495fcf3ce44SJohn Forte 	/*
1496fcf3ce44SJohn Forte 	 * -N6: Session state timeout occurred, or a session
1497fcf3ce44SJohn Forte 	 *	reinstatement cleared this session instance.  This results in
1498fcf3ce44SJohn Forte 	 *	the freeing of all associated resources and the session state
1499fcf3ce44SJohn Forte 	 *	is discarded.
1500fcf3ce44SJohn Forte 	 */
1501fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N6:
1502fcf3ce44SJohn Forte 		/* NOOP - Not last connection */
1503fcf3ce44SJohn Forte 		break;
1504fcf3ce44SJohn Forte 
1505fcf3ce44SJohn Forte 	/*
1506fcf3ce44SJohn Forte 	 * -N7: Login parameters for session have changed.
1507fcf3ce44SJohn Forte 	 *	Re-negeotation required.
1508fcf3ce44SJohn Forte 	 */
1509fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N7:
1510fcf3ce44SJohn Forte 		/* NOOP - Already attempting to update */
1511fcf3ce44SJohn Forte 		break;
1512fcf3ce44SJohn Forte 
1513fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
1514fcf3ce44SJohn Forte 	default:
1515fcf3ce44SJohn Forte 		ASSERT(FALSE);
1516fcf3ce44SJohn Forte 	}
1517fcf3ce44SJohn Forte }
1518fcf3ce44SJohn Forte 
1519fcf3ce44SJohn Forte 
1520fcf3ce44SJohn Forte /*
1521fcf3ce44SJohn Forte  * iscsi_sess_state_flushed -
1522fcf3ce44SJohn Forte  *
1523fcf3ce44SJohn Forte  */
1524fcf3ce44SJohn Forte static void
iscsi_sess_state_flushed(iscsi_sess_t * isp,iscsi_sess_event_t event,uint32_t event_count)1525904e51f6SJack Meng iscsi_sess_state_flushed(iscsi_sess_t *isp, iscsi_sess_event_t event,
1526904e51f6SJack Meng     uint32_t event_count)
1527fcf3ce44SJohn Forte {
1528fcf3ce44SJohn Forte 	iscsi_hba_t	*ihp;
1529904e51f6SJack Meng 	iscsi_enum_result_t	enum_result;
1530fcf3ce44SJohn Forte 
1531fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1532fcf3ce44SJohn Forte 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FLUSHED);
1533fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
1534fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
1535fcf3ce44SJohn Forte 
1536fcf3ce44SJohn Forte 	/* switch on event change */
1537fcf3ce44SJohn Forte 	switch (event) {
1538fcf3ce44SJohn Forte 	/* -N1: A session continuation attempt succeeded */
1539fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N1:
154008f26845Sbing zhao - Sun Microsystems - Beijing China 		isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN;
1541904e51f6SJack Meng 		rw_downgrade(&isp->sess_state_rwlock);
1542904e51f6SJack Meng 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1543904e51f6SJack Meng 			enum_result =
1544904e51f6SJack Meng 			    iscsi_sess_enum_request(isp, B_TRUE,
1545904e51f6SJack Meng 			    event_count);
1546904e51f6SJack Meng 			if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
1547904e51f6SJack Meng 				enum_result =
1548904e51f6SJack Meng 				    iscsi_sess_enum_query(isp);
1549904e51f6SJack Meng 			}
1550904e51f6SJack Meng 			if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
1551904e51f6SJack Meng 				iscsi_sess_enum_warn(isp, enum_result);
1552fcf3ce44SJohn Forte 			}
1553fcf3ce44SJohn Forte 		}
1554fcf3ce44SJohn Forte 		break;
1555fcf3ce44SJohn Forte 
1556fcf3ce44SJohn Forte 	/*
1557fcf3ce44SJohn Forte 	 * -N6: Session state timeout occurred, or a session
1558fcf3ce44SJohn Forte 	 *	reinstatement cleared this session instance.  This results in
1559fcf3ce44SJohn Forte 	 *	the freeing of all associated resources and the session state
1560fcf3ce44SJohn Forte 	 *	is discarded.
1561fcf3ce44SJohn Forte 	 */
1562fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N6:
1563fcf3ce44SJohn Forte 		isp->sess_state = ISCSI_SESS_STATE_FREE;
1564904e51f6SJack Meng 		rw_downgrade(&isp->sess_state_rwlock);
1565fcf3ce44SJohn Forte 
1566fcf3ce44SJohn Forte 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1567fcf3ce44SJohn Forte 			cmn_err(CE_NOTE, "!iscsi session(%u) %s offline\n",
1568fcf3ce44SJohn Forte 			    isp->sess_oid, isp->sess_name);
1569fcf3ce44SJohn Forte 		}
1570fcf3ce44SJohn Forte 
1571fcf3ce44SJohn Forte 		iscsi_sess_offline_luns(isp);
1572fcf3ce44SJohn Forte 		break;
1573fcf3ce44SJohn Forte 
1574fcf3ce44SJohn Forte 	/*
1575fcf3ce44SJohn Forte 	 * -N7: Login parameters for session have changed.
1576fcf3ce44SJohn Forte 	 *	Re-negeotation required.
1577fcf3ce44SJohn Forte 	 */
1578fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N7:
1579fcf3ce44SJohn Forte 		/* NOOP - not connected */
1580fcf3ce44SJohn Forte 		break;
1581fcf3ce44SJohn Forte 
1582fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
1583fcf3ce44SJohn Forte 	default:
1584fcf3ce44SJohn Forte 		ASSERT(FALSE);
1585fcf3ce44SJohn Forte 	}
1586fcf3ce44SJohn Forte }
1587fcf3ce44SJohn Forte 
1588fcf3ce44SJohn Forte /*
1589fcf3ce44SJohn Forte  * iscsi_sess_event_str -
1590fcf3ce44SJohn Forte  *
1591fcf3ce44SJohn Forte  */
1592fcf3ce44SJohn Forte static char *
iscsi_sess_event_str(iscsi_sess_event_t event)1593fcf3ce44SJohn Forte iscsi_sess_event_str(iscsi_sess_event_t event)
1594fcf3ce44SJohn Forte {
1595fcf3ce44SJohn Forte 	switch (event) {
1596fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N1:
1597fcf3ce44SJohn Forte 		return ("N1");
1598fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N3:
1599fcf3ce44SJohn Forte 		return ("N3");
1600fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N5:
1601fcf3ce44SJohn Forte 		return ("N5");
1602fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N6:
1603fcf3ce44SJohn Forte 		return ("N6");
1604fcf3ce44SJohn Forte 	case ISCSI_SESS_EVENT_N7:
1605fcf3ce44SJohn Forte 		return ("N7");
1606fcf3ce44SJohn Forte 	default:
1607fcf3ce44SJohn Forte 		return ("unknown");
1608fcf3ce44SJohn Forte 	}
1609fcf3ce44SJohn Forte }
1610fcf3ce44SJohn Forte 
1611fcf3ce44SJohn Forte /*
1612fcf3ce44SJohn Forte  * iscsi_sess_thread_create -
1613fcf3ce44SJohn Forte  *
1614fcf3ce44SJohn Forte  */
1615fcf3ce44SJohn Forte static iscsi_status_t
iscsi_sess_threads_create(iscsi_sess_t * isp)1616fcf3ce44SJohn Forte iscsi_sess_threads_create(iscsi_sess_t *isp)
1617fcf3ce44SJohn Forte {
1618fcf3ce44SJohn Forte 	iscsi_hba_t	*ihp;
1619fcf3ce44SJohn Forte 	char		th_name[ISCSI_TH_MAX_NAME_LEN];
1620fcf3ce44SJohn Forte 
1621fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1622fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
1623fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
1624fcf3ce44SJohn Forte 
1625fcf3ce44SJohn Forte 	/* Completion thread creation. */
1626fcf3ce44SJohn Forte 	if (snprintf(th_name, sizeof (th_name) - 1,
1627fcf3ce44SJohn Forte 	    ISCSI_SESS_IOTH_NAME_FORMAT, ihp->hba_oid,
1628fcf3ce44SJohn Forte 	    isp->sess_oid) >= sizeof (th_name)) {
1629fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
1630fcf3ce44SJohn Forte 	}
1631fcf3ce44SJohn Forte 
1632fcf3ce44SJohn Forte 	isp->sess_ic_thread = iscsi_thread_create(ihp->hba_dip,
1633fcf3ce44SJohn Forte 	    th_name, iscsi_ic_thread, isp);
1634fcf3ce44SJohn Forte 
1635fcf3ce44SJohn Forte 	if (isp->sess_ic_thread == NULL) {
1636fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
1637fcf3ce44SJohn Forte 	}
1638fcf3ce44SJohn Forte 
1639fcf3ce44SJohn Forte 	(void) iscsi_thread_start(isp->sess_ic_thread);
1640fcf3ce44SJohn Forte 
1641fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
1642fcf3ce44SJohn Forte }
1643fcf3ce44SJohn Forte 
1644fcf3ce44SJohn Forte /*
1645fcf3ce44SJohn Forte  * iscsi_sess_enumeration - This function is used to drive the enumeration
1646fcf3ce44SJohn Forte  * of LUs on a session.  It will first prepare the target by sending test
1647fcf3ce44SJohn Forte  * unit ready commands, then it will issue a report luns.  If the report
1648fcf3ce44SJohn Forte  * luns is successful then it will process all the luns in the report.
1649fcf3ce44SJohn Forte  * If report luns is not successful we will do a stepping enumeration
1650fcf3ce44SJohn Forte  * of luns until no more luns are found.
1651fcf3ce44SJohn Forte  */
1652fcf3ce44SJohn Forte static void
iscsi_sess_enumeration(void * arg)1653fcf3ce44SJohn Forte iscsi_sess_enumeration(void *arg)
1654fcf3ce44SJohn Forte {
1655fcf3ce44SJohn Forte 	iscsi_task_t		*itp = (iscsi_task_t *)arg;
1656fcf3ce44SJohn Forte 	iscsi_sess_t		*isp;
1657fcf3ce44SJohn Forte 	iscsi_status_t		rval    = ISCSI_STATUS_SUCCESS;
1658904e51f6SJack Meng 	iscsi_enum_result_t	enum_result = ISCSI_SESS_ENUM_COMPLETE;
1659904e51f6SJack Meng 	uint32_t		event_count = itp->t_event_count;
1660fcf3ce44SJohn Forte 
1661fcf3ce44SJohn Forte 	ASSERT(itp != NULL);
1662fcf3ce44SJohn Forte 	isp = (iscsi_sess_t *)itp->t_arg;
1663fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1664fcf3ce44SJohn Forte 
1665fcf3ce44SJohn Forte 	/*
1666fcf3ce44SJohn Forte 	 * Send initial TEST_UNIT_READY to target.  If it fails this we
1667fcf3ce44SJohn Forte 	 * stop our enumeration as the target is not responding properly.
1668fcf3ce44SJohn Forte 	 */
1669904e51f6SJack Meng 	rval = iscsi_sess_testunitready(isp, event_count);
1670fcf3ce44SJohn Forte 	if (ISCSI_SUCCESS(rval)) {
1671fcf3ce44SJohn Forte 		/*
1672fcf3ce44SJohn Forte 		 * Now we know the target is ready start our enumeration with
1673fcf3ce44SJohn Forte 		 * REPORT LUNs, If this fails we will have to fall back to
1674fcf3ce44SJohn Forte 		 * stepping
1675fcf3ce44SJohn Forte 		 */
1676904e51f6SJack Meng 		rval = iscsi_sess_reportluns(isp, event_count);
1677fcf3ce44SJohn Forte 		if (!ISCSI_SUCCESS(rval)) {
1678fcf3ce44SJohn Forte 			/*
1679fcf3ce44SJohn Forte 			 * report luns failed so lets just check for LUN 0.
1680fcf3ce44SJohn Forte 			 * This will match fcp's enumeration support and
1681fcf3ce44SJohn Forte 			 * avoid issues with older devices like the A5K that
1682fcf3ce44SJohn Forte 			 * respond poorly.
1683fcf3ce44SJohn Forte 			 */
1684fcf3ce44SJohn Forte 			if (isp->sess_lun_list == NULL) {
1685904e51f6SJack Meng 				iscsi_sess_inquiry(isp, 0, 0, event_count,
1686904e51f6SJack Meng 				    NULL);
1687fcf3ce44SJohn Forte 			}
1688fcf3ce44SJohn Forte 		}
1689fcf3ce44SJohn Forte 	} else {
1690904e51f6SJack Meng 		enum_result = ISCSI_SESS_ENUM_TUR_FAIL;
1691fcf3ce44SJohn Forte 	}
1692fcf3ce44SJohn Forte 
1693904e51f6SJack Meng 	kmem_free(itp, sizeof (iscsi_task_t));
1694904e51f6SJack Meng 	mutex_enter(&isp->sess_enum_lock);
1695904e51f6SJack Meng 	if (isp->sess_enum_result_count != 0) {
1696904e51f6SJack Meng 		isp->sess_enum_status = ISCSI_SESS_ENUM_DONE;
1697904e51f6SJack Meng 	} else {
1698904e51f6SJack Meng 		isp->sess_enum_status = ISCSI_SESS_ENUM_FREE;
1699fcf3ce44SJohn Forte 	}
1700904e51f6SJack Meng 	isp->sess_enum_result = enum_result;
1701904e51f6SJack Meng 	cv_broadcast(&isp->sess_enum_cv);
1702904e51f6SJack Meng 	mutex_exit(&isp->sess_enum_lock);
1703fcf3ce44SJohn Forte }
1704fcf3ce44SJohn Forte 
1705fcf3ce44SJohn Forte /*
1706fcf3ce44SJohn Forte  * iscsi_sess_testunitready - This is used during enumeration to
1707fcf3ce44SJohn Forte  * ensure an array is ready to be enumerated.
1708fcf3ce44SJohn Forte  */
1709fcf3ce44SJohn Forte static iscsi_status_t
iscsi_sess_testunitready(iscsi_sess_t * isp,uint32_t event_count)1710904e51f6SJack Meng iscsi_sess_testunitready(iscsi_sess_t *isp, uint32_t event_count)
1711fcf3ce44SJohn Forte {
1712fcf3ce44SJohn Forte 	iscsi_status_t			rval		= ISCSI_STATUS_SUCCESS;
1713fcf3ce44SJohn Forte 	int				retries		= 0;
1714fcf3ce44SJohn Forte 	struct uscsi_cmd		ucmd;
1715fcf3ce44SJohn Forte 	char				cdb[CDB_GROUP0];
1716fcf3ce44SJohn Forte 
1717fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1718fcf3ce44SJohn Forte 
1719fcf3ce44SJohn Forte 	/* loop until successful sending test unit ready or retries out */
1720904e51f6SJack Meng 	while ((retries++ < 3) &&
1721904e51f6SJack Meng 	    (isp->sess_state_event_count == event_count)) {
1722fcf3ce44SJohn Forte 		/* cdb is all zeros */
1723fcf3ce44SJohn Forte 		bzero(&cdb[0], CDB_GROUP0);
1724fcf3ce44SJohn Forte 
1725fcf3ce44SJohn Forte 		/* setup uscsi cmd */
1726fcf3ce44SJohn Forte 		bzero(&ucmd, sizeof (struct uscsi_cmd));
1727fcf3ce44SJohn Forte 		ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
1728fcf3ce44SJohn Forte 		ucmd.uscsi_cdb		= &cdb[0];
1729fcf3ce44SJohn Forte 		ucmd.uscsi_cdblen	= CDB_GROUP0;
1730fcf3ce44SJohn Forte 
1731fcf3ce44SJohn Forte 		/* send test unit ready to lun zero on this session */
1732fcf3ce44SJohn Forte 		rval = iscsi_handle_passthru(isp, 0, &ucmd);
1733fcf3ce44SJohn Forte 
1734fcf3ce44SJohn Forte 		/*
1735fcf3ce44SJohn Forte 		 * If passthru was successful then we were able to
1736fcf3ce44SJohn Forte 		 * communicate with the target, continue enumeration.
1737fcf3ce44SJohn Forte 		 */
1738fcf3ce44SJohn Forte 		if (ISCSI_SUCCESS(rval)) {
1739fcf3ce44SJohn Forte 			break;
1740fcf3ce44SJohn Forte 		}
1741904e51f6SJack Meng 	}
1742fcf3ce44SJohn Forte 
1743fcf3ce44SJohn Forte 	return (rval);
1744fcf3ce44SJohn Forte }
1745fcf3ce44SJohn Forte 
1746fcf3ce44SJohn Forte #define	SCSI_REPORTLUNS_ADDRESS_SIZE			8
1747fcf3ce44SJohn Forte #define	SCSI_REPORTLUNS_ADDRESS_MASK			0xC0
1748fcf3ce44SJohn Forte #define	SCSI_REPORTLUNS_ADDRESS_PERIPHERAL		0x00
1749fcf3ce44SJohn Forte #define	SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE		0x40
1750fcf3ce44SJohn Forte #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT		0x80
1751fcf3ce44SJohn Forte #define	SCSI_REPORTLUNS_ADDRESS_EXTENDED_UNIT		0xC0
1752fcf3ce44SJohn Forte #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_2B		0x00
1753fcf3ce44SJohn Forte #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_4B		0x01
1754fcf3ce44SJohn Forte #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_6B		0x10
1755fcf3ce44SJohn Forte #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_8B		0x20
1756fcf3ce44SJohn Forte #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_SIZE	0x30
1757fcf3ce44SJohn Forte 
1758fcf3ce44SJohn Forte /*
1759fcf3ce44SJohn Forte  * iscsi_sess_reportluns - This is used during enumeration to
1760fcf3ce44SJohn Forte  * ensure an array is ready to be enumerated.
1761fcf3ce44SJohn Forte  */
1762fcf3ce44SJohn Forte static iscsi_status_t
iscsi_sess_reportluns(iscsi_sess_t * isp,uint32_t event_count)1763904e51f6SJack Meng iscsi_sess_reportluns(iscsi_sess_t *isp, uint32_t event_count)
1764fcf3ce44SJohn Forte {
1765fcf3ce44SJohn Forte 	iscsi_status_t		rval		= ISCSI_STATUS_SUCCESS;
1766fcf3ce44SJohn Forte 	iscsi_hba_t		*ihp;
1767fcf3ce44SJohn Forte 	struct uscsi_cmd	ucmd;
1768fcf3ce44SJohn Forte 	unsigned char		cdb[CDB_GROUP5];
1769fcf3ce44SJohn Forte 	unsigned char		*buf		= NULL;
1770fcf3ce44SJohn Forte 	int			buf_len		= sizeof (struct scsi_inquiry);
1771fcf3ce44SJohn Forte 	uint32_t		lun_list_length = 0;
1772fcf3ce44SJohn Forte 	uint16_t		lun_num		= 0;
1773fcf3ce44SJohn Forte 	uint8_t			lun_addr_type	= 0;
1774fcf3ce44SJohn Forte 	uint32_t		lun_count	= 0;
1775fcf3ce44SJohn Forte 	uint32_t		lun_start	= 0;
1776fcf3ce44SJohn Forte 	uint32_t		lun_total	= 0;
1777fcf3ce44SJohn Forte 	int			retries		= 0;
177818f21261Sandrew.rutz@sun.com 	iscsi_lun_t		*ilp_next;
1779fcf3ce44SJohn Forte 	iscsi_lun_t		*ilp		= NULL;
1780fcf3ce44SJohn Forte 	replun_data_t		*saved_replun_ptr = NULL;
1781fcf3ce44SJohn Forte 
1782fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1783fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
1784fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
1785fcf3ce44SJohn Forte 
1786fcf3ce44SJohn Forte 	/*
1787fcf3ce44SJohn Forte 	 * Attempt to send report luns until we successfully
1788fcf3ce44SJohn Forte 	 * get all the data or the retries run out.
1789fcf3ce44SJohn Forte 	 */
1790904e51f6SJack Meng 	while ((retries++ < 3) &&
1791904e51f6SJack Meng 	    (isp->sess_state_event_count == event_count)) {
1792fcf3ce44SJohn Forte 		/*
1793fcf3ce44SJohn Forte 		 * Allocate our buffer based on current buf_len.
1794fcf3ce44SJohn Forte 		 * buf_len may change after we received a response
1795fcf3ce44SJohn Forte 		 * from the target.
1796fcf3ce44SJohn Forte 		 */
1797fcf3ce44SJohn Forte 		if (buf == NULL) {
1798fcf3ce44SJohn Forte 			buf = kmem_zalloc(buf_len, KM_SLEEP);
1799fcf3ce44SJohn Forte 		}
1800fcf3ce44SJohn Forte 
1801fcf3ce44SJohn Forte 		/* setup cdb */
1802fcf3ce44SJohn Forte 		bzero(&cdb, CDB_GROUP5);
1803fcf3ce44SJohn Forte 		cdb[0] = SCMD_REPORT_LUNS;
1804fcf3ce44SJohn Forte 		cdb[6] = (buf_len & 0xff000000) >> 24;
1805fcf3ce44SJohn Forte 		cdb[7] = (buf_len & 0x00ff0000) >> 16;
1806fcf3ce44SJohn Forte 		cdb[8] = (buf_len & 0x0000ff00) >> 8;
1807fcf3ce44SJohn Forte 		cdb[9] = (buf_len & 0x000000ff);
1808fcf3ce44SJohn Forte 
1809fcf3ce44SJohn Forte 		/* setup uscsi cmd */
1810fcf3ce44SJohn Forte 		bzero(&ucmd, sizeof (struct uscsi_cmd));
1811fcf3ce44SJohn Forte 		ucmd.uscsi_flags	= USCSI_READ;
1812fcf3ce44SJohn Forte 		ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
1813fcf3ce44SJohn Forte 		ucmd.uscsi_cdb		= (char *)&cdb[0];
1814fcf3ce44SJohn Forte 		ucmd.uscsi_cdblen	= CDB_GROUP5;
1815fcf3ce44SJohn Forte 		ucmd.uscsi_bufaddr	= (char *)buf;
1816fcf3ce44SJohn Forte 		ucmd.uscsi_buflen	= buf_len;
1817fcf3ce44SJohn Forte 
1818fcf3ce44SJohn Forte 		/* send uscsi cmd to lun 0 on session */
1819fcf3ce44SJohn Forte 		rval = iscsi_handle_passthru(isp, 0, &ucmd);
1820fcf3ce44SJohn Forte 
1821fcf3ce44SJohn Forte 		/* If passthru successful but not scsi status update istatus */
1822fcf3ce44SJohn Forte 		if (ISCSI_SUCCESS(rval) &&
1823fcf3ce44SJohn Forte 		    (ucmd.uscsi_status != STATUS_GOOD)) {
1824fcf3ce44SJohn Forte 			rval = ISCSI_STATUS_USCSI_FAILED;
1825fcf3ce44SJohn Forte 		}
1826fcf3ce44SJohn Forte 
1827fcf3ce44SJohn Forte 		/* If successful, check if we have all the data */
1828fcf3ce44SJohn Forte 		if (ISCSI_SUCCESS(rval)) {
1829fcf3ce44SJohn Forte 			/* total data - header (SCSI_REPORTLUNS_ADDRESS_SIZE) */
1830fcf3ce44SJohn Forte 			lun_list_length	= htonl(*(uint32_t *)buf);
1831fcf3ce44SJohn Forte 
1832fcf3ce44SJohn Forte 			if (buf_len >= lun_list_length +
1833fcf3ce44SJohn Forte 			    SCSI_REPORTLUNS_ADDRESS_SIZE) {
1834fcf3ce44SJohn Forte 				/* we have all the data, were done */
1835fcf3ce44SJohn Forte 				break;
1836fcf3ce44SJohn Forte 			}
1837fcf3ce44SJohn Forte 
1838fcf3ce44SJohn Forte 			/*
1839fcf3ce44SJohn Forte 			 * We don't have all the data.  free up the
1840fcf3ce44SJohn Forte 			 * memory for the next pass and update the
1841fcf3ce44SJohn Forte 			 * buf_len
1842fcf3ce44SJohn Forte 			 */
1843fcf3ce44SJohn Forte 			kmem_free(buf, buf_len);
1844fcf3ce44SJohn Forte 			buf = NULL;
1845fcf3ce44SJohn Forte 			buf_len = lun_list_length +
1846fcf3ce44SJohn Forte 			    SCSI_REPORTLUNS_ADDRESS_SIZE;
1847fcf3ce44SJohn Forte 		} else {
1848fcf3ce44SJohn Forte 			retries++;
1849fcf3ce44SJohn Forte 		}
1850904e51f6SJack Meng 	}
1851fcf3ce44SJohn Forte 
1852904e51f6SJack Meng 	if (isp->sess_state_event_count != event_count) {
1853904e51f6SJack Meng 		if (buf != NULL) {
1854904e51f6SJack Meng 			kmem_free(buf, buf_len);
1855904e51f6SJack Meng 			buf = NULL;
1856904e51f6SJack Meng 		}
1857904e51f6SJack Meng 		return (rval);
1858904e51f6SJack Meng 	}
1859fcf3ce44SJohn Forte 
1860904e51f6SJack Meng 	/* If not successful go no further */
1861fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(rval)) {
1862fcf3ce44SJohn Forte 		kmem_free(buf, buf_len);
1863fcf3ce44SJohn Forte 		return (rval);
1864fcf3ce44SJohn Forte 	}
1865fcf3ce44SJohn Forte 
1866fcf3ce44SJohn Forte 	/*
1867fcf3ce44SJohn Forte 	 * find out the number of luns returned by the SCSI ReportLun call
1868fcf3ce44SJohn Forte 	 * and allocate buffer space
1869fcf3ce44SJohn Forte 	 */
1870fcf3ce44SJohn Forte 	lun_total = lun_list_length / SCSI_REPORTLUNS_ADDRESS_SIZE;
1871fcf3ce44SJohn Forte 	saved_replun_ptr = kmem_zalloc(lun_total * sizeof (replun_data_t),
1872fcf3ce44SJohn Forte 	    KM_SLEEP);
1873fcf3ce44SJohn Forte 
1874fcf3ce44SJohn Forte 	/*
1875fcf3ce44SJohn Forte 	 * walk the isp->sess_lun_list
1876fcf3ce44SJohn Forte 	 * for each lun in this list
1877fcf3ce44SJohn Forte 	 *	look to see if this lun is in the SCSI ReportLun list we
1878fcf3ce44SJohn Forte 	 *	    just retrieved
1879904e51f6SJack Meng 	 *	if it is in the SCSI ReportLun list and it is already ONLINE or
1880904e51f6SJack Meng 	 *	if it is in the SCSI ReportLun list and it is OFFLINE or
1881904e51f6SJack Meng 	 *	if it isn't in the SCSI ReportLunlist or then
1882904e51f6SJack Meng 	 *	    issue the iscsi_sess_inquiry() to handle
1883fcf3ce44SJohn Forte 	 *
1884fcf3ce44SJohn Forte 	 *	as we walk the SCSI ReportLun list, we save this lun information
1885fcf3ce44SJohn Forte 	 *	    into the buffer we just allocated.  This will save us from
1886fcf3ce44SJohn Forte 	 *	    having to figure out this information later
1887fcf3ce44SJohn Forte 	 */
1888fcf3ce44SJohn Forte 	lun_start = 0;
1889dda652d3Sandrew.rutz@sun.com 	rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
189018f21261Sandrew.rutz@sun.com 	for (ilp = isp->sess_lun_list; ilp; ilp = ilp_next) {
1891904e51f6SJack Meng 		if (isp->sess_state_event_count != event_count)
1892904e51f6SJack Meng 			break;
1893904e51f6SJack Meng 
189418f21261Sandrew.rutz@sun.com 		ilp_next = ilp->lun_next;
189518f21261Sandrew.rutz@sun.com 
189630e7468fSPeter Dunlap 		for (lun_count = lun_start; lun_count < lun_total;
189730e7468fSPeter Dunlap 		    lun_count++) {
189830e7468fSPeter Dunlap 			/*
189930e7468fSPeter Dunlap 			 * if the first lun in saved_replun_ptr buffer has
190030e7468fSPeter Dunlap 			 * already been found we can move on and do not
190130e7468fSPeter Dunlap 			 * have to check this lun in the future
190230e7468fSPeter Dunlap 			 */
1903fcf3ce44SJohn Forte 			if (lun_count == lun_start &&
1904fcf3ce44SJohn Forte 			    saved_replun_ptr[lun_start].lun_found) {
1905fcf3ce44SJohn Forte 				lun_start++;
1906fcf3ce44SJohn Forte 				continue;
1907fcf3ce44SJohn Forte 			}
1908fcf3ce44SJohn Forte 			/*
1909fcf3ce44SJohn Forte 			 * check to see if the lun we are looking for is in the
1910fcf3ce44SJohn Forte 			 * saved_replun_ptr buffer
1911fcf3ce44SJohn Forte 			 * if it is, process the lun
1912fcf3ce44SJohn Forte 			 * if it isn't, then we must go to SCSI
1913fcf3ce44SJohn Forte 			 * Report Lun buffer
1914fcf3ce44SJohn Forte 			 * we retrieved to get lun info
1915fcf3ce44SJohn Forte 			 */
1916904e51f6SJack Meng 			if ((saved_replun_ptr[lun_count].lun_valid
1917904e51f6SJack Meng 			    == B_TRUE) &&
1918904e51f6SJack Meng 			    (saved_replun_ptr[lun_count].lun_num
1919904e51f6SJack Meng 			    == ilp->lun_num)) {
1920fcf3ce44SJohn Forte 				/*
1921904e51f6SJack Meng 				 * the lun we are looking for is found,
1922904e51f6SJack Meng 				 * give it to iscsi_sess_inquiry()
1923fcf3ce44SJohn Forte 				 */
1924904e51f6SJack Meng 				rw_exit(&isp->sess_lun_list_rwlock);
1925904e51f6SJack Meng 				iscsi_sess_inquiry(isp, ilp->lun_num,
1926904e51f6SJack Meng 				    saved_replun_ptr[lun_count].lun_addr_type,
1927904e51f6SJack Meng 				    event_count, ilp);
1928904e51f6SJack Meng 				rw_enter(&isp->sess_lun_list_rwlock,
1929904e51f6SJack Meng 				    RW_WRITER);
1930904e51f6SJack Meng 				saved_replun_ptr[lun_count].lun_found
1931904e51f6SJack Meng 				    = B_TRUE;
1932fcf3ce44SJohn Forte 				break;
1933904e51f6SJack Meng 			} else {
193430e7468fSPeter Dunlap 				/*
1935904e51f6SJack Meng 				 * lun information is not found in the
1936904e51f6SJack Meng 				 * saved_replun buffer, retrieve lun
1937904e51f6SJack Meng 				 * information from the SCSI Report Lun buffer
1938904e51f6SJack Meng 				 * and store this information in the
1939904e51f6SJack Meng 				 * saved_replun buffer
194030e7468fSPeter Dunlap 				 */
1941904e51f6SJack Meng 				if (retrieve_lundata(lun_count, buf, isp,
1942904e51f6SJack Meng 				    &lun_num, &lun_addr_type) !=
1943904e51f6SJack Meng 				    ISCSI_STATUS_SUCCESS) {
1944904e51f6SJack Meng 					continue;
1945904e51f6SJack Meng 				}
1946904e51f6SJack Meng 				saved_replun_ptr[lun_count].lun_valid = B_TRUE;
1947904e51f6SJack Meng 				saved_replun_ptr[lun_count].lun_num = lun_num;
1948904e51f6SJack Meng 				saved_replun_ptr[lun_count].lun_addr_type =
1949904e51f6SJack Meng 				    lun_addr_type;
1950904e51f6SJack Meng 				if (ilp->lun_num == lun_num) {
1951904e51f6SJack Meng 					/*
1952904e51f6SJack Meng 					 * lun is found in the SCSI Report Lun
1953904e51f6SJack Meng 					 * buffer, give it to inquiry
1954904e51f6SJack Meng 					 */
1955904e51f6SJack Meng 					rw_exit(&isp->sess_lun_list_rwlock);
1956904e51f6SJack Meng 					iscsi_sess_inquiry(isp, lun_num,
1957904e51f6SJack Meng 					    lun_addr_type, event_count, ilp);
1958904e51f6SJack Meng 					rw_enter(&isp->sess_lun_list_rwlock,
1959904e51f6SJack Meng 					    RW_WRITER);
1960904e51f6SJack Meng 					saved_replun_ptr[lun_count].lun_found
1961904e51f6SJack Meng 					    = B_TRUE;
1962fcf3ce44SJohn Forte 					break;
1963fcf3ce44SJohn Forte 				}
1964fcf3ce44SJohn Forte 			}
1965fcf3ce44SJohn Forte 		}
1966fcf3ce44SJohn Forte 
1967fcf3ce44SJohn Forte 		if (lun_count == lun_total) {
196830e7468fSPeter Dunlap 			/*
196930e7468fSPeter Dunlap 			 * this lun we found in the sess->lun_list does
197030e7468fSPeter Dunlap 			 * not exist anymore, need to offline this lun
197130e7468fSPeter Dunlap 			 */
1972fcf3ce44SJohn Forte 
1973904e51f6SJack Meng 			DTRACE_PROBE2(
1974904e51f6SJack Meng 			    sess_reportluns_lun_no_longer_exists,
1975fcf3ce44SJohn Forte 			    int, ilp->lun_num, int, ilp->lun_state);
1976fcf3ce44SJohn Forte 
1977dda652d3Sandrew.rutz@sun.com 			(void) iscsi_lun_destroy(ihp, ilp);
1978fcf3ce44SJohn Forte 		}
1979fcf3ce44SJohn Forte 	}
1980fcf3ce44SJohn Forte 	rw_exit(&isp->sess_lun_list_rwlock);
1981fcf3ce44SJohn Forte 	/*
1982fcf3ce44SJohn Forte 	 * look for new luns that we found in the SCSI Report Lun buffer that
1983fcf3ce44SJohn Forte 	 * we did not have in the sess->lun_list and add them into the list
1984fcf3ce44SJohn Forte 	 */
1985fcf3ce44SJohn Forte 	for (lun_count = lun_start; lun_count < lun_total; lun_count++) {
1986fcf3ce44SJohn Forte 		if (saved_replun_ptr[lun_count].lun_valid == B_FALSE) {
1987fcf3ce44SJohn Forte 			/*
1988fcf3ce44SJohn Forte 			 * lun information is not in the
1989fcf3ce44SJohn Forte 			 * saved_replun buffer, retrieve
1990fcf3ce44SJohn Forte 			 * it from the SCSI Report Lun buffer
1991fcf3ce44SJohn Forte 			 */
1992fcf3ce44SJohn Forte 			if (retrieve_lundata(lun_count, buf, isp,
1993fcf3ce44SJohn Forte 			    &lun_num, &lun_addr_type) != ISCSI_STATUS_SUCCESS) {
1994fcf3ce44SJohn Forte 				continue;
1995fcf3ce44SJohn Forte 			}
1996fcf3ce44SJohn Forte 		} else {
199730e7468fSPeter Dunlap 			/*
199830e7468fSPeter Dunlap 			 * lun information is in the saved_replun buffer
199930e7468fSPeter Dunlap 			 * if this lun has been found already,
200030e7468fSPeter Dunlap 			 * then we can move on
200130e7468fSPeter Dunlap 			 */
2002fcf3ce44SJohn Forte 			if (saved_replun_ptr[lun_count].lun_found == B_TRUE) {
2003fcf3ce44SJohn Forte 				continue;
2004fcf3ce44SJohn Forte 			}
2005fcf3ce44SJohn Forte 			lun_num = saved_replun_ptr[lun_count].lun_num;
2006904e51f6SJack Meng 			lun_addr_type =
2007904e51f6SJack Meng 			    saved_replun_ptr[lun_count].lun_addr_type;
2008fcf3ce44SJohn Forte 		}
2009fcf3ce44SJohn Forte 
2010fcf3ce44SJohn Forte 
2011fcf3ce44SJohn Forte 		/* New luns found should not conflict with existing luns */
2012fcf3ce44SJohn Forte 		rw_enter(&isp->sess_lun_list_rwlock, RW_READER);
2013fcf3ce44SJohn Forte 		for (ilp = isp->sess_lun_list; ilp; ilp = ilp->lun_next) {
2014fcf3ce44SJohn Forte 			if (ilp->lun_num == lun_num) {
2015fcf3ce44SJohn Forte 				break;
2016fcf3ce44SJohn Forte 			}
2017fcf3ce44SJohn Forte 		}
2018fcf3ce44SJohn Forte 		rw_exit(&isp->sess_lun_list_rwlock);
2019fcf3ce44SJohn Forte 
2020fcf3ce44SJohn Forte 		if (ilp == NULL) {
2021fcf3ce44SJohn Forte 			/* new lun found, add this lun */
2022904e51f6SJack Meng 			iscsi_sess_inquiry(isp, lun_num, lun_addr_type,
2023904e51f6SJack Meng 			    event_count, NULL);
2024fcf3ce44SJohn Forte 		} else {
2025fcf3ce44SJohn Forte 			cmn_err(CE_NOTE,
2026fcf3ce44SJohn Forte 			    "!Duplicate Lun Number(%d) recieved from "
2027fcf3ce44SJohn Forte 			    "Target(%s)", lun_num, isp->sess_name);
2028fcf3ce44SJohn Forte 		}
2029fcf3ce44SJohn Forte 	}
2030904e51f6SJack Meng 	if (buf != NULL) {
2031904e51f6SJack Meng 		kmem_free(buf, buf_len);
2032904e51f6SJack Meng 	}
2033fcf3ce44SJohn Forte 	kmem_free(saved_replun_ptr, lun_total * sizeof (replun_data_t));
2034904e51f6SJack Meng 
2035fcf3ce44SJohn Forte 	return (rval);
2036fcf3ce44SJohn Forte }
2037fcf3ce44SJohn Forte 
2038fcf3ce44SJohn Forte #define	ISCSI_MAX_INQUIRY_BUF_SIZE	0xFF
2039fcf3ce44SJohn Forte #define	ISCSI_MAX_INQUIRY_RETRIES	3
2040fcf3ce44SJohn Forte 
2041fcf3ce44SJohn Forte /*
2042fcf3ce44SJohn Forte  * iscsi_sess_inquiry - Final processing of a LUN before we create a tgt
2043904e51f6SJack Meng  * mapping, if necessary the old lun will be deleted.
2044904e51f6SJack Meng  *
2045904e51f6SJack Meng  * We need to collect the stardard inquiry page and the
2046fcf3ce44SJohn Forte  * vendor identification page for this LUN.  If both of these are
2047fcf3ce44SJohn Forte  * successful and the identification page contains a NAA or EUI type
2048fcf3ce44SJohn Forte  * we will continue.  Otherwise we fail the creation of a tgt for
2049fcf3ce44SJohn Forte  * this LUN.
2050fcf3ce44SJohn Forte  *
2051904e51f6SJack Meng  * Keep the old lun unchanged if it is online and following things are
2052904e51f6SJack Meng  * match, lun_addr_type, lun_type, and lun_guid.
2053904e51f6SJack Meng  *
2054904e51f6SJack Meng  * Online the old lun if it is offline/invalid and those three things
2055904e51f6SJack Meng  * are match.
2056904e51f6SJack Meng  *
2057904e51f6SJack Meng  * Online a new lun if the old lun is offline and any of those three things
2058904e51f6SJack Meng  * is not match, and needs to destroy the old first.
2059904e51f6SJack Meng  *
2060904e51f6SJack Meng  * Destroy the old lun and online the new lun if the old is online/invalid
2061904e51f6SJack Meng  * and any of those three things is not match, and then online the new lun
2062fcf3ce44SJohn Forte  */
2063fcf3ce44SJohn Forte static void
iscsi_sess_inquiry(iscsi_sess_t * isp,uint16_t lun_num,uint8_t lun_addr_type,uint32_t event_count,iscsi_lun_t * ilp)2064904e51f6SJack Meng iscsi_sess_inquiry(iscsi_sess_t *isp, uint16_t lun_num, uint8_t lun_addr_type,
2065904e51f6SJack Meng     uint32_t event_count, iscsi_lun_t *ilp)
2066fcf3ce44SJohn Forte {
2067fcf3ce44SJohn Forte 	iscsi_status_t		rval;
2068fcf3ce44SJohn Forte 	struct uscsi_cmd	ucmd;
2069fcf3ce44SJohn Forte 	uchar_t			cdb[CDB_GROUP0];
2070fcf3ce44SJohn Forte 	uchar_t			*inq;
2071fcf3ce44SJohn Forte 	size_t			inq_len;
2072fcf3ce44SJohn Forte 	uchar_t			*inq83;
2073fcf3ce44SJohn Forte 	size_t			inq83_len;
2074fcf3ce44SJohn Forte 	int			retries;
2075fcf3ce44SJohn Forte 	ddi_devid_t		devid;
2076fcf3ce44SJohn Forte 	char			*guid = NULL;
2077904e51f6SJack Meng 	iscsi_hba_t		*ihp;
2078904e51f6SJack Meng 	iscsi_status_t		status = ISCSI_STATUS_SUCCESS;
2079904e51f6SJack Meng 	boolean_t		inq_ready = B_FALSE;
2080904e51f6SJack Meng 	boolean_t		inq83_ready = B_FALSE;
2081904e51f6SJack Meng 	boolean_t		nochange = B_FALSE;
2082904e51f6SJack Meng 	uchar_t			lun_type;
2083fcf3ce44SJohn Forte 
2084fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2085904e51f6SJack Meng 	ihp	= isp->sess_hba;
2086904e51f6SJack Meng 	ASSERT(ihp != NULL);
2087fcf3ce44SJohn Forte 
2088fcf3ce44SJohn Forte 	inq	= kmem_zalloc(ISCSI_MAX_INQUIRY_BUF_SIZE, KM_SLEEP);
2089fcf3ce44SJohn Forte 	inq83	= kmem_zalloc(ISCSI_MAX_INQUIRY_BUF_SIZE, KM_SLEEP);
2090fcf3ce44SJohn Forte 
2091904e51f6SJack Meng 	if (ilp == NULL) {
2092904e51f6SJack Meng 		/* easy case, just to create the new lun */
2093904e51f6SJack Meng 		goto sess_inq;
2094904e51f6SJack Meng 	}
2095904e51f6SJack Meng 
2096904e51f6SJack Meng 	if (ilp->lun_addr_type != lun_addr_type) {
2097904e51f6SJack Meng 		goto offline_old;
2098904e51f6SJack Meng 	}
2099904e51f6SJack Meng 
2100904e51f6SJack Meng 	goto sess_inq;
2101904e51f6SJack Meng 
2102904e51f6SJack Meng offline_old:
2103904e51f6SJack Meng 	if (isp->sess_state_event_count != event_count) {
2104904e51f6SJack Meng 		goto inq_done;
2105904e51f6SJack Meng 	}
2106904e51f6SJack Meng 
2107904e51f6SJack Meng 	status = iscsi_lun_destroy(ihp, ilp);
2108904e51f6SJack Meng 	if (status != ISCSI_STATUS_SUCCESS) {
2109904e51f6SJack Meng 		/* have to abort the process */
2110904e51f6SJack Meng 		cmn_err(CE_WARN, "iscsi session(%u) is unable to offline"
2111904e51f6SJack Meng 		    " obsolete logical unit %d", isp->sess_oid, lun_num);
2112904e51f6SJack Meng 		goto inq_done;
2113904e51f6SJack Meng 	}
2114904e51f6SJack Meng 	ilp = NULL;
2115904e51f6SJack Meng 
2116904e51f6SJack Meng sess_inq:
2117904e51f6SJack Meng 	if (inq_ready == B_TRUE) {
2118904e51f6SJack Meng 		goto sess_inq83;
2119904e51f6SJack Meng 	}
2120fcf3ce44SJohn Forte 	/*
2121fcf3ce44SJohn Forte 	 * STANDARD INQUIRY - We need the standard inquiry information
2122fcf3ce44SJohn Forte 	 * to feed into the scsi_hba_nodename_compatible_get function.
2123fcf3ce44SJohn Forte 	 * This function is used to detemine which driver will bind
2124fcf3ce44SJohn Forte 	 * on top of us, via the compatible id.
2125fcf3ce44SJohn Forte 	 */
2126fcf3ce44SJohn Forte 	bzero(&cdb, CDB_GROUP0);
2127fcf3ce44SJohn Forte 	cdb[0] = SCMD_INQUIRY;
2128fcf3ce44SJohn Forte 	cdb[4] = ISCSI_MAX_INQUIRY_BUF_SIZE;
2129fcf3ce44SJohn Forte 
2130fcf3ce44SJohn Forte 	bzero(&ucmd, sizeof (struct uscsi_cmd));
2131fcf3ce44SJohn Forte 	ucmd.uscsi_flags	= USCSI_READ;
2132fcf3ce44SJohn Forte 	ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
2133fcf3ce44SJohn Forte 	ucmd.uscsi_cdb		= (char *)&cdb[0];
2134fcf3ce44SJohn Forte 	ucmd.uscsi_cdblen	= CDB_GROUP0;
2135fcf3ce44SJohn Forte 	ucmd.uscsi_bufaddr	= (char *)inq;
2136fcf3ce44SJohn Forte 	ucmd.uscsi_buflen	= ISCSI_MAX_INQUIRY_BUF_SIZE;
2137fcf3ce44SJohn Forte 
2138fcf3ce44SJohn Forte 	/* Attempt to get inquiry information until successful or retries */
2139fcf3ce44SJohn Forte 	retries = 0;
2140904e51f6SJack Meng 	while ((retries++ < ISCSI_MAX_INQUIRY_RETRIES) &&
2141904e51f6SJack Meng 	    (isp->sess_state_event_count == event_count)) {
2142fcf3ce44SJohn Forte 		/* issue passthru */
2143fcf3ce44SJohn Forte 		rval = iscsi_handle_passthru(isp, lun_num, &ucmd);
2144fcf3ce44SJohn Forte 
2145fcf3ce44SJohn Forte 		/* If we were successful but scsi stat failed update istatus */
2146fcf3ce44SJohn Forte 		if (ISCSI_SUCCESS(rval) &&
2147fcf3ce44SJohn Forte 		    (ucmd.uscsi_status != STATUS_GOOD)) {
2148fcf3ce44SJohn Forte 			rval = ISCSI_STATUS_USCSI_FAILED;
2149fcf3ce44SJohn Forte 		}
2150fcf3ce44SJohn Forte 
2151fcf3ce44SJohn Forte 		/* If successful break */
2152fcf3ce44SJohn Forte 		if (ISCSI_SUCCESS(rval)) {
2153fcf3ce44SJohn Forte 			inq_len = ISCSI_MAX_INQUIRY_BUF_SIZE - ucmd.uscsi_resid;
2154fcf3ce44SJohn Forte 			break;
2155fcf3ce44SJohn Forte 		}
2156fcf3ce44SJohn Forte 
2157fcf3ce44SJohn Forte 		/* loop until we are successful or retries run out */
2158904e51f6SJack Meng 	}
2159fcf3ce44SJohn Forte 
2160fcf3ce44SJohn Forte 	/* If failed don't continue */
2161fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(rval)) {
2162fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "iscsi session(%u) unable to enumerate "
2163fcf3ce44SJohn Forte 		    "logical unit - inquiry failed lun %d",
2164fcf3ce44SJohn Forte 		    isp->sess_oid, lun_num);
2165fcf3ce44SJohn Forte 
2166fcf3ce44SJohn Forte 		goto inq_done;
2167fcf3ce44SJohn Forte 	}
2168904e51f6SJack Meng 	inq_ready = B_TRUE;
2169fcf3ce44SJohn Forte 
2170904e51f6SJack Meng sess_inq83:
2171fcf3ce44SJohn Forte 	/*
2172fcf3ce44SJohn Forte 	 * T-10 SPC Section 6.4.2.  Standard INQUIRY Peripheral
2173fcf3ce44SJohn Forte 	 * qualifier of 000b is the only type we should attempt
2174fcf3ce44SJohn Forte 	 * to plumb under the IO stack.
2175fcf3ce44SJohn Forte 	 */
2176fcf3ce44SJohn Forte 	if ((inq[0] & SCSI_INQUIRY_PQUAL_MASK) != 0x00) {
2177904e51f6SJack Meng 		/* shouldn't enumerate, destroy the old one if exists */
2178904e51f6SJack Meng 		if (ilp != NULL) {
2179904e51f6SJack Meng 			goto offline_old;
2180904e51f6SJack Meng 		}
2181fcf3ce44SJohn Forte 		goto inq_done;
2182fcf3ce44SJohn Forte 	}
2183fcf3ce44SJohn Forte 
2184904e51f6SJack Meng 	/*
2185904e51f6SJack Meng 	 * If lun type has changed
2186904e51f6SJack Meng 	 */
2187904e51f6SJack Meng 	lun_type = ((struct scsi_inquiry *)inq)->inq_dtype & DTYPE_MASK;
2188904e51f6SJack Meng 	if ((ilp != NULL) && (ilp->lun_type != lun_type)) {
2189904e51f6SJack Meng 		goto offline_old;
2190904e51f6SJack Meng 	}
2191904e51f6SJack Meng 
2192904e51f6SJack Meng 	if (inq83_ready == B_TRUE) {
2193904e51f6SJack Meng 		goto guid_ready;
2194904e51f6SJack Meng 	}
2195904e51f6SJack Meng 
2196fcf3ce44SJohn Forte 	/*
2197fcf3ce44SJohn Forte 	 * VENDOR IDENTIFICATION INQUIRY - This will be used to identify
2198fcf3ce44SJohn Forte 	 * a unique lunId.  This Id is passed to the mdi alloc calls so
2199fcf3ce44SJohn Forte 	 * we can properly plumb into scsi_vhci/mpxio.
2200fcf3ce44SJohn Forte 	 */
2201fcf3ce44SJohn Forte 
2202fcf3ce44SJohn Forte 	bzero(&cdb, CDB_GROUP0);
2203fcf3ce44SJohn Forte 	cdb[0] = SCMD_INQUIRY;
2204fcf3ce44SJohn Forte 	cdb[1] = 0x01; /* EVP bit */
2205fcf3ce44SJohn Forte 	cdb[2] = 0x83;
2206fcf3ce44SJohn Forte 	cdb[4] = ISCSI_MAX_INQUIRY_BUF_SIZE;
2207fcf3ce44SJohn Forte 
2208fcf3ce44SJohn Forte 	ucmd.uscsi_flags	= USCSI_READ;
2209fcf3ce44SJohn Forte 	ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
2210fcf3ce44SJohn Forte 	ucmd.uscsi_cdb		= (char *)&cdb[0];
2211fcf3ce44SJohn Forte 	ucmd.uscsi_cdblen	= CDB_GROUP0;
2212fcf3ce44SJohn Forte 	ucmd.uscsi_bufaddr	= (char *)inq83;
2213fcf3ce44SJohn Forte 	ucmd.uscsi_buflen	= ISCSI_MAX_INQUIRY_BUF_SIZE;
2214fcf3ce44SJohn Forte 
2215fcf3ce44SJohn Forte 	/* Attempt to get inquiry information until successful or retries */
2216fcf3ce44SJohn Forte 	retries = 0;
2217904e51f6SJack Meng 	while ((retries++ < ISCSI_MAX_INQUIRY_RETRIES) &&
2218904e51f6SJack Meng 	    (isp->sess_state_event_count == event_count)) {
2219fcf3ce44SJohn Forte 		/* issue passthru command */
2220fcf3ce44SJohn Forte 		rval = iscsi_handle_passthru(isp, lun_num, &ucmd);
2221fcf3ce44SJohn Forte 
2222fcf3ce44SJohn Forte 		/* If we were successful but scsi stat failed update istatus */
2223fcf3ce44SJohn Forte 		if (ISCSI_SUCCESS(rval) &&
2224fcf3ce44SJohn Forte 		    (ucmd.uscsi_status != STATUS_GOOD)) {
2225fcf3ce44SJohn Forte 			rval = ISCSI_STATUS_USCSI_FAILED;
2226fcf3ce44SJohn Forte 		}
2227fcf3ce44SJohn Forte 
2228fcf3ce44SJohn Forte 		/* Break if successful */
2229fcf3ce44SJohn Forte 		if (ISCSI_SUCCESS(rval)) {
2230fcf3ce44SJohn Forte 			inq83_len = ISCSI_MAX_INQUIRY_BUF_SIZE -
2231fcf3ce44SJohn Forte 			    ucmd.uscsi_resid;
2232fcf3ce44SJohn Forte 			break;
2233fcf3ce44SJohn Forte 		}
2234904e51f6SJack Meng 	}
2235fcf3ce44SJohn Forte 
2236fcf3ce44SJohn Forte 	/*
2237fcf3ce44SJohn Forte 	 * If we were successful collecting page 83 data attempt
2238fcf3ce44SJohn Forte 	 * to generate a GUID.  If no GUID can be generated then
2239fcf3ce44SJohn Forte 	 * the logical unit will skip attempt to plumb under
2240fcf3ce44SJohn Forte 	 * scsi_vhci/mpxio.
2241fcf3ce44SJohn Forte 	 */
2242fcf3ce44SJohn Forte 	if (ISCSI_SUCCESS(rval)) {
2243fcf3ce44SJohn Forte 		/* create DEVID from inquiry data */
2244fcf3ce44SJohn Forte 		if (ddi_devid_scsi_encode(
2245fcf3ce44SJohn Forte 		    DEVID_SCSI_ENCODE_VERSION_LATEST, NULL,
2246fcf3ce44SJohn Forte 		    inq, inq_len, NULL, 0, inq83, inq83_len, &devid) ==
2247fcf3ce44SJohn Forte 		    DDI_SUCCESS) {
2248fcf3ce44SJohn Forte 
2249fcf3ce44SJohn Forte 			/* extract GUID from DEVID */
2250fcf3ce44SJohn Forte 			guid = ddi_devid_to_guid(devid);
2251fcf3ce44SJohn Forte 
2252fcf3ce44SJohn Forte 			/* devid no longer needed */
2253fcf3ce44SJohn Forte 			ddi_devid_free(devid);
2254fcf3ce44SJohn Forte 		}
2255fcf3ce44SJohn Forte 	}
2256904e51f6SJack Meng 	inq83_ready = B_TRUE;
2257904e51f6SJack Meng 
2258904e51f6SJack Meng guid_ready:
2259fcf3ce44SJohn Forte 
2260904e51f6SJack Meng 	if (ilp != NULL) {
2261904e51f6SJack Meng 		if ((guid == NULL) && (ilp->lun_guid == NULL)) {
2262904e51f6SJack Meng 			nochange = B_TRUE;
2263904e51f6SJack Meng 		}
2264904e51f6SJack Meng 
2265904e51f6SJack Meng 		if ((guid != NULL) && (ilp->lun_guid != NULL) &&
2266904e51f6SJack Meng 		    ((strlen(guid) + 1) == ilp->lun_guid_size) &&
2267904e51f6SJack Meng 		    (bcmp(guid, ilp->lun_guid, ilp->lun_guid_size) == 0)) {
2268904e51f6SJack Meng 			nochange = B_TRUE;
2269904e51f6SJack Meng 		}
2270fcf3ce44SJohn Forte 
2271904e51f6SJack Meng 		if (nochange != B_TRUE) {
2272904e51f6SJack Meng 			goto offline_old;
2273904e51f6SJack Meng 		}
2274904e51f6SJack Meng 
2275904e51f6SJack Meng 		if (ilp->lun_state & (ISCSI_LUN_STATE_OFFLINE |
2276904e51f6SJack Meng 		    ISCSI_LUN_STATE_INVALID)) {
2277904e51f6SJack Meng 			if (isp->sess_state_event_count == event_count) {
2278904e51f6SJack Meng 				(void) iscsi_lun_online(ihp, ilp);
2279904e51f6SJack Meng 			}
2280904e51f6SJack Meng 		}
2281904e51f6SJack Meng 	} else {
2282904e51f6SJack Meng 		if (isp->sess_state_event_count == event_count) {
2283904e51f6SJack Meng 			(void) iscsi_lun_create(isp, lun_num, lun_addr_type,
2284904e51f6SJack Meng 			    (struct scsi_inquiry *)inq, guid);
2285904e51f6SJack Meng 		}
2286904e51f6SJack Meng 	}
2287904e51f6SJack Meng 
2288904e51f6SJack Meng inq_done:
2289fcf3ce44SJohn Forte 	if (guid != NULL) {
2290904e51f6SJack Meng 		/* guid is no longer needed */
2291fcf3ce44SJohn Forte 		ddi_devid_free_guid(guid);
2292fcf3ce44SJohn Forte 	}
2293fcf3ce44SJohn Forte 
2294fcf3ce44SJohn Forte 	/* free up memory now that we are done */
2295fcf3ce44SJohn Forte 	kmem_free(inq, ISCSI_MAX_INQUIRY_BUF_SIZE);
2296fcf3ce44SJohn Forte 	kmem_free(inq83, ISCSI_MAX_INQUIRY_BUF_SIZE);
2297fcf3ce44SJohn Forte }
2298fcf3ce44SJohn Forte 
2299fcf3ce44SJohn Forte static iscsi_status_t
retrieve_lundata(uint32_t lun_count,unsigned char * buf,iscsi_sess_t * isp,uint16_t * lun_num,uint8_t * lun_addr_type)2300fcf3ce44SJohn Forte retrieve_lundata(uint32_t lun_count, unsigned char *buf, iscsi_sess_t *isp,
2301fcf3ce44SJohn Forte     uint16_t *lun_num, uint8_t *lun_addr_type)
2302fcf3ce44SJohn Forte {
2303fcf3ce44SJohn Forte 	uint32_t		lun_idx		= 0;
2304fcf3ce44SJohn Forte 
2305fcf3ce44SJohn Forte 	ASSERT(lun_num != NULL);
2306fcf3ce44SJohn Forte 	ASSERT(lun_addr_type != NULL);
2307fcf3ce44SJohn Forte 
2308fcf3ce44SJohn Forte 	lun_idx = (lun_count + 1) * SCSI_REPORTLUNS_ADDRESS_SIZE;
2309fcf3ce44SJohn Forte 	/* determine report luns addressing type */
2310fcf3ce44SJohn Forte 	switch (buf[lun_idx] & SCSI_REPORTLUNS_ADDRESS_MASK) {
2311fcf3ce44SJohn Forte 		/*
2312fcf3ce44SJohn Forte 		 * Vendors in the field have been found to be concatenating
2313fcf3ce44SJohn Forte 		 * bus/target/lun to equal the complete lun value instead
2314fcf3ce44SJohn Forte 		 * of switching to flat space addressing
2315fcf3ce44SJohn Forte 		 */
2316fcf3ce44SJohn Forte 		/* 00b - peripheral device addressing method */
2317fcf3ce44SJohn Forte 		case SCSI_REPORTLUNS_ADDRESS_PERIPHERAL:
2318fcf3ce44SJohn Forte 			/* FALLTHRU */
2319fcf3ce44SJohn Forte 		/* 10b - logical unit addressing method */
2320fcf3ce44SJohn Forte 		case SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT:
2321fcf3ce44SJohn Forte 			/* FALLTHRU */
2322fcf3ce44SJohn Forte 		/* 01b - flat space addressing method */
2323fcf3ce44SJohn Forte 		case SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE:
2324fcf3ce44SJohn Forte 			/* byte0 bit0-5=msb lun byte1 bit0-7=lsb lun */
2325fcf3ce44SJohn Forte 			*lun_addr_type = (buf[lun_idx] &
2326fcf3ce44SJohn Forte 			    SCSI_REPORTLUNS_ADDRESS_MASK) >> 6;
2327fcf3ce44SJohn Forte 			*lun_num = (buf[lun_idx] & 0x3F) << 8;
2328fcf3ce44SJohn Forte 			*lun_num |= buf[lun_idx + 1];
2329fcf3ce44SJohn Forte 			return (ISCSI_STATUS_SUCCESS);
2330fcf3ce44SJohn Forte 		default: /* protocol error */
2331fcf3ce44SJohn Forte 			cmn_err(CE_NOTE, "iscsi session(%u) unable "
2332fcf3ce44SJohn Forte 			    "to enumerate logical units - report "
2333fcf3ce44SJohn Forte 			    "luns returned an unsupported format",
2334fcf3ce44SJohn Forte 			    isp->sess_oid);
2335fcf3ce44SJohn Forte 			break;
2336fcf3ce44SJohn Forte 	}
2337fcf3ce44SJohn Forte 	return (ISCSI_STATUS_INTERNAL_ERROR);
2338fcf3ce44SJohn Forte }
2339fcf3ce44SJohn Forte 
2340fcf3ce44SJohn Forte /*
2341fcf3ce44SJohn Forte  * iscsi_sess_flush - flushes remaining pending io on the session
2342fcf3ce44SJohn Forte  */
2343fcf3ce44SJohn Forte static void
iscsi_sess_flush(iscsi_sess_t * isp)2344fcf3ce44SJohn Forte iscsi_sess_flush(iscsi_sess_t *isp)
2345fcf3ce44SJohn Forte {
2346fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp;
2347fcf3ce44SJohn Forte 
2348fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2349fcf3ce44SJohn Forte 	ASSERT(isp->sess_state != ISCSI_SESS_STATE_LOGGED_IN);
2350fcf3ce44SJohn Forte 
2351fcf3ce44SJohn Forte 	/*
2352fcf3ce44SJohn Forte 	 * Flush out any remaining commands in the pending
2353fcf3ce44SJohn Forte 	 * queue.
2354fcf3ce44SJohn Forte 	 */
2355fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
2356fcf3ce44SJohn Forte 	icmdp = isp->sess_queue_pending.head;
2357fcf3ce44SJohn Forte 	while (icmdp != NULL) {
23582b79d384Sbing zhao - Sun Microsystems - Beijing China 		if (isp->sess_state == ISCSI_SESS_STATE_FAILED) {
23592b79d384Sbing zhao - Sun Microsystems - Beijing China 			mutex_enter(&icmdp->cmd_mutex);
23602b79d384Sbing zhao - Sun Microsystems - Beijing China 			if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
23612b79d384Sbing zhao - Sun Microsystems - Beijing China 				icmdp->cmd_un.scsi.pkt_stat |= STAT_ABORTED;
23622b79d384Sbing zhao - Sun Microsystems - Beijing China 			}
23632b79d384Sbing zhao - Sun Microsystems - Beijing China 			mutex_exit(&icmdp->cmd_mutex);
23642b79d384Sbing zhao - Sun Microsystems - Beijing China 		}
23652b79d384Sbing zhao - Sun Microsystems - Beijing China 
2366fcf3ce44SJohn Forte 		iscsi_cmd_state_machine(icmdp,
2367fcf3ce44SJohn Forte 		    ISCSI_CMD_EVENT_E7, isp);
2368fcf3ce44SJohn Forte 		icmdp = isp->sess_queue_pending.head;
2369fcf3ce44SJohn Forte 	}
2370fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2371fcf3ce44SJohn Forte }
2372fcf3ce44SJohn Forte 
2373fcf3ce44SJohn Forte /*
2374fcf3ce44SJohn Forte  * iscsi_sess_offline_luns - offline all this sessions luns
2375fcf3ce44SJohn Forte  */
2376fcf3ce44SJohn Forte static void
iscsi_sess_offline_luns(iscsi_sess_t * isp)2377fcf3ce44SJohn Forte iscsi_sess_offline_luns(iscsi_sess_t *isp)
2378fcf3ce44SJohn Forte {
2379fcf3ce44SJohn Forte 	iscsi_lun_t	*ilp;
2380fcf3ce44SJohn Forte 	iscsi_hba_t	*ihp;
2381fcf3ce44SJohn Forte 
2382fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2383fcf3ce44SJohn Forte 	ASSERT(isp->sess_state != ISCSI_SESS_STATE_LOGGED_IN);
2384fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
2385fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
2386fcf3ce44SJohn Forte 
2387fcf3ce44SJohn Forte 	rw_enter(&isp->sess_lun_list_rwlock, RW_READER);
2388fcf3ce44SJohn Forte 	ilp = isp->sess_lun_list;
2389fcf3ce44SJohn Forte 	while (ilp != NULL) {
2390fcf3ce44SJohn Forte 		(void) iscsi_lun_offline(ihp, ilp, B_FALSE);
2391fcf3ce44SJohn Forte 		ilp = ilp->lun_next;
2392fcf3ce44SJohn Forte 	}
2393fcf3ce44SJohn Forte 	rw_exit(&isp->sess_lun_list_rwlock);
2394fcf3ce44SJohn Forte }
2395fcf3ce44SJohn Forte 
2396fcf3ce44SJohn Forte /*
2397fcf3ce44SJohn Forte  * iscsi_sess_get_by_target - return the session structure for based on a
2398fcf3ce44SJohn Forte  * passed in target oid and hba instance.  NOTE:  There may be
2399fcf3ce44SJohn Forte  * multiple sessions associated with any given target.  In this case,
2400fcf3ce44SJohn Forte  * we will return the first matching session.  This function
2401fcf3ce44SJohn Forte  * is intended to be used in retrieving target info that is constant
2402fcf3ce44SJohn Forte  * across sessions (target name, alias, etc.).
2403fcf3ce44SJohn Forte  */
2404fcf3ce44SJohn Forte int
iscsi_sess_get_by_target(uint32_t target_oid,iscsi_hba_t * ihp,iscsi_sess_t ** ispp)2405fcf3ce44SJohn Forte iscsi_sess_get_by_target(uint32_t target_oid, iscsi_hba_t *ihp,
2406fcf3ce44SJohn Forte     iscsi_sess_t **ispp)
2407fcf3ce44SJohn Forte {
2408fcf3ce44SJohn Forte 	int rval = 0;
2409fcf3ce44SJohn Forte 	iscsi_sess_t *isp = NULL;
2410fcf3ce44SJohn Forte 
2411fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
2412fcf3ce44SJohn Forte 	ASSERT(ispp != NULL);
2413fcf3ce44SJohn Forte 
2414fcf3ce44SJohn Forte 	/* See if we already created this session */
2415fcf3ce44SJohn Forte 	for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
2416fcf3ce44SJohn Forte 		/*
2417fcf3ce44SJohn Forte 		 * Look for a session associated to the given target.
2418fcf3ce44SJohn Forte 		 * Return the first one found.
2419fcf3ce44SJohn Forte 		 */
2420fcf3ce44SJohn Forte 		if (isp->sess_target_oid == target_oid) {
2421fcf3ce44SJohn Forte 			/* Found matching session */
2422fcf3ce44SJohn Forte 			break;
2423fcf3ce44SJohn Forte 		}
2424fcf3ce44SJohn Forte 	}
2425fcf3ce44SJohn Forte 
2426fcf3ce44SJohn Forte 	/* If not null this session is already available */
2427fcf3ce44SJohn Forte 	if (isp != NULL) {
2428fcf3ce44SJohn Forte 		/* Existing session, return it */
2429fcf3ce44SJohn Forte 		*ispp = isp;
2430fcf3ce44SJohn Forte 	} else {
2431fcf3ce44SJohn Forte 		rval = EFAULT;
2432fcf3ce44SJohn Forte 	}
2433fcf3ce44SJohn Forte 	return (rval);
2434fcf3ce44SJohn Forte }
24352b79d384Sbing zhao - Sun Microsystems - Beijing China 
24362b79d384Sbing zhao - Sun Microsystems - Beijing China static void
iscsi_sess_update_busy_luns(iscsi_sess_t * isp,boolean_t clear)24372b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_sess_update_busy_luns(iscsi_sess_t *isp, boolean_t clear)
24382b79d384Sbing zhao - Sun Microsystems - Beijing China {
24392b79d384Sbing zhao - Sun Microsystems - Beijing China 	iscsi_lun_t	*ilp;
24402b79d384Sbing zhao - Sun Microsystems - Beijing China 	iscsi_hba_t	*ihp;
24412b79d384Sbing zhao - Sun Microsystems - Beijing China 
24422b79d384Sbing zhao - Sun Microsystems - Beijing China 	ASSERT(isp != NULL);
24432b79d384Sbing zhao - Sun Microsystems - Beijing China 	ihp = isp->sess_hba;
24442b79d384Sbing zhao - Sun Microsystems - Beijing China 	ASSERT(ihp != NULL);
24452b79d384Sbing zhao - Sun Microsystems - Beijing China 
24462b79d384Sbing zhao - Sun Microsystems - Beijing China 	rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
24472b79d384Sbing zhao - Sun Microsystems - Beijing China 	ilp = isp->sess_lun_list;
24482b79d384Sbing zhao - Sun Microsystems - Beijing China 	while (ilp != NULL) {
24492b79d384Sbing zhao - Sun Microsystems - Beijing China 		if (clear == B_TRUE) {
24502b79d384Sbing zhao - Sun Microsystems - Beijing China 			ilp->lun_state &= ~ISCSI_LUN_STATE_BUSY;
24512b79d384Sbing zhao - Sun Microsystems - Beijing China 		} else {
24522b79d384Sbing zhao - Sun Microsystems - Beijing China 			ilp->lun_state |= ISCSI_LUN_STATE_BUSY;
24532b79d384Sbing zhao - Sun Microsystems - Beijing China 		}
24542b79d384Sbing zhao - Sun Microsystems - Beijing China 		ilp = ilp->lun_next;
24552b79d384Sbing zhao - Sun Microsystems - Beijing China 	}
24562b79d384Sbing zhao - Sun Microsystems - Beijing China 	rw_exit(&isp->sess_lun_list_rwlock);
24572b79d384Sbing zhao - Sun Microsystems - Beijing China }
2458904e51f6SJack Meng 
2459904e51f6SJack Meng /*
2460904e51f6SJack Meng  * Submits the scsi enumeration request. Returns
2461904e51f6SJack Meng  * ISCSI_SESS_ENUM_SUBMITTED upon success, or others if failures are met.
2462904e51f6SJack Meng  * If the request is submitted and the wait is set to B_TRUE, the caller
2463904e51f6SJack Meng  * must call iscsi_sess_enum_query at a later time to unblock next enum
2464904e51f6SJack Meng  */
2465904e51f6SJack Meng iscsi_enum_result_t
iscsi_sess_enum_request(iscsi_sess_t * isp,boolean_t wait,uint32_t event_count)2466*811eca55SToomas Soome iscsi_sess_enum_request(iscsi_sess_t *isp, boolean_t wait, uint32_t event_count)
2467*811eca55SToomas Soome {
2468904e51f6SJack Meng 	iscsi_task_t		*itp;
2469904e51f6SJack Meng 
2470904e51f6SJack Meng 	itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
2471904e51f6SJack Meng 	itp->t_arg = isp;
2472904e51f6SJack Meng 	itp->t_event_count = event_count;
2473904e51f6SJack Meng 
2474904e51f6SJack Meng 	mutex_enter(&isp->sess_enum_lock);
2475904e51f6SJack Meng 	while ((isp->sess_enum_status != ISCSI_SESS_ENUM_FREE) &&
2476904e51f6SJack Meng 	    (isp->sess_enum_status != ISCSI_SESS_ENUM_INPROG)) {
2477904e51f6SJack Meng 		cv_wait(&isp->sess_enum_cv, &isp->sess_enum_lock);
2478904e51f6SJack Meng 	}
2479904e51f6SJack Meng 	if (isp->sess_enum_status == ISCSI_SESS_ENUM_INPROG) {
2480904e51f6SJack Meng 		/* easy case */
2481904e51f6SJack Meng 		if (wait == B_TRUE) {
2482904e51f6SJack Meng 			isp->sess_enum_result_count ++;
2483904e51f6SJack Meng 		}
2484904e51f6SJack Meng 		mutex_exit(&isp->sess_enum_lock);
2485904e51f6SJack Meng 		kmem_free(itp, sizeof (iscsi_task_t));
2486904e51f6SJack Meng 		return (ISCSI_SESS_ENUM_SUBMITTED);
2487904e51f6SJack Meng 	}
2488904e51f6SJack Meng 
2489904e51f6SJack Meng 	ASSERT(isp->sess_enum_status == ISCSI_SESS_ENUM_FREE);
2490904e51f6SJack Meng 	ASSERT(isp->sess_enum_result_count == 0);
2491904e51f6SJack Meng 
2492904e51f6SJack Meng 	isp->sess_enum_status = ISCSI_SESS_ENUM_INPROG;
2493904e51f6SJack Meng 	if (ddi_taskq_dispatch(isp->sess_enum_taskq,
2494904e51f6SJack Meng 	    iscsi_sess_enumeration, itp, DDI_SLEEP) != DDI_SUCCESS) {
2495904e51f6SJack Meng 		isp->sess_enum_status = ISCSI_SESS_ENUM_FREE;
2496904e51f6SJack Meng 		mutex_exit(&isp->sess_enum_lock);
2497904e51f6SJack Meng 		kmem_free(itp, sizeof (iscsi_task_t));
2498904e51f6SJack Meng 		return (ISCSI_SESS_ENUM_SUBFAIL);
2499904e51f6SJack Meng 	}
2500904e51f6SJack Meng 	if (wait == B_TRUE) {
2501904e51f6SJack Meng 		isp->sess_enum_result_count ++;
2502904e51f6SJack Meng 	}
2503904e51f6SJack Meng 	mutex_exit(&isp->sess_enum_lock);
2504904e51f6SJack Meng 	return (ISCSI_SESS_ENUM_SUBMITTED);
2505904e51f6SJack Meng }
2506904e51f6SJack Meng 
2507904e51f6SJack Meng /*
2508904e51f6SJack Meng  * Wait and query the result of the enumeration.
2509904e51f6SJack Meng  * The last caller is responsible for kicking off the DONE status
2510904e51f6SJack Meng  */
2511904e51f6SJack Meng iscsi_enum_result_t
iscsi_sess_enum_query(iscsi_sess_t * isp)2512*811eca55SToomas Soome iscsi_sess_enum_query(iscsi_sess_t *isp)
2513*811eca55SToomas Soome {
2514904e51f6SJack Meng 	iscsi_enum_result_t	ret = ISCSI_SESS_ENUM_IOFAIL;
2515904e51f6SJack Meng 
2516904e51f6SJack Meng 	mutex_enter(&isp->sess_enum_lock);
2517904e51f6SJack Meng 	while (isp->sess_enum_status != ISCSI_SESS_ENUM_DONE) {
2518904e51f6SJack Meng 		cv_wait(&isp->sess_enum_cv, &isp->sess_enum_lock);
2519904e51f6SJack Meng 	}
2520904e51f6SJack Meng 	ret = isp->sess_enum_result;
2521904e51f6SJack Meng 	isp->sess_enum_result_count --;
2522904e51f6SJack Meng 	if (isp->sess_enum_result_count == 0) {
2523904e51f6SJack Meng 		isp->sess_enum_status = ISCSI_SESS_ENUM_FREE;
2524904e51f6SJack Meng 		cv_broadcast(&isp->sess_enum_cv);
2525904e51f6SJack Meng 	}
2526904e51f6SJack Meng 	mutex_exit(&isp->sess_enum_lock);
2527904e51f6SJack Meng 
2528904e51f6SJack Meng 	return (ret);
2529904e51f6SJack Meng }
2530904e51f6SJack Meng 
2531904e51f6SJack Meng static void
iscsi_sess_enum_warn(iscsi_sess_t * isp,iscsi_enum_result_t r)2532*811eca55SToomas Soome iscsi_sess_enum_warn(iscsi_sess_t *isp, iscsi_enum_result_t r)
2533*811eca55SToomas Soome {
2534904e51f6SJack Meng 	cmn_err(CE_WARN, "iscsi session (%u) enumeration fails - %s",
2535904e51f6SJack Meng 	    isp->sess_oid, iscsi_sess_enum_warn_msgs[r]);
2536904e51f6SJack Meng }
2537904e51f6SJack Meng 
2538904e51f6SJack Meng void
iscsi_sess_enter_state_zone(iscsi_sess_t * isp)2539*811eca55SToomas Soome iscsi_sess_enter_state_zone(iscsi_sess_t *isp)
2540*811eca55SToomas Soome {
2541904e51f6SJack Meng 	mutex_enter(&isp->sess_state_wmutex);
2542904e51f6SJack Meng 	while (isp->sess_state_hasw == B_TRUE) {
2543904e51f6SJack Meng 		cv_wait(&isp->sess_state_wcv, &isp->sess_state_wmutex);
2544904e51f6SJack Meng 	}
2545904e51f6SJack Meng 	isp->sess_state_hasw = B_TRUE;
2546904e51f6SJack Meng 	mutex_exit(&isp->sess_state_wmutex);
2547904e51f6SJack Meng 
2548904e51f6SJack Meng 	rw_enter(&isp->sess_state_rwlock, RW_WRITER);
2549904e51f6SJack Meng }
2550904e51f6SJack Meng 
2551904e51f6SJack Meng void
iscsi_sess_exit_state_zone(iscsi_sess_t * isp)2552*811eca55SToomas Soome iscsi_sess_exit_state_zone(iscsi_sess_t *isp)
2553*811eca55SToomas Soome {
2554904e51f6SJack Meng 	rw_exit(&isp->sess_state_rwlock);
2555904e51f6SJack Meng 
2556904e51f6SJack Meng 	mutex_enter(&isp->sess_state_wmutex);
2557904e51f6SJack Meng 	isp->sess_state_hasw = B_FALSE;
2558904e51f6SJack Meng 	cv_signal(&isp->sess_state_wcv);
2559904e51f6SJack Meng 	mutex_exit(&isp->sess_state_wmutex);
2560904e51f6SJack Meng }
2561