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_ */