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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #ifndef _SYS_IB_CLIENTS_OF_SOL_OFS_SOL_CMA_H
27 #define	_SYS_IB_CLIENTS_OF_SOL_OFS_SOL_CMA_H
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32 
33 #include <sys/sysmacros.h>
34 
35 #include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h>
36 #include <sys/ib/clients/of/rdma/rdma_cm.h>
37 #include <sys/ib/clients/of/sol_ofs/sol_ib_cma.h> /* Transport Specific */
38 
39 
40 #define	IS_UDP_CMID(idp)	((idp)->ps == RDMA_PS_UDP || \
41 	(idp)->ps == RDMA_PS_IPOIB)
42 #define	IS_VALID_SOCKADDR(sockaddrp) \
43 	((sockaddrp)->sa_family == AF_INET || \
44 	(sockaddrp)->sa_family == AF_INET6)
45 
46 /*
47  * Global structure which contains information about all
48  * CMIDs, which have called rdma_listen().
49  */
50 typedef struct sol_cma_glbl_listen_s {
51 	avl_node_t	cma_listen_node;
52 
53 	uint64_t	cma_listen_chan_sid;
54 	void		*cma_listen_clnt_hdl;
55 	void		*cma_listen_svc_hdl;
56 	genlist_t	cma_listen_chan_list;
57 } sol_cma_glbl_listen_t;
58 
59 /* State of the RDMA-CM ID */
60 typedef enum {
61 	SOL_CMA_CHAN_IDLE,
62 	SOL_CMA_CHAN_BOUND,
63 	SOL_CMA_CHAN_ADDR_QUERY,
64 	SOL_CMA_CHAN_ADDR_BOUND,
65 	SOL_CMA_CHAN_ADDR_RESLVD,
66 	SOL_CMA_CHAN_ROUTE_QUERY,
67 	SOL_CMA_CHAN_ROUTE_RESLVD,
68 
69 	SOL_CMA_CHAN_EVENT_NOTIFIED,
70 
71 	SOL_CMA_CHAN_CONNECT,
72 	SOL_CMA_CHAN_LISTEN,
73 	SOL_CMA_CHAN_DISCONNECT,
74 	SOL_CMA_CHAN_ACCEPT,
75 	SOL_CMA_CHAN_REJECT,
76 
77 	SOL_CMA_CHAN_DESTROYING,
78 	SOL_CMA_CHAN_DESTROY_PENDING,
79 	SOL_CMA_CHAN_DESTROY_WAIT,
80 
81 	SOL_CMA_CHAN_HCA_DOWN,
82 	SOL_CMA_CHAN_PORT_DOWN
83 } cma_chan_state_t;
84 
85 typedef struct listen_info_s {
86 	uint8_t			listen_is_root;
87 
88 	/* For Root CMIDs, pointer to global listen info */
89 	genlist_entry_t		*listen_entry;
90 	sol_cma_glbl_listen_t	*chan_glbl_listen_info;
91 
92 	/*
93 	 * For EP CMIDs, pointer to ib_device and root CMID
94 	 * for HCA DR
95 	 */
96 	genlist_entry_t		*listen_ep_dev_entry;
97 	genlist_entry_t		*listen_ep_root_entry;
98 	struct ib_device	*listen_ep_device;
99 
100 	/*
101 	 * Count & list of EPs for this listen_info.
102 	 * This is 0, if listen_is_root is 0.
103 	 */
104 	uint32_t		listen_eps;
105 	genlist_t		listen_list;
106 
107 	/* Transport Specific */
108 	union {
109 		/* For Root CMID */
110 		ibt_srv_hdl_t	_listen_srv_hdl;
111 
112 		/* For Endpoint CMID */
113 		ibt_sbind_hdl_t	_listen_sbind_hdl;
114 	} un_listen;
115 #define	listen_ib_srv_hdl	un_listen._listen_srv_hdl
116 #define	listen_ib_sbind_hdl	un_listen._listen_sbind_hdl
117 } sol_cma_listen_info_t;
118 
119 typedef enum {
120 	SOL_CMA_XPORT_NONE = 0,
121 	SOL_CMA_XPORT_IB,
122 	SOL_CMA_XPORT_IWARP
123 } sol_cma_xport_type_t;
124 
125 /*
126  * This is used to track the state of a client side CMID.
127  * 	CONNECT_NONE	Server side CMID, or CMID for which
128  * 			rdma_connect() has not been called.
129  *
130  * 	CLIENT_NONE	Client side CMID for which connection
131  * 			has been torn down.
132  *
133  * 			For UDP it also represents connection
134  * 			established (no more IBTF CM events
135  * 			expected).
136  *
137  * 	INITIATED	rdma_connect() has been called not yet
138  * 			established.
139  *
140  * 	ESTABLISHED	Client CMID has connection established.
141  */
142 typedef enum {
143 	SOL_CMA_CONNECT_NONE = 0,
144 	SOL_CMA_CONNECT_CLIENT_NONE,
145 	SOL_CMA_CONNECT_INITIATED,
146 	SOL_CMA_CONNECT_ESTABLISHED,
147 } sol_cma_connect_flag_t;
148 
149 /*
150  * This is used to track the state of CMIDs created for Connection
151  * Requests and listening CMID.
152  *
153  * 	NONE		Client CMID, listen CMID with no REQs yet.
154  *
155  * 	SERVER_DONE	REQ CMID connection done, no more events.
156  *
157  * 			For listening CMID all REQ CMIDs have events
158  * 			completed.
159  *
160  * 	CREATED		listening CMID with > 1 REQ CMID with events
161  * 			pending.
162  *
163  * 	QUEUED		REQ CMID in REQ AVL tree of listening CMID
164  *
165  * 	ACCEPTED	REQ CMID accepted and in ACPT AVL tree of the
166  * 			listening CMID.
167  */
168 typedef enum {
169 	REQ_CMID_NONE = 0,
170 	REQ_CMID_SERVER_NONE,
171 	REQ_CMID_CREATED,
172 	REQ_CMID_QUEUED,
173 	REQ_CMID_NOTIFIED,
174 	REQ_CMID_ACCEPTED,
175 } cma_req_cmid_state_t;
176 
177 #define	SOL_IS_SERVER_CMID(chanp)	\
178 	((chanp)->chan_req_state != REQ_CMID_NONE)
179 #define	SOL_IS_CLIENT_CMID(chanp)	\
180 	((chanp)->chan_connect_flag != SOL_CMA_CONNECT_NONE)
181 
182 #define	REQ_CMID_IN_REQ_AVL_TREE(chanp)	\
183 	((chanp)->chan_req_state == REQ_CMID_QUEUED ||	\
184 	(chanp)->chan_req_state == REQ_CMID_NOTIFIED)
185 #define	SOL_CMID_CLOSE_REQUIRED(chanp)		\
186 	((chanp)->chan_connect_flag == SOL_CMA_CONNECT_INITIATED ||	\
187 	(chanp)->chan_connect_flag == SOL_CMA_CONNECT_ESTABLISHED || \
188 	(chanp)->chan_req_state == REQ_CMID_ACCEPTED)
189 #define	SOL_CMAID_CONNECTED(chanp)	\
190 	(SOL_CMID_CLOSE_REQUIRED(chanp) ||	\
191 	(chanp)->chan_req_state  ==  REQ_CMID_NOTIFIED)
192 
193 /*
194  * CMID_DESTROYED	- Flag to indicate rdma_destroy_id has been
195  * 			called for this CMID
196  *
197  * EVENT_PROGRESS	- RDMACM Event for this CMID been passed to
198  * 			the sol_ofs client.
199  *
200  * API_PROGRESS		- rdma_resolve_addr() / rdma_resolve_route() /
201  *			rdma_listen() is in progress.
202  */
203 #define	SOL_CMA_CALLER_CMID_DESTROYED		0x01
204 #define	SOL_CMA_CALLER_EVENT_PROGRESS		0x02
205 #define	SOL_CMA_CALLER_API_PROGRESS		0x04
206 
207 typedef struct {
208 	struct rdma_cm_id	chan_rdma_cm;
209 
210 	/*
211 	 * Below are all CMA Channel specific fields required in Solaris,
212 	 * apart from rdma_cm_id.
213 	 */
214 
215 	/* AVL Tree for REQs and EST CMIDs */
216 	avl_node_t		chan_req_avl_node;
217 	avl_node_t		chan_acpt_avl_node;
218 	avl_tree_t		chan_req_avl_tree;
219 	avl_tree_t		chan_acpt_avl_tree;
220 
221 	/*
222 	 * chan_req_cnt -
223 	 *	REQ CMIDs created not yet notified to client
224 	 * chan_total_req_cnt -
225 	 *	REQ CMIDs created not destroy_id(0 not called.
226 	 */
227 	uint64_t		chan_req_cnt;
228 	uint64_t		chan_req_total_cnt;
229 
230 
231 	/* State for Server side and client side CMIDs */
232 	cma_req_cmid_state_t	chan_req_state;
233 	sol_cma_connect_flag_t	chan_connect_flag;
234 
235 	kmutex_t		chan_mutex;
236 	kcondvar_t		chan_destroy_cv;
237 	cma_chan_state_t	chan_state;
238 	uint8_t			chan_cmid_destroy_state;
239 
240 	/*
241 	 * Transport type for the rdma_id, IB or IWARP. This is set to
242 	 * NONE, when the transport type is not yet determined.
243 	 */
244 	sol_cma_xport_type_t	chan_xport_type;
245 
246 	/*
247 	 * Passed from sol_ofs consumer, using the rdma_map_id2clnthdl
248 	 * and rdma_map_id2qphdl
249 	 */
250 	void			*chan_ib_client_hdl;
251 	void			*chan_iw_client_hdl;
252 	void			*chan_qp_hdl;
253 
254 	/* Data for root / endpoint CM ID. */
255 	sol_cma_listen_info_t	*chan_listenp;
256 
257 	/* Ptr to the root CMID for Endpoint & Req CMID */
258 	struct rdma_cm_id	*listen_root;
259 #define	CHAN_LISTEN_LIST(chanp)	(((chanp)->chan_listenp)->listen_list)
260 #define	CHAN_LISTEN_ROOT(chanp)	((chanp)->listen_root)
261 
262 	struct rdma_conn_param	chan_param;
263 
264 	/* Session ID for completion */
265 	void			*chan_session_id;
266 
267 	uint32_t		chan_qp_num;
268 	uint8_t			chan_is_srq;
269 
270 	union {
271 		ibcma_chan_t	chan_ib_xport;
272 	} un_xport;	/* Transport specific fields */
273 #define	chan_ib			un_xport.chan_ib_xport
274 } sol_cma_chan_t;
275 
276 void ibcma_append_listen_list(struct rdma_cm_id *);
277 #ifdef	IWARP_SUPPORT
278 void iwcma_append_listen_list(struct rdma_cm_id *);
279 #endif
280 
281 
282 extern void cma_generate_event(struct rdma_cm_id *, enum rdma_cm_event_type,
283     int, struct rdma_conn_param *, struct rdma_ud_param *);
284 extern struct ib_device *sol_cma_acquire_device(ib_guid_t);
285 
286 static inline int
sol_cma_any_addr(struct sockaddr * addr)287 sol_cma_any_addr(struct sockaddr *addr)
288 {
289 	ASSERT(addr);
290 	if (addr->sa_family == AF_INET) {
291 		struct sockaddr_in	*in_addr;
292 		in_addr = (struct sockaddr_in *)addr;
293 
294 		return (in_addr->sin_addr.s_addr == INADDR_ANY);
295 	} else if (addr->sa_family == AF_INET6) {
296 		struct sockaddr_in6	*in6_addr;
297 		in6_addr = (struct sockaddr_in6 *)addr;
298 
299 		return (IN6_IS_ADDR_UNSPECIFIED(&(in6_addr->sin6_addr)));
300 	}
301 	return (0);
302 }
303 
304 static inline struct rdma_cm_id *
cma_create_new_id(struct rdma_cm_id * srcid)305 cma_create_new_id(struct rdma_cm_id *srcid)
306 {
307 	struct	rdma_cm_id	*newid;
308 	sol_cma_chan_t		*new_chanp, *src_chanp;
309 
310 	newid = rdma_create_id(srcid->event_handler, srcid->context,
311 	    srcid->ps);
312 	if (newid == NULL)
313 		return (newid);
314 
315 	if (srcid->device) {
316 		newid->device =
317 		    sol_cma_acquire_device(srcid->device->node_guid);
318 	}
319 	bcopy(&((srcid->route).addr), &((newid->route).addr),
320 	    sizeof (struct rdma_addr));
321 	if ((srcid->route).num_paths) {
322 		int	num_paths;
323 
324 		num_paths = (newid->route).num_paths =
325 		    (srcid->route).num_paths;
326 		(newid->route).path_rec = kmem_zalloc(num_paths *
327 		    sizeof (struct ib_sa_path_rec), KM_SLEEP);
328 		bcopy(&((srcid->route).path_rec),
329 		    &((newid->route).path_rec),
330 		    num_paths * sizeof (struct ib_sa_path_rec));
331 	}
332 	newid->port_num = srcid->port_num;
333 
334 	new_chanp = (sol_cma_chan_t *)newid;
335 	src_chanp = (sol_cma_chan_t *)srcid;
336 	new_chanp->chan_state = src_chanp->chan_state;
337 	new_chanp->chan_xport_type = src_chanp->chan_xport_type;
338 	if (CHAN_LISTEN_ROOT(src_chanp))
339 		CHAN_LISTEN_ROOT(new_chanp) =  CHAN_LISTEN_ROOT(src_chanp);
340 	else
341 		CHAN_LISTEN_ROOT(new_chanp) = srcid;
342 	return (newid);
343 }
344 
345 
346 static inline struct rdma_cm_id *
cma_get_req_idp(struct rdma_cm_id * root_idp,void * qp_hdl)347 cma_get_req_idp(struct rdma_cm_id *root_idp, void *qp_hdl)
348 {
349 	struct rdma_cm_id	*req_idp;
350 	sol_cma_chan_t		*root_chanp;
351 
352 	root_chanp = (sol_cma_chan_t *)root_idp;
353 	ASSERT(MUTEX_HELD(&root_chanp->chan_mutex));
354 	req_idp = (struct rdma_cm_id *)avl_find(
355 	    &root_chanp->chan_req_avl_tree, (void *)qp_hdl, NULL);
356 	return (req_idp);
357 }
358 
359 static inline struct rdma_cm_id *
cma_get_acpt_idp(struct rdma_cm_id * root_idp,void * qp_hdl)360 cma_get_acpt_idp(struct rdma_cm_id *root_idp, void *qp_hdl)
361 {
362 	struct rdma_cm_id	*acpt_idp;
363 	sol_cma_chan_t		*root_chanp;
364 
365 	root_chanp = (sol_cma_chan_t *)root_idp;
366 	ASSERT(MUTEX_HELD(&root_chanp->chan_mutex));
367 	acpt_idp = (struct rdma_cm_id *)avl_find(
368 	    &root_chanp->chan_acpt_avl_tree, (void *)qp_hdl, NULL);
369 	return (acpt_idp);
370 }
371 #ifdef __cplusplus
372 }
373 #endif
374 
375 #endif	/* _SYS_IB_CLIENTS_OF_SOL_OFS_SOL_CMA_H */
376