xref: /illumos-gate/usr/src/uts/common/io/idm/idm_conn_sm.c (revision 5fe3b0929d8a195dbfa4196d72a3f9b15b745171)
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 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2013 by Delphix. All rights reserved.
25  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
26  * Copyright 2020 Joyent, Inc.
27  */
28 
29 #include <sys/cpuvar.h>
30 #include <sys/ddi.h>
31 #include <sys/sunddi.h>
32 #include <sys/modctl.h>
33 #include <sys/socket.h>
34 #include <sys/strsubr.h>
35 #include <sys/note.h>
36 #include <sys/sdt.h>
37 
38 #define	IDM_CONN_SM_STRINGS
39 #define	IDM_CN_NOTIFY_STRINGS
40 #include <sys/idm/idm.h>
41 
42 boolean_t	idm_sm_logging = B_FALSE;
43 
44 extern idm_global_t	idm; /* Global state */
45 
46 static void
47 idm_conn_event_handler(void *event_ctx_opaque);
48 
49 static void
50 idm_state_s1_free(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
51 
52 static void
53 idm_state_s2_xpt_wait(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
54 
55 static void
56 idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
57 
58 static void
59 idm_state_s4_in_login(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
60 
61 static void
62 idm_state_s5_logged_in(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
63 
64 static void
65 idm_state_s6_in_logout(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
66 
67 static void
68 idm_logout_req_timeout(void *arg);
69 
70 static void
71 idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
72 
73 static void
74 idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
75 
76 static void
77 idm_state_s9_init_error(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
78 
79 static void
80 idm_state_s9a_rejected(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
81 
82 static void
83 idm_state_s9b_wait_snd_done_cb(idm_pdu_t *pdu,
84     idm_status_t status);
85 
86 static void
87 idm_state_s9b_wait_snd_done(idm_conn_t *ic,
88     idm_conn_event_ctx_t *event_ctx);
89 
90 static void
91 idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
92 
93 static void
94 idm_state_s11_complete(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
95 
96 static void
97 idm_state_s12_enable_dm(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
98 
99 static void
100 idm_update_state(idm_conn_t *ic, idm_conn_state_t new_state,
101     idm_conn_event_ctx_t *event_ctx);
102 
103 static void
104 idm_conn_unref(void *ic_void);
105 
106 static void
107 idm_conn_reject_unref(void *ic_void);
108 
109 static idm_pdu_event_action_t
110 idm_conn_sm_validate_pdu(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx,
111     idm_pdu_t *pdu);
112 
113 static idm_status_t
114 idm_ffp_enable(idm_conn_t *ic);
115 
116 static void
117 idm_ffp_disable(idm_conn_t *ic, idm_ffp_disable_t disable_type);
118 
119 static void
120 idm_initial_login_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
121 
122 static void
123 idm_login_success_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
124 
125 idm_status_t
idm_conn_sm_init(idm_conn_t * ic)126 idm_conn_sm_init(idm_conn_t *ic)
127 {
128 	char taskq_name[32];
129 
130 	/*
131 	 * Caller should have assigned a unique connection ID.  Use this
132 	 * connection ID to create a unique connection name string
133 	 */
134 	ASSERT(ic->ic_internal_cid != 0);
135 	(void) snprintf(taskq_name, sizeof (taskq_name) - 1, "conn_sm%08x",
136 	    ic->ic_internal_cid);
137 
138 	ic->ic_state_taskq = taskq_create(taskq_name, 1, minclsyspri, 4, 16384,
139 	    TASKQ_PREPOPULATE);
140 	if (ic->ic_state_taskq == NULL) {
141 		return (IDM_STATUS_FAIL);
142 	}
143 
144 	idm_sm_audit_init(&ic->ic_state_audit);
145 	mutex_init(&ic->ic_state_mutex, NULL, MUTEX_DEFAULT, NULL);
146 	cv_init(&ic->ic_state_cv, NULL, CV_DEFAULT, NULL);
147 
148 	ic->ic_state = CS_S1_FREE;
149 	ic->ic_last_state = CS_S1_FREE;
150 
151 	return (IDM_STATUS_SUCCESS);
152 }
153 
154 void
idm_conn_sm_fini(idm_conn_t * ic)155 idm_conn_sm_fini(idm_conn_t *ic)
156 {
157 
158 	/*
159 	 * The connection may only be partially created. If there
160 	 * is no taskq, then the connection SM was not initialized.
161 	 */
162 	if (ic->ic_state_taskq == NULL) {
163 		return;
164 	}
165 
166 	taskq_destroy(ic->ic_state_taskq);
167 
168 	cv_destroy(&ic->ic_state_cv);
169 	/*
170 	 * The thread that generated the event that got us here may still
171 	 * hold the ic_state_mutex. Once it is released we can safely
172 	 * destroy it since there is no way to locate the object now.
173 	 */
174 	mutex_enter(&ic->ic_state_mutex);
175 	IDM_SM_TIMER_CLEAR(ic);
176 	mutex_destroy(&ic->ic_state_mutex);
177 }
178 
179 void
idm_conn_event(idm_conn_t * ic,idm_conn_event_t event,uintptr_t event_info)180 idm_conn_event(idm_conn_t *ic, idm_conn_event_t event, uintptr_t event_info)
181 {
182 	mutex_enter(&ic->ic_state_mutex);
183 	idm_conn_event_locked(ic, event, event_info, CT_NONE);
184 	mutex_exit(&ic->ic_state_mutex);
185 }
186 
187 
188 idm_status_t
idm_conn_reinstate_event(idm_conn_t * old_ic,idm_conn_t * new_ic)189 idm_conn_reinstate_event(idm_conn_t *old_ic, idm_conn_t *new_ic)
190 {
191 	int result;
192 
193 	mutex_enter(&old_ic->ic_state_mutex);
194 	if (((old_ic->ic_conn_type == CONN_TYPE_INI) &&
195 	    (old_ic->ic_state != CS_S8_CLEANUP)) ||
196 	    ((old_ic->ic_conn_type == CONN_TYPE_TGT) &&
197 	    (old_ic->ic_state < CS_S5_LOGGED_IN))) {
198 		result = IDM_STATUS_FAIL;
199 	} else {
200 		result = IDM_STATUS_SUCCESS;
201 		new_ic->ic_reinstate_conn = old_ic;
202 		idm_conn_event_locked(new_ic->ic_reinstate_conn,
203 		    CE_CONN_REINSTATE, (uintptr_t)new_ic, CT_NONE);
204 	}
205 	mutex_exit(&old_ic->ic_state_mutex);
206 
207 	return (result);
208 }
209 
210 void
idm_conn_tx_pdu_event(idm_conn_t * ic,idm_conn_event_t event,uintptr_t event_info)211 idm_conn_tx_pdu_event(idm_conn_t *ic, idm_conn_event_t event,
212     uintptr_t event_info)
213 {
214 	ASSERT(mutex_owned(&ic->ic_state_mutex));
215 	ic->ic_pdu_events++;
216 	idm_conn_event_locked(ic, event, event_info, CT_TX_PDU);
217 }
218 
219 void
idm_conn_rx_pdu_event(idm_conn_t * ic,idm_conn_event_t event,uintptr_t event_info)220 idm_conn_rx_pdu_event(idm_conn_t *ic, idm_conn_event_t event,
221     uintptr_t event_info)
222 {
223 	ASSERT(mutex_owned(&ic->ic_state_mutex));
224 	ic->ic_pdu_events++;
225 	idm_conn_event_locked(ic, event, event_info, CT_RX_PDU);
226 }
227 
228 void
idm_conn_event_locked(idm_conn_t * ic,idm_conn_event_t event,uintptr_t event_info,idm_pdu_event_type_t pdu_event_type)229 idm_conn_event_locked(idm_conn_t *ic, idm_conn_event_t event,
230     uintptr_t event_info, idm_pdu_event_type_t pdu_event_type)
231 {
232 	idm_conn_event_ctx_t	*event_ctx;
233 
234 	ASSERT(mutex_owned(&ic->ic_state_mutex));
235 
236 	idm_sm_audit_event(&ic->ic_state_audit, SAS_IDM_CONN,
237 	    (int)ic->ic_state, (int)event, event_info);
238 
239 	/*
240 	 * It's very difficult to prevent a few straggling events
241 	 * at the end.  For example idm_sorx_thread will generate
242 	 * a CE_TRANSPORT_FAIL event when it exits.  Rather than
243 	 * push complicated restrictions all over the code to
244 	 * prevent this we will simply drop the events (and in
245 	 * the case of PDU events release them appropriately)
246 	 * since they are irrelevant once we are in a terminal state.
247 	 * Of course those threads need to have appropriate holds on
248 	 * the connection otherwise it might disappear.
249 	 */
250 	if ((ic->ic_state == CS_S9_INIT_ERROR) ||
251 	    (ic->ic_state == CS_S9A_REJECTED) ||
252 	    (ic->ic_state == CS_S11_COMPLETE)) {
253 		if ((pdu_event_type == CT_TX_PDU) ||
254 		    (pdu_event_type == CT_RX_PDU)) {
255 			ic->ic_pdu_events--;
256 			idm_pdu_complete((idm_pdu_t *)event_info,
257 			    IDM_STATUS_SUCCESS);
258 		}
259 		IDM_SM_LOG(CE_NOTE, "*** Dropping event %s (%d) because of"
260 		    "state %s (%d)",
261 		    idm_ce_name[event], event,
262 		    idm_cs_name[ic->ic_state], ic->ic_state);
263 		return;
264 	}
265 
266 	/*
267 	 * Normal event handling
268 	 */
269 	idm_conn_hold(ic);
270 
271 	event_ctx = kmem_zalloc(sizeof (*event_ctx), KM_SLEEP);
272 	event_ctx->iec_ic = ic;
273 	event_ctx->iec_event = event;
274 	event_ctx->iec_info = event_info;
275 	event_ctx->iec_pdu_event_type = pdu_event_type;
276 
277 	(void) taskq_dispatch(ic->ic_state_taskq, &idm_conn_event_handler,
278 	    event_ctx, TQ_SLEEP);
279 }
280 
281 static void
idm_conn_event_handler(void * event_ctx_opaque)282 idm_conn_event_handler(void *event_ctx_opaque)
283 {
284 	idm_conn_event_ctx_t *event_ctx = event_ctx_opaque;
285 	idm_conn_t *ic = event_ctx->iec_ic;
286 	idm_pdu_t *pdu = (idm_pdu_t *)event_ctx->iec_info;
287 	idm_pdu_event_action_t action;
288 
289 	IDM_SM_LOG(CE_NOTE, "idm_conn_event_handler: conn %p event %s(%d)",
290 	    (void *)ic, idm_ce_name[event_ctx->iec_event],
291 	    event_ctx->iec_event);
292 	DTRACE_PROBE2(conn__event,
293 	    idm_conn_t *, ic, idm_conn_event_ctx_t *, event_ctx);
294 
295 	/*
296 	 * Validate event
297 	 */
298 	ASSERT(event_ctx->iec_event != CE_UNDEFINED);
299 	ASSERT3U(event_ctx->iec_event, <, CE_MAX_EVENT);
300 
301 	/*
302 	 * Validate current state
303 	 */
304 	ASSERT(ic->ic_state != CS_S0_UNDEFINED);
305 	ASSERT3U(ic->ic_state, <, CS_MAX_STATE);
306 
307 	/*
308 	 * Validate PDU-related events against the current state.  If a PDU
309 	 * is not allowed in the current state we change the event to a
310 	 * protocol error.  This simplifies the state-specific event handlers.
311 	 * For example the CS_S2_XPT_WAIT state only needs to handle the
312 	 * CE_TX_PROTOCOL_ERROR and CE_RX_PROTOCOL_ERROR events since
313 	 * no PDU's can be transmitted or received in that state.
314 	 */
315 	event_ctx->iec_pdu_forwarded = B_FALSE;
316 	if (event_ctx->iec_pdu_event_type != CT_NONE) {
317 		ASSERT(pdu != NULL);
318 		action = idm_conn_sm_validate_pdu(ic, event_ctx, pdu);
319 
320 		switch (action) {
321 		case CA_TX_PROTOCOL_ERROR:
322 			/*
323 			 * Change event and forward the PDU
324 			 */
325 			event_ctx->iec_event = CE_TX_PROTOCOL_ERROR;
326 			break;
327 		case CA_RX_PROTOCOL_ERROR:
328 			/*
329 			 * Change event and forward the PDU.
330 			 */
331 			event_ctx->iec_event = CE_RX_PROTOCOL_ERROR;
332 			break;
333 		case CA_FORWARD:
334 			/*
335 			 * Let the state-specific event handlers take
336 			 * care of it.
337 			 */
338 			break;
339 		case CA_DROP:
340 			/*
341 			 * It never even happened
342 			 */
343 			IDM_SM_LOG(CE_NOTE, "*** drop PDU %p", (void *) pdu);
344 			idm_pdu_complete(pdu, IDM_STATUS_FAIL);
345 			event_ctx->iec_info = (uintptr_t)NULL;
346 			break;
347 		default:
348 			ASSERT(0);
349 			break;
350 		}
351 	}
352 
353 	switch (ic->ic_state) {
354 	case CS_S1_FREE:
355 		idm_state_s1_free(ic, event_ctx);
356 		break;
357 	case CS_S2_XPT_WAIT:
358 		idm_state_s2_xpt_wait(ic, event_ctx);
359 		break;
360 	case CS_S3_XPT_UP:
361 		idm_state_s3_xpt_up(ic, event_ctx);
362 		break;
363 	case CS_S4_IN_LOGIN:
364 		idm_state_s4_in_login(ic, event_ctx);
365 		break;
366 	case CS_S5_LOGGED_IN:
367 		idm_state_s5_logged_in(ic, event_ctx);
368 		break;
369 	case CS_S6_IN_LOGOUT:
370 		idm_state_s6_in_logout(ic, event_ctx);
371 		break;
372 	case CS_S7_LOGOUT_REQ:
373 		idm_state_s7_logout_req(ic, event_ctx);
374 		break;
375 	case CS_S8_CLEANUP:
376 		idm_state_s8_cleanup(ic, event_ctx);
377 		break;
378 	case CS_S9A_REJECTED:
379 		idm_state_s9a_rejected(ic, event_ctx);
380 		break;
381 	case CS_S9B_WAIT_SND_DONE:
382 		idm_state_s9b_wait_snd_done(ic, event_ctx);
383 		break;
384 	case CS_S9_INIT_ERROR:
385 		idm_state_s9_init_error(ic, event_ctx);
386 		break;
387 	case CS_S10_IN_CLEANUP:
388 		idm_state_s10_in_cleanup(ic, event_ctx);
389 		break;
390 	case CS_S11_COMPLETE:
391 		idm_state_s11_complete(ic, event_ctx);
392 		break;
393 	case CS_S12_ENABLE_DM:
394 		idm_state_s12_enable_dm(ic, event_ctx);
395 		break;
396 	default:
397 		ASSERT(0);
398 		break;
399 	}
400 
401 	/*
402 	 * Now that we've updated the state machine, if this was
403 	 * a PDU-related event take the appropriate action on the PDU
404 	 * (transmit it, forward it to the clients RX callback, drop
405 	 * it, etc).
406 	 */
407 	if (event_ctx->iec_pdu_event_type != CT_NONE) {
408 		switch (action) {
409 		case CA_TX_PROTOCOL_ERROR:
410 			idm_pdu_tx_protocol_error(ic, pdu);
411 			break;
412 		case CA_RX_PROTOCOL_ERROR:
413 			idm_pdu_rx_protocol_error(ic, pdu);
414 			break;
415 		case CA_FORWARD:
416 			if (!event_ctx->iec_pdu_forwarded) {
417 				if (event_ctx->iec_pdu_event_type ==
418 				    CT_RX_PDU) {
419 					idm_pdu_rx_forward(ic, pdu);
420 				} else {
421 					idm_pdu_tx_forward(ic, pdu);
422 				}
423 			}
424 			break;
425 		case CA_DROP:
426 			/* Already completed above. */
427 			ASSERT3P(event_ctx->iec_info, ==, NULL);
428 			break;
429 		default:
430 			ASSERT(0);
431 			break;
432 		}
433 	}
434 
435 	/*
436 	 * Update outstanding PDU event count (see idm_pdu_tx for
437 	 * how this is used)
438 	 */
439 	if ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ||
440 	    (event_ctx->iec_pdu_event_type == CT_RX_PDU)) {
441 		mutex_enter(&ic->ic_state_mutex);
442 		ic->ic_pdu_events--;
443 		mutex_exit(&ic->ic_state_mutex);
444 	}
445 
446 	idm_conn_rele(ic);
447 	kmem_free(event_ctx, sizeof (*event_ctx));
448 }
449 
450 static void
idm_state_s1_free(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)451 idm_state_s1_free(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
452 {
453 	switch (event_ctx->iec_event) {
454 	case CE_CONNECT_REQ:
455 		/* T1 */
456 		idm_update_state(ic, CS_S2_XPT_WAIT, event_ctx);
457 		break;
458 	case CE_CONNECT_ACCEPT:
459 		/* T3 */
460 		idm_update_state(ic, CS_S3_XPT_UP, event_ctx);
461 		break;
462 	case CE_TX_PROTOCOL_ERROR:
463 	case CE_RX_PROTOCOL_ERROR:
464 		/* This should never happen */
465 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
466 		break;
467 	default:
468 		ASSERT(0);
469 		/*NOTREACHED*/
470 	}
471 }
472 
473 
474 static void
idm_state_s2_xpt_wait(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)475 idm_state_s2_xpt_wait(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
476 {
477 	switch (event_ctx->iec_event) {
478 	case CE_CONNECT_SUCCESS:
479 		/* T4 */
480 		idm_update_state(ic, CS_S4_IN_LOGIN, event_ctx);
481 		break;
482 	case CE_TRANSPORT_FAIL:
483 	case CE_CONNECT_FAIL:
484 	case CE_LOGOUT_OTHER_CONN_RCV:
485 	case CE_TX_PROTOCOL_ERROR:
486 	case CE_RX_PROTOCOL_ERROR:
487 		/* T2 */
488 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
489 		break;
490 	default:
491 		ASSERT(0);
492 		/*NOTREACHED*/
493 	}
494 }
495 
496 
497 static void
idm_login_timeout(void * arg)498 idm_login_timeout(void *arg)
499 {
500 	idm_conn_t *ic = arg;
501 
502 	ic->ic_state_timeout = 0;
503 	idm_conn_event(ic, CE_LOGIN_TIMEOUT, (uintptr_t)NULL);
504 }
505 
506 static void
idm_state_s3_xpt_up(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)507 idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
508 {
509 	switch (event_ctx->iec_event) {
510 	case CE_LOGIN_RCV:
511 		/* T4 */
512 		/* Keep login timeout active through S3 and into S4 */
513 		idm_initial_login_actions(ic, event_ctx);
514 		idm_update_state(ic, CS_S4_IN_LOGIN, event_ctx);
515 		break;
516 	case CE_LOGIN_TIMEOUT:
517 		/*
518 		 * Don't need to cancel login timer since the timer is
519 		 * presumed to be the source of this event.
520 		 */
521 		(void) idm_notify_client(ic, CN_LOGIN_FAIL, (uintptr_t)NULL);
522 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
523 		break;
524 	case CE_CONNECT_REJECT:
525 		/*
526 		 * Iscsit doesn't want to hear from us again in this case.
527 		 * Since it rejected the connection it doesn't have a
528 		 * connection context to handle additional notifications.
529 		 * IDM needs to just clean things up on its own.
530 		 */
531 		IDM_SM_TIMER_CLEAR(ic);
532 		idm_update_state(ic, CS_S9A_REJECTED, event_ctx);
533 		break;
534 	case CE_CONNECT_FAIL:
535 	case CE_TRANSPORT_FAIL:
536 	case CE_LOGOUT_OTHER_CONN_SND:
537 		/* T6 */
538 		IDM_SM_TIMER_CLEAR(ic);
539 		(void) idm_notify_client(ic, CN_LOGIN_FAIL, (uintptr_t)NULL);
540 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
541 		break;
542 	case CE_TX_PROTOCOL_ERROR:
543 	case CE_RX_PROTOCOL_ERROR:
544 		/* Don't care */
545 		break;
546 	default:
547 		ASSERT(0);
548 		/*NOTREACHED*/
549 	}
550 }
551 
552 static void
idm_state_s4_in_login(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)553 idm_state_s4_in_login(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
554 {
555 	idm_pdu_t *pdu;
556 
557 	/*
558 	 * Login timer should no longer be active after leaving this
559 	 * state.
560 	 */
561 	switch (event_ctx->iec_event) {
562 	case CE_LOGIN_SUCCESS_RCV:
563 	case CE_LOGIN_SUCCESS_SND:
564 		ASSERT(ic->ic_client_callback == NULL);
565 
566 		IDM_SM_TIMER_CLEAR(ic);
567 		idm_login_success_actions(ic, event_ctx);
568 		if (ic->ic_rdma_extensions) {
569 			/* T19 */
570 			idm_update_state(ic, CS_S12_ENABLE_DM, event_ctx);
571 		} else {
572 			/* T5 */
573 			idm_update_state(ic, CS_S5_LOGGED_IN, event_ctx);
574 		}
575 		break;
576 	case CE_LOGIN_TIMEOUT:
577 		/* T7 */
578 		(void) idm_notify_client(ic, CN_LOGIN_FAIL, (uintptr_t)NULL);
579 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
580 		break;
581 	case CE_LOGIN_FAIL_SND:
582 		/*
583 		 * Allow the logout response pdu to be sent and defer
584 		 * the state machine cleanup until the completion callback.
585 		 * Only 1 level or callback interposition is allowed.
586 		 */
587 		IDM_SM_TIMER_CLEAR(ic);
588 		pdu = (idm_pdu_t *)event_ctx->iec_info;
589 		ASSERT(ic->ic_client_callback == NULL);
590 		ic->ic_client_callback = pdu->isp_callback;
591 		pdu->isp_callback =
592 		    idm_state_s9b_wait_snd_done_cb;
593 		idm_update_state(ic, CS_S9B_WAIT_SND_DONE,
594 		    event_ctx);
595 		break;
596 	case CE_LOGIN_FAIL_RCV:
597 		ASSERT(ic->ic_client_callback == NULL);
598 		/*
599 		 * Need to deliver this PDU to the initiator now because after
600 		 * we update the state to CS_S9_INIT_ERROR the initiator will
601 		 * no longer be in an appropriate state.
602 		 */
603 		event_ctx->iec_pdu_forwarded = B_TRUE;
604 		pdu = (idm_pdu_t *)event_ctx->iec_info;
605 		idm_pdu_rx_forward(ic, pdu);
606 		/* FALLTHROUGH */
607 	case CE_TRANSPORT_FAIL:
608 	case CE_LOGOUT_OTHER_CONN_SND:
609 	case CE_LOGOUT_OTHER_CONN_RCV:
610 		/* T7 */
611 		IDM_SM_TIMER_CLEAR(ic);
612 		(void) idm_notify_client(ic, CN_LOGIN_FAIL, (uintptr_t)NULL);
613 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
614 		break;
615 	case CE_LOGOUT_SESSION_SUCCESS:
616 		/*
617 		 * T8
618 		 * A session reinstatement request can be received while a
619 		 * session is active and a login is in process. The iSCSI
620 		 * connections are shut down by a CE_LOGOUT_SESSION_SUCCESS
621 		 * event sent from the session to the IDM layer.
622 		 */
623 		IDM_SM_TIMER_CLEAR(ic);
624 		if (IDM_CONN_ISTGT(ic)) {
625 			ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
626 		} else {
627 			ic->ic_transport_ops->it_ini_conn_disconnect(ic);
628 		}
629 		idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
630 		break;
631 
632 	case CE_LOGIN_SND:
633 		ASSERT(ic->ic_client_callback == NULL);
634 		/*
635 		 * Initiator connections will see initial login PDU
636 		 * in this state.  Target connections see initial
637 		 * login PDU in "xpt up" state.
638 		 */
639 		mutex_enter(&ic->ic_state_mutex);
640 		if (!(ic->ic_state_flags & CF_INITIAL_LOGIN)) {
641 			idm_initial_login_actions(ic, event_ctx);
642 		}
643 		mutex_exit(&ic->ic_state_mutex);
644 		break;
645 	case CE_MISC_TX:
646 	case CE_MISC_RX:
647 	case CE_LOGIN_RCV:
648 	case CE_TX_PROTOCOL_ERROR:
649 	case CE_RX_PROTOCOL_ERROR:
650 		/* Don't care */
651 		break;
652 	default:
653 		ASSERT(0);
654 		/*NOTREACHED*/
655 	}
656 }
657 
658 
659 static void
idm_state_s5_logged_in(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)660 idm_state_s5_logged_in(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
661 {
662 	switch (event_ctx->iec_event) {
663 	case CE_MISC_RX:
664 		/* MC/S: when removing the non-leading connection */
665 	case CE_LOGOUT_THIS_CONN_RCV:
666 	case CE_LOGOUT_THIS_CONN_SND:
667 	case CE_LOGOUT_OTHER_CONN_RCV:
668 	case CE_LOGOUT_OTHER_CONN_SND:
669 		/* T9 */
670 		idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */
671 		idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
672 		break;
673 	case CE_LOGOUT_SESSION_RCV:
674 	case CE_LOGOUT_SESSION_SND:
675 		/* T9 */
676 		idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
677 		idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
678 		break;
679 	case CE_LOGOUT_SESSION_SUCCESS:
680 		/* T8 */
681 		idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
682 
683 		/* Close connection */
684 		if (IDM_CONN_ISTGT(ic)) {
685 			ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
686 		} else {
687 			ic->ic_transport_ops->it_ini_conn_disconnect(ic);
688 		}
689 
690 		idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
691 		break;
692 	case CE_ASYNC_LOGOUT_RCV:
693 	case CE_ASYNC_LOGOUT_SND:
694 		/* T11 */
695 		idm_update_state(ic, CS_S7_LOGOUT_REQ, event_ctx);
696 		break;
697 	case CE_TRANSPORT_FAIL:
698 	case CE_ASYNC_DROP_CONN_RCV:
699 	case CE_ASYNC_DROP_CONN_SND:
700 	case CE_ASYNC_DROP_ALL_CONN_RCV:
701 	case CE_ASYNC_DROP_ALL_CONN_SND:
702 		/* T15 */
703 		idm_ffp_disable(ic, FD_CONN_FAIL); /* Implicit logout */
704 		idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
705 		break;
706 	case CE_MISC_TX:
707 	case CE_TX_PROTOCOL_ERROR:
708 	case CE_RX_PROTOCOL_ERROR:
709 	case CE_LOGIN_TIMEOUT:
710 		/* Don't care */
711 		break;
712 	default:
713 		ASSERT(0);
714 	}
715 }
716 
717 static void
idm_state_s6_in_logout_success_snd_done(idm_pdu_t * pdu,idm_status_t status)718 idm_state_s6_in_logout_success_snd_done(idm_pdu_t *pdu, idm_status_t status)
719 {
720 	idm_conn_t		*ic = pdu->isp_ic;
721 
722 	/*
723 	 * This pdu callback can be invoked by the tx thread,
724 	 * so run the disconnect code from another thread.
725 	 */
726 	pdu->isp_status = status;
727 	idm_conn_event(ic, CE_LOGOUT_SUCCESS_SND_DONE, (uintptr_t)pdu);
728 }
729 
730 static void
idm_state_s6_in_logout_fail_snd_done(idm_pdu_t * pdu,idm_status_t status)731 idm_state_s6_in_logout_fail_snd_done(idm_pdu_t *pdu, idm_status_t status)
732 {
733 	idm_conn_t		*ic = pdu->isp_ic;
734 
735 	/*
736 	 * This pdu callback can be invoked by the tx thread,
737 	 * so run the disconnect code from another thread.
738 	 */
739 	pdu->isp_status = status;
740 	idm_conn_event(ic, CE_LOGOUT_FAIL_SND_DONE, (uintptr_t)pdu);
741 }
742 
743 static void
idm_state_s6_in_logout(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)744 idm_state_s6_in_logout(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
745 {
746 	idm_pdu_t *pdu;
747 
748 	switch (event_ctx->iec_event) {
749 	case CE_LOGOUT_SUCCESS_SND_DONE:
750 		pdu = (idm_pdu_t *)event_ctx->iec_info;
751 
752 		/* Close connection (if it's not already closed) */
753 		ASSERT(IDM_CONN_ISTGT(ic));
754 		ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
755 
756 		/* restore client callback */
757 		pdu->isp_callback =  ic->ic_client_callback;
758 		ic->ic_client_callback = NULL;
759 		idm_pdu_complete(pdu, pdu->isp_status);
760 		idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
761 		break;
762 	case CE_LOGOUT_FAIL_SND_DONE:
763 		pdu = (idm_pdu_t *)event_ctx->iec_info;
764 		/* restore client callback */
765 		pdu->isp_callback =  ic->ic_client_callback;
766 		ic->ic_client_callback = NULL;
767 		idm_pdu_complete(pdu, pdu->isp_status);
768 		idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
769 		break;
770 	case CE_LOGOUT_SUCCESS_SND:
771 	case CE_LOGOUT_FAIL_SND:
772 		/*
773 		 * Allow the logout response pdu to be sent and defer
774 		 * the state machine update until the completion callback.
775 		 * Only 1 level or callback interposition is allowed.
776 		 */
777 		pdu = (idm_pdu_t *)event_ctx->iec_info;
778 		ASSERT(ic->ic_client_callback == NULL);
779 		ic->ic_client_callback = pdu->isp_callback;
780 		if (event_ctx->iec_event == CE_LOGOUT_SUCCESS_SND) {
781 			pdu->isp_callback =
782 			    idm_state_s6_in_logout_success_snd_done;
783 		} else {
784 			pdu->isp_callback =
785 			    idm_state_s6_in_logout_fail_snd_done;
786 		}
787 		break;
788 	case CE_LOGOUT_SUCCESS_RCV:
789 		/*
790 		 * Need to deliver this PDU to the initiator now because after
791 		 * we update the state to CS_S11_COMPLETE the initiator will
792 		 * no longer be in an appropriate state.
793 		 */
794 		event_ctx->iec_pdu_forwarded = B_TRUE;
795 		pdu = (idm_pdu_t *)event_ctx->iec_info;
796 		idm_pdu_rx_forward(ic, pdu);
797 		/* FALLTHROUGH */
798 	case CE_LOGOUT_SESSION_SUCCESS:
799 		/* T13 */
800 
801 		/* Close connection (if it's not already closed) */
802 		if (IDM_CONN_ISTGT(ic)) {
803 			ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
804 		} else {
805 			ic->ic_transport_ops->it_ini_conn_disconnect(ic);
806 		}
807 
808 		idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
809 		break;
810 	case CE_ASYNC_LOGOUT_RCV:
811 		/* T14 Do nothing */
812 		break;
813 	case CE_TRANSPORT_FAIL:
814 	case CE_ASYNC_DROP_CONN_RCV:
815 	case CE_ASYNC_DROP_CONN_SND:
816 	case CE_ASYNC_DROP_ALL_CONN_RCV:
817 	case CE_ASYNC_DROP_ALL_CONN_SND:
818 	case CE_LOGOUT_FAIL_RCV:
819 		idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
820 		break;
821 	case CE_TX_PROTOCOL_ERROR:
822 	case CE_RX_PROTOCOL_ERROR:
823 	case CE_MISC_TX:
824 	case CE_MISC_RX:
825 	case CE_LOGIN_TIMEOUT:
826 		/* Don't care */
827 		break;
828 	default:
829 		ASSERT(0);
830 	}
831 }
832 
833 
834 static void
idm_logout_req_timeout(void * arg)835 idm_logout_req_timeout(void *arg)
836 {
837 	idm_conn_t *ic = arg;
838 
839 	ic->ic_state_timeout = 0;
840 	idm_conn_event(ic, CE_LOGOUT_TIMEOUT, (uintptr_t)NULL);
841 }
842 
843 static void
idm_state_s7_logout_req(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)844 idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
845 {
846 	/* Must cancel logout timer before leaving this state */
847 	switch (event_ctx->iec_event) {
848 	case CE_LOGOUT_THIS_CONN_RCV:
849 	case CE_LOGOUT_THIS_CONN_SND:
850 	case CE_LOGOUT_OTHER_CONN_RCV:
851 	case CE_LOGOUT_OTHER_CONN_SND:
852 		/* T10 */
853 		if (IDM_CONN_ISTGT(ic)) {
854 			IDM_SM_TIMER_CLEAR(ic);
855 		}
856 		idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */
857 		idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
858 		break;
859 	case CE_LOGOUT_SESSION_RCV:
860 	case CE_LOGOUT_SESSION_SND:
861 		/* T10 */
862 		if (IDM_CONN_ISTGT(ic)) {
863 			IDM_SM_TIMER_CLEAR(ic);
864 		}
865 		idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
866 		idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
867 		break;
868 	case CE_ASYNC_LOGOUT_RCV:
869 	case CE_ASYNC_LOGOUT_SND:
870 		/* T12 Do nothing */
871 		break;
872 	case CE_TRANSPORT_FAIL:
873 	case CE_ASYNC_DROP_CONN_RCV:
874 	case CE_ASYNC_DROP_CONN_SND:
875 	case CE_ASYNC_DROP_ALL_CONN_RCV:
876 	case CE_ASYNC_DROP_ALL_CONN_SND:
877 		/* T16 */
878 		if (IDM_CONN_ISTGT(ic)) {
879 			IDM_SM_TIMER_CLEAR(ic);
880 		}
881 		/* FALLTHROUGH */
882 	case CE_LOGOUT_TIMEOUT:
883 		idm_ffp_disable(ic, FD_CONN_FAIL); /* Implicit logout */
884 		idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
885 		break;
886 	case CE_LOGOUT_SESSION_SUCCESS:
887 		/* T18 */
888 		if (IDM_CONN_ISTGT(ic)) {
889 			IDM_SM_TIMER_CLEAR(ic);
890 		}
891 		idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
892 
893 		/* Close connection (if it's not already closed) */
894 		if (IDM_CONN_ISTGT(ic)) {
895 			ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
896 		} else {
897 			ic->ic_transport_ops->it_ini_conn_disconnect(ic);
898 		}
899 
900 		idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
901 		break;
902 	case CE_TX_PROTOCOL_ERROR:
903 	case CE_RX_PROTOCOL_ERROR:
904 	case CE_MISC_TX:
905 	case CE_MISC_RX:
906 	case CE_LOGIN_TIMEOUT:
907 		/* Don't care */
908 		break;
909 	default:
910 		ASSERT(0);
911 	}
912 }
913 
914 
915 static void
idm_cleanup_timeout(void * arg)916 idm_cleanup_timeout(void *arg)
917 {
918 	idm_conn_t *ic = arg;
919 
920 	ic->ic_state_timeout = 0;
921 	idm_conn_event(ic, CE_CLEANUP_TIMEOUT, (uintptr_t)NULL);
922 }
923 
924 static void
idm_state_s8_cleanup(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)925 idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
926 {
927 	idm_pdu_t *pdu;
928 
929 	/*
930 	 * Need to cancel the cleanup timeout before leaving this state
931 	 * if it hasn't already fired.
932 	 */
933 	switch (event_ctx->iec_event) {
934 	case CE_LOGOUT_SUCCESS_RCV:
935 	case CE_LOGOUT_SUCCESS_SND:
936 	case CE_LOGOUT_SESSION_SUCCESS:
937 		IDM_SM_TIMER_CLEAR(ic);
938 		/*FALLTHROUGH*/
939 	case CE_CLEANUP_TIMEOUT:
940 		/* M1 */
941 		idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
942 		break;
943 	case CE_LOGOUT_OTHER_CONN_RCV:
944 	case CE_LOGOUT_OTHER_CONN_SND:
945 		/* M2 */
946 		idm_update_state(ic, CS_S10_IN_CLEANUP, event_ctx);
947 		break;
948 	case CE_LOGOUT_SUCCESS_SND_DONE:
949 	case CE_LOGOUT_FAIL_SND_DONE:
950 		pdu = (idm_pdu_t *)event_ctx->iec_info;
951 		/* restore client callback */
952 		pdu->isp_callback =  ic->ic_client_callback;
953 		ic->ic_client_callback = NULL;
954 		idm_pdu_complete(pdu, pdu->isp_status);
955 		break;
956 	case CE_LOGOUT_SESSION_RCV:
957 	case CE_LOGOUT_SESSION_SND:
958 	case CE_TX_PROTOCOL_ERROR:
959 	case CE_RX_PROTOCOL_ERROR:
960 	case CE_MISC_TX:
961 	case CE_MISC_RX:
962 	case CE_TRANSPORT_FAIL:
963 	case CE_LOGIN_TIMEOUT:
964 	case CE_LOGOUT_TIMEOUT:
965 		/* Don't care */
966 		break;
967 	default:
968 		ASSERT(0);
969 	}
970 }
971 
972 /* ARGSUSED */
973 static void
idm_state_s9_init_error(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)974 idm_state_s9_init_error(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
975 {
976 	/* All events ignored in this state */
977 }
978 
979 /* ARGSUSED */
980 static void
idm_state_s9a_rejected(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)981 idm_state_s9a_rejected(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
982 {
983 	/* All events ignored in this state */
984 }
985 
986 
987 static void
idm_state_s9b_wait_snd_done_cb(idm_pdu_t * pdu,idm_status_t status)988 idm_state_s9b_wait_snd_done_cb(idm_pdu_t *pdu, idm_status_t status)
989 {
990 	idm_conn_t		*ic = pdu->isp_ic;
991 
992 	/*
993 	 * This pdu callback can be invoked by the tx thread,
994 	 * so run the disconnect code from another thread.
995 	 */
996 	pdu->isp_status = status;
997 	idm_conn_event(ic, CE_LOGIN_FAIL_SND_DONE, (uintptr_t)pdu);
998 }
999 
1000 /*
1001  * CS_S9B_WAIT_SND_DONE -- wait for callback completion.
1002  */
1003 /* ARGSUSED */
1004 static void
idm_state_s9b_wait_snd_done(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)1005 idm_state_s9b_wait_snd_done(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1006 {
1007 	idm_pdu_t *pdu;
1008 	/*
1009 	 * Wait for completion of the login fail sequence and then
1010 	 * go to state S9_INIT_ERROR to clean up the connection.
1011 	 */
1012 	switch (event_ctx->iec_event) {
1013 	case CE_LOGIN_FAIL_SND_DONE:
1014 		pdu = (idm_pdu_t *)event_ctx->iec_info;
1015 		/* restore client callback */
1016 		pdu->isp_callback =  ic->ic_client_callback;
1017 		ic->ic_client_callback = NULL;
1018 		idm_pdu_complete(pdu, pdu->isp_status);
1019 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
1020 		break;
1021 
1022 	/* All other events ignored */
1023 	}
1024 }
1025 
1026 
1027 
1028 
1029 static void
idm_state_s10_in_cleanup(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)1030 idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1031 {
1032 	idm_pdu_t *pdu;
1033 
1034 	/*
1035 	 * Need to cancel the cleanup timeout before leaving this state
1036 	 * if it hasn't already fired.
1037 	 */
1038 	switch (event_ctx->iec_event) {
1039 	case CE_LOGOUT_FAIL_RCV:
1040 	case CE_LOGOUT_FAIL_SND:
1041 		idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
1042 		break;
1043 	case CE_LOGOUT_SUCCESS_SND:
1044 	case CE_LOGOUT_SUCCESS_RCV:
1045 	case CE_LOGOUT_SESSION_SUCCESS:
1046 		IDM_SM_TIMER_CLEAR(ic);
1047 		/*FALLTHROUGH*/
1048 	case CE_CLEANUP_TIMEOUT:
1049 		idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
1050 		break;
1051 	case CE_LOGOUT_SUCCESS_SND_DONE:
1052 	case CE_LOGOUT_FAIL_SND_DONE:
1053 		pdu = (idm_pdu_t *)event_ctx->iec_info;
1054 		/* restore client callback */
1055 		pdu->isp_callback =  ic->ic_client_callback;
1056 		ic->ic_client_callback = NULL;
1057 		idm_pdu_complete(pdu, pdu->isp_status);
1058 		break;
1059 	case CE_TX_PROTOCOL_ERROR:
1060 	case CE_RX_PROTOCOL_ERROR:
1061 	case CE_MISC_TX:
1062 	case CE_MISC_RX:
1063 	case CE_LOGIN_TIMEOUT:
1064 	case CE_LOGOUT_TIMEOUT:
1065 		/* Don't care */
1066 		break;
1067 	default:
1068 		ASSERT(0);
1069 	}
1070 }
1071 
1072 /* ARGSUSED */
1073 static void
idm_state_s11_complete(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)1074 idm_state_s11_complete(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1075 {
1076 	idm_pdu_t *pdu;
1077 
1078 	/*
1079 	 * Cleanup logout success/fail completion if it's been delayed
1080 	 * until now.
1081 	 *
1082 	 * All new events are filtered out before reaching this state, but
1083 	 * there might already be events in the event queue, so handle the
1084 	 * SND_DONE events here. Note that if either of the following
1085 	 * SND_DONE events happens AFTER the change to state S11, then the
1086 	 * event filter inside dm_conn_event_locked does enough cleanup.
1087 	 */
1088 	switch (event_ctx->iec_event) {
1089 	case CE_LOGOUT_SUCCESS_SND_DONE:
1090 	case CE_LOGOUT_FAIL_SND_DONE:
1091 		pdu = (idm_pdu_t *)event_ctx->iec_info;
1092 		/* restore client callback */
1093 		pdu->isp_callback =  ic->ic_client_callback;
1094 		ic->ic_client_callback = NULL;
1095 		idm_pdu_complete(pdu, pdu->isp_status);
1096 		break;
1097 	}
1098 
1099 }
1100 
1101 static void
idm_state_s12_enable_dm(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)1102 idm_state_s12_enable_dm(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1103 {
1104 	switch (event_ctx->iec_event) {
1105 	case CE_ENABLE_DM_SUCCESS:
1106 		/* T20 */
1107 		idm_update_state(ic, CS_S5_LOGGED_IN, event_ctx);
1108 		break;
1109 	case CE_ENABLE_DM_FAIL:
1110 		/* T21 */
1111 		idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
1112 		break;
1113 	case CE_TRANSPORT_FAIL:
1114 		/*
1115 		 * We expect to always hear back from the transport layer
1116 		 * once we have an "enable data-mover" request outstanding.
1117 		 * Therefore we'll ignore other events that may occur even
1118 		 * when they clearly indicate a problem and wait for
1119 		 * CE_ENABLE_DM_FAIL.  On a related note this means the
1120 		 * transport must ensure that it eventually completes the
1121 		 * "enable data-mover" operation with either success or
1122 		 * failure -- otherwise we'll be stuck here.
1123 		 */
1124 		break;
1125 	default:
1126 		ASSERT(0);
1127 		break;
1128 	}
1129 }
1130 
1131 static void
idm_update_state(idm_conn_t * ic,idm_conn_state_t new_state,idm_conn_event_ctx_t * event_ctx)1132 idm_update_state(idm_conn_t *ic, idm_conn_state_t new_state,
1133     idm_conn_event_ctx_t *event_ctx)
1134 {
1135 	int rc;
1136 	idm_status_t idm_status;
1137 
1138 	/*
1139 	 * Validate new state
1140 	 */
1141 	ASSERT(new_state != CS_S0_UNDEFINED);
1142 	ASSERT3U(new_state, <, CS_MAX_STATE);
1143 
1144 	/*
1145 	 * Update state in context.  We protect this with a mutex
1146 	 * even though the state machine code is single threaded so that
1147 	 * other threads can check the state value atomically.
1148 	 */
1149 	new_state = (new_state < CS_MAX_STATE) ?
1150 	    new_state : CS_S0_UNDEFINED;
1151 
1152 	IDM_SM_LOG(CE_NOTE, "idm_update_state: conn %p, evt %s(%d), "
1153 	    "%s(%d) --> %s(%d)", (void *)ic,
1154 	    idm_ce_name[event_ctx->iec_event], event_ctx->iec_event,
1155 	    idm_cs_name[ic->ic_state], ic->ic_state,
1156 	    idm_cs_name[new_state], new_state);
1157 
1158 	DTRACE_PROBE2(conn__state__change,
1159 	    idm_conn_t *, ic, idm_conn_state_t, new_state);
1160 
1161 	mutex_enter(&ic->ic_state_mutex);
1162 	idm_sm_audit_state_change(&ic->ic_state_audit, SAS_IDM_CONN,
1163 	    (int)ic->ic_state, (int)new_state);
1164 	ic->ic_last_state = ic->ic_state;
1165 	ic->ic_state = new_state;
1166 	cv_signal(&ic->ic_state_cv);
1167 	mutex_exit(&ic->ic_state_mutex);
1168 
1169 	switch (ic->ic_state) {
1170 	case CS_S1_FREE:
1171 		ASSERT(0); /* Initial state, can't return */
1172 		break;
1173 	case CS_S2_XPT_WAIT:
1174 		if ((rc = idm_ini_conn_finish(ic)) != 0) {
1175 			idm_conn_event(ic, CE_CONNECT_FAIL, (uintptr_t)NULL);
1176 		} else {
1177 			idm_conn_event(ic, CE_CONNECT_SUCCESS, (uintptr_t)NULL);
1178 		}
1179 		break;
1180 	case CS_S3_XPT_UP:
1181 		/*
1182 		 * Finish any connection related setup including
1183 		 * waking up the idm_tgt_conn_accept thread.
1184 		 * and starting the login timer.  If the function
1185 		 * fails then we return to "free" state.
1186 		 */
1187 		if ((rc = idm_tgt_conn_finish(ic)) != IDM_STATUS_SUCCESS) {
1188 			switch (rc) {
1189 			case IDM_STATUS_REJECT:
1190 				idm_conn_event(ic, CE_CONNECT_REJECT,
1191 				    (uintptr_t)NULL);
1192 				break;
1193 			default:
1194 				idm_conn_event(ic, CE_CONNECT_FAIL,
1195 				    (uintptr_t)NULL);
1196 				break;
1197 			}
1198 		}
1199 
1200 		/*
1201 		 * First login received will cause a transition to
1202 		 * CS_S4_IN_LOGIN.  Start login timer.
1203 		 */
1204 		IDM_SM_TIMER_CHECK(ic);
1205 		ic->ic_state_timeout = timeout(idm_login_timeout, ic,
1206 		    drv_usectohz(IDM_LOGIN_SECONDS * 1000000));
1207 		break;
1208 	case CS_S4_IN_LOGIN:
1209 		if (ic->ic_conn_type == CONN_TYPE_INI) {
1210 			(void) idm_notify_client(ic, CN_READY_FOR_LOGIN,
1211 			    (uintptr_t)NULL);
1212 			mutex_enter(&ic->ic_state_mutex);
1213 			ic->ic_state_flags |= CF_LOGIN_READY;
1214 			cv_signal(&ic->ic_state_cv);
1215 			mutex_exit(&ic->ic_state_mutex);
1216 		}
1217 		break;
1218 	case CS_S5_LOGGED_IN:
1219 		ASSERT(!ic->ic_ffp);
1220 		/*
1221 		 * IDM can go to FFP before the initiator but it
1222 		 * needs to go to FFP after the target (IDM target should
1223 		 * go to FFP after notify_ack).
1224 		 */
1225 		idm_status = idm_ffp_enable(ic);
1226 		if (idm_status != IDM_STATUS_SUCCESS) {
1227 			idm_conn_event(ic, CE_TRANSPORT_FAIL, (uintptr_t)NULL);
1228 		}
1229 
1230 		if (ic->ic_reinstate_conn) {
1231 			/* Connection reinstatement is complete */
1232 			idm_conn_event(ic->ic_reinstate_conn,
1233 			    CE_CONN_REINSTATE_SUCCESS, (uintptr_t)NULL);
1234 		}
1235 		break;
1236 	case CS_S6_IN_LOGOUT:
1237 		break;
1238 	case CS_S7_LOGOUT_REQ:
1239 		/* Start logout timer for target connections */
1240 		if (IDM_CONN_ISTGT(ic)) {
1241 			IDM_SM_TIMER_CHECK(ic);
1242 			ic->ic_state_timeout = timeout(idm_logout_req_timeout,
1243 			    ic, drv_usectohz(IDM_LOGOUT_SECONDS*1000000));
1244 		}
1245 		break;
1246 	case CS_S8_CLEANUP:
1247 		/* Close connection (if it's not already closed) */
1248 		if (IDM_CONN_ISTGT(ic)) {
1249 			ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
1250 		} else {
1251 			ic->ic_transport_ops->it_ini_conn_disconnect(ic);
1252 		}
1253 
1254 		/* Stop executing active tasks */
1255 		(void) idm_task_abort(ic, NULL, AT_INTERNAL_SUSPEND);
1256 
1257 		/* Start logout timer */
1258 		IDM_SM_TIMER_CHECK(ic);
1259 		ic->ic_state_timeout = timeout(idm_cleanup_timeout, ic,
1260 		    drv_usectohz(IDM_CLEANUP_SECONDS*1000000));
1261 		break;
1262 	case CS_S10_IN_CLEANUP:
1263 		break;
1264 	case CS_S9A_REJECTED:
1265 		/*
1266 		 * We never finished establishing the connection so no
1267 		 * disconnect.  No client notifications because the client
1268 		 * rejected the connection.
1269 		 */
1270 		idm_refcnt_async_wait_ref(&ic->ic_refcnt,
1271 		    &idm_conn_reject_unref);
1272 		break;
1273 	case CS_S9B_WAIT_SND_DONE:
1274 		break;
1275 	case CS_S9_INIT_ERROR:
1276 		if (IDM_CONN_ISTGT(ic)) {
1277 			ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
1278 		} else {
1279 			mutex_enter(&ic->ic_state_mutex);
1280 			ic->ic_state_flags |= CF_ERROR;
1281 			ic->ic_conn_sm_status = IDM_STATUS_FAIL;
1282 			cv_signal(&ic->ic_state_cv);
1283 			mutex_exit(&ic->ic_state_mutex);
1284 			if (ic->ic_last_state != CS_S1_FREE &&
1285 			    ic->ic_last_state != CS_S2_XPT_WAIT) {
1286 				ic->ic_transport_ops->it_ini_conn_disconnect(
1287 				    ic);
1288 			} else {
1289 				(void) idm_notify_client(ic, CN_CONNECT_FAIL,
1290 				    (uintptr_t)NULL);
1291 			}
1292 		}
1293 		/*FALLTHROUGH*/
1294 	case CS_S11_COMPLETE:
1295 		/*
1296 		 * No more traffic on this connection.  If this is an
1297 		 * initiator connection and we weren't connected yet
1298 		 * then don't send the "connect lost" event.
1299 		 * It's useful to the initiator to know whether we were
1300 		 * logging in at the time so send that information in the
1301 		 * data field.
1302 		 */
1303 		if (IDM_CONN_ISTGT(ic) ||
1304 		    ((ic->ic_last_state != CS_S1_FREE) &&
1305 		    (ic->ic_last_state != CS_S2_XPT_WAIT))) {
1306 			(void) idm_notify_client(ic, CN_CONNECT_LOST,
1307 			    (uintptr_t)(ic->ic_last_state == CS_S4_IN_LOGIN));
1308 		}
1309 
1310 		/* Abort all tasks */
1311 		(void) idm_task_abort(ic, NULL, AT_INTERNAL_ABORT);
1312 
1313 		/*
1314 		 * Handle terminal state actions on the global taskq so
1315 		 * we can clean up all the connection resources from
1316 		 * a separate thread context.
1317 		 */
1318 		idm_refcnt_async_wait_ref(&ic->ic_refcnt, &idm_conn_unref);
1319 		break;
1320 	case CS_S12_ENABLE_DM:
1321 
1322 		/*
1323 		 * The Enable DM state indicates the initiator to initiate
1324 		 * the hello sequence and the target to get ready to accept
1325 		 * the iSER Hello Message.
1326 		 */
1327 		idm_status = (IDM_CONN_ISINI(ic)) ?
1328 		    ic->ic_transport_ops->it_ini_enable_datamover(ic) :
1329 		    ic->ic_transport_ops->it_tgt_enable_datamover(ic);
1330 
1331 		if (idm_status == IDM_STATUS_SUCCESS) {
1332 			idm_conn_event(ic, CE_ENABLE_DM_SUCCESS,
1333 			    (uintptr_t)NULL);
1334 		} else {
1335 			idm_conn_event(ic, CE_ENABLE_DM_FAIL, (uintptr_t)NULL);
1336 		}
1337 
1338 		break;
1339 
1340 	default:
1341 		ASSERT(0);
1342 		break;
1343 
1344 	}
1345 }
1346 
1347 
1348 static void
idm_conn_unref(void * ic_void)1349 idm_conn_unref(void *ic_void)
1350 {
1351 	idm_conn_t *ic = ic_void;
1352 
1353 	/*
1354 	 * Client should not be notified that the connection is destroyed
1355 	 * until all references on the idm connection have been removed.
1356 	 * Otherwise references on the associated client context would need
1357 	 * to be tracked separately which seems like a waste (at least when
1358 	 * there is a one for one correspondence with references on the
1359 	 * IDM connection).
1360 	 */
1361 	if (IDM_CONN_ISTGT(ic)) {
1362 		(void) idm_notify_client(ic, CN_CONNECT_DESTROY,
1363 		    (uintptr_t)NULL);
1364 		idm_svc_conn_destroy(ic);
1365 	} else {
1366 		/* Initiator may destroy connection during this call */
1367 		(void) idm_notify_client(ic, CN_CONNECT_DESTROY,
1368 		    (uintptr_t)NULL);
1369 	}
1370 }
1371 
1372 static void
idm_conn_reject_unref(void * ic_void)1373 idm_conn_reject_unref(void *ic_void)
1374 {
1375 	idm_conn_t *ic = ic_void;
1376 
1377 	ASSERT(IDM_CONN_ISTGT(ic));
1378 
1379 	/* Don't notify the client since it rejected the connection */
1380 	idm_svc_conn_destroy(ic);
1381 }
1382 
1383 
1384 
1385 static idm_pdu_event_action_t
idm_conn_sm_validate_pdu(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx,idm_pdu_t * pdu)1386 idm_conn_sm_validate_pdu(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx,
1387     idm_pdu_t *pdu)
1388 {
1389 	char			*reason_string;
1390 	idm_pdu_event_action_t	action;
1391 
1392 	ASSERT((event_ctx->iec_pdu_event_type == CT_RX_PDU) ||
1393 	    (event_ctx->iec_pdu_event_type == CT_TX_PDU));
1394 
1395 	/*
1396 	 * Let's check the simple stuff first.  Make sure if this is a
1397 	 * target connection that the PDU is appropriate for a target
1398 	 * and if this is an initiator connection that the PDU is
1399 	 * appropriate for an initiator.  This code is not in the data
1400 	 * path so organization is more important than performance.
1401 	 */
1402 	switch (IDM_PDU_OPCODE(pdu)) {
1403 	case ISCSI_OP_NOOP_OUT:
1404 	case ISCSI_OP_SCSI_CMD:
1405 	case ISCSI_OP_SCSI_TASK_MGT_MSG:
1406 	case ISCSI_OP_LOGIN_CMD:
1407 	case ISCSI_OP_TEXT_CMD:
1408 	case ISCSI_OP_SCSI_DATA:
1409 	case ISCSI_OP_LOGOUT_CMD:
1410 	case ISCSI_OP_SNACK_CMD:
1411 		/*
1412 		 * Only the initiator should send these PDU's and
1413 		 * only the target should receive them.
1414 		 */
1415 		if (IDM_CONN_ISINI(ic) &&
1416 		    (event_ctx->iec_pdu_event_type == CT_RX_PDU)) {
1417 			reason_string = "Invalid RX PDU for initiator";
1418 			action = CA_RX_PROTOCOL_ERROR;
1419 			goto validate_pdu_done;
1420 		}
1421 
1422 		if (IDM_CONN_ISTGT(ic) &&
1423 		    (event_ctx->iec_pdu_event_type == CT_TX_PDU)) {
1424 			reason_string = "Invalid TX PDU for target";
1425 			action = CA_TX_PROTOCOL_ERROR;
1426 			goto validate_pdu_done;
1427 		}
1428 		break;
1429 	case ISCSI_OP_NOOP_IN:
1430 	case ISCSI_OP_SCSI_RSP:
1431 	case ISCSI_OP_SCSI_TASK_MGT_RSP:
1432 	case ISCSI_OP_LOGIN_RSP:
1433 	case ISCSI_OP_TEXT_RSP:
1434 	case ISCSI_OP_SCSI_DATA_RSP:
1435 	case ISCSI_OP_LOGOUT_RSP:
1436 	case ISCSI_OP_RTT_RSP:
1437 	case ISCSI_OP_ASYNC_EVENT:
1438 	case ISCSI_OP_REJECT_MSG:
1439 		/*
1440 		 * Only the target should send these PDU's and
1441 		 * only the initiator should receive them.
1442 		 */
1443 		if (IDM_CONN_ISTGT(ic) &&
1444 		    (event_ctx->iec_pdu_event_type == CT_RX_PDU)) {
1445 			reason_string = "Invalid RX PDU for target";
1446 			action = CA_RX_PROTOCOL_ERROR;
1447 			goto validate_pdu_done;
1448 		}
1449 
1450 		if (IDM_CONN_ISINI(ic) &&
1451 		    (event_ctx->iec_pdu_event_type == CT_TX_PDU)) {
1452 			reason_string = "Invalid TX PDU for initiator";
1453 			action = CA_TX_PROTOCOL_ERROR;
1454 			goto validate_pdu_done;
1455 		}
1456 		break;
1457 	default:
1458 		reason_string = "Unknown PDU Type";
1459 		action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1460 		    CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1461 		goto validate_pdu_done;
1462 	}
1463 
1464 	/*
1465 	 * Now validate the opcodes against the current state.
1466 	 */
1467 	reason_string = "PDU not allowed in current state";
1468 	switch (IDM_PDU_OPCODE(pdu)) {
1469 	case ISCSI_OP_NOOP_OUT:
1470 	case ISCSI_OP_NOOP_IN:
1471 		/*
1472 		 * Obviously S1-S3 are not allowed since login hasn't started.
1473 		 * S8 is probably out as well since the connection has been
1474 		 * dropped.
1475 		 */
1476 		switch (ic->ic_state) {
1477 		case CS_S4_IN_LOGIN:
1478 		case CS_S5_LOGGED_IN:
1479 		case CS_S6_IN_LOGOUT:
1480 		case CS_S7_LOGOUT_REQ:
1481 			action = CA_FORWARD;
1482 			goto validate_pdu_done;
1483 		case CS_S8_CLEANUP:
1484 		case CS_S10_IN_CLEANUP:
1485 			action = CA_DROP;
1486 			goto validate_pdu_done;
1487 		default:
1488 			action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1489 			    CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1490 			goto validate_pdu_done;
1491 		}
1492 		/*NOTREACHED*/
1493 	case ISCSI_OP_SCSI_CMD:
1494 	case ISCSI_OP_SCSI_RSP:
1495 	case ISCSI_OP_SCSI_TASK_MGT_MSG:
1496 	case ISCSI_OP_SCSI_TASK_MGT_RSP:
1497 	case ISCSI_OP_SCSI_DATA:
1498 	case ISCSI_OP_SCSI_DATA_RSP:
1499 	case ISCSI_OP_RTT_RSP:
1500 	case ISCSI_OP_SNACK_CMD:
1501 	case ISCSI_OP_TEXT_CMD:
1502 	case ISCSI_OP_TEXT_RSP:
1503 		switch (ic->ic_state) {
1504 		case CS_S5_LOGGED_IN:
1505 		case CS_S6_IN_LOGOUT:
1506 		case CS_S7_LOGOUT_REQ:
1507 			action = CA_FORWARD;
1508 			goto validate_pdu_done;
1509 		case CS_S8_CLEANUP:
1510 		case CS_S10_IN_CLEANUP:
1511 			action = CA_DROP;
1512 			goto validate_pdu_done;
1513 		default:
1514 			action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1515 			    CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1516 			goto validate_pdu_done;
1517 		}
1518 		/*NOTREACHED*/
1519 	case ISCSI_OP_LOGOUT_CMD:
1520 	case ISCSI_OP_LOGOUT_RSP:
1521 	case ISCSI_OP_REJECT_MSG:
1522 	case ISCSI_OP_ASYNC_EVENT:
1523 		switch (ic->ic_state) {
1524 		case CS_S5_LOGGED_IN:
1525 		case CS_S6_IN_LOGOUT:
1526 		case CS_S7_LOGOUT_REQ:
1527 			action = CA_FORWARD;
1528 			goto validate_pdu_done;
1529 		case CS_S8_CLEANUP:
1530 		case CS_S10_IN_CLEANUP:
1531 			action = CA_DROP;
1532 			goto validate_pdu_done;
1533 		default:
1534 			action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1535 			    CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1536 			goto validate_pdu_done;
1537 		}
1538 		/*NOTREACHED*/
1539 	case ISCSI_OP_LOGIN_CMD:
1540 	case ISCSI_OP_LOGIN_RSP:
1541 		switch (ic->ic_state) {
1542 		case CS_S3_XPT_UP:
1543 		case CS_S4_IN_LOGIN:
1544 			action = CA_FORWARD;
1545 			goto validate_pdu_done;
1546 		default:
1547 			action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1548 			    CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1549 			goto validate_pdu_done;
1550 		}
1551 		/*NOTREACHED*/
1552 	default:
1553 		/* This should never happen -- we already checked above */
1554 		ASSERT(0);
1555 		/*NOTREACHED*/
1556 	}
1557 
1558 	action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1559 	    CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1560 
1561 validate_pdu_done:
1562 	if (action != CA_FORWARD) {
1563 		DTRACE_PROBE2(idm__int__protocol__error,
1564 		    idm_conn_event_ctx_t *, event_ctx,
1565 		    char *, reason_string);
1566 	}
1567 
1568 	return (action);
1569 }
1570 
1571 /* ARGSUSED */
1572 void
idm_pdu_tx_protocol_error(idm_conn_t * ic,idm_pdu_t * pdu)1573 idm_pdu_tx_protocol_error(idm_conn_t *ic, idm_pdu_t *pdu)
1574 {
1575 	/*
1576 	 * Return the PDU to the caller indicating it was a protocol error.
1577 	 * Caller can take appropriate action.
1578 	 */
1579 	idm_pdu_complete(pdu, IDM_STATUS_PROTOCOL_ERROR);
1580 }
1581 
1582 void
idm_pdu_rx_protocol_error(idm_conn_t * ic,idm_pdu_t * pdu)1583 idm_pdu_rx_protocol_error(idm_conn_t *ic, idm_pdu_t *pdu)
1584 {
1585 	/*
1586 	 * Forward PDU to caller indicating it is a protocol error.
1587 	 * Caller should take appropriate action.
1588 	 */
1589 	(*ic->ic_conn_ops.icb_rx_error)(ic, pdu, IDM_STATUS_PROTOCOL_ERROR);
1590 }
1591 
1592 idm_status_t
idm_notify_client(idm_conn_t * ic,idm_client_notify_t cn,uintptr_t data)1593 idm_notify_client(idm_conn_t *ic, idm_client_notify_t cn, uintptr_t data)
1594 {
1595 	/*
1596 	 * We may want to make this more complicated at some point but
1597 	 * for now lets just call the client's notify function and return
1598 	 * the status.
1599 	 */
1600 	ASSERT(!mutex_owned(&ic->ic_state_mutex));
1601 	cn = (cn > CN_MAX) ? CN_MAX : cn;
1602 	IDM_SM_LOG(CE_NOTE, "idm_notify_client: ic=%p %s(%d)\n",
1603 	    (void *)ic, idm_cn_strings[cn], cn);
1604 	return ((*ic->ic_conn_ops.icb_client_notify)(ic, cn, data));
1605 }
1606 
1607 static idm_status_t
idm_ffp_enable(idm_conn_t * ic)1608 idm_ffp_enable(idm_conn_t *ic)
1609 {
1610 	idm_status_t rc;
1611 
1612 	/*
1613 	 * On the initiator side the client will see this notification
1614 	 * before the actual login succes PDU.  This shouldn't be a big
1615 	 * deal since the initiator drives the connection.  It can simply
1616 	 * wait for the login response then start sending SCSI commands.
1617 	 * Kind ugly though compared with the way things work on target
1618 	 * connections.
1619 	 */
1620 	mutex_enter(&ic->ic_state_mutex);
1621 	ic->ic_ffp = B_TRUE;
1622 	mutex_exit(&ic->ic_state_mutex);
1623 
1624 	rc = idm_notify_client(ic, CN_FFP_ENABLED, (uintptr_t)NULL);
1625 	if (rc != IDM_STATUS_SUCCESS) {
1626 		mutex_enter(&ic->ic_state_mutex);
1627 		ic->ic_ffp = B_FALSE;
1628 		mutex_exit(&ic->ic_state_mutex);
1629 	}
1630 	return (rc);
1631 }
1632 
1633 static void
idm_ffp_disable(idm_conn_t * ic,idm_ffp_disable_t disable_type)1634 idm_ffp_disable(idm_conn_t *ic, idm_ffp_disable_t disable_type)
1635 {
1636 	mutex_enter(&ic->ic_state_mutex);
1637 	ic->ic_ffp = B_FALSE;
1638 	mutex_exit(&ic->ic_state_mutex);
1639 
1640 	/* Client can't "fail" CN_FFP_DISABLED */
1641 	(void) idm_notify_client(ic, CN_FFP_DISABLED,
1642 	    (uintptr_t)disable_type);
1643 }
1644 
1645 static void
idm_initial_login_actions(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)1646 idm_initial_login_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1647 {
1648 	ASSERT((event_ctx->iec_event == CE_LOGIN_RCV) ||
1649 	    (event_ctx->iec_event == CE_LOGIN_SND));
1650 
1651 	/*
1652 	 * Currently it's not clear what we would do here -- since
1653 	 * we went to the trouble of coding an "initial login" hook
1654 	 * we'll leave it in for now.  Remove before integration if
1655 	 * it's not used for anything.
1656 	 */
1657 	ic->ic_state_flags |= CF_INITIAL_LOGIN;
1658 }
1659 
1660 static void
idm_login_success_actions(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)1661 idm_login_success_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1662 {
1663 	idm_pdu_t		*pdu = (idm_pdu_t *)event_ctx->iec_info;
1664 	iscsi_login_hdr_t	*login_req =
1665 	    (iscsi_login_hdr_t *)pdu->isp_hdr;
1666 
1667 	ASSERT((event_ctx->iec_event == CE_LOGIN_SUCCESS_RCV) ||
1668 	    (event_ctx->iec_event == CE_LOGIN_SUCCESS_SND));
1669 
1670 	/*
1671 	 * Save off CID
1672 	 */
1673 	mutex_enter(&ic->ic_state_mutex);
1674 	ic->ic_login_cid = ntohs(login_req->cid);
1675 	ic->ic_login_info_valid =  B_TRUE;
1676 
1677 	mutex_exit(&ic->ic_state_mutex);
1678 }
1679