1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * iSCSI connection interfaces
26  */
27 
28 #define	ISCSI_ICS_NAMES
29 #include "iscsi.h"
30 #include "persistent.h"
31 #include <sys/bootprops.h>
32 
33 extern ib_boot_prop_t   *iscsiboot_prop;
34 
35 static void iscsi_client_notify_task(void *cn_task_void);
36 
37 static void iscsi_conn_flush_active_cmds(iscsi_conn_t *icp);
38 
39 #define	SHUTDOWN_TIMEOUT	180 /* seconds */
40 
41 extern int modrootloaded;
42 
43 boolean_t iscsi_conn_logging = B_FALSE;
44 
45 /*
46  * +--------------------------------------------------------------------+
47  * | External Connection Interfaces					|
48  * +--------------------------------------------------------------------+
49  */
50 
51 /*
52  * iscsi_conn_create - This creates an iscsi connection structure and
53  * associates it with a session structure.  The session's sess_conn_list_rwlock
54  * should be held as a writer before calling this function.
55  */
56 iscsi_status_t
57 iscsi_conn_create(struct sockaddr *addr, iscsi_sess_t *isp, iscsi_conn_t **icpp)
58 {
59 	iscsi_conn_t	*icp	= NULL;
60 	char		th_name[ISCSI_TH_MAX_NAME_LEN];
61 
62 	/* See if this connection already exists */
63 	for (icp = isp->sess_conn_list; icp; icp = icp->conn_next) {
64 
65 		/*
66 		 * Compare the ioctl information to see if
67 		 * its a match for this connection.  (This
68 		 * is done by making sure the IPs are of
69 		 * the same size and then they are the
70 		 * same value.
71 		 */
72 		if (bcmp(&icp->conn_base_addr, addr,
73 		    SIZEOF_SOCKADDR(addr)) == 0) {
74 			/* It's a match, record this connection */
75 			break;
76 		}
77 	}
78 
79 	/* If icp is found return it */
80 	if (icp != NULL) {
81 		*icpp = icp;
82 		return (ISCSI_STATUS_SUCCESS);
83 	}
84 
85 	/* We are creating the connection, allocate, and setup */
86 	icp = (iscsi_conn_t *)kmem_zalloc(sizeof (iscsi_conn_t), KM_SLEEP);
87 
88 	/*
89 	 * Setup connection
90 	 */
91 	icp->conn_sig			= ISCSI_SIG_CONN;
92 	icp->conn_state			= ISCSI_CONN_STATE_FREE;
93 	mutex_init(&icp->conn_state_mutex, NULL, MUTEX_DRIVER, NULL);
94 	cv_init(&icp->conn_state_change, NULL, CV_DRIVER, NULL);
95 	mutex_init(&icp->conn_login_mutex, NULL, MUTEX_DRIVER, NULL);
96 	cv_init(&icp->conn_login_cv, NULL, CV_DRIVER, NULL);
97 	icp->conn_state_destroy		= B_FALSE;
98 	idm_sm_audit_init(&icp->conn_state_audit);
99 	icp->conn_sess			= isp;
100 
101 	mutex_enter(&iscsi_oid_mutex);
102 	icp->conn_oid = iscsi_oid++;
103 	mutex_exit(&iscsi_oid_mutex);
104 
105 	/*
106 	 * IDM CN taskq
107 	 */
108 
109 	if (snprintf(th_name, sizeof (th_name) - 1,
110 	    ISCSI_CONN_CN_TASKQ_NAME_FORMAT,
111 	    icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid,
112 	    icp->conn_oid) >= sizeof (th_name)) {
113 		cv_destroy(&icp->conn_state_change);
114 		mutex_destroy(&icp->conn_state_mutex);
115 		kmem_free(icp, sizeof (iscsi_conn_t));
116 		*icpp = NULL;
117 		return (ISCSI_STATUS_INTERNAL_ERROR);
118 	}
119 
120 	icp->conn_cn_taskq =
121 	    ddi_taskq_create(icp->conn_sess->sess_hba->hba_dip, th_name, 1,
122 	    TASKQ_DEFAULTPRI, 0);
123 	if (icp->conn_cn_taskq == NULL) {
124 		cv_destroy(&icp->conn_state_change);
125 		mutex_destroy(&icp->conn_state_mutex);
126 		kmem_free(icp, sizeof (iscsi_conn_t));
127 		*icpp = NULL;
128 		return (ISCSI_STATUS_INTERNAL_ERROR);
129 	}
130 
131 	/* Creation of the transfer thread */
132 	if (snprintf(th_name, sizeof (th_name) - 1, ISCSI_CONN_TXTH_NAME_FORMAT,
133 	    icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid,
134 	    icp->conn_oid) >= sizeof (th_name)) {
135 		cv_destroy(&icp->conn_state_change);
136 		mutex_destroy(&icp->conn_state_mutex);
137 		kmem_free(icp, sizeof (iscsi_conn_t));
138 		ddi_taskq_destroy(icp->conn_cn_taskq);
139 		*icpp = NULL;
140 		return (ISCSI_STATUS_INTERNAL_ERROR);
141 	}
142 
143 	icp->conn_tx_thread = iscsi_thread_create(isp->sess_hba->hba_dip,
144 	    th_name, iscsi_tx_thread, icp);
145 
146 	/* setup connection queues */
147 	iscsi_init_queue(&icp->conn_queue_active);
148 	iscsi_init_queue(&icp->conn_queue_idm_aborting);
149 
150 	bcopy(addr, &icp->conn_base_addr, sizeof (icp->conn_base_addr));
151 
152 	/* Add new connection to the session connection list */
153 	icp->conn_cid = isp->sess_conn_next_cid++;
154 	if (isp->sess_conn_list == NULL) {
155 		isp->sess_conn_list = isp->sess_conn_list_last_ptr = icp;
156 	} else {
157 		isp->sess_conn_list_last_ptr->conn_next = icp;
158 		isp->sess_conn_list_last_ptr = icp;
159 	}
160 
161 	KSTAT_INC_SESS_CNTR_CONN(isp);
162 	(void) iscsi_conn_kstat_init(icp);
163 
164 	*icpp = icp;
165 
166 	return (ISCSI_STATUS_SUCCESS);
167 }
168 
169 /*
170  * iscsi_conn_online - This attempts to take a connection from
171  * ISCSI_CONN_STATE_FREE to ISCSI_CONN_STATE_LOGGED_IN.
172  */
173 iscsi_status_t
174 iscsi_conn_online(iscsi_conn_t *icp)
175 {
176 	iscsi_task_t	*itp;
177 	iscsi_status_t	rval;
178 
179 	ASSERT(icp != NULL);
180 	ASSERT(mutex_owned(&icp->conn_state_mutex));
181 	ASSERT(icp->conn_state == ISCSI_CONN_STATE_FREE);
182 
183 	/*
184 	 * If we are attempting to connect then for the purposes of the
185 	 * other initiator code we are effectively in ISCSI_CONN_STATE_IN_LOGIN.
186 	 */
187 	iscsi_conn_update_state_locked(icp, ISCSI_CONN_STATE_IN_LOGIN);
188 	mutex_exit(&icp->conn_state_mutex);
189 
190 	/*
191 	 * Sync base connection information before login
192 	 * A login redirection might have shifted the
193 	 * current information from the base.
194 	 */
195 	bcopy(&icp->conn_base_addr, &icp->conn_curr_addr,
196 	    sizeof (icp->conn_curr_addr));
197 
198 	itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
199 	ASSERT(itp != NULL);
200 
201 	itp->t_arg = icp;
202 	itp->t_blocking = B_TRUE;
203 	rval = iscsi_login_start(itp);
204 	kmem_free(itp, sizeof (iscsi_task_t));
205 
206 	mutex_enter(&icp->conn_state_mutex);
207 
208 	return (rval);
209 }
210 
211 /*
212  * iscsi_conn_offline - This attempts to take a connection from
213  * any state to ISCSI_CONN_STATE_FREE.
214  */
215 iscsi_status_t
216 iscsi_conn_offline(iscsi_conn_t *icp)
217 {
218 	clock_t		delay;
219 
220 	ASSERT(icp != NULL);
221 
222 	/*
223 	 * We can only destroy a connection if its either in
224 	 * a state of FREE or LOGGED.  The other states are
225 	 * transitionary and its unsafe to perform actions
226 	 * on the connection in those states.  Set a flag
227 	 * on the connection to influence the transitions
228 	 * to quickly complete.  Then wait for a state
229 	 * transition.
230 	 *
231 	 * ISCSI_CONN_STATE_LOGGED_IN is set immediately at the
232 	 * start of CN_NOTIFY_FFP processing. icp->conn_state_ffp
233 	 * is set to true at the end of ffp processing, at which
234 	 * point any session updates are complete.  We don't
235 	 * want to start offlining the connection before we're
236 	 * done completing the FFP processing since this might
237 	 * interrupt the discovery process.
238 	 */
239 	delay = ddi_get_lbolt() + SEC_TO_TICK(SHUTDOWN_TIMEOUT);
240 	mutex_enter(&icp->conn_state_mutex);
241 	icp->conn_state_destroy = B_TRUE;
242 	while ((((icp->conn_state != ISCSI_CONN_STATE_FREE) &&
243 	    (icp->conn_state != ISCSI_CONN_STATE_LOGGED_IN)) ||
244 	    ((icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN) &&
245 	    !icp->conn_state_ffp)) &&
246 	    (ddi_get_lbolt() < delay)) {
247 		/* wait for transition */
248 		(void) cv_timedwait(&icp->conn_state_change,
249 		    &icp->conn_state_mutex, delay);
250 	}
251 
252 	switch (icp->conn_state) {
253 	case ISCSI_CONN_STATE_FREE:
254 		break;
255 	case ISCSI_CONN_STATE_LOGGED_IN:
256 		if (icp->conn_state_ffp) {
257 			/* Hold is released in iscsi_handle_logout */
258 			idm_conn_hold(icp->conn_ic);
259 			(void) iscsi_handle_logout(icp);
260 		} else {
261 			icp->conn_state_destroy = B_FALSE;
262 			mutex_exit(&icp->conn_state_mutex);
263 			return (ISCSI_STATUS_INTERNAL_ERROR);
264 		}
265 		break;
266 	case ISCSI_CONN_STATE_IN_LOGIN:
267 	case ISCSI_CONN_STATE_IN_LOGOUT:
268 	case ISCSI_CONN_STATE_FAILED:
269 	case ISCSI_CONN_STATE_POLLING:
270 	default:
271 		icp->conn_state_destroy = B_FALSE;
272 		mutex_exit(&icp->conn_state_mutex);
273 		return (ISCSI_STATUS_INTERNAL_ERROR);
274 	}
275 	mutex_exit(&icp->conn_state_mutex);
276 
277 	return (ISCSI_STATUS_SUCCESS);
278 }
279 
280 /*
281  * iscsi_conn_destroy - This destroys an iscsi connection structure
282  * and de-associates it with the session.  The connection should
283  * already been in the ISCSI_CONN_STATE_FREE when attempting this
284  * operation.
285  */
286 iscsi_status_t
287 iscsi_conn_destroy(iscsi_conn_t *icp)
288 {
289 	iscsi_sess_t	*isp;
290 	iscsi_conn_t	*t_icp;
291 
292 	ASSERT(icp != NULL);
293 	isp = icp->conn_sess;
294 	ASSERT(isp != NULL);
295 
296 	if (icp->conn_state != ISCSI_CONN_STATE_FREE) {
297 		return (ISCSI_STATUS_INTERNAL_ERROR);
298 	}
299 
300 	/* Destroy transfer thread */
301 	iscsi_thread_destroy(icp->conn_tx_thread);
302 	ddi_taskq_destroy(icp->conn_cn_taskq);
303 
304 	/* Terminate connection queues */
305 	iscsi_destroy_queue(&icp->conn_queue_idm_aborting);
306 	iscsi_destroy_queue(&icp->conn_queue_active);
307 
308 	cv_destroy(&icp->conn_login_cv);
309 	mutex_destroy(&icp->conn_login_mutex);
310 	cv_destroy(&icp->conn_state_change);
311 	mutex_destroy(&icp->conn_state_mutex);
312 
313 	/*
314 	 * Remove connection from sessions linked list.
315 	 */
316 	if (isp->sess_conn_list == icp) {
317 		/* connection first item in list */
318 		isp->sess_conn_list = icp->conn_next;
319 		/*
320 		 * check if this is also the last item in the list
321 		 */
322 		if (isp->sess_conn_list_last_ptr == icp) {
323 			isp->sess_conn_list_last_ptr = NULL;
324 		}
325 	} else {
326 		/*
327 		 * search session list for icp pointing
328 		 * to connection being removed.  Then
329 		 * update that connections next pointer.
330 		 */
331 		t_icp = isp->sess_conn_list;
332 		while (t_icp->conn_next != NULL) {
333 			if (t_icp->conn_next == icp) {
334 				break;
335 			}
336 			t_icp = t_icp->conn_next;
337 		}
338 		if (t_icp->conn_next == icp) {
339 			t_icp->conn_next = icp->conn_next;
340 			/*
341 			 * if this is the last connection in the list
342 			 * update the last_ptr to point to t_icp
343 			 */
344 			if (isp->sess_conn_list_last_ptr == icp) {
345 				isp->sess_conn_list_last_ptr = t_icp;
346 			}
347 		} else {
348 			/* couldn't find session */
349 			ASSERT(FALSE);
350 		}
351 	}
352 
353 	/* Free this Connections Data */
354 	iscsi_conn_kstat_term(icp);
355 	kmem_free(icp, sizeof (iscsi_conn_t));
356 
357 	return (ISCSI_STATUS_SUCCESS);
358 }
359 
360 
361 /*
362  * iscsi_conn_set_login_min_max - set min/max login window
363  *
364  * Used to set the min and max login window.  Input values
365  * are in seconds.
366  */
367 void
368 iscsi_conn_set_login_min_max(iscsi_conn_t *icp, int min, int max)
369 {
370 	ASSERT(icp != NULL);
371 
372 	icp->conn_login_min = ddi_get_lbolt() + SEC_TO_TICK(min);
373 	icp->conn_login_max = ddi_get_lbolt() + SEC_TO_TICK(max);
374 }
375 
376 
377 /*
378  * Process the idm notifications
379  */
380 idm_status_t
381 iscsi_client_notify(idm_conn_t *ic, idm_client_notify_t icn, uintptr_t data)
382 {
383 	iscsi_cn_task_t		*cn;
384 	iscsi_conn_t		*icp = ic->ic_handle;
385 	iscsi_sess_t		*isp;
386 
387 	/*
388 	 * Don't access icp if the notification is CN_CONNECT_DESTROY
389 	 * since icp may have already been freed.
390 	 *
391 	 * In particular, we cannot audit the CN_CONNECT_DESTROY event.
392 	 *
393 	 * Handle a few cases immediately, the rest in a task queue.
394 	 */
395 	switch (icn) {
396 	case CN_CONNECT_FAIL:
397 	case CN_LOGIN_FAIL:
398 		/*
399 		 * Wakeup any thread waiting for login stuff to happen.
400 		 */
401 		ASSERT(icp != NULL);
402 
403 		mutex_enter(&icp->conn_state_mutex);
404 		idm_sm_audit_event(&icp->conn_state_audit,
405 		    SAS_ISCSI_CONN, icp->conn_state, icn, data);
406 		mutex_exit(&icp->conn_state_mutex);
407 		iscsi_login_update_state(icp, LOGIN_ERROR);
408 		return (IDM_STATUS_SUCCESS);
409 
410 	case CN_READY_FOR_LOGIN:
411 		idm_conn_hold(ic); /* Released in CN_CONNECT_LOST */
412 		ASSERT(icp != NULL);
413 
414 		mutex_enter(&icp->conn_state_mutex);
415 		idm_sm_audit_event(&icp->conn_state_audit,
416 		    SAS_ISCSI_CONN, icp->conn_state, icn, data);
417 		icp->conn_state_idm_connected = B_TRUE;
418 		cv_broadcast(&icp->conn_state_change);
419 		mutex_exit(&icp->conn_state_mutex);
420 
421 		iscsi_login_update_state(icp, LOGIN_READY);
422 		return (IDM_STATUS_SUCCESS);
423 
424 	case CN_CONNECT_DESTROY:
425 		/*
426 		 * We released any dependecies we had on this object in
427 		 * either CN_LOGIN_FAIL or CN_CONNECT_LOST so we just need
428 		 * to destroy the IDM connection now.
429 		 */
430 		idm_ini_conn_destroy(ic);
431 		return (IDM_STATUS_SUCCESS);
432 	}
433 
434 	ASSERT(icp != NULL);
435 	mutex_enter(&icp->conn_state_mutex);
436 	idm_sm_audit_event(&icp->conn_state_audit,
437 	    SAS_ISCSI_CONN, icp->conn_state, icn, data);
438 	mutex_exit(&icp->conn_state_mutex);
439 	isp = icp->conn_sess;
440 
441 	/*
442 	 * Dispatch notifications to the taskq since they often require
443 	 * long blocking operations.  In the case of CN_CONNECT_DESTROY
444 	 * we actually just want to destroy the connection which we
445 	 * can't do in the IDM taskq context.
446 	 */
447 	cn = kmem_alloc(sizeof (*cn), KM_SLEEP);
448 
449 	cn->ct_ic = ic;
450 	cn->ct_icn = icn;
451 	cn->ct_data = data;
452 
453 	idm_conn_hold(ic);
454 
455 	if (ddi_taskq_dispatch(icp->conn_cn_taskq,
456 	    iscsi_client_notify_task, cn, DDI_SLEEP) != DDI_SUCCESS) {
457 		idm_conn_rele(ic);
458 		cmn_err(CE_WARN, "iscsi connection(%u) failure - "
459 		    "unable to schedule notify task", icp->conn_oid);
460 		iscsi_conn_update_state(icp, ISCSI_CONN_STATE_FREE);
461 		mutex_enter(&isp->sess_state_mutex);
462 		iscsi_sess_state_machine(isp,
463 		    ISCSI_SESS_EVENT_N6);
464 		mutex_exit(&isp->sess_state_mutex);
465 	}
466 
467 	return (IDM_STATUS_SUCCESS);
468 }
469 
470 static void
471 iscsi_client_notify_task(void *cn_task_void)
472 {
473 	iscsi_cn_task_t		*cn_task = cn_task_void;
474 	iscsi_conn_t		*icp;
475 	iscsi_sess_t		*isp;
476 	idm_conn_t		*ic;
477 	idm_client_notify_t	icn;
478 	uintptr_t		data;
479 	idm_ffp_disable_t	disable_type;
480 	boolean_t		in_login;
481 
482 	ic = cn_task->ct_ic;
483 	icn = cn_task->ct_icn;
484 	data = cn_task->ct_data;
485 
486 	icp = ic->ic_handle;
487 	ASSERT(icp != NULL);
488 	isp = icp->conn_sess;
489 
490 	switch (icn) {
491 	case CN_FFP_ENABLED:
492 		mutex_enter(&icp->conn_state_mutex);
493 		icp->conn_async_logout = B_FALSE;
494 		icp->conn_state_ffp = B_TRUE;
495 		cv_broadcast(&icp->conn_state_change);
496 		mutex_exit(&icp->conn_state_mutex);
497 
498 		/*
499 		 * This logic assumes that the IDM login-snooping code
500 		 * and the initiator login code will agree to go when
501 		 * the connection is in FFP or final error received.
502 		 * The reason we do this is that we don't want to process
503 		 * CN_FFP_DISABLED until CN_FFP_ENABLED has been full handled.
504 		 */
505 		mutex_enter(&icp->conn_login_mutex);
506 		while ((icp->conn_login_state != LOGIN_FFP) &&
507 		    (icp->conn_login_state != LOGIN_ERROR)) {
508 			cv_wait(&icp->conn_login_cv, &icp->conn_login_mutex);
509 		}
510 		mutex_exit(&icp->conn_login_mutex);
511 		break;
512 	case CN_FFP_DISABLED:
513 		disable_type = (idm_ffp_disable_t)data;
514 
515 		mutex_enter(&icp->conn_state_mutex);
516 		switch (disable_type) {
517 		case FD_SESS_LOGOUT:
518 		case FD_CONN_LOGOUT:
519 			if (icp->conn_async_logout) {
520 				/*
521 				 * Our logout was in response to an
522 				 * async logout request so treat this
523 				 * like a connection failure (we will
524 				 * try to re-establish the connection)
525 				 */
526 				iscsi_conn_update_state_locked(icp,
527 				    ISCSI_CONN_STATE_FAILED);
528 			} else {
529 				/*
530 				 * Logout due to to user config change,
531 				 * we will not try to re-establish
532 				 * the connection.
533 				 */
534 				iscsi_conn_update_state_locked(icp,
535 				    ISCSI_CONN_STATE_IN_LOGOUT);
536 				/*
537 				 * Hold off generating the ISCSI_SESS_EVENT_N3
538 				 * event until we get the CN_CONNECT_LOST
539 				 * notification.  This matches the pre-IDM
540 				 * implementation better.
541 				 */
542 			}
543 			break;
544 
545 		case FD_CONN_FAIL:
546 		default:
547 			if (icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN) {
548 				iscsi_conn_update_state_locked(icp,
549 				    ISCSI_CONN_STATE_FREE);
550 			} else {
551 				iscsi_conn_update_state_locked(icp,
552 				    ISCSI_CONN_STATE_FAILED);
553 			}
554 			break;
555 		}
556 
557 		icp->conn_state_ffp = B_FALSE;
558 		cv_broadcast(&icp->conn_state_change);
559 		mutex_exit(&icp->conn_state_mutex);
560 
561 		break;
562 	case CN_CONNECT_LOST:
563 		/*
564 		 * We only care about CN_CONNECT_LOST if we've logged in.  IDM
565 		 * sends a flag as the data payload to indicate whether we
566 		 * were trying to login.  The CN_LOGIN_FAIL notification
567 		 * gives us what we need to know for login failures and
568 		 * otherwise we will need to keep a bunch of state to know
569 		 * what CN_CONNECT_LOST means to us.
570 		 */
571 		in_login = (boolean_t)data;
572 		if (in_login ||
573 		    (icp->conn_prev_state == ISCSI_CONN_STATE_IN_LOGIN)) {
574 			mutex_enter(&icp->conn_state_mutex);
575 
576 			icp->conn_state_idm_connected = B_FALSE;
577 			cv_broadcast(&icp->conn_state_change);
578 			mutex_exit(&icp->conn_state_mutex);
579 
580 			/* Release connect hold from CN_READY_FOR_LOGIN */
581 			idm_conn_rele(ic);
582 			break;
583 		}
584 
585 		/* Any remaining commands are never going to finish */
586 		iscsi_conn_flush_active_cmds(icp);
587 
588 		/*
589 		 * The connection is no longer active so cleanup any
590 		 * references to the connection and release any holds so
591 		 * that IDM can finish cleanup.
592 		 */
593 		mutex_enter(&icp->conn_state_mutex);
594 		if (icp->conn_state != ISCSI_CONN_STATE_FAILED) {
595 
596 			mutex_enter(&isp->sess_state_mutex);
597 			iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N3);
598 			mutex_exit(&isp->sess_state_mutex);
599 
600 			iscsi_conn_update_state_locked(icp,
601 			    ISCSI_CONN_STATE_FREE);
602 		} else {
603 
604 			mutex_enter(&isp->sess_state_mutex);
605 			iscsi_sess_state_machine(isp,
606 			    ISCSI_SESS_EVENT_N5);
607 			mutex_exit(&isp->sess_state_mutex);
608 
609 			/*
610 			 * If session type is NORMAL, try to reestablish the
611 			 * connection.
612 			 */
613 			if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
614 				iscsi_conn_retry(isp, icp);
615 			} else {
616 
617 				mutex_enter(&isp->sess_state_mutex);
618 				iscsi_sess_state_machine(isp,
619 				    ISCSI_SESS_EVENT_N6);
620 				mutex_exit(&isp->sess_state_mutex);
621 
622 				iscsi_conn_update_state_locked(icp,
623 				    ISCSI_CONN_STATE_FREE);
624 			}
625 		}
626 
627 		(void) iscsi_thread_stop(icp->conn_tx_thread);
628 
629 		icp->conn_state_idm_connected = B_FALSE;
630 		cv_broadcast(&icp->conn_state_change);
631 		mutex_exit(&icp->conn_state_mutex);
632 
633 		/* Release connect hold from CN_READY_FOR_LOGIN */
634 		idm_conn_rele(ic);
635 		break;
636 	default:
637 		ISCSI_CONN_LOG(CE_WARN,
638 		    "iscsi_client_notify: unknown notification: "
639 		    "%x: NOT IMPLEMENTED YET: icp: %p ic: %p ",
640 		    icn, (void *)icp, (void *)ic);
641 		break;
642 	}
643 	/* free the task notify structure we allocated in iscsi_client_notify */
644 	kmem_free(cn_task, sizeof (*cn_task));
645 
646 	/* Release the hold we acquired in iscsi_client_notify */
647 	idm_conn_rele(ic);
648 }
649 
650 /*
651  * iscsi_conn_sync_params - used to update connection parameters
652  *
653  * Used to update connection parameters with current configured
654  * parameters in the persistent store.  This should be called
655  * before starting to make a new iscsi connection in iscsi_login.
656  */
657 iscsi_status_t
658 iscsi_conn_sync_params(iscsi_conn_t *icp)
659 {
660 	iscsi_sess_t		*isp;
661 	iscsi_hba_t		*ihp;
662 	int			param_id;
663 	persistent_param_t	pp;
664 	persistent_tunable_param_t	ptp;
665 	iscsi_config_sess_t	*ics;
666 	int			idx, size;
667 	char			*name;
668 
669 	ASSERT(icp != NULL);
670 	ASSERT((icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN) ||
671 	    (icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
672 	    (icp->conn_state == ISCSI_CONN_STATE_POLLING));
673 	isp = icp->conn_sess;
674 	ASSERT(isp != NULL);
675 	ihp = isp->sess_hba;
676 	ASSERT(ihp != NULL);
677 
678 	/*
679 	 * Check if someone is trying to destroy this
680 	 * connection.  If so fail the sync request,
681 	 * as a method of fast fail.
682 	 */
683 	if (icp->conn_state_destroy == B_TRUE) {
684 		return (ISCSI_STATUS_SHUTDOWN);
685 	}
686 
687 	bzero(&pp, sizeof (pp));
688 
689 	/* First get a copy of the HBA params */
690 	bcopy(&ihp->hba_params, &icp->conn_params,
691 	    sizeof (iscsi_login_params_t));
692 	bcopy(&ihp->hba_tunable_params, &icp->conn_tunable_params,
693 	    sizeof (iscsi_tunable_params_t));
694 
695 	/*
696 	 * Now we need to get the session configured
697 	 * values from the persistent store and apply
698 	 * them to our connection.
699 	 */
700 	(void) persistent_param_get((char *)isp->sess_name, &pp);
701 	for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM;
702 	    param_id++) {
703 		if (iscsiboot_prop && modrootloaded &&
704 		    !iscsi_chk_bootlun_mpxio(ihp) && isp->sess_boot) {
705 			/*
706 			 * iscsi boot with mpxio disabled
707 			 * while iscsi booting target's parameter overriden
708 			 * do no update target's parameters.
709 			 */
710 			if (pp.p_bitmap) {
711 				cmn_err(CE_NOTE, "Adopting "
712 				    " default login parameters in"
713 				    " boot session as MPxIO is disabled");
714 			}
715 			break;
716 		}
717 		if (pp.p_bitmap & (1 << param_id)) {
718 
719 			switch (param_id) {
720 			/*
721 			 * Boolean parameters
722 			 */
723 			case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER:
724 				icp->conn_params.data_pdu_in_order =
725 				    pp.p_params.data_pdu_in_order;
726 				break;
727 			case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA:
728 				icp->conn_params.immediate_data =
729 				    pp.p_params.immediate_data;
730 				break;
731 			case ISCSI_LOGIN_PARAM_INITIAL_R2T:
732 				icp->conn_params.initial_r2t =
733 				    pp.p_params.initial_r2t;
734 				break;
735 			case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER:
736 				icp->conn_params.data_pdu_in_order =
737 				    pp.p_params.data_pdu_in_order;
738 				break;
739 			/*
740 			 * Integer parameters
741 			 */
742 			case ISCSI_LOGIN_PARAM_HEADER_DIGEST:
743 				icp->conn_params.header_digest =
744 				    pp.p_params.header_digest;
745 				break;
746 			case ISCSI_LOGIN_PARAM_DATA_DIGEST:
747 				icp->conn_params.data_digest =
748 				    pp.p_params.data_digest;
749 				break;
750 			case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN:
751 				icp->conn_params.default_time_to_retain =
752 				    pp.p_params.default_time_to_retain;
753 				break;
754 			case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT:
755 				icp->conn_params.default_time_to_wait =
756 				    pp.p_params.default_time_to_wait;
757 				break;
758 			case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH:
759 				icp->conn_params.max_recv_data_seg_len =
760 				    pp.p_params.max_recv_data_seg_len;
761 				break;
762 			case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH:
763 				icp->conn_params.first_burst_length =
764 				    pp.p_params.first_burst_length;
765 				break;
766 			case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH:
767 				icp->conn_params.max_burst_length =
768 				    pp.p_params.max_burst_length;
769 				break;
770 
771 			/*
772 			 * Integer parameters which currently are unsettable
773 			 */
774 			case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS:
775 				/* FALLTHRU */
776 			case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T:
777 				/* FALLTHRU */
778 			case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL:
779 				/* FALLTHRU */
780 			default:
781 				break;
782 			}
783 		}
784 	}
785 
786 	if (persistent_get_tunable_param((char *)isp->sess_name, &ptp) ==
787 	    B_TRUE) {
788 		if (ptp.p_bitmap & ISCSI_TUNABLE_PARAM_RX_TIMEOUT_VALUE) {
789 			icp->conn_tunable_params.recv_login_rsp_timeout =
790 			    ptp.p_params.recv_login_rsp_timeout;
791 		}
792 		if (ptp.p_bitmap & ISCSI_TUNABLE_PARAM_CONN_LOGIN_MAX) {
793 			icp->conn_tunable_params.conn_login_max =
794 			    ptp.p_params.conn_login_max;
795 		}
796 		if (ptp.p_bitmap & ISCSI_TUNABLE_PARAM_LOGIN_POLLING_DELAY) {
797 			icp->conn_tunable_params.polling_login_delay =
798 			    ptp.p_params.polling_login_delay;
799 		}
800 	}
801 
802 	/* Skip binding checks on discovery sessions */
803 	if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) {
804 		return (ISCSI_STATUS_SUCCESS);
805 	}
806 
807 	/*
808 	 * Now we need to get the current optional connection
809 	 * binding information.
810 	 */
811 	/* setup initial buffer for configured session information */
812 	size = sizeof (*ics);
813 	ics = kmem_zalloc(size, KM_SLEEP);
814 	ics->ics_in = 1;
815 
816 	/* get configured sessions information */
817 	name = (char *)isp->sess_name;
818 	if (persistent_get_config_session(name, ics) == B_FALSE) {
819 		/*
820 		 * If we were unable to get target level information
821 		 * then check the initiator level information.
822 		 */
823 		name = (char *)isp->sess_hba->hba_name;
824 		if (persistent_get_config_session(name, ics) == B_FALSE) {
825 			/*
826 			 * No hba information is found.  So assume default
827 			 * one session unbound behavior.
828 			 */
829 			ics->ics_out = 1;
830 			ics->ics_bound = B_FALSE;
831 		}
832 	}
833 
834 	if (iscsiboot_prop && (ics->ics_out > 1) && isp->sess_boot &&
835 	    !iscsi_chk_bootlun_mpxio(ihp)) {
836 		/*
837 		 * iscsi booting session with mpxio disabled,
838 		 * no need set multiple sessions for booting session
839 		 */
840 		ics->ics_out = 1;
841 		ics->ics_bound = B_FALSE;
842 		cmn_err(CE_NOTE, "MPxIO is disabled,"
843 		    " no need to configure multiple boot sessions");
844 	}
845 
846 	/*
847 	 * Check to make sure this session is still a configured
848 	 * session.  The user might have decreased the session
849 	 * count. (NOTE: byte 5 of the sess_isid is the session
850 	 * count (via MS/T).  This counter starts at 0.)
851 	 */
852 
853 
854 	idx = isp->sess_isid[5];
855 
856 	if (iscsiboot_prop && (idx == ISCSI_MAX_CONFIG_SESSIONS)) {
857 		/*
858 		 * This is temporary session for boot session propose
859 		 * no need to bound IP for this session
860 		 */
861 		icp->conn_bound = B_FALSE;
862 		kmem_free(ics, sizeof (iscsi_config_sess_t));
863 		return (ISCSI_STATUS_SUCCESS);
864 	}
865 
866 	if (ics->ics_out <= idx) {
867 		/*
868 		 * No longer a configured session.  Return a
869 		 * failure so we don't attempt to relogin.
870 		 */
871 		return (ISCSI_STATUS_SHUTDOWN);
872 	}
873 
874 	/*
875 	 * If sessions are unbound set this information on
876 	 * the connection and return success.
877 	 */
878 	if (ics->ics_bound == B_FALSE) {
879 		icp->conn_bound = B_FALSE;
880 		kmem_free(ics, sizeof (iscsi_config_sess_t));
881 		return (ISCSI_STATUS_SUCCESS);
882 	}
883 
884 	/*
885 	 * Since the sessions are bound we need to find the matching
886 	 * binding information for the session's isid.  If this
887 	 * session's isid is > 0 then we need to get more configured
888 	 * session information to find the binding info.
889 	 */
890 	if (idx > 0) {
891 		int ics_out;
892 
893 		ics_out = ics->ics_out;
894 		/* record new size and free last buffer */
895 		size = ISCSI_SESSION_CONFIG_SIZE(ics_out);
896 		kmem_free(ics, sizeof (*ics));
897 
898 		/* allocate new buffer */
899 		ics = kmem_zalloc(size, KM_SLEEP);
900 		ics->ics_in = ics_out;
901 
902 		/* get configured sessions information */
903 		if (persistent_get_config_session(name, ics) != B_TRUE) {
904 			cmn_err(CE_NOTE, "iscsi session(%d) - "
905 			    "unable to get configured session information\n",
906 			    isp->sess_oid);
907 			kmem_free(ics, size);
908 			return (ISCSI_STATUS_SHUTDOWN);
909 		}
910 	}
911 
912 	/* Copy correct binding information to the connection */
913 	icp->conn_bound = B_TRUE;
914 	if (ics->ics_bindings[idx].i_insize == sizeof (struct in_addr)) {
915 		bcopy(&ics->ics_bindings[idx].i_addr.in4,
916 		    &icp->conn_bound_addr.sin4.sin_addr.s_addr,
917 		    sizeof (struct in_addr));
918 		icp->conn_bound_addr.sin4.sin_family = AF_INET;
919 	} else {
920 		bcopy(&ics->ics_bindings[idx].i_addr.in6,
921 		    &icp->conn_bound_addr.sin6.sin6_addr.s6_addr,
922 		    sizeof (struct in6_addr));
923 		icp->conn_bound_addr.sin6.sin6_family = AF_INET6;
924 	}
925 
926 	kmem_free(ics, size);
927 
928 	return (ISCSI_STATUS_SUCCESS);
929 }
930 
931 /*
932  * +--------------------------------------------------------------------+
933  * | Internal Connection Interfaces					|
934  * +--------------------------------------------------------------------+
935  */
936 
937 /*
938  * iscsi_conn_flush_active_cmds - flush all active icmdps
939  *	for a connection.
940  */
941 static void
942 iscsi_conn_flush_active_cmds(iscsi_conn_t *icp)
943 {
944 	iscsi_cmd_t	*icmdp;
945 	iscsi_sess_t	*isp;
946 	boolean_t	lock_held = B_FALSE;
947 
948 	ASSERT(icp != NULL);
949 	isp = icp->conn_sess;
950 	ASSERT(isp != NULL);
951 
952 	if (mutex_owned(&icp->conn_queue_active.mutex)) {
953 		lock_held = B_TRUE;
954 	} else {
955 		mutex_enter(&icp->conn_queue_active.mutex);
956 	}
957 
958 	/* Flush active queue */
959 	icmdp = icp->conn_queue_active.head;
960 	while (icmdp != NULL) {
961 
962 		mutex_enter(&icmdp->cmd_mutex);
963 		if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
964 			icmdp->cmd_un.scsi.pkt_stat |= STAT_ABORTED;
965 		}
966 		mutex_exit(&icmdp->cmd_mutex);
967 
968 		iscsi_cmd_state_machine(icmdp,
969 		    ISCSI_CMD_EVENT_E7, isp);
970 		icmdp = icp->conn_queue_active.head;
971 	}
972 
973 	/* Wait for active queue to drain */
974 	while (icp->conn_queue_active.count) {
975 		mutex_exit(&icp->conn_queue_active.mutex);
976 		delay(drv_usectohz(100000));
977 		mutex_enter(&icp->conn_queue_active.mutex);
978 	}
979 
980 	if (lock_held == B_FALSE) {
981 		mutex_exit(&icp->conn_queue_active.mutex);
982 	}
983 
984 	/* Wait for IDM abort queue to drain (if necessary) */
985 	mutex_enter(&icp->conn_queue_idm_aborting.mutex);
986 	while (icp->conn_queue_idm_aborting.count) {
987 		mutex_exit(&icp->conn_queue_idm_aborting.mutex);
988 		delay(drv_usectohz(100000));
989 		mutex_enter(&icp->conn_queue_idm_aborting.mutex);
990 	}
991 	mutex_exit(&icp->conn_queue_idm_aborting.mutex);
992 }
993 
994 /*
995  * iscsi_conn_retry - retry connect/login
996  */
997 void
998 iscsi_conn_retry(iscsi_sess_t *isp, iscsi_conn_t *icp)
999 {
1000 	iscsi_task_t *itp;
1001 
1002 	ASSERT(isp != NULL);
1003 	ASSERT(icp != NULL);
1004 
1005 	/* set login min/max time values */
1006 	iscsi_conn_set_login_min_max(icp,
1007 	    ISCSI_CONN_DEFAULT_LOGIN_MIN,
1008 	    icp->conn_tunable_params.conn_login_max);
1009 
1010 	ISCSI_CONN_LOG(CE_NOTE, "DEBUG: iscsi_conn_retry: icp: %p icp: %p ",
1011 	    (void *)icp,
1012 	    (void *)icp->conn_ic);
1013 
1014 	/*
1015 	 * Sync base connection information before login.
1016 	 * A login redirection might have shifted the
1017 	 * current information from the base.
1018 	 */
1019 	bcopy(&icp->conn_base_addr, &icp->conn_curr_addr,
1020 	    sizeof (icp->conn_curr_addr));
1021 
1022 	/* schedule login task */
1023 	itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
1024 	itp->t_arg = icp;
1025 	itp->t_blocking = B_FALSE;
1026 	if (ddi_taskq_dispatch(isp->sess_taskq,
1027 	    (void(*)())iscsi_login_start, itp, DDI_SLEEP) !=
1028 	    DDI_SUCCESS) {
1029 		kmem_free(itp, sizeof (iscsi_task_t));
1030 		cmn_err(CE_WARN, "iscsi connection(%u) failure - "
1031 		    "unable to schedule login task", icp->conn_oid);
1032 
1033 		iscsi_conn_update_state(icp, ISCSI_CONN_STATE_FREE);
1034 		mutex_enter(&isp->sess_state_mutex);
1035 		iscsi_sess_state_machine(isp,
1036 		    ISCSI_SESS_EVENT_N6);
1037 		mutex_exit(&isp->sess_state_mutex);
1038 	}
1039 }
1040 
1041 void
1042 iscsi_conn_update_state(iscsi_conn_t *icp, iscsi_conn_state_t
1043 			    next_state)
1044 {
1045 	mutex_enter(&icp->conn_state_mutex);
1046 	(void) iscsi_conn_update_state_locked(icp, next_state);
1047 	mutex_exit(&icp->conn_state_mutex);
1048 }
1049 
1050 void
1051 iscsi_conn_update_state_locked(iscsi_conn_t *icp,
1052 	    iscsi_conn_state_t next_state)
1053 {
1054 	ASSERT(mutex_owned(&icp->conn_state_mutex));
1055 	next_state = (next_state > ISCSI_CONN_STATE_MAX) ?
1056 	    ISCSI_CONN_STATE_MAX : next_state;
1057 	idm_sm_audit_state_change(&icp->conn_state_audit,
1058 	    SAS_ISCSI_CONN, icp->conn_state, next_state);
1059 	switch (next_state) {
1060 	case ISCSI_CONN_STATE_FREE:
1061 	case ISCSI_CONN_STATE_IN_LOGIN:
1062 	case ISCSI_CONN_STATE_LOGGED_IN:
1063 	case ISCSI_CONN_STATE_IN_LOGOUT:
1064 	case ISCSI_CONN_STATE_FAILED:
1065 	case ISCSI_CONN_STATE_POLLING:
1066 		ISCSI_CONN_LOG(CE_NOTE,
1067 		    "iscsi_conn_update_state conn %p %s(%d) -> %s(%d)",
1068 		    (void *)icp,
1069 		    iscsi_ics_name[icp->conn_state], icp->conn_state,
1070 		    iscsi_ics_name[next_state], next_state);
1071 		icp->conn_prev_state = icp->conn_state;
1072 		icp->conn_state = next_state;
1073 		cv_broadcast(&icp->conn_state_change);
1074 		break;
1075 	default:
1076 		cmn_err(CE_WARN, "Update state found illegal state: %x "
1077 		    "prev_state: %x", next_state, icp->conn_prev_state);
1078 		ASSERT(0);
1079 	}
1080 }
1081