xref: /onnv-gate/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_sess.c (revision 12161:1b0453703429)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
22*12161SJack.Meng@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
237836SJohn.Forte@Sun.COM  *
247836SJohn.Forte@Sun.COM  * iSCSI session interfaces
257836SJohn.Forte@Sun.COM  */
267836SJohn.Forte@Sun.COM 
278194SJack.Meng@Sun.COM #include <sys/bootprops.h>
287836SJohn.Forte@Sun.COM #include "iscsi.h"
297836SJohn.Forte@Sun.COM #include "persistent.h"
307836SJohn.Forte@Sun.COM #include "iscsi_targetparam.h"
317836SJohn.Forte@Sun.COM 
327836SJohn.Forte@Sun.COM #define	ISCSI_SESS_ENUM_TIMEOUT_DEFAULT	60
337836SJohn.Forte@Sun.COM #define	SCSI_INQUIRY_PQUAL_MASK 0xE0
347836SJohn.Forte@Sun.COM 
359162SPeter.Dunlap@Sun.COM boolean_t iscsi_sess_logging = B_FALSE;
367836SJohn.Forte@Sun.COM /*
377836SJohn.Forte@Sun.COM  * used to store report lun information found
387836SJohn.Forte@Sun.COM  *
397836SJohn.Forte@Sun.COM  * lun_valid:	if TRUE means the entry contains a valid entry
407836SJohn.Forte@Sun.COM  * lun_found:	if TRUE means the lun has been found in the sess_lun_list
417836SJohn.Forte@Sun.COM  * lun_num:	contains the lun_number
42*12161SJack.Meng@Sun.COM  * lun_addr_type:	indicates lun's type of addressing
437836SJohn.Forte@Sun.COM  */
447836SJohn.Forte@Sun.COM typedef	struct replun_data {
457836SJohn.Forte@Sun.COM 	boolean_t	lun_valid;
467836SJohn.Forte@Sun.COM 	boolean_t	lun_found;
477836SJohn.Forte@Sun.COM 	uint16_t	lun_num;
48*12161SJack.Meng@Sun.COM 	uint8_t		lun_addr_type;
497836SJohn.Forte@Sun.COM } replun_data_t;
507836SJohn.Forte@Sun.COM 
517836SJohn.Forte@Sun.COM int	iscsi_sess_enum_timeout = ISCSI_SESS_ENUM_TIMEOUT_DEFAULT;
527836SJohn.Forte@Sun.COM 
537836SJohn.Forte@Sun.COM /*
547836SJohn.Forte@Sun.COM  * The following private tunable, settable via
557836SJohn.Forte@Sun.COM  *      set iscsi:iscsi_sess_max_delay = 64
567836SJohn.Forte@Sun.COM  * in /etc/system, provides customer relief for configurations max interval in
577836SJohn.Forte@Sun.COM  * seconds of retry for a unreachable target during the login.
587836SJohn.Forte@Sun.COM  */
597836SJohn.Forte@Sun.COM int	iscsi_sess_max_delay = ISCSI_DEFAULT_MAX_STORM_DELAY;
607836SJohn.Forte@Sun.COM 
61*12161SJack.Meng@Sun.COM /*
62*12161SJack.Meng@Sun.COM  * Warning messages for the session scsi enumeration
63*12161SJack.Meng@Sun.COM  */
64*12161SJack.Meng@Sun.COM static const char *iscsi_sess_enum_warn_msgs[] = {
65*12161SJack.Meng@Sun.COM 	"completed",
66*12161SJack.Meng@Sun.COM 	"partially successful",
67*12161SJack.Meng@Sun.COM 	"IO failures",
68*12161SJack.Meng@Sun.COM 	"submitted",
69*12161SJack.Meng@Sun.COM 	"unable to submit the enumeration",
70*12161SJack.Meng@Sun.COM 	"session is gone",
71*12161SJack.Meng@Sun.COM 	"test unit ready failed"
72*12161SJack.Meng@Sun.COM };
73*12161SJack.Meng@Sun.COM 
747836SJohn.Forte@Sun.COM /* internal interfaces */
757836SJohn.Forte@Sun.COM /* LINTED E_STATIC_UNUSED */
767836SJohn.Forte@Sun.COM static iscsi_sess_t *iscsi_sess_alloc(iscsi_hba_t *ihp, iscsi_sess_type_t type);
777836SJohn.Forte@Sun.COM static char *iscsi_sess_event_str(iscsi_sess_event_t event);
787836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_sess_threads_create(iscsi_sess_t *isp);
797836SJohn.Forte@Sun.COM static void iscsi_sess_flush(iscsi_sess_t *isp);
807836SJohn.Forte@Sun.COM static void iscsi_sess_offline_luns(iscsi_sess_t *isp);
817836SJohn.Forte@Sun.COM static iscsi_status_t retrieve_lundata(uint32_t lun_count, unsigned char *buf,
827836SJohn.Forte@Sun.COM 	iscsi_sess_t *isp, uint16_t *lun_data, uint8_t *lun_addr_type);
837836SJohn.Forte@Sun.COM 
847836SJohn.Forte@Sun.COM /* internal state machine interfaces */
857836SJohn.Forte@Sun.COM static void iscsi_sess_state_free(iscsi_sess_t *isp,
86*12161SJack.Meng@Sun.COM     iscsi_sess_event_t event, uint32_t event_count);
877836SJohn.Forte@Sun.COM static void iscsi_sess_state_logged_in(iscsi_sess_t *isp,
88*12161SJack.Meng@Sun.COM     iscsi_sess_event_t event, uint32_t event_count);
897836SJohn.Forte@Sun.COM static void iscsi_sess_state_failed(iscsi_sess_t *isp,
90*12161SJack.Meng@Sun.COM     iscsi_sess_event_t event, uint32_t event_count);
917836SJohn.Forte@Sun.COM static void iscsi_sess_state_in_flush(iscsi_sess_t *isp,
92*12161SJack.Meng@Sun.COM     iscsi_sess_event_t event, uint32_t event_count);
937836SJohn.Forte@Sun.COM static void iscsi_sess_state_flushed(iscsi_sess_t *isp,
94*12161SJack.Meng@Sun.COM     iscsi_sess_event_t event, uint32_t event_count);
957836SJohn.Forte@Sun.COM 
967836SJohn.Forte@Sun.COM /* internal enumeration interfaces */
977836SJohn.Forte@Sun.COM static void iscsi_sess_enumeration(void *arg);
98*12161SJack.Meng@Sun.COM static iscsi_status_t iscsi_sess_testunitready(iscsi_sess_t *isp,
99*12161SJack.Meng@Sun.COM     uint32_t event_count);
100*12161SJack.Meng@Sun.COM static iscsi_status_t iscsi_sess_reportluns(iscsi_sess_t *isp,
101*12161SJack.Meng@Sun.COM     uint32_t event_count);
1027836SJohn.Forte@Sun.COM static void iscsi_sess_inquiry(iscsi_sess_t *isp, uint16_t lun_num,
103*12161SJack.Meng@Sun.COM     uint8_t lun_addr_type, uint32_t event_count, iscsi_lun_t *ilp);
1049780SBing.Zhao@Sun.COM static void iscsi_sess_update_busy_luns(iscsi_sess_t *isp, boolean_t clear);
105*12161SJack.Meng@Sun.COM static void iscsi_sess_enum_warn(iscsi_sess_t *isp, iscsi_enum_result_t r);
1067836SJohn.Forte@Sun.COM 
1077836SJohn.Forte@Sun.COM /*
1087836SJohn.Forte@Sun.COM  * +--------------------------------------------------------------------+
1097836SJohn.Forte@Sun.COM  * | External Session Interfaces					|
1107836SJohn.Forte@Sun.COM  * +--------------------------------------------------------------------+
1117836SJohn.Forte@Sun.COM  */
1127836SJohn.Forte@Sun.COM 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)1137836SJohn.Forte@Sun.COM iscsi_sess_create(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method,
1147836SJohn.Forte@Sun.COM     struct sockaddr *addr_dsc, char *target_name, int tpgt, uchar_t isid_lsb,
1157836SJohn.Forte@Sun.COM     iscsi_sess_type_t type, uint32_t *oid)
1167836SJohn.Forte@Sun.COM {
1177836SJohn.Forte@Sun.COM 	iscsi_sess_t	*isp		= NULL;
1187836SJohn.Forte@Sun.COM 	int		len		= 0;
1197836SJohn.Forte@Sun.COM 	char		*tq_name;
1207836SJohn.Forte@Sun.COM 	char		*th_name;
12111476SBing.Zhao@Sun.COM 	iscsi_status_t	status;
1227836SJohn.Forte@Sun.COM 
1237836SJohn.Forte@Sun.COM 	len = strlen(target_name);
1247836SJohn.Forte@Sun.COM 
1258277SJack.Meng@Sun.COM clean_failed_sess:
1268277SJack.Meng@Sun.COM 	if (isp != NULL) {
1278277SJack.Meng@Sun.COM 		(void) iscsi_sess_destroy(isp);
1288277SJack.Meng@Sun.COM 	}
1298277SJack.Meng@Sun.COM 
1307836SJohn.Forte@Sun.COM 	for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
1317836SJohn.Forte@Sun.COM 		/* Match target name and LSB ISID */
1327836SJohn.Forte@Sun.COM 		if ((strcmp((char *)isp->sess_name, target_name) == 0) &&
1337836SJohn.Forte@Sun.COM 		    (isp->sess_isid[5] == isid_lsb)) {
1347836SJohn.Forte@Sun.COM 
1357836SJohn.Forte@Sun.COM 			/* Match TPGT */
1367836SJohn.Forte@Sun.COM 			if (isp->sess_tpgt_conf == tpgt) {
1377836SJohn.Forte@Sun.COM 				/* Found mathing session, return oid/ptr */
1387836SJohn.Forte@Sun.COM 				*oid = isp->sess_oid;
13911476SBing.Zhao@Sun.COM 				if (isp->sess_wd_thread != NULL &&
14011476SBing.Zhao@Sun.COM 				    isp->sess_ic_thread != NULL) {
1418277SJack.Meng@Sun.COM 					return (isp);
1428277SJack.Meng@Sun.COM 				}
14311476SBing.Zhao@Sun.COM 
1448277SJack.Meng@Sun.COM 				if (isp->sess_wd_thread == NULL) {
14511476SBing.Zhao@Sun.COM 					/*
14611476SBing.Zhao@Sun.COM 					 * Under rare cases wd thread is already
14711476SBing.Zhao@Sun.COM 					 * freed, create it if so.
14811476SBing.Zhao@Sun.COM 					 */
14911476SBing.Zhao@Sun.COM 					th_name = kmem_zalloc(
15011476SBing.Zhao@Sun.COM 					    ISCSI_TH_MAX_NAME_LEN, KM_SLEEP);
15111476SBing.Zhao@Sun.COM 					if (snprintf(th_name,
15211476SBing.Zhao@Sun.COM 					    (ISCSI_TH_MAX_NAME_LEN - 1),
15311476SBing.Zhao@Sun.COM 					    ISCSI_SESS_WD_NAME_FORMAT,
15411476SBing.Zhao@Sun.COM 					    ihp->hba_oid, isp->sess_oid) <
15511476SBing.Zhao@Sun.COM 					    ISCSI_TH_MAX_NAME_LEN) {
15611476SBing.Zhao@Sun.COM 						isp->sess_wd_thread =
15711476SBing.Zhao@Sun.COM 						    iscsi_thread_create(
15811476SBing.Zhao@Sun.COM 						    ihp->hba_dip,
15911476SBing.Zhao@Sun.COM 						    th_name,
16011476SBing.Zhao@Sun.COM 						    iscsi_wd_thread,
16111476SBing.Zhao@Sun.COM 						    isp);
16211476SBing.Zhao@Sun.COM 						(void) iscsi_thread_start(
16311476SBing.Zhao@Sun.COM 						    isp->sess_wd_thread);
16411476SBing.Zhao@Sun.COM 					}
16511476SBing.Zhao@Sun.COM 					kmem_free(th_name,
16611476SBing.Zhao@Sun.COM 					    ISCSI_TH_MAX_NAME_LEN);
16711476SBing.Zhao@Sun.COM 					if (isp->sess_wd_thread == NULL) {
16811476SBing.Zhao@Sun.COM 						/* No way to save it */
16911476SBing.Zhao@Sun.COM 						goto clean_failed_sess;
17011476SBing.Zhao@Sun.COM 					}
17111476SBing.Zhao@Sun.COM 				}
17211476SBing.Zhao@Sun.COM 
17311476SBing.Zhao@Sun.COM 				if (isp->sess_ic_thread == NULL) {
17411476SBing.Zhao@Sun.COM 					status = iscsi_sess_threads_create(isp);
17511476SBing.Zhao@Sun.COM 					if (status != ISCSI_STATUS_SUCCESS) {
17611476SBing.Zhao@Sun.COM 						goto clean_failed_sess;
17711476SBing.Zhao@Sun.COM 					}
1788277SJack.Meng@Sun.COM 				}
1797836SJohn.Forte@Sun.COM 				return (isp);
1807836SJohn.Forte@Sun.COM 			}
1817836SJohn.Forte@Sun.COM 
1827836SJohn.Forte@Sun.COM 			/*
1837836SJohn.Forte@Sun.COM 			 * Also protect against creating duplicate
1847836SJohn.Forte@Sun.COM 			 * sessions with different configured tpgt
1857836SJohn.Forte@Sun.COM 			 * values.  default vs. defined.
1867836SJohn.Forte@Sun.COM 			 */
1877836SJohn.Forte@Sun.COM 			if ((((isp->sess_tpgt_conf == ISCSI_DEFAULT_TPGT) &&
1887836SJohn.Forte@Sun.COM 			    (tpgt != ISCSI_DEFAULT_TPGT)) ||
1897836SJohn.Forte@Sun.COM 			    ((isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) &&
1907836SJohn.Forte@Sun.COM 			    (tpgt == ISCSI_DEFAULT_TPGT)))) {
1917836SJohn.Forte@Sun.COM 				/* Dangerous configuration.  Fail Request */
1927836SJohn.Forte@Sun.COM 				return (NULL);
1937836SJohn.Forte@Sun.COM 			}
1947836SJohn.Forte@Sun.COM 		}
1957836SJohn.Forte@Sun.COM 	}
1967836SJohn.Forte@Sun.COM 
1977836SJohn.Forte@Sun.COM 	isp = (iscsi_sess_t *)kmem_zalloc(sizeof (iscsi_sess_t), KM_SLEEP);
1987836SJohn.Forte@Sun.COM 	/*
1997836SJohn.Forte@Sun.COM 	 * If this session is not a Send Targets session, set the target
2007836SJohn.Forte@Sun.COM 	 * that this session is associated with.
2017836SJohn.Forte@Sun.COM 	 */
2027836SJohn.Forte@Sun.COM 	if (strncmp(target_name, SENDTARGETS_DISCOVERY,
2037836SJohn.Forte@Sun.COM 	    strlen(SENDTARGETS_DISCOVERY))) {
2047836SJohn.Forte@Sun.COM 		isp->sess_target_oid = iscsi_targetparam_get_oid(
2057836SJohn.Forte@Sun.COM 		    (uchar_t *)target_name);
2067836SJohn.Forte@Sun.COM 	}
2077836SJohn.Forte@Sun.COM 
2088194SJack.Meng@Sun.COM 	if (method & iSCSIDiscoveryMethodBoot) {
2098194SJack.Meng@Sun.COM 		/* This is boot session. */
2108194SJack.Meng@Sun.COM 		isp->sess_boot = B_TRUE;
2118194SJack.Meng@Sun.COM 	} else {
2128194SJack.Meng@Sun.COM 		isp->sess_boot = B_FALSE;
2138194SJack.Meng@Sun.COM 	}
2148194SJack.Meng@Sun.COM 
2157836SJohn.Forte@Sun.COM 	/* Associate session with this discovery method */
2168194SJack.Meng@Sun.COM 	method = method & ~(iSCSIDiscoveryMethodBoot);
2178194SJack.Meng@Sun.COM 
2187836SJohn.Forte@Sun.COM 	isp->sess_discovered_by = method;
2197836SJohn.Forte@Sun.COM 	if (addr_dsc == NULL) {
2207836SJohn.Forte@Sun.COM 		bzero(&isp->sess_discovered_addr,
2217836SJohn.Forte@Sun.COM 		    sizeof (isp->sess_discovered_addr));
2227836SJohn.Forte@Sun.COM 	} else {
2237836SJohn.Forte@Sun.COM 		bcopy(addr_dsc, &isp->sess_discovered_addr,
2247836SJohn.Forte@Sun.COM 		    SIZEOF_SOCKADDR(addr_dsc));
2257836SJohn.Forte@Sun.COM 	}
2267836SJohn.Forte@Sun.COM 
2277836SJohn.Forte@Sun.COM 	/* assign unique key for the session */
2287836SJohn.Forte@Sun.COM 	mutex_enter(&iscsi_oid_mutex);
2297836SJohn.Forte@Sun.COM 	isp->sess_oid = iscsi_oid++;
2307836SJohn.Forte@Sun.COM 	*oid = isp->sess_oid;
2317836SJohn.Forte@Sun.COM 	mutex_exit(&iscsi_oid_mutex);
2327836SJohn.Forte@Sun.COM 
2337836SJohn.Forte@Sun.COM 	/* setup session parameters */
2347836SJohn.Forte@Sun.COM 	isp->sess_name_length		= 0;
2357836SJohn.Forte@Sun.COM 	isp->sess_sig			= ISCSI_SIG_SESS;
2367836SJohn.Forte@Sun.COM 	isp->sess_state			= ISCSI_SESS_STATE_FREE;
237*12161SJack.Meng@Sun.COM 	rw_init(&isp->sess_state_rwlock, NULL, RW_DRIVER, NULL);
2389780SBing.Zhao@Sun.COM 	mutex_init(&isp->sess_reset_mutex, NULL, MUTEX_DRIVER, NULL);
2397836SJohn.Forte@Sun.COM 	isp->sess_hba			= ihp;
2407836SJohn.Forte@Sun.COM 
2417836SJohn.Forte@Sun.COM 	isp->sess_isid[0]		= ISCSI_SUN_ISID_0;
2427836SJohn.Forte@Sun.COM 	isp->sess_isid[1]		= ISCSI_SUN_ISID_1;
2437836SJohn.Forte@Sun.COM 	isp->sess_isid[2]		= ISCSI_SUN_ISID_2;
2447836SJohn.Forte@Sun.COM 	isp->sess_isid[3]		= ISCSI_SUN_ISID_3;
2457836SJohn.Forte@Sun.COM 	isp->sess_isid[4]		= 0;
2467836SJohn.Forte@Sun.COM 	isp->sess_isid[5]		= isid_lsb;
2477836SJohn.Forte@Sun.COM 
2487836SJohn.Forte@Sun.COM 	isp->sess_cmdsn			= 1;
2497836SJohn.Forte@Sun.COM 	isp->sess_expcmdsn		= 1;
2507836SJohn.Forte@Sun.COM 	isp->sess_maxcmdsn		= 1;
2517836SJohn.Forte@Sun.COM 	isp->sess_last_err		= NoError;
2527836SJohn.Forte@Sun.COM 	isp->sess_tsid			= 0;
2537836SJohn.Forte@Sun.COM 	isp->sess_type			= type;
2549780SBing.Zhao@Sun.COM 	isp->sess_reset_in_progress	= B_FALSE;
25511424SJack.Meng@Sun.COM 	isp->sess_boot_nic_reset	= B_FALSE;
2569162SPeter.Dunlap@Sun.COM 	idm_sm_audit_init(&isp->sess_state_audit);
2577836SJohn.Forte@Sun.COM 
2587836SJohn.Forte@Sun.COM 	/* copy default driver login parameters */
2597836SJohn.Forte@Sun.COM 	bcopy(&ihp->hba_params, &isp->sess_params,
2607836SJohn.Forte@Sun.COM 	    sizeof (iscsi_login_params_t));
2617836SJohn.Forte@Sun.COM 
2627836SJohn.Forte@Sun.COM 	/* copy target name into session */
2637836SJohn.Forte@Sun.COM 	bcopy((char *)target_name, isp->sess_name, len);
2647836SJohn.Forte@Sun.COM 	isp->sess_name_length	= len;
2657836SJohn.Forte@Sun.COM 	isp->sess_tpgt_conf	= tpgt;
2667836SJohn.Forte@Sun.COM 	isp->sess_tpgt_nego	= ISCSI_DEFAULT_TPGT;
2677836SJohn.Forte@Sun.COM 
2687836SJohn.Forte@Sun.COM 	/* initialize pending and completion queues */
2697836SJohn.Forte@Sun.COM 	iscsi_init_queue(&isp->sess_queue_pending);
2707836SJohn.Forte@Sun.COM 	iscsi_init_queue(&isp->sess_queue_completion);
2717836SJohn.Forte@Sun.COM 
2727836SJohn.Forte@Sun.COM 	/* setup sessions lun list */
2737836SJohn.Forte@Sun.COM 	isp->sess_lun_list = NULL;
2747836SJohn.Forte@Sun.COM 	rw_init(&isp->sess_lun_list_rwlock, NULL, RW_DRIVER, NULL);
2757836SJohn.Forte@Sun.COM 
2767836SJohn.Forte@Sun.COM 	/* setup sessions connection list */
2777836SJohn.Forte@Sun.COM 	isp->sess_conn_act = NULL;
2787836SJohn.Forte@Sun.COM 	isp->sess_conn_list = NULL;
2797836SJohn.Forte@Sun.COM 	rw_init(&isp->sess_conn_list_rwlock, NULL, RW_DRIVER, NULL);
2807836SJohn.Forte@Sun.COM 
2817836SJohn.Forte@Sun.COM 	mutex_init(&isp->sess_cmdsn_mutex, NULL, MUTEX_DRIVER, NULL);
2827836SJohn.Forte@Sun.COM 
2837836SJohn.Forte@Sun.COM 	/* create the session task queue */
2847836SJohn.Forte@Sun.COM 	tq_name = kmem_zalloc(ISCSI_TH_MAX_NAME_LEN, KM_SLEEP);
2857836SJohn.Forte@Sun.COM 	if (snprintf(tq_name, (ISCSI_TH_MAX_NAME_LEN - 1),
2867836SJohn.Forte@Sun.COM 	    ISCSI_SESS_LOGIN_TASKQ_NAME_FORMAT, ihp->hba_oid, isp->sess_oid) <
2877836SJohn.Forte@Sun.COM 	    ISCSI_TH_MAX_NAME_LEN) {
288*12161SJack.Meng@Sun.COM 		isp->sess_login_taskq = ddi_taskq_create(ihp->hba_dip,
289*12161SJack.Meng@Sun.COM 		    tq_name, 1, TASKQ_DEFAULTPRI, 0);
290*12161SJack.Meng@Sun.COM 	}
291*12161SJack.Meng@Sun.COM 	if (isp->sess_login_taskq == NULL) {
292*12161SJack.Meng@Sun.COM 		kmem_free(tq_name, ISCSI_TH_MAX_NAME_LEN);
293*12161SJack.Meng@Sun.COM 		goto iscsi_sess_cleanup2;
294*12161SJack.Meng@Sun.COM 	}
295*12161SJack.Meng@Sun.COM 
296*12161SJack.Meng@Sun.COM 	if (snprintf(tq_name, (ISCSI_TH_MAX_NAME_LEN - 1),
297*12161SJack.Meng@Sun.COM 	    ISCSI_SESS_ENUM_TASKQ_NAME_FORMAT, ihp->hba_oid, isp->sess_oid) <
298*12161SJack.Meng@Sun.COM 	    ISCSI_TH_MAX_NAME_LEN) {
299*12161SJack.Meng@Sun.COM 		isp->sess_enum_taskq = ddi_taskq_create(ihp->hba_dip,
3007836SJohn.Forte@Sun.COM 		    tq_name, 1, TASKQ_DEFAULTPRI, 0);
3017836SJohn.Forte@Sun.COM 	}
3027836SJohn.Forte@Sun.COM 	kmem_free(tq_name, ISCSI_TH_MAX_NAME_LEN);
303*12161SJack.Meng@Sun.COM 	if (isp->sess_enum_taskq == NULL) {
304*12161SJack.Meng@Sun.COM 		goto iscsi_sess_cleanup1;
3057836SJohn.Forte@Sun.COM 	}
3067836SJohn.Forte@Sun.COM 	/* startup watchdog */
3077836SJohn.Forte@Sun.COM 	th_name = kmem_zalloc(ISCSI_TH_MAX_NAME_LEN, KM_SLEEP);
3087836SJohn.Forte@Sun.COM 	if (snprintf(th_name, (ISCSI_TH_MAX_NAME_LEN - 1),
3097836SJohn.Forte@Sun.COM 	    ISCSI_SESS_WD_NAME_FORMAT, ihp->hba_oid, isp->sess_oid) <
3107836SJohn.Forte@Sun.COM 	    ISCSI_TH_MAX_NAME_LEN) {
3117836SJohn.Forte@Sun.COM 		isp->sess_wd_thread = iscsi_thread_create(ihp->hba_dip,
3127836SJohn.Forte@Sun.COM 		    th_name, iscsi_wd_thread, isp);
3137836SJohn.Forte@Sun.COM 		(void) iscsi_thread_start(isp->sess_wd_thread);
3147836SJohn.Forte@Sun.COM 	}
31511476SBing.Zhao@Sun.COM 
3167836SJohn.Forte@Sun.COM 	kmem_free(th_name, ISCSI_TH_MAX_NAME_LEN);
3177836SJohn.Forte@Sun.COM 	if (isp->sess_wd_thread == NULL) {
318*12161SJack.Meng@Sun.COM 		goto iscsi_sess_cleanup0;
3197836SJohn.Forte@Sun.COM 	}
3207836SJohn.Forte@Sun.COM 
32111476SBing.Zhao@Sun.COM 	status = iscsi_sess_threads_create(isp);
32211476SBing.Zhao@Sun.COM 	if (status != ISCSI_STATUS_SUCCESS) {
32311476SBing.Zhao@Sun.COM 		goto iscsi_sess_cleanup1;
32411476SBing.Zhao@Sun.COM 	}
32511476SBing.Zhao@Sun.COM 
3267836SJohn.Forte@Sun.COM 	/* Add new target to the hba target list */
3277836SJohn.Forte@Sun.COM 	if (ihp->hba_sess_list == NULL) {
3287836SJohn.Forte@Sun.COM 		ihp->hba_sess_list = isp;
3297836SJohn.Forte@Sun.COM 	} else {
3307836SJohn.Forte@Sun.COM 		isp->sess_next = ihp->hba_sess_list;
3317836SJohn.Forte@Sun.COM 		ihp->hba_sess_list = isp;
3327836SJohn.Forte@Sun.COM 	}
3337836SJohn.Forte@Sun.COM 	KSTAT_INC_HBA_CNTR_SESS(ihp);
3347836SJohn.Forte@Sun.COM 
3357836SJohn.Forte@Sun.COM 	(void) iscsi_sess_kstat_init(isp);
3367836SJohn.Forte@Sun.COM 
337*12161SJack.Meng@Sun.COM 	if (type == ISCSI_SESS_TYPE_NORMAL) {
338*12161SJack.Meng@Sun.COM 		isp->sess_enum_status = ISCSI_SESS_ENUM_FREE;
339*12161SJack.Meng@Sun.COM 		isp->sess_enum_result = ISCSI_SESS_ENUM_COMPLETE;
340*12161SJack.Meng@Sun.COM 		isp->sess_enum_result_count = 0;
341*12161SJack.Meng@Sun.COM 		mutex_init(&isp->sess_enum_lock, NULL, MUTEX_DRIVER, NULL);
342*12161SJack.Meng@Sun.COM 		cv_init(&isp->sess_enum_cv, NULL, CV_DRIVER, NULL);
343*12161SJack.Meng@Sun.COM 	}
3447836SJohn.Forte@Sun.COM 
345*12161SJack.Meng@Sun.COM 	mutex_init(&isp->sess_state_wmutex, NULL, MUTEX_DRIVER, NULL);
346*12161SJack.Meng@Sun.COM 	cv_init(&isp->sess_state_wcv, NULL, CV_DRIVER, NULL);
347*12161SJack.Meng@Sun.COM 	isp->sess_state_hasw = B_FALSE;
348*12161SJack.Meng@Sun.COM 
349*12161SJack.Meng@Sun.COM 	isp->sess_state_event_count = 0;
350*12161SJack.Meng@Sun.COM 
351*12161SJack.Meng@Sun.COM 	return (isp);
352*12161SJack.Meng@Sun.COM iscsi_sess_cleanup0:
353*12161SJack.Meng@Sun.COM 	ddi_taskq_destroy(isp->sess_enum_taskq);
3547836SJohn.Forte@Sun.COM iscsi_sess_cleanup1:
355*12161SJack.Meng@Sun.COM 	ddi_taskq_destroy(isp->sess_login_taskq);
3567836SJohn.Forte@Sun.COM iscsi_sess_cleanup2:
35711476SBing.Zhao@Sun.COM 	if (isp->sess_wd_thread != NULL) {
35811476SBing.Zhao@Sun.COM 		iscsi_thread_destroy(isp->sess_wd_thread);
35911476SBing.Zhao@Sun.COM 		isp->sess_wd_thread  = NULL;
36011476SBing.Zhao@Sun.COM 	}
36111476SBing.Zhao@Sun.COM 	if (isp->sess_ic_thread != NULL) {
36211476SBing.Zhao@Sun.COM 		iscsi_thread_destroy(isp->sess_ic_thread);
36311476SBing.Zhao@Sun.COM 		isp->sess_ic_thread = NULL;
36411476SBing.Zhao@Sun.COM 	}
3657836SJohn.Forte@Sun.COM 	mutex_destroy(&isp->sess_cmdsn_mutex);
3667836SJohn.Forte@Sun.COM 	rw_destroy(&isp->sess_conn_list_rwlock);
3677836SJohn.Forte@Sun.COM 	rw_destroy(&isp->sess_lun_list_rwlock);
3687836SJohn.Forte@Sun.COM 	iscsi_destroy_queue(&isp->sess_queue_completion);
3697836SJohn.Forte@Sun.COM 	iscsi_destroy_queue(&isp->sess_queue_pending);
370*12161SJack.Meng@Sun.COM 	rw_destroy(&isp->sess_state_rwlock);
3719780SBing.Zhao@Sun.COM 	mutex_destroy(&isp->sess_reset_mutex);
3727836SJohn.Forte@Sun.COM 	kmem_free(isp, sizeof (iscsi_sess_t));
3737836SJohn.Forte@Sun.COM 
3747836SJohn.Forte@Sun.COM 	return (NULL);
3757836SJohn.Forte@Sun.COM }
3767836SJohn.Forte@Sun.COM 
3777836SJohn.Forte@Sun.COM /*
3787836SJohn.Forte@Sun.COM  * iscsi_sess_get - return the session structure for based on a
3797836SJohn.Forte@Sun.COM  * passed in oid and hba instance.
3807836SJohn.Forte@Sun.COM  */
3817836SJohn.Forte@Sun.COM int
iscsi_sess_get(uint32_t oid,iscsi_hba_t * ihp,iscsi_sess_t ** ispp)3827836SJohn.Forte@Sun.COM iscsi_sess_get(uint32_t oid, iscsi_hba_t *ihp, iscsi_sess_t **ispp)
3837836SJohn.Forte@Sun.COM {
3847836SJohn.Forte@Sun.COM 	int		rval		= 0;
3857836SJohn.Forte@Sun.COM 	iscsi_sess_t	*isp		= NULL;
3867836SJohn.Forte@Sun.COM 
3877836SJohn.Forte@Sun.COM 	ASSERT(ihp != NULL);
3887836SJohn.Forte@Sun.COM 	ASSERT(ispp != NULL);
3897836SJohn.Forte@Sun.COM 
3907836SJohn.Forte@Sun.COM 	/* See if we already created this session */
3917836SJohn.Forte@Sun.COM 	for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
3927836SJohn.Forte@Sun.COM 		/* compare target name as the unique identifier */
3937836SJohn.Forte@Sun.COM 		if (isp->sess_oid == oid) {
3947836SJohn.Forte@Sun.COM 			/* Found matching session */
3957836SJohn.Forte@Sun.COM 			break;
3967836SJohn.Forte@Sun.COM 		}
3977836SJohn.Forte@Sun.COM 	}
3987836SJohn.Forte@Sun.COM 
3997836SJohn.Forte@Sun.COM 	/* If not null this session is already available */
4007836SJohn.Forte@Sun.COM 	if (isp != NULL) {
4017836SJohn.Forte@Sun.COM 		/* Existing session, return it */
4027836SJohn.Forte@Sun.COM 		*ispp = isp;
4037836SJohn.Forte@Sun.COM 	} else {
4047836SJohn.Forte@Sun.COM 		rval = EFAULT;
4057836SJohn.Forte@Sun.COM 	}
4067836SJohn.Forte@Sun.COM 	return (rval);
4077836SJohn.Forte@Sun.COM }
4087836SJohn.Forte@Sun.COM 
4097836SJohn.Forte@Sun.COM /*
4107836SJohn.Forte@Sun.COM  * iscsi_sess_online - initiate online of sessions connections
4117836SJohn.Forte@Sun.COM  */
4127836SJohn.Forte@Sun.COM void
iscsi_sess_online(void * arg)4138488SBing.Zhao@Sun.COM iscsi_sess_online(void *arg)
4147836SJohn.Forte@Sun.COM {
4158488SBing.Zhao@Sun.COM 	iscsi_sess_t	*isp;
4167836SJohn.Forte@Sun.COM 	iscsi_hba_t	*ihp;
4177836SJohn.Forte@Sun.COM 	iscsi_conn_t	*icp;
4187836SJohn.Forte@Sun.COM 	int		idx;
419*12161SJack.Meng@Sun.COM 	uint32_t	event_count;
4207836SJohn.Forte@Sun.COM 
4218488SBing.Zhao@Sun.COM 	isp = (iscsi_sess_t *)arg;
4228488SBing.Zhao@Sun.COM 
4237836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
4247836SJohn.Forte@Sun.COM 	ihp = isp->sess_hba;
4257836SJohn.Forte@Sun.COM 	ASSERT(ihp != NULL);
4267836SJohn.Forte@Sun.COM 
4277836SJohn.Forte@Sun.COM 	/*
4287836SJohn.Forte@Sun.COM 	 * Stale /dev links can cause us to get floods
4297836SJohn.Forte@Sun.COM 	 * of config requests. To prevent these repeated
4307836SJohn.Forte@Sun.COM 	 * requests from causing unneeded login to the
4317836SJohn.Forte@Sun.COM 	 * unreachable target, we won't try it during
4327836SJohn.Forte@Sun.COM 	 * the delay.
4337836SJohn.Forte@Sun.COM 	 */
4347836SJohn.Forte@Sun.COM 	if (ddi_get_lbolt() < isp->sess_failure_lbolt +
4357836SJohn.Forte@Sun.COM 	    SEC_TO_TICK(isp->sess_storm_delay)) {
4367836SJohn.Forte@Sun.COM 		return;
4377836SJohn.Forte@Sun.COM 	}
4387836SJohn.Forte@Sun.COM 
4397836SJohn.Forte@Sun.COM 	/*
4407836SJohn.Forte@Sun.COM 	 * Perform a crude version of round robin to
4417836SJohn.Forte@Sun.COM 	 * determine which connection to use for
4427836SJohn.Forte@Sun.COM 	 * this session. Since byte 5 in session ID
4437836SJohn.Forte@Sun.COM 	 * is overridden for full feature session,
4447836SJohn.Forte@Sun.COM 	 * the connection to be selected depends on
4457836SJohn.Forte@Sun.COM 	 * the result of sess_isid[5] devided by the
4467836SJohn.Forte@Sun.COM 	 * next connection ID.
4477836SJohn.Forte@Sun.COM 	 * If MS/T is enabled and there are multiple
4487836SJohn.Forte@Sun.COM 	 * IPs are available on the target, we can
4497836SJohn.Forte@Sun.COM 	 * select different IPs to connect in this
4507836SJohn.Forte@Sun.COM 	 * way.
4517836SJohn.Forte@Sun.COM 	 */
4527836SJohn.Forte@Sun.COM 	icp = isp->sess_conn_act;
4537836SJohn.Forte@Sun.COM 	if (icp == NULL) {
4547836SJohn.Forte@Sun.COM 		icp = isp->sess_conn_list;
4557836SJohn.Forte@Sun.COM 		for (idx = 0; idx < (isp->sess_isid[5] %
4567836SJohn.Forte@Sun.COM 		    isp->sess_conn_next_cid); idx++) {
4577836SJohn.Forte@Sun.COM 			ASSERT(icp->conn_next != NULL);
4587836SJohn.Forte@Sun.COM 			icp = icp->conn_next;
4597836SJohn.Forte@Sun.COM 		}
4607836SJohn.Forte@Sun.COM 		isp->sess_conn_act = icp;
4617836SJohn.Forte@Sun.COM 	}
4627836SJohn.Forte@Sun.COM 
4637836SJohn.Forte@Sun.COM 	if (icp == NULL) {
4647836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "iscsi session(%d) - "
4657836SJohn.Forte@Sun.COM 		    "no connection assigned", isp->sess_oid);
4667836SJohn.Forte@Sun.COM 		return;
4677836SJohn.Forte@Sun.COM 	}
4687836SJohn.Forte@Sun.COM 
4697836SJohn.Forte@Sun.COM 	/*
4707836SJohn.Forte@Sun.COM 	 * If connection is in free state, start
4717836SJohn.Forte@Sun.COM 	 * login.  If already logged in, try to
4727836SJohn.Forte@Sun.COM 	 * re-enumerate LUs on the session.
4737836SJohn.Forte@Sun.COM 	 */
4747836SJohn.Forte@Sun.COM 	mutex_enter(&icp->conn_state_mutex);
4757836SJohn.Forte@Sun.COM 	if (icp->conn_state == ISCSI_CONN_STATE_FREE) {
4767836SJohn.Forte@Sun.COM 		/*
4777836SJohn.Forte@Sun.COM 		 * attempt to login into the first connection in our connection
4787836SJohn.Forte@Sun.COM 		 * list.  If this fails, we will try the next connection
4797836SJohn.Forte@Sun.COM 		 * in our list until end of the list.
4807836SJohn.Forte@Sun.COM 		 */
4817836SJohn.Forte@Sun.COM 		while (icp != NULL) {
4829162SPeter.Dunlap@Sun.COM 			if (iscsi_conn_online(icp) == ISCSI_STATUS_SUCCESS) {
4837836SJohn.Forte@Sun.COM 				mutex_exit(&icp->conn_state_mutex);
4847836SJohn.Forte@Sun.COM 				break;
4857836SJohn.Forte@Sun.COM 			} else {
4867836SJohn.Forte@Sun.COM 				mutex_exit(&icp->conn_state_mutex);
4877836SJohn.Forte@Sun.COM 				icp = icp->conn_next;
4887836SJohn.Forte@Sun.COM 				if (icp != NULL) {
4897836SJohn.Forte@Sun.COM 					mutex_enter(&icp->conn_state_mutex);
4907836SJohn.Forte@Sun.COM 				}
4917836SJohn.Forte@Sun.COM 			}
4927836SJohn.Forte@Sun.COM 		}
4937836SJohn.Forte@Sun.COM 		isp->sess_conn_act = icp;
4947836SJohn.Forte@Sun.COM 		if (icp == NULL) {
4957836SJohn.Forte@Sun.COM 		/* the target for this session is unreachable */
4967836SJohn.Forte@Sun.COM 			isp->sess_failure_lbolt = ddi_get_lbolt();
4977836SJohn.Forte@Sun.COM 			if (isp->sess_storm_delay == 0) {
4987836SJohn.Forte@Sun.COM 				isp->sess_storm_delay++;
4997836SJohn.Forte@Sun.COM 			} else {
5007836SJohn.Forte@Sun.COM 
5017836SJohn.Forte@Sun.COM 				if ((isp->sess_storm_delay * 2) <
5027836SJohn.Forte@Sun.COM 				    iscsi_sess_max_delay) {
5037836SJohn.Forte@Sun.COM 					isp->sess_storm_delay =
5047836SJohn.Forte@Sun.COM 					    isp->sess_storm_delay * 2;
5057836SJohn.Forte@Sun.COM 				} else {
5067836SJohn.Forte@Sun.COM 					isp->sess_storm_delay =
5077836SJohn.Forte@Sun.COM 					    iscsi_sess_max_delay;
5087836SJohn.Forte@Sun.COM 				}
5097836SJohn.Forte@Sun.COM 			}
5107836SJohn.Forte@Sun.COM 
5117836SJohn.Forte@Sun.COM 		} else {
5127836SJohn.Forte@Sun.COM 			isp->sess_storm_delay = 0;
5137836SJohn.Forte@Sun.COM 			isp->sess_failure_lbolt = 0;
5147836SJohn.Forte@Sun.COM 		}
5157836SJohn.Forte@Sun.COM 	} else if (icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN) {
5167836SJohn.Forte@Sun.COM 		mutex_exit(&icp->conn_state_mutex);
517*12161SJack.Meng@Sun.COM 		event_count = atomic_inc_32_nv(&isp->sess_state_event_count);
518*12161SJack.Meng@Sun.COM 		iscsi_sess_enter_state_zone(isp);
5197836SJohn.Forte@Sun.COM 		iscsi_sess_state_machine(isp,
520*12161SJack.Meng@Sun.COM 		    ISCSI_SESS_EVENT_N1, event_count);
521*12161SJack.Meng@Sun.COM 		iscsi_sess_exit_state_zone(isp);
5227836SJohn.Forte@Sun.COM 	} else {
5237836SJohn.Forte@Sun.COM 		mutex_exit(&icp->conn_state_mutex);
5247836SJohn.Forte@Sun.COM 	}
5257836SJohn.Forte@Sun.COM }
5267836SJohn.Forte@Sun.COM 
5277836SJohn.Forte@Sun.COM /*
5287836SJohn.Forte@Sun.COM  * iscsi_sess_destroy - Destroys a iscsi session structure
5297836SJohn.Forte@Sun.COM  * and de-associates it from the hba.
5307836SJohn.Forte@Sun.COM  */
5317836SJohn.Forte@Sun.COM iscsi_status_t
iscsi_sess_destroy(iscsi_sess_t * isp)5327836SJohn.Forte@Sun.COM iscsi_sess_destroy(iscsi_sess_t *isp)
5337836SJohn.Forte@Sun.COM {
5347836SJohn.Forte@Sun.COM 	iscsi_status_t	rval	= ISCSI_STATUS_SUCCESS;
5358049SLarry.Liu@Sun.COM 	iscsi_status_t	tmprval = ISCSI_STATUS_SUCCESS;
5367836SJohn.Forte@Sun.COM 	iscsi_hba_t	*ihp;
5377836SJohn.Forte@Sun.COM 	iscsi_sess_t	*t_isp;
5387836SJohn.Forte@Sun.COM 	iscsi_lun_t	*ilp;
5397836SJohn.Forte@Sun.COM 	iscsi_conn_t	*icp;
5407836SJohn.Forte@Sun.COM 
5417836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
5427836SJohn.Forte@Sun.COM 	ihp = isp->sess_hba;
5437836SJohn.Forte@Sun.COM 	ASSERT(ihp != NULL);
5447836SJohn.Forte@Sun.COM 
5457836SJohn.Forte@Sun.COM 	/*
5467836SJohn.Forte@Sun.COM 	 * The first step in tearing down the session
5477836SJohn.Forte@Sun.COM 	 * has to be offlining all the LUNs.  This will
5487836SJohn.Forte@Sun.COM 	 * ensure there is no outstanding IO by upper
5497836SJohn.Forte@Sun.COM 	 * level drivers.  If this fails then we are
5507836SJohn.Forte@Sun.COM 	 * unable to destroy the session.
5518049SLarry.Liu@Sun.COM 	 *
5528049SLarry.Liu@Sun.COM 	 * Try all luns and continue upon failure
5538049SLarry.Liu@Sun.COM 	 * to remove what is removable before returning
5548049SLarry.Liu@Sun.COM 	 * the last error.
5557836SJohn.Forte@Sun.COM 	 */
5567836SJohn.Forte@Sun.COM 	rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
5577836SJohn.Forte@Sun.COM 	ilp = isp->sess_lun_list;
5587836SJohn.Forte@Sun.COM 	while (ilp != NULL) {
5598049SLarry.Liu@Sun.COM 		iscsi_lun_t	*ilp_next = ilp->lun_next;
5608049SLarry.Liu@Sun.COM 
5618049SLarry.Liu@Sun.COM 		tmprval = iscsi_lun_destroy(ihp, ilp);
5628049SLarry.Liu@Sun.COM 		if (!ISCSI_SUCCESS(tmprval)) {
5638049SLarry.Liu@Sun.COM 			rval = tmprval;
5647836SJohn.Forte@Sun.COM 		}
5658049SLarry.Liu@Sun.COM 		ilp = ilp_next;
5667836SJohn.Forte@Sun.COM 	}
5677836SJohn.Forte@Sun.COM 	rw_exit(&isp->sess_lun_list_rwlock);
5687836SJohn.Forte@Sun.COM 
5698049SLarry.Liu@Sun.COM 	if (!ISCSI_SUCCESS(rval)) {
5708049SLarry.Liu@Sun.COM 		return (rval);
5718049SLarry.Liu@Sun.COM 	}
5728049SLarry.Liu@Sun.COM 
5737836SJohn.Forte@Sun.COM 	/* The next step is to logout of the connections. */
5749162SPeter.Dunlap@Sun.COM 	rw_enter(&isp->sess_conn_list_rwlock, RW_WRITER);
5757836SJohn.Forte@Sun.COM 	icp = isp->sess_conn_list;
5767836SJohn.Forte@Sun.COM 	while (icp != NULL) {
5777836SJohn.Forte@Sun.COM 		rval = iscsi_conn_offline(icp);
5787836SJohn.Forte@Sun.COM 		if (ISCSI_SUCCESS(rval)) {
5797836SJohn.Forte@Sun.COM 			/* Succes, Continue processing... */
5807836SJohn.Forte@Sun.COM 			icp = icp->conn_next;
5817836SJohn.Forte@Sun.COM 		} else {
5827836SJohn.Forte@Sun.COM 			/* Failure, Stop processing... */
5837836SJohn.Forte@Sun.COM 			rw_exit(&isp->sess_conn_list_rwlock);
5847836SJohn.Forte@Sun.COM 			return (rval);
5857836SJohn.Forte@Sun.COM 		}
5867836SJohn.Forte@Sun.COM 	}
5879162SPeter.Dunlap@Sun.COM 	rw_exit(&isp->sess_conn_list_rwlock);
5887836SJohn.Forte@Sun.COM 
5897836SJohn.Forte@Sun.COM 	/*
5907836SJohn.Forte@Sun.COM 	 * At this point all connections should be in
5917836SJohn.Forte@Sun.COM 	 * a FREE state which will have pushed the session
5927836SJohn.Forte@Sun.COM 	 * to a FREE state.
5937836SJohn.Forte@Sun.COM 	 */
5949162SPeter.Dunlap@Sun.COM 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FREE ||
5959162SPeter.Dunlap@Sun.COM 	    isp->sess_state == ISCSI_SESS_STATE_FAILED);
5967836SJohn.Forte@Sun.COM 
5977836SJohn.Forte@Sun.COM 	/* Stop watchdog before destroying connections */
5988277SJack.Meng@Sun.COM 	if (isp->sess_wd_thread) {
5998277SJack.Meng@Sun.COM 		iscsi_thread_destroy(isp->sess_wd_thread);
6008277SJack.Meng@Sun.COM 		isp->sess_wd_thread = NULL;
6018277SJack.Meng@Sun.COM 	}
6027836SJohn.Forte@Sun.COM 
6037836SJohn.Forte@Sun.COM 	/* Destroy connections */
6047836SJohn.Forte@Sun.COM 	rw_enter(&isp->sess_conn_list_rwlock, RW_WRITER);
6057836SJohn.Forte@Sun.COM 	icp = isp->sess_conn_list;
6067836SJohn.Forte@Sun.COM 	while (icp != NULL) {
6077836SJohn.Forte@Sun.COM 		rval = iscsi_conn_destroy(icp);
6087836SJohn.Forte@Sun.COM 		if (!ISCSI_SUCCESS(rval)) {
6097836SJohn.Forte@Sun.COM 			rw_exit(&isp->sess_conn_list_rwlock);
6107836SJohn.Forte@Sun.COM 			return (rval);
6117836SJohn.Forte@Sun.COM 		}
6127836SJohn.Forte@Sun.COM 		icp = isp->sess_conn_list;
6137836SJohn.Forte@Sun.COM 	}
6147836SJohn.Forte@Sun.COM 	rw_exit(&isp->sess_conn_list_rwlock);
6157836SJohn.Forte@Sun.COM 
61611476SBing.Zhao@Sun.COM 	/* Destroy Session ic thread */
61711476SBing.Zhao@Sun.COM 	if (isp->sess_ic_thread != NULL) {
61811476SBing.Zhao@Sun.COM 		iscsi_thread_destroy(isp->sess_ic_thread);
61911476SBing.Zhao@Sun.COM 		isp->sess_ic_thread = NULL;
62011476SBing.Zhao@Sun.COM 	}
62111476SBing.Zhao@Sun.COM 
6227836SJohn.Forte@Sun.COM 	/* Destroy session task queue */
623*12161SJack.Meng@Sun.COM 	ddi_taskq_destroy(isp->sess_enum_taskq);
624*12161SJack.Meng@Sun.COM 	ddi_taskq_destroy(isp->sess_login_taskq);
6257836SJohn.Forte@Sun.COM 
6267836SJohn.Forte@Sun.COM 	/* destroy pending and completion queues */
6277836SJohn.Forte@Sun.COM 	iscsi_destroy_queue(&isp->sess_queue_pending);
6287836SJohn.Forte@Sun.COM 	iscsi_destroy_queue(&isp->sess_queue_completion);
6297836SJohn.Forte@Sun.COM 
6307836SJohn.Forte@Sun.COM 	/* Remove session from ihp */
6317836SJohn.Forte@Sun.COM 	if (ihp->hba_sess_list == isp) {
6327836SJohn.Forte@Sun.COM 		/* session first item in list */
6337836SJohn.Forte@Sun.COM 		ihp->hba_sess_list = isp->sess_next;
6347836SJohn.Forte@Sun.COM 	} else {
6357836SJohn.Forte@Sun.COM 		/*
6367836SJohn.Forte@Sun.COM 		 * search hba list for isp pointing
6377836SJohn.Forte@Sun.COM 		 * to session being removed.  Then
6387836SJohn.Forte@Sun.COM 		 * update that sessions next pointer.
6397836SJohn.Forte@Sun.COM 		 */
6407836SJohn.Forte@Sun.COM 		t_isp = ihp->hba_sess_list;
6417836SJohn.Forte@Sun.COM 		while (t_isp->sess_next != NULL) {
6427836SJohn.Forte@Sun.COM 			if (t_isp->sess_next == isp) {
6437836SJohn.Forte@Sun.COM 				break;
6447836SJohn.Forte@Sun.COM 			}
6457836SJohn.Forte@Sun.COM 			t_isp = t_isp->sess_next;
6467836SJohn.Forte@Sun.COM 		}
6477836SJohn.Forte@Sun.COM 		if (t_isp->sess_next == isp) {
6487836SJohn.Forte@Sun.COM 			t_isp->sess_next = isp->sess_next;
6497836SJohn.Forte@Sun.COM 		} else {
6507836SJohn.Forte@Sun.COM 			/* couldn't find session */
6517836SJohn.Forte@Sun.COM 			ASSERT(FALSE);
6527836SJohn.Forte@Sun.COM 		}
6537836SJohn.Forte@Sun.COM 	}
6547836SJohn.Forte@Sun.COM 
655*12161SJack.Meng@Sun.COM 	if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
656*12161SJack.Meng@Sun.COM 		/* Wait for all enum requests complete */
657*12161SJack.Meng@Sun.COM 		mutex_enter(&isp->sess_enum_lock);
658*12161SJack.Meng@Sun.COM 		while (isp->sess_enum_result_count > 0) {
659*12161SJack.Meng@Sun.COM 			cv_wait(&isp->sess_enum_cv, &isp->sess_enum_lock);
660*12161SJack.Meng@Sun.COM 		}
661*12161SJack.Meng@Sun.COM 		mutex_exit(&isp->sess_enum_lock);
662*12161SJack.Meng@Sun.COM 	}
663*12161SJack.Meng@Sun.COM 
6647836SJohn.Forte@Sun.COM 	/* Destroy this Sessions Data */
6657836SJohn.Forte@Sun.COM 	(void) iscsi_sess_kstat_term(isp);
6667836SJohn.Forte@Sun.COM 	rw_destroy(&isp->sess_lun_list_rwlock);
6677836SJohn.Forte@Sun.COM 	rw_destroy(&isp->sess_conn_list_rwlock);
6687836SJohn.Forte@Sun.COM 	mutex_destroy(&isp->sess_cmdsn_mutex);
669*12161SJack.Meng@Sun.COM 	rw_destroy(&isp->sess_state_rwlock);
6709780SBing.Zhao@Sun.COM 	mutex_destroy(&isp->sess_reset_mutex);
671*12161SJack.Meng@Sun.COM 	if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
672*12161SJack.Meng@Sun.COM 		mutex_destroy(&isp->sess_enum_lock);
673*12161SJack.Meng@Sun.COM 		cv_destroy(&isp->sess_enum_cv);
674*12161SJack.Meng@Sun.COM 	}
675*12161SJack.Meng@Sun.COM 	mutex_destroy(&isp->sess_state_wmutex);
676*12161SJack.Meng@Sun.COM 	cv_destroy(&isp->sess_state_wcv);
6777836SJohn.Forte@Sun.COM 	kmem_free(isp, sizeof (iscsi_sess_t));
6787836SJohn.Forte@Sun.COM 	return (rval);
6797836SJohn.Forte@Sun.COM }
6807836SJohn.Forte@Sun.COM 
6818194SJack.Meng@Sun.COM extern ib_boot_prop_t   *iscsiboot_prop;
6827836SJohn.Forte@Sun.COM /*
6837836SJohn.Forte@Sun.COM  * static iscsi_sess_set_auth -
6847836SJohn.Forte@Sun.COM  *
6857836SJohn.Forte@Sun.COM  */
6867836SJohn.Forte@Sun.COM boolean_t
iscsi_sess_set_auth(iscsi_sess_t * isp)6877836SJohn.Forte@Sun.COM iscsi_sess_set_auth(iscsi_sess_t *isp)
6887836SJohn.Forte@Sun.COM {
6897836SJohn.Forte@Sun.COM 	char			*init_name;
6907836SJohn.Forte@Sun.COM 	iscsi_chap_props_t	*chap = NULL;
6917836SJohn.Forte@Sun.COM 	iscsi_auth_props_t	*auth = NULL;
6928194SJack.Meng@Sun.COM 	uchar_t			*tmp  = NULL;
6937836SJohn.Forte@Sun.COM 
6947836SJohn.Forte@Sun.COM 	if (isp == (iscsi_sess_t *)NULL) {
6957836SJohn.Forte@Sun.COM 		return (B_FALSE);
6967836SJohn.Forte@Sun.COM 	}
6977836SJohn.Forte@Sun.COM 
6987836SJohn.Forte@Sun.COM 	/* Obtain initiator's name */
6997836SJohn.Forte@Sun.COM 	if (isp->sess_hba == (iscsi_hba_t *)NULL) {
7007836SJohn.Forte@Sun.COM 		return (B_FALSE);
7017836SJohn.Forte@Sun.COM 	}
7028194SJack.Meng@Sun.COM 
7037836SJohn.Forte@Sun.COM 	init_name = (char *)isp->sess_hba->hba_name;
7047836SJohn.Forte@Sun.COM 
7057836SJohn.Forte@Sun.COM 	/* Zero out the session authentication structure */
7067836SJohn.Forte@Sun.COM 	bzero(&isp->sess_auth, sizeof (iscsi_auth_t));
7077836SJohn.Forte@Sun.COM 
7088194SJack.Meng@Sun.COM 	if (isp->sess_boot == B_FALSE) {
7098194SJack.Meng@Sun.COM 
7108194SJack.Meng@Sun.COM 		auth = (iscsi_auth_props_t *)kmem_zalloc
7118194SJack.Meng@Sun.COM 		    (sizeof (iscsi_auth_props_t), KM_SLEEP);
7128194SJack.Meng@Sun.COM 		/* Obtain target's authentication settings. */
7138194SJack.Meng@Sun.COM 		if (persistent_auth_get((char *)isp->sess_name, auth)
7148194SJack.Meng@Sun.COM 		    != B_TRUE) {
7158194SJack.Meng@Sun.COM 			/*
7168194SJack.Meng@Sun.COM 			 * If no target authentication settings found,
7178194SJack.Meng@Sun.COM 			 * try to obtain system wide configuration
7188194SJack.Meng@Sun.COM 			 * (from the initiator).
7198194SJack.Meng@Sun.COM 			 */
7208194SJack.Meng@Sun.COM 			bzero(auth, sizeof (*auth));
7218194SJack.Meng@Sun.COM 			if (persistent_auth_get(init_name, auth) != B_TRUE) {
7228194SJack.Meng@Sun.COM 				bzero(auth, sizeof (*auth));
7238194SJack.Meng@Sun.COM 				auth->a_auth_method = authMethodNone;
7248194SJack.Meng@Sun.COM 			}
7258194SJack.Meng@Sun.COM 
7268194SJack.Meng@Sun.COM 			/*
7278194SJack.Meng@Sun.COM 			 * We do not support system wide bi-directional
7288194SJack.Meng@Sun.COM 			 * auth flag.
7298194SJack.Meng@Sun.COM 			 */
7308194SJack.Meng@Sun.COM 			auth->a_bi_auth = B_FALSE;
7318194SJack.Meng@Sun.COM 		}
7328194SJack.Meng@Sun.COM 
7338194SJack.Meng@Sun.COM 		chap = (iscsi_chap_props_t *)kmem_zalloc
7348194SJack.Meng@Sun.COM 		    (sizeof (iscsi_chap_props_t), KM_SLEEP);
7357836SJohn.Forte@Sun.COM 
7368194SJack.Meng@Sun.COM 		/*
7378194SJack.Meng@Sun.COM 		 * Initialize the target-side chap name to the session name
7388194SJack.Meng@Sun.COM 		 * if no chap settings have been saved for the current session.
7398194SJack.Meng@Sun.COM 		 */
7408194SJack.Meng@Sun.COM 		if (persistent_chap_get((char *)isp->sess_name, chap)
7418194SJack.Meng@Sun.COM 		    == B_FALSE) {
7428194SJack.Meng@Sun.COM 			int name_len = strlen((char *)isp->sess_name);
7438194SJack.Meng@Sun.COM 			bcopy((char *)isp->sess_name, chap->c_user, name_len);
7448194SJack.Meng@Sun.COM 			chap->c_user_len = name_len;
7458194SJack.Meng@Sun.COM 			(void) (persistent_chap_set((char *)isp->sess_name,
7468194SJack.Meng@Sun.COM 			    chap));
7478194SJack.Meng@Sun.COM 			bzero(chap, sizeof (*chap));
7488194SJack.Meng@Sun.COM 		}
7497836SJohn.Forte@Sun.COM 
7508194SJack.Meng@Sun.COM 		if (auth->a_auth_method & authMethodCHAP) {
7518194SJack.Meng@Sun.COM 			/* Obtain initiator's CHAP settings. */
7528194SJack.Meng@Sun.COM 			if (persistent_chap_get(init_name, chap) == B_FALSE) {
7538194SJack.Meng@Sun.COM 				/* No initiator secret defined. */
7548194SJack.Meng@Sun.COM 				kmem_free(chap, sizeof (iscsi_chap_props_t));
7558194SJack.Meng@Sun.COM 				/* Set authentication method to NONE */
7568194SJack.Meng@Sun.COM 				isp->sess_auth.password_length = 0;
7578194SJack.Meng@Sun.COM 				kmem_free(auth, sizeof (iscsi_auth_props_t));
7588194SJack.Meng@Sun.COM 				return (B_FALSE);
7598194SJack.Meng@Sun.COM 			}
7608194SJack.Meng@Sun.COM 
7618194SJack.Meng@Sun.COM 			bcopy(chap->c_user, isp->sess_auth.username,
7628194SJack.Meng@Sun.COM 			    sizeof (chap->c_user));
7638194SJack.Meng@Sun.COM 			bcopy(chap->c_secret, isp->sess_auth.password,
7648194SJack.Meng@Sun.COM 			    sizeof (chap->c_secret));
7658194SJack.Meng@Sun.COM 			isp->sess_auth.password_length = chap->c_secret_len;
7668194SJack.Meng@Sun.COM 		} else {
7677836SJohn.Forte@Sun.COM 			/* Set authentication method to NONE */
7687836SJohn.Forte@Sun.COM 			isp->sess_auth.password_length = 0;
7698194SJack.Meng@Sun.COM 		}
7708194SJack.Meng@Sun.COM 
7718194SJack.Meng@Sun.COM 		/*
7728194SJack.Meng@Sun.COM 		 * Consider enabling bidirectional authentication only if
7738194SJack.Meng@Sun.COM 		 * authentication method is not NONE.
7748194SJack.Meng@Sun.COM 		 */
7758194SJack.Meng@Sun.COM 		if (auth->a_auth_method & authMethodCHAP &&
7768194SJack.Meng@Sun.COM 		    auth->a_bi_auth == B_TRUE) {
7778194SJack.Meng@Sun.COM 			/* Enable bi-directional authentication. */
7788194SJack.Meng@Sun.COM 			isp->sess_auth.bidirectional_auth = 1;
7798194SJack.Meng@Sun.COM 
7808194SJack.Meng@Sun.COM 			bzero(chap, sizeof (*chap));
7818194SJack.Meng@Sun.COM 			/* Obtain target's CHAP settings. */
7828194SJack.Meng@Sun.COM 			if (persistent_chap_get((char *)isp->sess_name, chap)
7838194SJack.Meng@Sun.COM 			    == B_TRUE) {
7848194SJack.Meng@Sun.COM 				bcopy(chap->c_secret,
7858194SJack.Meng@Sun.COM 				    isp->sess_auth.password_in,
7868194SJack.Meng@Sun.COM 				    sizeof (chap->c_secret));
7878194SJack.Meng@Sun.COM 				bcopy(chap->c_user, isp->sess_auth.username_in,
7888194SJack.Meng@Sun.COM 				    strlen((char *)chap->c_user));
7898194SJack.Meng@Sun.COM 				isp->sess_auth.password_length_in =
7908194SJack.Meng@Sun.COM 				    chap->c_secret_len;
7918194SJack.Meng@Sun.COM 			} else {
7928194SJack.Meng@Sun.COM 				/*
7938194SJack.Meng@Sun.COM 				 * No target secret defined.
7948194SJack.Meng@Sun.COM 				 * RADIUS server should have been enabled.
7958194SJack.Meng@Sun.COM 				 */
7968194SJack.Meng@Sun.COM 				/* EMPTY */
7978194SJack.Meng@Sun.COM 			}
7988194SJack.Meng@Sun.COM 		} else {
7998194SJack.Meng@Sun.COM 			/* Disable bi-directional authentication */
8008194SJack.Meng@Sun.COM 			isp->sess_auth.bidirectional_auth = 0;
8018194SJack.Meng@Sun.COM 		}
8028194SJack.Meng@Sun.COM 
8038194SJack.Meng@Sun.COM 		if (auth != NULL) {
8047836SJohn.Forte@Sun.COM 			kmem_free(auth, sizeof (iscsi_auth_props_t));
8058194SJack.Meng@Sun.COM 		}
8068194SJack.Meng@Sun.COM 		if (chap != NULL) {
8078194SJack.Meng@Sun.COM 			kmem_free(chap, sizeof (iscsi_chap_props_t));
8088194SJack.Meng@Sun.COM 		}
8098194SJack.Meng@Sun.COM 	} else {
8108194SJack.Meng@Sun.COM 		/*
8118194SJack.Meng@Sun.COM 		 * This session is boot session. We will use the CHAP and
8128194SJack.Meng@Sun.COM 		 * the user name got from the boot property structure instead
8138194SJack.Meng@Sun.COM 		 * of persistent sotre.
8148194SJack.Meng@Sun.COM 		 */
8158194SJack.Meng@Sun.COM 		if (iscsiboot_prop == NULL) {
8167836SJohn.Forte@Sun.COM 			return (B_FALSE);
8177836SJohn.Forte@Sun.COM 		}
8187836SJohn.Forte@Sun.COM 
8198194SJack.Meng@Sun.COM 		if (iscsiboot_prop->boot_init.ini_chap_sec == NULL) {
8208194SJack.Meng@Sun.COM 			return (B_FALSE);
8218194SJack.Meng@Sun.COM 		}
8228194SJack.Meng@Sun.COM 
8238194SJack.Meng@Sun.COM 		/* CHAP secret */
8248194SJack.Meng@Sun.COM 		(void) bcopy(iscsiboot_prop->boot_init.ini_chap_sec,
8258194SJack.Meng@Sun.COM 		    isp->sess_auth.password,
8268194SJack.Meng@Sun.COM 		    strlen((char *)iscsiboot_prop->boot_init.ini_chap_sec));
8277836SJohn.Forte@Sun.COM 
8288194SJack.Meng@Sun.COM 		/*
8298194SJack.Meng@Sun.COM 		 * If chap name is not set,
8308194SJack.Meng@Sun.COM 		 * we will use initiator name instead.
8318194SJack.Meng@Sun.COM 		 */
8328194SJack.Meng@Sun.COM 		if (iscsiboot_prop->boot_init.ini_chap_name == NULL) {
8338194SJack.Meng@Sun.COM 			(void) bcopy(init_name, isp->sess_auth.username,
8348194SJack.Meng@Sun.COM 			    strlen(init_name));
8358194SJack.Meng@Sun.COM 		} else {
8368194SJack.Meng@Sun.COM 			tmp = iscsiboot_prop->boot_init.ini_chap_name;
8378194SJack.Meng@Sun.COM 			(void) bcopy(tmp,
8388194SJack.Meng@Sun.COM 			    isp->sess_auth.username, strlen((char *)tmp));
8398194SJack.Meng@Sun.COM 		}
8408194SJack.Meng@Sun.COM 
8418194SJack.Meng@Sun.COM 		isp->sess_auth.password_length =
8428194SJack.Meng@Sun.COM 		    strlen((char *)iscsiboot_prop->boot_init.ini_chap_sec);
8437836SJohn.Forte@Sun.COM 
8448194SJack.Meng@Sun.COM 		if (iscsiboot_prop->boot_tgt.tgt_chap_sec != NULL) {
8458194SJack.Meng@Sun.COM 			/*
8468194SJack.Meng@Sun.COM 			 * Bidirectional authentication is required.
8478194SJack.Meng@Sun.COM 			 */
8488194SJack.Meng@Sun.COM 			tmp = iscsiboot_prop->boot_tgt.tgt_chap_sec;
8498194SJack.Meng@Sun.COM 			(void) bcopy(tmp,
8508194SJack.Meng@Sun.COM 			    isp->sess_auth.password_in, strlen((char *)tmp));
8518194SJack.Meng@Sun.COM 
8527836SJohn.Forte@Sun.COM 			/*
8538194SJack.Meng@Sun.COM 			 * If the target's chap name is not set, we will use
8548194SJack.Meng@Sun.COM 			 * session name instead.
8557836SJohn.Forte@Sun.COM 			 */
8568194SJack.Meng@Sun.COM 			if (iscsiboot_prop->boot_tgt.tgt_chap_name == NULL) {
8578194SJack.Meng@Sun.COM 				(void) bcopy(isp->sess_name,
8588194SJack.Meng@Sun.COM 				    isp->sess_auth.username_in,
8598194SJack.Meng@Sun.COM 				    isp->sess_name_length);
8608194SJack.Meng@Sun.COM 			} else {
8618194SJack.Meng@Sun.COM 				tmp = iscsiboot_prop->boot_tgt.tgt_chap_name;
8628194SJack.Meng@Sun.COM 				(void) bcopy(tmp,
8638194SJack.Meng@Sun.COM 				    isp->sess_auth.username_in,
8648194SJack.Meng@Sun.COM 				    strlen((char *)tmp));
8658194SJack.Meng@Sun.COM 			}
8668194SJack.Meng@Sun.COM 			tmp = iscsiboot_prop->boot_tgt.tgt_chap_sec;
8678194SJack.Meng@Sun.COM 			isp->sess_auth.password_length_in =
8688194SJack.Meng@Sun.COM 			    strlen((char *)tmp);
8698194SJack.Meng@Sun.COM 			isp->sess_auth.bidirectional_auth = 1;
8707836SJohn.Forte@Sun.COM 		}
8717836SJohn.Forte@Sun.COM 	}
8727836SJohn.Forte@Sun.COM 
8737836SJohn.Forte@Sun.COM 	/* Set up authentication buffers only if configured */
8747836SJohn.Forte@Sun.COM 	if ((isp->sess_auth.password_length != 0) ||
8757836SJohn.Forte@Sun.COM 	    (isp->sess_auth.password_length_in != 0)) {
8767836SJohn.Forte@Sun.COM 		isp->sess_auth.num_auth_buffers = 5;
8777836SJohn.Forte@Sun.COM 		isp->sess_auth.auth_buffers[0].address =
8787836SJohn.Forte@Sun.COM 		    &(isp->sess_auth.auth_client_block);
8797836SJohn.Forte@Sun.COM 		isp->sess_auth.auth_buffers[0].length =
8807836SJohn.Forte@Sun.COM 		    sizeof (isp->sess_auth.auth_client_block);
8817836SJohn.Forte@Sun.COM 		isp->sess_auth.auth_buffers[1].address =
8827836SJohn.Forte@Sun.COM 		    &(isp->sess_auth.auth_recv_string_block);
8837836SJohn.Forte@Sun.COM 		isp->sess_auth.auth_buffers[1].length =
8847836SJohn.Forte@Sun.COM 		    sizeof (isp->sess_auth.auth_recv_string_block);
8857836SJohn.Forte@Sun.COM 		isp->sess_auth.auth_buffers[2].address =
8867836SJohn.Forte@Sun.COM 		    &(isp->sess_auth.auth_send_string_block);
8877836SJohn.Forte@Sun.COM 		isp->sess_auth.auth_buffers[2].length =
8887836SJohn.Forte@Sun.COM 		    sizeof (isp->sess_auth.auth_send_string_block);
8897836SJohn.Forte@Sun.COM 		isp->sess_auth.auth_buffers[3].address =
8907836SJohn.Forte@Sun.COM 		    &(isp->sess_auth.auth_recv_binary_block);
8917836SJohn.Forte@Sun.COM 		isp->sess_auth.auth_buffers[3].length =
8927836SJohn.Forte@Sun.COM 		    sizeof (isp->sess_auth.auth_recv_binary_block);
8937836SJohn.Forte@Sun.COM 		isp->sess_auth.auth_buffers[4].address =
8947836SJohn.Forte@Sun.COM 		    &(isp->sess_auth.auth_send_binary_block);
8957836SJohn.Forte@Sun.COM 		isp->sess_auth.auth_buffers[4].length =
8967836SJohn.Forte@Sun.COM 		    sizeof (isp->sess_auth.auth_send_binary_block);
8977836SJohn.Forte@Sun.COM 	}
8987836SJohn.Forte@Sun.COM 
8997836SJohn.Forte@Sun.COM 	return (B_TRUE);
9007836SJohn.Forte@Sun.COM }
9017836SJohn.Forte@Sun.COM 
9029162SPeter.Dunlap@Sun.COM /*
9039162SPeter.Dunlap@Sun.COM  * iscsi_sess_reserve_itt - Used to reserve an ITT hash slot
9049162SPeter.Dunlap@Sun.COM  */
9059162SPeter.Dunlap@Sun.COM iscsi_status_t
iscsi_sess_reserve_scsi_itt(iscsi_cmd_t * icmdp)9069162SPeter.Dunlap@Sun.COM iscsi_sess_reserve_scsi_itt(iscsi_cmd_t *icmdp)
9079162SPeter.Dunlap@Sun.COM {
9089162SPeter.Dunlap@Sun.COM 	idm_task_t *itp;
9099162SPeter.Dunlap@Sun.COM 	iscsi_conn_t *icp = icmdp->cmd_conn;
9109162SPeter.Dunlap@Sun.COM 	itp = idm_task_alloc(icp->conn_ic);
9119162SPeter.Dunlap@Sun.COM 	if (itp == NULL)
9129162SPeter.Dunlap@Sun.COM 		return (ISCSI_STATUS_INTERNAL_ERROR);
9139162SPeter.Dunlap@Sun.COM 	itp->idt_private = icmdp;
9149162SPeter.Dunlap@Sun.COM 	icmdp->cmd_itp = itp;
9159162SPeter.Dunlap@Sun.COM 	icmdp->cmd_itt = itp->idt_tt;
9169162SPeter.Dunlap@Sun.COM 	return (ISCSI_STATUS_SUCCESS);
9179162SPeter.Dunlap@Sun.COM }
9189162SPeter.Dunlap@Sun.COM 
9199162SPeter.Dunlap@Sun.COM /*
9209162SPeter.Dunlap@Sun.COM  * iscsi_sess_release_scsi_itt - Used to release ITT hash slot
9219162SPeter.Dunlap@Sun.COM  */
9229162SPeter.Dunlap@Sun.COM void
iscsi_sess_release_scsi_itt(iscsi_cmd_t * icmdp)9239162SPeter.Dunlap@Sun.COM iscsi_sess_release_scsi_itt(iscsi_cmd_t *icmdp)
9249162SPeter.Dunlap@Sun.COM {
9259162SPeter.Dunlap@Sun.COM 	idm_task_free(icmdp->cmd_itp);
9269162SPeter.Dunlap@Sun.COM }
9277836SJohn.Forte@Sun.COM 
9287836SJohn.Forte@Sun.COM /*
9297836SJohn.Forte@Sun.COM  * iscsi_sess_reserve_itt - Used to reserve an ITT hash slot
9307836SJohn.Forte@Sun.COM  */
9317836SJohn.Forte@Sun.COM iscsi_status_t
iscsi_sess_reserve_itt(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)9327836SJohn.Forte@Sun.COM iscsi_sess_reserve_itt(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
9337836SJohn.Forte@Sun.COM {
9347836SJohn.Forte@Sun.COM 	/* If no more slots are open fail reservation */
9357836SJohn.Forte@Sun.COM 	if (isp->sess_cmd_table_count >= ISCSI_CMD_TABLE_SIZE) {
9367836SJohn.Forte@Sun.COM 		return (ISCSI_STATUS_ITT_TABLE_FULL);
9377836SJohn.Forte@Sun.COM 	}
9387836SJohn.Forte@Sun.COM 
9397836SJohn.Forte@Sun.COM 	/*
9409162SPeter.Dunlap@Sun.COM 	 * Keep itt values out of the range used by IDM
9419162SPeter.Dunlap@Sun.COM 	 */
9429162SPeter.Dunlap@Sun.COM 	if (isp->sess_itt < IDM_TASKIDS_MAX)
9439162SPeter.Dunlap@Sun.COM 		isp->sess_itt = IDM_TASKIDS_MAX;
9449162SPeter.Dunlap@Sun.COM 
9459162SPeter.Dunlap@Sun.COM 	/*
9467836SJohn.Forte@Sun.COM 	 * Find the next available slot.  Normally its the
9477836SJohn.Forte@Sun.COM 	 * slot pointed to by the session's sess_itt value.
9487836SJohn.Forte@Sun.COM 	 * If this is not true the table has become fragmented.
9497836SJohn.Forte@Sun.COM 	 * Fragmentation can occur during max loads and IOs
9507836SJohn.Forte@Sun.COM 	 * are completed out of order.  Defragmentation will
9517836SJohn.Forte@Sun.COM 	 * occur when IO slows down and ITT slots are released.
9527836SJohn.Forte@Sun.COM 	 */
9537836SJohn.Forte@Sun.COM 	while (isp->sess_cmd_table[isp->sess_itt %
9547836SJohn.Forte@Sun.COM 	    ISCSI_CMD_TABLE_SIZE] != NULL) {
9557836SJohn.Forte@Sun.COM 		isp->sess_itt++;
9567836SJohn.Forte@Sun.COM 	}
9577836SJohn.Forte@Sun.COM 
9587836SJohn.Forte@Sun.COM 	/* reserve slot and update counters */
9597836SJohn.Forte@Sun.COM 	icmdp->cmd_itt = isp->sess_itt;
9609162SPeter.Dunlap@Sun.COM 	isp->sess_cmd_table[isp->sess_itt %
9617836SJohn.Forte@Sun.COM 	    ISCSI_CMD_TABLE_SIZE] = icmdp;
9627836SJohn.Forte@Sun.COM 	isp->sess_cmd_table_count++;
9637836SJohn.Forte@Sun.COM 	isp->sess_itt++;
9647836SJohn.Forte@Sun.COM 
9657836SJohn.Forte@Sun.COM 	return (ISCSI_STATUS_SUCCESS);
9667836SJohn.Forte@Sun.COM }
9677836SJohn.Forte@Sun.COM 
9687836SJohn.Forte@Sun.COM /*
9697836SJohn.Forte@Sun.COM  * iscsi_sess_release_itt - Used to release ITT hash slot
9707836SJohn.Forte@Sun.COM  */
9717836SJohn.Forte@Sun.COM void
iscsi_sess_release_itt(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)9727836SJohn.Forte@Sun.COM iscsi_sess_release_itt(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
9737836SJohn.Forte@Sun.COM {
9747836SJohn.Forte@Sun.COM 	int hash_index = (icmdp->cmd_itt % ISCSI_CMD_TABLE_SIZE);
9757836SJohn.Forte@Sun.COM 
9767836SJohn.Forte@Sun.COM 	ASSERT(isp->sess_cmd_table[hash_index] != NULL);
9777836SJohn.Forte@Sun.COM 
9787836SJohn.Forte@Sun.COM 	/* release slot and update counters */
9797836SJohn.Forte@Sun.COM 	isp->sess_cmd_table[hash_index] = NULL;
9807836SJohn.Forte@Sun.COM 	isp->sess_cmd_table_count--;
9817836SJohn.Forte@Sun.COM }
9827836SJohn.Forte@Sun.COM 
9837836SJohn.Forte@Sun.COM /*
9847836SJohn.Forte@Sun.COM  * iscsi_sess_redrive_io - Used to redrive IO on connections in
9857836SJohn.Forte@Sun.COM  * a full feature state.
9867836SJohn.Forte@Sun.COM  */
9877836SJohn.Forte@Sun.COM void
iscsi_sess_redrive_io(iscsi_sess_t * isp)9887836SJohn.Forte@Sun.COM iscsi_sess_redrive_io(iscsi_sess_t *isp)
9897836SJohn.Forte@Sun.COM {
9907836SJohn.Forte@Sun.COM 	iscsi_conn_t	*icp;
9917836SJohn.Forte@Sun.COM 
9927836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
9937836SJohn.Forte@Sun.COM 
9947836SJohn.Forte@Sun.COM 	icp = isp->sess_conn_list;
9957836SJohn.Forte@Sun.COM 	while (icp != NULL) {
9967836SJohn.Forte@Sun.COM 		if (ISCSI_CONN_STATE_FULL_FEATURE(
9977836SJohn.Forte@Sun.COM 		    icp->conn_state)) {
99810185SJack.Meng@Sun.COM 			(void) iscsi_thread_send_wakeup(
9997836SJohn.Forte@Sun.COM 			    icp->conn_tx_thread);
10007836SJohn.Forte@Sun.COM 		}
10017836SJohn.Forte@Sun.COM 		icp = icp->conn_next;
10027836SJohn.Forte@Sun.COM 	}
10037836SJohn.Forte@Sun.COM }
10047836SJohn.Forte@Sun.COM 
10057836SJohn.Forte@Sun.COM /*
10067836SJohn.Forte@Sun.COM  * iscsi_sess_state_machine -
10077836SJohn.Forte@Sun.COM  *
10087836SJohn.Forte@Sun.COM  * 7.3.1  Session State Diagram for an Initiator
10097836SJohn.Forte@Sun.COM  *
10107836SJohn.Forte@Sun.COM  *      Symbolic Names for States:
10117836SJohn.Forte@Sun.COM  *        Q1: FREE      - State on instantiation of after cleanup
10127836SJohn.Forte@Sun.COM  *        Q3: LOGGED_IN - Waiting for all session events.
10137836SJohn.Forte@Sun.COM  *        Q4: FAILED    - Waiting for session recovery or session cont.
10147836SJohn.Forte@Sun.COM  *        Q5: IN_FLUSH	- A login parameter has changed.  We are in the
10157836SJohn.Forte@Sun.COM  *			  process of flushing active, aborting, and
10167836SJohn.Forte@Sun.COM  *			  completed queues. Once flushed the iscsi_ic_thread()
10177836SJohn.Forte@Sun.COM  *			  will drop of drop connections (T14) and reconnect
10187836SJohn.Forte@Sun.COM  *			  to the target with new values.
10197836SJohn.Forte@Sun.COM  *	  Q6: FLUSHED	- Active, Aborting and Completed Queues flushed.
10207836SJohn.Forte@Sun.COM  *			  Awaiting reconnect or failure. iscsi_tx/ic_threads
10217836SJohn.Forte@Sun.COM  *			  are still running and might be timing-out IOs.
10227836SJohn.Forte@Sun.COM  *      State Q3/4 represent the Full Feature Phase operation of the session.
10237836SJohn.Forte@Sun.COM  *
10247836SJohn.Forte@Sun.COM  *      The state diagram is as follows:
10257836SJohn.Forte@Sun.COM  *
102612001SZhang.Yi@Sun.COM  *                                ------ (N5/6/7 == NOOP)
102712001SZhang.Yi@Sun.COM  *                               / Q1    \
102812001SZhang.Yi@Sun.COM  *    +------------------------->\       /<-------------+
102912001SZhang.Yi@Sun.COM  *    |                           ---+---               |
103012001SZhang.Yi@Sun.COM  *    |                     N5       |N1                |
103112001SZhang.Yi@Sun.COM  *    |  +------+   +-------------+  |                  |
103212001SZhang.Yi@Sun.COM  *    |  |      V   V             |  V                  |
103312001SZhang.Yi@Sun.COM  *    |  |      ----+--           -----+                |
103412001SZhang.Yi@Sun.COM  *    |N6|N5/7 / Q4    \         / Q3   \(N6 == NOOP)   |
103512001SZhang.Yi@Sun.COM  *    +--+-----\       /----+--->\      /-----+---------+
103612001SZhang.Yi@Sun.COM  *    |         -------    /N1    -+----      |       N3|
103712001SZhang.Yi@Sun.COM  *    |  (N7 == NOOP)     /      N7|  ^ N1/3/5|         |
103812001SZhang.Yi@Sun.COM  *    |                  /         |  +-------+         |
103912001SZhang.Yi@Sun.COM  *    |  +-------+      /          |                    |
104012001SZhang.Yi@Sun.COM  *    |  |       V     /           v                    |
104112001SZhang.Yi@Sun.COM  *    |  |      -------           -+----                |
104212001SZhang.Yi@Sun.COM  *    |N6|N6   / Q6    \    N5   / Q5   \               |
104312001SZhang.Yi@Sun.COM  *    +--+-----\       /<--------\      /-----+---------+
104412001SZhang.Yi@Sun.COM  *              -------           ------      |       N3
104512001SZhang.Yi@Sun.COM  *            (N7 == NOOP)            ^ N1/3/5|
104612001SZhang.Yi@Sun.COM  *                                    +-------+
10477836SJohn.Forte@Sun.COM  *
10487836SJohn.Forte@Sun.COM  * The state transition table is as follows:
10497836SJohn.Forte@Sun.COM  *
105012001SZhang.Yi@Sun.COM  *            +------+------+----+--------+----+
105112001SZhang.Yi@Sun.COM  *            |Q1    |Q3    |Q4  |Q5      |Q6  |
105212001SZhang.Yi@Sun.COM  *       -----+------+------+----+--------+----+
105312001SZhang.Yi@Sun.COM  *        Q1  |N5/6/7|N1    | -  |        |    |
105412001SZhang.Yi@Sun.COM  *       -----+------+------+----+--------+----+
105512001SZhang.Yi@Sun.COM  *        Q3  |N3    |N1/3/5|N5  |N7      |    |
105612001SZhang.Yi@Sun.COM  *       -----+------+------+----+--------+----+
105712001SZhang.Yi@Sun.COM  *        Q4  |N6    |N1    |N5/7|        |    |
105812001SZhang.Yi@Sun.COM  *       -----+------+------+----+--------+----+
105912001SZhang.Yi@Sun.COM  *        Q5  |N3    |      |    |N1/3/5/7|N6  |
106012001SZhang.Yi@Sun.COM  *       -----+------+------+----+--------+----+
106112001SZhang.Yi@Sun.COM  *        Q6  |N6    |N1    |N6/7|        |    |
106212001SZhang.Yi@Sun.COM  *       -----+------+------+----+--------+----+
10637836SJohn.Forte@Sun.COM  *
10647836SJohn.Forte@Sun.COM  * Event definitions:
10657836SJohn.Forte@Sun.COM  *
10667836SJohn.Forte@Sun.COM  * -N1: A connection logged in
10677836SJohn.Forte@Sun.COM  * -N3: A connection logged out
10687836SJohn.Forte@Sun.COM  * -N5: A connection failed
10697836SJohn.Forte@Sun.COM  * -N6: Session state timeout occurred, or a session
10707836SJohn.Forte@Sun.COM  *      reinstatement cleared this session instance.  This results in
10717836SJohn.Forte@Sun.COM  *      the freeing of all associated resources and the session state
10727836SJohn.Forte@Sun.COM  *      is discarded.
10737836SJohn.Forte@Sun.COM  * -N7: Login parameters for session have changed.
10747836SJohn.Forte@Sun.COM  *	Re-negeotation required.
1075*12161SJack.Meng@Sun.COM  *
1076*12161SJack.Meng@Sun.COM  * Any caller to the state machine (and so as a state writer) must
1077*12161SJack.Meng@Sun.COM  * enter the state zone before calling this function, and vice versa
1078*12161SJack.Meng@Sun.COM  * any caller that doesn't change the state machine shouldn't enter
1079*12161SJack.Meng@Sun.COM  * the zone, and should act as a reader for a better performance.
1080*12161SJack.Meng@Sun.COM  *
1081*12161SJack.Meng@Sun.COM  * The handler of state transition shouldn't try to enter the state
1082*12161SJack.Meng@Sun.COM  * zone in the same thread or dead lock will occur.
10837836SJohn.Forte@Sun.COM  */
10847836SJohn.Forte@Sun.COM void
iscsi_sess_state_machine(iscsi_sess_t * isp,iscsi_sess_event_t event,uint32_t event_count)1085*12161SJack.Meng@Sun.COM iscsi_sess_state_machine(iscsi_sess_t *isp, iscsi_sess_event_t event,
1086*12161SJack.Meng@Sun.COM     uint32_t event_count)
10877836SJohn.Forte@Sun.COM {
10887836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
1089*12161SJack.Meng@Sun.COM 	ASSERT(rw_read_locked(&isp->sess_state_rwlock) == 0);
10907836SJohn.Forte@Sun.COM 
10917836SJohn.Forte@Sun.COM 	DTRACE_PROBE3(event, iscsi_sess_t *, isp,
10927836SJohn.Forte@Sun.COM 	    char *, iscsi_sess_state_str(isp->sess_state),
10937836SJohn.Forte@Sun.COM 	    char *, iscsi_sess_event_str(event));
10947836SJohn.Forte@Sun.COM 
10959162SPeter.Dunlap@Sun.COM 	/* Audit event */
10969162SPeter.Dunlap@Sun.COM 	idm_sm_audit_event(&isp->sess_state_audit,
10979162SPeter.Dunlap@Sun.COM 	    SAS_ISCSI_SESS, isp->sess_state, event, NULL);
10989162SPeter.Dunlap@Sun.COM 
10997836SJohn.Forte@Sun.COM 	isp->sess_prev_state = isp->sess_state;
11007836SJohn.Forte@Sun.COM 	isp->sess_state_lbolt = ddi_get_lbolt();
11017836SJohn.Forte@Sun.COM 
11029162SPeter.Dunlap@Sun.COM 	ISCSI_SESS_LOG(CE_NOTE,
1103*12161SJack.Meng@Sun.COM 	    "DEBUG: sess_state: isp: %p state: %d event: %d event count: %d",
1104*12161SJack.Meng@Sun.COM 	    (void *)isp, isp->sess_state, event, event_count);
11057836SJohn.Forte@Sun.COM 	switch (isp->sess_state) {
11067836SJohn.Forte@Sun.COM 	case ISCSI_SESS_STATE_FREE:
1107*12161SJack.Meng@Sun.COM 		iscsi_sess_state_free(isp, event, event_count);
11087836SJohn.Forte@Sun.COM 		break;
11097836SJohn.Forte@Sun.COM 	case ISCSI_SESS_STATE_LOGGED_IN:
1110*12161SJack.Meng@Sun.COM 		iscsi_sess_state_logged_in(isp, event, event_count);
11117836SJohn.Forte@Sun.COM 		break;
11127836SJohn.Forte@Sun.COM 	case ISCSI_SESS_STATE_FAILED:
1113*12161SJack.Meng@Sun.COM 		iscsi_sess_state_failed(isp, event, event_count);
11147836SJohn.Forte@Sun.COM 		break;
11157836SJohn.Forte@Sun.COM 	case ISCSI_SESS_STATE_IN_FLUSH:
1116*12161SJack.Meng@Sun.COM 		iscsi_sess_state_in_flush(isp, event, event_count);
11177836SJohn.Forte@Sun.COM 		break;
11187836SJohn.Forte@Sun.COM 	case ISCSI_SESS_STATE_FLUSHED:
1119*12161SJack.Meng@Sun.COM 		iscsi_sess_state_flushed(isp, event, event_count);
11207836SJohn.Forte@Sun.COM 		break;
11217836SJohn.Forte@Sun.COM 	default:
11227836SJohn.Forte@Sun.COM 		ASSERT(FALSE);
11237836SJohn.Forte@Sun.COM 	}
11249162SPeter.Dunlap@Sun.COM 
11259162SPeter.Dunlap@Sun.COM 	/* Audit state change */
11269162SPeter.Dunlap@Sun.COM 	if (isp->sess_prev_state != isp->sess_state) {
11279162SPeter.Dunlap@Sun.COM 		idm_sm_audit_state_change(&isp->sess_state_audit,
11289162SPeter.Dunlap@Sun.COM 		    SAS_ISCSI_SESS, isp->sess_prev_state, isp->sess_state);
11299162SPeter.Dunlap@Sun.COM 	}
11307836SJohn.Forte@Sun.COM }
11317836SJohn.Forte@Sun.COM 
11327836SJohn.Forte@Sun.COM 
11337836SJohn.Forte@Sun.COM /*
11347836SJohn.Forte@Sun.COM  * iscsi_sess_state_str -
11357836SJohn.Forte@Sun.COM  *
11367836SJohn.Forte@Sun.COM  */
11377836SJohn.Forte@Sun.COM char *
iscsi_sess_state_str(iscsi_sess_state_t state)11387836SJohn.Forte@Sun.COM iscsi_sess_state_str(iscsi_sess_state_t state)
11397836SJohn.Forte@Sun.COM {
11407836SJohn.Forte@Sun.COM 	switch (state) {
11417836SJohn.Forte@Sun.COM 	case ISCSI_SESS_STATE_FREE:
11427836SJohn.Forte@Sun.COM 		return ("free");
11437836SJohn.Forte@Sun.COM 	case ISCSI_SESS_STATE_LOGGED_IN:
11447836SJohn.Forte@Sun.COM 		return ("logged_in");
11457836SJohn.Forte@Sun.COM 	case ISCSI_SESS_STATE_FAILED:
11467836SJohn.Forte@Sun.COM 		return ("failed");
11477836SJohn.Forte@Sun.COM 	case ISCSI_SESS_STATE_IN_FLUSH:
11487836SJohn.Forte@Sun.COM 		return ("in_flush");
11497836SJohn.Forte@Sun.COM 	case ISCSI_SESS_STATE_FLUSHED:
11507836SJohn.Forte@Sun.COM 		return ("flushed");
11517836SJohn.Forte@Sun.COM 	default:
11527836SJohn.Forte@Sun.COM 		return ("unknown");
11537836SJohn.Forte@Sun.COM 	}
11547836SJohn.Forte@Sun.COM }
11557836SJohn.Forte@Sun.COM 
11567836SJohn.Forte@Sun.COM 
11577836SJohn.Forte@Sun.COM /*
11587836SJohn.Forte@Sun.COM  * +--------------------------------------------------------------------+
11597836SJohn.Forte@Sun.COM  * | Internal Session Interfaces					|
11607836SJohn.Forte@Sun.COM  * +--------------------------------------------------------------------+
11617836SJohn.Forte@Sun.COM  */
11627836SJohn.Forte@Sun.COM 
11637836SJohn.Forte@Sun.COM 
11647836SJohn.Forte@Sun.COM /*
11657836SJohn.Forte@Sun.COM  * iscsi_sess_state_free -
11667836SJohn.Forte@Sun.COM  *
11677836SJohn.Forte@Sun.COM  */
11687836SJohn.Forte@Sun.COM static void
iscsi_sess_state_free(iscsi_sess_t * isp,iscsi_sess_event_t event,uint32_t event_count)1169*12161SJack.Meng@Sun.COM iscsi_sess_state_free(iscsi_sess_t *isp, iscsi_sess_event_t event,
1170*12161SJack.Meng@Sun.COM     uint32_t event_count)
11717836SJohn.Forte@Sun.COM {
11727836SJohn.Forte@Sun.COM 	iscsi_hba_t		*ihp;
1173*12161SJack.Meng@Sun.COM 	iscsi_enum_result_t	enum_result;
11747836SJohn.Forte@Sun.COM 
11757836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
11767836SJohn.Forte@Sun.COM 	ihp = isp->sess_hba;
11777836SJohn.Forte@Sun.COM 	ASSERT(ihp != NULL);
11787836SJohn.Forte@Sun.COM 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FREE);
11797836SJohn.Forte@Sun.COM 
11807836SJohn.Forte@Sun.COM 	/* switch on event change */
11817836SJohn.Forte@Sun.COM 	switch (event) {
11827836SJohn.Forte@Sun.COM 	/*
11837836SJohn.Forte@Sun.COM 	 * -N1: A connection logged in
11847836SJohn.Forte@Sun.COM 	 */
11857836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N1:
118611476SBing.Zhao@Sun.COM 		isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN;
1187*12161SJack.Meng@Sun.COM 		rw_downgrade(&isp->sess_state_rwlock);
118811476SBing.Zhao@Sun.COM 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
118911476SBing.Zhao@Sun.COM 			cmn_err(CE_NOTE,
119011476SBing.Zhao@Sun.COM 			    "!iscsi session(%u) %s online\n",
119111476SBing.Zhao@Sun.COM 			    isp->sess_oid, isp->sess_name);
1192*12161SJack.Meng@Sun.COM 			enum_result =
1193*12161SJack.Meng@Sun.COM 			    iscsi_sess_enum_request(isp, B_TRUE,
1194*12161SJack.Meng@Sun.COM 			    event_count);
1195*12161SJack.Meng@Sun.COM 			if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
1196*12161SJack.Meng@Sun.COM 				enum_result =
1197*12161SJack.Meng@Sun.COM 				    iscsi_sess_enum_query(isp);
1198*12161SJack.Meng@Sun.COM 			}
1199*12161SJack.Meng@Sun.COM 			if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
1200*12161SJack.Meng@Sun.COM 				iscsi_sess_enum_warn(isp, enum_result);
12017836SJohn.Forte@Sun.COM 			}
12027836SJohn.Forte@Sun.COM 		}
12037836SJohn.Forte@Sun.COM 		break;
12047836SJohn.Forte@Sun.COM 
12057836SJohn.Forte@Sun.COM 	/*
120612001SZhang.Yi@Sun.COM 	 * -N5: A connection failed
120712001SZhang.Yi@Sun.COM 	 */
120812001SZhang.Yi@Sun.COM 	case ISCSI_SESS_EVENT_N5:
120912001SZhang.Yi@Sun.COM 		/* NOOP - not connected */
121012001SZhang.Yi@Sun.COM 		break;
121112001SZhang.Yi@Sun.COM 
121212001SZhang.Yi@Sun.COM 	/*
12137836SJohn.Forte@Sun.COM 	 * -N6: Session state timeout occurred, or a session
12147836SJohn.Forte@Sun.COM 	 *	reinstatement cleared this session instance.  This results in
12157836SJohn.Forte@Sun.COM 	 *	the freeing of all associated resources and the session state
12167836SJohn.Forte@Sun.COM 	 *	is discarded.
12177836SJohn.Forte@Sun.COM 	 */
12187836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N6:
12197836SJohn.Forte@Sun.COM 		/* FALLTHRU */
12207836SJohn.Forte@Sun.COM 
12217836SJohn.Forte@Sun.COM 	/*
12227836SJohn.Forte@Sun.COM 	 * -N7: Login parameters for session have changed.
12237836SJohn.Forte@Sun.COM 	 *	Re-negeotation required.
12247836SJohn.Forte@Sun.COM 	 */
12257836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N7:
12267836SJohn.Forte@Sun.COM 		/* NOOP - not connected */
12277836SJohn.Forte@Sun.COM 		break;
12287836SJohn.Forte@Sun.COM 
12297836SJohn.Forte@Sun.COM 	/* All other events are invalid for this state */
12307836SJohn.Forte@Sun.COM 	default:
12317836SJohn.Forte@Sun.COM 		ASSERT(FALSE);
12327836SJohn.Forte@Sun.COM 	}
12337836SJohn.Forte@Sun.COM }
12347836SJohn.Forte@Sun.COM 
12357836SJohn.Forte@Sun.COM 
12367836SJohn.Forte@Sun.COM /*
12377836SJohn.Forte@Sun.COM  * iscsi_sess_logged_in -
12387836SJohn.Forte@Sun.COM  *
12397836SJohn.Forte@Sun.COM  */
12407836SJohn.Forte@Sun.COM static void
iscsi_sess_state_logged_in(iscsi_sess_t * isp,iscsi_sess_event_t event,uint32_t event_count)1241*12161SJack.Meng@Sun.COM iscsi_sess_state_logged_in(iscsi_sess_t *isp, iscsi_sess_event_t event,
1242*12161SJack.Meng@Sun.COM     uint32_t event_count)
12437836SJohn.Forte@Sun.COM {
1244*12161SJack.Meng@Sun.COM 	iscsi_enum_result_t	enum_result;
12457836SJohn.Forte@Sun.COM 
12467836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
12477836SJohn.Forte@Sun.COM 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_LOGGED_IN);
12487836SJohn.Forte@Sun.COM 
12497836SJohn.Forte@Sun.COM 	/* switch on event change */
12507836SJohn.Forte@Sun.COM 	switch (event) {
12517836SJohn.Forte@Sun.COM 	/*
12527836SJohn.Forte@Sun.COM 	 * -N1: At least one transport connection reached the
12537836SJohn.Forte@Sun.COM 	 * LOGGED_IN state
12547836SJohn.Forte@Sun.COM 	 */
12557836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N1:
12567836SJohn.Forte@Sun.COM 		/*
12577836SJohn.Forte@Sun.COM 		 * A different connection already logged in.  If the
12587836SJohn.Forte@Sun.COM 		 * session is NORMAL, just re-enumerate the session.
12597836SJohn.Forte@Sun.COM 		 */
1260*12161SJack.Meng@Sun.COM 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1261*12161SJack.Meng@Sun.COM 			rw_downgrade(&isp->sess_state_rwlock);
1262*12161SJack.Meng@Sun.COM 			enum_result =
1263*12161SJack.Meng@Sun.COM 			    iscsi_sess_enum_request(isp, B_TRUE, event_count);
1264*12161SJack.Meng@Sun.COM 			if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
1265*12161SJack.Meng@Sun.COM 				enum_result = iscsi_sess_enum_query(isp);
1266*12161SJack.Meng@Sun.COM 			}
1267*12161SJack.Meng@Sun.COM 			if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
1268*12161SJack.Meng@Sun.COM 				iscsi_sess_enum_warn(isp, enum_result);
1269*12161SJack.Meng@Sun.COM 			}
12707836SJohn.Forte@Sun.COM 		}
12717836SJohn.Forte@Sun.COM 		break;
12727836SJohn.Forte@Sun.COM 
12737836SJohn.Forte@Sun.COM 	/*
12747836SJohn.Forte@Sun.COM 	 * -N3: A connection logged out.
12757836SJohn.Forte@Sun.COM 	 */
12767836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N3:
12777836SJohn.Forte@Sun.COM 		/* FALLTHRU */
12787836SJohn.Forte@Sun.COM 
12797836SJohn.Forte@Sun.COM 	/*
12807836SJohn.Forte@Sun.COM 	 * -N5: A connection failed
12817836SJohn.Forte@Sun.COM 	 */
12827836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N5:
12837836SJohn.Forte@Sun.COM 		/*
12847836SJohn.Forte@Sun.COM 		 * MC/S: If this is the last connection to
12857836SJohn.Forte@Sun.COM 		 * fail then move the the failed state.
12867836SJohn.Forte@Sun.COM 		 */
12877836SJohn.Forte@Sun.COM 		if (event == ISCSI_SESS_EVENT_N3) {
12887836SJohn.Forte@Sun.COM 			isp->sess_state = ISCSI_SESS_STATE_FREE;
12897836SJohn.Forte@Sun.COM 		} else {
12907836SJohn.Forte@Sun.COM 			isp->sess_state = ISCSI_SESS_STATE_FAILED;
12917836SJohn.Forte@Sun.COM 		}
1292*12161SJack.Meng@Sun.COM 		rw_downgrade(&isp->sess_state_rwlock);
12937836SJohn.Forte@Sun.COM 
12947836SJohn.Forte@Sun.COM 		/* no longer connected reset nego tpgt */
12957836SJohn.Forte@Sun.COM 		isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT;
12967836SJohn.Forte@Sun.COM 
12977836SJohn.Forte@Sun.COM 		iscsi_sess_flush(isp);
12987836SJohn.Forte@Sun.COM 
12997836SJohn.Forte@Sun.COM 		if (event == ISCSI_SESS_EVENT_N3) {
13007836SJohn.Forte@Sun.COM 			if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
13017836SJohn.Forte@Sun.COM 				cmn_err(CE_NOTE,
13027836SJohn.Forte@Sun.COM 				    "!iscsi session(%u) %s offline\n",
13037836SJohn.Forte@Sun.COM 				    isp->sess_oid, isp->sess_name);
13047836SJohn.Forte@Sun.COM 			}
13058336SJack.Meng@Sun.COM 			/*
13068336SJack.Meng@Sun.COM 			 * During the process of offlining the LUNs
13078336SJack.Meng@Sun.COM 			 * our ic thread might be calling back into
13088336SJack.Meng@Sun.COM 			 * the driver via a target driver failure
13098336SJack.Meng@Sun.COM 			 * path to do a reset or something
13108336SJack.Meng@Sun.COM 			 * we need to release the sess_state_mutex
13118336SJack.Meng@Sun.COM 			 * while we are killing these threads so
13128336SJack.Meng@Sun.COM 			 * they don't get deadlocked.
13138336SJack.Meng@Sun.COM 			 */
13147836SJohn.Forte@Sun.COM 			iscsi_sess_offline_luns(isp);
13157836SJohn.Forte@Sun.COM 		}
13167836SJohn.Forte@Sun.COM 
13179780SBing.Zhao@Sun.COM 		mutex_enter(&isp->sess_reset_mutex);
13189780SBing.Zhao@Sun.COM 		isp->sess_reset_in_progress = B_FALSE;
13199780SBing.Zhao@Sun.COM 		mutex_exit(&isp->sess_reset_mutex);
13209780SBing.Zhao@Sun.COM 		/* update busy luns if needed */
13219780SBing.Zhao@Sun.COM 		iscsi_sess_update_busy_luns(isp, B_TRUE);
13229780SBing.Zhao@Sun.COM 
13237836SJohn.Forte@Sun.COM 		break;
13247836SJohn.Forte@Sun.COM 
13257836SJohn.Forte@Sun.COM 	/*
13267836SJohn.Forte@Sun.COM 	 * -N6: Session state timeout occurred, or a session
13277836SJohn.Forte@Sun.COM 	 *	reinstatement cleared this session instance.  This results in
13287836SJohn.Forte@Sun.COM 	 *	the freeing of all associated resources and the session state
13297836SJohn.Forte@Sun.COM 	 *	is discarded.
13307836SJohn.Forte@Sun.COM 	 */
13317836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N6:
13327836SJohn.Forte@Sun.COM 		/* NOOP - Not last connection */
13337836SJohn.Forte@Sun.COM 		break;
13347836SJohn.Forte@Sun.COM 
13357836SJohn.Forte@Sun.COM 	/*
13367836SJohn.Forte@Sun.COM 	 * -N7: Login parameters for session have changed.
13377836SJohn.Forte@Sun.COM 	 *	Re-negeotation required.
13387836SJohn.Forte@Sun.COM 	 */
13397836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N7:
13407836SJohn.Forte@Sun.COM 		isp->sess_state = ISCSI_SESS_STATE_IN_FLUSH;
13417836SJohn.Forte@Sun.COM 		break;
13427836SJohn.Forte@Sun.COM 
13437836SJohn.Forte@Sun.COM 	/* All other events are invalid for this state */
13447836SJohn.Forte@Sun.COM 	default:
13457836SJohn.Forte@Sun.COM 		ASSERT(FALSE);
13467836SJohn.Forte@Sun.COM 	}
13477836SJohn.Forte@Sun.COM }
13487836SJohn.Forte@Sun.COM 
13497836SJohn.Forte@Sun.COM 
13507836SJohn.Forte@Sun.COM /*
13517836SJohn.Forte@Sun.COM  * iscsi_sess_state_failed -
13527836SJohn.Forte@Sun.COM  *
13537836SJohn.Forte@Sun.COM  */
13547836SJohn.Forte@Sun.COM static void
iscsi_sess_state_failed(iscsi_sess_t * isp,iscsi_sess_event_t event,uint32_t event_count)1355*12161SJack.Meng@Sun.COM iscsi_sess_state_failed(iscsi_sess_t *isp, iscsi_sess_event_t event,
1356*12161SJack.Meng@Sun.COM     uint32_t event_count)
13577836SJohn.Forte@Sun.COM {
13587836SJohn.Forte@Sun.COM 	iscsi_hba_t		*ihp;
1359*12161SJack.Meng@Sun.COM 	iscsi_enum_result_t	enum_result;
13607836SJohn.Forte@Sun.COM 
13617836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
13627836SJohn.Forte@Sun.COM 	ihp = isp->sess_hba;
13637836SJohn.Forte@Sun.COM 	ASSERT(ihp != NULL);
13647836SJohn.Forte@Sun.COM 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FAILED);
13657836SJohn.Forte@Sun.COM 
13667836SJohn.Forte@Sun.COM 	/* switch on event change */
13677836SJohn.Forte@Sun.COM 	switch (event) {
13687836SJohn.Forte@Sun.COM 	/* -N1: A session continuation attempt succeeded */
13697836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N1:
137011476SBing.Zhao@Sun.COM 		isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN;
1371*12161SJack.Meng@Sun.COM 		rw_downgrade(&isp->sess_state_rwlock);
1372*12161SJack.Meng@Sun.COM 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1373*12161SJack.Meng@Sun.COM 			enum_result =
1374*12161SJack.Meng@Sun.COM 			    iscsi_sess_enum_request(isp, B_TRUE,
1375*12161SJack.Meng@Sun.COM 			    event_count);
1376*12161SJack.Meng@Sun.COM 			if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
1377*12161SJack.Meng@Sun.COM 				enum_result =
1378*12161SJack.Meng@Sun.COM 				    iscsi_sess_enum_query(isp);
137911476SBing.Zhao@Sun.COM 			}
1380*12161SJack.Meng@Sun.COM 			if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
1381*12161SJack.Meng@Sun.COM 				iscsi_sess_enum_warn(isp, enum_result);
1382*12161SJack.Meng@Sun.COM 			}
13837836SJohn.Forte@Sun.COM 		}
13847836SJohn.Forte@Sun.COM 		break;
13857836SJohn.Forte@Sun.COM 
13867836SJohn.Forte@Sun.COM 	/*
138712001SZhang.Yi@Sun.COM 	 * -N5: A connection failed
138812001SZhang.Yi@Sun.COM 	 */
138912001SZhang.Yi@Sun.COM 	case ISCSI_SESS_EVENT_N5:
139012001SZhang.Yi@Sun.COM 		/* NOOP - not connected */
139112001SZhang.Yi@Sun.COM 		break;
139212001SZhang.Yi@Sun.COM 
139312001SZhang.Yi@Sun.COM 	/*
13947836SJohn.Forte@Sun.COM 	 * -N6: Session state timeout occurred, or a session
13957836SJohn.Forte@Sun.COM 	 *	reinstatement cleared this session instance.  This results in
13967836SJohn.Forte@Sun.COM 	 *	the freeing of all associated resources and the session state
13977836SJohn.Forte@Sun.COM 	 *	is discarded.
13987836SJohn.Forte@Sun.COM 	 */
13997836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N6:
14007836SJohn.Forte@Sun.COM 		isp->sess_state = ISCSI_SESS_STATE_FREE;
14017836SJohn.Forte@Sun.COM 
14027836SJohn.Forte@Sun.COM 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
14037836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE, "!iscsi session(%u) %s offline\n",
14047836SJohn.Forte@Sun.COM 			    isp->sess_oid, isp->sess_name);
14057836SJohn.Forte@Sun.COM 		}
14067836SJohn.Forte@Sun.COM 
1407*12161SJack.Meng@Sun.COM 		rw_downgrade(&isp->sess_state_rwlock);
14087836SJohn.Forte@Sun.COM 		iscsi_sess_offline_luns(isp);
14097836SJohn.Forte@Sun.COM 		break;
14107836SJohn.Forte@Sun.COM 
14117836SJohn.Forte@Sun.COM 	/*
14127836SJohn.Forte@Sun.COM 	 * -N7: Login parameters for session have changed.
14137836SJohn.Forte@Sun.COM 	 *	Re-negeotation required.
14147836SJohn.Forte@Sun.COM 	 */
14157836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N7:
14167836SJohn.Forte@Sun.COM 		/* NOOP - not connected */
14177836SJohn.Forte@Sun.COM 		break;
14187836SJohn.Forte@Sun.COM 
14197836SJohn.Forte@Sun.COM 	/* All other events are invalid for this state */
14207836SJohn.Forte@Sun.COM 	default:
14217836SJohn.Forte@Sun.COM 		ASSERT(FALSE);
14227836SJohn.Forte@Sun.COM 	}
14237836SJohn.Forte@Sun.COM }
14247836SJohn.Forte@Sun.COM 
14257836SJohn.Forte@Sun.COM /*
14267836SJohn.Forte@Sun.COM  * iscsi_sess_state_in_flush -
14277836SJohn.Forte@Sun.COM  *
14287836SJohn.Forte@Sun.COM  */
1429*12161SJack.Meng@Sun.COM /* ARGSUSED */
14307836SJohn.Forte@Sun.COM static void
iscsi_sess_state_in_flush(iscsi_sess_t * isp,iscsi_sess_event_t event,uint32_t event_count)1431*12161SJack.Meng@Sun.COM iscsi_sess_state_in_flush(iscsi_sess_t *isp, iscsi_sess_event_t event,
1432*12161SJack.Meng@Sun.COM     uint32_t event_count)
14337836SJohn.Forte@Sun.COM {
14347836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
14357836SJohn.Forte@Sun.COM 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_IN_FLUSH);
14367836SJohn.Forte@Sun.COM 
14377836SJohn.Forte@Sun.COM 	/* switch on event change */
14387836SJohn.Forte@Sun.COM 	switch (event) {
14397836SJohn.Forte@Sun.COM 	/* -N1: A session continuation attempt succeeded */
14407836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N1:
14417836SJohn.Forte@Sun.COM 		/* NOOP - connections already online */
14427836SJohn.Forte@Sun.COM 		break;
14437836SJohn.Forte@Sun.COM 
14447836SJohn.Forte@Sun.COM 	/*
14457836SJohn.Forte@Sun.COM 	 * -N3: A connection logged out.
14467836SJohn.Forte@Sun.COM 	 */
14477836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N3:
14487836SJohn.Forte@Sun.COM 		/* FALLTHRU */
14497836SJohn.Forte@Sun.COM 
14507836SJohn.Forte@Sun.COM 	/*
14517836SJohn.Forte@Sun.COM 	 * -N5: A connection failed
14527836SJohn.Forte@Sun.COM 	 */
14537836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N5:
14547836SJohn.Forte@Sun.COM 		/*
14557836SJohn.Forte@Sun.COM 		 * MC/S: If this is the last connection to
14567836SJohn.Forte@Sun.COM 		 * fail then move the the failed state.
14577836SJohn.Forte@Sun.COM 		 */
14587836SJohn.Forte@Sun.COM 		if (event == ISCSI_SESS_EVENT_N3) {
14597836SJohn.Forte@Sun.COM 			isp->sess_state = ISCSI_SESS_STATE_FREE;
14607836SJohn.Forte@Sun.COM 		} else {
14617836SJohn.Forte@Sun.COM 			isp->sess_state = ISCSI_SESS_STATE_FLUSHED;
14627836SJohn.Forte@Sun.COM 		}
1463*12161SJack.Meng@Sun.COM 		rw_downgrade(&isp->sess_state_rwlock);
14647836SJohn.Forte@Sun.COM 
14657836SJohn.Forte@Sun.COM 		/* no longer connected reset nego tpgt */
14667836SJohn.Forte@Sun.COM 		isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT;
14677836SJohn.Forte@Sun.COM 		iscsi_sess_flush(isp);
14687836SJohn.Forte@Sun.COM 
14697836SJohn.Forte@Sun.COM 		if (event == ISCSI_SESS_EVENT_N3) {
14707836SJohn.Forte@Sun.COM 			if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
14717836SJohn.Forte@Sun.COM 				cmn_err(CE_NOTE,
14727836SJohn.Forte@Sun.COM 				    "!iscsi session(%u) %s offline\n",
14737836SJohn.Forte@Sun.COM 				    isp->sess_oid, isp->sess_name);
14747836SJohn.Forte@Sun.COM 			}
14758336SJack.Meng@Sun.COM 			/*
14768336SJack.Meng@Sun.COM 			 * During the process of offlining the LUNs
14778336SJack.Meng@Sun.COM 			 * our ic thread might be calling back into
14788336SJack.Meng@Sun.COM 			 * the driver via a target driver failure
14798336SJack.Meng@Sun.COM 			 * path to do a reset or something
14808336SJack.Meng@Sun.COM 			 * we need to release the sess_state_mutex
14818336SJack.Meng@Sun.COM 			 * while we are killing these threads so
14828336SJack.Meng@Sun.COM 			 * they don't get deadlocked.
14838336SJack.Meng@Sun.COM 			 */
14847836SJohn.Forte@Sun.COM 			iscsi_sess_offline_luns(isp);
14857836SJohn.Forte@Sun.COM 		}
14867836SJohn.Forte@Sun.COM 
14879780SBing.Zhao@Sun.COM 		mutex_enter(&isp->sess_reset_mutex);
14889780SBing.Zhao@Sun.COM 		isp->sess_reset_in_progress = B_FALSE;
14899780SBing.Zhao@Sun.COM 		mutex_exit(&isp->sess_reset_mutex);
14909780SBing.Zhao@Sun.COM 		/* update busy luns if needed */
14919780SBing.Zhao@Sun.COM 		iscsi_sess_update_busy_luns(isp, B_TRUE);
14929780SBing.Zhao@Sun.COM 
14937836SJohn.Forte@Sun.COM 		break;
14947836SJohn.Forte@Sun.COM 
14957836SJohn.Forte@Sun.COM 	/*
14967836SJohn.Forte@Sun.COM 	 * -N6: Session state timeout occurred, or a session
14977836SJohn.Forte@Sun.COM 	 *	reinstatement cleared this session instance.  This results in
14987836SJohn.Forte@Sun.COM 	 *	the freeing of all associated resources and the session state
14997836SJohn.Forte@Sun.COM 	 *	is discarded.
15007836SJohn.Forte@Sun.COM 	 */
15017836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N6:
15027836SJohn.Forte@Sun.COM 		/* NOOP - Not last connection */
15037836SJohn.Forte@Sun.COM 		break;
15047836SJohn.Forte@Sun.COM 
15057836SJohn.Forte@Sun.COM 	/*
15067836SJohn.Forte@Sun.COM 	 * -N7: Login parameters for session have changed.
15077836SJohn.Forte@Sun.COM 	 *	Re-negeotation required.
15087836SJohn.Forte@Sun.COM 	 */
15097836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N7:
15107836SJohn.Forte@Sun.COM 		/* NOOP - Already attempting to update */
15117836SJohn.Forte@Sun.COM 		break;
15127836SJohn.Forte@Sun.COM 
15137836SJohn.Forte@Sun.COM 	/* All other events are invalid for this state */
15147836SJohn.Forte@Sun.COM 	default:
15157836SJohn.Forte@Sun.COM 		ASSERT(FALSE);
15167836SJohn.Forte@Sun.COM 	}
15177836SJohn.Forte@Sun.COM }
15187836SJohn.Forte@Sun.COM 
15197836SJohn.Forte@Sun.COM 
15207836SJohn.Forte@Sun.COM /*
15217836SJohn.Forte@Sun.COM  * iscsi_sess_state_flushed -
15227836SJohn.Forte@Sun.COM  *
15237836SJohn.Forte@Sun.COM  */
15247836SJohn.Forte@Sun.COM static void
iscsi_sess_state_flushed(iscsi_sess_t * isp,iscsi_sess_event_t event,uint32_t event_count)1525*12161SJack.Meng@Sun.COM iscsi_sess_state_flushed(iscsi_sess_t *isp, iscsi_sess_event_t event,
1526*12161SJack.Meng@Sun.COM     uint32_t event_count)
15277836SJohn.Forte@Sun.COM {
15287836SJohn.Forte@Sun.COM 	iscsi_hba_t	*ihp;
1529*12161SJack.Meng@Sun.COM 	iscsi_enum_result_t	enum_result;
15307836SJohn.Forte@Sun.COM 
15317836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
15327836SJohn.Forte@Sun.COM 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FLUSHED);
15337836SJohn.Forte@Sun.COM 	ihp = isp->sess_hba;
15347836SJohn.Forte@Sun.COM 	ASSERT(ihp != NULL);
15357836SJohn.Forte@Sun.COM 
15367836SJohn.Forte@Sun.COM 	/* switch on event change */
15377836SJohn.Forte@Sun.COM 	switch (event) {
15387836SJohn.Forte@Sun.COM 	/* -N1: A session continuation attempt succeeded */
15397836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N1:
154011476SBing.Zhao@Sun.COM 		isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN;
1541*12161SJack.Meng@Sun.COM 		rw_downgrade(&isp->sess_state_rwlock);
1542*12161SJack.Meng@Sun.COM 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1543*12161SJack.Meng@Sun.COM 			enum_result =
1544*12161SJack.Meng@Sun.COM 			    iscsi_sess_enum_request(isp, B_TRUE,
1545*12161SJack.Meng@Sun.COM 			    event_count);
1546*12161SJack.Meng@Sun.COM 			if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
1547*12161SJack.Meng@Sun.COM 				enum_result =
1548*12161SJack.Meng@Sun.COM 				    iscsi_sess_enum_query(isp);
154911476SBing.Zhao@Sun.COM 			}
1550*12161SJack.Meng@Sun.COM 			if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
1551*12161SJack.Meng@Sun.COM 				iscsi_sess_enum_warn(isp, enum_result);
1552*12161SJack.Meng@Sun.COM 			}
15537836SJohn.Forte@Sun.COM 		}
15547836SJohn.Forte@Sun.COM 		break;
15557836SJohn.Forte@Sun.COM 
15567836SJohn.Forte@Sun.COM 	/*
15577836SJohn.Forte@Sun.COM 	 * -N6: Session state timeout occurred, or a session
15587836SJohn.Forte@Sun.COM 	 *	reinstatement cleared this session instance.  This results in
15597836SJohn.Forte@Sun.COM 	 *	the freeing of all associated resources and the session state
15607836SJohn.Forte@Sun.COM 	 *	is discarded.
15617836SJohn.Forte@Sun.COM 	 */
15627836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N6:
15637836SJohn.Forte@Sun.COM 		isp->sess_state = ISCSI_SESS_STATE_FREE;
1564*12161SJack.Meng@Sun.COM 		rw_downgrade(&isp->sess_state_rwlock);
15657836SJohn.Forte@Sun.COM 
15667836SJohn.Forte@Sun.COM 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
15677836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE, "!iscsi session(%u) %s offline\n",
15687836SJohn.Forte@Sun.COM 			    isp->sess_oid, isp->sess_name);
15697836SJohn.Forte@Sun.COM 		}
15707836SJohn.Forte@Sun.COM 
15717836SJohn.Forte@Sun.COM 		iscsi_sess_offline_luns(isp);
15727836SJohn.Forte@Sun.COM 		break;
15737836SJohn.Forte@Sun.COM 
15747836SJohn.Forte@Sun.COM 	/*
15757836SJohn.Forte@Sun.COM 	 * -N7: Login parameters for session have changed.
15767836SJohn.Forte@Sun.COM 	 *	Re-negeotation required.
15777836SJohn.Forte@Sun.COM 	 */
15787836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N7:
15797836SJohn.Forte@Sun.COM 		/* NOOP - not connected */
15807836SJohn.Forte@Sun.COM 		break;
15817836SJohn.Forte@Sun.COM 
15827836SJohn.Forte@Sun.COM 	/* All other events are invalid for this state */
15837836SJohn.Forte@Sun.COM 	default:
15847836SJohn.Forte@Sun.COM 		ASSERT(FALSE);
15857836SJohn.Forte@Sun.COM 	}
15867836SJohn.Forte@Sun.COM }
15877836SJohn.Forte@Sun.COM 
15887836SJohn.Forte@Sun.COM /*
15897836SJohn.Forte@Sun.COM  * iscsi_sess_event_str -
15907836SJohn.Forte@Sun.COM  *
15917836SJohn.Forte@Sun.COM  */
15927836SJohn.Forte@Sun.COM static char *
iscsi_sess_event_str(iscsi_sess_event_t event)15937836SJohn.Forte@Sun.COM iscsi_sess_event_str(iscsi_sess_event_t event)
15947836SJohn.Forte@Sun.COM {
15957836SJohn.Forte@Sun.COM 	switch (event) {
15967836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N1:
15977836SJohn.Forte@Sun.COM 		return ("N1");
15987836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N3:
15997836SJohn.Forte@Sun.COM 		return ("N3");
16007836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N5:
16017836SJohn.Forte@Sun.COM 		return ("N5");
16027836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N6:
16037836SJohn.Forte@Sun.COM 		return ("N6");
16047836SJohn.Forte@Sun.COM 	case ISCSI_SESS_EVENT_N7:
16057836SJohn.Forte@Sun.COM 		return ("N7");
16067836SJohn.Forte@Sun.COM 	default:
16077836SJohn.Forte@Sun.COM 		return ("unknown");
16087836SJohn.Forte@Sun.COM 	}
16097836SJohn.Forte@Sun.COM }
16107836SJohn.Forte@Sun.COM 
16117836SJohn.Forte@Sun.COM /*
16127836SJohn.Forte@Sun.COM  * iscsi_sess_thread_create -
16137836SJohn.Forte@Sun.COM  *
16147836SJohn.Forte@Sun.COM  */
16157836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_sess_threads_create(iscsi_sess_t * isp)16167836SJohn.Forte@Sun.COM iscsi_sess_threads_create(iscsi_sess_t *isp)
16177836SJohn.Forte@Sun.COM {
16187836SJohn.Forte@Sun.COM 	iscsi_hba_t	*ihp;
16197836SJohn.Forte@Sun.COM 	char		th_name[ISCSI_TH_MAX_NAME_LEN];
16207836SJohn.Forte@Sun.COM 
16217836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
16227836SJohn.Forte@Sun.COM 	ihp = isp->sess_hba;
16237836SJohn.Forte@Sun.COM 	ASSERT(ihp != NULL);
16247836SJohn.Forte@Sun.COM 
16257836SJohn.Forte@Sun.COM 	/* Completion thread creation. */
16267836SJohn.Forte@Sun.COM 	if (snprintf(th_name, sizeof (th_name) - 1,
16277836SJohn.Forte@Sun.COM 	    ISCSI_SESS_IOTH_NAME_FORMAT, ihp->hba_oid,
16287836SJohn.Forte@Sun.COM 	    isp->sess_oid) >= sizeof (th_name)) {
16297836SJohn.Forte@Sun.COM 		return (ISCSI_STATUS_INTERNAL_ERROR);
16307836SJohn.Forte@Sun.COM 	}
16317836SJohn.Forte@Sun.COM 
16327836SJohn.Forte@Sun.COM 	isp->sess_ic_thread = iscsi_thread_create(ihp->hba_dip,
16337836SJohn.Forte@Sun.COM 	    th_name, iscsi_ic_thread, isp);
16347836SJohn.Forte@Sun.COM 
16357836SJohn.Forte@Sun.COM 	if (isp->sess_ic_thread == NULL) {
16367836SJohn.Forte@Sun.COM 		return (ISCSI_STATUS_INTERNAL_ERROR);
16377836SJohn.Forte@Sun.COM 	}
16387836SJohn.Forte@Sun.COM 
16397836SJohn.Forte@Sun.COM 	(void) iscsi_thread_start(isp->sess_ic_thread);
16407836SJohn.Forte@Sun.COM 
16417836SJohn.Forte@Sun.COM 	return (ISCSI_STATUS_SUCCESS);
16427836SJohn.Forte@Sun.COM }
16437836SJohn.Forte@Sun.COM 
16447836SJohn.Forte@Sun.COM /*
16457836SJohn.Forte@Sun.COM  * iscsi_sess_enumeration - This function is used to drive the enumeration
16467836SJohn.Forte@Sun.COM  * of LUs on a session.  It will first prepare the target by sending test
16477836SJohn.Forte@Sun.COM  * unit ready commands, then it will issue a report luns.  If the report
16487836SJohn.Forte@Sun.COM  * luns is successful then it will process all the luns in the report.
16497836SJohn.Forte@Sun.COM  * If report luns is not successful we will do a stepping enumeration
16507836SJohn.Forte@Sun.COM  * of luns until no more luns are found.
16517836SJohn.Forte@Sun.COM  */
16527836SJohn.Forte@Sun.COM static void
iscsi_sess_enumeration(void * arg)16537836SJohn.Forte@Sun.COM iscsi_sess_enumeration(void *arg)
16547836SJohn.Forte@Sun.COM {
16557836SJohn.Forte@Sun.COM 	iscsi_task_t		*itp = (iscsi_task_t *)arg;
16567836SJohn.Forte@Sun.COM 	iscsi_sess_t		*isp;
16577836SJohn.Forte@Sun.COM 	iscsi_status_t		rval    = ISCSI_STATUS_SUCCESS;
1658*12161SJack.Meng@Sun.COM 	iscsi_enum_result_t	enum_result = ISCSI_SESS_ENUM_COMPLETE;
1659*12161SJack.Meng@Sun.COM 	uint32_t		event_count = itp->t_event_count;
16607836SJohn.Forte@Sun.COM 
16617836SJohn.Forte@Sun.COM 	ASSERT(itp != NULL);
16627836SJohn.Forte@Sun.COM 	isp = (iscsi_sess_t *)itp->t_arg;
16637836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
16647836SJohn.Forte@Sun.COM 
16657836SJohn.Forte@Sun.COM 	/*
16667836SJohn.Forte@Sun.COM 	 * Send initial TEST_UNIT_READY to target.  If it fails this we
16677836SJohn.Forte@Sun.COM 	 * stop our enumeration as the target is not responding properly.
16687836SJohn.Forte@Sun.COM 	 */
1669*12161SJack.Meng@Sun.COM 	rval = iscsi_sess_testunitready(isp, event_count);
16707836SJohn.Forte@Sun.COM 	if (ISCSI_SUCCESS(rval)) {
16717836SJohn.Forte@Sun.COM 		/*
16727836SJohn.Forte@Sun.COM 		 * Now we know the target is ready start our enumeration with
16737836SJohn.Forte@Sun.COM 		 * REPORT LUNs, If this fails we will have to fall back to
16747836SJohn.Forte@Sun.COM 		 * stepping
16757836SJohn.Forte@Sun.COM 		 */
1676*12161SJack.Meng@Sun.COM 		rval = iscsi_sess_reportluns(isp, event_count);
16777836SJohn.Forte@Sun.COM 		if (!ISCSI_SUCCESS(rval)) {
16787836SJohn.Forte@Sun.COM 			/*
16797836SJohn.Forte@Sun.COM 			 * report luns failed so lets just check for LUN 0.
16807836SJohn.Forte@Sun.COM 			 * This will match fcp's enumeration support and
16817836SJohn.Forte@Sun.COM 			 * avoid issues with older devices like the A5K that
16827836SJohn.Forte@Sun.COM 			 * respond poorly.
16837836SJohn.Forte@Sun.COM 			 */
16847836SJohn.Forte@Sun.COM 			if (isp->sess_lun_list == NULL) {
1685*12161SJack.Meng@Sun.COM 				iscsi_sess_inquiry(isp, 0, 0, event_count,
1686*12161SJack.Meng@Sun.COM 				    NULL);
16877836SJohn.Forte@Sun.COM 			}
16887836SJohn.Forte@Sun.COM 		}
16897836SJohn.Forte@Sun.COM 	} else {
1690*12161SJack.Meng@Sun.COM 		enum_result = ISCSI_SESS_ENUM_TUR_FAIL;
16917836SJohn.Forte@Sun.COM 	}
16927836SJohn.Forte@Sun.COM 
1693*12161SJack.Meng@Sun.COM 	kmem_free(itp, sizeof (iscsi_task_t));
1694*12161SJack.Meng@Sun.COM 	mutex_enter(&isp->sess_enum_lock);
1695*12161SJack.Meng@Sun.COM 	if (isp->sess_enum_result_count != 0) {
1696*12161SJack.Meng@Sun.COM 		isp->sess_enum_status = ISCSI_SESS_ENUM_DONE;
1697*12161SJack.Meng@Sun.COM 	} else {
1698*12161SJack.Meng@Sun.COM 		isp->sess_enum_status = ISCSI_SESS_ENUM_FREE;
16997836SJohn.Forte@Sun.COM 	}
1700*12161SJack.Meng@Sun.COM 	isp->sess_enum_result = enum_result;
1701*12161SJack.Meng@Sun.COM 	cv_broadcast(&isp->sess_enum_cv);
1702*12161SJack.Meng@Sun.COM 	mutex_exit(&isp->sess_enum_lock);
17037836SJohn.Forte@Sun.COM }
17047836SJohn.Forte@Sun.COM 
17057836SJohn.Forte@Sun.COM /*
17067836SJohn.Forte@Sun.COM  * iscsi_sess_testunitready - This is used during enumeration to
17077836SJohn.Forte@Sun.COM  * ensure an array is ready to be enumerated.
17087836SJohn.Forte@Sun.COM  */
17097836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_sess_testunitready(iscsi_sess_t * isp,uint32_t event_count)1710*12161SJack.Meng@Sun.COM iscsi_sess_testunitready(iscsi_sess_t *isp, uint32_t event_count)
17117836SJohn.Forte@Sun.COM {
17127836SJohn.Forte@Sun.COM 	iscsi_status_t			rval		= ISCSI_STATUS_SUCCESS;
17137836SJohn.Forte@Sun.COM 	int				retries		= 0;
17147836SJohn.Forte@Sun.COM 	struct uscsi_cmd		ucmd;
17157836SJohn.Forte@Sun.COM 	char				cdb[CDB_GROUP0];
17167836SJohn.Forte@Sun.COM 
17177836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
17187836SJohn.Forte@Sun.COM 
17197836SJohn.Forte@Sun.COM 	/* loop until successful sending test unit ready or retries out */
1720*12161SJack.Meng@Sun.COM 	while ((retries++ < 3) &&
1721*12161SJack.Meng@Sun.COM 	    (isp->sess_state_event_count == event_count)) {
17227836SJohn.Forte@Sun.COM 		/* cdb is all zeros */
17237836SJohn.Forte@Sun.COM 		bzero(&cdb[0], CDB_GROUP0);
17247836SJohn.Forte@Sun.COM 
17257836SJohn.Forte@Sun.COM 		/* setup uscsi cmd */
17267836SJohn.Forte@Sun.COM 		bzero(&ucmd, sizeof (struct uscsi_cmd));
17277836SJohn.Forte@Sun.COM 		ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
17287836SJohn.Forte@Sun.COM 		ucmd.uscsi_cdb		= &cdb[0];
17297836SJohn.Forte@Sun.COM 		ucmd.uscsi_cdblen	= CDB_GROUP0;
17307836SJohn.Forte@Sun.COM 
17317836SJohn.Forte@Sun.COM 		/* send test unit ready to lun zero on this session */
17327836SJohn.Forte@Sun.COM 		rval = iscsi_handle_passthru(isp, 0, &ucmd);
17337836SJohn.Forte@Sun.COM 
17347836SJohn.Forte@Sun.COM 		/*
17357836SJohn.Forte@Sun.COM 		 * If passthru was successful then we were able to
17367836SJohn.Forte@Sun.COM 		 * communicate with the target, continue enumeration.
17377836SJohn.Forte@Sun.COM 		 */
17387836SJohn.Forte@Sun.COM 		if (ISCSI_SUCCESS(rval)) {
17397836SJohn.Forte@Sun.COM 			break;
17407836SJohn.Forte@Sun.COM 		}
1741*12161SJack.Meng@Sun.COM 	}
17427836SJohn.Forte@Sun.COM 
17437836SJohn.Forte@Sun.COM 	return (rval);
17447836SJohn.Forte@Sun.COM }
17457836SJohn.Forte@Sun.COM 
17467836SJohn.Forte@Sun.COM #define	SCSI_REPORTLUNS_ADDRESS_SIZE			8
17477836SJohn.Forte@Sun.COM #define	SCSI_REPORTLUNS_ADDRESS_MASK			0xC0
17487836SJohn.Forte@Sun.COM #define	SCSI_REPORTLUNS_ADDRESS_PERIPHERAL		0x00
17497836SJohn.Forte@Sun.COM #define	SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE		0x40
17507836SJohn.Forte@Sun.COM #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT		0x80
17517836SJohn.Forte@Sun.COM #define	SCSI_REPORTLUNS_ADDRESS_EXTENDED_UNIT		0xC0
17527836SJohn.Forte@Sun.COM #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_2B		0x00
17537836SJohn.Forte@Sun.COM #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_4B		0x01
17547836SJohn.Forte@Sun.COM #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_6B		0x10
17557836SJohn.Forte@Sun.COM #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_8B		0x20
17567836SJohn.Forte@Sun.COM #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_SIZE	0x30
17577836SJohn.Forte@Sun.COM 
17587836SJohn.Forte@Sun.COM /*
17597836SJohn.Forte@Sun.COM  * iscsi_sess_reportluns - This is used during enumeration to
17607836SJohn.Forte@Sun.COM  * ensure an array is ready to be enumerated.
17617836SJohn.Forte@Sun.COM  */
17627836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_sess_reportluns(iscsi_sess_t * isp,uint32_t event_count)1763*12161SJack.Meng@Sun.COM iscsi_sess_reportluns(iscsi_sess_t *isp, uint32_t event_count)
17647836SJohn.Forte@Sun.COM {
17657836SJohn.Forte@Sun.COM 	iscsi_status_t		rval		= ISCSI_STATUS_SUCCESS;
17667836SJohn.Forte@Sun.COM 	iscsi_hba_t		*ihp;
17677836SJohn.Forte@Sun.COM 	struct uscsi_cmd	ucmd;
17687836SJohn.Forte@Sun.COM 	unsigned char		cdb[CDB_GROUP5];
17697836SJohn.Forte@Sun.COM 	unsigned char		*buf		= NULL;
17707836SJohn.Forte@Sun.COM 	int			buf_len		= sizeof (struct scsi_inquiry);
17717836SJohn.Forte@Sun.COM 	uint32_t		lun_list_length = 0;
17727836SJohn.Forte@Sun.COM 	uint16_t		lun_num		= 0;
17737836SJohn.Forte@Sun.COM 	uint8_t			lun_addr_type	= 0;
17747836SJohn.Forte@Sun.COM 	uint32_t		lun_count	= 0;
17757836SJohn.Forte@Sun.COM 	uint32_t		lun_start	= 0;
17767836SJohn.Forte@Sun.COM 	uint32_t		lun_total	= 0;
17777836SJohn.Forte@Sun.COM 	int			retries		= 0;
17788866Sandrew.rutz@sun.com 	iscsi_lun_t		*ilp_next;
17797836SJohn.Forte@Sun.COM 	iscsi_lun_t		*ilp		= NULL;
17807836SJohn.Forte@Sun.COM 	replun_data_t		*saved_replun_ptr = NULL;
17817836SJohn.Forte@Sun.COM 
17827836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
17837836SJohn.Forte@Sun.COM 	ihp = isp->sess_hba;
17847836SJohn.Forte@Sun.COM 	ASSERT(ihp != NULL);
17857836SJohn.Forte@Sun.COM 
17867836SJohn.Forte@Sun.COM 	/*
17877836SJohn.Forte@Sun.COM 	 * Attempt to send report luns until we successfully
17887836SJohn.Forte@Sun.COM 	 * get all the data or the retries run out.
17897836SJohn.Forte@Sun.COM 	 */
1790*12161SJack.Meng@Sun.COM 	while ((retries++ < 3) &&
1791*12161SJack.Meng@Sun.COM 	    (isp->sess_state_event_count == event_count)) {
17927836SJohn.Forte@Sun.COM 		/*
17937836SJohn.Forte@Sun.COM 		 * Allocate our buffer based on current buf_len.
17947836SJohn.Forte@Sun.COM 		 * buf_len may change after we received a response
17957836SJohn.Forte@Sun.COM 		 * from the target.
17967836SJohn.Forte@Sun.COM 		 */
17977836SJohn.Forte@Sun.COM 		if (buf == NULL) {
17987836SJohn.Forte@Sun.COM 			buf = kmem_zalloc(buf_len, KM_SLEEP);
17997836SJohn.Forte@Sun.COM 		}
18007836SJohn.Forte@Sun.COM 
18017836SJohn.Forte@Sun.COM 		/* setup cdb */
18027836SJohn.Forte@Sun.COM 		bzero(&cdb, CDB_GROUP5);
18037836SJohn.Forte@Sun.COM 		cdb[0] = SCMD_REPORT_LUNS;
18047836SJohn.Forte@Sun.COM 		cdb[6] = (buf_len & 0xff000000) >> 24;
18057836SJohn.Forte@Sun.COM 		cdb[7] = (buf_len & 0x00ff0000) >> 16;
18067836SJohn.Forte@Sun.COM 		cdb[8] = (buf_len & 0x0000ff00) >> 8;
18077836SJohn.Forte@Sun.COM 		cdb[9] = (buf_len & 0x000000ff);
18087836SJohn.Forte@Sun.COM 
18097836SJohn.Forte@Sun.COM 		/* setup uscsi cmd */
18107836SJohn.Forte@Sun.COM 		bzero(&ucmd, sizeof (struct uscsi_cmd));
18117836SJohn.Forte@Sun.COM 		ucmd.uscsi_flags	= USCSI_READ;
18127836SJohn.Forte@Sun.COM 		ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
18137836SJohn.Forte@Sun.COM 		ucmd.uscsi_cdb		= (char *)&cdb[0];
18147836SJohn.Forte@Sun.COM 		ucmd.uscsi_cdblen	= CDB_GROUP5;
18157836SJohn.Forte@Sun.COM 		ucmd.uscsi_bufaddr	= (char *)buf;
18167836SJohn.Forte@Sun.COM 		ucmd.uscsi_buflen	= buf_len;
18177836SJohn.Forte@Sun.COM 
18187836SJohn.Forte@Sun.COM 		/* send uscsi cmd to lun 0 on session */
18197836SJohn.Forte@Sun.COM 		rval = iscsi_handle_passthru(isp, 0, &ucmd);
18207836SJohn.Forte@Sun.COM 
18217836SJohn.Forte@Sun.COM 		/* If passthru successful but not scsi status update istatus */
18227836SJohn.Forte@Sun.COM 		if (ISCSI_SUCCESS(rval) &&
18237836SJohn.Forte@Sun.COM 		    (ucmd.uscsi_status != STATUS_GOOD)) {
18247836SJohn.Forte@Sun.COM 			rval = ISCSI_STATUS_USCSI_FAILED;
18257836SJohn.Forte@Sun.COM 		}
18267836SJohn.Forte@Sun.COM 
18277836SJohn.Forte@Sun.COM 		/* If successful, check if we have all the data */
18287836SJohn.Forte@Sun.COM 		if (ISCSI_SUCCESS(rval)) {
18297836SJohn.Forte@Sun.COM 			/* total data - header (SCSI_REPORTLUNS_ADDRESS_SIZE) */
18307836SJohn.Forte@Sun.COM 			lun_list_length	= htonl(*(uint32_t *)buf);
18317836SJohn.Forte@Sun.COM 
18327836SJohn.Forte@Sun.COM 			if (buf_len >= lun_list_length +
18337836SJohn.Forte@Sun.COM 			    SCSI_REPORTLUNS_ADDRESS_SIZE) {
18347836SJohn.Forte@Sun.COM 				/* we have all the data, were done */
18357836SJohn.Forte@Sun.COM 				break;
18367836SJohn.Forte@Sun.COM 			}
18377836SJohn.Forte@Sun.COM 
18387836SJohn.Forte@Sun.COM 			/*
18397836SJohn.Forte@Sun.COM 			 * We don't have all the data.  free up the
18407836SJohn.Forte@Sun.COM 			 * memory for the next pass and update the
18417836SJohn.Forte@Sun.COM 			 * buf_len
18427836SJohn.Forte@Sun.COM 			 */
18437836SJohn.Forte@Sun.COM 			kmem_free(buf, buf_len);
18447836SJohn.Forte@Sun.COM 			buf = NULL;
18457836SJohn.Forte@Sun.COM 			buf_len = lun_list_length +
18467836SJohn.Forte@Sun.COM 			    SCSI_REPORTLUNS_ADDRESS_SIZE;
18477836SJohn.Forte@Sun.COM 		} else {
18487836SJohn.Forte@Sun.COM 			retries++;
18497836SJohn.Forte@Sun.COM 		}
1850*12161SJack.Meng@Sun.COM 	}
18517836SJohn.Forte@Sun.COM 
1852*12161SJack.Meng@Sun.COM 	if (isp->sess_state_event_count != event_count) {
1853*12161SJack.Meng@Sun.COM 		if (buf != NULL) {
1854*12161SJack.Meng@Sun.COM 			kmem_free(buf, buf_len);
1855*12161SJack.Meng@Sun.COM 			buf = NULL;
1856*12161SJack.Meng@Sun.COM 		}
1857*12161SJack.Meng@Sun.COM 		return (rval);
1858*12161SJack.Meng@Sun.COM 	}
18597836SJohn.Forte@Sun.COM 
1860*12161SJack.Meng@Sun.COM 	/* If not successful go no further */
18617836SJohn.Forte@Sun.COM 	if (!ISCSI_SUCCESS(rval)) {
18627836SJohn.Forte@Sun.COM 		kmem_free(buf, buf_len);
18637836SJohn.Forte@Sun.COM 		return (rval);
18647836SJohn.Forte@Sun.COM 	}
18657836SJohn.Forte@Sun.COM 
18667836SJohn.Forte@Sun.COM 	/*
18677836SJohn.Forte@Sun.COM 	 * find out the number of luns returned by the SCSI ReportLun call
18687836SJohn.Forte@Sun.COM 	 * and allocate buffer space
18697836SJohn.Forte@Sun.COM 	 */
18707836SJohn.Forte@Sun.COM 	lun_total = lun_list_length / SCSI_REPORTLUNS_ADDRESS_SIZE;
18717836SJohn.Forte@Sun.COM 	saved_replun_ptr = kmem_zalloc(lun_total * sizeof (replun_data_t),
18727836SJohn.Forte@Sun.COM 	    KM_SLEEP);
18737836SJohn.Forte@Sun.COM 
18747836SJohn.Forte@Sun.COM 	/*
18757836SJohn.Forte@Sun.COM 	 * walk the isp->sess_lun_list
18767836SJohn.Forte@Sun.COM 	 * for each lun in this list
18777836SJohn.Forte@Sun.COM 	 *	look to see if this lun is in the SCSI ReportLun list we
18787836SJohn.Forte@Sun.COM 	 *	    just retrieved
1879*12161SJack.Meng@Sun.COM 	 *	if it is in the SCSI ReportLun list and it is already ONLINE or
1880*12161SJack.Meng@Sun.COM 	 *	if it is in the SCSI ReportLun list and it is OFFLINE or
1881*12161SJack.Meng@Sun.COM 	 *	if it isn't in the SCSI ReportLunlist or then
1882*12161SJack.Meng@Sun.COM 	 *	    issue the iscsi_sess_inquiry() to handle
18837836SJohn.Forte@Sun.COM 	 *
18847836SJohn.Forte@Sun.COM 	 *	as we walk the SCSI ReportLun list, we save this lun information
18857836SJohn.Forte@Sun.COM 	 *	    into the buffer we just allocated.  This will save us from
18867836SJohn.Forte@Sun.COM 	 *	    having to figure out this information later
18877836SJohn.Forte@Sun.COM 	 */
18887836SJohn.Forte@Sun.COM 	lun_start = 0;
18898500Sandrew.rutz@sun.com 	rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
18908866Sandrew.rutz@sun.com 	for (ilp = isp->sess_lun_list; ilp; ilp = ilp_next) {
1891*12161SJack.Meng@Sun.COM 		if (isp->sess_state_event_count != event_count)
1892*12161SJack.Meng@Sun.COM 			break;
1893*12161SJack.Meng@Sun.COM 
18948866Sandrew.rutz@sun.com 		ilp_next = ilp->lun_next;
18958866Sandrew.rutz@sun.com 
18969162SPeter.Dunlap@Sun.COM 		for (lun_count = lun_start; lun_count < lun_total;
18979162SPeter.Dunlap@Sun.COM 		    lun_count++) {
18989162SPeter.Dunlap@Sun.COM 			/*
18999162SPeter.Dunlap@Sun.COM 			 * if the first lun in saved_replun_ptr buffer has
19009162SPeter.Dunlap@Sun.COM 			 * already been found we can move on and do not
19019162SPeter.Dunlap@Sun.COM 			 * have to check this lun in the future
19029162SPeter.Dunlap@Sun.COM 			 */
19037836SJohn.Forte@Sun.COM 			if (lun_count == lun_start &&
19047836SJohn.Forte@Sun.COM 			    saved_replun_ptr[lun_start].lun_found) {
19057836SJohn.Forte@Sun.COM 				lun_start++;
19067836SJohn.Forte@Sun.COM 				continue;
19077836SJohn.Forte@Sun.COM 			}
19087836SJohn.Forte@Sun.COM 			/*
19097836SJohn.Forte@Sun.COM 			 * check to see if the lun we are looking for is in the
19107836SJohn.Forte@Sun.COM 			 * saved_replun_ptr buffer
19117836SJohn.Forte@Sun.COM 			 * if it is, process the lun
19127836SJohn.Forte@Sun.COM 			 * if it isn't, then we must go to SCSI
19137836SJohn.Forte@Sun.COM 			 * Report Lun buffer
19147836SJohn.Forte@Sun.COM 			 * we retrieved to get lun info
19157836SJohn.Forte@Sun.COM 			 */
1916*12161SJack.Meng@Sun.COM 			if ((saved_replun_ptr[lun_count].lun_valid
1917*12161SJack.Meng@Sun.COM 			    == B_TRUE) &&
1918*12161SJack.Meng@Sun.COM 			    (saved_replun_ptr[lun_count].lun_num
1919*12161SJack.Meng@Sun.COM 			    == ilp->lun_num)) {
19207836SJohn.Forte@Sun.COM 				/*
1921*12161SJack.Meng@Sun.COM 				 * the lun we are looking for is found,
1922*12161SJack.Meng@Sun.COM 				 * give it to iscsi_sess_inquiry()
19237836SJohn.Forte@Sun.COM 				 */
1924*12161SJack.Meng@Sun.COM 				rw_exit(&isp->sess_lun_list_rwlock);
1925*12161SJack.Meng@Sun.COM 				iscsi_sess_inquiry(isp, ilp->lun_num,
1926*12161SJack.Meng@Sun.COM 				    saved_replun_ptr[lun_count].lun_addr_type,
1927*12161SJack.Meng@Sun.COM 				    event_count, ilp);
1928*12161SJack.Meng@Sun.COM 				rw_enter(&isp->sess_lun_list_rwlock,
1929*12161SJack.Meng@Sun.COM 				    RW_WRITER);
1930*12161SJack.Meng@Sun.COM 				saved_replun_ptr[lun_count].lun_found
1931*12161SJack.Meng@Sun.COM 				    = B_TRUE;
19327836SJohn.Forte@Sun.COM 				break;
1933*12161SJack.Meng@Sun.COM 			} else {
19349162SPeter.Dunlap@Sun.COM 				/*
1935*12161SJack.Meng@Sun.COM 				 * lun information is not found in the
1936*12161SJack.Meng@Sun.COM 				 * saved_replun buffer, retrieve lun
1937*12161SJack.Meng@Sun.COM 				 * information from the SCSI Report Lun buffer
1938*12161SJack.Meng@Sun.COM 				 * and store this information in the
1939*12161SJack.Meng@Sun.COM 				 * saved_replun buffer
19409162SPeter.Dunlap@Sun.COM 				 */
1941*12161SJack.Meng@Sun.COM 				if (retrieve_lundata(lun_count, buf, isp,
1942*12161SJack.Meng@Sun.COM 				    &lun_num, &lun_addr_type) !=
1943*12161SJack.Meng@Sun.COM 				    ISCSI_STATUS_SUCCESS) {
1944*12161SJack.Meng@Sun.COM 					continue;
1945*12161SJack.Meng@Sun.COM 				}
1946*12161SJack.Meng@Sun.COM 				saved_replun_ptr[lun_count].lun_valid = B_TRUE;
1947*12161SJack.Meng@Sun.COM 				saved_replun_ptr[lun_count].lun_num = lun_num;
1948*12161SJack.Meng@Sun.COM 				saved_replun_ptr[lun_count].lun_addr_type =
1949*12161SJack.Meng@Sun.COM 				    lun_addr_type;
1950*12161SJack.Meng@Sun.COM 				if (ilp->lun_num == lun_num) {
1951*12161SJack.Meng@Sun.COM 					/*
1952*12161SJack.Meng@Sun.COM 					 * lun is found in the SCSI Report Lun
1953*12161SJack.Meng@Sun.COM 					 * buffer, give it to inquiry
1954*12161SJack.Meng@Sun.COM 					 */
1955*12161SJack.Meng@Sun.COM 					rw_exit(&isp->sess_lun_list_rwlock);
1956*12161SJack.Meng@Sun.COM 					iscsi_sess_inquiry(isp, lun_num,
1957*12161SJack.Meng@Sun.COM 					    lun_addr_type, event_count, ilp);
1958*12161SJack.Meng@Sun.COM 					rw_enter(&isp->sess_lun_list_rwlock,
1959*12161SJack.Meng@Sun.COM 					    RW_WRITER);
1960*12161SJack.Meng@Sun.COM 					saved_replun_ptr[lun_count].lun_found
1961*12161SJack.Meng@Sun.COM 					    = B_TRUE;
19627836SJohn.Forte@Sun.COM 					break;
19637836SJohn.Forte@Sun.COM 				}
19647836SJohn.Forte@Sun.COM 			}
19657836SJohn.Forte@Sun.COM 		}
19667836SJohn.Forte@Sun.COM 
19677836SJohn.Forte@Sun.COM 		if (lun_count == lun_total) {
19689162SPeter.Dunlap@Sun.COM 			/*
19699162SPeter.Dunlap@Sun.COM 			 * this lun we found in the sess->lun_list does
19709162SPeter.Dunlap@Sun.COM 			 * not exist anymore, need to offline this lun
19719162SPeter.Dunlap@Sun.COM 			 */
19727836SJohn.Forte@Sun.COM 
1973*12161SJack.Meng@Sun.COM 			DTRACE_PROBE2(
1974*12161SJack.Meng@Sun.COM 			    sess_reportluns_lun_no_longer_exists,
19757836SJohn.Forte@Sun.COM 			    int, ilp->lun_num, int, ilp->lun_state);
19767836SJohn.Forte@Sun.COM 
19778500Sandrew.rutz@sun.com 			(void) iscsi_lun_destroy(ihp, ilp);
19787836SJohn.Forte@Sun.COM 		}
19797836SJohn.Forte@Sun.COM 	}
19807836SJohn.Forte@Sun.COM 	rw_exit(&isp->sess_lun_list_rwlock);
19817836SJohn.Forte@Sun.COM 	/*
19827836SJohn.Forte@Sun.COM 	 * look for new luns that we found in the SCSI Report Lun buffer that
19837836SJohn.Forte@Sun.COM 	 * we did not have in the sess->lun_list and add them into the list
19847836SJohn.Forte@Sun.COM 	 */
19857836SJohn.Forte@Sun.COM 	for (lun_count = lun_start; lun_count < lun_total; lun_count++) {
19867836SJohn.Forte@Sun.COM 		if (saved_replun_ptr[lun_count].lun_valid == B_FALSE) {
19877836SJohn.Forte@Sun.COM 			/*
19887836SJohn.Forte@Sun.COM 			 * lun information is not in the
19897836SJohn.Forte@Sun.COM 			 * saved_replun buffer, retrieve
19907836SJohn.Forte@Sun.COM 			 * it from the SCSI Report Lun buffer
19917836SJohn.Forte@Sun.COM 			 */
19927836SJohn.Forte@Sun.COM 			if (retrieve_lundata(lun_count, buf, isp,
19937836SJohn.Forte@Sun.COM 			    &lun_num, &lun_addr_type) != ISCSI_STATUS_SUCCESS) {
19947836SJohn.Forte@Sun.COM 				continue;
19957836SJohn.Forte@Sun.COM 			}
19967836SJohn.Forte@Sun.COM 		} else {
19979162SPeter.Dunlap@Sun.COM 			/*
19989162SPeter.Dunlap@Sun.COM 			 * lun information is in the saved_replun buffer
19999162SPeter.Dunlap@Sun.COM 			 * if this lun has been found already,
20009162SPeter.Dunlap@Sun.COM 			 * then we can move on
20019162SPeter.Dunlap@Sun.COM 			 */
20027836SJohn.Forte@Sun.COM 			if (saved_replun_ptr[lun_count].lun_found == B_TRUE) {
20037836SJohn.Forte@Sun.COM 				continue;
20047836SJohn.Forte@Sun.COM 			}
20057836SJohn.Forte@Sun.COM 			lun_num = saved_replun_ptr[lun_count].lun_num;
2006*12161SJack.Meng@Sun.COM 			lun_addr_type =
2007*12161SJack.Meng@Sun.COM 			    saved_replun_ptr[lun_count].lun_addr_type;
20087836SJohn.Forte@Sun.COM 		}
20097836SJohn.Forte@Sun.COM 
20107836SJohn.Forte@Sun.COM 
20117836SJohn.Forte@Sun.COM 		/* New luns found should not conflict with existing luns */
20127836SJohn.Forte@Sun.COM 		rw_enter(&isp->sess_lun_list_rwlock, RW_READER);
20137836SJohn.Forte@Sun.COM 		for (ilp = isp->sess_lun_list; ilp; ilp = ilp->lun_next) {
20147836SJohn.Forte@Sun.COM 			if (ilp->lun_num == lun_num) {
20157836SJohn.Forte@Sun.COM 				break;
20167836SJohn.Forte@Sun.COM 			}
20177836SJohn.Forte@Sun.COM 		}
20187836SJohn.Forte@Sun.COM 		rw_exit(&isp->sess_lun_list_rwlock);
20197836SJohn.Forte@Sun.COM 
20207836SJohn.Forte@Sun.COM 		if (ilp == NULL) {
20217836SJohn.Forte@Sun.COM 			/* new lun found, add this lun */
2022*12161SJack.Meng@Sun.COM 			iscsi_sess_inquiry(isp, lun_num, lun_addr_type,
2023*12161SJack.Meng@Sun.COM 			    event_count, NULL);
20247836SJohn.Forte@Sun.COM 		} else {
20257836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE,
20267836SJohn.Forte@Sun.COM 			    "!Duplicate Lun Number(%d) recieved from "
20277836SJohn.Forte@Sun.COM 			    "Target(%s)", lun_num, isp->sess_name);
20287836SJohn.Forte@Sun.COM 		}
20297836SJohn.Forte@Sun.COM 	}
2030*12161SJack.Meng@Sun.COM 	if (buf != NULL) {
2031*12161SJack.Meng@Sun.COM 		kmem_free(buf, buf_len);
2032*12161SJack.Meng@Sun.COM 	}
2033*12161SJack.Meng@Sun.COM 	kmem_free(saved_replun_ptr, lun_total * sizeof (replun_data_t));
20347836SJohn.Forte@Sun.COM 
20357836SJohn.Forte@Sun.COM 	return (rval);
20367836SJohn.Forte@Sun.COM }
20377836SJohn.Forte@Sun.COM 
20387836SJohn.Forte@Sun.COM #define	ISCSI_MAX_INQUIRY_BUF_SIZE	0xFF
20397836SJohn.Forte@Sun.COM #define	ISCSI_MAX_INQUIRY_RETRIES	3
20407836SJohn.Forte@Sun.COM 
20417836SJohn.Forte@Sun.COM /*
20427836SJohn.Forte@Sun.COM  * iscsi_sess_inquiry - Final processing of a LUN before we create a tgt
2043*12161SJack.Meng@Sun.COM  * mapping, if necessary the old lun will be deleted.
2044*12161SJack.Meng@Sun.COM  *
2045*12161SJack.Meng@Sun.COM  * We need to collect the stardard inquiry page and the
20467836SJohn.Forte@Sun.COM  * vendor identification page for this LUN.  If both of these are
20477836SJohn.Forte@Sun.COM  * successful and the identification page contains a NAA or EUI type
20487836SJohn.Forte@Sun.COM  * we will continue.  Otherwise we fail the creation of a tgt for
20497836SJohn.Forte@Sun.COM  * this LUN.
20507836SJohn.Forte@Sun.COM  *
2051*12161SJack.Meng@Sun.COM  * Keep the old lun unchanged if it is online and following things are
2052*12161SJack.Meng@Sun.COM  * match, lun_addr_type, lun_type, and lun_guid.
2053*12161SJack.Meng@Sun.COM  *
2054*12161SJack.Meng@Sun.COM  * Online the old lun if it is offline/invalid and those three things
2055*12161SJack.Meng@Sun.COM  * are match.
2056*12161SJack.Meng@Sun.COM  *
2057*12161SJack.Meng@Sun.COM  * Online a new lun if the old lun is offline and any of those three things
2058*12161SJack.Meng@Sun.COM  * is not match, and needs to destroy the old first.
2059*12161SJack.Meng@Sun.COM  *
2060*12161SJack.Meng@Sun.COM  * Destroy the old lun and online the new lun if the old is online/invalid
2061*12161SJack.Meng@Sun.COM  * and any of those three things is not match, and then online the new lun
20627836SJohn.Forte@Sun.COM  */
20637836SJohn.Forte@Sun.COM 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)2064*12161SJack.Meng@Sun.COM iscsi_sess_inquiry(iscsi_sess_t *isp, uint16_t lun_num, uint8_t lun_addr_type,
2065*12161SJack.Meng@Sun.COM     uint32_t event_count, iscsi_lun_t *ilp)
20667836SJohn.Forte@Sun.COM {
20677836SJohn.Forte@Sun.COM 	iscsi_status_t		rval;
20687836SJohn.Forte@Sun.COM 	struct uscsi_cmd	ucmd;
20697836SJohn.Forte@Sun.COM 	uchar_t			cdb[CDB_GROUP0];
20707836SJohn.Forte@Sun.COM 	uchar_t			*inq;
20717836SJohn.Forte@Sun.COM 	size_t			inq_len;
20727836SJohn.Forte@Sun.COM 	uchar_t			*inq83;
20737836SJohn.Forte@Sun.COM 	size_t			inq83_len;
20747836SJohn.Forte@Sun.COM 	int			retries;
20757836SJohn.Forte@Sun.COM 	ddi_devid_t		devid;
20767836SJohn.Forte@Sun.COM 	char			*guid = NULL;
2077*12161SJack.Meng@Sun.COM 	iscsi_hba_t		*ihp;
2078*12161SJack.Meng@Sun.COM 	iscsi_status_t		status = ISCSI_STATUS_SUCCESS;
2079*12161SJack.Meng@Sun.COM 	boolean_t		inq_ready = B_FALSE;
2080*12161SJack.Meng@Sun.COM 	boolean_t		inq83_ready = B_FALSE;
2081*12161SJack.Meng@Sun.COM 	boolean_t		nochange = B_FALSE;
2082*12161SJack.Meng@Sun.COM 	uchar_t			lun_type;
20837836SJohn.Forte@Sun.COM 
20847836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
2085*12161SJack.Meng@Sun.COM 	ihp	= isp->sess_hba;
2086*12161SJack.Meng@Sun.COM 	ASSERT(ihp != NULL);
20877836SJohn.Forte@Sun.COM 
20887836SJohn.Forte@Sun.COM 	inq	= kmem_zalloc(ISCSI_MAX_INQUIRY_BUF_SIZE, KM_SLEEP);
20897836SJohn.Forte@Sun.COM 	inq83	= kmem_zalloc(ISCSI_MAX_INQUIRY_BUF_SIZE, KM_SLEEP);
20907836SJohn.Forte@Sun.COM 
2091*12161SJack.Meng@Sun.COM 	if (ilp == NULL) {
2092*12161SJack.Meng@Sun.COM 		/* easy case, just to create the new lun */
2093*12161SJack.Meng@Sun.COM 		goto sess_inq;
2094*12161SJack.Meng@Sun.COM 	}
2095*12161SJack.Meng@Sun.COM 
2096*12161SJack.Meng@Sun.COM 	if (ilp->lun_addr_type != lun_addr_type) {
2097*12161SJack.Meng@Sun.COM 		goto offline_old;
2098*12161SJack.Meng@Sun.COM 	}
2099*12161SJack.Meng@Sun.COM 
2100*12161SJack.Meng@Sun.COM 	goto sess_inq;
2101*12161SJack.Meng@Sun.COM 
2102*12161SJack.Meng@Sun.COM offline_old:
2103*12161SJack.Meng@Sun.COM 	if (isp->sess_state_event_count != event_count) {
2104*12161SJack.Meng@Sun.COM 		goto inq_done;
2105*12161SJack.Meng@Sun.COM 	}
2106*12161SJack.Meng@Sun.COM 
2107*12161SJack.Meng@Sun.COM 	status = iscsi_lun_destroy(ihp, ilp);
2108*12161SJack.Meng@Sun.COM 	if (status != ISCSI_STATUS_SUCCESS) {
2109*12161SJack.Meng@Sun.COM 		/* have to abort the process */
2110*12161SJack.Meng@Sun.COM 		cmn_err(CE_WARN, "iscsi session(%u) is unable to offline"
2111*12161SJack.Meng@Sun.COM 		    " obsolete logical unit %d", isp->sess_oid, lun_num);
2112*12161SJack.Meng@Sun.COM 		goto inq_done;
2113*12161SJack.Meng@Sun.COM 	}
2114*12161SJack.Meng@Sun.COM 	ilp = NULL;
2115*12161SJack.Meng@Sun.COM 
2116*12161SJack.Meng@Sun.COM sess_inq:
2117*12161SJack.Meng@Sun.COM 	if (inq_ready == B_TRUE) {
2118*12161SJack.Meng@Sun.COM 		goto sess_inq83;
2119*12161SJack.Meng@Sun.COM 	}
21207836SJohn.Forte@Sun.COM 	/*
21217836SJohn.Forte@Sun.COM 	 * STANDARD INQUIRY - We need the standard inquiry information
21227836SJohn.Forte@Sun.COM 	 * to feed into the scsi_hba_nodename_compatible_get function.
21237836SJohn.Forte@Sun.COM 	 * This function is used to detemine which driver will bind
21247836SJohn.Forte@Sun.COM 	 * on top of us, via the compatible id.
21257836SJohn.Forte@Sun.COM 	 */
21267836SJohn.Forte@Sun.COM 	bzero(&cdb, CDB_GROUP0);
21277836SJohn.Forte@Sun.COM 	cdb[0] = SCMD_INQUIRY;
21287836SJohn.Forte@Sun.COM 	cdb[4] = ISCSI_MAX_INQUIRY_BUF_SIZE;
21297836SJohn.Forte@Sun.COM 
21307836SJohn.Forte@Sun.COM 	bzero(&ucmd, sizeof (struct uscsi_cmd));
21317836SJohn.Forte@Sun.COM 	ucmd.uscsi_flags	= USCSI_READ;
21327836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
21337836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb		= (char *)&cdb[0];
21347836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen	= CDB_GROUP0;
21357836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr	= (char *)inq;
21367836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen	= ISCSI_MAX_INQUIRY_BUF_SIZE;
21377836SJohn.Forte@Sun.COM 
21387836SJohn.Forte@Sun.COM 	/* Attempt to get inquiry information until successful or retries */
21397836SJohn.Forte@Sun.COM 	retries = 0;
2140*12161SJack.Meng@Sun.COM 	while ((retries++ < ISCSI_MAX_INQUIRY_RETRIES) &&
2141*12161SJack.Meng@Sun.COM 	    (isp->sess_state_event_count == event_count)) {
21427836SJohn.Forte@Sun.COM 		/* issue passthru */
21437836SJohn.Forte@Sun.COM 		rval = iscsi_handle_passthru(isp, lun_num, &ucmd);
21447836SJohn.Forte@Sun.COM 
21457836SJohn.Forte@Sun.COM 		/* If we were successful but scsi stat failed update istatus */
21467836SJohn.Forte@Sun.COM 		if (ISCSI_SUCCESS(rval) &&
21477836SJohn.Forte@Sun.COM 		    (ucmd.uscsi_status != STATUS_GOOD)) {
21487836SJohn.Forte@Sun.COM 			rval = ISCSI_STATUS_USCSI_FAILED;
21497836SJohn.Forte@Sun.COM 		}
21507836SJohn.Forte@Sun.COM 
21517836SJohn.Forte@Sun.COM 		/* If successful break */
21527836SJohn.Forte@Sun.COM 		if (ISCSI_SUCCESS(rval)) {
21537836SJohn.Forte@Sun.COM 			inq_len = ISCSI_MAX_INQUIRY_BUF_SIZE - ucmd.uscsi_resid;
21547836SJohn.Forte@Sun.COM 			break;
21557836SJohn.Forte@Sun.COM 		}
21567836SJohn.Forte@Sun.COM 
21577836SJohn.Forte@Sun.COM 		/* loop until we are successful or retries run out */
2158*12161SJack.Meng@Sun.COM 	}
21597836SJohn.Forte@Sun.COM 
21607836SJohn.Forte@Sun.COM 	/* If failed don't continue */
21617836SJohn.Forte@Sun.COM 	if (!ISCSI_SUCCESS(rval)) {
21627836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "iscsi session(%u) unable to enumerate "
21637836SJohn.Forte@Sun.COM 		    "logical unit - inquiry failed lun %d",
21647836SJohn.Forte@Sun.COM 		    isp->sess_oid, lun_num);
21657836SJohn.Forte@Sun.COM 
21667836SJohn.Forte@Sun.COM 		goto inq_done;
21677836SJohn.Forte@Sun.COM 	}
2168*12161SJack.Meng@Sun.COM 	inq_ready = B_TRUE;
21697836SJohn.Forte@Sun.COM 
2170*12161SJack.Meng@Sun.COM sess_inq83:
21717836SJohn.Forte@Sun.COM 	/*
21727836SJohn.Forte@Sun.COM 	 * T-10 SPC Section 6.4.2.  Standard INQUIRY Peripheral
21737836SJohn.Forte@Sun.COM 	 * qualifier of 000b is the only type we should attempt
21747836SJohn.Forte@Sun.COM 	 * to plumb under the IO stack.
21757836SJohn.Forte@Sun.COM 	 */
21767836SJohn.Forte@Sun.COM 	if ((inq[0] & SCSI_INQUIRY_PQUAL_MASK) != 0x00) {
2177*12161SJack.Meng@Sun.COM 		/* shouldn't enumerate, destroy the old one if exists */
2178*12161SJack.Meng@Sun.COM 		if (ilp != NULL) {
2179*12161SJack.Meng@Sun.COM 			goto offline_old;
2180*12161SJack.Meng@Sun.COM 		}
21817836SJohn.Forte@Sun.COM 		goto inq_done;
21827836SJohn.Forte@Sun.COM 	}
21837836SJohn.Forte@Sun.COM 
21847836SJohn.Forte@Sun.COM 	/*
2185*12161SJack.Meng@Sun.COM 	 * If lun type has changed
2186*12161SJack.Meng@Sun.COM 	 */
2187*12161SJack.Meng@Sun.COM 	lun_type = ((struct scsi_inquiry *)inq)->inq_dtype & DTYPE_MASK;
2188*12161SJack.Meng@Sun.COM 	if ((ilp != NULL) && (ilp->lun_type != lun_type)) {
2189*12161SJack.Meng@Sun.COM 		goto offline_old;
2190*12161SJack.Meng@Sun.COM 	}
2191*12161SJack.Meng@Sun.COM 
2192*12161SJack.Meng@Sun.COM 	if (inq83_ready == B_TRUE) {
2193*12161SJack.Meng@Sun.COM 		goto guid_ready;
2194*12161SJack.Meng@Sun.COM 	}
2195*12161SJack.Meng@Sun.COM 
2196*12161SJack.Meng@Sun.COM 	/*
21977836SJohn.Forte@Sun.COM 	 * VENDOR IDENTIFICATION INQUIRY - This will be used to identify
21987836SJohn.Forte@Sun.COM 	 * a unique lunId.  This Id is passed to the mdi alloc calls so
21997836SJohn.Forte@Sun.COM 	 * we can properly plumb into scsi_vhci/mpxio.
22007836SJohn.Forte@Sun.COM 	 */
22017836SJohn.Forte@Sun.COM 
22027836SJohn.Forte@Sun.COM 	bzero(&cdb, CDB_GROUP0);
22037836SJohn.Forte@Sun.COM 	cdb[0] = SCMD_INQUIRY;
22047836SJohn.Forte@Sun.COM 	cdb[1] = 0x01; /* EVP bit */
22057836SJohn.Forte@Sun.COM 	cdb[2] = 0x83;
22067836SJohn.Forte@Sun.COM 	cdb[4] = ISCSI_MAX_INQUIRY_BUF_SIZE;
22077836SJohn.Forte@Sun.COM 
22087836SJohn.Forte@Sun.COM 	ucmd.uscsi_flags	= USCSI_READ;
22097836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
22107836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb		= (char *)&cdb[0];
22117836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen	= CDB_GROUP0;
22127836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr	= (char *)inq83;
22137836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen	= ISCSI_MAX_INQUIRY_BUF_SIZE;
22147836SJohn.Forte@Sun.COM 
22157836SJohn.Forte@Sun.COM 	/* Attempt to get inquiry information until successful or retries */
22167836SJohn.Forte@Sun.COM 	retries = 0;
2217*12161SJack.Meng@Sun.COM 	while ((retries++ < ISCSI_MAX_INQUIRY_RETRIES) &&
2218*12161SJack.Meng@Sun.COM 	    (isp->sess_state_event_count == event_count)) {
22197836SJohn.Forte@Sun.COM 		/* issue passthru command */
22207836SJohn.Forte@Sun.COM 		rval = iscsi_handle_passthru(isp, lun_num, &ucmd);
22217836SJohn.Forte@Sun.COM 
22227836SJohn.Forte@Sun.COM 		/* If we were successful but scsi stat failed update istatus */
22237836SJohn.Forte@Sun.COM 		if (ISCSI_SUCCESS(rval) &&
22247836SJohn.Forte@Sun.COM 		    (ucmd.uscsi_status != STATUS_GOOD)) {
22257836SJohn.Forte@Sun.COM 			rval = ISCSI_STATUS_USCSI_FAILED;
22267836SJohn.Forte@Sun.COM 		}
22277836SJohn.Forte@Sun.COM 
22287836SJohn.Forte@Sun.COM 		/* Break if successful */
22297836SJohn.Forte@Sun.COM 		if (ISCSI_SUCCESS(rval)) {
22307836SJohn.Forte@Sun.COM 			inq83_len = ISCSI_MAX_INQUIRY_BUF_SIZE -
22317836SJohn.Forte@Sun.COM 			    ucmd.uscsi_resid;
22327836SJohn.Forte@Sun.COM 			break;
22337836SJohn.Forte@Sun.COM 		}
2234*12161SJack.Meng@Sun.COM 	}
22357836SJohn.Forte@Sun.COM 
22367836SJohn.Forte@Sun.COM 	/*
22377836SJohn.Forte@Sun.COM 	 * If we were successful collecting page 83 data attempt
22387836SJohn.Forte@Sun.COM 	 * to generate a GUID.  If no GUID can be generated then
22397836SJohn.Forte@Sun.COM 	 * the logical unit will skip attempt to plumb under
22407836SJohn.Forte@Sun.COM 	 * scsi_vhci/mpxio.
22417836SJohn.Forte@Sun.COM 	 */
22427836SJohn.Forte@Sun.COM 	if (ISCSI_SUCCESS(rval)) {
22437836SJohn.Forte@Sun.COM 		/* create DEVID from inquiry data */
22447836SJohn.Forte@Sun.COM 		if (ddi_devid_scsi_encode(
22457836SJohn.Forte@Sun.COM 		    DEVID_SCSI_ENCODE_VERSION_LATEST, NULL,
22467836SJohn.Forte@Sun.COM 		    inq, inq_len, NULL, 0, inq83, inq83_len, &devid) ==
22477836SJohn.Forte@Sun.COM 		    DDI_SUCCESS) {
22487836SJohn.Forte@Sun.COM 
22497836SJohn.Forte@Sun.COM 			/* extract GUID from DEVID */
22507836SJohn.Forte@Sun.COM 			guid = ddi_devid_to_guid(devid);
22517836SJohn.Forte@Sun.COM 
22527836SJohn.Forte@Sun.COM 			/* devid no longer needed */
22537836SJohn.Forte@Sun.COM 			ddi_devid_free(devid);
22547836SJohn.Forte@Sun.COM 		}
22557836SJohn.Forte@Sun.COM 	}
2256*12161SJack.Meng@Sun.COM 	inq83_ready = B_TRUE;
22577836SJohn.Forte@Sun.COM 
2258*12161SJack.Meng@Sun.COM guid_ready:
2259*12161SJack.Meng@Sun.COM 
2260*12161SJack.Meng@Sun.COM 	if (ilp != NULL) {
2261*12161SJack.Meng@Sun.COM 		if ((guid == NULL) && (ilp->lun_guid == NULL)) {
2262*12161SJack.Meng@Sun.COM 			nochange = B_TRUE;
2263*12161SJack.Meng@Sun.COM 		}
2264*12161SJack.Meng@Sun.COM 
2265*12161SJack.Meng@Sun.COM 		if ((guid != NULL) && (ilp->lun_guid != NULL) &&
2266*12161SJack.Meng@Sun.COM 		    ((strlen(guid) + 1) == ilp->lun_guid_size) &&
2267*12161SJack.Meng@Sun.COM 		    (bcmp(guid, ilp->lun_guid, ilp->lun_guid_size) == 0)) {
2268*12161SJack.Meng@Sun.COM 			nochange = B_TRUE;
2269*12161SJack.Meng@Sun.COM 		}
2270*12161SJack.Meng@Sun.COM 
2271*12161SJack.Meng@Sun.COM 		if (nochange != B_TRUE) {
2272*12161SJack.Meng@Sun.COM 			goto offline_old;
2273*12161SJack.Meng@Sun.COM 		}
22747836SJohn.Forte@Sun.COM 
2275*12161SJack.Meng@Sun.COM 		if (ilp->lun_state & (ISCSI_LUN_STATE_OFFLINE |
2276*12161SJack.Meng@Sun.COM 		    ISCSI_LUN_STATE_INVALID)) {
2277*12161SJack.Meng@Sun.COM 			if (isp->sess_state_event_count == event_count) {
2278*12161SJack.Meng@Sun.COM 				(void) iscsi_lun_online(ihp, ilp);
2279*12161SJack.Meng@Sun.COM 			}
2280*12161SJack.Meng@Sun.COM 		}
2281*12161SJack.Meng@Sun.COM 	} else {
2282*12161SJack.Meng@Sun.COM 		if (isp->sess_state_event_count == event_count) {
2283*12161SJack.Meng@Sun.COM 			(void) iscsi_lun_create(isp, lun_num, lun_addr_type,
2284*12161SJack.Meng@Sun.COM 			    (struct scsi_inquiry *)inq, guid);
2285*12161SJack.Meng@Sun.COM 		}
2286*12161SJack.Meng@Sun.COM 	}
2287*12161SJack.Meng@Sun.COM 
2288*12161SJack.Meng@Sun.COM inq_done:
22897836SJohn.Forte@Sun.COM 	if (guid != NULL) {
2290*12161SJack.Meng@Sun.COM 		/* guid is no longer needed */
22917836SJohn.Forte@Sun.COM 		ddi_devid_free_guid(guid);
22927836SJohn.Forte@Sun.COM 	}
22937836SJohn.Forte@Sun.COM 
22947836SJohn.Forte@Sun.COM 	/* free up memory now that we are done */
22957836SJohn.Forte@Sun.COM 	kmem_free(inq, ISCSI_MAX_INQUIRY_BUF_SIZE);
22967836SJohn.Forte@Sun.COM 	kmem_free(inq83, ISCSI_MAX_INQUIRY_BUF_SIZE);
22977836SJohn.Forte@Sun.COM }
22987836SJohn.Forte@Sun.COM 
22997836SJohn.Forte@Sun.COM 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)23007836SJohn.Forte@Sun.COM retrieve_lundata(uint32_t lun_count, unsigned char *buf, iscsi_sess_t *isp,
23017836SJohn.Forte@Sun.COM     uint16_t *lun_num, uint8_t *lun_addr_type)
23027836SJohn.Forte@Sun.COM {
23037836SJohn.Forte@Sun.COM 	uint32_t		lun_idx		= 0;
23047836SJohn.Forte@Sun.COM 
23057836SJohn.Forte@Sun.COM 	ASSERT(lun_num != NULL);
23067836SJohn.Forte@Sun.COM 	ASSERT(lun_addr_type != NULL);
23077836SJohn.Forte@Sun.COM 
23087836SJohn.Forte@Sun.COM 	lun_idx = (lun_count + 1) * SCSI_REPORTLUNS_ADDRESS_SIZE;
23097836SJohn.Forte@Sun.COM 	/* determine report luns addressing type */
23107836SJohn.Forte@Sun.COM 	switch (buf[lun_idx] & SCSI_REPORTLUNS_ADDRESS_MASK) {
23117836SJohn.Forte@Sun.COM 		/*
23127836SJohn.Forte@Sun.COM 		 * Vendors in the field have been found to be concatenating
23137836SJohn.Forte@Sun.COM 		 * bus/target/lun to equal the complete lun value instead
23147836SJohn.Forte@Sun.COM 		 * of switching to flat space addressing
23157836SJohn.Forte@Sun.COM 		 */
23167836SJohn.Forte@Sun.COM 		/* 00b - peripheral device addressing method */
23177836SJohn.Forte@Sun.COM 		case SCSI_REPORTLUNS_ADDRESS_PERIPHERAL:
23187836SJohn.Forte@Sun.COM 			/* FALLTHRU */
23197836SJohn.Forte@Sun.COM 		/* 10b - logical unit addressing method */
23207836SJohn.Forte@Sun.COM 		case SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT:
23217836SJohn.Forte@Sun.COM 			/* FALLTHRU */
23227836SJohn.Forte@Sun.COM 		/* 01b - flat space addressing method */
23237836SJohn.Forte@Sun.COM 		case SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE:
23247836SJohn.Forte@Sun.COM 			/* byte0 bit0-5=msb lun byte1 bit0-7=lsb lun */
23257836SJohn.Forte@Sun.COM 			*lun_addr_type = (buf[lun_idx] &
23267836SJohn.Forte@Sun.COM 			    SCSI_REPORTLUNS_ADDRESS_MASK) >> 6;
23277836SJohn.Forte@Sun.COM 			*lun_num = (buf[lun_idx] & 0x3F) << 8;
23287836SJohn.Forte@Sun.COM 			*lun_num |= buf[lun_idx + 1];
23297836SJohn.Forte@Sun.COM 			return (ISCSI_STATUS_SUCCESS);
23307836SJohn.Forte@Sun.COM 		default: /* protocol error */
23317836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE, "iscsi session(%u) unable "
23327836SJohn.Forte@Sun.COM 			    "to enumerate logical units - report "
23337836SJohn.Forte@Sun.COM 			    "luns returned an unsupported format",
23347836SJohn.Forte@Sun.COM 			    isp->sess_oid);
23357836SJohn.Forte@Sun.COM 			break;
23367836SJohn.Forte@Sun.COM 	}
23377836SJohn.Forte@Sun.COM 	return (ISCSI_STATUS_INTERNAL_ERROR);
23387836SJohn.Forte@Sun.COM }
23397836SJohn.Forte@Sun.COM 
23407836SJohn.Forte@Sun.COM /*
23417836SJohn.Forte@Sun.COM  * iscsi_sess_flush - flushes remaining pending io on the session
23427836SJohn.Forte@Sun.COM  */
23437836SJohn.Forte@Sun.COM static void
iscsi_sess_flush(iscsi_sess_t * isp)23447836SJohn.Forte@Sun.COM iscsi_sess_flush(iscsi_sess_t *isp)
23457836SJohn.Forte@Sun.COM {
23467836SJohn.Forte@Sun.COM 	iscsi_cmd_t	*icmdp;
23477836SJohn.Forte@Sun.COM 
23487836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
23497836SJohn.Forte@Sun.COM 	ASSERT(isp->sess_state != ISCSI_SESS_STATE_LOGGED_IN);
23507836SJohn.Forte@Sun.COM 
23517836SJohn.Forte@Sun.COM 	/*
23527836SJohn.Forte@Sun.COM 	 * Flush out any remaining commands in the pending
23537836SJohn.Forte@Sun.COM 	 * queue.
23547836SJohn.Forte@Sun.COM 	 */
23557836SJohn.Forte@Sun.COM 	mutex_enter(&isp->sess_queue_pending.mutex);
23567836SJohn.Forte@Sun.COM 	icmdp = isp->sess_queue_pending.head;
23577836SJohn.Forte@Sun.COM 	while (icmdp != NULL) {
23589780SBing.Zhao@Sun.COM 		if (isp->sess_state == ISCSI_SESS_STATE_FAILED) {
23599780SBing.Zhao@Sun.COM 			mutex_enter(&icmdp->cmd_mutex);
23609780SBing.Zhao@Sun.COM 			if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
23619780SBing.Zhao@Sun.COM 				icmdp->cmd_un.scsi.pkt_stat |= STAT_ABORTED;
23629780SBing.Zhao@Sun.COM 			}
23639780SBing.Zhao@Sun.COM 			mutex_exit(&icmdp->cmd_mutex);
23649780SBing.Zhao@Sun.COM 		}
23659780SBing.Zhao@Sun.COM 
23667836SJohn.Forte@Sun.COM 		iscsi_cmd_state_machine(icmdp,
23677836SJohn.Forte@Sun.COM 		    ISCSI_CMD_EVENT_E7, isp);
23687836SJohn.Forte@Sun.COM 		icmdp = isp->sess_queue_pending.head;
23697836SJohn.Forte@Sun.COM 	}
23707836SJohn.Forte@Sun.COM 	mutex_exit(&isp->sess_queue_pending.mutex);
23717836SJohn.Forte@Sun.COM }
23727836SJohn.Forte@Sun.COM 
23737836SJohn.Forte@Sun.COM /*
23747836SJohn.Forte@Sun.COM  * iscsi_sess_offline_luns - offline all this sessions luns
23757836SJohn.Forte@Sun.COM  */
23767836SJohn.Forte@Sun.COM static void
iscsi_sess_offline_luns(iscsi_sess_t * isp)23777836SJohn.Forte@Sun.COM iscsi_sess_offline_luns(iscsi_sess_t *isp)
23787836SJohn.Forte@Sun.COM {
23797836SJohn.Forte@Sun.COM 	iscsi_lun_t	*ilp;
23807836SJohn.Forte@Sun.COM 	iscsi_hba_t	*ihp;
23817836SJohn.Forte@Sun.COM 
23827836SJohn.Forte@Sun.COM 	ASSERT(isp != NULL);
23837836SJohn.Forte@Sun.COM 	ASSERT(isp->sess_state != ISCSI_SESS_STATE_LOGGED_IN);
23847836SJohn.Forte@Sun.COM 	ihp = isp->sess_hba;
23857836SJohn.Forte@Sun.COM 	ASSERT(ihp != NULL);
23867836SJohn.Forte@Sun.COM 
23877836SJohn.Forte@Sun.COM 	rw_enter(&isp->sess_lun_list_rwlock, RW_READER);
23887836SJohn.Forte@Sun.COM 	ilp = isp->sess_lun_list;
23897836SJohn.Forte@Sun.COM 	while (ilp != NULL) {
23907836SJohn.Forte@Sun.COM 		(void) iscsi_lun_offline(ihp, ilp, B_FALSE);
23917836SJohn.Forte@Sun.COM 		ilp = ilp->lun_next;
23927836SJohn.Forte@Sun.COM 	}
23937836SJohn.Forte@Sun.COM 	rw_exit(&isp->sess_lun_list_rwlock);
23947836SJohn.Forte@Sun.COM }
23957836SJohn.Forte@Sun.COM 
23967836SJohn.Forte@Sun.COM /*
23977836SJohn.Forte@Sun.COM  * iscsi_sess_get_by_target - return the session structure for based on a
23987836SJohn.Forte@Sun.COM  * passed in target oid and hba instance.  NOTE:  There may be
23997836SJohn.Forte@Sun.COM  * multiple sessions associated with any given target.  In this case,
24007836SJohn.Forte@Sun.COM  * we will return the first matching session.  This function
24017836SJohn.Forte@Sun.COM  * is intended to be used in retrieving target info that is constant
24027836SJohn.Forte@Sun.COM  * across sessions (target name, alias, etc.).
24037836SJohn.Forte@Sun.COM  */
24047836SJohn.Forte@Sun.COM int
iscsi_sess_get_by_target(uint32_t target_oid,iscsi_hba_t * ihp,iscsi_sess_t ** ispp)24057836SJohn.Forte@Sun.COM iscsi_sess_get_by_target(uint32_t target_oid, iscsi_hba_t *ihp,
24067836SJohn.Forte@Sun.COM     iscsi_sess_t **ispp)
24077836SJohn.Forte@Sun.COM {
24087836SJohn.Forte@Sun.COM 	int rval = 0;
24097836SJohn.Forte@Sun.COM 	iscsi_sess_t *isp = NULL;
24107836SJohn.Forte@Sun.COM 
24117836SJohn.Forte@Sun.COM 	ASSERT(ihp != NULL);
24127836SJohn.Forte@Sun.COM 	ASSERT(ispp != NULL);
24137836SJohn.Forte@Sun.COM 
24147836SJohn.Forte@Sun.COM 	/* See if we already created this session */
24157836SJohn.Forte@Sun.COM 	for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
24167836SJohn.Forte@Sun.COM 		/*
24177836SJohn.Forte@Sun.COM 		 * Look for a session associated to the given target.
24187836SJohn.Forte@Sun.COM 		 * Return the first one found.
24197836SJohn.Forte@Sun.COM 		 */
24207836SJohn.Forte@Sun.COM 		if (isp->sess_target_oid == target_oid) {
24217836SJohn.Forte@Sun.COM 			/* Found matching session */
24227836SJohn.Forte@Sun.COM 			break;
24237836SJohn.Forte@Sun.COM 		}
24247836SJohn.Forte@Sun.COM 	}
24257836SJohn.Forte@Sun.COM 
24267836SJohn.Forte@Sun.COM 	/* If not null this session is already available */
24277836SJohn.Forte@Sun.COM 	if (isp != NULL) {
24287836SJohn.Forte@Sun.COM 		/* Existing session, return it */
24297836SJohn.Forte@Sun.COM 		*ispp = isp;
24307836SJohn.Forte@Sun.COM 	} else {
24317836SJohn.Forte@Sun.COM 		rval = EFAULT;
24327836SJohn.Forte@Sun.COM 	}
24337836SJohn.Forte@Sun.COM 	return (rval);
24347836SJohn.Forte@Sun.COM }
24359780SBing.Zhao@Sun.COM 
24369780SBing.Zhao@Sun.COM static void
iscsi_sess_update_busy_luns(iscsi_sess_t * isp,boolean_t clear)24379780SBing.Zhao@Sun.COM iscsi_sess_update_busy_luns(iscsi_sess_t *isp, boolean_t clear)
24389780SBing.Zhao@Sun.COM {
24399780SBing.Zhao@Sun.COM 	iscsi_lun_t	*ilp;
24409780SBing.Zhao@Sun.COM 	iscsi_hba_t	*ihp;
24419780SBing.Zhao@Sun.COM 
24429780SBing.Zhao@Sun.COM 	ASSERT(isp != NULL);
24439780SBing.Zhao@Sun.COM 	ihp = isp->sess_hba;
24449780SBing.Zhao@Sun.COM 	ASSERT(ihp != NULL);
24459780SBing.Zhao@Sun.COM 
24469780SBing.Zhao@Sun.COM 	rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
24479780SBing.Zhao@Sun.COM 	ilp = isp->sess_lun_list;
24489780SBing.Zhao@Sun.COM 	while (ilp != NULL) {
24499780SBing.Zhao@Sun.COM 		if (clear == B_TRUE) {
24509780SBing.Zhao@Sun.COM 			ilp->lun_state &= ~ISCSI_LUN_STATE_BUSY;
24519780SBing.Zhao@Sun.COM 		} else {
24529780SBing.Zhao@Sun.COM 			ilp->lun_state |= ISCSI_LUN_STATE_BUSY;
24539780SBing.Zhao@Sun.COM 		}
24549780SBing.Zhao@Sun.COM 		ilp = ilp->lun_next;
24559780SBing.Zhao@Sun.COM 	}
24569780SBing.Zhao@Sun.COM 	rw_exit(&isp->sess_lun_list_rwlock);
24579780SBing.Zhao@Sun.COM }
2458*12161SJack.Meng@Sun.COM 
2459*12161SJack.Meng@Sun.COM /*
2460*12161SJack.Meng@Sun.COM  * Submits the scsi enumeration request. Returns
2461*12161SJack.Meng@Sun.COM  * ISCSI_SESS_ENUM_SUBMITTED upon success, or others if failures are met.
2462*12161SJack.Meng@Sun.COM  * If the request is submitted and the wait is set to B_TRUE, the caller
2463*12161SJack.Meng@Sun.COM  * must call iscsi_sess_enum_query at a later time to unblock next enum
2464*12161SJack.Meng@Sun.COM  */
2465*12161SJack.Meng@Sun.COM iscsi_enum_result_t
iscsi_sess_enum_request(iscsi_sess_t * isp,boolean_t wait,uint32_t event_count)2466*12161SJack.Meng@Sun.COM iscsi_sess_enum_request(iscsi_sess_t *isp, boolean_t wait,
2467*12161SJack.Meng@Sun.COM     uint32_t event_count) {
2468*12161SJack.Meng@Sun.COM 	iscsi_task_t		*itp;
2469*12161SJack.Meng@Sun.COM 
2470*12161SJack.Meng@Sun.COM 	itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
2471*12161SJack.Meng@Sun.COM 	itp->t_arg = isp;
2472*12161SJack.Meng@Sun.COM 	itp->t_event_count = event_count;
2473*12161SJack.Meng@Sun.COM 
2474*12161SJack.Meng@Sun.COM 	mutex_enter(&isp->sess_enum_lock);
2475*12161SJack.Meng@Sun.COM 	while ((isp->sess_enum_status != ISCSI_SESS_ENUM_FREE) &&
2476*12161SJack.Meng@Sun.COM 	    (isp->sess_enum_status != ISCSI_SESS_ENUM_INPROG)) {
2477*12161SJack.Meng@Sun.COM 		cv_wait(&isp->sess_enum_cv, &isp->sess_enum_lock);
2478*12161SJack.Meng@Sun.COM 	}
2479*12161SJack.Meng@Sun.COM 	if (isp->sess_enum_status == ISCSI_SESS_ENUM_INPROG) {
2480*12161SJack.Meng@Sun.COM 		/* easy case */
2481*12161SJack.Meng@Sun.COM 		if (wait == B_TRUE) {
2482*12161SJack.Meng@Sun.COM 			isp->sess_enum_result_count ++;
2483*12161SJack.Meng@Sun.COM 		}
2484*12161SJack.Meng@Sun.COM 		mutex_exit(&isp->sess_enum_lock);
2485*12161SJack.Meng@Sun.COM 		kmem_free(itp, sizeof (iscsi_task_t));
2486*12161SJack.Meng@Sun.COM 		return (ISCSI_SESS_ENUM_SUBMITTED);
2487*12161SJack.Meng@Sun.COM 	}
2488*12161SJack.Meng@Sun.COM 
2489*12161SJack.Meng@Sun.COM 	ASSERT(isp->sess_enum_status == ISCSI_SESS_ENUM_FREE);
2490*12161SJack.Meng@Sun.COM 	ASSERT(isp->sess_enum_result_count == 0);
2491*12161SJack.Meng@Sun.COM 
2492*12161SJack.Meng@Sun.COM 	isp->sess_enum_status = ISCSI_SESS_ENUM_INPROG;
2493*12161SJack.Meng@Sun.COM 	if (ddi_taskq_dispatch(isp->sess_enum_taskq,
2494*12161SJack.Meng@Sun.COM 	    iscsi_sess_enumeration, itp, DDI_SLEEP) != DDI_SUCCESS) {
2495*12161SJack.Meng@Sun.COM 		isp->sess_enum_status = ISCSI_SESS_ENUM_FREE;
2496*12161SJack.Meng@Sun.COM 		mutex_exit(&isp->sess_enum_lock);
2497*12161SJack.Meng@Sun.COM 		kmem_free(itp, sizeof (iscsi_task_t));
2498*12161SJack.Meng@Sun.COM 		return (ISCSI_SESS_ENUM_SUBFAIL);
2499*12161SJack.Meng@Sun.COM 	}
2500*12161SJack.Meng@Sun.COM 	if (wait == B_TRUE) {
2501*12161SJack.Meng@Sun.COM 		isp->sess_enum_result_count ++;
2502*12161SJack.Meng@Sun.COM 	}
2503*12161SJack.Meng@Sun.COM 	mutex_exit(&isp->sess_enum_lock);
2504*12161SJack.Meng@Sun.COM 	return (ISCSI_SESS_ENUM_SUBMITTED);
2505*12161SJack.Meng@Sun.COM }
2506*12161SJack.Meng@Sun.COM 
2507*12161SJack.Meng@Sun.COM /*
2508*12161SJack.Meng@Sun.COM  * Wait and query the result of the enumeration.
2509*12161SJack.Meng@Sun.COM  * The last caller is responsible for kicking off the DONE status
2510*12161SJack.Meng@Sun.COM  */
2511*12161SJack.Meng@Sun.COM iscsi_enum_result_t
iscsi_sess_enum_query(iscsi_sess_t * isp)2512*12161SJack.Meng@Sun.COM iscsi_sess_enum_query(iscsi_sess_t *isp) {
2513*12161SJack.Meng@Sun.COM 	iscsi_enum_result_t	ret = ISCSI_SESS_ENUM_IOFAIL;
2514*12161SJack.Meng@Sun.COM 
2515*12161SJack.Meng@Sun.COM 	mutex_enter(&isp->sess_enum_lock);
2516*12161SJack.Meng@Sun.COM 	while (isp->sess_enum_status != ISCSI_SESS_ENUM_DONE) {
2517*12161SJack.Meng@Sun.COM 		cv_wait(&isp->sess_enum_cv, &isp->sess_enum_lock);
2518*12161SJack.Meng@Sun.COM 	}
2519*12161SJack.Meng@Sun.COM 	ret = isp->sess_enum_result;
2520*12161SJack.Meng@Sun.COM 	isp->sess_enum_result_count --;
2521*12161SJack.Meng@Sun.COM 	if (isp->sess_enum_result_count == 0) {
2522*12161SJack.Meng@Sun.COM 		isp->sess_enum_status = ISCSI_SESS_ENUM_FREE;
2523*12161SJack.Meng@Sun.COM 		cv_broadcast(&isp->sess_enum_cv);
2524*12161SJack.Meng@Sun.COM 	}
2525*12161SJack.Meng@Sun.COM 	mutex_exit(&isp->sess_enum_lock);
2526*12161SJack.Meng@Sun.COM 
2527*12161SJack.Meng@Sun.COM 	return (ret);
2528*12161SJack.Meng@Sun.COM }
2529*12161SJack.Meng@Sun.COM 
2530*12161SJack.Meng@Sun.COM static void
iscsi_sess_enum_warn(iscsi_sess_t * isp,iscsi_enum_result_t r)2531*12161SJack.Meng@Sun.COM iscsi_sess_enum_warn(iscsi_sess_t *isp, iscsi_enum_result_t r) {
2532*12161SJack.Meng@Sun.COM 	cmn_err(CE_WARN, "iscsi session (%u) enumeration fails - %s",
2533*12161SJack.Meng@Sun.COM 	    isp->sess_oid, iscsi_sess_enum_warn_msgs[r]);
2534*12161SJack.Meng@Sun.COM }
2535*12161SJack.Meng@Sun.COM 
2536*12161SJack.Meng@Sun.COM void
iscsi_sess_enter_state_zone(iscsi_sess_t * isp)2537*12161SJack.Meng@Sun.COM iscsi_sess_enter_state_zone(iscsi_sess_t *isp) {
2538*12161SJack.Meng@Sun.COM 	mutex_enter(&isp->sess_state_wmutex);
2539*12161SJack.Meng@Sun.COM 	while (isp->sess_state_hasw == B_TRUE) {
2540*12161SJack.Meng@Sun.COM 		cv_wait(&isp->sess_state_wcv, &isp->sess_state_wmutex);
2541*12161SJack.Meng@Sun.COM 	}
2542*12161SJack.Meng@Sun.COM 	isp->sess_state_hasw = B_TRUE;
2543*12161SJack.Meng@Sun.COM 	mutex_exit(&isp->sess_state_wmutex);
2544*12161SJack.Meng@Sun.COM 
2545*12161SJack.Meng@Sun.COM 	rw_enter(&isp->sess_state_rwlock, RW_WRITER);
2546*12161SJack.Meng@Sun.COM }
2547*12161SJack.Meng@Sun.COM 
2548*12161SJack.Meng@Sun.COM void
iscsi_sess_exit_state_zone(iscsi_sess_t * isp)2549*12161SJack.Meng@Sun.COM iscsi_sess_exit_state_zone(iscsi_sess_t *isp) {
2550*12161SJack.Meng@Sun.COM 	rw_exit(&isp->sess_state_rwlock);
2551*12161SJack.Meng@Sun.COM 
2552*12161SJack.Meng@Sun.COM 	mutex_enter(&isp->sess_state_wmutex);
2553*12161SJack.Meng@Sun.COM 	isp->sess_state_hasw = B_FALSE;
2554*12161SJack.Meng@Sun.COM 	cv_signal(&isp->sess_state_wcv);
2555*12161SJack.Meng@Sun.COM 	mutex_exit(&isp->sess_state_wmutex);
2556*12161SJack.Meng@Sun.COM }
2557