1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 26 */ 27 #ifndef _IDM_CONN_SM_H_ 28 #define _IDM_CONN_SM_H_ 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 35 /* 36 * IDM connection state machine events. Most events get generated internally 37 * either by the state machine or by the IDM TX/RX code. For example when IDM 38 * receives a login request for a target connectionit will generate a 39 * CE_LOGIN_RCV event. Similarly when the target sends a successful login 40 * response IDM generate a "CE_LOGIN_SUCCESS_SND" event. The following 41 * events are not detected on the TX/RX path and must be generated explicitly 42 * by the client when appropriate: 43 * 44 * CE_LOGOUT_OTHER_CONN_RCV 45 * CE_ASYNC_DROP_CONN_RCV (Only because the message may be received on 46 * a different connection from the connection being dropped) 47 * CE_ASYNC_DROP_ALL_CONN_RCV 48 * CE_LOGOUT_OTHER_CONN_SND 49 * CE_ASYNC_DROP_ALL_CONN_SND 50 * 51 * The following events might occur in any state since they are driven 52 * by the PDU's that IDM receives: 53 * 54 * CE_LOGIN_RCV 55 * CE_LOGIN_SUCCESS_RCV 56 * CE_LOGIN_FAIL_RCV 57 * CE_LOGOUT_SUCCESS_RCV 58 * CE_LOGOUT_FAIL_RCV 59 * CE_ASYNC_LOGOUT_RCV 60 * CE_MISC_RCV 61 * CE_RX_PROTOCOL_ERROR 62 */ 63 64 #define IDM_LOGIN_SECONDS 20 65 #define IDM_LOGOUT_SECONDS 20 66 #define IDM_CLEANUP_SECONDS 0 67 68 #define IDM_CONN_EVENT_LIST() \ 69 item(CE_UNDEFINED) \ 70 /* Initiator events */ \ 71 item(CE_CONNECT_REQ) \ 72 item(CE_CONNECT_FAIL) \ 73 item(CE_CONNECT_SUCCESS) \ 74 item(CE_LOGIN_SND) \ 75 item(CE_LOGIN_SUCCESS_RCV) \ 76 item(CE_LOGIN_FAIL_RCV) \ 77 item(CE_LOGOUT_THIS_CONN_SND) \ 78 item(CE_LOGOUT_OTHER_CONN_SND) \ 79 item(CE_LOGOUT_SESSION_SND) \ 80 item(CE_LOGOUT_SUCCESS_RCV) \ 81 item(CE_LOGOUT_FAIL_RCV) \ 82 item(CE_ASYNC_LOGOUT_RCV) \ 83 item(CE_ASYNC_DROP_CONN_RCV) \ 84 item(CE_ASYNC_DROP_ALL_CONN_RCV) \ 85 /* Target events */ \ 86 item(CE_CONNECT_ACCEPT) \ 87 item(CE_CONNECT_REJECT) \ 88 item(CE_LOGIN_RCV) \ 89 item(CE_LOGIN_TIMEOUT) \ 90 item(CE_LOGIN_SUCCESS_SND) \ 91 item(CE_LOGIN_FAIL_SND) \ 92 item(CE_LOGIN_FAIL_SND_DONE) \ 93 item(CE_LOGOUT_THIS_CONN_RCV) \ 94 item(CE_LOGOUT_OTHER_CONN_RCV) \ 95 item(CE_LOGOUT_SESSION_RCV) \ 96 item(CE_LOGOUT_SUCCESS_SND) \ 97 item(CE_LOGOUT_SUCCESS_SND_DONE) \ 98 item(CE_LOGOUT_FAIL_SND) \ 99 item(CE_LOGOUT_FAIL_SND_DONE) \ 100 item(CE_CLEANUP_TIMEOUT) \ 101 item(CE_ASYNC_LOGOUT_SND) \ 102 item(CE_ASYNC_DROP_CONN_SND) \ 103 item(CE_ASYNC_DROP_ALL_CONN_SND) \ 104 item(CE_LOGOUT_TIMEOUT) \ 105 /* Common events */ \ 106 item(CE_TRANSPORT_FAIL) \ 107 item(CE_MISC_TX) \ 108 item(CE_TX_PROTOCOL_ERROR) \ 109 item(CE_MISC_RX) \ 110 item(CE_RX_PROTOCOL_ERROR) \ 111 item(CE_LOGOUT_SESSION_SUCCESS) \ 112 item(CE_CONN_REINSTATE) \ 113 item(CE_CONN_REINSTATE_SUCCESS) \ 114 item(CE_CONN_REINSTATE_FAIL) \ 115 item(CE_ENABLE_DM_SUCCESS) \ 116 item(CE_ENABLE_DM_FAIL) \ 117 /* Add new events above CE_MAX_EVENT */ \ 118 item(CE_MAX_EVENT) 119 120 /* Update idm_ce_name table whenever connection events are modified */ 121 typedef enum { 122 #define item(a) a, 123 IDM_CONN_EVENT_LIST() 124 #undef item 125 } idm_conn_event_t; 126 127 #ifdef IDM_CONN_SM_STRINGS 128 /* An array of event text values, for use in logging events */ 129 static const char *idm_ce_name[CE_MAX_EVENT+1] = { 130 #define item(a) #a, 131 IDM_CONN_EVENT_LIST() 132 #undef item 133 }; 134 #endif 135 136 #define CONN_STATE_LIST() \ 137 item(CS_S0_UNDEFINED) \ 138 item(CS_S1_FREE) \ 139 item(CS_S2_XPT_WAIT) \ 140 item(CS_S3_XPT_UP) \ 141 item(CS_S4_IN_LOGIN) \ 142 item(CS_S5_LOGGED_IN) \ 143 item(CS_S6_IN_LOGOUT) \ 144 item(CS_S7_LOGOUT_REQ) \ 145 item(CS_S8_CLEANUP) \ 146 item(CS_S9_INIT_ERROR) \ 147 item(CS_S10_IN_CLEANUP) \ 148 item(CS_S11_COMPLETE) \ 149 item(CS_S12_ENABLE_DM) \ 150 item(CS_S9A_REJECTED) \ 151 item(CS_S9B_WAIT_SND_DONE) \ 152 /* Add new connection states above CS_MAX_STATE */ \ 153 item(CS_MAX_STATE) 154 155 /* Update idm_cs_name table whenever connection states are modified */ 156 typedef enum { 157 #define item(a) a, 158 CONN_STATE_LIST() 159 #undef item 160 } idm_conn_state_t; 161 162 #ifdef IDM_CONN_SM_STRINGS 163 /* An array of state text values, for use in logging state transitions */ 164 static const char *idm_cs_name[CS_MAX_STATE+1] = { 165 #define item(a) #a, 166 CONN_STATE_LIST() 167 #undef item 168 }; 169 #endif 170 171 /* 172 * Currently the state machine has a condition where idm_login_timeout() is 173 * left active after the connection has been closed. This causes the system 174 * to panic when idm_login_timeout() modifies the freed memory. In an attempt 175 * to isolate and find this issue special attention is being placed on 176 * the ic_state_timeout value. After each untimeout call the value will now 177 * be cleared. Just before the value is set the code will check for 0 and 178 * display an error. One final change is being done in idm_conn_sm_fini() which 179 * if ic_state_machine is not 0, an error message will be displayed and 180 * untimeout() called. That should prevent customer sites from seeing the 181 * panic. The code also calls ASSERT(0) which should cause a panic during 182 * system test. 183 */ 184 #define IDM_SM_TIMER_CHECK(ic) \ 185 if (ic->ic_state_timeout) { \ 186 cmn_err(CE_WARN, "%s: existing timeout still set. " \ 187 "state: %s, last: %s\n", __func__, \ 188 idm_cs_name[ic->ic_state], \ 189 idm_cs_name[ic->ic_last_state]); \ 190 ASSERT(0); \ 191 } 192 193 #define IDM_SM_TIMER_CLEAR(ic) \ 194 (void) untimeout(ic->ic_state_timeout); \ 195 ic->ic_state_timeout = 0; 196 197 typedef enum { 198 CT_NONE = 0, 199 CT_RX_PDU, 200 CT_TX_PDU 201 } idm_pdu_event_type_t; 202 203 typedef enum { 204 CA_TX_PROTOCOL_ERROR, /* Send "protocol error" to state machine */ 205 CA_RX_PROTOCOL_ERROR, /* Send "protocol error" to state machine */ 206 CA_FORWARD, /* State machine event and forward to client */ 207 CA_DROP /* Drop PDU */ 208 } idm_pdu_event_action_t; 209 210 typedef struct { 211 struct idm_conn_s *iec_ic; 212 idm_conn_event_t iec_event; 213 uintptr_t iec_info; 214 idm_pdu_event_type_t iec_pdu_event_type; 215 boolean_t iec_pdu_forwarded; 216 } idm_conn_event_ctx_t; 217 218 idm_status_t 219 idm_conn_sm_init(struct idm_conn_s *ic); 220 221 void 222 idm_conn_sm_fini(struct idm_conn_s *ic); 223 224 idm_status_t 225 idm_notify_client(struct idm_conn_s *ic, idm_client_notify_t cn, 226 uintptr_t data); 227 228 void 229 idm_conn_event(struct idm_conn_s *ic, idm_conn_event_t event, uintptr_t data); 230 231 void 232 idm_conn_event(struct idm_conn_s *ic, idm_conn_event_t event, uintptr_t data); 233 234 void 235 idm_conn_event_locked(struct idm_conn_s *ic, idm_conn_event_t event, 236 uintptr_t event_info, idm_pdu_event_type_t pdu_event_type); 237 238 idm_status_t 239 idm_conn_reinstate_event(struct idm_conn_s *old_ic, struct idm_conn_s *new_ic); 240 241 void 242 idm_conn_tx_pdu_event(struct idm_conn_s *ic, idm_conn_event_t event, 243 uintptr_t data); 244 245 void 246 idm_conn_rx_pdu_event(struct idm_conn_s *ic, idm_conn_event_t event, 247 uintptr_t data); 248 249 char * 250 idm_conn_state_str(struct idm_conn_s *ic); 251 252 #ifdef __cplusplus 253 } 254 #endif 255 256 #endif /* _IDM_CONN_SM_H_ */ 257