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