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
sol_cma_any_addr(struct sockaddr * addr)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 *
cma_create_new_id(struct rdma_cm_id * srcid)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 *
cma_get_req_idp(struct rdma_cm_id * root_idp,void * qp_hdl)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 *
cma_get_acpt_idp(struct rdma_cm_id * root_idp,void * qp_hdl)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