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