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