xref: /illumos-gate/usr/src/uts/common/sys/idm/idm_conn_sm.h (revision b1e2e3fb17324e9ddf43db264a0c64da7756d9e6)
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_ */
309