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.
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.
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]
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2013 by Delphix. All rights reserved.
25 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28 #include <sys/cpuvar.h>
30 #include <sys/sunddi.h>
31 #include <sys/modctl.h>
32 #include <sys/socket.h>
33 #include <sys/strsubr.h>
37 #define IDM_CONN_SM_STRINGS
38 #define IDM_CN_NOTIFY_STRINGS
39 #include <sys/idm/idm.h>
41 boolean_t idm_sm_logging
= B_FALSE
;
43 extern idm_global_t idm
; /* Global state */
46 idm_conn_event_handler(void *event_ctx_opaque
);
49 idm_state_s1_free(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
52 idm_state_s2_xpt_wait(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
55 idm_state_s3_xpt_up(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
58 idm_state_s4_in_login(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
61 idm_state_s5_logged_in(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
64 idm_state_s6_in_logout(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
67 idm_logout_req_timeout(void *arg
);
70 idm_state_s7_logout_req(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
73 idm_state_s8_cleanup(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
76 idm_state_s9_init_error(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
79 idm_state_s9a_rejected(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
82 idm_state_s9b_wait_snd_done_cb(idm_pdu_t
*pdu
,
86 idm_state_s9b_wait_snd_done(idm_conn_t
*ic
,
87 idm_conn_event_ctx_t
*event_ctx
);
90 idm_state_s10_in_cleanup(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
93 idm_state_s11_complete(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
96 idm_state_s12_enable_dm(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
99 idm_update_state(idm_conn_t
*ic
, idm_conn_state_t new_state
,
100 idm_conn_event_ctx_t
*event_ctx
);
103 idm_conn_unref(void *ic_void
);
106 idm_conn_reject_unref(void *ic_void
);
108 static idm_pdu_event_action_t
109 idm_conn_sm_validate_pdu(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
,
113 idm_ffp_enable(idm_conn_t
*ic
);
116 idm_ffp_disable(idm_conn_t
*ic
, idm_ffp_disable_t disable_type
);
119 idm_initial_login_actions(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
122 idm_login_success_actions(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
);
125 idm_conn_sm_init(idm_conn_t
*ic
)
130 * Caller should have assigned a unique connection ID. Use this
131 * connection ID to create a unique connection name string
133 ASSERT(ic
->ic_internal_cid
!= 0);
134 (void) snprintf(taskq_name
, sizeof (taskq_name
) - 1, "conn_sm%08x",
135 ic
->ic_internal_cid
);
137 ic
->ic_state_taskq
= taskq_create(taskq_name
, 1, minclsyspri
, 4, 16384,
139 if (ic
->ic_state_taskq
== NULL
) {
140 return (IDM_STATUS_FAIL
);
143 idm_sm_audit_init(&ic
->ic_state_audit
);
144 mutex_init(&ic
->ic_state_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
145 cv_init(&ic
->ic_state_cv
, NULL
, CV_DEFAULT
, NULL
);
147 ic
->ic_state
= CS_S1_FREE
;
148 ic
->ic_last_state
= CS_S1_FREE
;
150 return (IDM_STATUS_SUCCESS
);
154 idm_conn_sm_fini(idm_conn_t
*ic
)
158 * The connection may only be partially created. If there
159 * is no taskq, then the connection SM was not initialized.
161 if (ic
->ic_state_taskq
== NULL
) {
165 taskq_destroy(ic
->ic_state_taskq
);
167 cv_destroy(&ic
->ic_state_cv
);
169 * The thread that generated the event that got us here may still
170 * hold the ic_state_mutex. Once it is released we can safely
171 * destroy it since there is no way to locate the object now.
173 mutex_enter(&ic
->ic_state_mutex
);
174 IDM_SM_TIMER_CLEAR(ic
);
175 mutex_destroy(&ic
->ic_state_mutex
);
179 idm_conn_event(idm_conn_t
*ic
, idm_conn_event_t event
, uintptr_t event_info
)
181 mutex_enter(&ic
->ic_state_mutex
);
182 idm_conn_event_locked(ic
, event
, event_info
, CT_NONE
);
183 mutex_exit(&ic
->ic_state_mutex
);
188 idm_conn_reinstate_event(idm_conn_t
*old_ic
, idm_conn_t
*new_ic
)
192 mutex_enter(&old_ic
->ic_state_mutex
);
193 if (((old_ic
->ic_conn_type
== CONN_TYPE_INI
) &&
194 (old_ic
->ic_state
!= CS_S8_CLEANUP
)) ||
195 ((old_ic
->ic_conn_type
== CONN_TYPE_TGT
) &&
196 (old_ic
->ic_state
< CS_S5_LOGGED_IN
))) {
197 result
= IDM_STATUS_FAIL
;
199 result
= IDM_STATUS_SUCCESS
;
200 new_ic
->ic_reinstate_conn
= old_ic
;
201 idm_conn_event_locked(new_ic
->ic_reinstate_conn
,
202 CE_CONN_REINSTATE
, (uintptr_t)new_ic
, CT_NONE
);
204 mutex_exit(&old_ic
->ic_state_mutex
);
210 idm_conn_tx_pdu_event(idm_conn_t
*ic
, idm_conn_event_t event
,
211 uintptr_t event_info
)
213 ASSERT(mutex_owned(&ic
->ic_state_mutex
));
215 idm_conn_event_locked(ic
, event
, event_info
, CT_TX_PDU
);
219 idm_conn_rx_pdu_event(idm_conn_t
*ic
, idm_conn_event_t event
,
220 uintptr_t event_info
)
222 ASSERT(mutex_owned(&ic
->ic_state_mutex
));
224 idm_conn_event_locked(ic
, event
, event_info
, CT_RX_PDU
);
228 idm_conn_event_locked(idm_conn_t
*ic
, idm_conn_event_t event
,
229 uintptr_t event_info
, idm_pdu_event_type_t pdu_event_type
)
231 idm_conn_event_ctx_t
*event_ctx
;
233 ASSERT(mutex_owned(&ic
->ic_state_mutex
));
235 idm_sm_audit_event(&ic
->ic_state_audit
, SAS_IDM_CONN
,
236 (int)ic
->ic_state
, (int)event
, event_info
);
239 * It's very difficult to prevent a few straggling events
240 * at the end. For example idm_sorx_thread will generate
241 * a CE_TRANSPORT_FAIL event when it exits. Rather than
242 * push complicated restrictions all over the code to
243 * prevent this we will simply drop the events (and in
244 * the case of PDU events release them appropriately)
245 * since they are irrelevant once we are in a terminal state.
246 * Of course those threads need to have appropriate holds on
247 * the connection otherwise it might disappear.
249 if ((ic
->ic_state
== CS_S9_INIT_ERROR
) ||
250 (ic
->ic_state
== CS_S9A_REJECTED
) ||
251 (ic
->ic_state
== CS_S11_COMPLETE
)) {
252 if ((pdu_event_type
== CT_TX_PDU
) ||
253 (pdu_event_type
== CT_RX_PDU
)) {
255 idm_pdu_complete((idm_pdu_t
*)event_info
,
258 IDM_SM_LOG(CE_NOTE
, "*** Dropping event %s (%d) because of"
260 idm_ce_name
[event
], event
,
261 idm_cs_name
[ic
->ic_state
], ic
->ic_state
);
266 * Normal event handling
270 event_ctx
= kmem_zalloc(sizeof (*event_ctx
), KM_SLEEP
);
271 event_ctx
->iec_ic
= ic
;
272 event_ctx
->iec_event
= event
;
273 event_ctx
->iec_info
= event_info
;
274 event_ctx
->iec_pdu_event_type
= pdu_event_type
;
276 (void) taskq_dispatch(ic
->ic_state_taskq
, &idm_conn_event_handler
,
277 event_ctx
, TQ_SLEEP
);
281 idm_conn_event_handler(void *event_ctx_opaque
)
283 idm_conn_event_ctx_t
*event_ctx
= event_ctx_opaque
;
284 idm_conn_t
*ic
= event_ctx
->iec_ic
;
285 idm_pdu_t
*pdu
= (idm_pdu_t
*)event_ctx
->iec_info
;
286 idm_pdu_event_action_t action
;
288 IDM_SM_LOG(CE_NOTE
, "idm_conn_event_handler: conn %p event %s(%d)",
289 (void *)ic
, idm_ce_name
[event_ctx
->iec_event
],
290 event_ctx
->iec_event
);
291 DTRACE_PROBE2(conn__event
,
292 idm_conn_t
*, ic
, idm_conn_event_ctx_t
*, event_ctx
);
297 ASSERT(event_ctx
->iec_event
!= CE_UNDEFINED
);
298 ASSERT3U(event_ctx
->iec_event
, <, CE_MAX_EVENT
);
301 * Validate current state
303 ASSERT(ic
->ic_state
!= CS_S0_UNDEFINED
);
304 ASSERT3U(ic
->ic_state
, <, CS_MAX_STATE
);
307 * Validate PDU-related events against the current state. If a PDU
308 * is not allowed in the current state we change the event to a
309 * protocol error. This simplifies the state-specific event handlers.
310 * For example the CS_S2_XPT_WAIT state only needs to handle the
311 * CE_TX_PROTOCOL_ERROR and CE_RX_PROTOCOL_ERROR events since
312 * no PDU's can be transmitted or received in that state.
314 event_ctx
->iec_pdu_forwarded
= B_FALSE
;
315 if (event_ctx
->iec_pdu_event_type
!= CT_NONE
) {
317 action
= idm_conn_sm_validate_pdu(ic
, event_ctx
, pdu
);
320 case CA_TX_PROTOCOL_ERROR
:
322 * Change event and forward the PDU
324 event_ctx
->iec_event
= CE_TX_PROTOCOL_ERROR
;
326 case CA_RX_PROTOCOL_ERROR
:
328 * Change event and forward the PDU.
330 event_ctx
->iec_event
= CE_RX_PROTOCOL_ERROR
;
334 * Let the state-specific event handlers take
340 * It never even happened
342 IDM_SM_LOG(CE_NOTE
, "*** drop PDU %p", (void *) pdu
);
343 idm_pdu_complete(pdu
, IDM_STATUS_FAIL
);
351 switch (ic
->ic_state
) {
353 idm_state_s1_free(ic
, event_ctx
);
356 idm_state_s2_xpt_wait(ic
, event_ctx
);
359 idm_state_s3_xpt_up(ic
, event_ctx
);
362 idm_state_s4_in_login(ic
, event_ctx
);
364 case CS_S5_LOGGED_IN
:
365 idm_state_s5_logged_in(ic
, event_ctx
);
367 case CS_S6_IN_LOGOUT
:
368 idm_state_s6_in_logout(ic
, event_ctx
);
370 case CS_S7_LOGOUT_REQ
:
371 idm_state_s7_logout_req(ic
, event_ctx
);
374 idm_state_s8_cleanup(ic
, event_ctx
);
376 case CS_S9A_REJECTED
:
377 idm_state_s9a_rejected(ic
, event_ctx
);
379 case CS_S9B_WAIT_SND_DONE
:
380 idm_state_s9b_wait_snd_done(ic
, event_ctx
);
382 case CS_S9_INIT_ERROR
:
383 idm_state_s9_init_error(ic
, event_ctx
);
385 case CS_S10_IN_CLEANUP
:
386 idm_state_s10_in_cleanup(ic
, event_ctx
);
388 case CS_S11_COMPLETE
:
389 idm_state_s11_complete(ic
, event_ctx
);
391 case CS_S12_ENABLE_DM
:
392 idm_state_s12_enable_dm(ic
, event_ctx
);
400 * Now that we've updated the state machine, if this was
401 * a PDU-related event take the appropriate action on the PDU
402 * (transmit it, forward it to the clients RX callback, drop
405 if (event_ctx
->iec_pdu_event_type
!= CT_NONE
) {
407 case CA_TX_PROTOCOL_ERROR
:
408 idm_pdu_tx_protocol_error(ic
, pdu
);
410 case CA_RX_PROTOCOL_ERROR
:
411 idm_pdu_rx_protocol_error(ic
, pdu
);
414 if (!event_ctx
->iec_pdu_forwarded
) {
415 if (event_ctx
->iec_pdu_event_type
==
417 idm_pdu_rx_forward(ic
, pdu
);
419 idm_pdu_tx_forward(ic
, pdu
);
430 * Update outstanding PDU event count (see idm_pdu_tx for
433 if ((event_ctx
->iec_pdu_event_type
== CT_TX_PDU
) ||
434 (event_ctx
->iec_pdu_event_type
== CT_RX_PDU
)) {
435 mutex_enter(&ic
->ic_state_mutex
);
437 mutex_exit(&ic
->ic_state_mutex
);
441 kmem_free(event_ctx
, sizeof (*event_ctx
));
445 idm_state_s1_free(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
447 switch (event_ctx
->iec_event
) {
450 idm_update_state(ic
, CS_S2_XPT_WAIT
, event_ctx
);
452 case CE_CONNECT_ACCEPT
:
454 idm_update_state(ic
, CS_S3_XPT_UP
, event_ctx
);
456 case CE_TX_PROTOCOL_ERROR
:
457 case CE_RX_PROTOCOL_ERROR
:
458 /* This should never happen */
459 idm_update_state(ic
, CS_S9_INIT_ERROR
, event_ctx
);
469 idm_state_s2_xpt_wait(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
471 switch (event_ctx
->iec_event
) {
472 case CE_CONNECT_SUCCESS
:
474 idm_update_state(ic
, CS_S4_IN_LOGIN
, event_ctx
);
476 case CE_TRANSPORT_FAIL
:
477 case CE_CONNECT_FAIL
:
478 case CE_LOGOUT_OTHER_CONN_RCV
:
479 case CE_TX_PROTOCOL_ERROR
:
480 case CE_RX_PROTOCOL_ERROR
:
482 idm_update_state(ic
, CS_S9_INIT_ERROR
, event_ctx
);
492 idm_login_timeout(void *arg
)
494 idm_conn_t
*ic
= arg
;
496 ic
->ic_state_timeout
= 0;
497 idm_conn_event(ic
, CE_LOGIN_TIMEOUT
, (uintptr_t)NULL
);
501 idm_state_s3_xpt_up(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
503 switch (event_ctx
->iec_event
) {
506 /* Keep login timeout active through S3 and into S4 */
507 idm_initial_login_actions(ic
, event_ctx
);
508 idm_update_state(ic
, CS_S4_IN_LOGIN
, event_ctx
);
510 case CE_LOGIN_TIMEOUT
:
512 * Don't need to cancel login timer since the timer is
513 * presumed to be the source of this event.
515 (void) idm_notify_client(ic
, CN_LOGIN_FAIL
, (uintptr_t)NULL
);
516 idm_update_state(ic
, CS_S9_INIT_ERROR
, event_ctx
);
518 case CE_CONNECT_REJECT
:
520 * Iscsit doesn't want to hear from us again in this case.
521 * Since it rejected the connection it doesn't have a
522 * connection context to handle additional notifications.
523 * IDM needs to just clean things up on its own.
525 IDM_SM_TIMER_CLEAR(ic
);
526 idm_update_state(ic
, CS_S9A_REJECTED
, event_ctx
);
528 case CE_CONNECT_FAIL
:
529 case CE_TRANSPORT_FAIL
:
530 case CE_LOGOUT_OTHER_CONN_SND
:
532 IDM_SM_TIMER_CLEAR(ic
);
533 (void) idm_notify_client(ic
, CN_LOGIN_FAIL
, (uintptr_t)NULL
);
534 idm_update_state(ic
, CS_S9_INIT_ERROR
, event_ctx
);
536 case CE_TX_PROTOCOL_ERROR
:
537 case CE_RX_PROTOCOL_ERROR
:
547 idm_state_s4_in_login(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
552 * Login timer should no longer be active after leaving this
555 switch (event_ctx
->iec_event
) {
556 case CE_LOGIN_SUCCESS_RCV
:
557 case CE_LOGIN_SUCCESS_SND
:
558 ASSERT(ic
->ic_client_callback
== NULL
);
560 IDM_SM_TIMER_CLEAR(ic
);
561 idm_login_success_actions(ic
, event_ctx
);
562 if (ic
->ic_rdma_extensions
) {
564 idm_update_state(ic
, CS_S12_ENABLE_DM
, event_ctx
);
567 idm_update_state(ic
, CS_S5_LOGGED_IN
, event_ctx
);
570 case CE_LOGIN_TIMEOUT
:
572 (void) idm_notify_client(ic
, CN_LOGIN_FAIL
, (uintptr_t)NULL
);
573 idm_update_state(ic
, CS_S9_INIT_ERROR
, event_ctx
);
575 case CE_LOGIN_FAIL_SND
:
577 * Allow the logout response pdu to be sent and defer
578 * the state machine cleanup until the completion callback.
579 * Only 1 level or callback interposition is allowed.
581 IDM_SM_TIMER_CLEAR(ic
);
582 pdu
= (idm_pdu_t
*)event_ctx
->iec_info
;
583 ASSERT(ic
->ic_client_callback
== NULL
);
584 ic
->ic_client_callback
= pdu
->isp_callback
;
586 idm_state_s9b_wait_snd_done_cb
;
587 idm_update_state(ic
, CS_S9B_WAIT_SND_DONE
,
590 case CE_LOGIN_FAIL_RCV
:
591 ASSERT(ic
->ic_client_callback
== NULL
);
593 * Need to deliver this PDU to the initiator now because after
594 * we update the state to CS_S9_INIT_ERROR the initiator will
595 * no longer be in an appropriate state.
597 event_ctx
->iec_pdu_forwarded
= B_TRUE
;
598 pdu
= (idm_pdu_t
*)event_ctx
->iec_info
;
599 idm_pdu_rx_forward(ic
, pdu
);
601 case CE_TRANSPORT_FAIL
:
602 case CE_LOGOUT_OTHER_CONN_SND
:
603 case CE_LOGOUT_OTHER_CONN_RCV
:
605 IDM_SM_TIMER_CLEAR(ic
);
606 (void) idm_notify_client(ic
, CN_LOGIN_FAIL
, (uintptr_t)NULL
);
607 idm_update_state(ic
, CS_S9_INIT_ERROR
, event_ctx
);
609 case CE_LOGOUT_SESSION_SUCCESS
:
612 * A session reinstatement request can be received while a
613 * session is active and a login is in process. The iSCSI
614 * connections are shut down by a CE_LOGOUT_SESSION_SUCCESS
615 * event sent from the session to the IDM layer.
617 IDM_SM_TIMER_CLEAR(ic
);
618 if (IDM_CONN_ISTGT(ic
)) {
619 ic
->ic_transport_ops
->it_tgt_conn_disconnect(ic
);
621 ic
->ic_transport_ops
->it_ini_conn_disconnect(ic
);
623 idm_update_state(ic
, CS_S11_COMPLETE
, event_ctx
);
627 ASSERT(ic
->ic_client_callback
== NULL
);
629 * Initiator connections will see initial login PDU
630 * in this state. Target connections see initial
631 * login PDU in "xpt up" state.
633 mutex_enter(&ic
->ic_state_mutex
);
634 if (!(ic
->ic_state_flags
& CF_INITIAL_LOGIN
)) {
635 idm_initial_login_actions(ic
, event_ctx
);
637 mutex_exit(&ic
->ic_state_mutex
);
642 case CE_TX_PROTOCOL_ERROR
:
643 case CE_RX_PROTOCOL_ERROR
:
654 idm_state_s5_logged_in(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
656 switch (event_ctx
->iec_event
) {
658 /* MC/S: when removing the non-leading connection */
659 case CE_LOGOUT_THIS_CONN_RCV
:
660 case CE_LOGOUT_THIS_CONN_SND
:
661 case CE_LOGOUT_OTHER_CONN_RCV
:
662 case CE_LOGOUT_OTHER_CONN_SND
:
664 idm_ffp_disable(ic
, FD_CONN_LOGOUT
); /* Explicit logout */
665 idm_update_state(ic
, CS_S6_IN_LOGOUT
, event_ctx
);
667 case CE_LOGOUT_SESSION_RCV
:
668 case CE_LOGOUT_SESSION_SND
:
670 idm_ffp_disable(ic
, FD_SESS_LOGOUT
); /* Explicit logout */
671 idm_update_state(ic
, CS_S6_IN_LOGOUT
, event_ctx
);
673 case CE_LOGOUT_SESSION_SUCCESS
:
675 idm_ffp_disable(ic
, FD_SESS_LOGOUT
); /* Explicit logout */
677 /* Close connection */
678 if (IDM_CONN_ISTGT(ic
)) {
679 ic
->ic_transport_ops
->it_tgt_conn_disconnect(ic
);
681 ic
->ic_transport_ops
->it_ini_conn_disconnect(ic
);
684 idm_update_state(ic
, CS_S11_COMPLETE
, event_ctx
);
686 case CE_ASYNC_LOGOUT_RCV
:
687 case CE_ASYNC_LOGOUT_SND
:
689 idm_update_state(ic
, CS_S7_LOGOUT_REQ
, event_ctx
);
691 case CE_TRANSPORT_FAIL
:
692 case CE_ASYNC_DROP_CONN_RCV
:
693 case CE_ASYNC_DROP_CONN_SND
:
694 case CE_ASYNC_DROP_ALL_CONN_RCV
:
695 case CE_ASYNC_DROP_ALL_CONN_SND
:
697 idm_ffp_disable(ic
, FD_CONN_FAIL
); /* Implicit logout */
698 idm_update_state(ic
, CS_S8_CLEANUP
, event_ctx
);
701 case CE_TX_PROTOCOL_ERROR
:
702 case CE_RX_PROTOCOL_ERROR
:
703 case CE_LOGIN_TIMEOUT
:
712 idm_state_s6_in_logout_success_snd_done(idm_pdu_t
*pdu
, idm_status_t status
)
714 idm_conn_t
*ic
= pdu
->isp_ic
;
717 * This pdu callback can be invoked by the tx thread,
718 * so run the disconnect code from another thread.
720 pdu
->isp_status
= status
;
721 idm_conn_event(ic
, CE_LOGOUT_SUCCESS_SND_DONE
, (uintptr_t)pdu
);
725 idm_state_s6_in_logout_fail_snd_done(idm_pdu_t
*pdu
, idm_status_t status
)
727 idm_conn_t
*ic
= pdu
->isp_ic
;
730 * This pdu callback can be invoked by the tx thread,
731 * so run the disconnect code from another thread.
733 pdu
->isp_status
= status
;
734 idm_conn_event(ic
, CE_LOGOUT_FAIL_SND_DONE
, (uintptr_t)pdu
);
738 idm_state_s6_in_logout(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
742 switch (event_ctx
->iec_event
) {
743 case CE_LOGOUT_SUCCESS_SND_DONE
:
744 pdu
= (idm_pdu_t
*)event_ctx
->iec_info
;
746 /* Close connection (if it's not already closed) */
747 ASSERT(IDM_CONN_ISTGT(ic
));
748 ic
->ic_transport_ops
->it_tgt_conn_disconnect(ic
);
750 /* restore client callback */
751 pdu
->isp_callback
= ic
->ic_client_callback
;
752 ic
->ic_client_callback
= NULL
;
753 idm_pdu_complete(pdu
, pdu
->isp_status
);
754 idm_update_state(ic
, CS_S11_COMPLETE
, event_ctx
);
756 case CE_LOGOUT_FAIL_SND_DONE
:
757 pdu
= (idm_pdu_t
*)event_ctx
->iec_info
;
758 /* restore client callback */
759 pdu
->isp_callback
= ic
->ic_client_callback
;
760 ic
->ic_client_callback
= NULL
;
761 idm_pdu_complete(pdu
, pdu
->isp_status
);
762 idm_update_state(ic
, CS_S8_CLEANUP
, event_ctx
);
764 case CE_LOGOUT_SUCCESS_SND
:
765 case CE_LOGOUT_FAIL_SND
:
767 * Allow the logout response pdu to be sent and defer
768 * the state machine update until the completion callback.
769 * Only 1 level or callback interposition is allowed.
771 pdu
= (idm_pdu_t
*)event_ctx
->iec_info
;
772 ASSERT(ic
->ic_client_callback
== NULL
);
773 ic
->ic_client_callback
= pdu
->isp_callback
;
774 if (event_ctx
->iec_event
== CE_LOGOUT_SUCCESS_SND
) {
776 idm_state_s6_in_logout_success_snd_done
;
779 idm_state_s6_in_logout_fail_snd_done
;
782 case CE_LOGOUT_SUCCESS_RCV
:
784 * Need to deliver this PDU to the initiator now because after
785 * we update the state to CS_S11_COMPLETE the initiator will
786 * no longer be in an appropriate state.
788 event_ctx
->iec_pdu_forwarded
= B_TRUE
;
789 pdu
= (idm_pdu_t
*)event_ctx
->iec_info
;
790 idm_pdu_rx_forward(ic
, pdu
);
792 case CE_LOGOUT_SESSION_SUCCESS
:
795 /* Close connection (if it's not already closed) */
796 if (IDM_CONN_ISTGT(ic
)) {
797 ic
->ic_transport_ops
->it_tgt_conn_disconnect(ic
);
799 ic
->ic_transport_ops
->it_ini_conn_disconnect(ic
);
802 idm_update_state(ic
, CS_S11_COMPLETE
, event_ctx
);
804 case CE_ASYNC_LOGOUT_RCV
:
807 case CE_TRANSPORT_FAIL
:
808 case CE_ASYNC_DROP_CONN_RCV
:
809 case CE_ASYNC_DROP_CONN_SND
:
810 case CE_ASYNC_DROP_ALL_CONN_RCV
:
811 case CE_ASYNC_DROP_ALL_CONN_SND
:
812 case CE_LOGOUT_FAIL_RCV
:
813 idm_update_state(ic
, CS_S8_CLEANUP
, event_ctx
);
815 case CE_TX_PROTOCOL_ERROR
:
816 case CE_RX_PROTOCOL_ERROR
:
819 case CE_LOGIN_TIMEOUT
:
829 idm_logout_req_timeout(void *arg
)
831 idm_conn_t
*ic
= arg
;
833 ic
->ic_state_timeout
= 0;
834 idm_conn_event(ic
, CE_LOGOUT_TIMEOUT
, (uintptr_t)NULL
);
838 idm_state_s7_logout_req(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
840 /* Must cancel logout timer before leaving this state */
841 switch (event_ctx
->iec_event
) {
842 case CE_LOGOUT_THIS_CONN_RCV
:
843 case CE_LOGOUT_THIS_CONN_SND
:
844 case CE_LOGOUT_OTHER_CONN_RCV
:
845 case CE_LOGOUT_OTHER_CONN_SND
:
847 if (IDM_CONN_ISTGT(ic
)) {
848 IDM_SM_TIMER_CLEAR(ic
);
850 idm_ffp_disable(ic
, FD_CONN_LOGOUT
); /* Explicit logout */
851 idm_update_state(ic
, CS_S6_IN_LOGOUT
, event_ctx
);
853 case CE_LOGOUT_SESSION_RCV
:
854 case CE_LOGOUT_SESSION_SND
:
856 if (IDM_CONN_ISTGT(ic
)) {
857 IDM_SM_TIMER_CLEAR(ic
);
859 idm_ffp_disable(ic
, FD_SESS_LOGOUT
); /* Explicit logout */
860 idm_update_state(ic
, CS_S6_IN_LOGOUT
, event_ctx
);
862 case CE_ASYNC_LOGOUT_RCV
:
863 case CE_ASYNC_LOGOUT_SND
:
866 case CE_TRANSPORT_FAIL
:
867 case CE_ASYNC_DROP_CONN_RCV
:
868 case CE_ASYNC_DROP_CONN_SND
:
869 case CE_ASYNC_DROP_ALL_CONN_RCV
:
870 case CE_ASYNC_DROP_ALL_CONN_SND
:
872 if (IDM_CONN_ISTGT(ic
)) {
873 IDM_SM_TIMER_CLEAR(ic
);
876 case CE_LOGOUT_TIMEOUT
:
877 idm_ffp_disable(ic
, FD_CONN_FAIL
); /* Implicit logout */
878 idm_update_state(ic
, CS_S8_CLEANUP
, event_ctx
);
880 case CE_LOGOUT_SESSION_SUCCESS
:
882 if (IDM_CONN_ISTGT(ic
)) {
883 IDM_SM_TIMER_CLEAR(ic
);
885 idm_ffp_disable(ic
, FD_SESS_LOGOUT
); /* Explicit logout */
887 /* Close connection (if it's not already closed) */
888 if (IDM_CONN_ISTGT(ic
)) {
889 ic
->ic_transport_ops
->it_tgt_conn_disconnect(ic
);
891 ic
->ic_transport_ops
->it_ini_conn_disconnect(ic
);
894 idm_update_state(ic
, CS_S11_COMPLETE
, event_ctx
);
896 case CE_TX_PROTOCOL_ERROR
:
897 case CE_RX_PROTOCOL_ERROR
:
900 case CE_LOGIN_TIMEOUT
:
910 idm_cleanup_timeout(void *arg
)
912 idm_conn_t
*ic
= arg
;
914 ic
->ic_state_timeout
= 0;
915 idm_conn_event(ic
, CE_CLEANUP_TIMEOUT
, (uintptr_t)NULL
);
919 idm_state_s8_cleanup(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
924 * Need to cancel the cleanup timeout before leaving this state
925 * if it hasn't already fired.
927 switch (event_ctx
->iec_event
) {
928 case CE_LOGOUT_SUCCESS_RCV
:
929 case CE_LOGOUT_SUCCESS_SND
:
930 case CE_LOGOUT_SESSION_SUCCESS
:
931 IDM_SM_TIMER_CLEAR(ic
);
933 case CE_CLEANUP_TIMEOUT
:
935 idm_update_state(ic
, CS_S11_COMPLETE
, event_ctx
);
937 case CE_LOGOUT_OTHER_CONN_RCV
:
938 case CE_LOGOUT_OTHER_CONN_SND
:
940 idm_update_state(ic
, CS_S10_IN_CLEANUP
, event_ctx
);
942 case CE_LOGOUT_SUCCESS_SND_DONE
:
943 case CE_LOGOUT_FAIL_SND_DONE
:
944 pdu
= (idm_pdu_t
*)event_ctx
->iec_info
;
945 /* restore client callback */
946 pdu
->isp_callback
= ic
->ic_client_callback
;
947 ic
->ic_client_callback
= NULL
;
948 idm_pdu_complete(pdu
, pdu
->isp_status
);
950 case CE_LOGOUT_SESSION_RCV
:
951 case CE_LOGOUT_SESSION_SND
:
952 case CE_TX_PROTOCOL_ERROR
:
953 case CE_RX_PROTOCOL_ERROR
:
956 case CE_TRANSPORT_FAIL
:
957 case CE_LOGIN_TIMEOUT
:
958 case CE_LOGOUT_TIMEOUT
:
968 idm_state_s9_init_error(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
970 /* All events ignored in this state */
975 idm_state_s9a_rejected(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
977 /* All events ignored in this state */
982 idm_state_s9b_wait_snd_done_cb(idm_pdu_t
*pdu
, idm_status_t status
)
984 idm_conn_t
*ic
= pdu
->isp_ic
;
987 * This pdu callback can be invoked by the tx thread,
988 * so run the disconnect code from another thread.
990 pdu
->isp_status
= status
;
991 idm_conn_event(ic
, CE_LOGIN_FAIL_SND_DONE
, (uintptr_t)pdu
);
995 * CS_S9B_WAIT_SND_DONE -- wait for callback completion.
999 idm_state_s9b_wait_snd_done(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
1003 * Wait for completion of the login fail sequence and then
1004 * go to state S9_INIT_ERROR to clean up the connection.
1006 switch (event_ctx
->iec_event
) {
1007 case CE_LOGIN_FAIL_SND_DONE
:
1008 pdu
= (idm_pdu_t
*)event_ctx
->iec_info
;
1009 /* restore client callback */
1010 pdu
->isp_callback
= ic
->ic_client_callback
;
1011 ic
->ic_client_callback
= NULL
;
1012 idm_pdu_complete(pdu
, pdu
->isp_status
);
1013 idm_update_state(ic
, CS_S9_INIT_ERROR
, event_ctx
);
1016 /* All other events ignored */
1024 idm_state_s10_in_cleanup(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
1029 * Need to cancel the cleanup timeout before leaving this state
1030 * if it hasn't already fired.
1032 switch (event_ctx
->iec_event
) {
1033 case CE_LOGOUT_FAIL_RCV
:
1034 case CE_LOGOUT_FAIL_SND
:
1035 idm_update_state(ic
, CS_S8_CLEANUP
, event_ctx
);
1037 case CE_LOGOUT_SUCCESS_SND
:
1038 case CE_LOGOUT_SUCCESS_RCV
:
1039 case CE_LOGOUT_SESSION_SUCCESS
:
1040 IDM_SM_TIMER_CLEAR(ic
);
1042 case CE_CLEANUP_TIMEOUT
:
1043 idm_update_state(ic
, CS_S11_COMPLETE
, event_ctx
);
1045 case CE_LOGOUT_SUCCESS_SND_DONE
:
1046 case CE_LOGOUT_FAIL_SND_DONE
:
1047 pdu
= (idm_pdu_t
*)event_ctx
->iec_info
;
1048 /* restore client callback */
1049 pdu
->isp_callback
= ic
->ic_client_callback
;
1050 ic
->ic_client_callback
= NULL
;
1051 idm_pdu_complete(pdu
, pdu
->isp_status
);
1053 case CE_TX_PROTOCOL_ERROR
:
1054 case CE_RX_PROTOCOL_ERROR
:
1057 case CE_LOGIN_TIMEOUT
:
1058 case CE_LOGOUT_TIMEOUT
:
1068 idm_state_s11_complete(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
1073 * Cleanup logout success/fail completion if it's been delayed
1076 * All new events are filtered out before reaching this state, but
1077 * there might already be events in the event queue, so handle the
1078 * SND_DONE events here. Note that if either of the following
1079 * SND_DONE events happens AFTER the change to state S11, then the
1080 * event filter inside dm_conn_event_locked does enough cleanup.
1082 switch (event_ctx
->iec_event
) {
1083 case CE_LOGOUT_SUCCESS_SND_DONE
:
1084 case CE_LOGOUT_FAIL_SND_DONE
:
1085 pdu
= (idm_pdu_t
*)event_ctx
->iec_info
;
1086 /* restore client callback */
1087 pdu
->isp_callback
= ic
->ic_client_callback
;
1088 ic
->ic_client_callback
= NULL
;
1089 idm_pdu_complete(pdu
, pdu
->isp_status
);
1096 idm_state_s12_enable_dm(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
1098 switch (event_ctx
->iec_event
) {
1099 case CE_ENABLE_DM_SUCCESS
:
1101 idm_update_state(ic
, CS_S5_LOGGED_IN
, event_ctx
);
1103 case CE_ENABLE_DM_FAIL
:
1105 idm_update_state(ic
, CS_S9_INIT_ERROR
, event_ctx
);
1107 case CE_TRANSPORT_FAIL
:
1109 * We expect to always hear back from the transport layer
1110 * once we have an "enable data-mover" request outstanding.
1111 * Therefore we'll ignore other events that may occur even
1112 * when they clearly indicate a problem and wait for
1113 * CE_ENABLE_DM_FAIL. On a related note this means the
1114 * transport must ensure that it eventually completes the
1115 * "enable data-mover" operation with either success or
1116 * failure -- otherwise we'll be stuck here.
1126 idm_update_state(idm_conn_t
*ic
, idm_conn_state_t new_state
,
1127 idm_conn_event_ctx_t
*event_ctx
)
1130 idm_status_t idm_status
;
1133 * Validate new state
1135 ASSERT(new_state
!= CS_S0_UNDEFINED
);
1136 ASSERT3U(new_state
, <, CS_MAX_STATE
);
1139 * Update state in context. We protect this with a mutex
1140 * even though the state machine code is single threaded so that
1141 * other threads can check the state value atomically.
1143 new_state
= (new_state
< CS_MAX_STATE
) ?
1144 new_state
: CS_S0_UNDEFINED
;
1146 IDM_SM_LOG(CE_NOTE
, "idm_update_state: conn %p, evt %s(%d), "
1147 "%s(%d) --> %s(%d)", (void *)ic
,
1148 idm_ce_name
[event_ctx
->iec_event
], event_ctx
->iec_event
,
1149 idm_cs_name
[ic
->ic_state
], ic
->ic_state
,
1150 idm_cs_name
[new_state
], new_state
);
1152 DTRACE_PROBE2(conn__state__change
,
1153 idm_conn_t
*, ic
, idm_conn_state_t
, new_state
);
1155 mutex_enter(&ic
->ic_state_mutex
);
1156 idm_sm_audit_state_change(&ic
->ic_state_audit
, SAS_IDM_CONN
,
1157 (int)ic
->ic_state
, (int)new_state
);
1158 ic
->ic_last_state
= ic
->ic_state
;
1159 ic
->ic_state
= new_state
;
1160 cv_signal(&ic
->ic_state_cv
);
1161 mutex_exit(&ic
->ic_state_mutex
);
1163 switch (ic
->ic_state
) {
1165 ASSERT(0); /* Initial state, can't return */
1167 case CS_S2_XPT_WAIT
:
1168 if ((rc
= idm_ini_conn_finish(ic
)) != 0) {
1169 idm_conn_event(ic
, CE_CONNECT_FAIL
, (uintptr_t)NULL
);
1171 idm_conn_event(ic
, CE_CONNECT_SUCCESS
, (uintptr_t)NULL
);
1176 * Finish any connection related setup including
1177 * waking up the idm_tgt_conn_accept thread.
1178 * and starting the login timer. If the function
1179 * fails then we return to "free" state.
1181 if ((rc
= idm_tgt_conn_finish(ic
)) != IDM_STATUS_SUCCESS
) {
1183 case IDM_STATUS_REJECT
:
1184 idm_conn_event(ic
, CE_CONNECT_REJECT
,
1188 idm_conn_event(ic
, CE_CONNECT_FAIL
,
1195 * First login received will cause a transition to
1196 * CS_S4_IN_LOGIN. Start login timer.
1198 IDM_SM_TIMER_CHECK(ic
);
1199 ic
->ic_state_timeout
= timeout(idm_login_timeout
, ic
,
1200 drv_usectohz(IDM_LOGIN_SECONDS
*1000000));
1202 case CS_S4_IN_LOGIN
:
1203 if (ic
->ic_conn_type
== CONN_TYPE_INI
) {
1204 (void) idm_notify_client(ic
, CN_READY_FOR_LOGIN
,
1206 mutex_enter(&ic
->ic_state_mutex
);
1207 ic
->ic_state_flags
|= CF_LOGIN_READY
;
1208 cv_signal(&ic
->ic_state_cv
);
1209 mutex_exit(&ic
->ic_state_mutex
);
1212 case CS_S5_LOGGED_IN
:
1213 ASSERT(!ic
->ic_ffp
);
1215 * IDM can go to FFP before the initiator but it
1216 * needs to go to FFP after the target (IDM target should
1217 * go to FFP after notify_ack).
1219 idm_status
= idm_ffp_enable(ic
);
1220 if (idm_status
!= IDM_STATUS_SUCCESS
) {
1221 idm_conn_event(ic
, CE_TRANSPORT_FAIL
, (uintptr_t)NULL
);
1224 if (ic
->ic_reinstate_conn
) {
1225 /* Connection reinstatement is complete */
1226 idm_conn_event(ic
->ic_reinstate_conn
,
1227 CE_CONN_REINSTATE_SUCCESS
, (uintptr_t)NULL
);
1230 case CS_S6_IN_LOGOUT
:
1232 case CS_S7_LOGOUT_REQ
:
1233 /* Start logout timer for target connections */
1234 if (IDM_CONN_ISTGT(ic
)) {
1235 IDM_SM_TIMER_CHECK(ic
);
1236 ic
->ic_state_timeout
= timeout(idm_logout_req_timeout
,
1237 ic
, drv_usectohz(IDM_LOGOUT_SECONDS
*1000000));
1241 /* Close connection (if it's not already closed) */
1242 if (IDM_CONN_ISTGT(ic
)) {
1243 ic
->ic_transport_ops
->it_tgt_conn_disconnect(ic
);
1245 ic
->ic_transport_ops
->it_ini_conn_disconnect(ic
);
1248 /* Stop executing active tasks */
1249 idm_task_abort(ic
, NULL
, AT_INTERNAL_SUSPEND
);
1251 /* Start logout timer */
1252 IDM_SM_TIMER_CHECK(ic
);
1253 ic
->ic_state_timeout
= timeout(idm_cleanup_timeout
, ic
,
1254 drv_usectohz(IDM_CLEANUP_SECONDS
*1000000));
1256 case CS_S10_IN_CLEANUP
:
1258 case CS_S9A_REJECTED
:
1260 * We never finished establishing the connection so no
1261 * disconnect. No client notifications because the client
1262 * rejected the connection.
1264 idm_refcnt_async_wait_ref(&ic
->ic_refcnt
,
1265 &idm_conn_reject_unref
);
1267 case CS_S9B_WAIT_SND_DONE
:
1269 case CS_S9_INIT_ERROR
:
1270 if (IDM_CONN_ISTGT(ic
)) {
1271 ic
->ic_transport_ops
->it_tgt_conn_disconnect(ic
);
1273 mutex_enter(&ic
->ic_state_mutex
);
1274 ic
->ic_state_flags
|= CF_ERROR
;
1275 ic
->ic_conn_sm_status
= IDM_STATUS_FAIL
;
1276 cv_signal(&ic
->ic_state_cv
);
1277 mutex_exit(&ic
->ic_state_mutex
);
1278 if (ic
->ic_last_state
!= CS_S1_FREE
&&
1279 ic
->ic_last_state
!= CS_S2_XPT_WAIT
) {
1280 ic
->ic_transport_ops
->it_ini_conn_disconnect(
1283 (void) idm_notify_client(ic
, CN_CONNECT_FAIL
,
1288 case CS_S11_COMPLETE
:
1290 * No more traffic on this connection. If this is an
1291 * initiator connection and we weren't connected yet
1292 * then don't send the "connect lost" event.
1293 * It's useful to the initiator to know whether we were
1294 * logging in at the time so send that information in the
1297 if (IDM_CONN_ISTGT(ic
) ||
1298 ((ic
->ic_last_state
!= CS_S1_FREE
) &&
1299 (ic
->ic_last_state
!= CS_S2_XPT_WAIT
))) {
1300 (void) idm_notify_client(ic
, CN_CONNECT_LOST
,
1301 (uintptr_t)(ic
->ic_last_state
== CS_S4_IN_LOGIN
));
1304 /* Abort all tasks */
1305 idm_task_abort(ic
, NULL
, AT_INTERNAL_ABORT
);
1308 * Handle terminal state actions on the global taskq so
1309 * we can clean up all the connection resources from
1310 * a separate thread context.
1312 idm_refcnt_async_wait_ref(&ic
->ic_refcnt
, &idm_conn_unref
);
1314 case CS_S12_ENABLE_DM
:
1317 * The Enable DM state indicates the initiator to initiate
1318 * the hello sequence and the target to get ready to accept
1319 * the iSER Hello Message.
1321 idm_status
= (IDM_CONN_ISINI(ic
)) ?
1322 ic
->ic_transport_ops
->it_ini_enable_datamover(ic
) :
1323 ic
->ic_transport_ops
->it_tgt_enable_datamover(ic
);
1325 if (idm_status
== IDM_STATUS_SUCCESS
) {
1326 idm_conn_event(ic
, CE_ENABLE_DM_SUCCESS
,
1329 idm_conn_event(ic
, CE_ENABLE_DM_FAIL
, (uintptr_t)NULL
);
1343 idm_conn_unref(void *ic_void
)
1345 idm_conn_t
*ic
= ic_void
;
1348 * Client should not be notified that the connection is destroyed
1349 * until all references on the idm connection have been removed.
1350 * Otherwise references on the associated client context would need
1351 * to be tracked separately which seems like a waste (at least when
1352 * there is a one for one correspondence with references on the
1355 if (IDM_CONN_ISTGT(ic
)) {
1356 (void) idm_notify_client(ic
, CN_CONNECT_DESTROY
,
1358 idm_svc_conn_destroy(ic
);
1360 /* Initiator may destroy connection during this call */
1361 (void) idm_notify_client(ic
, CN_CONNECT_DESTROY
,
1367 idm_conn_reject_unref(void *ic_void
)
1369 idm_conn_t
*ic
= ic_void
;
1371 ASSERT(IDM_CONN_ISTGT(ic
));
1373 /* Don't notify the client since it rejected the connection */
1374 idm_svc_conn_destroy(ic
);
1379 static idm_pdu_event_action_t
1380 idm_conn_sm_validate_pdu(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
,
1383 char *reason_string
;
1384 idm_pdu_event_action_t action
;
1386 ASSERT((event_ctx
->iec_pdu_event_type
== CT_RX_PDU
) ||
1387 (event_ctx
->iec_pdu_event_type
== CT_TX_PDU
));
1390 * Let's check the simple stuff first. Make sure if this is a
1391 * target connection that the PDU is appropriate for a target
1392 * and if this is an initiator connection that the PDU is
1393 * appropriate for an initiator. This code is not in the data
1394 * path so organization is more important than performance.
1396 switch (IDM_PDU_OPCODE(pdu
)) {
1397 case ISCSI_OP_NOOP_OUT
:
1398 case ISCSI_OP_SCSI_CMD
:
1399 case ISCSI_OP_SCSI_TASK_MGT_MSG
:
1400 case ISCSI_OP_LOGIN_CMD
:
1401 case ISCSI_OP_TEXT_CMD
:
1402 case ISCSI_OP_SCSI_DATA
:
1403 case ISCSI_OP_LOGOUT_CMD
:
1404 case ISCSI_OP_SNACK_CMD
:
1406 * Only the initiator should send these PDU's and
1407 * only the target should receive them.
1409 if (IDM_CONN_ISINI(ic
) &&
1410 (event_ctx
->iec_pdu_event_type
== CT_RX_PDU
)) {
1411 reason_string
= "Invalid RX PDU for initiator";
1412 action
= CA_RX_PROTOCOL_ERROR
;
1413 goto validate_pdu_done
;
1416 if (IDM_CONN_ISTGT(ic
) &&
1417 (event_ctx
->iec_pdu_event_type
== CT_TX_PDU
)) {
1418 reason_string
= "Invalid TX PDU for target";
1419 action
= CA_TX_PROTOCOL_ERROR
;
1420 goto validate_pdu_done
;
1423 case ISCSI_OP_NOOP_IN
:
1424 case ISCSI_OP_SCSI_RSP
:
1425 case ISCSI_OP_SCSI_TASK_MGT_RSP
:
1426 case ISCSI_OP_LOGIN_RSP
:
1427 case ISCSI_OP_TEXT_RSP
:
1428 case ISCSI_OP_SCSI_DATA_RSP
:
1429 case ISCSI_OP_LOGOUT_RSP
:
1430 case ISCSI_OP_RTT_RSP
:
1431 case ISCSI_OP_ASYNC_EVENT
:
1432 case ISCSI_OP_REJECT_MSG
:
1434 * Only the target should send these PDU's and
1435 * only the initiator should receive them.
1437 if (IDM_CONN_ISTGT(ic
) &&
1438 (event_ctx
->iec_pdu_event_type
== CT_RX_PDU
)) {
1439 reason_string
= "Invalid RX PDU for target";
1440 action
= CA_RX_PROTOCOL_ERROR
;
1441 goto validate_pdu_done
;
1444 if (IDM_CONN_ISINI(ic
) &&
1445 (event_ctx
->iec_pdu_event_type
== CT_TX_PDU
)) {
1446 reason_string
= "Invalid TX PDU for initiator";
1447 action
= CA_TX_PROTOCOL_ERROR
;
1448 goto validate_pdu_done
;
1452 reason_string
= "Unknown PDU Type";
1453 action
= ((event_ctx
->iec_pdu_event_type
== CT_TX_PDU
) ?
1454 CA_TX_PROTOCOL_ERROR
: CA_RX_PROTOCOL_ERROR
);
1455 goto validate_pdu_done
;
1459 * Now validate the opcodes against the current state.
1461 reason_string
= "PDU not allowed in current state";
1462 switch (IDM_PDU_OPCODE(pdu
)) {
1463 case ISCSI_OP_NOOP_OUT
:
1464 case ISCSI_OP_NOOP_IN
:
1466 * Obviously S1-S3 are not allowed since login hasn't started.
1467 * S8 is probably out as well since the connection has been
1470 switch (ic
->ic_state
) {
1471 case CS_S4_IN_LOGIN
:
1472 case CS_S5_LOGGED_IN
:
1473 case CS_S6_IN_LOGOUT
:
1474 case CS_S7_LOGOUT_REQ
:
1475 action
= CA_FORWARD
;
1476 goto validate_pdu_done
;
1478 case CS_S10_IN_CLEANUP
:
1482 action
= ((event_ctx
->iec_pdu_event_type
== CT_TX_PDU
) ?
1483 CA_TX_PROTOCOL_ERROR
: CA_RX_PROTOCOL_ERROR
);
1484 goto validate_pdu_done
;
1487 case ISCSI_OP_SCSI_CMD
:
1488 case ISCSI_OP_SCSI_RSP
:
1489 case ISCSI_OP_SCSI_TASK_MGT_MSG
:
1490 case ISCSI_OP_SCSI_TASK_MGT_RSP
:
1491 case ISCSI_OP_SCSI_DATA
:
1492 case ISCSI_OP_SCSI_DATA_RSP
:
1493 case ISCSI_OP_RTT_RSP
:
1494 case ISCSI_OP_SNACK_CMD
:
1495 case ISCSI_OP_TEXT_CMD
:
1496 case ISCSI_OP_TEXT_RSP
:
1497 switch (ic
->ic_state
) {
1498 case CS_S5_LOGGED_IN
:
1499 case CS_S6_IN_LOGOUT
:
1500 case CS_S7_LOGOUT_REQ
:
1501 action
= CA_FORWARD
;
1502 goto validate_pdu_done
;
1504 case CS_S10_IN_CLEANUP
:
1508 action
= ((event_ctx
->iec_pdu_event_type
== CT_TX_PDU
) ?
1509 CA_TX_PROTOCOL_ERROR
: CA_RX_PROTOCOL_ERROR
);
1510 goto validate_pdu_done
;
1513 case ISCSI_OP_LOGOUT_CMD
:
1514 case ISCSI_OP_LOGOUT_RSP
:
1515 case ISCSI_OP_REJECT_MSG
:
1516 case ISCSI_OP_ASYNC_EVENT
:
1517 switch (ic
->ic_state
) {
1518 case CS_S5_LOGGED_IN
:
1519 case CS_S6_IN_LOGOUT
:
1520 case CS_S7_LOGOUT_REQ
:
1521 action
= CA_FORWARD
;
1522 goto validate_pdu_done
;
1524 case CS_S10_IN_CLEANUP
:
1528 action
= ((event_ctx
->iec_pdu_event_type
== CT_TX_PDU
) ?
1529 CA_TX_PROTOCOL_ERROR
: CA_RX_PROTOCOL_ERROR
);
1530 goto validate_pdu_done
;
1533 case ISCSI_OP_LOGIN_CMD
:
1534 case ISCSI_OP_LOGIN_RSP
:
1535 switch (ic
->ic_state
) {
1537 case CS_S4_IN_LOGIN
:
1538 action
= CA_FORWARD
;
1539 goto validate_pdu_done
;
1541 action
= ((event_ctx
->iec_pdu_event_type
== CT_TX_PDU
) ?
1542 CA_TX_PROTOCOL_ERROR
: CA_RX_PROTOCOL_ERROR
);
1543 goto validate_pdu_done
;
1547 /* This should never happen -- we already checked above */
1552 action
= ((event_ctx
->iec_pdu_event_type
== CT_TX_PDU
) ?
1553 CA_TX_PROTOCOL_ERROR
: CA_RX_PROTOCOL_ERROR
);
1556 if (action
!= CA_FORWARD
) {
1557 DTRACE_PROBE2(idm__int__protocol__error
,
1558 idm_conn_event_ctx_t
*, event_ctx
,
1559 char *, reason_string
);
1567 idm_pdu_tx_protocol_error(idm_conn_t
*ic
, idm_pdu_t
*pdu
)
1570 * Return the PDU to the caller indicating it was a protocol error.
1571 * Caller can take appropriate action.
1573 idm_pdu_complete(pdu
, IDM_STATUS_PROTOCOL_ERROR
);
1577 idm_pdu_rx_protocol_error(idm_conn_t
*ic
, idm_pdu_t
*pdu
)
1580 * Forward PDU to caller indicating it is a protocol error.
1581 * Caller should take appropriate action.
1583 (*ic
->ic_conn_ops
.icb_rx_error
)(ic
, pdu
, IDM_STATUS_PROTOCOL_ERROR
);
1587 idm_notify_client(idm_conn_t
*ic
, idm_client_notify_t cn
, uintptr_t data
)
1590 * We may want to make this more complicated at some point but
1591 * for now lets just call the client's notify function and return
1594 ASSERT(!mutex_owned(&ic
->ic_state_mutex
));
1595 cn
= (cn
> CN_MAX
) ? CN_MAX
: cn
;
1596 IDM_SM_LOG(CE_NOTE
, "idm_notify_client: ic=%p %s(%d)\n",
1597 (void *)ic
, idm_cn_strings
[cn
], cn
);
1598 return ((*ic
->ic_conn_ops
.icb_client_notify
)(ic
, cn
, data
));
1602 idm_ffp_enable(idm_conn_t
*ic
)
1607 * On the initiator side the client will see this notification
1608 * before the actual login succes PDU. This shouldn't be a big
1609 * deal since the initiator drives the connection. It can simply
1610 * wait for the login response then start sending SCSI commands.
1611 * Kind ugly though compared with the way things work on target
1614 mutex_enter(&ic
->ic_state_mutex
);
1615 ic
->ic_ffp
= B_TRUE
;
1616 mutex_exit(&ic
->ic_state_mutex
);
1618 rc
= idm_notify_client(ic
, CN_FFP_ENABLED
, (uintptr_t)NULL
);
1619 if (rc
!= IDM_STATUS_SUCCESS
) {
1620 mutex_enter(&ic
->ic_state_mutex
);
1621 ic
->ic_ffp
= B_FALSE
;
1622 mutex_exit(&ic
->ic_state_mutex
);
1628 idm_ffp_disable(idm_conn_t
*ic
, idm_ffp_disable_t disable_type
)
1630 mutex_enter(&ic
->ic_state_mutex
);
1631 ic
->ic_ffp
= B_FALSE
;
1632 mutex_exit(&ic
->ic_state_mutex
);
1634 /* Client can't "fail" CN_FFP_DISABLED */
1635 (void) idm_notify_client(ic
, CN_FFP_DISABLED
,
1636 (uintptr_t)disable_type
);
1640 idm_initial_login_actions(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
1642 ASSERT((event_ctx
->iec_event
== CE_LOGIN_RCV
) ||
1643 (event_ctx
->iec_event
== CE_LOGIN_SND
));
1646 * Currently it's not clear what we would do here -- since
1647 * we went to the trouble of coding an "initial login" hook
1648 * we'll leave it in for now. Remove before integration if
1649 * it's not used for anything.
1651 ic
->ic_state_flags
|= CF_INITIAL_LOGIN
;
1655 idm_login_success_actions(idm_conn_t
*ic
, idm_conn_event_ctx_t
*event_ctx
)
1657 idm_pdu_t
*pdu
= (idm_pdu_t
*)event_ctx
->iec_info
;
1658 iscsi_login_hdr_t
*login_req
=
1659 (iscsi_login_hdr_t
*)pdu
->isp_hdr
;
1661 ASSERT((event_ctx
->iec_event
== CE_LOGIN_SUCCESS_RCV
) ||
1662 (event_ctx
->iec_event
== CE_LOGIN_SUCCESS_SND
));
1667 mutex_enter(&ic
->ic_state_mutex
);
1668 ic
->ic_login_cid
= ntohs(login_req
->cid
);
1669 ic
->ic_login_info_valid
= B_TRUE
;
1671 mutex_exit(&ic
->ic_state_mutex
);