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