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