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