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