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 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 * 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 * 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 * 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