17978SPeter.Dunlap@Sun.COM /*
27978SPeter.Dunlap@Sun.COM * CDDL HEADER START
37978SPeter.Dunlap@Sun.COM *
47978SPeter.Dunlap@Sun.COM * The contents of this file are subject to the terms of the
57978SPeter.Dunlap@Sun.COM * Common Development and Distribution License (the "License").
67978SPeter.Dunlap@Sun.COM * You may not use this file except in compliance with the License.
77978SPeter.Dunlap@Sun.COM *
87978SPeter.Dunlap@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97978SPeter.Dunlap@Sun.COM * or http://www.opensolaris.org/os/licensing.
107978SPeter.Dunlap@Sun.COM * See the License for the specific language governing permissions
117978SPeter.Dunlap@Sun.COM * and limitations under the License.
127978SPeter.Dunlap@Sun.COM *
137978SPeter.Dunlap@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147978SPeter.Dunlap@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157978SPeter.Dunlap@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167978SPeter.Dunlap@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177978SPeter.Dunlap@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187978SPeter.Dunlap@Sun.COM *
197978SPeter.Dunlap@Sun.COM * CDDL HEADER END
207978SPeter.Dunlap@Sun.COM */
217978SPeter.Dunlap@Sun.COM
227978SPeter.Dunlap@Sun.COM /*
2312372SPriya.Krishnan@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
247978SPeter.Dunlap@Sun.COM */
257978SPeter.Dunlap@Sun.COM
267978SPeter.Dunlap@Sun.COM #include <sys/cpuvar.h>
277978SPeter.Dunlap@Sun.COM #include <sys/ddi.h>
287978SPeter.Dunlap@Sun.COM #include <sys/sunddi.h>
297978SPeter.Dunlap@Sun.COM #include <sys/modctl.h>
307978SPeter.Dunlap@Sun.COM #include <sys/socket.h>
317978SPeter.Dunlap@Sun.COM #include <sys/strsubr.h>
327978SPeter.Dunlap@Sun.COM #include <sys/note.h>
337978SPeter.Dunlap@Sun.COM #include <sys/sdt.h>
347978SPeter.Dunlap@Sun.COM
357978SPeter.Dunlap@Sun.COM #define IDM_CONN_SM_STRINGS
369162SPeter.Dunlap@Sun.COM #define IDM_CN_NOTIFY_STRINGS
377978SPeter.Dunlap@Sun.COM #include <sys/idm/idm.h>
387978SPeter.Dunlap@Sun.COM
397978SPeter.Dunlap@Sun.COM boolean_t idm_sm_logging = B_FALSE;
407978SPeter.Dunlap@Sun.COM
417978SPeter.Dunlap@Sun.COM extern idm_global_t idm; /* Global state */
427978SPeter.Dunlap@Sun.COM
437978SPeter.Dunlap@Sun.COM static void
447978SPeter.Dunlap@Sun.COM idm_conn_event_handler(void *event_ctx_opaque);
457978SPeter.Dunlap@Sun.COM
467978SPeter.Dunlap@Sun.COM static void
477978SPeter.Dunlap@Sun.COM idm_state_s1_free(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
487978SPeter.Dunlap@Sun.COM
497978SPeter.Dunlap@Sun.COM static void
507978SPeter.Dunlap@Sun.COM idm_state_s2_xpt_wait(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
517978SPeter.Dunlap@Sun.COM
527978SPeter.Dunlap@Sun.COM static void
537978SPeter.Dunlap@Sun.COM idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
547978SPeter.Dunlap@Sun.COM
557978SPeter.Dunlap@Sun.COM static void
567978SPeter.Dunlap@Sun.COM idm_state_s4_in_login(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
577978SPeter.Dunlap@Sun.COM
587978SPeter.Dunlap@Sun.COM static void
597978SPeter.Dunlap@Sun.COM idm_state_s5_logged_in(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
607978SPeter.Dunlap@Sun.COM
617978SPeter.Dunlap@Sun.COM static void
627978SPeter.Dunlap@Sun.COM idm_state_s6_in_logout(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
637978SPeter.Dunlap@Sun.COM
647978SPeter.Dunlap@Sun.COM static void
657978SPeter.Dunlap@Sun.COM idm_logout_req_timeout(void *arg);
667978SPeter.Dunlap@Sun.COM
677978SPeter.Dunlap@Sun.COM static void
687978SPeter.Dunlap@Sun.COM idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
697978SPeter.Dunlap@Sun.COM
707978SPeter.Dunlap@Sun.COM static void
717978SPeter.Dunlap@Sun.COM idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
727978SPeter.Dunlap@Sun.COM
737978SPeter.Dunlap@Sun.COM static void
747978SPeter.Dunlap@Sun.COM idm_state_s9_init_error(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
757978SPeter.Dunlap@Sun.COM
767978SPeter.Dunlap@Sun.COM static void
779373SPeter.Dunlap@Sun.COM idm_state_s9a_rejected(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
789373SPeter.Dunlap@Sun.COM
799373SPeter.Dunlap@Sun.COM static void
8011552SPeter.Cudhea@Sun.COM idm_state_s9b_wait_snd_done_cb(idm_pdu_t *pdu,
8111552SPeter.Cudhea@Sun.COM idm_status_t status);
8211552SPeter.Cudhea@Sun.COM
8311552SPeter.Cudhea@Sun.COM static void
8411552SPeter.Cudhea@Sun.COM idm_state_s9b_wait_snd_done(idm_conn_t *ic,
8511552SPeter.Cudhea@Sun.COM idm_conn_event_ctx_t *event_ctx);
8611552SPeter.Cudhea@Sun.COM
8711552SPeter.Cudhea@Sun.COM static void
887978SPeter.Dunlap@Sun.COM idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
897978SPeter.Dunlap@Sun.COM
907978SPeter.Dunlap@Sun.COM static void
917978SPeter.Dunlap@Sun.COM idm_state_s11_complete(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
927978SPeter.Dunlap@Sun.COM
937978SPeter.Dunlap@Sun.COM static void
947978SPeter.Dunlap@Sun.COM idm_state_s12_enable_dm(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
957978SPeter.Dunlap@Sun.COM
967978SPeter.Dunlap@Sun.COM static void
977978SPeter.Dunlap@Sun.COM idm_update_state(idm_conn_t *ic, idm_conn_state_t new_state,
987978SPeter.Dunlap@Sun.COM idm_conn_event_ctx_t *event_ctx);
997978SPeter.Dunlap@Sun.COM
1007978SPeter.Dunlap@Sun.COM static void
1017978SPeter.Dunlap@Sun.COM idm_conn_unref(void *ic_void);
1027978SPeter.Dunlap@Sun.COM
1039373SPeter.Dunlap@Sun.COM static void
1049373SPeter.Dunlap@Sun.COM idm_conn_reject_unref(void *ic_void);
1059373SPeter.Dunlap@Sun.COM
1067978SPeter.Dunlap@Sun.COM static idm_pdu_event_action_t
1077978SPeter.Dunlap@Sun.COM idm_conn_sm_validate_pdu(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx,
1087978SPeter.Dunlap@Sun.COM idm_pdu_t *pdu);
1097978SPeter.Dunlap@Sun.COM
1107978SPeter.Dunlap@Sun.COM static idm_status_t
1117978SPeter.Dunlap@Sun.COM idm_ffp_enable(idm_conn_t *ic);
1127978SPeter.Dunlap@Sun.COM
1137978SPeter.Dunlap@Sun.COM static void
1147978SPeter.Dunlap@Sun.COM idm_ffp_disable(idm_conn_t *ic, idm_ffp_disable_t disable_type);
1157978SPeter.Dunlap@Sun.COM
1167978SPeter.Dunlap@Sun.COM static void
1177978SPeter.Dunlap@Sun.COM idm_initial_login_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
1187978SPeter.Dunlap@Sun.COM
1197978SPeter.Dunlap@Sun.COM static void
1207978SPeter.Dunlap@Sun.COM idm_login_success_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
1217978SPeter.Dunlap@Sun.COM
1227978SPeter.Dunlap@Sun.COM idm_status_t
idm_conn_sm_init(idm_conn_t * ic)1237978SPeter.Dunlap@Sun.COM idm_conn_sm_init(idm_conn_t *ic)
1247978SPeter.Dunlap@Sun.COM {
1257978SPeter.Dunlap@Sun.COM char taskq_name[32];
1267978SPeter.Dunlap@Sun.COM
1277978SPeter.Dunlap@Sun.COM /*
1287978SPeter.Dunlap@Sun.COM * Caller should have assigned a unique connection ID. Use this
1297978SPeter.Dunlap@Sun.COM * connection ID to create a unique connection name string
1307978SPeter.Dunlap@Sun.COM */
1317978SPeter.Dunlap@Sun.COM ASSERT(ic->ic_internal_cid != 0);
1327978SPeter.Dunlap@Sun.COM (void) snprintf(taskq_name, sizeof (taskq_name) - 1, "conn_sm%08x",
1337978SPeter.Dunlap@Sun.COM ic->ic_internal_cid);
1347978SPeter.Dunlap@Sun.COM
1359162SPeter.Dunlap@Sun.COM ic->ic_state_taskq = taskq_create(taskq_name, 1, minclsyspri, 4, 16384,
1367978SPeter.Dunlap@Sun.COM TASKQ_PREPOPULATE);
1377978SPeter.Dunlap@Sun.COM if (ic->ic_state_taskq == NULL) {
1387978SPeter.Dunlap@Sun.COM return (IDM_STATUS_FAIL);
1397978SPeter.Dunlap@Sun.COM }
1407978SPeter.Dunlap@Sun.COM
1417978SPeter.Dunlap@Sun.COM idm_sm_audit_init(&ic->ic_state_audit);
1427978SPeter.Dunlap@Sun.COM mutex_init(&ic->ic_state_mutex, NULL, MUTEX_DEFAULT, NULL);
1437978SPeter.Dunlap@Sun.COM cv_init(&ic->ic_state_cv, NULL, CV_DEFAULT, NULL);
1447978SPeter.Dunlap@Sun.COM
1457978SPeter.Dunlap@Sun.COM ic->ic_state = CS_S1_FREE;
1467978SPeter.Dunlap@Sun.COM ic->ic_last_state = CS_S1_FREE;
1477978SPeter.Dunlap@Sun.COM
1487978SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
1497978SPeter.Dunlap@Sun.COM }
1507978SPeter.Dunlap@Sun.COM
1517978SPeter.Dunlap@Sun.COM void
idm_conn_sm_fini(idm_conn_t * ic)1527978SPeter.Dunlap@Sun.COM idm_conn_sm_fini(idm_conn_t *ic)
1537978SPeter.Dunlap@Sun.COM {
1549358SJames.Moore@Sun.COM
1559358SJames.Moore@Sun.COM /*
1569358SJames.Moore@Sun.COM * The connection may only be partially created. If there
1579358SJames.Moore@Sun.COM * is no taskq, then the connection SM was not initialized.
1589358SJames.Moore@Sun.COM */
1599358SJames.Moore@Sun.COM if (ic->ic_state_taskq == NULL) {
1609358SJames.Moore@Sun.COM return;
1619358SJames.Moore@Sun.COM }
1629358SJames.Moore@Sun.COM
1637978SPeter.Dunlap@Sun.COM taskq_destroy(ic->ic_state_taskq);
1647978SPeter.Dunlap@Sun.COM
1657978SPeter.Dunlap@Sun.COM cv_destroy(&ic->ic_state_cv);
1667978SPeter.Dunlap@Sun.COM /*
1677978SPeter.Dunlap@Sun.COM * The thread that generated the event that got us here may still
1687978SPeter.Dunlap@Sun.COM * hold the ic_state_mutex. Once it is released we can safely
1697978SPeter.Dunlap@Sun.COM * destroy it since there is no way to locate the object now.
1707978SPeter.Dunlap@Sun.COM */
1717978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
1727978SPeter.Dunlap@Sun.COM mutex_destroy(&ic->ic_state_mutex);
1737978SPeter.Dunlap@Sun.COM }
1747978SPeter.Dunlap@Sun.COM
1757978SPeter.Dunlap@Sun.COM void
idm_conn_event(idm_conn_t * ic,idm_conn_event_t event,uintptr_t event_info)1767978SPeter.Dunlap@Sun.COM idm_conn_event(idm_conn_t *ic, idm_conn_event_t event, uintptr_t event_info)
1777978SPeter.Dunlap@Sun.COM {
1787978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
1797978SPeter.Dunlap@Sun.COM idm_conn_event_locked(ic, event, event_info, CT_NONE);
1807978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
1817978SPeter.Dunlap@Sun.COM }
1827978SPeter.Dunlap@Sun.COM
1839162SPeter.Dunlap@Sun.COM
1847978SPeter.Dunlap@Sun.COM idm_status_t
idm_conn_reinstate_event(idm_conn_t * old_ic,idm_conn_t * new_ic)1857978SPeter.Dunlap@Sun.COM idm_conn_reinstate_event(idm_conn_t *old_ic, idm_conn_t *new_ic)
1867978SPeter.Dunlap@Sun.COM {
1877978SPeter.Dunlap@Sun.COM int result;
1887978SPeter.Dunlap@Sun.COM
1897978SPeter.Dunlap@Sun.COM mutex_enter(&old_ic->ic_state_mutex);
1907978SPeter.Dunlap@Sun.COM if (((old_ic->ic_conn_type == CONN_TYPE_INI) &&
1917978SPeter.Dunlap@Sun.COM (old_ic->ic_state != CS_S8_CLEANUP)) ||
1927978SPeter.Dunlap@Sun.COM ((old_ic->ic_conn_type == CONN_TYPE_TGT) &&
1937978SPeter.Dunlap@Sun.COM (old_ic->ic_state < CS_S5_LOGGED_IN))) {
1947978SPeter.Dunlap@Sun.COM result = IDM_STATUS_FAIL;
1957978SPeter.Dunlap@Sun.COM } else {
1967978SPeter.Dunlap@Sun.COM result = IDM_STATUS_SUCCESS;
1977978SPeter.Dunlap@Sun.COM new_ic->ic_reinstate_conn = old_ic;
1987978SPeter.Dunlap@Sun.COM idm_conn_event_locked(new_ic->ic_reinstate_conn,
1997978SPeter.Dunlap@Sun.COM CE_CONN_REINSTATE, (uintptr_t)new_ic, CT_NONE);
2007978SPeter.Dunlap@Sun.COM }
2017978SPeter.Dunlap@Sun.COM mutex_exit(&old_ic->ic_state_mutex);
2027978SPeter.Dunlap@Sun.COM
2037978SPeter.Dunlap@Sun.COM return (result);
2047978SPeter.Dunlap@Sun.COM }
2057978SPeter.Dunlap@Sun.COM
2067978SPeter.Dunlap@Sun.COM void
idm_conn_tx_pdu_event(idm_conn_t * ic,idm_conn_event_t event,uintptr_t event_info)2077978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(idm_conn_t *ic, idm_conn_event_t event,
2087978SPeter.Dunlap@Sun.COM uintptr_t event_info)
2097978SPeter.Dunlap@Sun.COM {
2107978SPeter.Dunlap@Sun.COM ASSERT(mutex_owned(&ic->ic_state_mutex));
2117978SPeter.Dunlap@Sun.COM ic->ic_pdu_events++;
2127978SPeter.Dunlap@Sun.COM idm_conn_event_locked(ic, event, event_info, CT_TX_PDU);
2137978SPeter.Dunlap@Sun.COM }
2147978SPeter.Dunlap@Sun.COM
2157978SPeter.Dunlap@Sun.COM void
idm_conn_rx_pdu_event(idm_conn_t * ic,idm_conn_event_t event,uintptr_t event_info)2167978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(idm_conn_t *ic, idm_conn_event_t event,
2177978SPeter.Dunlap@Sun.COM uintptr_t event_info)
2187978SPeter.Dunlap@Sun.COM {
2197978SPeter.Dunlap@Sun.COM ASSERT(mutex_owned(&ic->ic_state_mutex));
2207978SPeter.Dunlap@Sun.COM ic->ic_pdu_events++;
2217978SPeter.Dunlap@Sun.COM idm_conn_event_locked(ic, event, event_info, CT_RX_PDU);
2227978SPeter.Dunlap@Sun.COM }
2237978SPeter.Dunlap@Sun.COM
2249162SPeter.Dunlap@Sun.COM 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)2257978SPeter.Dunlap@Sun.COM idm_conn_event_locked(idm_conn_t *ic, idm_conn_event_t event,
2267978SPeter.Dunlap@Sun.COM uintptr_t event_info, idm_pdu_event_type_t pdu_event_type)
2277978SPeter.Dunlap@Sun.COM {
2287978SPeter.Dunlap@Sun.COM idm_conn_event_ctx_t *event_ctx;
2297978SPeter.Dunlap@Sun.COM
23011078SPeter.Cudhea@Sun.COM ASSERT(mutex_owned(&ic->ic_state_mutex));
23111078SPeter.Cudhea@Sun.COM
2327978SPeter.Dunlap@Sun.COM idm_sm_audit_event(&ic->ic_state_audit, SAS_IDM_CONN,
2337978SPeter.Dunlap@Sun.COM (int)ic->ic_state, (int)event, event_info);
2347978SPeter.Dunlap@Sun.COM
2357978SPeter.Dunlap@Sun.COM /*
2367978SPeter.Dunlap@Sun.COM * It's very difficult to prevent a few straggling events
2377978SPeter.Dunlap@Sun.COM * at the end. For example idm_sorx_thread will generate
2387978SPeter.Dunlap@Sun.COM * a CE_TRANSPORT_FAIL event when it exits. Rather than
2397978SPeter.Dunlap@Sun.COM * push complicated restrictions all over the code to
2407978SPeter.Dunlap@Sun.COM * prevent this we will simply drop the events (and in
2417978SPeter.Dunlap@Sun.COM * the case of PDU events release them appropriately)
2427978SPeter.Dunlap@Sun.COM * since they are irrelevant once we are in a terminal state.
2437978SPeter.Dunlap@Sun.COM * Of course those threads need to have appropriate holds on
2447978SPeter.Dunlap@Sun.COM * the connection otherwise it might disappear.
2457978SPeter.Dunlap@Sun.COM */
2467978SPeter.Dunlap@Sun.COM if ((ic->ic_state == CS_S9_INIT_ERROR) ||
2479373SPeter.Dunlap@Sun.COM (ic->ic_state == CS_S9A_REJECTED) ||
2487978SPeter.Dunlap@Sun.COM (ic->ic_state == CS_S11_COMPLETE)) {
2497978SPeter.Dunlap@Sun.COM if ((pdu_event_type == CT_TX_PDU) ||
2507978SPeter.Dunlap@Sun.COM (pdu_event_type == CT_RX_PDU)) {
2517978SPeter.Dunlap@Sun.COM ic->ic_pdu_events--;
2527978SPeter.Dunlap@Sun.COM idm_pdu_complete((idm_pdu_t *)event_info,
2537978SPeter.Dunlap@Sun.COM IDM_STATUS_SUCCESS);
2547978SPeter.Dunlap@Sun.COM }
2557978SPeter.Dunlap@Sun.COM IDM_SM_LOG(CE_NOTE, "*** Dropping event %s (%d) because of"
2567978SPeter.Dunlap@Sun.COM "state %s (%d)",
2577978SPeter.Dunlap@Sun.COM idm_ce_name[event], event,
2587978SPeter.Dunlap@Sun.COM idm_cs_name[ic->ic_state], ic->ic_state);
2597978SPeter.Dunlap@Sun.COM return;
2607978SPeter.Dunlap@Sun.COM }
2617978SPeter.Dunlap@Sun.COM
2627978SPeter.Dunlap@Sun.COM /*
2637978SPeter.Dunlap@Sun.COM * Normal event handling
2647978SPeter.Dunlap@Sun.COM */
2657978SPeter.Dunlap@Sun.COM idm_conn_hold(ic);
2667978SPeter.Dunlap@Sun.COM
2677978SPeter.Dunlap@Sun.COM event_ctx = kmem_zalloc(sizeof (*event_ctx), KM_SLEEP);
2687978SPeter.Dunlap@Sun.COM event_ctx->iec_ic = ic;
2697978SPeter.Dunlap@Sun.COM event_ctx->iec_event = event;
2707978SPeter.Dunlap@Sun.COM event_ctx->iec_info = event_info;
2717978SPeter.Dunlap@Sun.COM event_ctx->iec_pdu_event_type = pdu_event_type;
2727978SPeter.Dunlap@Sun.COM
2737978SPeter.Dunlap@Sun.COM (void) taskq_dispatch(ic->ic_state_taskq, &idm_conn_event_handler,
2747978SPeter.Dunlap@Sun.COM event_ctx, TQ_SLEEP);
2757978SPeter.Dunlap@Sun.COM }
2767978SPeter.Dunlap@Sun.COM
2777978SPeter.Dunlap@Sun.COM static void
idm_conn_event_handler(void * event_ctx_opaque)2787978SPeter.Dunlap@Sun.COM idm_conn_event_handler(void *event_ctx_opaque)
2797978SPeter.Dunlap@Sun.COM {
2807978SPeter.Dunlap@Sun.COM idm_conn_event_ctx_t *event_ctx = event_ctx_opaque;
2817978SPeter.Dunlap@Sun.COM idm_conn_t *ic = event_ctx->iec_ic;
2827978SPeter.Dunlap@Sun.COM idm_pdu_t *pdu = (idm_pdu_t *)event_ctx->iec_info;
2837978SPeter.Dunlap@Sun.COM idm_pdu_event_action_t action;
2847978SPeter.Dunlap@Sun.COM
2857978SPeter.Dunlap@Sun.COM IDM_SM_LOG(CE_NOTE, "idm_conn_event_handler: conn %p event %s(%d)",
2867978SPeter.Dunlap@Sun.COM (void *)ic, idm_ce_name[event_ctx->iec_event],
2877978SPeter.Dunlap@Sun.COM event_ctx->iec_event);
2887978SPeter.Dunlap@Sun.COM DTRACE_PROBE2(conn__event,
2899162SPeter.Dunlap@Sun.COM idm_conn_t *, ic, idm_conn_event_ctx_t *, event_ctx);
2907978SPeter.Dunlap@Sun.COM
2917978SPeter.Dunlap@Sun.COM /*
2927978SPeter.Dunlap@Sun.COM * Validate event
2937978SPeter.Dunlap@Sun.COM */
2947978SPeter.Dunlap@Sun.COM ASSERT(event_ctx->iec_event != CE_UNDEFINED);
2957978SPeter.Dunlap@Sun.COM ASSERT3U(event_ctx->iec_event, <, CE_MAX_EVENT);
2967978SPeter.Dunlap@Sun.COM
2977978SPeter.Dunlap@Sun.COM /*
2987978SPeter.Dunlap@Sun.COM * Validate current state
2997978SPeter.Dunlap@Sun.COM */
3007978SPeter.Dunlap@Sun.COM ASSERT(ic->ic_state != CS_S0_UNDEFINED);
3017978SPeter.Dunlap@Sun.COM ASSERT3U(ic->ic_state, <, CS_MAX_STATE);
3027978SPeter.Dunlap@Sun.COM
3037978SPeter.Dunlap@Sun.COM /*
3047978SPeter.Dunlap@Sun.COM * Validate PDU-related events against the current state. If a PDU
3057978SPeter.Dunlap@Sun.COM * is not allowed in the current state we change the event to a
3067978SPeter.Dunlap@Sun.COM * protocol error. This simplifies the state-specific event handlers.
3077978SPeter.Dunlap@Sun.COM * For example the CS_S2_XPT_WAIT state only needs to handle the
3087978SPeter.Dunlap@Sun.COM * CE_TX_PROTOCOL_ERROR and CE_RX_PROTOCOL_ERROR events since
3097978SPeter.Dunlap@Sun.COM * no PDU's can be transmitted or received in that state.
3107978SPeter.Dunlap@Sun.COM */
3119162SPeter.Dunlap@Sun.COM event_ctx->iec_pdu_forwarded = B_FALSE;
3127978SPeter.Dunlap@Sun.COM if (event_ctx->iec_pdu_event_type != CT_NONE) {
3137978SPeter.Dunlap@Sun.COM ASSERT(pdu != NULL);
3147978SPeter.Dunlap@Sun.COM action = idm_conn_sm_validate_pdu(ic, event_ctx, pdu);
3157978SPeter.Dunlap@Sun.COM
3167978SPeter.Dunlap@Sun.COM switch (action) {
3177978SPeter.Dunlap@Sun.COM case CA_TX_PROTOCOL_ERROR:
3187978SPeter.Dunlap@Sun.COM /*
3197978SPeter.Dunlap@Sun.COM * Change event and forward the PDU
3207978SPeter.Dunlap@Sun.COM */
3217978SPeter.Dunlap@Sun.COM event_ctx->iec_event = CE_TX_PROTOCOL_ERROR;
3227978SPeter.Dunlap@Sun.COM break;
3237978SPeter.Dunlap@Sun.COM case CA_RX_PROTOCOL_ERROR:
3247978SPeter.Dunlap@Sun.COM /*
3257978SPeter.Dunlap@Sun.COM * Change event and forward the PDU.
3267978SPeter.Dunlap@Sun.COM */
3277978SPeter.Dunlap@Sun.COM event_ctx->iec_event = CE_RX_PROTOCOL_ERROR;
3287978SPeter.Dunlap@Sun.COM break;
3297978SPeter.Dunlap@Sun.COM case CA_FORWARD:
3307978SPeter.Dunlap@Sun.COM /*
3317978SPeter.Dunlap@Sun.COM * Let the state-specific event handlers take
3327978SPeter.Dunlap@Sun.COM * care of it.
3337978SPeter.Dunlap@Sun.COM */
3347978SPeter.Dunlap@Sun.COM break;
3357978SPeter.Dunlap@Sun.COM case CA_DROP:
3367978SPeter.Dunlap@Sun.COM /*
3377978SPeter.Dunlap@Sun.COM * It never even happened
3387978SPeter.Dunlap@Sun.COM */
3397978SPeter.Dunlap@Sun.COM IDM_SM_LOG(CE_NOTE, "*** drop PDU %p", (void *) pdu);
3407978SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, IDM_STATUS_FAIL);
3417978SPeter.Dunlap@Sun.COM break;
3427978SPeter.Dunlap@Sun.COM default:
3437978SPeter.Dunlap@Sun.COM ASSERT(0);
3447978SPeter.Dunlap@Sun.COM break;
3457978SPeter.Dunlap@Sun.COM }
3467978SPeter.Dunlap@Sun.COM }
3477978SPeter.Dunlap@Sun.COM
3487978SPeter.Dunlap@Sun.COM switch (ic->ic_state) {
3497978SPeter.Dunlap@Sun.COM case CS_S1_FREE:
3507978SPeter.Dunlap@Sun.COM idm_state_s1_free(ic, event_ctx);
3517978SPeter.Dunlap@Sun.COM break;
3527978SPeter.Dunlap@Sun.COM case CS_S2_XPT_WAIT:
3537978SPeter.Dunlap@Sun.COM idm_state_s2_xpt_wait(ic, event_ctx);
3547978SPeter.Dunlap@Sun.COM break;
3557978SPeter.Dunlap@Sun.COM case CS_S3_XPT_UP:
3567978SPeter.Dunlap@Sun.COM idm_state_s3_xpt_up(ic, event_ctx);
3577978SPeter.Dunlap@Sun.COM break;
3587978SPeter.Dunlap@Sun.COM case CS_S4_IN_LOGIN:
3597978SPeter.Dunlap@Sun.COM idm_state_s4_in_login(ic, event_ctx);
3607978SPeter.Dunlap@Sun.COM break;
3617978SPeter.Dunlap@Sun.COM case CS_S5_LOGGED_IN:
3627978SPeter.Dunlap@Sun.COM idm_state_s5_logged_in(ic, event_ctx);
3637978SPeter.Dunlap@Sun.COM break;
3647978SPeter.Dunlap@Sun.COM case CS_S6_IN_LOGOUT:
3657978SPeter.Dunlap@Sun.COM idm_state_s6_in_logout(ic, event_ctx);
3667978SPeter.Dunlap@Sun.COM break;
3677978SPeter.Dunlap@Sun.COM case CS_S7_LOGOUT_REQ:
3687978SPeter.Dunlap@Sun.COM idm_state_s7_logout_req(ic, event_ctx);
3697978SPeter.Dunlap@Sun.COM break;
3707978SPeter.Dunlap@Sun.COM case CS_S8_CLEANUP:
3717978SPeter.Dunlap@Sun.COM idm_state_s8_cleanup(ic, event_ctx);
3727978SPeter.Dunlap@Sun.COM break;
3739373SPeter.Dunlap@Sun.COM case CS_S9A_REJECTED:
3749373SPeter.Dunlap@Sun.COM idm_state_s9a_rejected(ic, event_ctx);
3759373SPeter.Dunlap@Sun.COM break;
37611552SPeter.Cudhea@Sun.COM case CS_S9B_WAIT_SND_DONE:
37711552SPeter.Cudhea@Sun.COM idm_state_s9b_wait_snd_done(ic, event_ctx);
37811552SPeter.Cudhea@Sun.COM break;
3797978SPeter.Dunlap@Sun.COM case CS_S9_INIT_ERROR:
3807978SPeter.Dunlap@Sun.COM idm_state_s9_init_error(ic, event_ctx);
3817978SPeter.Dunlap@Sun.COM break;
3827978SPeter.Dunlap@Sun.COM case CS_S10_IN_CLEANUP:
3837978SPeter.Dunlap@Sun.COM idm_state_s10_in_cleanup(ic, event_ctx);
3847978SPeter.Dunlap@Sun.COM break;
3857978SPeter.Dunlap@Sun.COM case CS_S11_COMPLETE:
3867978SPeter.Dunlap@Sun.COM idm_state_s11_complete(ic, event_ctx);
3877978SPeter.Dunlap@Sun.COM break;
3887978SPeter.Dunlap@Sun.COM case CS_S12_ENABLE_DM:
3897978SPeter.Dunlap@Sun.COM idm_state_s12_enable_dm(ic, event_ctx);
3907978SPeter.Dunlap@Sun.COM break;
3917978SPeter.Dunlap@Sun.COM default:
3927978SPeter.Dunlap@Sun.COM ASSERT(0);
3937978SPeter.Dunlap@Sun.COM break;
3947978SPeter.Dunlap@Sun.COM }
3957978SPeter.Dunlap@Sun.COM
3967978SPeter.Dunlap@Sun.COM /*
3977978SPeter.Dunlap@Sun.COM * Now that we've updated the state machine, if this was
3987978SPeter.Dunlap@Sun.COM * a PDU-related event take the appropriate action on the PDU
3997978SPeter.Dunlap@Sun.COM * (transmit it, forward it to the clients RX callback, drop
4007978SPeter.Dunlap@Sun.COM * it, etc).
4017978SPeter.Dunlap@Sun.COM */
4027978SPeter.Dunlap@Sun.COM if (event_ctx->iec_pdu_event_type != CT_NONE) {
4037978SPeter.Dunlap@Sun.COM switch (action) {
4047978SPeter.Dunlap@Sun.COM case CA_TX_PROTOCOL_ERROR:
4057978SPeter.Dunlap@Sun.COM idm_pdu_tx_protocol_error(ic, pdu);
4067978SPeter.Dunlap@Sun.COM break;
4077978SPeter.Dunlap@Sun.COM case CA_RX_PROTOCOL_ERROR:
4087978SPeter.Dunlap@Sun.COM idm_pdu_rx_protocol_error(ic, pdu);
4097978SPeter.Dunlap@Sun.COM break;
4107978SPeter.Dunlap@Sun.COM case CA_FORWARD:
4119162SPeter.Dunlap@Sun.COM if (!event_ctx->iec_pdu_forwarded) {
4129162SPeter.Dunlap@Sun.COM if (event_ctx->iec_pdu_event_type ==
4139162SPeter.Dunlap@Sun.COM CT_RX_PDU) {
4149162SPeter.Dunlap@Sun.COM idm_pdu_rx_forward(ic, pdu);
4159162SPeter.Dunlap@Sun.COM } else {
4169162SPeter.Dunlap@Sun.COM idm_pdu_tx_forward(ic, pdu);
4179162SPeter.Dunlap@Sun.COM }
4187978SPeter.Dunlap@Sun.COM }
4197978SPeter.Dunlap@Sun.COM break;
4207978SPeter.Dunlap@Sun.COM default:
4217978SPeter.Dunlap@Sun.COM ASSERT(0);
4227978SPeter.Dunlap@Sun.COM break;
4237978SPeter.Dunlap@Sun.COM }
4247978SPeter.Dunlap@Sun.COM }
4257978SPeter.Dunlap@Sun.COM
4267978SPeter.Dunlap@Sun.COM /*
4277978SPeter.Dunlap@Sun.COM * Update outstanding PDU event count (see idm_pdu_tx for
4287978SPeter.Dunlap@Sun.COM * how this is used)
4297978SPeter.Dunlap@Sun.COM */
4307978SPeter.Dunlap@Sun.COM if ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ||
4317978SPeter.Dunlap@Sun.COM (event_ctx->iec_pdu_event_type == CT_RX_PDU)) {
4327978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
4337978SPeter.Dunlap@Sun.COM ic->ic_pdu_events--;
4347978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
4357978SPeter.Dunlap@Sun.COM }
4367978SPeter.Dunlap@Sun.COM
4377978SPeter.Dunlap@Sun.COM idm_conn_rele(ic);
4387978SPeter.Dunlap@Sun.COM kmem_free(event_ctx, sizeof (*event_ctx));
4397978SPeter.Dunlap@Sun.COM }
4407978SPeter.Dunlap@Sun.COM
4417978SPeter.Dunlap@Sun.COM static void
idm_state_s1_free(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)4427978SPeter.Dunlap@Sun.COM idm_state_s1_free(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
4437978SPeter.Dunlap@Sun.COM {
4447978SPeter.Dunlap@Sun.COM switch (event_ctx->iec_event) {
4457978SPeter.Dunlap@Sun.COM case CE_CONNECT_REQ:
4467978SPeter.Dunlap@Sun.COM /* T1 */
4477978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S2_XPT_WAIT, event_ctx);
4487978SPeter.Dunlap@Sun.COM break;
4497978SPeter.Dunlap@Sun.COM case CE_CONNECT_ACCEPT:
4507978SPeter.Dunlap@Sun.COM /* T3 */
4517978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S3_XPT_UP, event_ctx);
4527978SPeter.Dunlap@Sun.COM break;
4537978SPeter.Dunlap@Sun.COM case CE_TX_PROTOCOL_ERROR:
4547978SPeter.Dunlap@Sun.COM case CE_RX_PROTOCOL_ERROR:
4557978SPeter.Dunlap@Sun.COM /* This should never happen */
4567978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
4577978SPeter.Dunlap@Sun.COM break;
4587978SPeter.Dunlap@Sun.COM default:
4597978SPeter.Dunlap@Sun.COM ASSERT(0);
4607978SPeter.Dunlap@Sun.COM /*NOTREACHED*/
4617978SPeter.Dunlap@Sun.COM }
4627978SPeter.Dunlap@Sun.COM }
4637978SPeter.Dunlap@Sun.COM
4647978SPeter.Dunlap@Sun.COM
4657978SPeter.Dunlap@Sun.COM static void
idm_state_s2_xpt_wait(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)4667978SPeter.Dunlap@Sun.COM idm_state_s2_xpt_wait(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
4677978SPeter.Dunlap@Sun.COM {
4687978SPeter.Dunlap@Sun.COM switch (event_ctx->iec_event) {
4697978SPeter.Dunlap@Sun.COM case CE_CONNECT_SUCCESS:
4707978SPeter.Dunlap@Sun.COM /* T4 */
4717978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S4_IN_LOGIN, event_ctx);
4727978SPeter.Dunlap@Sun.COM break;
47310766SPeter.Cudhea@Sun.COM case CE_TRANSPORT_FAIL:
4747978SPeter.Dunlap@Sun.COM case CE_CONNECT_FAIL:
4757978SPeter.Dunlap@Sun.COM case CE_LOGOUT_OTHER_CONN_RCV:
4767978SPeter.Dunlap@Sun.COM case CE_TX_PROTOCOL_ERROR:
4777978SPeter.Dunlap@Sun.COM case CE_RX_PROTOCOL_ERROR:
4787978SPeter.Dunlap@Sun.COM /* T2 */
4797978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
4807978SPeter.Dunlap@Sun.COM break;
4817978SPeter.Dunlap@Sun.COM default:
4827978SPeter.Dunlap@Sun.COM ASSERT(0);
4837978SPeter.Dunlap@Sun.COM /*NOTREACHED*/
4847978SPeter.Dunlap@Sun.COM }
4857978SPeter.Dunlap@Sun.COM }
4867978SPeter.Dunlap@Sun.COM
4877978SPeter.Dunlap@Sun.COM
4887978SPeter.Dunlap@Sun.COM static void
idm_login_timeout(void * arg)4897978SPeter.Dunlap@Sun.COM idm_login_timeout(void *arg)
4907978SPeter.Dunlap@Sun.COM {
4917978SPeter.Dunlap@Sun.COM idm_conn_t *ic = arg;
4927978SPeter.Dunlap@Sun.COM
4937978SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_LOGIN_TIMEOUT, NULL);
4947978SPeter.Dunlap@Sun.COM }
4957978SPeter.Dunlap@Sun.COM
4967978SPeter.Dunlap@Sun.COM static void
idm_state_s3_xpt_up(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)4977978SPeter.Dunlap@Sun.COM idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
4987978SPeter.Dunlap@Sun.COM {
4997978SPeter.Dunlap@Sun.COM switch (event_ctx->iec_event) {
5007978SPeter.Dunlap@Sun.COM case CE_LOGIN_RCV:
5017978SPeter.Dunlap@Sun.COM /* T4 */
5027978SPeter.Dunlap@Sun.COM idm_initial_login_actions(ic, event_ctx);
5037978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S4_IN_LOGIN, event_ctx);
5047978SPeter.Dunlap@Sun.COM break;
5057978SPeter.Dunlap@Sun.COM case CE_LOGIN_TIMEOUT:
5067978SPeter.Dunlap@Sun.COM /*
5077978SPeter.Dunlap@Sun.COM * Don't need to cancel login timer since the timer is
5087978SPeter.Dunlap@Sun.COM * presumed to be the source of this event.
5097978SPeter.Dunlap@Sun.COM */
5107978SPeter.Dunlap@Sun.COM (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
5117978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
5127978SPeter.Dunlap@Sun.COM break;
5137978SPeter.Dunlap@Sun.COM case CE_CONNECT_REJECT:
5149373SPeter.Dunlap@Sun.COM /*
5159373SPeter.Dunlap@Sun.COM * Iscsit doesn't want to hear from us again in this case.
5169373SPeter.Dunlap@Sun.COM * Since it rejected the connection it doesn't have a
5179373SPeter.Dunlap@Sun.COM * connection context to handle additional notifications.
5189373SPeter.Dunlap@Sun.COM * IDM needs to just clean things up on its own.
5199373SPeter.Dunlap@Sun.COM */
5209373SPeter.Dunlap@Sun.COM (void) untimeout(ic->ic_state_timeout);
5219373SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S9A_REJECTED, event_ctx);
5229373SPeter.Dunlap@Sun.COM break;
5237978SPeter.Dunlap@Sun.COM case CE_CONNECT_FAIL:
5247978SPeter.Dunlap@Sun.COM case CE_TRANSPORT_FAIL:
5257978SPeter.Dunlap@Sun.COM case CE_LOGOUT_OTHER_CONN_SND:
5267978SPeter.Dunlap@Sun.COM /* T6 */
5277978SPeter.Dunlap@Sun.COM (void) untimeout(ic->ic_state_timeout);
5287978SPeter.Dunlap@Sun.COM (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
5297978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
5307978SPeter.Dunlap@Sun.COM break;
5317978SPeter.Dunlap@Sun.COM case CE_TX_PROTOCOL_ERROR:
5327978SPeter.Dunlap@Sun.COM case CE_RX_PROTOCOL_ERROR:
5337978SPeter.Dunlap@Sun.COM /* Don't care */
5347978SPeter.Dunlap@Sun.COM break;
5357978SPeter.Dunlap@Sun.COM default:
5367978SPeter.Dunlap@Sun.COM ASSERT(0);
5377978SPeter.Dunlap@Sun.COM /*NOTREACHED*/
5387978SPeter.Dunlap@Sun.COM }
5397978SPeter.Dunlap@Sun.COM }
5407978SPeter.Dunlap@Sun.COM
5417978SPeter.Dunlap@Sun.COM static void
idm_state_s4_in_login(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)5427978SPeter.Dunlap@Sun.COM idm_state_s4_in_login(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
5437978SPeter.Dunlap@Sun.COM {
5447978SPeter.Dunlap@Sun.COM idm_pdu_t *pdu;
5457978SPeter.Dunlap@Sun.COM
5467978SPeter.Dunlap@Sun.COM /*
5477978SPeter.Dunlap@Sun.COM * Login timer should no longer be active after leaving this
5487978SPeter.Dunlap@Sun.COM * state.
5497978SPeter.Dunlap@Sun.COM */
5507978SPeter.Dunlap@Sun.COM switch (event_ctx->iec_event) {
5517978SPeter.Dunlap@Sun.COM case CE_LOGIN_SUCCESS_RCV:
5527978SPeter.Dunlap@Sun.COM case CE_LOGIN_SUCCESS_SND:
55311552SPeter.Cudhea@Sun.COM ASSERT(ic->ic_client_callback == NULL);
55411552SPeter.Cudhea@Sun.COM
5557978SPeter.Dunlap@Sun.COM (void) untimeout(ic->ic_state_timeout);
5567978SPeter.Dunlap@Sun.COM idm_login_success_actions(ic, event_ctx);
5577978SPeter.Dunlap@Sun.COM if (ic->ic_rdma_extensions) {
5587978SPeter.Dunlap@Sun.COM /* T19 */
5597978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S12_ENABLE_DM, event_ctx);
5607978SPeter.Dunlap@Sun.COM } else {
5617978SPeter.Dunlap@Sun.COM /* T5 */
5627978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S5_LOGGED_IN, event_ctx);
5637978SPeter.Dunlap@Sun.COM }
5647978SPeter.Dunlap@Sun.COM break;
5657978SPeter.Dunlap@Sun.COM case CE_LOGIN_TIMEOUT:
5667978SPeter.Dunlap@Sun.COM /* T7 */
5677978SPeter.Dunlap@Sun.COM (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
5687978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
5697978SPeter.Dunlap@Sun.COM break;
5707978SPeter.Dunlap@Sun.COM case CE_LOGIN_FAIL_SND:
5717978SPeter.Dunlap@Sun.COM /*
5727978SPeter.Dunlap@Sun.COM * Allow the logout response pdu to be sent and defer
57311552SPeter.Cudhea@Sun.COM * the state machine cleanup until the completion callback.
5747978SPeter.Dunlap@Sun.COM * Only 1 level or callback interposition is allowed.
5757978SPeter.Dunlap@Sun.COM */
5767978SPeter.Dunlap@Sun.COM (void) untimeout(ic->ic_state_timeout);
5777978SPeter.Dunlap@Sun.COM pdu = (idm_pdu_t *)event_ctx->iec_info;
5787978SPeter.Dunlap@Sun.COM ASSERT(ic->ic_client_callback == NULL);
5797978SPeter.Dunlap@Sun.COM ic->ic_client_callback = pdu->isp_callback;
5807978SPeter.Dunlap@Sun.COM pdu->isp_callback =
58111552SPeter.Cudhea@Sun.COM idm_state_s9b_wait_snd_done_cb;
58211552SPeter.Cudhea@Sun.COM idm_update_state(ic, CS_S9B_WAIT_SND_DONE,
58311552SPeter.Cudhea@Sun.COM event_ctx);
5847978SPeter.Dunlap@Sun.COM break;
5857978SPeter.Dunlap@Sun.COM case CE_LOGIN_FAIL_RCV:
58611552SPeter.Cudhea@Sun.COM ASSERT(ic->ic_client_callback == NULL);
5879162SPeter.Dunlap@Sun.COM /*
5889162SPeter.Dunlap@Sun.COM * Need to deliver this PDU to the initiator now because after
5899162SPeter.Dunlap@Sun.COM * we update the state to CS_S9_INIT_ERROR the initiator will
5909162SPeter.Dunlap@Sun.COM * no longer be in an appropriate state.
5919162SPeter.Dunlap@Sun.COM */
5929162SPeter.Dunlap@Sun.COM event_ctx->iec_pdu_forwarded = B_TRUE;
5939162SPeter.Dunlap@Sun.COM pdu = (idm_pdu_t *)event_ctx->iec_info;
5949162SPeter.Dunlap@Sun.COM idm_pdu_rx_forward(ic, pdu);
5959162SPeter.Dunlap@Sun.COM /* FALLTHROUGH */
5967978SPeter.Dunlap@Sun.COM case CE_TRANSPORT_FAIL:
5977978SPeter.Dunlap@Sun.COM case CE_LOGOUT_OTHER_CONN_SND:
5987978SPeter.Dunlap@Sun.COM case CE_LOGOUT_OTHER_CONN_RCV:
5997978SPeter.Dunlap@Sun.COM /* T7 */
6007978SPeter.Dunlap@Sun.COM (void) untimeout(ic->ic_state_timeout);
6017978SPeter.Dunlap@Sun.COM (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
6027978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
6037978SPeter.Dunlap@Sun.COM break;
604*12579SPriya.Krishnan@Sun.COM case CE_LOGOUT_SESSION_SUCCESS:
605*12579SPriya.Krishnan@Sun.COM /*
606*12579SPriya.Krishnan@Sun.COM * T8
607*12579SPriya.Krishnan@Sun.COM * A session reinstatement request can be received while a
608*12579SPriya.Krishnan@Sun.COM * session is active and a login is in process. The iSCSI
609*12579SPriya.Krishnan@Sun.COM * connections are shut down by a CE_LOGOUT_SESSION_SUCCESS
610*12579SPriya.Krishnan@Sun.COM * event sent from the session to the IDM layer.
611*12579SPriya.Krishnan@Sun.COM */
612*12579SPriya.Krishnan@Sun.COM if (IDM_CONN_ISTGT(ic)) {
613*12579SPriya.Krishnan@Sun.COM ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
614*12579SPriya.Krishnan@Sun.COM } else {
615*12579SPriya.Krishnan@Sun.COM ic->ic_transport_ops->it_ini_conn_disconnect(ic);
616*12579SPriya.Krishnan@Sun.COM }
617*12579SPriya.Krishnan@Sun.COM idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
618*12579SPriya.Krishnan@Sun.COM break;
619*12579SPriya.Krishnan@Sun.COM
6207978SPeter.Dunlap@Sun.COM case CE_LOGIN_SND:
62111552SPeter.Cudhea@Sun.COM ASSERT(ic->ic_client_callback == NULL);
6227978SPeter.Dunlap@Sun.COM /*
6237978SPeter.Dunlap@Sun.COM * Initiator connections will see initial login PDU
6247978SPeter.Dunlap@Sun.COM * in this state. Target connections see initial
6257978SPeter.Dunlap@Sun.COM * login PDU in "xpt up" state.
6267978SPeter.Dunlap@Sun.COM */
6277978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
6287978SPeter.Dunlap@Sun.COM if (!(ic->ic_state_flags & CF_INITIAL_LOGIN)) {
6297978SPeter.Dunlap@Sun.COM idm_initial_login_actions(ic, event_ctx);
6307978SPeter.Dunlap@Sun.COM }
6317978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
6327978SPeter.Dunlap@Sun.COM break;
6337978SPeter.Dunlap@Sun.COM case CE_MISC_TX:
6347978SPeter.Dunlap@Sun.COM case CE_MISC_RX:
6357978SPeter.Dunlap@Sun.COM case CE_LOGIN_RCV:
6367978SPeter.Dunlap@Sun.COM case CE_TX_PROTOCOL_ERROR:
6377978SPeter.Dunlap@Sun.COM case CE_RX_PROTOCOL_ERROR:
6387978SPeter.Dunlap@Sun.COM /* Don't care */
6397978SPeter.Dunlap@Sun.COM break;
6407978SPeter.Dunlap@Sun.COM default:
6417978SPeter.Dunlap@Sun.COM ASSERT(0);
6427978SPeter.Dunlap@Sun.COM /*NOTREACHED*/
6437978SPeter.Dunlap@Sun.COM }
6447978SPeter.Dunlap@Sun.COM }
6457978SPeter.Dunlap@Sun.COM
6467978SPeter.Dunlap@Sun.COM
6477978SPeter.Dunlap@Sun.COM static void
idm_state_s5_logged_in(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)6487978SPeter.Dunlap@Sun.COM idm_state_s5_logged_in(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
6497978SPeter.Dunlap@Sun.COM {
6507978SPeter.Dunlap@Sun.COM switch (event_ctx->iec_event) {
65112372SPriya.Krishnan@Sun.COM case CE_MISC_RX:
65212372SPriya.Krishnan@Sun.COM /* MC/S: when removing the non-leading connection */
6537978SPeter.Dunlap@Sun.COM case CE_LOGOUT_THIS_CONN_RCV:
6547978SPeter.Dunlap@Sun.COM case CE_LOGOUT_THIS_CONN_SND:
6557978SPeter.Dunlap@Sun.COM case CE_LOGOUT_OTHER_CONN_RCV:
6567978SPeter.Dunlap@Sun.COM case CE_LOGOUT_OTHER_CONN_SND:
6577978SPeter.Dunlap@Sun.COM /* T9 */
6587978SPeter.Dunlap@Sun.COM idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */
6597978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
6607978SPeter.Dunlap@Sun.COM break;
6617978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SESSION_RCV:
6627978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SESSION_SND:
6637978SPeter.Dunlap@Sun.COM /* T9 */
6647978SPeter.Dunlap@Sun.COM idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
6657978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
6667978SPeter.Dunlap@Sun.COM break;
6677978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SESSION_SUCCESS:
6687978SPeter.Dunlap@Sun.COM /* T8 */
6697978SPeter.Dunlap@Sun.COM idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
6707978SPeter.Dunlap@Sun.COM
6717978SPeter.Dunlap@Sun.COM /* Close connection */
6727978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic)) {
6737978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
6747978SPeter.Dunlap@Sun.COM } else {
6757978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_ini_conn_disconnect(ic);
6767978SPeter.Dunlap@Sun.COM }
6777978SPeter.Dunlap@Sun.COM
6787978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
6797978SPeter.Dunlap@Sun.COM break;
6807978SPeter.Dunlap@Sun.COM case CE_ASYNC_LOGOUT_RCV:
6817978SPeter.Dunlap@Sun.COM case CE_ASYNC_LOGOUT_SND:
6827978SPeter.Dunlap@Sun.COM /* T11 */
6837978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S7_LOGOUT_REQ, event_ctx);
6847978SPeter.Dunlap@Sun.COM break;
6857978SPeter.Dunlap@Sun.COM case CE_TRANSPORT_FAIL:
6867978SPeter.Dunlap@Sun.COM case CE_ASYNC_DROP_CONN_RCV:
6877978SPeter.Dunlap@Sun.COM case CE_ASYNC_DROP_CONN_SND:
6887978SPeter.Dunlap@Sun.COM case CE_ASYNC_DROP_ALL_CONN_RCV:
6897978SPeter.Dunlap@Sun.COM case CE_ASYNC_DROP_ALL_CONN_SND:
6907978SPeter.Dunlap@Sun.COM /* T15 */
6917978SPeter.Dunlap@Sun.COM idm_ffp_disable(ic, FD_CONN_FAIL); /* Implicit logout */
6927978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
6937978SPeter.Dunlap@Sun.COM break;
6947978SPeter.Dunlap@Sun.COM case CE_MISC_TX:
6957978SPeter.Dunlap@Sun.COM case CE_TX_PROTOCOL_ERROR:
6967978SPeter.Dunlap@Sun.COM case CE_RX_PROTOCOL_ERROR:
69711078SPeter.Cudhea@Sun.COM case CE_LOGIN_TIMEOUT:
6987978SPeter.Dunlap@Sun.COM /* Don't care */
6997978SPeter.Dunlap@Sun.COM break;
7007978SPeter.Dunlap@Sun.COM default:
7017978SPeter.Dunlap@Sun.COM ASSERT(0);
7027978SPeter.Dunlap@Sun.COM }
7037978SPeter.Dunlap@Sun.COM }
7047978SPeter.Dunlap@Sun.COM
7057978SPeter.Dunlap@Sun.COM static void
idm_state_s6_in_logout_success_snd_done(idm_pdu_t * pdu,idm_status_t status)7067978SPeter.Dunlap@Sun.COM idm_state_s6_in_logout_success_snd_done(idm_pdu_t *pdu, idm_status_t status)
7077978SPeter.Dunlap@Sun.COM {
7087978SPeter.Dunlap@Sun.COM idm_conn_t *ic = pdu->isp_ic;
7097978SPeter.Dunlap@Sun.COM
7107978SPeter.Dunlap@Sun.COM /*
7117978SPeter.Dunlap@Sun.COM * This pdu callback can be invoked by the tx thread,
7127978SPeter.Dunlap@Sun.COM * so run the disconnect code from another thread.
7137978SPeter.Dunlap@Sun.COM */
7147978SPeter.Dunlap@Sun.COM pdu->isp_status = status;
7157978SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_LOGOUT_SUCCESS_SND_DONE, (uintptr_t)pdu);
7167978SPeter.Dunlap@Sun.COM }
7177978SPeter.Dunlap@Sun.COM
7187978SPeter.Dunlap@Sun.COM static void
idm_state_s6_in_logout_fail_snd_done(idm_pdu_t * pdu,idm_status_t status)7197978SPeter.Dunlap@Sun.COM idm_state_s6_in_logout_fail_snd_done(idm_pdu_t *pdu, idm_status_t status)
7207978SPeter.Dunlap@Sun.COM {
7217978SPeter.Dunlap@Sun.COM idm_conn_t *ic = pdu->isp_ic;
7227978SPeter.Dunlap@Sun.COM
7237978SPeter.Dunlap@Sun.COM /*
7247978SPeter.Dunlap@Sun.COM * This pdu callback can be invoked by the tx thread,
7257978SPeter.Dunlap@Sun.COM * so run the disconnect code from another thread.
7267978SPeter.Dunlap@Sun.COM */
7277978SPeter.Dunlap@Sun.COM pdu->isp_status = status;
7287978SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_LOGOUT_FAIL_SND_DONE, (uintptr_t)pdu);
7297978SPeter.Dunlap@Sun.COM }
7307978SPeter.Dunlap@Sun.COM
7317978SPeter.Dunlap@Sun.COM static void
idm_state_s6_in_logout(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)7327978SPeter.Dunlap@Sun.COM idm_state_s6_in_logout(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
7337978SPeter.Dunlap@Sun.COM {
7347978SPeter.Dunlap@Sun.COM idm_pdu_t *pdu;
7357978SPeter.Dunlap@Sun.COM
7367978SPeter.Dunlap@Sun.COM switch (event_ctx->iec_event) {
7377978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SUCCESS_SND_DONE:
7387978SPeter.Dunlap@Sun.COM pdu = (idm_pdu_t *)event_ctx->iec_info;
7397978SPeter.Dunlap@Sun.COM
7407978SPeter.Dunlap@Sun.COM /* Close connection (if it's not already closed) */
7417978SPeter.Dunlap@Sun.COM ASSERT(IDM_CONN_ISTGT(ic));
7427978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
7437978SPeter.Dunlap@Sun.COM
7447978SPeter.Dunlap@Sun.COM /* restore client callback */
7457978SPeter.Dunlap@Sun.COM pdu->isp_callback = ic->ic_client_callback;
7467978SPeter.Dunlap@Sun.COM ic->ic_client_callback = NULL;
7477978SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, pdu->isp_status);
7487978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
7497978SPeter.Dunlap@Sun.COM break;
7507978SPeter.Dunlap@Sun.COM case CE_LOGOUT_FAIL_SND_DONE:
7517978SPeter.Dunlap@Sun.COM pdu = (idm_pdu_t *)event_ctx->iec_info;
7527978SPeter.Dunlap@Sun.COM /* restore client callback */
7537978SPeter.Dunlap@Sun.COM pdu->isp_callback = ic->ic_client_callback;
7547978SPeter.Dunlap@Sun.COM ic->ic_client_callback = NULL;
7557978SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, pdu->isp_status);
7567978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
7577978SPeter.Dunlap@Sun.COM break;
7587978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SUCCESS_SND:
7597978SPeter.Dunlap@Sun.COM case CE_LOGOUT_FAIL_SND:
7607978SPeter.Dunlap@Sun.COM /*
7617978SPeter.Dunlap@Sun.COM * Allow the logout response pdu to be sent and defer
7627978SPeter.Dunlap@Sun.COM * the state machine update until the completion callback.
7637978SPeter.Dunlap@Sun.COM * Only 1 level or callback interposition is allowed.
7647978SPeter.Dunlap@Sun.COM */
7657978SPeter.Dunlap@Sun.COM pdu = (idm_pdu_t *)event_ctx->iec_info;
7667978SPeter.Dunlap@Sun.COM ASSERT(ic->ic_client_callback == NULL);
7677978SPeter.Dunlap@Sun.COM ic->ic_client_callback = pdu->isp_callback;
7687978SPeter.Dunlap@Sun.COM if (event_ctx->iec_event == CE_LOGOUT_SUCCESS_SND) {
7697978SPeter.Dunlap@Sun.COM pdu->isp_callback =
7707978SPeter.Dunlap@Sun.COM idm_state_s6_in_logout_success_snd_done;
7717978SPeter.Dunlap@Sun.COM } else {
7727978SPeter.Dunlap@Sun.COM pdu->isp_callback =
7737978SPeter.Dunlap@Sun.COM idm_state_s6_in_logout_fail_snd_done;
7747978SPeter.Dunlap@Sun.COM }
7757978SPeter.Dunlap@Sun.COM break;
7767978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SUCCESS_RCV:
7779162SPeter.Dunlap@Sun.COM /*
7789162SPeter.Dunlap@Sun.COM * Need to deliver this PDU to the initiator now because after
7799162SPeter.Dunlap@Sun.COM * we update the state to CS_S11_COMPLETE the initiator will
7809162SPeter.Dunlap@Sun.COM * no longer be in an appropriate state.
7819162SPeter.Dunlap@Sun.COM */
7829162SPeter.Dunlap@Sun.COM event_ctx->iec_pdu_forwarded = B_TRUE;
7839162SPeter.Dunlap@Sun.COM pdu = (idm_pdu_t *)event_ctx->iec_info;
7849162SPeter.Dunlap@Sun.COM idm_pdu_rx_forward(ic, pdu);
7859162SPeter.Dunlap@Sun.COM /* FALLTHROUGH */
7867978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SESSION_SUCCESS:
7877978SPeter.Dunlap@Sun.COM /* T13 */
7887978SPeter.Dunlap@Sun.COM
7897978SPeter.Dunlap@Sun.COM /* Close connection (if it's not already closed) */
7907978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic)) {
7917978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
7927978SPeter.Dunlap@Sun.COM } else {
7937978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_ini_conn_disconnect(ic);
7947978SPeter.Dunlap@Sun.COM }
7957978SPeter.Dunlap@Sun.COM
7967978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
7977978SPeter.Dunlap@Sun.COM break;
7987978SPeter.Dunlap@Sun.COM case CE_ASYNC_LOGOUT_RCV:
7997978SPeter.Dunlap@Sun.COM /* T14 Do nothing */
8007978SPeter.Dunlap@Sun.COM break;
8017978SPeter.Dunlap@Sun.COM case CE_TRANSPORT_FAIL:
8027978SPeter.Dunlap@Sun.COM case CE_ASYNC_DROP_CONN_RCV:
8037978SPeter.Dunlap@Sun.COM case CE_ASYNC_DROP_CONN_SND:
8047978SPeter.Dunlap@Sun.COM case CE_ASYNC_DROP_ALL_CONN_RCV:
8057978SPeter.Dunlap@Sun.COM case CE_ASYNC_DROP_ALL_CONN_SND:
8067978SPeter.Dunlap@Sun.COM case CE_LOGOUT_FAIL_RCV:
8077978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
8087978SPeter.Dunlap@Sun.COM break;
8097978SPeter.Dunlap@Sun.COM case CE_TX_PROTOCOL_ERROR:
8107978SPeter.Dunlap@Sun.COM case CE_RX_PROTOCOL_ERROR:
8117978SPeter.Dunlap@Sun.COM case CE_MISC_TX:
8127978SPeter.Dunlap@Sun.COM case CE_MISC_RX:
81311078SPeter.Cudhea@Sun.COM case CE_LOGIN_TIMEOUT:
8147978SPeter.Dunlap@Sun.COM /* Don't care */
8157978SPeter.Dunlap@Sun.COM break;
8167978SPeter.Dunlap@Sun.COM default:
8177978SPeter.Dunlap@Sun.COM ASSERT(0);
8187978SPeter.Dunlap@Sun.COM }
8197978SPeter.Dunlap@Sun.COM }
8207978SPeter.Dunlap@Sun.COM
8217978SPeter.Dunlap@Sun.COM
8227978SPeter.Dunlap@Sun.COM static void
idm_logout_req_timeout(void * arg)8237978SPeter.Dunlap@Sun.COM idm_logout_req_timeout(void *arg)
8247978SPeter.Dunlap@Sun.COM {
8257978SPeter.Dunlap@Sun.COM idm_conn_t *ic = arg;
8267978SPeter.Dunlap@Sun.COM
8277978SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_LOGOUT_TIMEOUT, NULL);
8287978SPeter.Dunlap@Sun.COM }
8297978SPeter.Dunlap@Sun.COM
8307978SPeter.Dunlap@Sun.COM static void
idm_state_s7_logout_req(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)8317978SPeter.Dunlap@Sun.COM idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
8327978SPeter.Dunlap@Sun.COM {
8337978SPeter.Dunlap@Sun.COM /* Must cancel logout timer before leaving this state */
8347978SPeter.Dunlap@Sun.COM switch (event_ctx->iec_event) {
8357978SPeter.Dunlap@Sun.COM case CE_LOGOUT_THIS_CONN_RCV:
8367978SPeter.Dunlap@Sun.COM case CE_LOGOUT_THIS_CONN_SND:
8377978SPeter.Dunlap@Sun.COM case CE_LOGOUT_OTHER_CONN_RCV:
8387978SPeter.Dunlap@Sun.COM case CE_LOGOUT_OTHER_CONN_SND:
8397978SPeter.Dunlap@Sun.COM /* T10 */
8407978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic)) {
8417978SPeter.Dunlap@Sun.COM (void) untimeout(ic->ic_state_timeout);
8427978SPeter.Dunlap@Sun.COM }
8437978SPeter.Dunlap@Sun.COM idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */
8447978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
8457978SPeter.Dunlap@Sun.COM break;
8467978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SESSION_RCV:
8477978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SESSION_SND:
8487978SPeter.Dunlap@Sun.COM /* T10 */
8497978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic)) {
8507978SPeter.Dunlap@Sun.COM (void) untimeout(ic->ic_state_timeout);
8517978SPeter.Dunlap@Sun.COM }
8527978SPeter.Dunlap@Sun.COM idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
8537978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
8547978SPeter.Dunlap@Sun.COM break;
8557978SPeter.Dunlap@Sun.COM case CE_ASYNC_LOGOUT_RCV:
8567978SPeter.Dunlap@Sun.COM case CE_ASYNC_LOGOUT_SND:
8577978SPeter.Dunlap@Sun.COM /* T12 Do nothing */
8587978SPeter.Dunlap@Sun.COM break;
8597978SPeter.Dunlap@Sun.COM case CE_TRANSPORT_FAIL:
8607978SPeter.Dunlap@Sun.COM case CE_ASYNC_DROP_CONN_RCV:
8617978SPeter.Dunlap@Sun.COM case CE_ASYNC_DROP_CONN_SND:
8627978SPeter.Dunlap@Sun.COM case CE_ASYNC_DROP_ALL_CONN_RCV:
8637978SPeter.Dunlap@Sun.COM case CE_ASYNC_DROP_ALL_CONN_SND:
8647978SPeter.Dunlap@Sun.COM /* T16 */
8657978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic)) {
8667978SPeter.Dunlap@Sun.COM (void) untimeout(ic->ic_state_timeout);
8677978SPeter.Dunlap@Sun.COM }
8687978SPeter.Dunlap@Sun.COM /* FALLTHROUGH */
8697978SPeter.Dunlap@Sun.COM case CE_LOGOUT_TIMEOUT:
8707978SPeter.Dunlap@Sun.COM idm_ffp_disable(ic, FD_CONN_FAIL); /* Implicit logout */
8717978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
8727978SPeter.Dunlap@Sun.COM break;
8737978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SESSION_SUCCESS:
8747978SPeter.Dunlap@Sun.COM /* T18 */
8757978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic)) {
8767978SPeter.Dunlap@Sun.COM (void) untimeout(ic->ic_state_timeout);
8777978SPeter.Dunlap@Sun.COM }
8787978SPeter.Dunlap@Sun.COM idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
8797978SPeter.Dunlap@Sun.COM
8807978SPeter.Dunlap@Sun.COM /* Close connection (if it's not already closed) */
8817978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic)) {
8827978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
8837978SPeter.Dunlap@Sun.COM } else {
8847978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_ini_conn_disconnect(ic);
8857978SPeter.Dunlap@Sun.COM }
8867978SPeter.Dunlap@Sun.COM
8877978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
8887978SPeter.Dunlap@Sun.COM break;
8897978SPeter.Dunlap@Sun.COM case CE_TX_PROTOCOL_ERROR:
8907978SPeter.Dunlap@Sun.COM case CE_RX_PROTOCOL_ERROR:
8917978SPeter.Dunlap@Sun.COM case CE_MISC_TX:
8927978SPeter.Dunlap@Sun.COM case CE_MISC_RX:
89311078SPeter.Cudhea@Sun.COM case CE_LOGIN_TIMEOUT:
8947978SPeter.Dunlap@Sun.COM /* Don't care */
8957978SPeter.Dunlap@Sun.COM break;
8967978SPeter.Dunlap@Sun.COM default:
8977978SPeter.Dunlap@Sun.COM ASSERT(0);
8987978SPeter.Dunlap@Sun.COM }
8997978SPeter.Dunlap@Sun.COM }
9007978SPeter.Dunlap@Sun.COM
9017978SPeter.Dunlap@Sun.COM
9027978SPeter.Dunlap@Sun.COM static void
idm_cleanup_timeout(void * arg)9037978SPeter.Dunlap@Sun.COM idm_cleanup_timeout(void *arg)
9047978SPeter.Dunlap@Sun.COM {
9057978SPeter.Dunlap@Sun.COM idm_conn_t *ic = arg;
9067978SPeter.Dunlap@Sun.COM
9077978SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_CLEANUP_TIMEOUT, NULL);
9087978SPeter.Dunlap@Sun.COM }
9097978SPeter.Dunlap@Sun.COM
9107978SPeter.Dunlap@Sun.COM static void
idm_state_s8_cleanup(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)9117978SPeter.Dunlap@Sun.COM idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
9127978SPeter.Dunlap@Sun.COM {
9137978SPeter.Dunlap@Sun.COM idm_pdu_t *pdu;
9147978SPeter.Dunlap@Sun.COM
9157978SPeter.Dunlap@Sun.COM /*
9167978SPeter.Dunlap@Sun.COM * Need to cancel the cleanup timeout before leaving this state
9177978SPeter.Dunlap@Sun.COM * if it hasn't already fired.
9187978SPeter.Dunlap@Sun.COM */
9197978SPeter.Dunlap@Sun.COM switch (event_ctx->iec_event) {
9207978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SUCCESS_RCV:
9217978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SUCCESS_SND:
9227978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SESSION_SUCCESS:
9237978SPeter.Dunlap@Sun.COM (void) untimeout(ic->ic_state_timeout);
9247978SPeter.Dunlap@Sun.COM /*FALLTHROUGH*/
9257978SPeter.Dunlap@Sun.COM case CE_CLEANUP_TIMEOUT:
9267978SPeter.Dunlap@Sun.COM /* M1 */
9277978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
9287978SPeter.Dunlap@Sun.COM break;
9297978SPeter.Dunlap@Sun.COM case CE_LOGOUT_OTHER_CONN_RCV:
9307978SPeter.Dunlap@Sun.COM case CE_LOGOUT_OTHER_CONN_SND:
9317978SPeter.Dunlap@Sun.COM /* M2 */
9327978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S10_IN_CLEANUP, event_ctx);
9337978SPeter.Dunlap@Sun.COM break;
9347978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SUCCESS_SND_DONE:
9357978SPeter.Dunlap@Sun.COM case CE_LOGOUT_FAIL_SND_DONE:
9367978SPeter.Dunlap@Sun.COM pdu = (idm_pdu_t *)event_ctx->iec_info;
9377978SPeter.Dunlap@Sun.COM /* restore client callback */
9387978SPeter.Dunlap@Sun.COM pdu->isp_callback = ic->ic_client_callback;
9397978SPeter.Dunlap@Sun.COM ic->ic_client_callback = NULL;
9407978SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, pdu->isp_status);
9417978SPeter.Dunlap@Sun.COM break;
9427978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SESSION_RCV:
9437978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SESSION_SND:
9447978SPeter.Dunlap@Sun.COM case CE_TX_PROTOCOL_ERROR:
9457978SPeter.Dunlap@Sun.COM case CE_RX_PROTOCOL_ERROR:
9467978SPeter.Dunlap@Sun.COM case CE_MISC_TX:
9477978SPeter.Dunlap@Sun.COM case CE_MISC_RX:
9487978SPeter.Dunlap@Sun.COM case CE_TRANSPORT_FAIL:
94911078SPeter.Cudhea@Sun.COM case CE_LOGIN_TIMEOUT:
9507978SPeter.Dunlap@Sun.COM case CE_LOGOUT_TIMEOUT:
9517978SPeter.Dunlap@Sun.COM /* Don't care */
9527978SPeter.Dunlap@Sun.COM break;
9537978SPeter.Dunlap@Sun.COM default:
9547978SPeter.Dunlap@Sun.COM ASSERT(0);
9557978SPeter.Dunlap@Sun.COM }
9567978SPeter.Dunlap@Sun.COM }
9577978SPeter.Dunlap@Sun.COM
9587978SPeter.Dunlap@Sun.COM /* ARGSUSED */
9597978SPeter.Dunlap@Sun.COM static void
idm_state_s9_init_error(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)9607978SPeter.Dunlap@Sun.COM idm_state_s9_init_error(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
9617978SPeter.Dunlap@Sun.COM {
96211552SPeter.Cudhea@Sun.COM /* All events ignored in this state */
9637978SPeter.Dunlap@Sun.COM }
9647978SPeter.Dunlap@Sun.COM
9659373SPeter.Dunlap@Sun.COM /* ARGSUSED */
9669373SPeter.Dunlap@Sun.COM static void
idm_state_s9a_rejected(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)9679373SPeter.Dunlap@Sun.COM idm_state_s9a_rejected(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
9689373SPeter.Dunlap@Sun.COM {
96911552SPeter.Cudhea@Sun.COM /* All events ignored in this state */
97011552SPeter.Cudhea@Sun.COM }
97111552SPeter.Cudhea@Sun.COM
97211552SPeter.Cudhea@Sun.COM
97311552SPeter.Cudhea@Sun.COM static void
idm_state_s9b_wait_snd_done_cb(idm_pdu_t * pdu,idm_status_t status)97411552SPeter.Cudhea@Sun.COM idm_state_s9b_wait_snd_done_cb(idm_pdu_t *pdu, idm_status_t status)
97511552SPeter.Cudhea@Sun.COM {
97611552SPeter.Cudhea@Sun.COM idm_conn_t *ic = pdu->isp_ic;
97711552SPeter.Cudhea@Sun.COM
97811552SPeter.Cudhea@Sun.COM /*
97911552SPeter.Cudhea@Sun.COM * This pdu callback can be invoked by the tx thread,
98011552SPeter.Cudhea@Sun.COM * so run the disconnect code from another thread.
98111552SPeter.Cudhea@Sun.COM */
98211552SPeter.Cudhea@Sun.COM pdu->isp_status = status;
98311552SPeter.Cudhea@Sun.COM idm_conn_event(ic, CE_LOGIN_FAIL_SND_DONE, (uintptr_t)pdu);
9849373SPeter.Dunlap@Sun.COM }
9859373SPeter.Dunlap@Sun.COM
98611552SPeter.Cudhea@Sun.COM /*
98711552SPeter.Cudhea@Sun.COM * CS_S9B_WAIT_SND_DONE -- wait for callback completion.
98811552SPeter.Cudhea@Sun.COM */
98911552SPeter.Cudhea@Sun.COM /* ARGSUSED */
99011552SPeter.Cudhea@Sun.COM static void
idm_state_s9b_wait_snd_done(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)99111552SPeter.Cudhea@Sun.COM idm_state_s9b_wait_snd_done(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
99211552SPeter.Cudhea@Sun.COM {
99311552SPeter.Cudhea@Sun.COM idm_pdu_t *pdu;
99411552SPeter.Cudhea@Sun.COM /*
99511552SPeter.Cudhea@Sun.COM * Wait for completion of the login fail sequence and then
99611552SPeter.Cudhea@Sun.COM * go to state S9_INIT_ERROR to clean up the connection.
99711552SPeter.Cudhea@Sun.COM */
99811552SPeter.Cudhea@Sun.COM switch (event_ctx->iec_event) {
99911552SPeter.Cudhea@Sun.COM case CE_LOGIN_FAIL_SND_DONE:
100011552SPeter.Cudhea@Sun.COM pdu = (idm_pdu_t *)event_ctx->iec_info;
100111552SPeter.Cudhea@Sun.COM /* restore client callback */
100211552SPeter.Cudhea@Sun.COM pdu->isp_callback = ic->ic_client_callback;
100311552SPeter.Cudhea@Sun.COM ic->ic_client_callback = NULL;
100411552SPeter.Cudhea@Sun.COM idm_pdu_complete(pdu, pdu->isp_status);
100511552SPeter.Cudhea@Sun.COM idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
100611552SPeter.Cudhea@Sun.COM break;
100711552SPeter.Cudhea@Sun.COM
100811552SPeter.Cudhea@Sun.COM /* All other events ignored */
100911552SPeter.Cudhea@Sun.COM }
101011552SPeter.Cudhea@Sun.COM }
101111552SPeter.Cudhea@Sun.COM
101211552SPeter.Cudhea@Sun.COM
101311552SPeter.Cudhea@Sun.COM
101411552SPeter.Cudhea@Sun.COM
10157978SPeter.Dunlap@Sun.COM static void
idm_state_s10_in_cleanup(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)10167978SPeter.Dunlap@Sun.COM idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
10177978SPeter.Dunlap@Sun.COM {
10187978SPeter.Dunlap@Sun.COM idm_pdu_t *pdu;
10197978SPeter.Dunlap@Sun.COM
10207978SPeter.Dunlap@Sun.COM /*
10217978SPeter.Dunlap@Sun.COM * Need to cancel the cleanup timeout before leaving this state
10227978SPeter.Dunlap@Sun.COM * if it hasn't already fired.
10237978SPeter.Dunlap@Sun.COM */
10247978SPeter.Dunlap@Sun.COM switch (event_ctx->iec_event) {
10257978SPeter.Dunlap@Sun.COM case CE_LOGOUT_FAIL_RCV:
10267978SPeter.Dunlap@Sun.COM case CE_LOGOUT_FAIL_SND:
10277978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
10287978SPeter.Dunlap@Sun.COM break;
10297978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SUCCESS_SND:
10307978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SUCCESS_RCV:
10317978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SESSION_SUCCESS:
10327978SPeter.Dunlap@Sun.COM (void) untimeout(ic->ic_state_timeout);
10337978SPeter.Dunlap@Sun.COM /*FALLTHROUGH*/
10347978SPeter.Dunlap@Sun.COM case CE_CLEANUP_TIMEOUT:
10357978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
10367978SPeter.Dunlap@Sun.COM break;
10377978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SUCCESS_SND_DONE:
10387978SPeter.Dunlap@Sun.COM case CE_LOGOUT_FAIL_SND_DONE:
10397978SPeter.Dunlap@Sun.COM pdu = (idm_pdu_t *)event_ctx->iec_info;
10407978SPeter.Dunlap@Sun.COM /* restore client callback */
10417978SPeter.Dunlap@Sun.COM pdu->isp_callback = ic->ic_client_callback;
10427978SPeter.Dunlap@Sun.COM ic->ic_client_callback = NULL;
10437978SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, pdu->isp_status);
10447978SPeter.Dunlap@Sun.COM break;
10457978SPeter.Dunlap@Sun.COM case CE_TX_PROTOCOL_ERROR:
10467978SPeter.Dunlap@Sun.COM case CE_RX_PROTOCOL_ERROR:
10477978SPeter.Dunlap@Sun.COM case CE_MISC_TX:
10487978SPeter.Dunlap@Sun.COM case CE_MISC_RX:
104911078SPeter.Cudhea@Sun.COM case CE_LOGIN_TIMEOUT:
10507978SPeter.Dunlap@Sun.COM case CE_LOGOUT_TIMEOUT:
10517978SPeter.Dunlap@Sun.COM /* Don't care */
10527978SPeter.Dunlap@Sun.COM break;
10537978SPeter.Dunlap@Sun.COM default:
10547978SPeter.Dunlap@Sun.COM ASSERT(0);
10557978SPeter.Dunlap@Sun.COM }
10567978SPeter.Dunlap@Sun.COM }
10577978SPeter.Dunlap@Sun.COM
10587978SPeter.Dunlap@Sun.COM /* ARGSUSED */
10597978SPeter.Dunlap@Sun.COM static void
idm_state_s11_complete(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)10607978SPeter.Dunlap@Sun.COM idm_state_s11_complete(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
10617978SPeter.Dunlap@Sun.COM {
10627978SPeter.Dunlap@Sun.COM idm_pdu_t *pdu;
10637978SPeter.Dunlap@Sun.COM
10647978SPeter.Dunlap@Sun.COM /*
10657978SPeter.Dunlap@Sun.COM * Cleanup logout success/fail completion if it's been delayed
10667978SPeter.Dunlap@Sun.COM * until now.
106711552SPeter.Cudhea@Sun.COM *
106811552SPeter.Cudhea@Sun.COM * All new events are filtered out before reaching this state, but
106911552SPeter.Cudhea@Sun.COM * there might already be events in the event queue, so handle the
107011552SPeter.Cudhea@Sun.COM * SND_DONE events here. Note that if either of the following
107111552SPeter.Cudhea@Sun.COM * SND_DONE events happens AFTER the change to state S11, then the
107211552SPeter.Cudhea@Sun.COM * event filter inside dm_conn_event_locked does enough cleanup.
10737978SPeter.Dunlap@Sun.COM */
10747978SPeter.Dunlap@Sun.COM switch (event_ctx->iec_event) {
10757978SPeter.Dunlap@Sun.COM case CE_LOGOUT_SUCCESS_SND_DONE:
10767978SPeter.Dunlap@Sun.COM case CE_LOGOUT_FAIL_SND_DONE:
10777978SPeter.Dunlap@Sun.COM pdu = (idm_pdu_t *)event_ctx->iec_info;
10787978SPeter.Dunlap@Sun.COM /* restore client callback */
10797978SPeter.Dunlap@Sun.COM pdu->isp_callback = ic->ic_client_callback;
10807978SPeter.Dunlap@Sun.COM ic->ic_client_callback = NULL;
10817978SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, pdu->isp_status);
10827978SPeter.Dunlap@Sun.COM break;
10837978SPeter.Dunlap@Sun.COM }
108411552SPeter.Cudhea@Sun.COM
10857978SPeter.Dunlap@Sun.COM }
10867978SPeter.Dunlap@Sun.COM
10877978SPeter.Dunlap@Sun.COM static void
idm_state_s12_enable_dm(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)10887978SPeter.Dunlap@Sun.COM idm_state_s12_enable_dm(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
10897978SPeter.Dunlap@Sun.COM {
10907978SPeter.Dunlap@Sun.COM switch (event_ctx->iec_event) {
10917978SPeter.Dunlap@Sun.COM case CE_ENABLE_DM_SUCCESS:
10927978SPeter.Dunlap@Sun.COM /* T20 */
10937978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S5_LOGGED_IN, event_ctx);
10947978SPeter.Dunlap@Sun.COM break;
10957978SPeter.Dunlap@Sun.COM case CE_ENABLE_DM_FAIL:
10967978SPeter.Dunlap@Sun.COM /* T21 */
10977978SPeter.Dunlap@Sun.COM idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
10987978SPeter.Dunlap@Sun.COM break;
10997978SPeter.Dunlap@Sun.COM case CE_TRANSPORT_FAIL:
11007978SPeter.Dunlap@Sun.COM /*
11017978SPeter.Dunlap@Sun.COM * We expect to always hear back from the transport layer
11027978SPeter.Dunlap@Sun.COM * once we have an "enable data-mover" request outstanding.
11037978SPeter.Dunlap@Sun.COM * Therefore we'll ignore other events that may occur even
11047978SPeter.Dunlap@Sun.COM * when they clearly indicate a problem and wait for
11057978SPeter.Dunlap@Sun.COM * CE_ENABLE_DM_FAIL. On a related note this means the
11067978SPeter.Dunlap@Sun.COM * transport must ensure that it eventually completes the
11077978SPeter.Dunlap@Sun.COM * "enable data-mover" operation with either success or
11087978SPeter.Dunlap@Sun.COM * failure -- otherwise we'll be stuck here.
11097978SPeter.Dunlap@Sun.COM */
11107978SPeter.Dunlap@Sun.COM break;
11117978SPeter.Dunlap@Sun.COM default:
11127978SPeter.Dunlap@Sun.COM ASSERT(0);
11137978SPeter.Dunlap@Sun.COM break;
11147978SPeter.Dunlap@Sun.COM }
11157978SPeter.Dunlap@Sun.COM }
11167978SPeter.Dunlap@Sun.COM
11177978SPeter.Dunlap@Sun.COM static void
idm_update_state(idm_conn_t * ic,idm_conn_state_t new_state,idm_conn_event_ctx_t * event_ctx)11187978SPeter.Dunlap@Sun.COM idm_update_state(idm_conn_t *ic, idm_conn_state_t new_state,
11197978SPeter.Dunlap@Sun.COM idm_conn_event_ctx_t *event_ctx)
11207978SPeter.Dunlap@Sun.COM {
11217978SPeter.Dunlap@Sun.COM int rc;
11227978SPeter.Dunlap@Sun.COM idm_status_t idm_status;
11237978SPeter.Dunlap@Sun.COM
11247978SPeter.Dunlap@Sun.COM /*
11257978SPeter.Dunlap@Sun.COM * Validate new state
11267978SPeter.Dunlap@Sun.COM */
11277978SPeter.Dunlap@Sun.COM ASSERT(new_state != CS_S0_UNDEFINED);
11287978SPeter.Dunlap@Sun.COM ASSERT3U(new_state, <, CS_MAX_STATE);
11297978SPeter.Dunlap@Sun.COM
11307978SPeter.Dunlap@Sun.COM /*
11317978SPeter.Dunlap@Sun.COM * Update state in context. We protect this with a mutex
11327978SPeter.Dunlap@Sun.COM * even though the state machine code is single threaded so that
11337978SPeter.Dunlap@Sun.COM * other threads can check the state value atomically.
11347978SPeter.Dunlap@Sun.COM */
11357978SPeter.Dunlap@Sun.COM new_state = (new_state < CS_MAX_STATE) ?
11367978SPeter.Dunlap@Sun.COM new_state : CS_S0_UNDEFINED;
11377978SPeter.Dunlap@Sun.COM
11387978SPeter.Dunlap@Sun.COM IDM_SM_LOG(CE_NOTE, "idm_update_state: conn %p, evt %s(%d), "
11397978SPeter.Dunlap@Sun.COM "%s(%d) --> %s(%d)", (void *)ic,
11407978SPeter.Dunlap@Sun.COM idm_ce_name[event_ctx->iec_event], event_ctx->iec_event,
11417978SPeter.Dunlap@Sun.COM idm_cs_name[ic->ic_state], ic->ic_state,
11427978SPeter.Dunlap@Sun.COM idm_cs_name[new_state], new_state);
11437978SPeter.Dunlap@Sun.COM
11447978SPeter.Dunlap@Sun.COM DTRACE_PROBE2(conn__state__change,
11457978SPeter.Dunlap@Sun.COM idm_conn_t *, ic, idm_conn_state_t, new_state);
11467978SPeter.Dunlap@Sun.COM
11477978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
11487978SPeter.Dunlap@Sun.COM idm_sm_audit_state_change(&ic->ic_state_audit, SAS_IDM_CONN,
11497978SPeter.Dunlap@Sun.COM (int)ic->ic_state, (int)new_state);
11507978SPeter.Dunlap@Sun.COM ic->ic_last_state = ic->ic_state;
11517978SPeter.Dunlap@Sun.COM ic->ic_state = new_state;
11527978SPeter.Dunlap@Sun.COM cv_signal(&ic->ic_state_cv);
11537978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
11547978SPeter.Dunlap@Sun.COM
11557978SPeter.Dunlap@Sun.COM switch (ic->ic_state) {
11567978SPeter.Dunlap@Sun.COM case CS_S1_FREE:
11577978SPeter.Dunlap@Sun.COM ASSERT(0); /* Initial state, can't return */
11587978SPeter.Dunlap@Sun.COM break;
11597978SPeter.Dunlap@Sun.COM case CS_S2_XPT_WAIT:
11607978SPeter.Dunlap@Sun.COM if ((rc = idm_ini_conn_finish(ic)) != 0) {
11617978SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_CONNECT_FAIL, NULL);
11627978SPeter.Dunlap@Sun.COM } else {
11637978SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_CONNECT_SUCCESS, NULL);
11647978SPeter.Dunlap@Sun.COM }
11657978SPeter.Dunlap@Sun.COM break;
11667978SPeter.Dunlap@Sun.COM case CS_S3_XPT_UP:
11677978SPeter.Dunlap@Sun.COM /*
11687978SPeter.Dunlap@Sun.COM * Finish any connection related setup including
11697978SPeter.Dunlap@Sun.COM * waking up the idm_tgt_conn_accept thread.
11707978SPeter.Dunlap@Sun.COM * and starting the login timer. If the function
11717978SPeter.Dunlap@Sun.COM * fails then we return to "free" state.
11727978SPeter.Dunlap@Sun.COM */
11737978SPeter.Dunlap@Sun.COM if ((rc = idm_tgt_conn_finish(ic)) != IDM_STATUS_SUCCESS) {
11747978SPeter.Dunlap@Sun.COM switch (rc) {
11757978SPeter.Dunlap@Sun.COM case IDM_STATUS_REJECT:
11767978SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_CONNECT_REJECT, NULL);
11777978SPeter.Dunlap@Sun.COM break;
11787978SPeter.Dunlap@Sun.COM default:
11797978SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_CONNECT_FAIL, NULL);
11807978SPeter.Dunlap@Sun.COM break;
11817978SPeter.Dunlap@Sun.COM }
11827978SPeter.Dunlap@Sun.COM }
11837978SPeter.Dunlap@Sun.COM
11847978SPeter.Dunlap@Sun.COM /*
11857978SPeter.Dunlap@Sun.COM * First login received will cause a transition to
11867978SPeter.Dunlap@Sun.COM * CS_S4_IN_LOGIN. Start login timer.
11877978SPeter.Dunlap@Sun.COM */
11887978SPeter.Dunlap@Sun.COM ic->ic_state_timeout = timeout(idm_login_timeout, ic,
11897978SPeter.Dunlap@Sun.COM drv_usectohz(IDM_LOGIN_SECONDS*1000000));
11907978SPeter.Dunlap@Sun.COM break;
11917978SPeter.Dunlap@Sun.COM case CS_S4_IN_LOGIN:
11927978SPeter.Dunlap@Sun.COM if (ic->ic_conn_type == CONN_TYPE_INI) {
119310766SPeter.Cudhea@Sun.COM (void) idm_notify_client(ic, CN_READY_FOR_LOGIN, NULL);
11947978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
11957978SPeter.Dunlap@Sun.COM ic->ic_state_flags |= CF_LOGIN_READY;
11967978SPeter.Dunlap@Sun.COM cv_signal(&ic->ic_state_cv);
11977978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
11987978SPeter.Dunlap@Sun.COM }
11997978SPeter.Dunlap@Sun.COM break;
12007978SPeter.Dunlap@Sun.COM case CS_S5_LOGGED_IN:
12017978SPeter.Dunlap@Sun.COM ASSERT(!ic->ic_ffp);
12027978SPeter.Dunlap@Sun.COM /*
12037978SPeter.Dunlap@Sun.COM * IDM can go to FFP before the initiator but it
12047978SPeter.Dunlap@Sun.COM * needs to go to FFP after the target (IDM target should
12057978SPeter.Dunlap@Sun.COM * go to FFP after notify_ack).
12067978SPeter.Dunlap@Sun.COM */
12077978SPeter.Dunlap@Sun.COM idm_status = idm_ffp_enable(ic);
12087978SPeter.Dunlap@Sun.COM if (idm_status != IDM_STATUS_SUCCESS) {
12097978SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_TRANSPORT_FAIL, NULL);
12107978SPeter.Dunlap@Sun.COM }
12117978SPeter.Dunlap@Sun.COM
12127978SPeter.Dunlap@Sun.COM if (ic->ic_reinstate_conn) {
12137978SPeter.Dunlap@Sun.COM /* Connection reinstatement is complete */
121411078SPeter.Cudhea@Sun.COM idm_conn_event(ic->ic_reinstate_conn,
121511078SPeter.Cudhea@Sun.COM CE_CONN_REINSTATE_SUCCESS, NULL);
12167978SPeter.Dunlap@Sun.COM }
12177978SPeter.Dunlap@Sun.COM break;
12187978SPeter.Dunlap@Sun.COM case CS_S6_IN_LOGOUT:
12197978SPeter.Dunlap@Sun.COM break;
12207978SPeter.Dunlap@Sun.COM case CS_S7_LOGOUT_REQ:
12217978SPeter.Dunlap@Sun.COM /* Start logout timer for target connections */
12227978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic)) {
12237978SPeter.Dunlap@Sun.COM ic->ic_state_timeout = timeout(idm_logout_req_timeout,
12247978SPeter.Dunlap@Sun.COM ic, drv_usectohz(IDM_LOGOUT_SECONDS*1000000));
12257978SPeter.Dunlap@Sun.COM }
12267978SPeter.Dunlap@Sun.COM break;
12277978SPeter.Dunlap@Sun.COM case CS_S8_CLEANUP:
12287978SPeter.Dunlap@Sun.COM /* Close connection (if it's not already closed) */
12297978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic)) {
12307978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
12317978SPeter.Dunlap@Sun.COM } else {
12327978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_ini_conn_disconnect(ic);
12337978SPeter.Dunlap@Sun.COM }
12347978SPeter.Dunlap@Sun.COM
12357978SPeter.Dunlap@Sun.COM /* Stop executing active tasks */
12367978SPeter.Dunlap@Sun.COM idm_task_abort(ic, NULL, AT_INTERNAL_SUSPEND);
12377978SPeter.Dunlap@Sun.COM
12387978SPeter.Dunlap@Sun.COM /* Start logout timer */
12397978SPeter.Dunlap@Sun.COM ic->ic_state_timeout = timeout(idm_cleanup_timeout, ic,
12407978SPeter.Dunlap@Sun.COM drv_usectohz(IDM_CLEANUP_SECONDS*1000000));
12417978SPeter.Dunlap@Sun.COM break;
12427978SPeter.Dunlap@Sun.COM case CS_S10_IN_CLEANUP:
12437978SPeter.Dunlap@Sun.COM break;
12449373SPeter.Dunlap@Sun.COM case CS_S9A_REJECTED:
12459373SPeter.Dunlap@Sun.COM /*
12469373SPeter.Dunlap@Sun.COM * We never finished establishing the connection so no
124711552SPeter.Cudhea@Sun.COM * disconnect. No client notifications because the client
12489373SPeter.Dunlap@Sun.COM * rejected the connection.
12499373SPeter.Dunlap@Sun.COM */
12509373SPeter.Dunlap@Sun.COM idm_refcnt_async_wait_ref(&ic->ic_refcnt,
12519373SPeter.Dunlap@Sun.COM &idm_conn_reject_unref);
12529373SPeter.Dunlap@Sun.COM break;
125311552SPeter.Cudhea@Sun.COM case CS_S9B_WAIT_SND_DONE:
125411552SPeter.Cudhea@Sun.COM break;
12557978SPeter.Dunlap@Sun.COM case CS_S9_INIT_ERROR:
12567978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic)) {
12577978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
12587978SPeter.Dunlap@Sun.COM } else {
12597978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
12607978SPeter.Dunlap@Sun.COM ic->ic_state_flags |= CF_ERROR;
12617978SPeter.Dunlap@Sun.COM ic->ic_conn_sm_status = IDM_STATUS_FAIL;
12627978SPeter.Dunlap@Sun.COM cv_signal(&ic->ic_state_cv);
12637978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
12649162SPeter.Dunlap@Sun.COM if (ic->ic_last_state != CS_S1_FREE &&
12659162SPeter.Dunlap@Sun.COM ic->ic_last_state != CS_S2_XPT_WAIT) {
12669162SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_ini_conn_disconnect(
12679162SPeter.Dunlap@Sun.COM ic);
12689162SPeter.Dunlap@Sun.COM } else {
12699162SPeter.Dunlap@Sun.COM (void) idm_notify_client(ic, CN_CONNECT_FAIL,
12709162SPeter.Dunlap@Sun.COM NULL);
12719162SPeter.Dunlap@Sun.COM }
12727978SPeter.Dunlap@Sun.COM }
12737978SPeter.Dunlap@Sun.COM /*FALLTHROUGH*/
12747978SPeter.Dunlap@Sun.COM case CS_S11_COMPLETE:
12759162SPeter.Dunlap@Sun.COM /*
12769162SPeter.Dunlap@Sun.COM * No more traffic on this connection. If this is an
12779162SPeter.Dunlap@Sun.COM * initiator connection and we weren't connected yet
12789162SPeter.Dunlap@Sun.COM * then don't send the "connect lost" event.
12799162SPeter.Dunlap@Sun.COM * It's useful to the initiator to know whether we were
12809162SPeter.Dunlap@Sun.COM * logging in at the time so send that information in the
12819162SPeter.Dunlap@Sun.COM * data field.
12829162SPeter.Dunlap@Sun.COM */
12839162SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic) ||
12849162SPeter.Dunlap@Sun.COM ((ic->ic_last_state != CS_S1_FREE) &&
12859162SPeter.Dunlap@Sun.COM (ic->ic_last_state != CS_S2_XPT_WAIT))) {
12869162SPeter.Dunlap@Sun.COM (void) idm_notify_client(ic, CN_CONNECT_LOST,
12879162SPeter.Dunlap@Sun.COM (uintptr_t)(ic->ic_last_state == CS_S4_IN_LOGIN));
12889162SPeter.Dunlap@Sun.COM }
12897978SPeter.Dunlap@Sun.COM
12907978SPeter.Dunlap@Sun.COM /* Abort all tasks */
12917978SPeter.Dunlap@Sun.COM idm_task_abort(ic, NULL, AT_INTERNAL_ABORT);
12927978SPeter.Dunlap@Sun.COM
12937978SPeter.Dunlap@Sun.COM /*
12947978SPeter.Dunlap@Sun.COM * Handle terminal state actions on the global taskq so
12957978SPeter.Dunlap@Sun.COM * we can clean up all the connection resources from
12967978SPeter.Dunlap@Sun.COM * a separate thread context.
12977978SPeter.Dunlap@Sun.COM */
12987978SPeter.Dunlap@Sun.COM idm_refcnt_async_wait_ref(&ic->ic_refcnt, &idm_conn_unref);
12997978SPeter.Dunlap@Sun.COM break;
13007978SPeter.Dunlap@Sun.COM case CS_S12_ENABLE_DM:
13017978SPeter.Dunlap@Sun.COM
13027978SPeter.Dunlap@Sun.COM /*
13037978SPeter.Dunlap@Sun.COM * The Enable DM state indicates the initiator to initiate
13047978SPeter.Dunlap@Sun.COM * the hello sequence and the target to get ready to accept
13057978SPeter.Dunlap@Sun.COM * the iSER Hello Message.
13067978SPeter.Dunlap@Sun.COM */
13077978SPeter.Dunlap@Sun.COM idm_status = (IDM_CONN_ISINI(ic)) ?
13087978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_ini_enable_datamover(ic) :
13097978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_tgt_enable_datamover(ic);
13107978SPeter.Dunlap@Sun.COM
13117978SPeter.Dunlap@Sun.COM if (idm_status == IDM_STATUS_SUCCESS) {
13127978SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_ENABLE_DM_SUCCESS, NULL);
13137978SPeter.Dunlap@Sun.COM } else {
13147978SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_ENABLE_DM_FAIL, NULL);
13157978SPeter.Dunlap@Sun.COM }
13167978SPeter.Dunlap@Sun.COM
13177978SPeter.Dunlap@Sun.COM break;
131811552SPeter.Cudhea@Sun.COM
131911552SPeter.Cudhea@Sun.COM default:
132011552SPeter.Cudhea@Sun.COM ASSERT(0);
132111552SPeter.Cudhea@Sun.COM break;
132211552SPeter.Cudhea@Sun.COM
13237978SPeter.Dunlap@Sun.COM }
13247978SPeter.Dunlap@Sun.COM }
13257978SPeter.Dunlap@Sun.COM
13267978SPeter.Dunlap@Sun.COM
13277978SPeter.Dunlap@Sun.COM static void
idm_conn_unref(void * ic_void)13287978SPeter.Dunlap@Sun.COM idm_conn_unref(void *ic_void)
13297978SPeter.Dunlap@Sun.COM {
13307978SPeter.Dunlap@Sun.COM idm_conn_t *ic = ic_void;
13317978SPeter.Dunlap@Sun.COM
13327978SPeter.Dunlap@Sun.COM /*
13337978SPeter.Dunlap@Sun.COM * Client should not be notified that the connection is destroyed
13347978SPeter.Dunlap@Sun.COM * until all references on the idm connection have been removed.
13357978SPeter.Dunlap@Sun.COM * Otherwise references on the associated client context would need
13367978SPeter.Dunlap@Sun.COM * to be tracked separately which seems like a waste (at least when
13377978SPeter.Dunlap@Sun.COM * there is a one for one correspondence with references on the
13387978SPeter.Dunlap@Sun.COM * IDM connection).
13397978SPeter.Dunlap@Sun.COM */
13407978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic)) {
13417978SPeter.Dunlap@Sun.COM (void) idm_notify_client(ic, CN_CONNECT_DESTROY, NULL);
13427978SPeter.Dunlap@Sun.COM idm_svc_conn_destroy(ic);
13437978SPeter.Dunlap@Sun.COM } else {
13447978SPeter.Dunlap@Sun.COM /* Initiator may destroy connection during this call */
13457978SPeter.Dunlap@Sun.COM (void) idm_notify_client(ic, CN_CONNECT_DESTROY, NULL);
13467978SPeter.Dunlap@Sun.COM }
13477978SPeter.Dunlap@Sun.COM }
13487978SPeter.Dunlap@Sun.COM
13499373SPeter.Dunlap@Sun.COM static void
idm_conn_reject_unref(void * ic_void)13509373SPeter.Dunlap@Sun.COM idm_conn_reject_unref(void *ic_void)
13519373SPeter.Dunlap@Sun.COM {
13529373SPeter.Dunlap@Sun.COM idm_conn_t *ic = ic_void;
13539373SPeter.Dunlap@Sun.COM
13549373SPeter.Dunlap@Sun.COM ASSERT(IDM_CONN_ISTGT(ic));
13559373SPeter.Dunlap@Sun.COM
13569373SPeter.Dunlap@Sun.COM /* Don't notify the client since it rejected the connection */
13579373SPeter.Dunlap@Sun.COM idm_svc_conn_destroy(ic);
13589373SPeter.Dunlap@Sun.COM }
13599373SPeter.Dunlap@Sun.COM
13609373SPeter.Dunlap@Sun.COM
13617978SPeter.Dunlap@Sun.COM
13627978SPeter.Dunlap@Sun.COM 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)13637978SPeter.Dunlap@Sun.COM idm_conn_sm_validate_pdu(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx,
13647978SPeter.Dunlap@Sun.COM idm_pdu_t *pdu)
13657978SPeter.Dunlap@Sun.COM {
13667978SPeter.Dunlap@Sun.COM char *reason_string;
13677978SPeter.Dunlap@Sun.COM idm_pdu_event_action_t action;
13687978SPeter.Dunlap@Sun.COM
13697978SPeter.Dunlap@Sun.COM ASSERT((event_ctx->iec_pdu_event_type == CT_RX_PDU) ||
13707978SPeter.Dunlap@Sun.COM (event_ctx->iec_pdu_event_type == CT_TX_PDU));
13717978SPeter.Dunlap@Sun.COM
13727978SPeter.Dunlap@Sun.COM /*
13737978SPeter.Dunlap@Sun.COM * Let's check the simple stuff first. Make sure if this is a
13747978SPeter.Dunlap@Sun.COM * target connection that the PDU is appropriate for a target
13757978SPeter.Dunlap@Sun.COM * and if this is an initiator connection that the PDU is
13767978SPeter.Dunlap@Sun.COM * appropriate for an initiator. This code is not in the data
13777978SPeter.Dunlap@Sun.COM * path so organization is more important than performance.
13787978SPeter.Dunlap@Sun.COM */
13797978SPeter.Dunlap@Sun.COM switch (IDM_PDU_OPCODE(pdu)) {
13807978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_OUT:
13817978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_CMD:
13827978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_MSG:
13837978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGIN_CMD:
13847978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_CMD:
13857978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA:
13867978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGOUT_CMD:
13877978SPeter.Dunlap@Sun.COM case ISCSI_OP_SNACK_CMD:
13887978SPeter.Dunlap@Sun.COM /*
13897978SPeter.Dunlap@Sun.COM * Only the initiator should send these PDU's and
13907978SPeter.Dunlap@Sun.COM * only the target should receive them.
13917978SPeter.Dunlap@Sun.COM */
13927978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISINI(ic) &&
13937978SPeter.Dunlap@Sun.COM (event_ctx->iec_pdu_event_type == CT_RX_PDU)) {
13947978SPeter.Dunlap@Sun.COM reason_string = "Invalid RX PDU for initiator";
13957978SPeter.Dunlap@Sun.COM action = CA_RX_PROTOCOL_ERROR;
13967978SPeter.Dunlap@Sun.COM goto validate_pdu_done;
13977978SPeter.Dunlap@Sun.COM }
13987978SPeter.Dunlap@Sun.COM
13997978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic) &&
14007978SPeter.Dunlap@Sun.COM (event_ctx->iec_pdu_event_type == CT_TX_PDU)) {
14017978SPeter.Dunlap@Sun.COM reason_string = "Invalid TX PDU for target";
14027978SPeter.Dunlap@Sun.COM action = CA_TX_PROTOCOL_ERROR;
14037978SPeter.Dunlap@Sun.COM goto validate_pdu_done;
14047978SPeter.Dunlap@Sun.COM }
14057978SPeter.Dunlap@Sun.COM break;
14067978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_IN:
14077978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_RSP:
14087978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_RSP:
14097978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGIN_RSP:
14107978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_RSP:
14117978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA_RSP:
14127978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGOUT_RSP:
14137978SPeter.Dunlap@Sun.COM case ISCSI_OP_RTT_RSP:
14147978SPeter.Dunlap@Sun.COM case ISCSI_OP_ASYNC_EVENT:
14157978SPeter.Dunlap@Sun.COM case ISCSI_OP_REJECT_MSG:
14167978SPeter.Dunlap@Sun.COM /*
14177978SPeter.Dunlap@Sun.COM * Only the target should send these PDU's and
14187978SPeter.Dunlap@Sun.COM * only the initiator should receive them.
14197978SPeter.Dunlap@Sun.COM */
14207978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic) &&
14217978SPeter.Dunlap@Sun.COM (event_ctx->iec_pdu_event_type == CT_RX_PDU)) {
14227978SPeter.Dunlap@Sun.COM reason_string = "Invalid RX PDU for target";
14237978SPeter.Dunlap@Sun.COM action = CA_RX_PROTOCOL_ERROR;
14247978SPeter.Dunlap@Sun.COM goto validate_pdu_done;
14257978SPeter.Dunlap@Sun.COM }
14267978SPeter.Dunlap@Sun.COM
14277978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISINI(ic) &&
14287978SPeter.Dunlap@Sun.COM (event_ctx->iec_pdu_event_type == CT_TX_PDU)) {
14297978SPeter.Dunlap@Sun.COM reason_string = "Invalid TX PDU for initiator";
14307978SPeter.Dunlap@Sun.COM action = CA_TX_PROTOCOL_ERROR;
14317978SPeter.Dunlap@Sun.COM goto validate_pdu_done;
14327978SPeter.Dunlap@Sun.COM }
14337978SPeter.Dunlap@Sun.COM break;
14347978SPeter.Dunlap@Sun.COM default:
14357978SPeter.Dunlap@Sun.COM reason_string = "Unknown PDU Type";
14367978SPeter.Dunlap@Sun.COM action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
14377978SPeter.Dunlap@Sun.COM CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
14387978SPeter.Dunlap@Sun.COM goto validate_pdu_done;
14397978SPeter.Dunlap@Sun.COM }
14407978SPeter.Dunlap@Sun.COM
14417978SPeter.Dunlap@Sun.COM /*
14427978SPeter.Dunlap@Sun.COM * Now validate the opcodes against the current state.
14437978SPeter.Dunlap@Sun.COM */
14447978SPeter.Dunlap@Sun.COM reason_string = "PDU not allowed in current state";
14457978SPeter.Dunlap@Sun.COM switch (IDM_PDU_OPCODE(pdu)) {
14467978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_OUT:
14477978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_IN:
14487978SPeter.Dunlap@Sun.COM /*
14497978SPeter.Dunlap@Sun.COM * Obviously S1-S3 are not allowed since login hasn't started.
14507978SPeter.Dunlap@Sun.COM * S8 is probably out as well since the connection has been
14517978SPeter.Dunlap@Sun.COM * dropped.
14527978SPeter.Dunlap@Sun.COM */
14537978SPeter.Dunlap@Sun.COM switch (ic->ic_state) {
14547978SPeter.Dunlap@Sun.COM case CS_S4_IN_LOGIN:
14557978SPeter.Dunlap@Sun.COM case CS_S5_LOGGED_IN:
14567978SPeter.Dunlap@Sun.COM case CS_S6_IN_LOGOUT:
14577978SPeter.Dunlap@Sun.COM case CS_S7_LOGOUT_REQ:
14587978SPeter.Dunlap@Sun.COM action = CA_FORWARD;
14597978SPeter.Dunlap@Sun.COM goto validate_pdu_done;
14607978SPeter.Dunlap@Sun.COM case CS_S8_CLEANUP:
14617978SPeter.Dunlap@Sun.COM case CS_S10_IN_CLEANUP:
14627978SPeter.Dunlap@Sun.COM action = CA_DROP;
14637978SPeter.Dunlap@Sun.COM break;
14647978SPeter.Dunlap@Sun.COM default:
14657978SPeter.Dunlap@Sun.COM action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
14667978SPeter.Dunlap@Sun.COM CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
14677978SPeter.Dunlap@Sun.COM goto validate_pdu_done;
14687978SPeter.Dunlap@Sun.COM }
14697978SPeter.Dunlap@Sun.COM /*NOTREACHED*/
14707978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_CMD:
14717978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_RSP:
14727978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_MSG:
14737978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_RSP:
14747978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA:
14757978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA_RSP:
14767978SPeter.Dunlap@Sun.COM case ISCSI_OP_RTT_RSP:
14777978SPeter.Dunlap@Sun.COM case ISCSI_OP_SNACK_CMD:
14787978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_CMD:
14797978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_RSP:
14807978SPeter.Dunlap@Sun.COM switch (ic->ic_state) {
14817978SPeter.Dunlap@Sun.COM case CS_S5_LOGGED_IN:
14827978SPeter.Dunlap@Sun.COM case CS_S6_IN_LOGOUT:
14837978SPeter.Dunlap@Sun.COM case CS_S7_LOGOUT_REQ:
14847978SPeter.Dunlap@Sun.COM action = CA_FORWARD;
14857978SPeter.Dunlap@Sun.COM goto validate_pdu_done;
14867978SPeter.Dunlap@Sun.COM case CS_S8_CLEANUP:
14877978SPeter.Dunlap@Sun.COM case CS_S10_IN_CLEANUP:
14887978SPeter.Dunlap@Sun.COM action = CA_DROP;
14897978SPeter.Dunlap@Sun.COM break;
14907978SPeter.Dunlap@Sun.COM default:
14917978SPeter.Dunlap@Sun.COM action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
14927978SPeter.Dunlap@Sun.COM CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
14937978SPeter.Dunlap@Sun.COM goto validate_pdu_done;
14947978SPeter.Dunlap@Sun.COM }
14957978SPeter.Dunlap@Sun.COM /*NOTREACHED*/
14967978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGOUT_CMD:
14977978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGOUT_RSP:
14987978SPeter.Dunlap@Sun.COM case ISCSI_OP_REJECT_MSG:
14997978SPeter.Dunlap@Sun.COM case ISCSI_OP_ASYNC_EVENT:
15007978SPeter.Dunlap@Sun.COM switch (ic->ic_state) {
15017978SPeter.Dunlap@Sun.COM case CS_S5_LOGGED_IN:
15027978SPeter.Dunlap@Sun.COM case CS_S6_IN_LOGOUT:
15037978SPeter.Dunlap@Sun.COM case CS_S7_LOGOUT_REQ:
15047978SPeter.Dunlap@Sun.COM action = CA_FORWARD;
15057978SPeter.Dunlap@Sun.COM goto validate_pdu_done;
15067978SPeter.Dunlap@Sun.COM case CS_S8_CLEANUP:
15077978SPeter.Dunlap@Sun.COM case CS_S10_IN_CLEANUP:
15087978SPeter.Dunlap@Sun.COM action = CA_DROP;
15097978SPeter.Dunlap@Sun.COM break;
15107978SPeter.Dunlap@Sun.COM default:
15117978SPeter.Dunlap@Sun.COM action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
15127978SPeter.Dunlap@Sun.COM CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
15137978SPeter.Dunlap@Sun.COM goto validate_pdu_done;
15147978SPeter.Dunlap@Sun.COM }
15157978SPeter.Dunlap@Sun.COM /*NOTREACHED*/
15167978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGIN_CMD:
15177978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGIN_RSP:
15187978SPeter.Dunlap@Sun.COM switch (ic->ic_state) {
15197978SPeter.Dunlap@Sun.COM case CS_S3_XPT_UP:
15207978SPeter.Dunlap@Sun.COM case CS_S4_IN_LOGIN:
15217978SPeter.Dunlap@Sun.COM action = CA_FORWARD;
15227978SPeter.Dunlap@Sun.COM goto validate_pdu_done;
15237978SPeter.Dunlap@Sun.COM default:
15247978SPeter.Dunlap@Sun.COM action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
15257978SPeter.Dunlap@Sun.COM CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
15267978SPeter.Dunlap@Sun.COM goto validate_pdu_done;
15277978SPeter.Dunlap@Sun.COM }
15287978SPeter.Dunlap@Sun.COM /*NOTREACHED*/
15297978SPeter.Dunlap@Sun.COM default:
15307978SPeter.Dunlap@Sun.COM /* This should never happen -- we already checked above */
15317978SPeter.Dunlap@Sun.COM ASSERT(0);
15327978SPeter.Dunlap@Sun.COM /*NOTREACHED*/
15337978SPeter.Dunlap@Sun.COM }
15347978SPeter.Dunlap@Sun.COM
15357978SPeter.Dunlap@Sun.COM action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
15367978SPeter.Dunlap@Sun.COM CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
15377978SPeter.Dunlap@Sun.COM
15387978SPeter.Dunlap@Sun.COM validate_pdu_done:
15397978SPeter.Dunlap@Sun.COM if (action != CA_FORWARD) {
15407978SPeter.Dunlap@Sun.COM DTRACE_PROBE2(idm__int__protocol__error,
15417978SPeter.Dunlap@Sun.COM idm_conn_event_ctx_t *, event_ctx,
15427978SPeter.Dunlap@Sun.COM char *, reason_string);
15437978SPeter.Dunlap@Sun.COM }
15447978SPeter.Dunlap@Sun.COM
15457978SPeter.Dunlap@Sun.COM return (action);
15467978SPeter.Dunlap@Sun.COM }
15477978SPeter.Dunlap@Sun.COM
15487978SPeter.Dunlap@Sun.COM /* ARGSUSED */
15497978SPeter.Dunlap@Sun.COM void
idm_pdu_tx_protocol_error(idm_conn_t * ic,idm_pdu_t * pdu)15507978SPeter.Dunlap@Sun.COM idm_pdu_tx_protocol_error(idm_conn_t *ic, idm_pdu_t *pdu)
15517978SPeter.Dunlap@Sun.COM {
15527978SPeter.Dunlap@Sun.COM /*
15537978SPeter.Dunlap@Sun.COM * Return the PDU to the caller indicating it was a protocol error.
15547978SPeter.Dunlap@Sun.COM * Caller can take appropriate action.
15557978SPeter.Dunlap@Sun.COM */
15567978SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, IDM_STATUS_PROTOCOL_ERROR);
15577978SPeter.Dunlap@Sun.COM }
15587978SPeter.Dunlap@Sun.COM
15597978SPeter.Dunlap@Sun.COM void
idm_pdu_rx_protocol_error(idm_conn_t * ic,idm_pdu_t * pdu)15607978SPeter.Dunlap@Sun.COM idm_pdu_rx_protocol_error(idm_conn_t *ic, idm_pdu_t *pdu)
15617978SPeter.Dunlap@Sun.COM {
15627978SPeter.Dunlap@Sun.COM /*
15637978SPeter.Dunlap@Sun.COM * Forward PDU to caller indicating it is a protocol error.
15647978SPeter.Dunlap@Sun.COM * Caller should take appropriate action.
15657978SPeter.Dunlap@Sun.COM */
15667978SPeter.Dunlap@Sun.COM (*ic->ic_conn_ops.icb_rx_error)(ic, pdu, IDM_STATUS_PROTOCOL_ERROR);
15677978SPeter.Dunlap@Sun.COM }
15687978SPeter.Dunlap@Sun.COM
15697978SPeter.Dunlap@Sun.COM idm_status_t
idm_notify_client(idm_conn_t * ic,idm_client_notify_t cn,uintptr_t data)15707978SPeter.Dunlap@Sun.COM idm_notify_client(idm_conn_t *ic, idm_client_notify_t cn, uintptr_t data)
15717978SPeter.Dunlap@Sun.COM {
15727978SPeter.Dunlap@Sun.COM /*
15737978SPeter.Dunlap@Sun.COM * We may want to make this more complicated at some point but
15747978SPeter.Dunlap@Sun.COM * for now lets just call the client's notify function and return
15757978SPeter.Dunlap@Sun.COM * the status.
15767978SPeter.Dunlap@Sun.COM */
157710766SPeter.Cudhea@Sun.COM ASSERT(!mutex_owned(&ic->ic_state_mutex));
15789162SPeter.Dunlap@Sun.COM cn = (cn > CN_MAX) ? CN_MAX : cn;
15799162SPeter.Dunlap@Sun.COM IDM_SM_LOG(CE_NOTE, "idm_notify_client: ic=%p %s(%d)\n",
15809162SPeter.Dunlap@Sun.COM (void *)ic, idm_cn_strings[cn], cn);
15817978SPeter.Dunlap@Sun.COM return ((*ic->ic_conn_ops.icb_client_notify)(ic, cn, data));
15827978SPeter.Dunlap@Sun.COM }
15837978SPeter.Dunlap@Sun.COM
15847978SPeter.Dunlap@Sun.COM static idm_status_t
idm_ffp_enable(idm_conn_t * ic)15857978SPeter.Dunlap@Sun.COM idm_ffp_enable(idm_conn_t *ic)
15867978SPeter.Dunlap@Sun.COM {
15877978SPeter.Dunlap@Sun.COM idm_status_t rc;
15887978SPeter.Dunlap@Sun.COM
15897978SPeter.Dunlap@Sun.COM /*
15907978SPeter.Dunlap@Sun.COM * On the initiator side the client will see this notification
15917978SPeter.Dunlap@Sun.COM * before the actual login succes PDU. This shouldn't be a big
15927978SPeter.Dunlap@Sun.COM * deal since the initiator drives the connection. It can simply
15937978SPeter.Dunlap@Sun.COM * wait for the login response then start sending SCSI commands.
15947978SPeter.Dunlap@Sun.COM * Kind ugly though compared with the way things work on target
15957978SPeter.Dunlap@Sun.COM * connections.
15967978SPeter.Dunlap@Sun.COM */
15977978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
15987978SPeter.Dunlap@Sun.COM ic->ic_ffp = B_TRUE;
15997978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
16007978SPeter.Dunlap@Sun.COM
16017978SPeter.Dunlap@Sun.COM rc = idm_notify_client(ic, CN_FFP_ENABLED, NULL);
16027978SPeter.Dunlap@Sun.COM if (rc != IDM_STATUS_SUCCESS) {
16037978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
16047978SPeter.Dunlap@Sun.COM ic->ic_ffp = B_FALSE;
16057978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
16067978SPeter.Dunlap@Sun.COM }
16077978SPeter.Dunlap@Sun.COM return (rc);
16087978SPeter.Dunlap@Sun.COM }
16097978SPeter.Dunlap@Sun.COM
16107978SPeter.Dunlap@Sun.COM static void
idm_ffp_disable(idm_conn_t * ic,idm_ffp_disable_t disable_type)16117978SPeter.Dunlap@Sun.COM idm_ffp_disable(idm_conn_t *ic, idm_ffp_disable_t disable_type)
16127978SPeter.Dunlap@Sun.COM {
16137978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
16147978SPeter.Dunlap@Sun.COM ic->ic_ffp = B_FALSE;
16157978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
16167978SPeter.Dunlap@Sun.COM
16177978SPeter.Dunlap@Sun.COM /* Client can't "fail" CN_FFP_DISABLED */
16187978SPeter.Dunlap@Sun.COM (void) idm_notify_client(ic, CN_FFP_DISABLED,
16197978SPeter.Dunlap@Sun.COM (uintptr_t)disable_type);
16207978SPeter.Dunlap@Sun.COM }
16217978SPeter.Dunlap@Sun.COM
16227978SPeter.Dunlap@Sun.COM static void
idm_initial_login_actions(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)16237978SPeter.Dunlap@Sun.COM idm_initial_login_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
16247978SPeter.Dunlap@Sun.COM {
16257978SPeter.Dunlap@Sun.COM ASSERT((event_ctx->iec_event == CE_LOGIN_RCV) ||
16267978SPeter.Dunlap@Sun.COM (event_ctx->iec_event == CE_LOGIN_SND));
16277978SPeter.Dunlap@Sun.COM
16287978SPeter.Dunlap@Sun.COM /*
16297978SPeter.Dunlap@Sun.COM * Currently it's not clear what we would do here -- since
16307978SPeter.Dunlap@Sun.COM * we went to the trouble of coding an "initial login" hook
16317978SPeter.Dunlap@Sun.COM * we'll leave it in for now. Remove before integration if
16327978SPeter.Dunlap@Sun.COM * it's not used for anything.
16337978SPeter.Dunlap@Sun.COM */
16347978SPeter.Dunlap@Sun.COM ic->ic_state_flags |= CF_INITIAL_LOGIN;
16357978SPeter.Dunlap@Sun.COM }
16367978SPeter.Dunlap@Sun.COM
16377978SPeter.Dunlap@Sun.COM static void
idm_login_success_actions(idm_conn_t * ic,idm_conn_event_ctx_t * event_ctx)16387978SPeter.Dunlap@Sun.COM idm_login_success_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
16397978SPeter.Dunlap@Sun.COM {
16407978SPeter.Dunlap@Sun.COM idm_pdu_t *pdu = (idm_pdu_t *)event_ctx->iec_info;
16417978SPeter.Dunlap@Sun.COM iscsi_login_hdr_t *login_req =
16427978SPeter.Dunlap@Sun.COM (iscsi_login_hdr_t *)pdu->isp_hdr;
16437978SPeter.Dunlap@Sun.COM
16447978SPeter.Dunlap@Sun.COM ASSERT((event_ctx->iec_event == CE_LOGIN_SUCCESS_RCV) ||
16457978SPeter.Dunlap@Sun.COM (event_ctx->iec_event == CE_LOGIN_SUCCESS_SND));
16467978SPeter.Dunlap@Sun.COM
16477978SPeter.Dunlap@Sun.COM /*
16487978SPeter.Dunlap@Sun.COM * Save off CID
16497978SPeter.Dunlap@Sun.COM */
16507978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
16517978SPeter.Dunlap@Sun.COM ic->ic_login_cid = ntohs(login_req->cid);
16527978SPeter.Dunlap@Sun.COM ic->ic_login_info_valid = B_TRUE;
16537978SPeter.Dunlap@Sun.COM
16547978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
16557978SPeter.Dunlap@Sun.COM }
1656