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