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