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