xref: /titanic_52/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_sess.c (revision 904e51f67bfac9f3ec88d9254757474c448808eb)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23  *
24  * iSCSI session interfaces
25  */
26 
27 #include <sys/bootprops.h>
28 #include "iscsi.h"
29 #include "persistent.h"
30 #include "iscsi_targetparam.h"
31 
32 #define	ISCSI_SESS_ENUM_TIMEOUT_DEFAULT	60
33 #define	SCSI_INQUIRY_PQUAL_MASK 0xE0
34 
35 boolean_t iscsi_sess_logging = B_FALSE;
36 /*
37  * used to store report lun information found
38  *
39  * lun_valid:	if TRUE means the entry contains a valid entry
40  * lun_found:	if TRUE means the lun has been found in the sess_lun_list
41  * lun_num:	contains the lun_number
42  * lun_addr_type:	indicates lun's type of addressing
43  */
44 typedef	struct replun_data {
45 	boolean_t	lun_valid;
46 	boolean_t	lun_found;
47 	uint16_t	lun_num;
48 	uint8_t		lun_addr_type;
49 } replun_data_t;
50 
51 int	iscsi_sess_enum_timeout = ISCSI_SESS_ENUM_TIMEOUT_DEFAULT;
52 
53 /*
54  * The following private tunable, settable via
55  *      set iscsi:iscsi_sess_max_delay = 64
56  * in /etc/system, provides customer relief for configurations max interval in
57  * seconds of retry for a unreachable target during the login.
58  */
59 int	iscsi_sess_max_delay = ISCSI_DEFAULT_MAX_STORM_DELAY;
60 
61 /*
62  * Warning messages for the session scsi enumeration
63  */
64 static const char *iscsi_sess_enum_warn_msgs[] = {
65 	"completed",
66 	"partially successful",
67 	"IO failures",
68 	"submitted",
69 	"unable to submit the enumeration",
70 	"session is gone",
71 	"test unit ready failed"
72 };
73 
74 /* internal interfaces */
75 /* LINTED E_STATIC_UNUSED */
76 static iscsi_sess_t *iscsi_sess_alloc(iscsi_hba_t *ihp, iscsi_sess_type_t type);
77 static char *iscsi_sess_event_str(iscsi_sess_event_t event);
78 static iscsi_status_t iscsi_sess_threads_create(iscsi_sess_t *isp);
79 static void iscsi_sess_flush(iscsi_sess_t *isp);
80 static void iscsi_sess_offline_luns(iscsi_sess_t *isp);
81 static iscsi_status_t retrieve_lundata(uint32_t lun_count, unsigned char *buf,
82 	iscsi_sess_t *isp, uint16_t *lun_data, uint8_t *lun_addr_type);
83 
84 /* internal state machine interfaces */
85 static void iscsi_sess_state_free(iscsi_sess_t *isp,
86     iscsi_sess_event_t event, uint32_t event_count);
87 static void iscsi_sess_state_logged_in(iscsi_sess_t *isp,
88     iscsi_sess_event_t event, uint32_t event_count);
89 static void iscsi_sess_state_failed(iscsi_sess_t *isp,
90     iscsi_sess_event_t event, uint32_t event_count);
91 static void iscsi_sess_state_in_flush(iscsi_sess_t *isp,
92     iscsi_sess_event_t event, uint32_t event_count);
93 static void iscsi_sess_state_flushed(iscsi_sess_t *isp,
94     iscsi_sess_event_t event, uint32_t event_count);
95 
96 /* internal enumeration interfaces */
97 static void iscsi_sess_enumeration(void *arg);
98 static iscsi_status_t iscsi_sess_testunitready(iscsi_sess_t *isp,
99     uint32_t event_count);
100 static iscsi_status_t iscsi_sess_reportluns(iscsi_sess_t *isp,
101     uint32_t event_count);
102 static void iscsi_sess_inquiry(iscsi_sess_t *isp, uint16_t lun_num,
103     uint8_t lun_addr_type, uint32_t event_count, iscsi_lun_t *ilp);
104 static void iscsi_sess_update_busy_luns(iscsi_sess_t *isp, boolean_t clear);
105 static void iscsi_sess_enum_warn(iscsi_sess_t *isp, iscsi_enum_result_t r);
106 
107 /*
108  * +--------------------------------------------------------------------+
109  * | External Session Interfaces					|
110  * +--------------------------------------------------------------------+
111  */
112 iscsi_sess_t *
113 iscsi_sess_create(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method,
114     struct sockaddr *addr_dsc, char *target_name, int tpgt, uchar_t isid_lsb,
115     iscsi_sess_type_t type, uint32_t *oid)
116 {
117 	iscsi_sess_t	*isp		= NULL;
118 	int		len		= 0;
119 	char		*tq_name;
120 	char		*th_name;
121 	iscsi_status_t	status;
122 
123 	len = strlen(target_name);
124 
125 clean_failed_sess:
126 	if (isp != NULL) {
127 		(void) iscsi_sess_destroy(isp);
128 	}
129 
130 	for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
131 		/* Match target name and LSB ISID */
132 		if ((strcmp((char *)isp->sess_name, target_name) == 0) &&
133 		    (isp->sess_isid[5] == isid_lsb)) {
134 
135 			/* Match TPGT */
136 			if (isp->sess_tpgt_conf == tpgt) {
137 				/* Found mathing session, return oid/ptr */
138 				*oid = isp->sess_oid;
139 				if (isp->sess_wd_thread != NULL &&
140 				    isp->sess_ic_thread != NULL) {
141 					return (isp);
142 				}
143 
144 				if (isp->sess_wd_thread == NULL) {
145 					/*
146 					 * Under rare cases wd thread is already
147 					 * freed, create it if so.
148 					 */
149 					th_name = kmem_zalloc(
150 					    ISCSI_TH_MAX_NAME_LEN, KM_SLEEP);
151 					if (snprintf(th_name,
152 					    (ISCSI_TH_MAX_NAME_LEN - 1),
153 					    ISCSI_SESS_WD_NAME_FORMAT,
154 					    ihp->hba_oid, isp->sess_oid) <
155 					    ISCSI_TH_MAX_NAME_LEN) {
156 						isp->sess_wd_thread =
157 						    iscsi_thread_create(
158 						    ihp->hba_dip,
159 						    th_name,
160 						    iscsi_wd_thread,
161 						    isp);
162 						(void) iscsi_thread_start(
163 						    isp->sess_wd_thread);
164 					}
165 					kmem_free(th_name,
166 					    ISCSI_TH_MAX_NAME_LEN);
167 					if (isp->sess_wd_thread == NULL) {
168 						/* No way to save it */
169 						goto clean_failed_sess;
170 					}
171 				}
172 
173 				if (isp->sess_ic_thread == NULL) {
174 					status = iscsi_sess_threads_create(isp);
175 					if (status != ISCSI_STATUS_SUCCESS) {
176 						goto clean_failed_sess;
177 					}
178 				}
179 				return (isp);
180 			}
181 
182 			/*
183 			 * Also protect against creating duplicate
184 			 * sessions with different configured tpgt
185 			 * values.  default vs. defined.
186 			 */
187 			if ((((isp->sess_tpgt_conf == ISCSI_DEFAULT_TPGT) &&
188 			    (tpgt != ISCSI_DEFAULT_TPGT)) ||
189 			    ((isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) &&
190 			    (tpgt == ISCSI_DEFAULT_TPGT)))) {
191 				/* Dangerous configuration.  Fail Request */
192 				return (NULL);
193 			}
194 		}
195 	}
196 
197 	isp = (iscsi_sess_t *)kmem_zalloc(sizeof (iscsi_sess_t), KM_SLEEP);
198 	/*
199 	 * If this session is not a Send Targets session, set the target
200 	 * that this session is associated with.
201 	 */
202 	if (strncmp(target_name, SENDTARGETS_DISCOVERY,
203 	    strlen(SENDTARGETS_DISCOVERY))) {
204 		isp->sess_target_oid = iscsi_targetparam_get_oid(
205 		    (uchar_t *)target_name);
206 	}
207 
208 	if (method & iSCSIDiscoveryMethodBoot) {
209 		/* This is boot session. */
210 		isp->sess_boot = B_TRUE;
211 	} else {
212 		isp->sess_boot = B_FALSE;
213 	}
214 
215 	/* Associate session with this discovery method */
216 	method = method & ~(iSCSIDiscoveryMethodBoot);
217 
218 	isp->sess_discovered_by = method;
219 	if (addr_dsc == NULL) {
220 		bzero(&isp->sess_discovered_addr,
221 		    sizeof (isp->sess_discovered_addr));
222 	} else {
223 		bcopy(addr_dsc, &isp->sess_discovered_addr,
224 		    SIZEOF_SOCKADDR(addr_dsc));
225 	}
226 
227 	/* assign unique key for the session */
228 	mutex_enter(&iscsi_oid_mutex);
229 	isp->sess_oid = iscsi_oid++;
230 	*oid = isp->sess_oid;
231 	mutex_exit(&iscsi_oid_mutex);
232 
233 	/* setup session parameters */
234 	isp->sess_name_length		= 0;
235 	isp->sess_sig			= ISCSI_SIG_SESS;
236 	isp->sess_state			= ISCSI_SESS_STATE_FREE;
237 	rw_init(&isp->sess_state_rwlock, NULL, RW_DRIVER, NULL);
238 	mutex_init(&isp->sess_reset_mutex, NULL, MUTEX_DRIVER, NULL);
239 	isp->sess_hba			= ihp;
240 
241 	isp->sess_isid[0]		= ISCSI_SUN_ISID_0;
242 	isp->sess_isid[1]		= ISCSI_SUN_ISID_1;
243 	isp->sess_isid[2]		= ISCSI_SUN_ISID_2;
244 	isp->sess_isid[3]		= ISCSI_SUN_ISID_3;
245 	isp->sess_isid[4]		= 0;
246 	isp->sess_isid[5]		= isid_lsb;
247 
248 	isp->sess_cmdsn			= 1;
249 	isp->sess_expcmdsn		= 1;
250 	isp->sess_maxcmdsn		= 1;
251 	isp->sess_last_err		= NoError;
252 	isp->sess_tsid			= 0;
253 	isp->sess_type			= type;
254 	isp->sess_reset_in_progress	= B_FALSE;
255 	isp->sess_boot_nic_reset	= B_FALSE;
256 	idm_sm_audit_init(&isp->sess_state_audit);
257 
258 	/* copy default driver login parameters */
259 	bcopy(&ihp->hba_params, &isp->sess_params,
260 	    sizeof (iscsi_login_params_t));
261 
262 	/* copy target name into session */
263 	bcopy((char *)target_name, isp->sess_name, len);
264 	isp->sess_name_length	= len;
265 	isp->sess_tpgt_conf	= tpgt;
266 	isp->sess_tpgt_nego	= ISCSI_DEFAULT_TPGT;
267 
268 	/* initialize pending and completion queues */
269 	iscsi_init_queue(&isp->sess_queue_pending);
270 	iscsi_init_queue(&isp->sess_queue_completion);
271 
272 	/* setup sessions lun list */
273 	isp->sess_lun_list = NULL;
274 	rw_init(&isp->sess_lun_list_rwlock, NULL, RW_DRIVER, NULL);
275 
276 	/* setup sessions connection list */
277 	isp->sess_conn_act = NULL;
278 	isp->sess_conn_list = NULL;
279 	rw_init(&isp->sess_conn_list_rwlock, NULL, RW_DRIVER, NULL);
280 
281 	mutex_init(&isp->sess_cmdsn_mutex, NULL, MUTEX_DRIVER, NULL);
282 
283 	/* create the session task queue */
284 	tq_name = kmem_zalloc(ISCSI_TH_MAX_NAME_LEN, KM_SLEEP);
285 	if (snprintf(tq_name, (ISCSI_TH_MAX_NAME_LEN - 1),
286 	    ISCSI_SESS_LOGIN_TASKQ_NAME_FORMAT, ihp->hba_oid, isp->sess_oid) <
287 	    ISCSI_TH_MAX_NAME_LEN) {
288 		isp->sess_login_taskq = ddi_taskq_create(ihp->hba_dip,
289 		    tq_name, 1, TASKQ_DEFAULTPRI, 0);
290 	}
291 	if (isp->sess_login_taskq == NULL) {
292 		kmem_free(tq_name, ISCSI_TH_MAX_NAME_LEN);
293 		goto iscsi_sess_cleanup2;
294 	}
295 
296 	if (snprintf(tq_name, (ISCSI_TH_MAX_NAME_LEN - 1),
297 	    ISCSI_SESS_ENUM_TASKQ_NAME_FORMAT, ihp->hba_oid, isp->sess_oid) <
298 	    ISCSI_TH_MAX_NAME_LEN) {
299 		isp->sess_enum_taskq = ddi_taskq_create(ihp->hba_dip,
300 		    tq_name, 1, TASKQ_DEFAULTPRI, 0);
301 	}
302 	kmem_free(tq_name, ISCSI_TH_MAX_NAME_LEN);
303 	if (isp->sess_enum_taskq == NULL) {
304 		goto iscsi_sess_cleanup1;
305 	}
306 	/* startup watchdog */
307 	th_name = kmem_zalloc(ISCSI_TH_MAX_NAME_LEN, KM_SLEEP);
308 	if (snprintf(th_name, (ISCSI_TH_MAX_NAME_LEN - 1),
309 	    ISCSI_SESS_WD_NAME_FORMAT, ihp->hba_oid, isp->sess_oid) <
310 	    ISCSI_TH_MAX_NAME_LEN) {
311 		isp->sess_wd_thread = iscsi_thread_create(ihp->hba_dip,
312 		    th_name, iscsi_wd_thread, isp);
313 		(void) iscsi_thread_start(isp->sess_wd_thread);
314 	}
315 
316 	kmem_free(th_name, ISCSI_TH_MAX_NAME_LEN);
317 	if (isp->sess_wd_thread == NULL) {
318 		goto iscsi_sess_cleanup0;
319 	}
320 
321 	status = iscsi_sess_threads_create(isp);
322 	if (status != ISCSI_STATUS_SUCCESS) {
323 		goto iscsi_sess_cleanup1;
324 	}
325 
326 	/* Add new target to the hba target list */
327 	if (ihp->hba_sess_list == NULL) {
328 		ihp->hba_sess_list = isp;
329 	} else {
330 		isp->sess_next = ihp->hba_sess_list;
331 		ihp->hba_sess_list = isp;
332 	}
333 	KSTAT_INC_HBA_CNTR_SESS(ihp);
334 
335 	(void) iscsi_sess_kstat_init(isp);
336 
337 	if (type == ISCSI_SESS_TYPE_NORMAL) {
338 		isp->sess_enum_status = ISCSI_SESS_ENUM_FREE;
339 		isp->sess_enum_result = ISCSI_SESS_ENUM_COMPLETE;
340 		isp->sess_enum_result_count = 0;
341 		mutex_init(&isp->sess_enum_lock, NULL, MUTEX_DRIVER, NULL);
342 		cv_init(&isp->sess_enum_cv, NULL, CV_DRIVER, NULL);
343 	}
344 
345 	mutex_init(&isp->sess_state_wmutex, NULL, MUTEX_DRIVER, NULL);
346 	cv_init(&isp->sess_state_wcv, NULL, CV_DRIVER, NULL);
347 	isp->sess_state_hasw = B_FALSE;
348 
349 	isp->sess_state_event_count = 0;
350 
351 	return (isp);
352 iscsi_sess_cleanup0:
353 	ddi_taskq_destroy(isp->sess_enum_taskq);
354 iscsi_sess_cleanup1:
355 	ddi_taskq_destroy(isp->sess_login_taskq);
356 iscsi_sess_cleanup2:
357 	if (isp->sess_wd_thread != NULL) {
358 		iscsi_thread_destroy(isp->sess_wd_thread);
359 		isp->sess_wd_thread  = NULL;
360 	}
361 	if (isp->sess_ic_thread != NULL) {
362 		iscsi_thread_destroy(isp->sess_ic_thread);
363 		isp->sess_ic_thread = NULL;
364 	}
365 	mutex_destroy(&isp->sess_cmdsn_mutex);
366 	rw_destroy(&isp->sess_conn_list_rwlock);
367 	rw_destroy(&isp->sess_lun_list_rwlock);
368 	iscsi_destroy_queue(&isp->sess_queue_completion);
369 	iscsi_destroy_queue(&isp->sess_queue_pending);
370 	rw_destroy(&isp->sess_state_rwlock);
371 	mutex_destroy(&isp->sess_reset_mutex);
372 	kmem_free(isp, sizeof (iscsi_sess_t));
373 
374 	return (NULL);
375 }
376 
377 /*
378  * iscsi_sess_get - return the session structure for based on a
379  * passed in oid and hba instance.
380  */
381 int
382 iscsi_sess_get(uint32_t oid, iscsi_hba_t *ihp, iscsi_sess_t **ispp)
383 {
384 	int		rval		= 0;
385 	iscsi_sess_t	*isp		= NULL;
386 
387 	ASSERT(ihp != NULL);
388 	ASSERT(ispp != NULL);
389 
390 	/* See if we already created this session */
391 	for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
392 		/* compare target name as the unique identifier */
393 		if (isp->sess_oid == oid) {
394 			/* Found matching session */
395 			break;
396 		}
397 	}
398 
399 	/* If not null this session is already available */
400 	if (isp != NULL) {
401 		/* Existing session, return it */
402 		*ispp = isp;
403 	} else {
404 		rval = EFAULT;
405 	}
406 	return (rval);
407 }
408 
409 /*
410  * iscsi_sess_online - initiate online of sessions connections
411  */
412 void
413 iscsi_sess_online(void *arg)
414 {
415 	iscsi_sess_t	*isp;
416 	iscsi_hba_t	*ihp;
417 	iscsi_conn_t	*icp;
418 	int		idx;
419 	uint32_t	event_count;
420 
421 	isp = (iscsi_sess_t *)arg;
422 
423 	ASSERT(isp != NULL);
424 	ihp = isp->sess_hba;
425 	ASSERT(ihp != NULL);
426 
427 	/*
428 	 * Stale /dev links can cause us to get floods
429 	 * of config requests. To prevent these repeated
430 	 * requests from causing unneeded login to the
431 	 * unreachable target, we won't try it during
432 	 * the delay.
433 	 */
434 	if (ddi_get_lbolt() < isp->sess_failure_lbolt +
435 	    SEC_TO_TICK(isp->sess_storm_delay)) {
436 		return;
437 	}
438 
439 	/*
440 	 * Perform a crude version of round robin to
441 	 * determine which connection to use for
442 	 * this session. Since byte 5 in session ID
443 	 * is overridden for full feature session,
444 	 * the connection to be selected depends on
445 	 * the result of sess_isid[5] devided by the
446 	 * next connection ID.
447 	 * If MS/T is enabled and there are multiple
448 	 * IPs are available on the target, we can
449 	 * select different IPs to connect in this
450 	 * way.
451 	 */
452 	icp = isp->sess_conn_act;
453 	if (icp == NULL) {
454 		icp = isp->sess_conn_list;
455 		for (idx = 0; idx < (isp->sess_isid[5] %
456 		    isp->sess_conn_next_cid); idx++) {
457 			ASSERT(icp->conn_next != NULL);
458 			icp = icp->conn_next;
459 		}
460 		isp->sess_conn_act = icp;
461 	}
462 
463 	if (icp == NULL) {
464 		cmn_err(CE_NOTE, "iscsi session(%d) - "
465 		    "no connection assigned", isp->sess_oid);
466 		return;
467 	}
468 
469 	/*
470 	 * If connection is in free state, start
471 	 * login.  If already logged in, try to
472 	 * re-enumerate LUs on the session.
473 	 */
474 	mutex_enter(&icp->conn_state_mutex);
475 	if (icp->conn_state == ISCSI_CONN_STATE_FREE) {
476 		/*
477 		 * attempt to login into the first connection in our connection
478 		 * list.  If this fails, we will try the next connection
479 		 * in our list until end of the list.
480 		 */
481 		while (icp != NULL) {
482 			if (iscsi_conn_online(icp) == ISCSI_STATUS_SUCCESS) {
483 				mutex_exit(&icp->conn_state_mutex);
484 				break;
485 			} else {
486 				mutex_exit(&icp->conn_state_mutex);
487 				icp = icp->conn_next;
488 				if (icp != NULL) {
489 					mutex_enter(&icp->conn_state_mutex);
490 				}
491 			}
492 		}
493 		isp->sess_conn_act = icp;
494 		if (icp == NULL) {
495 		/* the target for this session is unreachable */
496 			isp->sess_failure_lbolt = ddi_get_lbolt();
497 			if (isp->sess_storm_delay == 0) {
498 				isp->sess_storm_delay++;
499 			} else {
500 
501 				if ((isp->sess_storm_delay * 2) <
502 				    iscsi_sess_max_delay) {
503 					isp->sess_storm_delay =
504 					    isp->sess_storm_delay * 2;
505 				} else {
506 					isp->sess_storm_delay =
507 					    iscsi_sess_max_delay;
508 				}
509 			}
510 
511 		} else {
512 			isp->sess_storm_delay = 0;
513 			isp->sess_failure_lbolt = 0;
514 		}
515 	} else if (icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN) {
516 		mutex_exit(&icp->conn_state_mutex);
517 		event_count = atomic_inc_32_nv(&isp->sess_state_event_count);
518 		iscsi_sess_enter_state_zone(isp);
519 		iscsi_sess_state_machine(isp,
520 		    ISCSI_SESS_EVENT_N1, event_count);
521 		iscsi_sess_exit_state_zone(isp);
522 	} else {
523 		mutex_exit(&icp->conn_state_mutex);
524 	}
525 }
526 
527 /*
528  * iscsi_sess_destroy - Destroys a iscsi session structure
529  * and de-associates it from the hba.
530  */
531 iscsi_status_t
532 iscsi_sess_destroy(iscsi_sess_t *isp)
533 {
534 	iscsi_status_t	rval	= ISCSI_STATUS_SUCCESS;
535 	iscsi_status_t	tmprval = ISCSI_STATUS_SUCCESS;
536 	iscsi_hba_t	*ihp;
537 	iscsi_sess_t	*t_isp;
538 	iscsi_lun_t	*ilp;
539 	iscsi_conn_t	*icp;
540 
541 	ASSERT(isp != NULL);
542 	ihp = isp->sess_hba;
543 	ASSERT(ihp != NULL);
544 
545 	/*
546 	 * The first step in tearing down the session
547 	 * has to be offlining all the LUNs.  This will
548 	 * ensure there is no outstanding IO by upper
549 	 * level drivers.  If this fails then we are
550 	 * unable to destroy the session.
551 	 *
552 	 * Try all luns and continue upon failure
553 	 * to remove what is removable before returning
554 	 * the last error.
555 	 */
556 	rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
557 	ilp = isp->sess_lun_list;
558 	while (ilp != NULL) {
559 		iscsi_lun_t	*ilp_next = ilp->lun_next;
560 
561 		tmprval = iscsi_lun_destroy(ihp, ilp);
562 		if (!ISCSI_SUCCESS(tmprval)) {
563 			rval = tmprval;
564 		}
565 		ilp = ilp_next;
566 	}
567 	rw_exit(&isp->sess_lun_list_rwlock);
568 
569 	if (!ISCSI_SUCCESS(rval)) {
570 		return (rval);
571 	}
572 
573 	/* The next step is to logout of the connections. */
574 	rw_enter(&isp->sess_conn_list_rwlock, RW_WRITER);
575 	icp = isp->sess_conn_list;
576 	while (icp != NULL) {
577 		rval = iscsi_conn_offline(icp);
578 		if (ISCSI_SUCCESS(rval)) {
579 			/* Succes, Continue processing... */
580 			icp = icp->conn_next;
581 		} else {
582 			/* Failure, Stop processing... */
583 			rw_exit(&isp->sess_conn_list_rwlock);
584 			return (rval);
585 		}
586 	}
587 	rw_exit(&isp->sess_conn_list_rwlock);
588 
589 	/*
590 	 * At this point all connections should be in
591 	 * a FREE state which will have pushed the session
592 	 * to a FREE state.
593 	 */
594 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FREE ||
595 	    isp->sess_state == ISCSI_SESS_STATE_FAILED);
596 
597 	/* Stop watchdog before destroying connections */
598 	if (isp->sess_wd_thread) {
599 		iscsi_thread_destroy(isp->sess_wd_thread);
600 		isp->sess_wd_thread = NULL;
601 	}
602 
603 	/* Destroy connections */
604 	rw_enter(&isp->sess_conn_list_rwlock, RW_WRITER);
605 	icp = isp->sess_conn_list;
606 	while (icp != NULL) {
607 		rval = iscsi_conn_destroy(icp);
608 		if (!ISCSI_SUCCESS(rval)) {
609 			rw_exit(&isp->sess_conn_list_rwlock);
610 			return (rval);
611 		}
612 		icp = isp->sess_conn_list;
613 	}
614 	rw_exit(&isp->sess_conn_list_rwlock);
615 
616 	/* Destroy Session ic thread */
617 	if (isp->sess_ic_thread != NULL) {
618 		iscsi_thread_destroy(isp->sess_ic_thread);
619 		isp->sess_ic_thread = NULL;
620 	}
621 
622 	/* Destroy session task queue */
623 	ddi_taskq_destroy(isp->sess_enum_taskq);
624 	ddi_taskq_destroy(isp->sess_login_taskq);
625 
626 	/* destroy pending and completion queues */
627 	iscsi_destroy_queue(&isp->sess_queue_pending);
628 	iscsi_destroy_queue(&isp->sess_queue_completion);
629 
630 	/* Remove session from ihp */
631 	if (ihp->hba_sess_list == isp) {
632 		/* session first item in list */
633 		ihp->hba_sess_list = isp->sess_next;
634 	} else {
635 		/*
636 		 * search hba list for isp pointing
637 		 * to session being removed.  Then
638 		 * update that sessions next pointer.
639 		 */
640 		t_isp = ihp->hba_sess_list;
641 		while (t_isp->sess_next != NULL) {
642 			if (t_isp->sess_next == isp) {
643 				break;
644 			}
645 			t_isp = t_isp->sess_next;
646 		}
647 		if (t_isp->sess_next == isp) {
648 			t_isp->sess_next = isp->sess_next;
649 		} else {
650 			/* couldn't find session */
651 			ASSERT(FALSE);
652 		}
653 	}
654 
655 	if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
656 		/* Wait for all enum requests complete */
657 		mutex_enter(&isp->sess_enum_lock);
658 		while (isp->sess_enum_result_count > 0) {
659 			cv_wait(&isp->sess_enum_cv, &isp->sess_enum_lock);
660 		}
661 		mutex_exit(&isp->sess_enum_lock);
662 	}
663 
664 	/* Destroy this Sessions Data */
665 	(void) iscsi_sess_kstat_term(isp);
666 	rw_destroy(&isp->sess_lun_list_rwlock);
667 	rw_destroy(&isp->sess_conn_list_rwlock);
668 	mutex_destroy(&isp->sess_cmdsn_mutex);
669 	rw_destroy(&isp->sess_state_rwlock);
670 	mutex_destroy(&isp->sess_reset_mutex);
671 	if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
672 		mutex_destroy(&isp->sess_enum_lock);
673 		cv_destroy(&isp->sess_enum_cv);
674 	}
675 	mutex_destroy(&isp->sess_state_wmutex);
676 	cv_destroy(&isp->sess_state_wcv);
677 	kmem_free(isp, sizeof (iscsi_sess_t));
678 	return (rval);
679 }
680 
681 extern ib_boot_prop_t   *iscsiboot_prop;
682 /*
683  * static iscsi_sess_set_auth -
684  *
685  */
686 boolean_t
687 iscsi_sess_set_auth(iscsi_sess_t *isp)
688 {
689 	char			*init_name;
690 	iscsi_chap_props_t	*chap = NULL;
691 	iscsi_auth_props_t	*auth = NULL;
692 	uchar_t			*tmp  = NULL;
693 
694 	if (isp == (iscsi_sess_t *)NULL) {
695 		return (B_FALSE);
696 	}
697 
698 	/* Obtain initiator's name */
699 	if (isp->sess_hba == (iscsi_hba_t *)NULL) {
700 		return (B_FALSE);
701 	}
702 
703 	init_name = (char *)isp->sess_hba->hba_name;
704 
705 	/* Zero out the session authentication structure */
706 	bzero(&isp->sess_auth, sizeof (iscsi_auth_t));
707 
708 	if (isp->sess_boot == B_FALSE) {
709 
710 		auth = (iscsi_auth_props_t *)kmem_zalloc
711 		    (sizeof (iscsi_auth_props_t), KM_SLEEP);
712 		/* Obtain target's authentication settings. */
713 		if (persistent_auth_get((char *)isp->sess_name, auth)
714 		    != B_TRUE) {
715 			/*
716 			 * If no target authentication settings found,
717 			 * try to obtain system wide configuration
718 			 * (from the initiator).
719 			 */
720 			bzero(auth, sizeof (*auth));
721 			if (persistent_auth_get(init_name, auth) != B_TRUE) {
722 				bzero(auth, sizeof (*auth));
723 				auth->a_auth_method = authMethodNone;
724 			}
725 
726 			/*
727 			 * We do not support system wide bi-directional
728 			 * auth flag.
729 			 */
730 			auth->a_bi_auth = B_FALSE;
731 		}
732 
733 		chap = (iscsi_chap_props_t *)kmem_zalloc
734 		    (sizeof (iscsi_chap_props_t), KM_SLEEP);
735 
736 		/*
737 		 * Initialize the target-side chap name to the session name
738 		 * if no chap settings have been saved for the current session.
739 		 */
740 		if (persistent_chap_get((char *)isp->sess_name, chap)
741 		    == B_FALSE) {
742 			int name_len = strlen((char *)isp->sess_name);
743 			bcopy((char *)isp->sess_name, chap->c_user, name_len);
744 			chap->c_user_len = name_len;
745 			(void) (persistent_chap_set((char *)isp->sess_name,
746 			    chap));
747 			bzero(chap, sizeof (*chap));
748 		}
749 
750 		if (auth->a_auth_method & authMethodCHAP) {
751 			/* Obtain initiator's CHAP settings. */
752 			if (persistent_chap_get(init_name, chap) == B_FALSE) {
753 				/* No initiator secret defined. */
754 				kmem_free(chap, sizeof (iscsi_chap_props_t));
755 				/* Set authentication method to NONE */
756 				isp->sess_auth.password_length = 0;
757 				kmem_free(auth, sizeof (iscsi_auth_props_t));
758 				return (B_FALSE);
759 			}
760 
761 			bcopy(chap->c_user, isp->sess_auth.username,
762 			    sizeof (chap->c_user));
763 			bcopy(chap->c_secret, isp->sess_auth.password,
764 			    sizeof (chap->c_secret));
765 			isp->sess_auth.password_length = chap->c_secret_len;
766 		} else {
767 			/* Set authentication method to NONE */
768 			isp->sess_auth.password_length = 0;
769 		}
770 
771 		/*
772 		 * Consider enabling bidirectional authentication only if
773 		 * authentication method is not NONE.
774 		 */
775 		if (auth->a_auth_method & authMethodCHAP &&
776 		    auth->a_bi_auth == B_TRUE) {
777 			/* Enable bi-directional authentication. */
778 			isp->sess_auth.bidirectional_auth = 1;
779 
780 			bzero(chap, sizeof (*chap));
781 			/* Obtain target's CHAP settings. */
782 			if (persistent_chap_get((char *)isp->sess_name, chap)
783 			    == B_TRUE) {
784 				bcopy(chap->c_secret,
785 				    isp->sess_auth.password_in,
786 				    sizeof (chap->c_secret));
787 				bcopy(chap->c_user, isp->sess_auth.username_in,
788 				    strlen((char *)chap->c_user));
789 				isp->sess_auth.password_length_in =
790 				    chap->c_secret_len;
791 			} else {
792 				/*
793 				 * No target secret defined.
794 				 * RADIUS server should have been enabled.
795 				 */
796 				/* EMPTY */
797 			}
798 		} else {
799 			/* Disable bi-directional authentication */
800 			isp->sess_auth.bidirectional_auth = 0;
801 		}
802 
803 		if (auth != NULL) {
804 			kmem_free(auth, sizeof (iscsi_auth_props_t));
805 		}
806 		if (chap != NULL) {
807 			kmem_free(chap, sizeof (iscsi_chap_props_t));
808 		}
809 	} else {
810 		/*
811 		 * This session is boot session. We will use the CHAP and
812 		 * the user name got from the boot property structure instead
813 		 * of persistent sotre.
814 		 */
815 		if (iscsiboot_prop == NULL) {
816 			return (B_FALSE);
817 		}
818 
819 		if (iscsiboot_prop->boot_init.ini_chap_sec == NULL) {
820 			return (B_FALSE);
821 		}
822 
823 		/* CHAP secret */
824 		(void) bcopy(iscsiboot_prop->boot_init.ini_chap_sec,
825 		    isp->sess_auth.password,
826 		    strlen((char *)iscsiboot_prop->boot_init.ini_chap_sec));
827 
828 		/*
829 		 * If chap name is not set,
830 		 * we will use initiator name instead.
831 		 */
832 		if (iscsiboot_prop->boot_init.ini_chap_name == NULL) {
833 			(void) bcopy(init_name, isp->sess_auth.username,
834 			    strlen(init_name));
835 		} else {
836 			tmp = iscsiboot_prop->boot_init.ini_chap_name;
837 			(void) bcopy(tmp,
838 			    isp->sess_auth.username, strlen((char *)tmp));
839 		}
840 
841 		isp->sess_auth.password_length =
842 		    strlen((char *)iscsiboot_prop->boot_init.ini_chap_sec);
843 
844 		if (iscsiboot_prop->boot_tgt.tgt_chap_sec != NULL) {
845 			/*
846 			 * Bidirectional authentication is required.
847 			 */
848 			tmp = iscsiboot_prop->boot_tgt.tgt_chap_sec;
849 			(void) bcopy(tmp,
850 			    isp->sess_auth.password_in, strlen((char *)tmp));
851 
852 			/*
853 			 * If the target's chap name is not set, we will use
854 			 * session name instead.
855 			 */
856 			if (iscsiboot_prop->boot_tgt.tgt_chap_name == NULL) {
857 				(void) bcopy(isp->sess_name,
858 				    isp->sess_auth.username_in,
859 				    isp->sess_name_length);
860 			} else {
861 				tmp = iscsiboot_prop->boot_tgt.tgt_chap_name;
862 				(void) bcopy(tmp,
863 				    isp->sess_auth.username_in,
864 				    strlen((char *)tmp));
865 			}
866 			tmp = iscsiboot_prop->boot_tgt.tgt_chap_sec;
867 			isp->sess_auth.password_length_in =
868 			    strlen((char *)tmp);
869 			isp->sess_auth.bidirectional_auth = 1;
870 		}
871 	}
872 
873 	/* Set up authentication buffers only if configured */
874 	if ((isp->sess_auth.password_length != 0) ||
875 	    (isp->sess_auth.password_length_in != 0)) {
876 		isp->sess_auth.num_auth_buffers = 5;
877 		isp->sess_auth.auth_buffers[0].address =
878 		    &(isp->sess_auth.auth_client_block);
879 		isp->sess_auth.auth_buffers[0].length =
880 		    sizeof (isp->sess_auth.auth_client_block);
881 		isp->sess_auth.auth_buffers[1].address =
882 		    &(isp->sess_auth.auth_recv_string_block);
883 		isp->sess_auth.auth_buffers[1].length =
884 		    sizeof (isp->sess_auth.auth_recv_string_block);
885 		isp->sess_auth.auth_buffers[2].address =
886 		    &(isp->sess_auth.auth_send_string_block);
887 		isp->sess_auth.auth_buffers[2].length =
888 		    sizeof (isp->sess_auth.auth_send_string_block);
889 		isp->sess_auth.auth_buffers[3].address =
890 		    &(isp->sess_auth.auth_recv_binary_block);
891 		isp->sess_auth.auth_buffers[3].length =
892 		    sizeof (isp->sess_auth.auth_recv_binary_block);
893 		isp->sess_auth.auth_buffers[4].address =
894 		    &(isp->sess_auth.auth_send_binary_block);
895 		isp->sess_auth.auth_buffers[4].length =
896 		    sizeof (isp->sess_auth.auth_send_binary_block);
897 	}
898 
899 	return (B_TRUE);
900 }
901 
902 /*
903  * iscsi_sess_reserve_itt - Used to reserve an ITT hash slot
904  */
905 iscsi_status_t
906 iscsi_sess_reserve_scsi_itt(iscsi_cmd_t *icmdp)
907 {
908 	idm_task_t *itp;
909 	iscsi_conn_t *icp = icmdp->cmd_conn;
910 	itp = idm_task_alloc(icp->conn_ic);
911 	if (itp == NULL)
912 		return (ISCSI_STATUS_INTERNAL_ERROR);
913 	itp->idt_private = icmdp;
914 	icmdp->cmd_itp = itp;
915 	icmdp->cmd_itt = itp->idt_tt;
916 	return (ISCSI_STATUS_SUCCESS);
917 }
918 
919 /*
920  * iscsi_sess_release_scsi_itt - Used to release ITT hash slot
921  */
922 void
923 iscsi_sess_release_scsi_itt(iscsi_cmd_t *icmdp)
924 {
925 	idm_task_free(icmdp->cmd_itp);
926 }
927 
928 /*
929  * iscsi_sess_reserve_itt - Used to reserve an ITT hash slot
930  */
931 iscsi_status_t
932 iscsi_sess_reserve_itt(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
933 {
934 	/* If no more slots are open fail reservation */
935 	if (isp->sess_cmd_table_count >= ISCSI_CMD_TABLE_SIZE) {
936 		return (ISCSI_STATUS_ITT_TABLE_FULL);
937 	}
938 
939 	/*
940 	 * Keep itt values out of the range used by IDM
941 	 */
942 	if (isp->sess_itt < IDM_TASKIDS_MAX)
943 		isp->sess_itt = IDM_TASKIDS_MAX;
944 
945 	/*
946 	 * Find the next available slot.  Normally its the
947 	 * slot pointed to by the session's sess_itt value.
948 	 * If this is not true the table has become fragmented.
949 	 * Fragmentation can occur during max loads and IOs
950 	 * are completed out of order.  Defragmentation will
951 	 * occur when IO slows down and ITT slots are released.
952 	 */
953 	while (isp->sess_cmd_table[isp->sess_itt %
954 	    ISCSI_CMD_TABLE_SIZE] != NULL) {
955 		isp->sess_itt++;
956 	}
957 
958 	/* reserve slot and update counters */
959 	icmdp->cmd_itt = isp->sess_itt;
960 	isp->sess_cmd_table[isp->sess_itt %
961 	    ISCSI_CMD_TABLE_SIZE] = icmdp;
962 	isp->sess_cmd_table_count++;
963 	isp->sess_itt++;
964 
965 	return (ISCSI_STATUS_SUCCESS);
966 }
967 
968 /*
969  * iscsi_sess_release_itt - Used to release ITT hash slot
970  */
971 void
972 iscsi_sess_release_itt(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
973 {
974 	int hash_index = (icmdp->cmd_itt % ISCSI_CMD_TABLE_SIZE);
975 
976 	ASSERT(isp->sess_cmd_table[hash_index] != NULL);
977 
978 	/* release slot and update counters */
979 	isp->sess_cmd_table[hash_index] = NULL;
980 	isp->sess_cmd_table_count--;
981 }
982 
983 /*
984  * iscsi_sess_redrive_io - Used to redrive IO on connections in
985  * a full feature state.
986  */
987 void
988 iscsi_sess_redrive_io(iscsi_sess_t *isp)
989 {
990 	iscsi_conn_t	*icp;
991 
992 	ASSERT(isp != NULL);
993 
994 	icp = isp->sess_conn_list;
995 	while (icp != NULL) {
996 		if (ISCSI_CONN_STATE_FULL_FEATURE(
997 		    icp->conn_state)) {
998 			(void) iscsi_thread_send_wakeup(
999 			    icp->conn_tx_thread);
1000 		}
1001 		icp = icp->conn_next;
1002 	}
1003 }
1004 
1005 /*
1006  * iscsi_sess_state_machine -
1007  *
1008  * 7.3.1  Session State Diagram for an Initiator
1009  *
1010  *      Symbolic Names for States:
1011  *        Q1: FREE      - State on instantiation of after cleanup
1012  *        Q3: LOGGED_IN - Waiting for all session events.
1013  *        Q4: FAILED    - Waiting for session recovery or session cont.
1014  *        Q5: IN_FLUSH	- A login parameter has changed.  We are in the
1015  *			  process of flushing active, aborting, and
1016  *			  completed queues. Once flushed the iscsi_ic_thread()
1017  *			  will drop of drop connections (T14) and reconnect
1018  *			  to the target with new values.
1019  *	  Q6: FLUSHED	- Active, Aborting and Completed Queues flushed.
1020  *			  Awaiting reconnect or failure. iscsi_tx/ic_threads
1021  *			  are still running and might be timing-out IOs.
1022  *      State Q3/4 represent the Full Feature Phase operation of the session.
1023  *
1024  *      The state diagram is as follows:
1025  *
1026  *                                ------ (N5/6/7 == NOOP)
1027  *                               / Q1    \
1028  *    +------------------------->\       /<-------------+
1029  *    |                           ---+---               |
1030  *    |                     N5       |N1                |
1031  *    |  +------+   +-------------+  |                  |
1032  *    |  |      V   V             |  V                  |
1033  *    |  |      ----+--           -----+                |
1034  *    |N6|N5/7 / Q4    \         / Q3   \(N6 == NOOP)   |
1035  *    +--+-----\       /----+--->\      /-----+---------+
1036  *    |         -------    /N1    -+----      |       N3|
1037  *    |  (N7 == NOOP)     /      N7|  ^ N1/3/5|         |
1038  *    |                  /         |  +-------+         |
1039  *    |  +-------+      /          |                    |
1040  *    |  |       V     /           v                    |
1041  *    |  |      -------           -+----                |
1042  *    |N6|N6   / Q6    \    N5   / Q5   \               |
1043  *    +--+-----\       /<--------\      /-----+---------+
1044  *              -------           ------      |       N3
1045  *            (N7 == NOOP)            ^ N1/3/5|
1046  *                                    +-------+
1047  *
1048  * The state transition table is as follows:
1049  *
1050  *            +------+------+----+--------+----+
1051  *            |Q1    |Q3    |Q4  |Q5      |Q6  |
1052  *       -----+------+------+----+--------+----+
1053  *        Q1  |N5/6/7|N1    | -  |        |    |
1054  *       -----+------+------+----+--------+----+
1055  *        Q3  |N3    |N1/3/5|N5  |N7      |    |
1056  *       -----+------+------+----+--------+----+
1057  *        Q4  |N6    |N1    |N5/7|        |    |
1058  *       -----+------+------+----+--------+----+
1059  *        Q5  |N3    |      |    |N1/3/5/7|N6  |
1060  *       -----+------+------+----+--------+----+
1061  *        Q6  |N6    |N1    |N6/7|        |    |
1062  *       -----+------+------+----+--------+----+
1063  *
1064  * Event definitions:
1065  *
1066  * -N1: A connection logged in
1067  * -N3: A connection logged out
1068  * -N5: A connection failed
1069  * -N6: Session state timeout occurred, or a session
1070  *      reinstatement cleared this session instance.  This results in
1071  *      the freeing of all associated resources and the session state
1072  *      is discarded.
1073  * -N7: Login parameters for session have changed.
1074  *	Re-negeotation required.
1075  *
1076  * Any caller to the state machine (and so as a state writer) must
1077  * enter the state zone before calling this function, and vice versa
1078  * any caller that doesn't change the state machine shouldn't enter
1079  * the zone, and should act as a reader for a better performance.
1080  *
1081  * The handler of state transition shouldn't try to enter the state
1082  * zone in the same thread or dead lock will occur.
1083  */
1084 void
1085 iscsi_sess_state_machine(iscsi_sess_t *isp, iscsi_sess_event_t event,
1086     uint32_t event_count)
1087 {
1088 	ASSERT(isp != NULL);
1089 	ASSERT(rw_read_locked(&isp->sess_state_rwlock) == 0);
1090 
1091 	DTRACE_PROBE3(event, iscsi_sess_t *, isp,
1092 	    char *, iscsi_sess_state_str(isp->sess_state),
1093 	    char *, iscsi_sess_event_str(event));
1094 
1095 	/* Audit event */
1096 	idm_sm_audit_event(&isp->sess_state_audit,
1097 	    SAS_ISCSI_SESS, isp->sess_state, event, NULL);
1098 
1099 	isp->sess_prev_state = isp->sess_state;
1100 	isp->sess_state_lbolt = ddi_get_lbolt();
1101 
1102 	ISCSI_SESS_LOG(CE_NOTE,
1103 	    "DEBUG: sess_state: isp: %p state: %d event: %d event count: %d",
1104 	    (void *)isp, isp->sess_state, event, event_count);
1105 	switch (isp->sess_state) {
1106 	case ISCSI_SESS_STATE_FREE:
1107 		iscsi_sess_state_free(isp, event, event_count);
1108 		break;
1109 	case ISCSI_SESS_STATE_LOGGED_IN:
1110 		iscsi_sess_state_logged_in(isp, event, event_count);
1111 		break;
1112 	case ISCSI_SESS_STATE_FAILED:
1113 		iscsi_sess_state_failed(isp, event, event_count);
1114 		break;
1115 	case ISCSI_SESS_STATE_IN_FLUSH:
1116 		iscsi_sess_state_in_flush(isp, event, event_count);
1117 		break;
1118 	case ISCSI_SESS_STATE_FLUSHED:
1119 		iscsi_sess_state_flushed(isp, event, event_count);
1120 		break;
1121 	default:
1122 		ASSERT(FALSE);
1123 	}
1124 
1125 	/* Audit state change */
1126 	if (isp->sess_prev_state != isp->sess_state) {
1127 		idm_sm_audit_state_change(&isp->sess_state_audit,
1128 		    SAS_ISCSI_SESS, isp->sess_prev_state, isp->sess_state);
1129 	}
1130 }
1131 
1132 
1133 /*
1134  * iscsi_sess_state_str -
1135  *
1136  */
1137 char *
1138 iscsi_sess_state_str(iscsi_sess_state_t state)
1139 {
1140 	switch (state) {
1141 	case ISCSI_SESS_STATE_FREE:
1142 		return ("free");
1143 	case ISCSI_SESS_STATE_LOGGED_IN:
1144 		return ("logged_in");
1145 	case ISCSI_SESS_STATE_FAILED:
1146 		return ("failed");
1147 	case ISCSI_SESS_STATE_IN_FLUSH:
1148 		return ("in_flush");
1149 	case ISCSI_SESS_STATE_FLUSHED:
1150 		return ("flushed");
1151 	default:
1152 		return ("unknown");
1153 	}
1154 }
1155 
1156 
1157 /*
1158  * +--------------------------------------------------------------------+
1159  * | Internal Session Interfaces					|
1160  * +--------------------------------------------------------------------+
1161  */
1162 
1163 
1164 /*
1165  * iscsi_sess_state_free -
1166  *
1167  */
1168 static void
1169 iscsi_sess_state_free(iscsi_sess_t *isp, iscsi_sess_event_t event,
1170     uint32_t event_count)
1171 {
1172 	iscsi_hba_t		*ihp;
1173 	iscsi_enum_result_t	enum_result;
1174 
1175 	ASSERT(isp != NULL);
1176 	ihp = isp->sess_hba;
1177 	ASSERT(ihp != NULL);
1178 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FREE);
1179 
1180 	/* switch on event change */
1181 	switch (event) {
1182 	/*
1183 	 * -N1: A connection logged in
1184 	 */
1185 	case ISCSI_SESS_EVENT_N1:
1186 		isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN;
1187 		rw_downgrade(&isp->sess_state_rwlock);
1188 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1189 			cmn_err(CE_NOTE,
1190 			    "!iscsi session(%u) %s online\n",
1191 			    isp->sess_oid, isp->sess_name);
1192 			enum_result =
1193 			    iscsi_sess_enum_request(isp, B_TRUE,
1194 			    event_count);
1195 			if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
1196 				enum_result =
1197 				    iscsi_sess_enum_query(isp);
1198 			}
1199 			if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
1200 				iscsi_sess_enum_warn(isp, enum_result);
1201 			}
1202 		}
1203 		break;
1204 
1205 	/*
1206 	 * -N5: A connection failed
1207 	 */
1208 	case ISCSI_SESS_EVENT_N5:
1209 		/* NOOP - not connected */
1210 		break;
1211 
1212 	/*
1213 	 * -N6: Session state timeout occurred, or a session
1214 	 *	reinstatement cleared this session instance.  This results in
1215 	 *	the freeing of all associated resources and the session state
1216 	 *	is discarded.
1217 	 */
1218 	case ISCSI_SESS_EVENT_N6:
1219 		/* FALLTHRU */
1220 
1221 	/*
1222 	 * -N7: Login parameters for session have changed.
1223 	 *	Re-negeotation required.
1224 	 */
1225 	case ISCSI_SESS_EVENT_N7:
1226 		/* NOOP - not connected */
1227 		break;
1228 
1229 	/* All other events are invalid for this state */
1230 	default:
1231 		ASSERT(FALSE);
1232 	}
1233 }
1234 
1235 
1236 /*
1237  * iscsi_sess_logged_in -
1238  *
1239  */
1240 static void
1241 iscsi_sess_state_logged_in(iscsi_sess_t *isp, iscsi_sess_event_t event,
1242     uint32_t event_count)
1243 {
1244 	iscsi_enum_result_t	enum_result;
1245 
1246 	ASSERT(isp != NULL);
1247 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_LOGGED_IN);
1248 
1249 	/* switch on event change */
1250 	switch (event) {
1251 	/*
1252 	 * -N1: At least one transport connection reached the
1253 	 * LOGGED_IN state
1254 	 */
1255 	case ISCSI_SESS_EVENT_N1:
1256 		/*
1257 		 * A different connection already logged in.  If the
1258 		 * session is NORMAL, just re-enumerate the session.
1259 		 */
1260 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1261 			rw_downgrade(&isp->sess_state_rwlock);
1262 			enum_result =
1263 			    iscsi_sess_enum_request(isp, B_TRUE, event_count);
1264 			if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
1265 				enum_result = iscsi_sess_enum_query(isp);
1266 			}
1267 			if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
1268 				iscsi_sess_enum_warn(isp, enum_result);
1269 			}
1270 		}
1271 		break;
1272 
1273 	/*
1274 	 * -N3: A connection logged out.
1275 	 */
1276 	case ISCSI_SESS_EVENT_N3:
1277 		/* FALLTHRU */
1278 
1279 	/*
1280 	 * -N5: A connection failed
1281 	 */
1282 	case ISCSI_SESS_EVENT_N5:
1283 		/*
1284 		 * MC/S: If this is the last connection to
1285 		 * fail then move the the failed state.
1286 		 */
1287 		if (event == ISCSI_SESS_EVENT_N3) {
1288 			isp->sess_state = ISCSI_SESS_STATE_FREE;
1289 		} else {
1290 			isp->sess_state = ISCSI_SESS_STATE_FAILED;
1291 		}
1292 		rw_downgrade(&isp->sess_state_rwlock);
1293 
1294 		/* no longer connected reset nego tpgt */
1295 		isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT;
1296 
1297 		iscsi_sess_flush(isp);
1298 
1299 		if (event == ISCSI_SESS_EVENT_N3) {
1300 			if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1301 				cmn_err(CE_NOTE,
1302 				    "!iscsi session(%u) %s offline\n",
1303 				    isp->sess_oid, isp->sess_name);
1304 			}
1305 			/*
1306 			 * During the process of offlining the LUNs
1307 			 * our ic thread might be calling back into
1308 			 * the driver via a target driver failure
1309 			 * path to do a reset or something
1310 			 * we need to release the sess_state_mutex
1311 			 * while we are killing these threads so
1312 			 * they don't get deadlocked.
1313 			 */
1314 			iscsi_sess_offline_luns(isp);
1315 		}
1316 
1317 		mutex_enter(&isp->sess_reset_mutex);
1318 		isp->sess_reset_in_progress = B_FALSE;
1319 		mutex_exit(&isp->sess_reset_mutex);
1320 		/* update busy luns if needed */
1321 		iscsi_sess_update_busy_luns(isp, B_TRUE);
1322 
1323 		break;
1324 
1325 	/*
1326 	 * -N6: Session state timeout occurred, or a session
1327 	 *	reinstatement cleared this session instance.  This results in
1328 	 *	the freeing of all associated resources and the session state
1329 	 *	is discarded.
1330 	 */
1331 	case ISCSI_SESS_EVENT_N6:
1332 		/* NOOP - Not last connection */
1333 		break;
1334 
1335 	/*
1336 	 * -N7: Login parameters for session have changed.
1337 	 *	Re-negeotation required.
1338 	 */
1339 	case ISCSI_SESS_EVENT_N7:
1340 		isp->sess_state = ISCSI_SESS_STATE_IN_FLUSH;
1341 		break;
1342 
1343 	/* All other events are invalid for this state */
1344 	default:
1345 		ASSERT(FALSE);
1346 	}
1347 }
1348 
1349 
1350 /*
1351  * iscsi_sess_state_failed -
1352  *
1353  */
1354 static void
1355 iscsi_sess_state_failed(iscsi_sess_t *isp, iscsi_sess_event_t event,
1356     uint32_t event_count)
1357 {
1358 	iscsi_hba_t		*ihp;
1359 	iscsi_enum_result_t	enum_result;
1360 
1361 	ASSERT(isp != NULL);
1362 	ihp = isp->sess_hba;
1363 	ASSERT(ihp != NULL);
1364 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FAILED);
1365 
1366 	/* switch on event change */
1367 	switch (event) {
1368 	/* -N1: A session continuation attempt succeeded */
1369 	case ISCSI_SESS_EVENT_N1:
1370 		isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN;
1371 		rw_downgrade(&isp->sess_state_rwlock);
1372 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1373 			enum_result =
1374 			    iscsi_sess_enum_request(isp, B_TRUE,
1375 			    event_count);
1376 			if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
1377 				enum_result =
1378 				    iscsi_sess_enum_query(isp);
1379 			}
1380 			if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
1381 				iscsi_sess_enum_warn(isp, enum_result);
1382 			}
1383 		}
1384 		break;
1385 
1386 	/*
1387 	 * -N5: A connection failed
1388 	 */
1389 	case ISCSI_SESS_EVENT_N5:
1390 		/* NOOP - not connected */
1391 		break;
1392 
1393 	/*
1394 	 * -N6: Session state timeout occurred, or a session
1395 	 *	reinstatement cleared this session instance.  This results in
1396 	 *	the freeing of all associated resources and the session state
1397 	 *	is discarded.
1398 	 */
1399 	case ISCSI_SESS_EVENT_N6:
1400 		isp->sess_state = ISCSI_SESS_STATE_FREE;
1401 
1402 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1403 			cmn_err(CE_NOTE, "!iscsi session(%u) %s offline\n",
1404 			    isp->sess_oid, isp->sess_name);
1405 		}
1406 
1407 		rw_downgrade(&isp->sess_state_rwlock);
1408 		iscsi_sess_offline_luns(isp);
1409 		break;
1410 
1411 	/*
1412 	 * -N7: Login parameters for session have changed.
1413 	 *	Re-negeotation required.
1414 	 */
1415 	case ISCSI_SESS_EVENT_N7:
1416 		/* NOOP - not connected */
1417 		break;
1418 
1419 	/* All other events are invalid for this state */
1420 	default:
1421 		ASSERT(FALSE);
1422 	}
1423 }
1424 
1425 /*
1426  * iscsi_sess_state_in_flush -
1427  *
1428  */
1429 /* ARGSUSED */
1430 static void
1431 iscsi_sess_state_in_flush(iscsi_sess_t *isp, iscsi_sess_event_t event,
1432     uint32_t event_count)
1433 {
1434 	ASSERT(isp != NULL);
1435 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_IN_FLUSH);
1436 
1437 	/* switch on event change */
1438 	switch (event) {
1439 	/* -N1: A session continuation attempt succeeded */
1440 	case ISCSI_SESS_EVENT_N1:
1441 		/* NOOP - connections already online */
1442 		break;
1443 
1444 	/*
1445 	 * -N3: A connection logged out.
1446 	 */
1447 	case ISCSI_SESS_EVENT_N3:
1448 		/* FALLTHRU */
1449 
1450 	/*
1451 	 * -N5: A connection failed
1452 	 */
1453 	case ISCSI_SESS_EVENT_N5:
1454 		/*
1455 		 * MC/S: If this is the last connection to
1456 		 * fail then move the the failed state.
1457 		 */
1458 		if (event == ISCSI_SESS_EVENT_N3) {
1459 			isp->sess_state = ISCSI_SESS_STATE_FREE;
1460 		} else {
1461 			isp->sess_state = ISCSI_SESS_STATE_FLUSHED;
1462 		}
1463 		rw_downgrade(&isp->sess_state_rwlock);
1464 
1465 		/* no longer connected reset nego tpgt */
1466 		isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT;
1467 		iscsi_sess_flush(isp);
1468 
1469 		if (event == ISCSI_SESS_EVENT_N3) {
1470 			if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1471 				cmn_err(CE_NOTE,
1472 				    "!iscsi session(%u) %s offline\n",
1473 				    isp->sess_oid, isp->sess_name);
1474 			}
1475 			/*
1476 			 * During the process of offlining the LUNs
1477 			 * our ic thread might be calling back into
1478 			 * the driver via a target driver failure
1479 			 * path to do a reset or something
1480 			 * we need to release the sess_state_mutex
1481 			 * while we are killing these threads so
1482 			 * they don't get deadlocked.
1483 			 */
1484 			iscsi_sess_offline_luns(isp);
1485 		}
1486 
1487 		mutex_enter(&isp->sess_reset_mutex);
1488 		isp->sess_reset_in_progress = B_FALSE;
1489 		mutex_exit(&isp->sess_reset_mutex);
1490 		/* update busy luns if needed */
1491 		iscsi_sess_update_busy_luns(isp, B_TRUE);
1492 
1493 		break;
1494 
1495 	/*
1496 	 * -N6: Session state timeout occurred, or a session
1497 	 *	reinstatement cleared this session instance.  This results in
1498 	 *	the freeing of all associated resources and the session state
1499 	 *	is discarded.
1500 	 */
1501 	case ISCSI_SESS_EVENT_N6:
1502 		/* NOOP - Not last connection */
1503 		break;
1504 
1505 	/*
1506 	 * -N7: Login parameters for session have changed.
1507 	 *	Re-negeotation required.
1508 	 */
1509 	case ISCSI_SESS_EVENT_N7:
1510 		/* NOOP - Already attempting to update */
1511 		break;
1512 
1513 	/* All other events are invalid for this state */
1514 	default:
1515 		ASSERT(FALSE);
1516 	}
1517 }
1518 
1519 
1520 /*
1521  * iscsi_sess_state_flushed -
1522  *
1523  */
1524 static void
1525 iscsi_sess_state_flushed(iscsi_sess_t *isp, iscsi_sess_event_t event,
1526     uint32_t event_count)
1527 {
1528 	iscsi_hba_t	*ihp;
1529 	iscsi_enum_result_t	enum_result;
1530 
1531 	ASSERT(isp != NULL);
1532 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FLUSHED);
1533 	ihp = isp->sess_hba;
1534 	ASSERT(ihp != NULL);
1535 
1536 	/* switch on event change */
1537 	switch (event) {
1538 	/* -N1: A session continuation attempt succeeded */
1539 	case ISCSI_SESS_EVENT_N1:
1540 		isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN;
1541 		rw_downgrade(&isp->sess_state_rwlock);
1542 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1543 			enum_result =
1544 			    iscsi_sess_enum_request(isp, B_TRUE,
1545 			    event_count);
1546 			if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
1547 				enum_result =
1548 				    iscsi_sess_enum_query(isp);
1549 			}
1550 			if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
1551 				iscsi_sess_enum_warn(isp, enum_result);
1552 			}
1553 		}
1554 		break;
1555 
1556 	/*
1557 	 * -N6: Session state timeout occurred, or a session
1558 	 *	reinstatement cleared this session instance.  This results in
1559 	 *	the freeing of all associated resources and the session state
1560 	 *	is discarded.
1561 	 */
1562 	case ISCSI_SESS_EVENT_N6:
1563 		isp->sess_state = ISCSI_SESS_STATE_FREE;
1564 		rw_downgrade(&isp->sess_state_rwlock);
1565 
1566 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1567 			cmn_err(CE_NOTE, "!iscsi session(%u) %s offline\n",
1568 			    isp->sess_oid, isp->sess_name);
1569 		}
1570 
1571 		iscsi_sess_offline_luns(isp);
1572 		break;
1573 
1574 	/*
1575 	 * -N7: Login parameters for session have changed.
1576 	 *	Re-negeotation required.
1577 	 */
1578 	case ISCSI_SESS_EVENT_N7:
1579 		/* NOOP - not connected */
1580 		break;
1581 
1582 	/* All other events are invalid for this state */
1583 	default:
1584 		ASSERT(FALSE);
1585 	}
1586 }
1587 
1588 /*
1589  * iscsi_sess_event_str -
1590  *
1591  */
1592 static char *
1593 iscsi_sess_event_str(iscsi_sess_event_t event)
1594 {
1595 	switch (event) {
1596 	case ISCSI_SESS_EVENT_N1:
1597 		return ("N1");
1598 	case ISCSI_SESS_EVENT_N3:
1599 		return ("N3");
1600 	case ISCSI_SESS_EVENT_N5:
1601 		return ("N5");
1602 	case ISCSI_SESS_EVENT_N6:
1603 		return ("N6");
1604 	case ISCSI_SESS_EVENT_N7:
1605 		return ("N7");
1606 	default:
1607 		return ("unknown");
1608 	}
1609 }
1610 
1611 /*
1612  * iscsi_sess_thread_create -
1613  *
1614  */
1615 static iscsi_status_t
1616 iscsi_sess_threads_create(iscsi_sess_t *isp)
1617 {
1618 	iscsi_hba_t	*ihp;
1619 	char		th_name[ISCSI_TH_MAX_NAME_LEN];
1620 
1621 	ASSERT(isp != NULL);
1622 	ihp = isp->sess_hba;
1623 	ASSERT(ihp != NULL);
1624 
1625 	/* Completion thread creation. */
1626 	if (snprintf(th_name, sizeof (th_name) - 1,
1627 	    ISCSI_SESS_IOTH_NAME_FORMAT, ihp->hba_oid,
1628 	    isp->sess_oid) >= sizeof (th_name)) {
1629 		return (ISCSI_STATUS_INTERNAL_ERROR);
1630 	}
1631 
1632 	isp->sess_ic_thread = iscsi_thread_create(ihp->hba_dip,
1633 	    th_name, iscsi_ic_thread, isp);
1634 
1635 	if (isp->sess_ic_thread == NULL) {
1636 		return (ISCSI_STATUS_INTERNAL_ERROR);
1637 	}
1638 
1639 	(void) iscsi_thread_start(isp->sess_ic_thread);
1640 
1641 	return (ISCSI_STATUS_SUCCESS);
1642 }
1643 
1644 /*
1645  * iscsi_sess_enumeration - This function is used to drive the enumeration
1646  * of LUs on a session.  It will first prepare the target by sending test
1647  * unit ready commands, then it will issue a report luns.  If the report
1648  * luns is successful then it will process all the luns in the report.
1649  * If report luns is not successful we will do a stepping enumeration
1650  * of luns until no more luns are found.
1651  */
1652 static void
1653 iscsi_sess_enumeration(void *arg)
1654 {
1655 	iscsi_task_t		*itp = (iscsi_task_t *)arg;
1656 	iscsi_sess_t		*isp;
1657 	iscsi_status_t		rval    = ISCSI_STATUS_SUCCESS;
1658 	iscsi_enum_result_t	enum_result = ISCSI_SESS_ENUM_COMPLETE;
1659 	uint32_t		event_count = itp->t_event_count;
1660 
1661 	ASSERT(itp != NULL);
1662 	isp = (iscsi_sess_t *)itp->t_arg;
1663 	ASSERT(isp != NULL);
1664 
1665 	/*
1666 	 * Send initial TEST_UNIT_READY to target.  If it fails this we
1667 	 * stop our enumeration as the target is not responding properly.
1668 	 */
1669 	rval = iscsi_sess_testunitready(isp, event_count);
1670 	if (ISCSI_SUCCESS(rval)) {
1671 		/*
1672 		 * Now we know the target is ready start our enumeration with
1673 		 * REPORT LUNs, If this fails we will have to fall back to
1674 		 * stepping
1675 		 */
1676 		rval = iscsi_sess_reportluns(isp, event_count);
1677 		if (!ISCSI_SUCCESS(rval)) {
1678 			/*
1679 			 * report luns failed so lets just check for LUN 0.
1680 			 * This will match fcp's enumeration support and
1681 			 * avoid issues with older devices like the A5K that
1682 			 * respond poorly.
1683 			 */
1684 			if (isp->sess_lun_list == NULL) {
1685 				iscsi_sess_inquiry(isp, 0, 0, event_count,
1686 				    NULL);
1687 			}
1688 		}
1689 	} else {
1690 		enum_result = ISCSI_SESS_ENUM_TUR_FAIL;
1691 	}
1692 
1693 	kmem_free(itp, sizeof (iscsi_task_t));
1694 	mutex_enter(&isp->sess_enum_lock);
1695 	if (isp->sess_enum_result_count != 0) {
1696 		isp->sess_enum_status = ISCSI_SESS_ENUM_DONE;
1697 	} else {
1698 		isp->sess_enum_status = ISCSI_SESS_ENUM_FREE;
1699 	}
1700 	isp->sess_enum_result = enum_result;
1701 	cv_broadcast(&isp->sess_enum_cv);
1702 	mutex_exit(&isp->sess_enum_lock);
1703 }
1704 
1705 /*
1706  * iscsi_sess_testunitready - This is used during enumeration to
1707  * ensure an array is ready to be enumerated.
1708  */
1709 static iscsi_status_t
1710 iscsi_sess_testunitready(iscsi_sess_t *isp, uint32_t event_count)
1711 {
1712 	iscsi_status_t			rval		= ISCSI_STATUS_SUCCESS;
1713 	int				retries		= 0;
1714 	struct uscsi_cmd		ucmd;
1715 	char				cdb[CDB_GROUP0];
1716 
1717 	ASSERT(isp != NULL);
1718 
1719 	/* loop until successful sending test unit ready or retries out */
1720 	while ((retries++ < 3) &&
1721 	    (isp->sess_state_event_count == event_count)) {
1722 		/* cdb is all zeros */
1723 		bzero(&cdb[0], CDB_GROUP0);
1724 
1725 		/* setup uscsi cmd */
1726 		bzero(&ucmd, sizeof (struct uscsi_cmd));
1727 		ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
1728 		ucmd.uscsi_cdb		= &cdb[0];
1729 		ucmd.uscsi_cdblen	= CDB_GROUP0;
1730 
1731 		/* send test unit ready to lun zero on this session */
1732 		rval = iscsi_handle_passthru(isp, 0, &ucmd);
1733 
1734 		/*
1735 		 * If passthru was successful then we were able to
1736 		 * communicate with the target, continue enumeration.
1737 		 */
1738 		if (ISCSI_SUCCESS(rval)) {
1739 			break;
1740 		}
1741 	}
1742 
1743 	return (rval);
1744 }
1745 
1746 #define	SCSI_REPORTLUNS_ADDRESS_SIZE			8
1747 #define	SCSI_REPORTLUNS_ADDRESS_MASK			0xC0
1748 #define	SCSI_REPORTLUNS_ADDRESS_PERIPHERAL		0x00
1749 #define	SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE		0x40
1750 #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT		0x80
1751 #define	SCSI_REPORTLUNS_ADDRESS_EXTENDED_UNIT		0xC0
1752 #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_2B		0x00
1753 #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_4B		0x01
1754 #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_6B		0x10
1755 #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_8B		0x20
1756 #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_SIZE	0x30
1757 
1758 /*
1759  * iscsi_sess_reportluns - This is used during enumeration to
1760  * ensure an array is ready to be enumerated.
1761  */
1762 static iscsi_status_t
1763 iscsi_sess_reportluns(iscsi_sess_t *isp, uint32_t event_count)
1764 {
1765 	iscsi_status_t		rval		= ISCSI_STATUS_SUCCESS;
1766 	iscsi_hba_t		*ihp;
1767 	struct uscsi_cmd	ucmd;
1768 	unsigned char		cdb[CDB_GROUP5];
1769 	unsigned char		*buf		= NULL;
1770 	int			buf_len		= sizeof (struct scsi_inquiry);
1771 	uint32_t		lun_list_length = 0;
1772 	uint16_t		lun_num		= 0;
1773 	uint8_t			lun_addr_type	= 0;
1774 	uint32_t		lun_count	= 0;
1775 	uint32_t		lun_start	= 0;
1776 	uint32_t		lun_total	= 0;
1777 	int			retries		= 0;
1778 	iscsi_lun_t		*ilp_next;
1779 	iscsi_lun_t		*ilp		= NULL;
1780 	replun_data_t		*saved_replun_ptr = NULL;
1781 
1782 	ASSERT(isp != NULL);
1783 	ihp = isp->sess_hba;
1784 	ASSERT(ihp != NULL);
1785 
1786 	/*
1787 	 * Attempt to send report luns until we successfully
1788 	 * get all the data or the retries run out.
1789 	 */
1790 	while ((retries++ < 3) &&
1791 	    (isp->sess_state_event_count == event_count)) {
1792 		/*
1793 		 * Allocate our buffer based on current buf_len.
1794 		 * buf_len may change after we received a response
1795 		 * from the target.
1796 		 */
1797 		if (buf == NULL) {
1798 			buf = kmem_zalloc(buf_len, KM_SLEEP);
1799 		}
1800 
1801 		/* setup cdb */
1802 		bzero(&cdb, CDB_GROUP5);
1803 		cdb[0] = SCMD_REPORT_LUNS;
1804 		cdb[6] = (buf_len & 0xff000000) >> 24;
1805 		cdb[7] = (buf_len & 0x00ff0000) >> 16;
1806 		cdb[8] = (buf_len & 0x0000ff00) >> 8;
1807 		cdb[9] = (buf_len & 0x000000ff);
1808 
1809 		/* setup uscsi cmd */
1810 		bzero(&ucmd, sizeof (struct uscsi_cmd));
1811 		ucmd.uscsi_flags	= USCSI_READ;
1812 		ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
1813 		ucmd.uscsi_cdb		= (char *)&cdb[0];
1814 		ucmd.uscsi_cdblen	= CDB_GROUP5;
1815 		ucmd.uscsi_bufaddr	= (char *)buf;
1816 		ucmd.uscsi_buflen	= buf_len;
1817 
1818 		/* send uscsi cmd to lun 0 on session */
1819 		rval = iscsi_handle_passthru(isp, 0, &ucmd);
1820 
1821 		/* If passthru successful but not scsi status update istatus */
1822 		if (ISCSI_SUCCESS(rval) &&
1823 		    (ucmd.uscsi_status != STATUS_GOOD)) {
1824 			rval = ISCSI_STATUS_USCSI_FAILED;
1825 		}
1826 
1827 		/* If successful, check if we have all the data */
1828 		if (ISCSI_SUCCESS(rval)) {
1829 			/* total data - header (SCSI_REPORTLUNS_ADDRESS_SIZE) */
1830 			lun_list_length	= htonl(*(uint32_t *)buf);
1831 
1832 			if (buf_len >= lun_list_length +
1833 			    SCSI_REPORTLUNS_ADDRESS_SIZE) {
1834 				/* we have all the data, were done */
1835 				break;
1836 			}
1837 
1838 			/*
1839 			 * We don't have all the data.  free up the
1840 			 * memory for the next pass and update the
1841 			 * buf_len
1842 			 */
1843 			kmem_free(buf, buf_len);
1844 			buf = NULL;
1845 			buf_len = lun_list_length +
1846 			    SCSI_REPORTLUNS_ADDRESS_SIZE;
1847 		} else {
1848 			retries++;
1849 		}
1850 	}
1851 
1852 	if (isp->sess_state_event_count != event_count) {
1853 		if (buf != NULL) {
1854 			kmem_free(buf, buf_len);
1855 			buf = NULL;
1856 		}
1857 		return (rval);
1858 	}
1859 
1860 	/* If not successful go no further */
1861 	if (!ISCSI_SUCCESS(rval)) {
1862 		kmem_free(buf, buf_len);
1863 		return (rval);
1864 	}
1865 
1866 	/*
1867 	 * find out the number of luns returned by the SCSI ReportLun call
1868 	 * and allocate buffer space
1869 	 */
1870 	lun_total = lun_list_length / SCSI_REPORTLUNS_ADDRESS_SIZE;
1871 	saved_replun_ptr = kmem_zalloc(lun_total * sizeof (replun_data_t),
1872 	    KM_SLEEP);
1873 
1874 	/*
1875 	 * walk the isp->sess_lun_list
1876 	 * for each lun in this list
1877 	 *	look to see if this lun is in the SCSI ReportLun list we
1878 	 *	    just retrieved
1879 	 *	if it is in the SCSI ReportLun list and it is already ONLINE or
1880 	 *	if it is in the SCSI ReportLun list and it is OFFLINE or
1881 	 *	if it isn't in the SCSI ReportLunlist or then
1882 	 *	    issue the iscsi_sess_inquiry() to handle
1883 	 *
1884 	 *	as we walk the SCSI ReportLun list, we save this lun information
1885 	 *	    into the buffer we just allocated.  This will save us from
1886 	 *	    having to figure out this information later
1887 	 */
1888 	lun_start = 0;
1889 	rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
1890 	for (ilp = isp->sess_lun_list; ilp; ilp = ilp_next) {
1891 		if (isp->sess_state_event_count != event_count)
1892 			break;
1893 
1894 		ilp_next = ilp->lun_next;
1895 
1896 		for (lun_count = lun_start; lun_count < lun_total;
1897 		    lun_count++) {
1898 			/*
1899 			 * if the first lun in saved_replun_ptr buffer has
1900 			 * already been found we can move on and do not
1901 			 * have to check this lun in the future
1902 			 */
1903 			if (lun_count == lun_start &&
1904 			    saved_replun_ptr[lun_start].lun_found) {
1905 				lun_start++;
1906 				continue;
1907 			}
1908 			/*
1909 			 * check to see if the lun we are looking for is in the
1910 			 * saved_replun_ptr buffer
1911 			 * if it is, process the lun
1912 			 * if it isn't, then we must go to SCSI
1913 			 * Report Lun buffer
1914 			 * we retrieved to get lun info
1915 			 */
1916 			if ((saved_replun_ptr[lun_count].lun_valid
1917 			    == B_TRUE) &&
1918 			    (saved_replun_ptr[lun_count].lun_num
1919 			    == ilp->lun_num)) {
1920 				/*
1921 				 * the lun we are looking for is found,
1922 				 * give it to iscsi_sess_inquiry()
1923 				 */
1924 				rw_exit(&isp->sess_lun_list_rwlock);
1925 				iscsi_sess_inquiry(isp, ilp->lun_num,
1926 				    saved_replun_ptr[lun_count].lun_addr_type,
1927 				    event_count, ilp);
1928 				rw_enter(&isp->sess_lun_list_rwlock,
1929 				    RW_WRITER);
1930 				saved_replun_ptr[lun_count].lun_found
1931 				    = B_TRUE;
1932 				break;
1933 			} else {
1934 				/*
1935 				 * lun information is not found in the
1936 				 * saved_replun buffer, retrieve lun
1937 				 * information from the SCSI Report Lun buffer
1938 				 * and store this information in the
1939 				 * saved_replun buffer
1940 				 */
1941 				if (retrieve_lundata(lun_count, buf, isp,
1942 				    &lun_num, &lun_addr_type) !=
1943 				    ISCSI_STATUS_SUCCESS) {
1944 					continue;
1945 				}
1946 				saved_replun_ptr[lun_count].lun_valid = B_TRUE;
1947 				saved_replun_ptr[lun_count].lun_num = lun_num;
1948 				saved_replun_ptr[lun_count].lun_addr_type =
1949 				    lun_addr_type;
1950 				if (ilp->lun_num == lun_num) {
1951 					/*
1952 					 * lun is found in the SCSI Report Lun
1953 					 * buffer, give it to inquiry
1954 					 */
1955 					rw_exit(&isp->sess_lun_list_rwlock);
1956 					iscsi_sess_inquiry(isp, lun_num,
1957 					    lun_addr_type, event_count, ilp);
1958 					rw_enter(&isp->sess_lun_list_rwlock,
1959 					    RW_WRITER);
1960 					saved_replun_ptr[lun_count].lun_found
1961 					    = B_TRUE;
1962 					break;
1963 				}
1964 			}
1965 		}
1966 
1967 		if (lun_count == lun_total) {
1968 			/*
1969 			 * this lun we found in the sess->lun_list does
1970 			 * not exist anymore, need to offline this lun
1971 			 */
1972 
1973 			DTRACE_PROBE2(
1974 			    sess_reportluns_lun_no_longer_exists,
1975 			    int, ilp->lun_num, int, ilp->lun_state);
1976 
1977 			(void) iscsi_lun_destroy(ihp, ilp);
1978 		}
1979 	}
1980 	rw_exit(&isp->sess_lun_list_rwlock);
1981 	/*
1982 	 * look for new luns that we found in the SCSI Report Lun buffer that
1983 	 * we did not have in the sess->lun_list and add them into the list
1984 	 */
1985 	for (lun_count = lun_start; lun_count < lun_total; lun_count++) {
1986 		if (saved_replun_ptr[lun_count].lun_valid == B_FALSE) {
1987 			/*
1988 			 * lun information is not in the
1989 			 * saved_replun buffer, retrieve
1990 			 * it from the SCSI Report Lun buffer
1991 			 */
1992 			if (retrieve_lundata(lun_count, buf, isp,
1993 			    &lun_num, &lun_addr_type) != ISCSI_STATUS_SUCCESS) {
1994 				continue;
1995 			}
1996 		} else {
1997 			/*
1998 			 * lun information is in the saved_replun buffer
1999 			 * if this lun has been found already,
2000 			 * then we can move on
2001 			 */
2002 			if (saved_replun_ptr[lun_count].lun_found == B_TRUE) {
2003 				continue;
2004 			}
2005 			lun_num = saved_replun_ptr[lun_count].lun_num;
2006 			lun_addr_type =
2007 			    saved_replun_ptr[lun_count].lun_addr_type;
2008 		}
2009 
2010 
2011 		/* New luns found should not conflict with existing luns */
2012 		rw_enter(&isp->sess_lun_list_rwlock, RW_READER);
2013 		for (ilp = isp->sess_lun_list; ilp; ilp = ilp->lun_next) {
2014 			if (ilp->lun_num == lun_num) {
2015 				break;
2016 			}
2017 		}
2018 		rw_exit(&isp->sess_lun_list_rwlock);
2019 
2020 		if (ilp == NULL) {
2021 			/* new lun found, add this lun */
2022 			iscsi_sess_inquiry(isp, lun_num, lun_addr_type,
2023 			    event_count, NULL);
2024 		} else {
2025 			cmn_err(CE_NOTE,
2026 			    "!Duplicate Lun Number(%d) recieved from "
2027 			    "Target(%s)", lun_num, isp->sess_name);
2028 		}
2029 	}
2030 	if (buf != NULL) {
2031 		kmem_free(buf, buf_len);
2032 	}
2033 	kmem_free(saved_replun_ptr, lun_total * sizeof (replun_data_t));
2034 
2035 	return (rval);
2036 }
2037 
2038 #define	ISCSI_MAX_INQUIRY_BUF_SIZE	0xFF
2039 #define	ISCSI_MAX_INQUIRY_RETRIES	3
2040 
2041 /*
2042  * iscsi_sess_inquiry - Final processing of a LUN before we create a tgt
2043  * mapping, if necessary the old lun will be deleted.
2044  *
2045  * We need to collect the stardard inquiry page and the
2046  * vendor identification page for this LUN.  If both of these are
2047  * successful and the identification page contains a NAA or EUI type
2048  * we will continue.  Otherwise we fail the creation of a tgt for
2049  * this LUN.
2050  *
2051  * Keep the old lun unchanged if it is online and following things are
2052  * match, lun_addr_type, lun_type, and lun_guid.
2053  *
2054  * Online the old lun if it is offline/invalid and those three things
2055  * are match.
2056  *
2057  * Online a new lun if the old lun is offline and any of those three things
2058  * is not match, and needs to destroy the old first.
2059  *
2060  * Destroy the old lun and online the new lun if the old is online/invalid
2061  * and any of those three things is not match, and then online the new lun
2062  */
2063 static void
2064 iscsi_sess_inquiry(iscsi_sess_t *isp, uint16_t lun_num, uint8_t lun_addr_type,
2065     uint32_t event_count, iscsi_lun_t *ilp)
2066 {
2067 	iscsi_status_t		rval;
2068 	struct uscsi_cmd	ucmd;
2069 	uchar_t			cdb[CDB_GROUP0];
2070 	uchar_t			*inq;
2071 	size_t			inq_len;
2072 	uchar_t			*inq83;
2073 	size_t			inq83_len;
2074 	int			retries;
2075 	ddi_devid_t		devid;
2076 	char			*guid = NULL;
2077 	iscsi_hba_t		*ihp;
2078 	iscsi_status_t		status = ISCSI_STATUS_SUCCESS;
2079 	boolean_t		inq_ready = B_FALSE;
2080 	boolean_t		inq83_ready = B_FALSE;
2081 	boolean_t		nochange = B_FALSE;
2082 	uchar_t			lun_type;
2083 
2084 	ASSERT(isp != NULL);
2085 	ihp	= isp->sess_hba;
2086 	ASSERT(ihp != NULL);
2087 
2088 	inq	= kmem_zalloc(ISCSI_MAX_INQUIRY_BUF_SIZE, KM_SLEEP);
2089 	inq83	= kmem_zalloc(ISCSI_MAX_INQUIRY_BUF_SIZE, KM_SLEEP);
2090 
2091 	if (ilp == NULL) {
2092 		/* easy case, just to create the new lun */
2093 		goto sess_inq;
2094 	}
2095 
2096 	if (ilp->lun_addr_type != lun_addr_type) {
2097 		goto offline_old;
2098 	}
2099 
2100 	goto sess_inq;
2101 
2102 offline_old:
2103 	if (isp->sess_state_event_count != event_count) {
2104 		goto inq_done;
2105 	}
2106 
2107 	status = iscsi_lun_destroy(ihp, ilp);
2108 	if (status != ISCSI_STATUS_SUCCESS) {
2109 		/* have to abort the process */
2110 		cmn_err(CE_WARN, "iscsi session(%u) is unable to offline"
2111 		    " obsolete logical unit %d", isp->sess_oid, lun_num);
2112 		goto inq_done;
2113 	}
2114 	ilp = NULL;
2115 
2116 sess_inq:
2117 	if (inq_ready == B_TRUE) {
2118 		goto sess_inq83;
2119 	}
2120 	/*
2121 	 * STANDARD INQUIRY - We need the standard inquiry information
2122 	 * to feed into the scsi_hba_nodename_compatible_get function.
2123 	 * This function is used to detemine which driver will bind
2124 	 * on top of us, via the compatible id.
2125 	 */
2126 	bzero(&cdb, CDB_GROUP0);
2127 	cdb[0] = SCMD_INQUIRY;
2128 	cdb[4] = ISCSI_MAX_INQUIRY_BUF_SIZE;
2129 
2130 	bzero(&ucmd, sizeof (struct uscsi_cmd));
2131 	ucmd.uscsi_flags	= USCSI_READ;
2132 	ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
2133 	ucmd.uscsi_cdb		= (char *)&cdb[0];
2134 	ucmd.uscsi_cdblen	= CDB_GROUP0;
2135 	ucmd.uscsi_bufaddr	= (char *)inq;
2136 	ucmd.uscsi_buflen	= ISCSI_MAX_INQUIRY_BUF_SIZE;
2137 
2138 	/* Attempt to get inquiry information until successful or retries */
2139 	retries = 0;
2140 	while ((retries++ < ISCSI_MAX_INQUIRY_RETRIES) &&
2141 	    (isp->sess_state_event_count == event_count)) {
2142 		/* issue passthru */
2143 		rval = iscsi_handle_passthru(isp, lun_num, &ucmd);
2144 
2145 		/* If we were successful but scsi stat failed update istatus */
2146 		if (ISCSI_SUCCESS(rval) &&
2147 		    (ucmd.uscsi_status != STATUS_GOOD)) {
2148 			rval = ISCSI_STATUS_USCSI_FAILED;
2149 		}
2150 
2151 		/* If successful break */
2152 		if (ISCSI_SUCCESS(rval)) {
2153 			inq_len = ISCSI_MAX_INQUIRY_BUF_SIZE - ucmd.uscsi_resid;
2154 			break;
2155 		}
2156 
2157 		/* loop until we are successful or retries run out */
2158 	}
2159 
2160 	/* If failed don't continue */
2161 	if (!ISCSI_SUCCESS(rval)) {
2162 		cmn_err(CE_NOTE, "iscsi session(%u) unable to enumerate "
2163 		    "logical unit - inquiry failed lun %d",
2164 		    isp->sess_oid, lun_num);
2165 
2166 		goto inq_done;
2167 	}
2168 	inq_ready = B_TRUE;
2169 
2170 sess_inq83:
2171 	/*
2172 	 * T-10 SPC Section 6.4.2.  Standard INQUIRY Peripheral
2173 	 * qualifier of 000b is the only type we should attempt
2174 	 * to plumb under the IO stack.
2175 	 */
2176 	if ((inq[0] & SCSI_INQUIRY_PQUAL_MASK) != 0x00) {
2177 		/* shouldn't enumerate, destroy the old one if exists */
2178 		if (ilp != NULL) {
2179 			goto offline_old;
2180 		}
2181 		goto inq_done;
2182 	}
2183 
2184 	/*
2185 	 * If lun type has changed
2186 	 */
2187 	lun_type = ((struct scsi_inquiry *)inq)->inq_dtype & DTYPE_MASK;
2188 	if ((ilp != NULL) && (ilp->lun_type != lun_type)) {
2189 		goto offline_old;
2190 	}
2191 
2192 	if (inq83_ready == B_TRUE) {
2193 		goto guid_ready;
2194 	}
2195 
2196 	/*
2197 	 * VENDOR IDENTIFICATION INQUIRY - This will be used to identify
2198 	 * a unique lunId.  This Id is passed to the mdi alloc calls so
2199 	 * we can properly plumb into scsi_vhci/mpxio.
2200 	 */
2201 
2202 	bzero(&cdb, CDB_GROUP0);
2203 	cdb[0] = SCMD_INQUIRY;
2204 	cdb[1] = 0x01; /* EVP bit */
2205 	cdb[2] = 0x83;
2206 	cdb[4] = ISCSI_MAX_INQUIRY_BUF_SIZE;
2207 
2208 	ucmd.uscsi_flags	= USCSI_READ;
2209 	ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
2210 	ucmd.uscsi_cdb		= (char *)&cdb[0];
2211 	ucmd.uscsi_cdblen	= CDB_GROUP0;
2212 	ucmd.uscsi_bufaddr	= (char *)inq83;
2213 	ucmd.uscsi_buflen	= ISCSI_MAX_INQUIRY_BUF_SIZE;
2214 
2215 	/* Attempt to get inquiry information until successful or retries */
2216 	retries = 0;
2217 	while ((retries++ < ISCSI_MAX_INQUIRY_RETRIES) &&
2218 	    (isp->sess_state_event_count == event_count)) {
2219 		/* issue passthru command */
2220 		rval = iscsi_handle_passthru(isp, lun_num, &ucmd);
2221 
2222 		/* If we were successful but scsi stat failed update istatus */
2223 		if (ISCSI_SUCCESS(rval) &&
2224 		    (ucmd.uscsi_status != STATUS_GOOD)) {
2225 			rval = ISCSI_STATUS_USCSI_FAILED;
2226 		}
2227 
2228 		/* Break if successful */
2229 		if (ISCSI_SUCCESS(rval)) {
2230 			inq83_len = ISCSI_MAX_INQUIRY_BUF_SIZE -
2231 			    ucmd.uscsi_resid;
2232 			break;
2233 		}
2234 	}
2235 
2236 	/*
2237 	 * If we were successful collecting page 83 data attempt
2238 	 * to generate a GUID.  If no GUID can be generated then
2239 	 * the logical unit will skip attempt to plumb under
2240 	 * scsi_vhci/mpxio.
2241 	 */
2242 	if (ISCSI_SUCCESS(rval)) {
2243 		/* create DEVID from inquiry data */
2244 		if (ddi_devid_scsi_encode(
2245 		    DEVID_SCSI_ENCODE_VERSION_LATEST, NULL,
2246 		    inq, inq_len, NULL, 0, inq83, inq83_len, &devid) ==
2247 		    DDI_SUCCESS) {
2248 
2249 			/* extract GUID from DEVID */
2250 			guid = ddi_devid_to_guid(devid);
2251 
2252 			/* devid no longer needed */
2253 			ddi_devid_free(devid);
2254 		}
2255 	}
2256 	inq83_ready = B_TRUE;
2257 
2258 guid_ready:
2259 
2260 	if (ilp != NULL) {
2261 		if ((guid == NULL) && (ilp->lun_guid == NULL)) {
2262 			nochange = B_TRUE;
2263 		}
2264 
2265 		if ((guid != NULL) && (ilp->lun_guid != NULL) &&
2266 		    ((strlen(guid) + 1) == ilp->lun_guid_size) &&
2267 		    (bcmp(guid, ilp->lun_guid, ilp->lun_guid_size) == 0)) {
2268 			nochange = B_TRUE;
2269 		}
2270 
2271 		if (nochange != B_TRUE) {
2272 			goto offline_old;
2273 		}
2274 
2275 		if (ilp->lun_state & (ISCSI_LUN_STATE_OFFLINE |
2276 		    ISCSI_LUN_STATE_INVALID)) {
2277 			if (isp->sess_state_event_count == event_count) {
2278 				(void) iscsi_lun_online(ihp, ilp);
2279 			}
2280 		}
2281 	} else {
2282 		if (isp->sess_state_event_count == event_count) {
2283 			(void) iscsi_lun_create(isp, lun_num, lun_addr_type,
2284 			    (struct scsi_inquiry *)inq, guid);
2285 		}
2286 	}
2287 
2288 inq_done:
2289 	if (guid != NULL) {
2290 		/* guid is no longer needed */
2291 		ddi_devid_free_guid(guid);
2292 	}
2293 
2294 	/* free up memory now that we are done */
2295 	kmem_free(inq, ISCSI_MAX_INQUIRY_BUF_SIZE);
2296 	kmem_free(inq83, ISCSI_MAX_INQUIRY_BUF_SIZE);
2297 }
2298 
2299 static iscsi_status_t
2300 retrieve_lundata(uint32_t lun_count, unsigned char *buf, iscsi_sess_t *isp,
2301     uint16_t *lun_num, uint8_t *lun_addr_type)
2302 {
2303 	uint32_t		lun_idx		= 0;
2304 
2305 	ASSERT(lun_num != NULL);
2306 	ASSERT(lun_addr_type != NULL);
2307 
2308 	lun_idx = (lun_count + 1) * SCSI_REPORTLUNS_ADDRESS_SIZE;
2309 	/* determine report luns addressing type */
2310 	switch (buf[lun_idx] & SCSI_REPORTLUNS_ADDRESS_MASK) {
2311 		/*
2312 		 * Vendors in the field have been found to be concatenating
2313 		 * bus/target/lun to equal the complete lun value instead
2314 		 * of switching to flat space addressing
2315 		 */
2316 		/* 00b - peripheral device addressing method */
2317 		case SCSI_REPORTLUNS_ADDRESS_PERIPHERAL:
2318 			/* FALLTHRU */
2319 		/* 10b - logical unit addressing method */
2320 		case SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT:
2321 			/* FALLTHRU */
2322 		/* 01b - flat space addressing method */
2323 		case SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE:
2324 			/* byte0 bit0-5=msb lun byte1 bit0-7=lsb lun */
2325 			*lun_addr_type = (buf[lun_idx] &
2326 			    SCSI_REPORTLUNS_ADDRESS_MASK) >> 6;
2327 			*lun_num = (buf[lun_idx] & 0x3F) << 8;
2328 			*lun_num |= buf[lun_idx + 1];
2329 			return (ISCSI_STATUS_SUCCESS);
2330 		default: /* protocol error */
2331 			cmn_err(CE_NOTE, "iscsi session(%u) unable "
2332 			    "to enumerate logical units - report "
2333 			    "luns returned an unsupported format",
2334 			    isp->sess_oid);
2335 			break;
2336 	}
2337 	return (ISCSI_STATUS_INTERNAL_ERROR);
2338 }
2339 
2340 /*
2341  * iscsi_sess_flush - flushes remaining pending io on the session
2342  */
2343 static void
2344 iscsi_sess_flush(iscsi_sess_t *isp)
2345 {
2346 	iscsi_cmd_t	*icmdp;
2347 
2348 	ASSERT(isp != NULL);
2349 	ASSERT(isp->sess_state != ISCSI_SESS_STATE_LOGGED_IN);
2350 
2351 	/*
2352 	 * Flush out any remaining commands in the pending
2353 	 * queue.
2354 	 */
2355 	mutex_enter(&isp->sess_queue_pending.mutex);
2356 	icmdp = isp->sess_queue_pending.head;
2357 	while (icmdp != NULL) {
2358 		if (isp->sess_state == ISCSI_SESS_STATE_FAILED) {
2359 			mutex_enter(&icmdp->cmd_mutex);
2360 			if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
2361 				icmdp->cmd_un.scsi.pkt_stat |= STAT_ABORTED;
2362 			}
2363 			mutex_exit(&icmdp->cmd_mutex);
2364 		}
2365 
2366 		iscsi_cmd_state_machine(icmdp,
2367 		    ISCSI_CMD_EVENT_E7, isp);
2368 		icmdp = isp->sess_queue_pending.head;
2369 	}
2370 	mutex_exit(&isp->sess_queue_pending.mutex);
2371 }
2372 
2373 /*
2374  * iscsi_sess_offline_luns - offline all this sessions luns
2375  */
2376 static void
2377 iscsi_sess_offline_luns(iscsi_sess_t *isp)
2378 {
2379 	iscsi_lun_t	*ilp;
2380 	iscsi_hba_t	*ihp;
2381 
2382 	ASSERT(isp != NULL);
2383 	ASSERT(isp->sess_state != ISCSI_SESS_STATE_LOGGED_IN);
2384 	ihp = isp->sess_hba;
2385 	ASSERT(ihp != NULL);
2386 
2387 	rw_enter(&isp->sess_lun_list_rwlock, RW_READER);
2388 	ilp = isp->sess_lun_list;
2389 	while (ilp != NULL) {
2390 		(void) iscsi_lun_offline(ihp, ilp, B_FALSE);
2391 		ilp = ilp->lun_next;
2392 	}
2393 	rw_exit(&isp->sess_lun_list_rwlock);
2394 }
2395 
2396 /*
2397  * iscsi_sess_get_by_target - return the session structure for based on a
2398  * passed in target oid and hba instance.  NOTE:  There may be
2399  * multiple sessions associated with any given target.  In this case,
2400  * we will return the first matching session.  This function
2401  * is intended to be used in retrieving target info that is constant
2402  * across sessions (target name, alias, etc.).
2403  */
2404 int
2405 iscsi_sess_get_by_target(uint32_t target_oid, iscsi_hba_t *ihp,
2406     iscsi_sess_t **ispp)
2407 {
2408 	int rval = 0;
2409 	iscsi_sess_t *isp = NULL;
2410 
2411 	ASSERT(ihp != NULL);
2412 	ASSERT(ispp != NULL);
2413 
2414 	/* See if we already created this session */
2415 	for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
2416 		/*
2417 		 * Look for a session associated to the given target.
2418 		 * Return the first one found.
2419 		 */
2420 		if (isp->sess_target_oid == target_oid) {
2421 			/* Found matching session */
2422 			break;
2423 		}
2424 	}
2425 
2426 	/* If not null this session is already available */
2427 	if (isp != NULL) {
2428 		/* Existing session, return it */
2429 		*ispp = isp;
2430 	} else {
2431 		rval = EFAULT;
2432 	}
2433 	return (rval);
2434 }
2435 
2436 static void
2437 iscsi_sess_update_busy_luns(iscsi_sess_t *isp, boolean_t clear)
2438 {
2439 	iscsi_lun_t	*ilp;
2440 	iscsi_hba_t	*ihp;
2441 
2442 	ASSERT(isp != NULL);
2443 	ihp = isp->sess_hba;
2444 	ASSERT(ihp != NULL);
2445 
2446 	rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
2447 	ilp = isp->sess_lun_list;
2448 	while (ilp != NULL) {
2449 		if (clear == B_TRUE) {
2450 			ilp->lun_state &= ~ISCSI_LUN_STATE_BUSY;
2451 		} else {
2452 			ilp->lun_state |= ISCSI_LUN_STATE_BUSY;
2453 		}
2454 		ilp = ilp->lun_next;
2455 	}
2456 	rw_exit(&isp->sess_lun_list_rwlock);
2457 }
2458 
2459 /*
2460  * Submits the scsi enumeration request. Returns
2461  * ISCSI_SESS_ENUM_SUBMITTED upon success, or others if failures are met.
2462  * If the request is submitted and the wait is set to B_TRUE, the caller
2463  * must call iscsi_sess_enum_query at a later time to unblock next enum
2464  */
2465 iscsi_enum_result_t
2466 iscsi_sess_enum_request(iscsi_sess_t *isp, boolean_t wait,
2467     uint32_t event_count) {
2468 	iscsi_task_t		*itp;
2469 
2470 	itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
2471 	itp->t_arg = isp;
2472 	itp->t_event_count = event_count;
2473 
2474 	mutex_enter(&isp->sess_enum_lock);
2475 	while ((isp->sess_enum_status != ISCSI_SESS_ENUM_FREE) &&
2476 	    (isp->sess_enum_status != ISCSI_SESS_ENUM_INPROG)) {
2477 		cv_wait(&isp->sess_enum_cv, &isp->sess_enum_lock);
2478 	}
2479 	if (isp->sess_enum_status == ISCSI_SESS_ENUM_INPROG) {
2480 		/* easy case */
2481 		if (wait == B_TRUE) {
2482 			isp->sess_enum_result_count ++;
2483 		}
2484 		mutex_exit(&isp->sess_enum_lock);
2485 		kmem_free(itp, sizeof (iscsi_task_t));
2486 		return (ISCSI_SESS_ENUM_SUBMITTED);
2487 	}
2488 
2489 	ASSERT(isp->sess_enum_status == ISCSI_SESS_ENUM_FREE);
2490 	ASSERT(isp->sess_enum_result_count == 0);
2491 
2492 	isp->sess_enum_status = ISCSI_SESS_ENUM_INPROG;
2493 	if (ddi_taskq_dispatch(isp->sess_enum_taskq,
2494 	    iscsi_sess_enumeration, itp, DDI_SLEEP) != DDI_SUCCESS) {
2495 		isp->sess_enum_status = ISCSI_SESS_ENUM_FREE;
2496 		mutex_exit(&isp->sess_enum_lock);
2497 		kmem_free(itp, sizeof (iscsi_task_t));
2498 		return (ISCSI_SESS_ENUM_SUBFAIL);
2499 	}
2500 	if (wait == B_TRUE) {
2501 		isp->sess_enum_result_count ++;
2502 	}
2503 	mutex_exit(&isp->sess_enum_lock);
2504 	return (ISCSI_SESS_ENUM_SUBMITTED);
2505 }
2506 
2507 /*
2508  * Wait and query the result of the enumeration.
2509  * The last caller is responsible for kicking off the DONE status
2510  */
2511 iscsi_enum_result_t
2512 iscsi_sess_enum_query(iscsi_sess_t *isp) {
2513 	iscsi_enum_result_t	ret = ISCSI_SESS_ENUM_IOFAIL;
2514 
2515 	mutex_enter(&isp->sess_enum_lock);
2516 	while (isp->sess_enum_status != ISCSI_SESS_ENUM_DONE) {
2517 		cv_wait(&isp->sess_enum_cv, &isp->sess_enum_lock);
2518 	}
2519 	ret = isp->sess_enum_result;
2520 	isp->sess_enum_result_count --;
2521 	if (isp->sess_enum_result_count == 0) {
2522 		isp->sess_enum_status = ISCSI_SESS_ENUM_FREE;
2523 		cv_broadcast(&isp->sess_enum_cv);
2524 	}
2525 	mutex_exit(&isp->sess_enum_lock);
2526 
2527 	return (ret);
2528 }
2529 
2530 static void
2531 iscsi_sess_enum_warn(iscsi_sess_t *isp, iscsi_enum_result_t r) {
2532 	cmn_err(CE_WARN, "iscsi session (%u) enumeration fails - %s",
2533 	    isp->sess_oid, iscsi_sess_enum_warn_msgs[r]);
2534 }
2535 
2536 void
2537 iscsi_sess_enter_state_zone(iscsi_sess_t *isp) {
2538 	mutex_enter(&isp->sess_state_wmutex);
2539 	while (isp->sess_state_hasw == B_TRUE) {
2540 		cv_wait(&isp->sess_state_wcv, &isp->sess_state_wmutex);
2541 	}
2542 	isp->sess_state_hasw = B_TRUE;
2543 	mutex_exit(&isp->sess_state_wmutex);
2544 
2545 	rw_enter(&isp->sess_state_rwlock, RW_WRITER);
2546 }
2547 
2548 void
2549 iscsi_sess_exit_state_zone(iscsi_sess_t *isp) {
2550 	rw_exit(&isp->sess_state_rwlock);
2551 
2552 	mutex_enter(&isp->sess_state_wmutex);
2553 	isp->sess_state_hasw = B_FALSE;
2554 	cv_signal(&isp->sess_state_wcv);
2555 	mutex_exit(&isp->sess_state_wmutex);
2556 }
2557