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 */
26
27 #include <sys/cpuvar.h>
28 #include <sys/ddi.h>
29 #include <sys/sunddi.h>
30 #include <sys/modctl.h>
31 #include <sys/socket.h>
32 #include <sys/strsubr.h>
33 #include <sys/note.h>
34 #include <sys/sdt.h>
35
36 #define IDM_CONN_SM_STRINGS
37 #define IDM_CN_NOTIFY_STRINGS
38 #include <sys/idm/idm.h>
39
40 boolean_t idm_sm_logging = B_FALSE;
41
42 extern idm_global_t idm; /* Global state */
43
44 static void
153 idm_conn_sm_fini(idm_conn_t *ic)
154 {
155
156 /*
157 * The connection may only be partially created. If there
158 * is no taskq, then the connection SM was not initialized.
159 */
160 if (ic->ic_state_taskq == NULL) {
161 return;
162 }
163
164 taskq_destroy(ic->ic_state_taskq);
165
166 cv_destroy(&ic->ic_state_cv);
167 /*
168 * The thread that generated the event that got us here may still
169 * hold the ic_state_mutex. Once it is released we can safely
170 * destroy it since there is no way to locate the object now.
171 */
172 mutex_enter(&ic->ic_state_mutex);
173 mutex_destroy(&ic->ic_state_mutex);
174 }
175
176 void
177 idm_conn_event(idm_conn_t *ic, idm_conn_event_t event, uintptr_t event_info)
178 {
179 mutex_enter(&ic->ic_state_mutex);
180 idm_conn_event_locked(ic, event, event_info, CT_NONE);
181 mutex_exit(&ic->ic_state_mutex);
182 }
183
184
185 idm_status_t
186 idm_conn_reinstate_event(idm_conn_t *old_ic, idm_conn_t *new_ic)
187 {
188 int result;
189
190 mutex_enter(&old_ic->ic_state_mutex);
191 if (((old_ic->ic_conn_type == CONN_TYPE_INI) &&
192 (old_ic->ic_state != CS_S8_CLEANUP)) ||
474 case CE_TRANSPORT_FAIL:
475 case CE_CONNECT_FAIL:
476 case CE_LOGOUT_OTHER_CONN_RCV:
477 case CE_TX_PROTOCOL_ERROR:
478 case CE_RX_PROTOCOL_ERROR:
479 /* T2 */
480 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
481 break;
482 default:
483 ASSERT(0);
484 /*NOTREACHED*/
485 }
486 }
487
488
489 static void
490 idm_login_timeout(void *arg)
491 {
492 idm_conn_t *ic = arg;
493
494 idm_conn_event(ic, CE_LOGIN_TIMEOUT, NULL);
495 }
496
497 static void
498 idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
499 {
500 switch (event_ctx->iec_event) {
501 case CE_LOGIN_RCV:
502 /* T4 */
503 idm_initial_login_actions(ic, event_ctx);
504 idm_update_state(ic, CS_S4_IN_LOGIN, event_ctx);
505 break;
506 case CE_LOGIN_TIMEOUT:
507 /*
508 * Don't need to cancel login timer since the timer is
509 * presumed to be the source of this event.
510 */
511 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
512 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
513 break;
514 case CE_CONNECT_REJECT:
515 /*
516 * Iscsit doesn't want to hear from us again in this case.
517 * Since it rejected the connection it doesn't have a
518 * connection context to handle additional notifications.
519 * IDM needs to just clean things up on its own.
520 */
521 (void) untimeout(ic->ic_state_timeout);
522 idm_update_state(ic, CS_S9A_REJECTED, event_ctx);
523 break;
524 case CE_CONNECT_FAIL:
525 case CE_TRANSPORT_FAIL:
526 case CE_LOGOUT_OTHER_CONN_SND:
527 /* T6 */
528 (void) untimeout(ic->ic_state_timeout);
529 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
530 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
531 break;
532 case CE_TX_PROTOCOL_ERROR:
533 case CE_RX_PROTOCOL_ERROR:
534 /* Don't care */
535 break;
536 default:
537 ASSERT(0);
538 /*NOTREACHED*/
539 }
540 }
541
542 static void
543 idm_state_s4_in_login(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
544 {
545 idm_pdu_t *pdu;
546
547 /*
548 * Login timer should no longer be active after leaving this
549 * state.
550 */
551 switch (event_ctx->iec_event) {
552 case CE_LOGIN_SUCCESS_RCV:
553 case CE_LOGIN_SUCCESS_SND:
554 ASSERT(ic->ic_client_callback == NULL);
555
556 (void) untimeout(ic->ic_state_timeout);
557 idm_login_success_actions(ic, event_ctx);
558 if (ic->ic_rdma_extensions) {
559 /* T19 */
560 idm_update_state(ic, CS_S12_ENABLE_DM, event_ctx);
561 } else {
562 /* T5 */
563 idm_update_state(ic, CS_S5_LOGGED_IN, event_ctx);
564 }
565 break;
566 case CE_LOGIN_TIMEOUT:
567 /* T7 */
568 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
569 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
570 break;
571 case CE_LOGIN_FAIL_SND:
572 /*
573 * Allow the logout response pdu to be sent and defer
574 * the state machine cleanup until the completion callback.
575 * Only 1 level or callback interposition is allowed.
576 */
577 (void) untimeout(ic->ic_state_timeout);
578 pdu = (idm_pdu_t *)event_ctx->iec_info;
579 ASSERT(ic->ic_client_callback == NULL);
580 ic->ic_client_callback = pdu->isp_callback;
581 pdu->isp_callback =
582 idm_state_s9b_wait_snd_done_cb;
583 idm_update_state(ic, CS_S9B_WAIT_SND_DONE,
584 event_ctx);
585 break;
586 case CE_LOGIN_FAIL_RCV:
587 ASSERT(ic->ic_client_callback == NULL);
588 /*
589 * Need to deliver this PDU to the initiator now because after
590 * we update the state to CS_S9_INIT_ERROR the initiator will
591 * no longer be in an appropriate state.
592 */
593 event_ctx->iec_pdu_forwarded = B_TRUE;
594 pdu = (idm_pdu_t *)event_ctx->iec_info;
595 idm_pdu_rx_forward(ic, pdu);
596 /* FALLTHROUGH */
597 case CE_TRANSPORT_FAIL:
598 case CE_LOGOUT_OTHER_CONN_SND:
599 case CE_LOGOUT_OTHER_CONN_RCV:
600 /* T7 */
601 (void) untimeout(ic->ic_state_timeout);
602 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
603 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
604 break;
605 case CE_LOGOUT_SESSION_SUCCESS:
606 /*
607 * T8
608 * A session reinstatement request can be received while a
609 * session is active and a login is in process. The iSCSI
610 * connections are shut down by a CE_LOGOUT_SESSION_SUCCESS
611 * event sent from the session to the IDM layer.
612 */
613 (void) untimeout(ic->ic_state_timeout);
614 if (IDM_CONN_ISTGT(ic)) {
615 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
616 } else {
617 ic->ic_transport_ops->it_ini_conn_disconnect(ic);
618 }
619 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
620 break;
621
622 case CE_LOGIN_SND:
623 ASSERT(ic->ic_client_callback == NULL);
624 /*
625 * Initiator connections will see initial login PDU
626 * in this state. Target connections see initial
627 * login PDU in "xpt up" state.
628 */
629 mutex_enter(&ic->ic_state_mutex);
630 if (!(ic->ic_state_flags & CF_INITIAL_LOGIN)) {
631 idm_initial_login_actions(ic, event_ctx);
632 }
633 mutex_exit(&ic->ic_state_mutex);
809 idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
810 break;
811 case CE_TX_PROTOCOL_ERROR:
812 case CE_RX_PROTOCOL_ERROR:
813 case CE_MISC_TX:
814 case CE_MISC_RX:
815 case CE_LOGIN_TIMEOUT:
816 /* Don't care */
817 break;
818 default:
819 ASSERT(0);
820 }
821 }
822
823
824 static void
825 idm_logout_req_timeout(void *arg)
826 {
827 idm_conn_t *ic = arg;
828
829 idm_conn_event(ic, CE_LOGOUT_TIMEOUT, NULL);
830 }
831
832 static void
833 idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
834 {
835 /* Must cancel logout timer before leaving this state */
836 switch (event_ctx->iec_event) {
837 case CE_LOGOUT_THIS_CONN_RCV:
838 case CE_LOGOUT_THIS_CONN_SND:
839 case CE_LOGOUT_OTHER_CONN_RCV:
840 case CE_LOGOUT_OTHER_CONN_SND:
841 /* T10 */
842 if (IDM_CONN_ISTGT(ic)) {
843 (void) untimeout(ic->ic_state_timeout);
844 }
845 idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */
846 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
847 break;
848 case CE_LOGOUT_SESSION_RCV:
849 case CE_LOGOUT_SESSION_SND:
850 /* T10 */
851 if (IDM_CONN_ISTGT(ic)) {
852 (void) untimeout(ic->ic_state_timeout);
853 }
854 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
855 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
856 break;
857 case CE_ASYNC_LOGOUT_RCV:
858 case CE_ASYNC_LOGOUT_SND:
859 /* T12 Do nothing */
860 break;
861 case CE_TRANSPORT_FAIL:
862 case CE_ASYNC_DROP_CONN_RCV:
863 case CE_ASYNC_DROP_CONN_SND:
864 case CE_ASYNC_DROP_ALL_CONN_RCV:
865 case CE_ASYNC_DROP_ALL_CONN_SND:
866 /* T16 */
867 if (IDM_CONN_ISTGT(ic)) {
868 (void) untimeout(ic->ic_state_timeout);
869 }
870 /* FALLTHROUGH */
871 case CE_LOGOUT_TIMEOUT:
872 idm_ffp_disable(ic, FD_CONN_FAIL); /* Implicit logout */
873 idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
874 break;
875 case CE_LOGOUT_SESSION_SUCCESS:
876 /* T18 */
877 if (IDM_CONN_ISTGT(ic)) {
878 (void) untimeout(ic->ic_state_timeout);
879 }
880 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
881
882 /* Close connection (if it's not already closed) */
883 if (IDM_CONN_ISTGT(ic)) {
884 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
885 } else {
886 ic->ic_transport_ops->it_ini_conn_disconnect(ic);
887 }
888
889 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
890 break;
891 case CE_TX_PROTOCOL_ERROR:
892 case CE_RX_PROTOCOL_ERROR:
893 case CE_MISC_TX:
894 case CE_MISC_RX:
895 case CE_LOGIN_TIMEOUT:
896 /* Don't care */
897 break;
898 default:
899 ASSERT(0);
900 }
901 }
902
903
904 static void
905 idm_cleanup_timeout(void *arg)
906 {
907 idm_conn_t *ic = arg;
908
909 idm_conn_event(ic, CE_CLEANUP_TIMEOUT, NULL);
910 }
911
912 static void
913 idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
914 {
915 idm_pdu_t *pdu;
916
917 /*
918 * Need to cancel the cleanup timeout before leaving this state
919 * if it hasn't already fired.
920 */
921 switch (event_ctx->iec_event) {
922 case CE_LOGOUT_SUCCESS_RCV:
923 case CE_LOGOUT_SUCCESS_SND:
924 case CE_LOGOUT_SESSION_SUCCESS:
925 (void) untimeout(ic->ic_state_timeout);
926 /*FALLTHROUGH*/
927 case CE_CLEANUP_TIMEOUT:
928 /* M1 */
929 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
930 break;
931 case CE_LOGOUT_OTHER_CONN_RCV:
932 case CE_LOGOUT_OTHER_CONN_SND:
933 /* M2 */
934 idm_update_state(ic, CS_S10_IN_CLEANUP, event_ctx);
935 break;
936 case CE_LOGOUT_SUCCESS_SND_DONE:
937 case CE_LOGOUT_FAIL_SND_DONE:
938 pdu = (idm_pdu_t *)event_ctx->iec_info;
939 /* restore client callback */
940 pdu->isp_callback = ic->ic_client_callback;
941 ic->ic_client_callback = NULL;
942 idm_pdu_complete(pdu, pdu->isp_status);
943 break;
944 case CE_LOGOUT_SESSION_RCV:
945 case CE_LOGOUT_SESSION_SND:
1014
1015
1016
1017 static void
1018 idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1019 {
1020 idm_pdu_t *pdu;
1021
1022 /*
1023 * Need to cancel the cleanup timeout before leaving this state
1024 * if it hasn't already fired.
1025 */
1026 switch (event_ctx->iec_event) {
1027 case CE_LOGOUT_FAIL_RCV:
1028 case CE_LOGOUT_FAIL_SND:
1029 idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
1030 break;
1031 case CE_LOGOUT_SUCCESS_SND:
1032 case CE_LOGOUT_SUCCESS_RCV:
1033 case CE_LOGOUT_SESSION_SUCCESS:
1034 (void) untimeout(ic->ic_state_timeout);
1035 /*FALLTHROUGH*/
1036 case CE_CLEANUP_TIMEOUT:
1037 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
1038 break;
1039 case CE_LOGOUT_SUCCESS_SND_DONE:
1040 case CE_LOGOUT_FAIL_SND_DONE:
1041 pdu = (idm_pdu_t *)event_ctx->iec_info;
1042 /* restore client callback */
1043 pdu->isp_callback = ic->ic_client_callback;
1044 ic->ic_client_callback = NULL;
1045 idm_pdu_complete(pdu, pdu->isp_status);
1046 break;
1047 case CE_TX_PROTOCOL_ERROR:
1048 case CE_RX_PROTOCOL_ERROR:
1049 case CE_MISC_TX:
1050 case CE_MISC_RX:
1051 case CE_LOGIN_TIMEOUT:
1052 case CE_LOGOUT_TIMEOUT:
1053 /* Don't care */
1054 break;
1170 * Finish any connection related setup including
1171 * waking up the idm_tgt_conn_accept thread.
1172 * and starting the login timer. If the function
1173 * fails then we return to "free" state.
1174 */
1175 if ((rc = idm_tgt_conn_finish(ic)) != IDM_STATUS_SUCCESS) {
1176 switch (rc) {
1177 case IDM_STATUS_REJECT:
1178 idm_conn_event(ic, CE_CONNECT_REJECT, NULL);
1179 break;
1180 default:
1181 idm_conn_event(ic, CE_CONNECT_FAIL, NULL);
1182 break;
1183 }
1184 }
1185
1186 /*
1187 * First login received will cause a transition to
1188 * CS_S4_IN_LOGIN. Start login timer.
1189 */
1190 ic->ic_state_timeout = timeout(idm_login_timeout, ic,
1191 drv_usectohz(IDM_LOGIN_SECONDS*1000000));
1192 break;
1193 case CS_S4_IN_LOGIN:
1194 if (ic->ic_conn_type == CONN_TYPE_INI) {
1195 (void) idm_notify_client(ic, CN_READY_FOR_LOGIN, NULL);
1196 mutex_enter(&ic->ic_state_mutex);
1197 ic->ic_state_flags |= CF_LOGIN_READY;
1198 cv_signal(&ic->ic_state_cv);
1199 mutex_exit(&ic->ic_state_mutex);
1200 }
1201 break;
1202 case CS_S5_LOGGED_IN:
1203 ASSERT(!ic->ic_ffp);
1204 /*
1205 * IDM can go to FFP before the initiator but it
1206 * needs to go to FFP after the target (IDM target should
1207 * go to FFP after notify_ack).
1208 */
1209 idm_status = idm_ffp_enable(ic);
1210 if (idm_status != IDM_STATUS_SUCCESS) {
1211 idm_conn_event(ic, CE_TRANSPORT_FAIL, NULL);
1212 }
1213
1214 if (ic->ic_reinstate_conn) {
1215 /* Connection reinstatement is complete */
1216 idm_conn_event(ic->ic_reinstate_conn,
1217 CE_CONN_REINSTATE_SUCCESS, NULL);
1218 }
1219 break;
1220 case CS_S6_IN_LOGOUT:
1221 break;
1222 case CS_S7_LOGOUT_REQ:
1223 /* Start logout timer for target connections */
1224 if (IDM_CONN_ISTGT(ic)) {
1225 ic->ic_state_timeout = timeout(idm_logout_req_timeout,
1226 ic, drv_usectohz(IDM_LOGOUT_SECONDS*1000000));
1227 }
1228 break;
1229 case CS_S8_CLEANUP:
1230 /* Close connection (if it's not already closed) */
1231 if (IDM_CONN_ISTGT(ic)) {
1232 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
1233 } else {
1234 ic->ic_transport_ops->it_ini_conn_disconnect(ic);
1235 }
1236
1237 /* Stop executing active tasks */
1238 idm_task_abort(ic, NULL, AT_INTERNAL_SUSPEND);
1239
1240 /* Start logout timer */
1241 ic->ic_state_timeout = timeout(idm_cleanup_timeout, ic,
1242 drv_usectohz(IDM_CLEANUP_SECONDS*1000000));
1243 break;
1244 case CS_S10_IN_CLEANUP:
1245 break;
1246 case CS_S9A_REJECTED:
1247 /*
1248 * We never finished establishing the connection so no
1249 * disconnect. No client notifications because the client
1250 * rejected the connection.
1251 */
1252 idm_refcnt_async_wait_ref(&ic->ic_refcnt,
1253 &idm_conn_reject_unref);
1254 break;
1255 case CS_S9B_WAIT_SND_DONE:
1256 break;
1257 case CS_S9_INIT_ERROR:
1258 if (IDM_CONN_ISTGT(ic)) {
1259 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
1260 } else {
|
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 2015 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 #include <sys/cpuvar.h>
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 #include <sys/modctl.h>
32 #include <sys/socket.h>
33 #include <sys/strsubr.h>
34 #include <sys/note.h>
35 #include <sys/sdt.h>
36
37 #define IDM_CONN_SM_STRINGS
38 #define IDM_CN_NOTIFY_STRINGS
39 #include <sys/idm/idm.h>
40
41 boolean_t idm_sm_logging = B_FALSE;
42
43 extern idm_global_t idm; /* Global state */
44
45 static void
154 idm_conn_sm_fini(idm_conn_t *ic)
155 {
156
157 /*
158 * The connection may only be partially created. If there
159 * is no taskq, then the connection SM was not initialized.
160 */
161 if (ic->ic_state_taskq == NULL) {
162 return;
163 }
164
165 taskq_destroy(ic->ic_state_taskq);
166
167 cv_destroy(&ic->ic_state_cv);
168 /*
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.
172 */
173 mutex_enter(&ic->ic_state_mutex);
174 IDM_SM_TIMER_CLEAR(ic);
175 mutex_destroy(&ic->ic_state_mutex);
176 }
177
178 void
179 idm_conn_event(idm_conn_t *ic, idm_conn_event_t event, uintptr_t event_info)
180 {
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);
184 }
185
186
187 idm_status_t
188 idm_conn_reinstate_event(idm_conn_t *old_ic, idm_conn_t *new_ic)
189 {
190 int result;
191
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)) ||
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:
481 /* T2 */
482 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
483 break;
484 default:
485 ASSERT(0);
486 /*NOTREACHED*/
487 }
488 }
489
490
491 static void
492 idm_login_timeout(void *arg)
493 {
494 idm_conn_t *ic = arg;
495
496 ic->ic_state_timeout = 0;
497 idm_conn_event(ic, CE_LOGIN_TIMEOUT, NULL);
498 }
499
500 static void
501 idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
502 {
503 switch (event_ctx->iec_event) {
504 case CE_LOGIN_RCV:
505 /* T4 */
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);
509 break;
510 case CE_LOGIN_TIMEOUT:
511 /*
512 * Don't need to cancel login timer since the timer is
513 * presumed to be the source of this event.
514 */
515 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
516 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
517 break;
518 case CE_CONNECT_REJECT:
519 /*
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.
524 */
525 IDM_SM_TIMER_CLEAR(ic);
526 idm_update_state(ic, CS_S9A_REJECTED, event_ctx);
527 break;
528 case CE_CONNECT_FAIL:
529 case CE_TRANSPORT_FAIL:
530 case CE_LOGOUT_OTHER_CONN_SND:
531 /* T6 */
532 IDM_SM_TIMER_CLEAR(ic);
533 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
534 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
535 break;
536 case CE_TX_PROTOCOL_ERROR:
537 case CE_RX_PROTOCOL_ERROR:
538 /* Don't care */
539 break;
540 default:
541 ASSERT(0);
542 /*NOTREACHED*/
543 }
544 }
545
546 static void
547 idm_state_s4_in_login(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
548 {
549 idm_pdu_t *pdu;
550
551 /*
552 * Login timer should no longer be active after leaving this
553 * state.
554 */
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);
559
560 IDM_SM_TIMER_CLEAR(ic);
561 idm_login_success_actions(ic, event_ctx);
562 if (ic->ic_rdma_extensions) {
563 /* T19 */
564 idm_update_state(ic, CS_S12_ENABLE_DM, event_ctx);
565 } else {
566 /* T5 */
567 idm_update_state(ic, CS_S5_LOGGED_IN, event_ctx);
568 }
569 break;
570 case CE_LOGIN_TIMEOUT:
571 /* T7 */
572 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
573 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
574 break;
575 case CE_LOGIN_FAIL_SND:
576 /*
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.
580 */
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;
585 pdu->isp_callback =
586 idm_state_s9b_wait_snd_done_cb;
587 idm_update_state(ic, CS_S9B_WAIT_SND_DONE,
588 event_ctx);
589 break;
590 case CE_LOGIN_FAIL_RCV:
591 ASSERT(ic->ic_client_callback == NULL);
592 /*
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.
596 */
597 event_ctx->iec_pdu_forwarded = B_TRUE;
598 pdu = (idm_pdu_t *)event_ctx->iec_info;
599 idm_pdu_rx_forward(ic, pdu);
600 /* FALLTHROUGH */
601 case CE_TRANSPORT_FAIL:
602 case CE_LOGOUT_OTHER_CONN_SND:
603 case CE_LOGOUT_OTHER_CONN_RCV:
604 /* T7 */
605 IDM_SM_TIMER_CLEAR(ic);
606 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
607 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
608 break;
609 case CE_LOGOUT_SESSION_SUCCESS:
610 /*
611 * T8
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.
616 */
617 IDM_SM_TIMER_CLEAR(ic);
618 if (IDM_CONN_ISTGT(ic)) {
619 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
620 } else {
621 ic->ic_transport_ops->it_ini_conn_disconnect(ic);
622 }
623 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
624 break;
625
626 case CE_LOGIN_SND:
627 ASSERT(ic->ic_client_callback == NULL);
628 /*
629 * Initiator connections will see initial login PDU
630 * in this state. Target connections see initial
631 * login PDU in "xpt up" state.
632 */
633 mutex_enter(&ic->ic_state_mutex);
634 if (!(ic->ic_state_flags & CF_INITIAL_LOGIN)) {
635 idm_initial_login_actions(ic, event_ctx);
636 }
637 mutex_exit(&ic->ic_state_mutex);
813 idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
814 break;
815 case CE_TX_PROTOCOL_ERROR:
816 case CE_RX_PROTOCOL_ERROR:
817 case CE_MISC_TX:
818 case CE_MISC_RX:
819 case CE_LOGIN_TIMEOUT:
820 /* Don't care */
821 break;
822 default:
823 ASSERT(0);
824 }
825 }
826
827
828 static void
829 idm_logout_req_timeout(void *arg)
830 {
831 idm_conn_t *ic = arg;
832
833 ic->ic_state_timeout = 0;
834 idm_conn_event(ic, CE_LOGOUT_TIMEOUT, NULL);
835 }
836
837 static void
838 idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
839 {
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:
846 /* T10 */
847 if (IDM_CONN_ISTGT(ic)) {
848 IDM_SM_TIMER_CLEAR(ic);
849 }
850 idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */
851 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
852 break;
853 case CE_LOGOUT_SESSION_RCV:
854 case CE_LOGOUT_SESSION_SND:
855 /* T10 */
856 if (IDM_CONN_ISTGT(ic)) {
857 IDM_SM_TIMER_CLEAR(ic);
858 }
859 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
860 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
861 break;
862 case CE_ASYNC_LOGOUT_RCV:
863 case CE_ASYNC_LOGOUT_SND:
864 /* T12 Do nothing */
865 break;
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:
871 /* T16 */
872 if (IDM_CONN_ISTGT(ic)) {
873 IDM_SM_TIMER_CLEAR(ic);
874 }
875 /* FALLTHROUGH */
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);
879 break;
880 case CE_LOGOUT_SESSION_SUCCESS:
881 /* T18 */
882 if (IDM_CONN_ISTGT(ic)) {
883 IDM_SM_TIMER_CLEAR(ic);
884 }
885 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
886
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);
890 } else {
891 ic->ic_transport_ops->it_ini_conn_disconnect(ic);
892 }
893
894 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
895 break;
896 case CE_TX_PROTOCOL_ERROR:
897 case CE_RX_PROTOCOL_ERROR:
898 case CE_MISC_TX:
899 case CE_MISC_RX:
900 case CE_LOGIN_TIMEOUT:
901 /* Don't care */
902 break;
903 default:
904 ASSERT(0);
905 }
906 }
907
908
909 static void
910 idm_cleanup_timeout(void *arg)
911 {
912 idm_conn_t *ic = arg;
913
914 ic->ic_state_timeout = 0;
915 idm_conn_event(ic, CE_CLEANUP_TIMEOUT, NULL);
916 }
917
918 static void
919 idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
920 {
921 idm_pdu_t *pdu;
922
923 /*
924 * Need to cancel the cleanup timeout before leaving this state
925 * if it hasn't already fired.
926 */
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);
932 /*FALLTHROUGH*/
933 case CE_CLEANUP_TIMEOUT:
934 /* M1 */
935 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
936 break;
937 case CE_LOGOUT_OTHER_CONN_RCV:
938 case CE_LOGOUT_OTHER_CONN_SND:
939 /* M2 */
940 idm_update_state(ic, CS_S10_IN_CLEANUP, event_ctx);
941 break;
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);
949 break;
950 case CE_LOGOUT_SESSION_RCV:
951 case CE_LOGOUT_SESSION_SND:
1020
1021
1022
1023 static void
1024 idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1025 {
1026 idm_pdu_t *pdu;
1027
1028 /*
1029 * Need to cancel the cleanup timeout before leaving this state
1030 * if it hasn't already fired.
1031 */
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);
1036 break;
1037 case CE_LOGOUT_SUCCESS_SND:
1038 case CE_LOGOUT_SUCCESS_RCV:
1039 case CE_LOGOUT_SESSION_SUCCESS:
1040 IDM_SM_TIMER_CLEAR(ic);
1041 /*FALLTHROUGH*/
1042 case CE_CLEANUP_TIMEOUT:
1043 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
1044 break;
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);
1052 break;
1053 case CE_TX_PROTOCOL_ERROR:
1054 case CE_RX_PROTOCOL_ERROR:
1055 case CE_MISC_TX:
1056 case CE_MISC_RX:
1057 case CE_LOGIN_TIMEOUT:
1058 case CE_LOGOUT_TIMEOUT:
1059 /* Don't care */
1060 break;
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.
1180 */
1181 if ((rc = idm_tgt_conn_finish(ic)) != IDM_STATUS_SUCCESS) {
1182 switch (rc) {
1183 case IDM_STATUS_REJECT:
1184 idm_conn_event(ic, CE_CONNECT_REJECT, NULL);
1185 break;
1186 default:
1187 idm_conn_event(ic, CE_CONNECT_FAIL, NULL);
1188 break;
1189 }
1190 }
1191
1192 /*
1193 * First login received will cause a transition to
1194 * CS_S4_IN_LOGIN. Start login timer.
1195 */
1196 IDM_SM_TIMER_CHECK(ic);
1197 ic->ic_state_timeout = timeout(idm_login_timeout, ic,
1198 drv_usectohz(IDM_LOGIN_SECONDS*1000000));
1199 break;
1200 case CS_S4_IN_LOGIN:
1201 if (ic->ic_conn_type == CONN_TYPE_INI) {
1202 (void) idm_notify_client(ic, CN_READY_FOR_LOGIN, NULL);
1203 mutex_enter(&ic->ic_state_mutex);
1204 ic->ic_state_flags |= CF_LOGIN_READY;
1205 cv_signal(&ic->ic_state_cv);
1206 mutex_exit(&ic->ic_state_mutex);
1207 }
1208 break;
1209 case CS_S5_LOGGED_IN:
1210 ASSERT(!ic->ic_ffp);
1211 /*
1212 * IDM can go to FFP before the initiator but it
1213 * needs to go to FFP after the target (IDM target should
1214 * go to FFP after notify_ack).
1215 */
1216 idm_status = idm_ffp_enable(ic);
1217 if (idm_status != IDM_STATUS_SUCCESS) {
1218 idm_conn_event(ic, CE_TRANSPORT_FAIL, NULL);
1219 }
1220
1221 if (ic->ic_reinstate_conn) {
1222 /* Connection reinstatement is complete */
1223 idm_conn_event(ic->ic_reinstate_conn,
1224 CE_CONN_REINSTATE_SUCCESS, NULL);
1225 }
1226 break;
1227 case CS_S6_IN_LOGOUT:
1228 break;
1229 case CS_S7_LOGOUT_REQ:
1230 /* Start logout timer for target connections */
1231 if (IDM_CONN_ISTGT(ic)) {
1232 IDM_SM_TIMER_CHECK(ic);
1233 ic->ic_state_timeout = timeout(idm_logout_req_timeout,
1234 ic, drv_usectohz(IDM_LOGOUT_SECONDS*1000000));
1235 }
1236 break;
1237 case CS_S8_CLEANUP:
1238 /* Close connection (if it's not already closed) */
1239 if (IDM_CONN_ISTGT(ic)) {
1240 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
1241 } else {
1242 ic->ic_transport_ops->it_ini_conn_disconnect(ic);
1243 }
1244
1245 /* Stop executing active tasks */
1246 idm_task_abort(ic, NULL, AT_INTERNAL_SUSPEND);
1247
1248 /* Start logout timer */
1249 IDM_SM_TIMER_CHECK(ic);
1250 ic->ic_state_timeout = timeout(idm_cleanup_timeout, ic,
1251 drv_usectohz(IDM_CLEANUP_SECONDS*1000000));
1252 break;
1253 case CS_S10_IN_CLEANUP:
1254 break;
1255 case CS_S9A_REJECTED:
1256 /*
1257 * We never finished establishing the connection so no
1258 * disconnect. No client notifications because the client
1259 * rejected the connection.
1260 */
1261 idm_refcnt_async_wait_ref(&ic->ic_refcnt,
1262 &idm_conn_reject_unref);
1263 break;
1264 case CS_S9B_WAIT_SND_DONE:
1265 break;
1266 case CS_S9_INIT_ERROR:
1267 if (IDM_CONN_ISTGT(ic)) {
1268 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
1269 } else {
|