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