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