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 			iscsi_sess_offline_luns(isp);
1150 		}
1151 
1152 		/*
1153 		 * During the process of offlining the LUNs our ic
1154 		 * thread might be calling back into the driver via
1155 		 * a target driver failure path to do a reset or something
1156 		 * we need to release the sess_state_mutex while we
1157 		 * are killing these threads to they don't get deadlocked.
1158 		 */
1159 		mutex_exit(&isp->sess_state_mutex);
1160 		iscsi_thread_destroy(isp->sess_ic_thread);
1161 		mutex_enter(&isp->sess_state_mutex);
1162 		break;
1163 
1164 	/*
1165 	 * -N6: Session state timeout occurred, or a session
1166 	 *	reinstatement cleared this session instance.  This results in
1167 	 *	the freeing of all associated resources and the session state
1168 	 *	is discarded.
1169 	 */
1170 	case ISCSI_SESS_EVENT_N6:
1171 		/* NOOP - Not last connection */
1172 		break;
1173 
1174 	/*
1175 	 * -N7: Login parameters for session have changed.
1176 	 *	Re-negeotation required.
1177 	 */
1178 	case ISCSI_SESS_EVENT_N7:
1179 		isp->sess_state = ISCSI_SESS_STATE_IN_FLUSH;
1180 		break;
1181 
1182 	/* All other events are invalid for this state */
1183 	default:
1184 		ASSERT(FALSE);
1185 	}
1186 }
1187 
1188 
1189 /*
1190  * iscsi_sess_state_failed -
1191  *
1192  */
1193 static void
1194 iscsi_sess_state_failed(iscsi_sess_t *isp, iscsi_sess_event_t event)
1195 {
1196 	iscsi_status_t		rval;
1197 	iscsi_hba_t		*ihp;
1198 	iscsi_task_t		*itp;
1199 
1200 	ASSERT(isp != NULL);
1201 	ihp = isp->sess_hba;
1202 	ASSERT(ihp != NULL);
1203 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FAILED);
1204 
1205 	/* switch on event change */
1206 	switch (event) {
1207 	/* -N1: A session continuation attempt succeeded */
1208 	case ISCSI_SESS_EVENT_N1:
1209 		rval = iscsi_sess_threads_create(isp);
1210 		if (ISCSI_SUCCESS(rval)) {
1211 			isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN;
1212 			if ((isp->sess_type == ISCSI_SESS_TYPE_NORMAL) &&
1213 			    (isp->sess_enum_in_progress == B_FALSE)) {
1214 				isp->sess_enum_in_progress = B_TRUE;
1215 				mutex_exit(&isp->sess_state_mutex);
1216 
1217 				/* start enumeration */
1218 				itp = kmem_zalloc(sizeof (iscsi_task_t),
1219 				    KM_SLEEP);
1220 				itp->t_arg = isp;
1221 				itp->t_blocking = B_FALSE;
1222 				if (ddi_taskq_dispatch(isp->sess_taskq,
1223 				    iscsi_sess_enumeration, itp, DDI_SLEEP) !=
1224 				    DDI_SUCCESS) {
1225 					kmem_free(itp, sizeof (iscsi_task_t));
1226 					cmn_err(CE_WARN,
1227 					    "iscsi connection (%u) failure - "
1228 					    "unable to schedule enumeration",
1229 					    isp->sess_oid);
1230 				}
1231 
1232 				mutex_enter(&isp->sess_state_mutex);
1233 				isp->sess_enum_in_progress = B_FALSE;
1234 			}
1235 		} else {
1236 			isp->sess_state = ISCSI_SESS_STATE_FREE;
1237 			ASSERT(FALSE);
1238 		}
1239 		break;
1240 
1241 	/*
1242 	 * -N6: Session state timeout occurred, or a session
1243 	 *	reinstatement cleared this session instance.  This results in
1244 	 *	the freeing of all associated resources and the session state
1245 	 *	is discarded.
1246 	 */
1247 	case ISCSI_SESS_EVENT_N6:
1248 		isp->sess_state = ISCSI_SESS_STATE_FREE;
1249 
1250 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1251 			cmn_err(CE_NOTE, "!iscsi session(%u) %s offline\n",
1252 			    isp->sess_oid, isp->sess_name);
1253 		}
1254 
1255 		mutex_exit(&isp->sess_state_mutex);
1256 		iscsi_sess_offline_luns(isp);
1257 		mutex_enter(&isp->sess_state_mutex);
1258 		break;
1259 
1260 	/*
1261 	 * -N7: Login parameters for session have changed.
1262 	 *	Re-negeotation required.
1263 	 */
1264 	case ISCSI_SESS_EVENT_N7:
1265 		/* NOOP - not connected */
1266 		break;
1267 
1268 	/* All other events are invalid for this state */
1269 	default:
1270 		ASSERT(FALSE);
1271 	}
1272 }
1273 
1274 
1275 /*
1276  * iscsi_sess_state_in_flush -
1277  *
1278  */
1279 static void
1280 iscsi_sess_state_in_flush(iscsi_sess_t *isp, iscsi_sess_event_t event)
1281 {
1282 	ASSERT(isp != NULL);
1283 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_IN_FLUSH);
1284 
1285 	/* switch on event change */
1286 	switch (event) {
1287 	/* -N1: A session continuation attempt succeeded */
1288 	case ISCSI_SESS_EVENT_N1:
1289 		/* NOOP - connections already online */
1290 		break;
1291 
1292 	/*
1293 	 * -N3: A connection logged out.
1294 	 */
1295 	case ISCSI_SESS_EVENT_N3:
1296 		/* FALLTHRU */
1297 
1298 	/*
1299 	 * -N5: A connection failed
1300 	 */
1301 	case ISCSI_SESS_EVENT_N5:
1302 		/*
1303 		 * MC/S: If this is the last connection to
1304 		 * fail then move the the failed state.
1305 		 */
1306 		if (event == ISCSI_SESS_EVENT_N3) {
1307 			isp->sess_state = ISCSI_SESS_STATE_FREE;
1308 		} else {
1309 			isp->sess_state = ISCSI_SESS_STATE_FLUSHED;
1310 		}
1311 
1312 		/* no longer connected reset nego tpgt */
1313 		isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT;
1314 		iscsi_sess_flush(isp);
1315 
1316 		if (event == ISCSI_SESS_EVENT_N3) {
1317 			if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1318 				cmn_err(CE_NOTE,
1319 				    "!iscsi session(%u) %s offline\n",
1320 				    isp->sess_oid, isp->sess_name);
1321 			}
1322 			iscsi_sess_offline_luns(isp);
1323 		}
1324 
1325 		/*
1326 		 * During the process of offlining the LUNs our ic
1327 		 * thread might be calling back into the driver via
1328 		 * a target driver failure path to do a reset or something
1329 		 * we need to release the sess_state_mutex while we
1330 		 * are killing these threads to they don't get deadlocked.
1331 		 */
1332 		mutex_exit(&isp->sess_state_mutex);
1333 		iscsi_thread_destroy(isp->sess_ic_thread);
1334 		mutex_enter(&isp->sess_state_mutex);
1335 		break;
1336 
1337 	/*
1338 	 * -N6: Session state timeout occurred, or a session
1339 	 *	reinstatement cleared this session instance.  This results in
1340 	 *	the freeing of all associated resources and the session state
1341 	 *	is discarded.
1342 	 */
1343 	case ISCSI_SESS_EVENT_N6:
1344 		/* NOOP - Not last connection */
1345 		break;
1346 
1347 	/*
1348 	 * -N7: Login parameters for session have changed.
1349 	 *	Re-negeotation required.
1350 	 */
1351 	case ISCSI_SESS_EVENT_N7:
1352 		/* NOOP - Already attempting to update */
1353 		break;
1354 
1355 	/* All other events are invalid for this state */
1356 	default:
1357 		ASSERT(FALSE);
1358 	}
1359 }
1360 
1361 
1362 /*
1363  * iscsi_sess_state_flushed -
1364  *
1365  */
1366 static void
1367 iscsi_sess_state_flushed(iscsi_sess_t *isp, iscsi_sess_event_t event)
1368 {
1369 	iscsi_status_t	rval;
1370 	iscsi_hba_t	*ihp;
1371 	iscsi_task_t	*itp;
1372 
1373 	ASSERT(isp != NULL);
1374 	ASSERT(isp->sess_state == ISCSI_SESS_STATE_FLUSHED);
1375 	ihp = isp->sess_hba;
1376 	ASSERT(ihp != NULL);
1377 
1378 	/* switch on event change */
1379 	switch (event) {
1380 	/* -N1: A session continuation attempt succeeded */
1381 	case ISCSI_SESS_EVENT_N1:
1382 		rval = iscsi_sess_threads_create(isp);
1383 		if (ISCSI_SUCCESS(rval)) {
1384 			isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN;
1385 			if ((isp->sess_type == ISCSI_SESS_TYPE_NORMAL) &&
1386 			    (isp->sess_enum_in_progress == B_FALSE)) {
1387 				isp->sess_enum_in_progress = B_TRUE;
1388 				mutex_exit(&isp->sess_state_mutex);
1389 
1390 				/* start enumeration */
1391 				itp = kmem_zalloc(sizeof (iscsi_task_t),
1392 				    KM_SLEEP);
1393 				itp->t_arg = isp;
1394 				itp->t_blocking = B_FALSE;
1395 				if (ddi_taskq_dispatch(isp->sess_taskq,
1396 				    iscsi_sess_enumeration, itp, DDI_SLEEP) !=
1397 				    DDI_SUCCESS) {
1398 					kmem_free(itp, sizeof (iscsi_task_t));
1399 					cmn_err(CE_WARN,
1400 					    "iscsi connection (%u) failure - "
1401 					    "unable to schedule enumeration",
1402 					    isp->sess_oid);
1403 				}
1404 
1405 				mutex_enter(&isp->sess_state_mutex);
1406 				isp->sess_enum_in_progress = B_FALSE;
1407 			}
1408 		} else {
1409 			isp->sess_state = ISCSI_SESS_STATE_FREE;
1410 			ASSERT(FALSE);
1411 		}
1412 		break;
1413 
1414 	/*
1415 	 * -N6: Session state timeout occurred, or a session
1416 	 *	reinstatement cleared this session instance.  This results in
1417 	 *	the freeing of all associated resources and the session state
1418 	 *	is discarded.
1419 	 */
1420 	case ISCSI_SESS_EVENT_N6:
1421 		isp->sess_state = ISCSI_SESS_STATE_FREE;
1422 
1423 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1424 			cmn_err(CE_NOTE, "!iscsi session(%u) %s offline\n",
1425 			    isp->sess_oid, isp->sess_name);
1426 		}
1427 
1428 		mutex_exit(&isp->sess_state_mutex);
1429 		iscsi_sess_offline_luns(isp);
1430 		mutex_enter(&isp->sess_state_mutex);
1431 		break;
1432 
1433 	/*
1434 	 * -N7: Login parameters for session have changed.
1435 	 *	Re-negeotation required.
1436 	 */
1437 	case ISCSI_SESS_EVENT_N7:
1438 		/* NOOP - not connected */
1439 		break;
1440 
1441 	/* All other events are invalid for this state */
1442 	default:
1443 		ASSERT(FALSE);
1444 	}
1445 }
1446 
1447 /*
1448  * iscsi_sess_event_str -
1449  *
1450  */
1451 static char *
1452 iscsi_sess_event_str(iscsi_sess_event_t event)
1453 {
1454 	switch (event) {
1455 	case ISCSI_SESS_EVENT_N1:
1456 		return ("N1");
1457 	case ISCSI_SESS_EVENT_N3:
1458 		return ("N3");
1459 	case ISCSI_SESS_EVENT_N5:
1460 		return ("N5");
1461 	case ISCSI_SESS_EVENT_N6:
1462 		return ("N6");
1463 	case ISCSI_SESS_EVENT_N7:
1464 		return ("N7");
1465 	default:
1466 		return ("unknown");
1467 	}
1468 }
1469 
1470 /*
1471  * iscsi_sess_thread_create -
1472  *
1473  */
1474 static iscsi_status_t
1475 iscsi_sess_threads_create(iscsi_sess_t *isp)
1476 {
1477 	iscsi_hba_t	*ihp;
1478 	char		th_name[ISCSI_TH_MAX_NAME_LEN];
1479 
1480 	ASSERT(isp != NULL);
1481 	ihp = isp->sess_hba;
1482 	ASSERT(ihp != NULL);
1483 
1484 	/* Completion thread creation. */
1485 	if (snprintf(th_name, sizeof (th_name) - 1,
1486 	    ISCSI_SESS_IOTH_NAME_FORMAT, ihp->hba_oid,
1487 	    isp->sess_oid) >= sizeof (th_name)) {
1488 		return (ISCSI_STATUS_INTERNAL_ERROR);
1489 	}
1490 
1491 	isp->sess_ic_thread = iscsi_thread_create(ihp->hba_dip,
1492 	    th_name, iscsi_ic_thread, isp);
1493 
1494 	if (isp->sess_ic_thread == NULL) {
1495 		return (ISCSI_STATUS_INTERNAL_ERROR);
1496 	}
1497 
1498 	(void) iscsi_thread_start(isp->sess_ic_thread);
1499 
1500 	return (ISCSI_STATUS_SUCCESS);
1501 }
1502 
1503 /*
1504  * iscsi_sess_enumeration - This function is used to drive the enumeration
1505  * of LUs on a session.  It will first prepare the target by sending test
1506  * unit ready commands, then it will issue a report luns.  If the report
1507  * luns is successful then it will process all the luns in the report.
1508  * If report luns is not successful we will do a stepping enumeration
1509  * of luns until no more luns are found.
1510  */
1511 static void
1512 iscsi_sess_enumeration(void *arg)
1513 {
1514 	iscsi_task_t		*itp = (iscsi_task_t *)arg;
1515 	iscsi_sess_t		*isp;
1516 	iscsi_status_t		rval    = ISCSI_STATUS_SUCCESS;
1517 
1518 	ASSERT(itp != NULL);
1519 	isp = (iscsi_sess_t *)itp->t_arg;
1520 	ASSERT(isp != NULL);
1521 
1522 	/*
1523 	 * Send initial TEST_UNIT_READY to target.  If it fails this we
1524 	 * stop our enumeration as the target is not responding properly.
1525 	 */
1526 	rval = iscsi_sess_testunitready(isp);
1527 	if (ISCSI_SUCCESS(rval)) {
1528 		/*
1529 		 * Now we know the target is ready start our enumeration with
1530 		 * REPORT LUNs, If this fails we will have to fall back to
1531 		 * stepping
1532 		 */
1533 		rval = iscsi_sess_reportluns(isp);
1534 		if (!ISCSI_SUCCESS(rval)) {
1535 			/*
1536 			 * report luns failed so lets just check for LUN 0.
1537 			 * This will match fcp's enumeration support and
1538 			 * avoid issues with older devices like the A5K that
1539 			 * respond poorly.
1540 			 */
1541 			if (isp->sess_lun_list == NULL) {
1542 				iscsi_sess_inquiry(isp, 0, 0);
1543 			}
1544 		}
1545 	} else {
1546 		cmn_err(CE_NOTE, "iscsi session(%u) unable to enumerate "
1547 		    "logical units - test unit ready failed", isp->sess_oid);
1548 	}
1549 
1550 	if (itp->t_blocking == B_FALSE) {
1551 		kmem_free(itp, sizeof (iscsi_task_t));
1552 	}
1553 }
1554 
1555 /*
1556  * iscsi_sess_testunitready - This is used during enumeration to
1557  * ensure an array is ready to be enumerated.
1558  */
1559 static iscsi_status_t
1560 iscsi_sess_testunitready(iscsi_sess_t *isp)
1561 {
1562 	iscsi_status_t			rval		= ISCSI_STATUS_SUCCESS;
1563 	int				retries		= 0;
1564 	struct uscsi_cmd		ucmd;
1565 	char				cdb[CDB_GROUP0];
1566 
1567 	ASSERT(isp != NULL);
1568 
1569 	/* loop until successful sending test unit ready or retries out */
1570 	do {
1571 		/* cdb is all zeros */
1572 		bzero(&cdb[0], CDB_GROUP0);
1573 
1574 		/* setup uscsi cmd */
1575 		bzero(&ucmd, sizeof (struct uscsi_cmd));
1576 		ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
1577 		ucmd.uscsi_cdb		= &cdb[0];
1578 		ucmd.uscsi_cdblen	= CDB_GROUP0;
1579 
1580 		/* send test unit ready to lun zero on this session */
1581 		rval = iscsi_handle_passthru(isp, 0, &ucmd);
1582 
1583 		/*
1584 		 * If passthru was successful then we were able to
1585 		 * communicate with the target, continue enumeration.
1586 		 */
1587 		if (ISCSI_SUCCESS(rval)) {
1588 			break;
1589 		}
1590 
1591 	} while (retries++ < 3);
1592 
1593 	return (rval);
1594 }
1595 
1596 #define	SCSI_REPORTLUNS_ADDRESS_SIZE			8
1597 #define	SCSI_REPORTLUNS_ADDRESS_MASK			0xC0
1598 #define	SCSI_REPORTLUNS_ADDRESS_PERIPHERAL		0x00
1599 #define	SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE		0x40
1600 #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT		0x80
1601 #define	SCSI_REPORTLUNS_ADDRESS_EXTENDED_UNIT		0xC0
1602 #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_2B		0x00
1603 #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_4B		0x01
1604 #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_6B		0x10
1605 #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_8B		0x20
1606 #define	SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_SIZE	0x30
1607 
1608 /*
1609  * iscsi_sess_reportluns - This is used during enumeration to
1610  * ensure an array is ready to be enumerated.
1611  */
1612 static iscsi_status_t
1613 iscsi_sess_reportluns(iscsi_sess_t *isp)
1614 {
1615 	iscsi_status_t		rval		= ISCSI_STATUS_SUCCESS;
1616 	iscsi_hba_t		*ihp;
1617 	struct uscsi_cmd	ucmd;
1618 	unsigned char		cdb[CDB_GROUP5];
1619 	unsigned char		*buf		= NULL;
1620 	int			buf_len		= sizeof (struct scsi_inquiry);
1621 	uint32_t		lun_list_length = 0;
1622 	uint16_t		lun_num		= 0;
1623 	uint8_t			lun_addr_type	= 0;
1624 	uint32_t		lun_count	= 0;
1625 	uint32_t		lun_start	= 0;
1626 	uint32_t		lun_total	= 0;
1627 	int			retries		= 0;
1628 	iscsi_lun_t		*ilp		= NULL;
1629 	replun_data_t		*saved_replun_ptr = NULL;
1630 
1631 	ASSERT(isp != NULL);
1632 	ihp = isp->sess_hba;
1633 	ASSERT(ihp != NULL);
1634 
1635 	/*
1636 	 * Attempt to send report luns until we successfully
1637 	 * get all the data or the retries run out.
1638 	 */
1639 	do {
1640 		/*
1641 		 * Allocate our buffer based on current buf_len.
1642 		 * buf_len may change after we received a response
1643 		 * from the target.
1644 		 */
1645 		if (buf == NULL) {
1646 			buf = kmem_zalloc(buf_len, KM_SLEEP);
1647 		}
1648 
1649 		/* setup cdb */
1650 		bzero(&cdb, CDB_GROUP5);
1651 		cdb[0] = SCMD_REPORT_LUNS;
1652 		cdb[6] = (buf_len & 0xff000000) >> 24;
1653 		cdb[7] = (buf_len & 0x00ff0000) >> 16;
1654 		cdb[8] = (buf_len & 0x0000ff00) >> 8;
1655 		cdb[9] = (buf_len & 0x000000ff);
1656 
1657 		/* setup uscsi cmd */
1658 		bzero(&ucmd, sizeof (struct uscsi_cmd));
1659 		ucmd.uscsi_flags	= USCSI_READ;
1660 		ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
1661 		ucmd.uscsi_cdb		= (char *)&cdb[0];
1662 		ucmd.uscsi_cdblen	= CDB_GROUP5;
1663 		ucmd.uscsi_bufaddr	= (char *)buf;
1664 		ucmd.uscsi_buflen	= buf_len;
1665 
1666 		/* send uscsi cmd to lun 0 on session */
1667 		rval = iscsi_handle_passthru(isp, 0, &ucmd);
1668 
1669 		/* If passthru successful but not scsi status update istatus */
1670 		if (ISCSI_SUCCESS(rval) &&
1671 		    (ucmd.uscsi_status != STATUS_GOOD)) {
1672 			rval = ISCSI_STATUS_USCSI_FAILED;
1673 		}
1674 
1675 		/* If successful, check if we have all the data */
1676 		if (ISCSI_SUCCESS(rval)) {
1677 			/* total data - header (SCSI_REPORTLUNS_ADDRESS_SIZE) */
1678 			lun_list_length	= htonl(*(uint32_t *)buf);
1679 
1680 			if (buf_len >= lun_list_length +
1681 			    SCSI_REPORTLUNS_ADDRESS_SIZE) {
1682 				/* we have all the data, were done */
1683 				break;
1684 			}
1685 
1686 			/*
1687 			 * We don't have all the data.  free up the
1688 			 * memory for the next pass and update the
1689 			 * buf_len
1690 			 */
1691 			kmem_free(buf, buf_len);
1692 			buf = NULL;
1693 			buf_len = lun_list_length +
1694 			    SCSI_REPORTLUNS_ADDRESS_SIZE;
1695 		} else {
1696 			retries++;
1697 		}
1698 
1699 	} while (retries < 3);
1700 
1701 	/* If not successful go no farther */
1702 	if (!ISCSI_SUCCESS(rval)) {
1703 		kmem_free(buf, buf_len);
1704 		return (rval);
1705 	}
1706 
1707 	/*
1708 	 * find out the number of luns returned by the SCSI ReportLun call
1709 	 * and allocate buffer space
1710 	 */
1711 	lun_total = lun_list_length / SCSI_REPORTLUNS_ADDRESS_SIZE;
1712 	saved_replun_ptr = kmem_zalloc(lun_total * sizeof (replun_data_t),
1713 	    KM_SLEEP);
1714 
1715 	/*
1716 	 * walk the isp->sess_lun_list
1717 	 * for each lun in this list
1718 	 *	look to see if this lun is in the SCSI ReportLun list we
1719 	 *	    just retrieved
1720 	 *	if it is in the SCSI ReportLun list and it is already ONLINE
1721 	 *	    nothing needs to be done
1722 	 *	if it is in the SCSI ReportLun list and it is OFFLINE,
1723 	 *	    issue the iscsi_lun_online()
1724 	 *	if it isn't in the SCSI ReportLunlist then
1725 	 *	    issue the iscsi_sess_inquiry()
1726 	 *
1727 	 *	as we walk the SCSI ReportLun list, we save this lun information
1728 	 *	    into the buffer we just allocated.  This will save us from
1729 	 *	    having to figure out this information later
1730 	 */
1731 	lun_start = 0;
1732 	rw_enter(&isp->sess_lun_list_rwlock, RW_READER);
1733 	for (ilp = isp->sess_lun_list; ilp; ilp = ilp->lun_next) {
1734 		for (lun_count = lun_start;
1735 		    lun_count < lun_total; lun_count++) {
1736 		/*
1737 		 * if the first lun in saved_replun_ptr buffer has already
1738 		 * been found we can move on and do not have to check this lun
1739 		 * in the future
1740 		 */
1741 			if (lun_count == lun_start &&
1742 			    saved_replun_ptr[lun_start].lun_found) {
1743 				lun_start++;
1744 				continue;
1745 			}
1746 			/*
1747 			 * check to see if the lun we are looking for is in the
1748 			 * saved_replun_ptr buffer
1749 			 * if it is, process the lun
1750 			 * if it isn't, then we must go to SCSI
1751 			 * Report Lun buffer
1752 			 * we retrieved to get lun info
1753 			 */
1754 			if (saved_replun_ptr[lun_count].lun_valid ==
1755 			    B_TRUE) {
1756 				if (saved_replun_ptr[lun_count].lun_num ==
1757 				    ilp->lun_num) {
1758 				/*
1759 				 * the lun we are looking for is found
1760 				 *
1761 				 * if the state of the lun is currently OFFLINE,
1762 				 * turn it back online
1763 				 */
1764 				if (ilp->lun_state ==
1765 				    ISCSI_LUN_STATE_OFFLINE) {
1766 					DTRACE_PROBE2(
1767 					    sess_reportluns_lun_is_not_online,
1768 					    int, ilp->lun_num, int,
1769 					    ilp->lun_state);
1770 					iscsi_lun_online(ihp, ilp);
1771 				}
1772 				saved_replun_ptr[lun_count].lun_found = B_TRUE;
1773 				break;
1774 			}
1775 		} else {
1776 			/*
1777 			 * lun information is not found in the saved_replun
1778 			 * buffer, retrieve lun information from the SCSI
1779 			 * Report Lun buffer and store this information in
1780 			 * the saved_replun buffer
1781 			 */
1782 			if (retrieve_lundata(lun_count, buf, isp, &lun_num,
1783 			    &lun_addr_type) != ISCSI_STATUS_SUCCESS) {
1784 				continue;
1785 			}
1786 			saved_replun_ptr[lun_count].lun_valid = B_TRUE;
1787 			saved_replun_ptr[lun_count].lun_num = lun_num;
1788 			if (ilp->lun_num == lun_num) {
1789 			/*
1790 			 * lun is found in the SCSI Report Lun buffer
1791 			 * make sure the lun is in the ONLINE state
1792 			 */
1793 				saved_replun_ptr[lun_count].lun_found = B_TRUE;
1794 					if (ilp->lun_state ==
1795 					    ISCSI_LUN_STATE_OFFLINE) {
1796 #define	SRLINON sess_reportluns_lun_is_not_online
1797 						DTRACE_PROBE2(
1798 						    SRLINON,
1799 						    int, ilp->lun_num, int,
1800 						    ilp->lun_state);
1801 
1802 							iscsi_lun_online(
1803 							    ihp, ilp);
1804 #undef SRLINON
1805 					}
1806 					break;
1807 				}
1808 			}
1809 		}
1810 
1811 		if (lun_count == lun_total) {
1812 		/*
1813 		 * this lun we found in the sess->lun_list does not exist
1814 		 * anymore, need to offline this lun
1815 		 */
1816 
1817 			DTRACE_PROBE2(sess_reportluns_lun_no_longer_exists,
1818 			    int, ilp->lun_num, int, ilp->lun_state);
1819 
1820 			if (ilp->lun_state == ISCSI_LUN_STATE_ONLINE) {
1821 				(void) iscsi_lun_offline(ihp, ilp, B_FALSE);
1822 			}
1823 		}
1824 	}
1825 	rw_exit(&isp->sess_lun_list_rwlock);
1826 
1827 	/*
1828 	 * look for new luns that we found in the SCSI Report Lun buffer that
1829 	 * we did not have in the sess->lun_list and add them into the list
1830 	 */
1831 	for (lun_count = lun_start; lun_count < lun_total; lun_count++) {
1832 		if (saved_replun_ptr[lun_count].lun_valid == B_FALSE) {
1833 			/*
1834 			 * lun information is not in the
1835 			 * saved_replun buffer, retrieve
1836 			 * it from the SCSI Report Lun buffer
1837 			 */
1838 			if (retrieve_lundata(lun_count, buf, isp,
1839 			    &lun_num, &lun_addr_type) != ISCSI_STATUS_SUCCESS) {
1840 				continue;
1841 			}
1842 		} else {
1843 		/*
1844 		 * lun information is in the saved_replun buffer
1845 		 *    if this lun has been found already, then we can move on
1846 		 */
1847 			if (saved_replun_ptr[lun_count].lun_found == B_TRUE) {
1848 				continue;
1849 			}
1850 			lun_num = saved_replun_ptr[lun_count].lun_num;
1851 		}
1852 
1853 
1854 		/* New luns found should not conflict with existing luns */
1855 		rw_enter(&isp->sess_lun_list_rwlock, RW_READER);
1856 		for (ilp = isp->sess_lun_list; ilp; ilp = ilp->lun_next) {
1857 			if (ilp->lun_num == lun_num) {
1858 				break;
1859 			}
1860 		}
1861 		rw_exit(&isp->sess_lun_list_rwlock);
1862 
1863 		if (ilp == NULL) {
1864 			/* new lun found, add this lun */
1865 			iscsi_sess_inquiry(isp, lun_num, lun_addr_type);
1866 		} else {
1867 			cmn_err(CE_NOTE,
1868 			    "!Duplicate Lun Number(%d) recieved from "
1869 			    "Target(%s)", lun_num, isp->sess_name);
1870 		}
1871 	}
1872 
1873 	kmem_free(buf, buf_len);
1874 	kmem_free(saved_replun_ptr, lun_total * sizeof (replun_data_t));
1875 	return (rval);
1876 }
1877 
1878 #define	ISCSI_MAX_INQUIRY_BUF_SIZE	0xFF
1879 #define	ISCSI_MAX_INQUIRY_RETRIES	3
1880 
1881 /*
1882  * iscsi_sess_inquiry - Final processing of a LUN before we create a tgt
1883  * mapping.  We need to collect the stardard inquiry page and the
1884  * vendor identification page for this LUN.  If both of these are
1885  * successful and the identification page contains a NAA or EUI type
1886  * we will continue.  Otherwise we fail the creation of a tgt for
1887  * this LUN.
1888  *
1889  * The GUID creation in this function will be removed
1890  * we are pushing to have all this GUID code somewhere else.
1891  */
1892 static void
1893 iscsi_sess_inquiry(iscsi_sess_t *isp, uint16_t lun_num, uint8_t lun_addr_type)
1894 {
1895 	iscsi_status_t		rval;
1896 	struct uscsi_cmd	ucmd;
1897 	uchar_t			cdb[CDB_GROUP0];
1898 	uchar_t			*inq;
1899 	size_t			inq_len;
1900 	uchar_t			*inq83;
1901 	size_t			inq83_len;
1902 	int			retries;
1903 	ddi_devid_t		devid;
1904 	char			*guid = NULL;
1905 
1906 	ASSERT(isp != NULL);
1907 
1908 	inq	= kmem_zalloc(ISCSI_MAX_INQUIRY_BUF_SIZE, KM_SLEEP);
1909 	inq83	= kmem_zalloc(ISCSI_MAX_INQUIRY_BUF_SIZE, KM_SLEEP);
1910 
1911 	/*
1912 	 * STANDARD INQUIRY - We need the standard inquiry information
1913 	 * to feed into the scsi_hba_nodename_compatible_get function.
1914 	 * This function is used to detemine which driver will bind
1915 	 * on top of us, via the compatible id.
1916 	 */
1917 	bzero(&cdb, CDB_GROUP0);
1918 	cdb[0] = SCMD_INQUIRY;
1919 	cdb[4] = ISCSI_MAX_INQUIRY_BUF_SIZE;
1920 
1921 	bzero(&ucmd, sizeof (struct uscsi_cmd));
1922 	ucmd.uscsi_flags	= USCSI_READ;
1923 	ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
1924 	ucmd.uscsi_cdb		= (char *)&cdb[0];
1925 	ucmd.uscsi_cdblen	= CDB_GROUP0;
1926 	ucmd.uscsi_bufaddr	= (char *)inq;
1927 	ucmd.uscsi_buflen	= ISCSI_MAX_INQUIRY_BUF_SIZE;
1928 
1929 	/* Attempt to get inquiry information until successful or retries */
1930 	retries = 0;
1931 	do {
1932 		/* issue passthru */
1933 		rval = iscsi_handle_passthru(isp, lun_num, &ucmd);
1934 
1935 		/* If we were successful but scsi stat failed update istatus */
1936 		if (ISCSI_SUCCESS(rval) &&
1937 		    (ucmd.uscsi_status != STATUS_GOOD)) {
1938 			rval = ISCSI_STATUS_USCSI_FAILED;
1939 		}
1940 
1941 		/* If successful break */
1942 		if (ISCSI_SUCCESS(rval)) {
1943 			inq_len = ISCSI_MAX_INQUIRY_BUF_SIZE - ucmd.uscsi_resid;
1944 			break;
1945 		}
1946 
1947 		/* loop until we are successful or retries run out */
1948 	} while (retries++ < ISCSI_MAX_INQUIRY_RETRIES);
1949 
1950 	/* If failed don't continue */
1951 	if (!ISCSI_SUCCESS(rval)) {
1952 		cmn_err(CE_NOTE, "iscsi session(%u) unable to enumerate "
1953 		    "logical unit - inquiry failed lun %d",
1954 		    isp->sess_oid, lun_num);
1955 
1956 		goto inq_done;
1957 	}
1958 
1959 	/*
1960 	 * T-10 SPC Section 6.4.2.  Standard INQUIRY Peripheral
1961 	 * qualifier of 000b is the only type we should attempt
1962 	 * to plumb under the IO stack.
1963 	 */
1964 	if ((inq[0] & SCSI_INQUIRY_PQUAL_MASK) != 0x00) {
1965 		goto inq_done;
1966 	}
1967 
1968 	/*
1969 	 * VENDOR IDENTIFICATION INQUIRY - This will be used to identify
1970 	 * a unique lunId.  This Id is passed to the mdi alloc calls so
1971 	 * we can properly plumb into scsi_vhci/mpxio.
1972 	 */
1973 
1974 	bzero(&cdb, CDB_GROUP0);
1975 	cdb[0] = SCMD_INQUIRY;
1976 	cdb[1] = 0x01; /* EVP bit */
1977 	cdb[2] = 0x83;
1978 	cdb[4] = ISCSI_MAX_INQUIRY_BUF_SIZE;
1979 
1980 	ucmd.uscsi_flags	= USCSI_READ;
1981 	ucmd.uscsi_timeout	= iscsi_sess_enum_timeout;
1982 	ucmd.uscsi_cdb		= (char *)&cdb[0];
1983 	ucmd.uscsi_cdblen	= CDB_GROUP0;
1984 	ucmd.uscsi_bufaddr	= (char *)inq83;
1985 	ucmd.uscsi_buflen	= ISCSI_MAX_INQUIRY_BUF_SIZE;
1986 
1987 	/* Attempt to get inquiry information until successful or retries */
1988 	retries = 0;
1989 	do {
1990 		/* issue passthru command */
1991 		rval = iscsi_handle_passthru(isp, lun_num, &ucmd);
1992 
1993 		/* If we were successful but scsi stat failed update istatus */
1994 		if (ISCSI_SUCCESS(rval) &&
1995 		    (ucmd.uscsi_status != STATUS_GOOD)) {
1996 			rval = ISCSI_STATUS_USCSI_FAILED;
1997 		}
1998 
1999 		/* Break if successful */
2000 		if (ISCSI_SUCCESS(rval)) {
2001 			inq83_len = ISCSI_MAX_INQUIRY_BUF_SIZE -
2002 			    ucmd.uscsi_resid;
2003 			break;
2004 		}
2005 
2006 	} while (retries++ < ISCSI_MAX_INQUIRY_RETRIES);
2007 
2008 	/*
2009 	 * If we were successful collecting page 83 data attempt
2010 	 * to generate a GUID.  If no GUID can be generated then
2011 	 * the logical unit will skip attempt to plumb under
2012 	 * scsi_vhci/mpxio.
2013 	 */
2014 	if (ISCSI_SUCCESS(rval)) {
2015 		/* create DEVID from inquiry data */
2016 		if (ddi_devid_scsi_encode(
2017 		    DEVID_SCSI_ENCODE_VERSION_LATEST, NULL,
2018 		    inq, inq_len, NULL, 0, inq83, inq83_len, &devid) ==
2019 		    DDI_SUCCESS) {
2020 
2021 			/* extract GUID from DEVID */
2022 			guid = ddi_devid_to_guid(devid);
2023 
2024 			/* devid no longer needed */
2025 			ddi_devid_free(devid);
2026 		}
2027 	}
2028 
2029 	rval = iscsi_lun_create(isp, lun_num, lun_addr_type,
2030 	    (struct scsi_inquiry *)inq, guid);
2031 
2032 	if (guid != NULL) {
2033 		/* guid no longer needed */
2034 		ddi_devid_free_guid(guid);
2035 	}
2036 
2037 inq_done:
2038 	/* free up memory now that we are done */
2039 	kmem_free(inq, ISCSI_MAX_INQUIRY_BUF_SIZE);
2040 	kmem_free(inq83, ISCSI_MAX_INQUIRY_BUF_SIZE);
2041 }
2042 
2043 static iscsi_status_t
2044 retrieve_lundata(uint32_t lun_count, unsigned char *buf, iscsi_sess_t *isp,
2045     uint16_t *lun_num, uint8_t *lun_addr_type)
2046 {
2047 	uint32_t		lun_idx		= 0;
2048 
2049 	ASSERT(lun_num != NULL);
2050 	ASSERT(lun_addr_type != NULL);
2051 
2052 	lun_idx = (lun_count + 1) * SCSI_REPORTLUNS_ADDRESS_SIZE;
2053 	/* determine report luns addressing type */
2054 	switch (buf[lun_idx] & SCSI_REPORTLUNS_ADDRESS_MASK) {
2055 		/*
2056 		 * Vendors in the field have been found to be concatenating
2057 		 * bus/target/lun to equal the complete lun value instead
2058 		 * of switching to flat space addressing
2059 		 */
2060 		/* 00b - peripheral device addressing method */
2061 		case SCSI_REPORTLUNS_ADDRESS_PERIPHERAL:
2062 			/* FALLTHRU */
2063 		/* 10b - logical unit addressing method */
2064 		case SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT:
2065 			/* FALLTHRU */
2066 		/* 01b - flat space addressing method */
2067 		case SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE:
2068 			/* byte0 bit0-5=msb lun byte1 bit0-7=lsb lun */
2069 			*lun_addr_type = (buf[lun_idx] &
2070 			    SCSI_REPORTLUNS_ADDRESS_MASK) >> 6;
2071 			*lun_num = (buf[lun_idx] & 0x3F) << 8;
2072 			*lun_num |= buf[lun_idx + 1];
2073 			return (ISCSI_STATUS_SUCCESS);
2074 		default: /* protocol error */
2075 			cmn_err(CE_NOTE, "iscsi session(%u) unable "
2076 			    "to enumerate logical units - report "
2077 			    "luns returned an unsupported format",
2078 			    isp->sess_oid);
2079 			break;
2080 	}
2081 	return (ISCSI_STATUS_INTERNAL_ERROR);
2082 }
2083 
2084 /*
2085  * iscsi_sess_flush - flushes remaining pending io on the session
2086  */
2087 static void
2088 iscsi_sess_flush(iscsi_sess_t *isp)
2089 {
2090 	iscsi_cmd_t	*icmdp;
2091 
2092 	ASSERT(isp != NULL);
2093 	ASSERT(isp->sess_state != ISCSI_SESS_STATE_LOGGED_IN);
2094 
2095 	/*
2096 	 * Flush out any remaining commands in the pending
2097 	 * queue.
2098 	 */
2099 	mutex_enter(&isp->sess_queue_pending.mutex);
2100 	icmdp = isp->sess_queue_pending.head;
2101 	while (icmdp != NULL) {
2102 		iscsi_cmd_state_machine(icmdp,
2103 		    ISCSI_CMD_EVENT_E7, isp);
2104 		icmdp = isp->sess_queue_pending.head;
2105 	}
2106 	mutex_exit(&isp->sess_queue_pending.mutex);
2107 }
2108 
2109 /*
2110  * iscsi_sess_offline_luns - offline all this sessions luns
2111  */
2112 static void
2113 iscsi_sess_offline_luns(iscsi_sess_t *isp)
2114 {
2115 	iscsi_lun_t	*ilp;
2116 	iscsi_hba_t	*ihp;
2117 
2118 	ASSERT(isp != NULL);
2119 	ASSERT(isp->sess_state != ISCSI_SESS_STATE_LOGGED_IN);
2120 	ihp = isp->sess_hba;
2121 	ASSERT(ihp != NULL);
2122 
2123 	rw_enter(&isp->sess_lun_list_rwlock, RW_READER);
2124 	ilp = isp->sess_lun_list;
2125 	while (ilp != NULL) {
2126 		(void) iscsi_lun_offline(ihp, ilp, B_FALSE);
2127 		ilp = ilp->lun_next;
2128 	}
2129 	rw_exit(&isp->sess_lun_list_rwlock);
2130 }
2131 
2132 /*
2133  * iscsi_sess_get_by_target - return the session structure for based on a
2134  * passed in target oid and hba instance.  NOTE:  There may be
2135  * multiple sessions associated with any given target.  In this case,
2136  * we will return the first matching session.  This function
2137  * is intended to be used in retrieving target info that is constant
2138  * across sessions (target name, alias, etc.).
2139  */
2140 int
2141 iscsi_sess_get_by_target(uint32_t target_oid, iscsi_hba_t *ihp,
2142     iscsi_sess_t **ispp)
2143 {
2144 	int rval = 0;
2145 	iscsi_sess_t *isp = NULL;
2146 
2147 	ASSERT(ihp != NULL);
2148 	ASSERT(ispp != NULL);
2149 
2150 	/* See if we already created this session */
2151 	for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
2152 		/*
2153 		 * Look for a session associated to the given target.
2154 		 * Return the first one found.
2155 		 */
2156 		if (isp->sess_target_oid == target_oid) {
2157 			/* Found matching session */
2158 			break;
2159 		}
2160 	}
2161 
2162 	/* If not null this session is already available */
2163 	if (isp != NULL) {
2164 		/* Existing session, return it */
2165 		*ispp = isp;
2166 	} else {
2167 		rval = EFAULT;
2168 	}
2169 	return (rval);
2170 }
2171