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