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