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 /* Update idm_ce_name table whenever connection events are modified */
  69 typedef enum {
  70         CE_UNDEFINED = 0,
  71 
  72         /* Initiator events */
  73         CE_CONNECT_REQ,
  74         CE_CONNECT_FAIL,
  75         CE_CONNECT_SUCCESS,
  76         CE_LOGIN_SND,
  77         CE_LOGIN_SUCCESS_RCV,
  78         CE_LOGIN_FAIL_RCV,
  79         CE_LOGOUT_THIS_CONN_SND,
  80         CE_LOGOUT_OTHER_CONN_SND,
  81         CE_LOGOUT_SESSION_SND,
  82         CE_LOGOUT_SUCCESS_RCV,
  83         CE_LOGOUT_FAIL_RCV,
  84         CE_ASYNC_LOGOUT_RCV,
  85         CE_ASYNC_DROP_CONN_RCV,
  86         CE_ASYNC_DROP_ALL_CONN_RCV,
  87 
  88         /* Target events */
  89         CE_CONNECT_ACCEPT,
  90         CE_CONNECT_REJECT,
  91         CE_LOGIN_RCV,
  92         CE_LOGIN_TIMEOUT,
  93         CE_LOGIN_SUCCESS_SND,
  94         CE_LOGIN_FAIL_SND,
  95         CE_LOGIN_FAIL_SND_DONE,
  96         CE_LOGOUT_THIS_CONN_RCV,
  97         CE_LOGOUT_OTHER_CONN_RCV,
  98         CE_LOGOUT_SESSION_RCV,
  99         CE_LOGOUT_SUCCESS_SND,
 100         CE_LOGOUT_SUCCESS_SND_DONE,
 101         CE_LOGOUT_FAIL_SND,
 102         CE_LOGOUT_FAIL_SND_DONE,
 103         CE_CLEANUP_TIMEOUT,
 104         CE_ASYNC_LOGOUT_SND,
 105         CE_ASYNC_DROP_CONN_SND,
 106         CE_ASYNC_DROP_ALL_CONN_SND,
 107         CE_LOGOUT_TIMEOUT,
 108 
 109         /* Common events */
 110         CE_TRANSPORT_FAIL,
 111         CE_MISC_TX,
 112         CE_TX_PROTOCOL_ERROR,
 113         CE_MISC_RX,
 114         CE_RX_PROTOCOL_ERROR,
 115         CE_LOGOUT_SESSION_SUCCESS,
 116         CE_CONN_REINSTATE,
 117         CE_CONN_REINSTATE_SUCCESS,
 118         CE_CONN_REINSTATE_FAIL,
 119         CE_ENABLE_DM_SUCCESS,
 120         CE_ENABLE_DM_FAIL,
 121 
 122         /* Add new events above CE_MAX_EVENT */
 123         CE_MAX_EVENT
 124 } idm_conn_event_t;
 125 
 126 #ifdef IDM_CONN_SM_STRINGS
 127 /* An array of event text values, for use in logging events */
 128 static const char *idm_ce_name[CE_MAX_EVENT+1] = {
 129         "CE_UNDEFINED",
 130         "CE_CONNECT_REQ",
 131         "CE_CONNECT_FAIL",
 132         "CE_CONNECT_SUCCESS",
 133         "CE_LOGIN_SND",
 134         "CE_LOGIN_SUCCESS_RCV",
 135         "CE_LOGIN_FAIL_RCV",
 136         "CE_LOGOUT_THIS_CONN_SND",
 137         "CE_LOGOUT_OTHER_CONN_SND",
 138         "CE_LOGOUT_SESSION_SND",
 139         "CE_LOGOUT_SUCCESS_RCV",
 140         "CE_LOGOUT_FAIL_RCV",
 141         "CE_ASYNC_LOGOUT_RCV",
 142         "CE_ASYNC_DROP_CONN_RCV",
 143         "CE_ASYNC_DROP_ALL_CONN_RCV",
 144         "CE_CONNECT_ACCEPT",
 145         "CE_CONNECT_REJECT",
 146         "CE_LOGIN_RCV",
 147         "CE_LOGIN_TIMEOUT",
 148         "CE_LOGIN_SUCCESS_SND",
 149         "CE_LOGIN_FAIL_SND",
 150         "CE_LOGIN_FAIL_SND_DONE",
 151         "CE_LOGOUT_THIS_CONN_RCV",
 152         "CE_LOGOUT_OTHER_CONN_RCV",
 153         "CE_LOGOUT_SESSION_RCV",
 154         "CE_LOGOUT_SUCCESS_SND",
 155         "CE_LOGOUT_SUCCESS_SND_DONE",
 156         "CE_LOGOUT_FAIL_SND",
 157         "CE_LOGOUT_FAIL_SND_DONE",
 158         "CE_CLEANUP_TIMEOUT",
 159         "CE_ASYNC_LOGOUT_SND",
 160         "CE_ASYNC_DROP_CONN_SND",
 161         "CE_ASYNC_DROP_ALL_CONN_SND",
 162         "CE_LOGOUT_TIMEOUT",
 163         "CE_TRANSPORT_FAIL",
 164         "CE_MISC_TX",
 165         "CE_TX_PROTOCOL_ERROR",
 166         "CE_MISC_RX",
 167         "CE_RX_PROTOCOL_ERROR",
 168         "CE_LOGOUT_SESSION_SUCCESS",
 169         "CE_CONN_REINSTATE",
 170         "CE_CONN_REINSTATE_SUCCESS",
 171         "CE_CONN_REINSTATE_FAIL",
 172         "CE_ENABLE_DM_SUCCESS",
 173         "CE_ENABLE_DM_FAIL",
 174         "CE_MAX_EVENT"
 175 };
 176 #endif
 177 
 178 /* Update idm_cs_name table whenever connection states are modified */
 179 typedef enum {
 180         CS_S0_UNDEFINED = 0,
 181 
 182         CS_S1_FREE,
 183         CS_S2_XPT_WAIT,
 184         CS_S3_XPT_UP,
 185         CS_S4_IN_LOGIN,
 186         CS_S5_LOGGED_IN,
 187         CS_S6_IN_LOGOUT,
 188         CS_S7_LOGOUT_REQ,
 189         CS_S8_CLEANUP,
 190         CS_S9_INIT_ERROR,
 191         CS_S10_IN_CLEANUP,
 192         CS_S11_COMPLETE,
 193         CS_S12_ENABLE_DM,
 194         CS_S9A_REJECTED,
 195         CS_S9B_WAIT_SND_DONE,
 196 
 197         /* Add new connection states above CS_MAX_STATE */
 198         CS_MAX_STATE
 199 } idm_conn_state_t;
 200 
 201 #ifdef IDM_CONN_SM_STRINGS
 202 /* An array of state text values, for use in logging state transitions */
 203 static const char *idm_cs_name[CS_MAX_STATE+1] = {
 204         "CS_S0_UNDEFINED",
 205         "CS_S1_FREE",
 206         "CS_S2_XPT_WAIT",
 207         "CS_S3_XPT_UP",
 208         "CS_S4_IN_LOGIN",
 209         "CS_S5_LOGGED_IN",
 210         "CS_S6_IN_LOGOUT",
 211         "CS_S7_LOGOUT_REQ",
 212         "CS_S8_CLEANUP",
 213         "CS_S9_INIT_ERROR",
 214         "CS_S10_IN_CLEANUP",
 215         "CS_S11_COMPLETE",
 216         "CS_S12_ENABLE_DM",
 217         "CS_S9A_REJECTED",
 218         "CS_S9B_WAIT_SND_DONE",
 219         "CS_MAX_STATE"
 220 };
 221 #endif
 222 
 223 /*
 224  * Currently the state machine has a condition where idm_login_timeout() is
 225  * left active after the connection has been closed. This causes the system
 226  * to panic when idm_login_timeout() modifies the freed memory. In an attempt
 227  * to isolate and find this issue special attention is being placed on
 228  * the ic_state_timeout value. After each untimeout call the value will now
 229  * be cleared. Just before the value is set the code will check for 0 and
 230  * display an error. One final change is being done in idm_conn_sm_fini() which
 231  * if ic_state_machine is not 0, an error message will be displayed and
 232  * untimeout() called. That should prevent customer sites from seeing the
 233  * panic. The code also calls ASSERT(0) which should cause a panic during
 234  * system test.
 235  */
 236 #define IDM_SM_TIMER_CHECK(ic) \
 237         if (ic->ic_state_timeout) { \
 238                 cmn_err(CE_WARN, "%s: existing timeout still set. " \
 239                     "state: %s, last: %s\n", __func__, \
 240                     idm_cs_name[ic->ic_state], \
 241                     idm_cs_name[ic->ic_last_state]); \
 242                 ASSERT(0); \
 243         }
 244 
 245 #define IDM_SM_TIMER_CLEAR(ic) \
 246         (void) untimeout(ic->ic_state_timeout); \
 247         ic->ic_state_timeout = 0;
 248 
 249 typedef enum {
 250         CT_NONE = 0,
 251         CT_RX_PDU,
 252         CT_TX_PDU
 253 } idm_pdu_event_type_t;
 254 
 255 typedef enum {
 256         CA_TX_PROTOCOL_ERROR,   /* Send "protocol error" to state machine */
 257         CA_RX_PROTOCOL_ERROR,   /* Send "protocol error" to state machine */
 258         CA_FORWARD,             /* State machine event and forward to client */
 259         CA_DROP                 /* Drop PDU */
 260 } idm_pdu_event_action_t;
 261 
 262 typedef struct {
 263         struct idm_conn_s       *iec_ic;
 264         idm_conn_event_t        iec_event;
 265         uintptr_t               iec_info;
 266         idm_pdu_event_type_t    iec_pdu_event_type;
 267         boolean_t               iec_pdu_forwarded;
 268 } idm_conn_event_ctx_t;
 269 
 270 idm_status_t
 271 idm_conn_sm_init(struct idm_conn_s *ic);
 272 
 273 void
 274 idm_conn_sm_fini(struct idm_conn_s *ic);
 275 
 276 idm_status_t
 277 idm_notify_client(struct idm_conn_s *ic, idm_client_notify_t cn,
 278     uintptr_t data);
 279 
 280 void
 281 idm_conn_event(struct idm_conn_s *ic, idm_conn_event_t event, uintptr_t data);
 282 
 283 void
 284 idm_conn_event(struct idm_conn_s *ic, idm_conn_event_t event, uintptr_t data);
 285 
 286 void
 287 idm_conn_event_locked(struct idm_conn_s *ic, idm_conn_event_t event,
 288     uintptr_t event_info, idm_pdu_event_type_t pdu_event_type);
 289 
 290 idm_status_t
 291 idm_conn_reinstate_event(struct idm_conn_s *old_ic, struct idm_conn_s *new_ic);
 292 
 293 void
 294 idm_conn_tx_pdu_event(struct idm_conn_s *ic, idm_conn_event_t event,
 295     uintptr_t data);
 296 
 297 void
 298 idm_conn_rx_pdu_event(struct idm_conn_s *ic, idm_conn_event_t event,
 299     uintptr_t data);
 300 
 301 char *
 302 idm_conn_state_str(struct idm_conn_s *ic);
 303 
 304 #ifdef  __cplusplus
 305 }
 306 #endif
 307 
 308 #endif /* _IDM_CONN_SM_H_ */