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