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 /* 27 * sol_cma is a part of sol_ofs misc module. This file 28 * provides interfaces for supporting the communication 29 * management API defined in "rdma_cm.h". In-Kernel 30 * consumers of the "rdma_cm.h" API should link sol_ofs 31 * misc module using : 32 * -N misc/sol_ofs 33 * Solaris uCMA (sol_ucma) driver is the current consumer for 34 * sol_cma. 35 */ 36 37 /* Standard driver includes */ 38 #include <sys/types.h> 39 #include <sys/modctl.h> 40 #include <sys/errno.h> 41 #include <sys/stat.h> 42 #include <sys/ddi.h> 43 #include <sys/sunddi.h> 44 #include <sys/modctl.h> 45 46 #include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h> 47 #include <sys/ib/clients/of/ofed_kernel.h> 48 #include <sys/ib/clients/of/rdma/ib_addr.h> 49 #include <sys/ib/clients/of/rdma/rdma_cm.h> 50 51 #include <sys/ib/clients/of/sol_ofs/sol_cma.h> 52 #include <sys/ib/clients/of/sol_ofs/sol_kverb_impl.h> 53 54 /* Modload support */ 55 static struct modlmisc sol_ofs_modmisc = { 56 &mod_miscops, 57 "Solaris OFS Misc module" 58 }; 59 60 struct modlinkage sol_ofs_modlinkage = { 61 MODREV_1, 62 (void *)&sol_ofs_modmisc, 63 NULL 64 }; 65 66 static ib_client_t *sol_cma_ib_client; 67 sol_cma_glbl_listen_t sol_cma_glbl_listen; 68 avl_tree_t sol_cma_glbl_listen_tree; 69 70 static void sol_cma_add_dev(struct ib_device *); 71 static void sol_cma_rem_dev(struct ib_device *); 72 73 static llist_head_t sol_cma_dev_list = LLIST_HEAD_INIT(sol_cma_dev_list); 74 kmutex_t sol_cma_dev_mutex; 75 kmutex_t sol_cma_glob_mutex; 76 77 char *sol_rdmacm_dbg_str = "sol_rdmacm"; 78 char *sol_ofs_dbg_str = "sol_ofs_mod"; 79 80 /* 81 * Local functions defines. 82 */ 83 int sol_cma_req_cmid_cmp(const void *p1, const void *p2); 84 int sol_cma_cmid_cmp(const void *p1, const void *p2); 85 int sol_cma_svc_cmp(const void *, const void *); 86 87 static struct rdma_cm_id *cma_alloc_chan(rdma_cm_event_handler, 88 void *, enum rdma_port_space); 89 static void cma_set_chan_state(sol_cma_chan_t *, cma_chan_state_t); 90 static int cma_cas_chan_state(sol_cma_chan_t *, cma_chan_state_t, 91 cma_chan_state_t); 92 static void cma_free_listen_list(struct rdma_cm_id *); 93 static void cma_destroy_id(struct rdma_cm_id *); 94 static void cma_handle_nomore_events(sol_cma_chan_t *); 95 96 extern void sol_ofs_dprintf_init(); 97 extern void sol_ofs_dprintf_fini(); 98 99 cma_chan_state_t cma_get_chan_state(sol_cma_chan_t *); 100 extern int ibcma_init_root_chan(sol_cma_chan_t *, sol_cma_glbl_listen_t *); 101 extern int ibcma_fini_root_chan(sol_cma_chan_t *); 102 extern void ibcma_copy_srv_hdl(sol_cma_chan_t *, sol_cma_glbl_listen_t *); 103 extern int ibcma_fini_ep_chan(sol_cma_chan_t *); 104 extern uint64_t ibcma_init_root_sid(sol_cma_chan_t *); 105 extern void rdma_ib_destroy_id(struct rdma_cm_id *); 106 extern int rdma_ib_bind_addr(struct rdma_cm_id *, struct sockaddr *); 107 extern int rdma_ib_resolve_addr(struct rdma_cm_id *, struct sockaddr *, 108 struct sockaddr *, int); 109 extern int rdma_ib_resolve_route(struct rdma_cm_id *, int); 110 extern int rdma_ib_init_qp_attr(struct rdma_cm_id *, struct ib_qp_attr *, 111 int *); 112 extern int rdma_ib_connect(struct rdma_cm_id *, struct rdma_conn_param *); 113 extern int rdma_ib_listen(struct rdma_cm_id *, int); 114 extern int rdma_ib_accept(struct rdma_cm_id *, struct rdma_conn_param *); 115 extern int rdma_ib_reject(struct rdma_cm_id *, const void *, uint8_t); 116 extern int rdma_ib_disconnect(struct rdma_cm_id *); 117 extern int rdma_ib_join_multicast(struct rdma_cm_id *, struct sockaddr *, 118 void *); 119 extern void rdma_ib_leave_multicast(struct rdma_cm_id *, struct sockaddr *); 120 121 int 122 _init(void) 123 { 124 int err; 125 126 sol_ofs_dprintf_init(); 127 SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "_init()"); 128 129 mutex_init(&sol_cma_glob_mutex, NULL, MUTEX_DRIVER, NULL); 130 mutex_init(&sol_cma_dev_mutex, NULL, MUTEX_DRIVER, NULL); 131 avl_create(&sol_cma_glbl_listen_tree, 132 sol_cma_svc_cmp, sizeof (sol_cma_glbl_listen_t), 133 offsetof(sol_cma_glbl_listen_t, cma_listen_node)); 134 135 sol_cma_ib_client = kmem_zalloc(sizeof (ib_client_t), KM_NOSLEEP); 136 if (!sol_cma_ib_client) { 137 SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str, 138 "_init() - mem alloc failed"); 139 avl_destroy(&sol_cma_glbl_listen_tree); 140 mutex_destroy(&sol_cma_dev_mutex); 141 mutex_destroy(&sol_cma_glob_mutex); 142 sol_ofs_dprintf_fini(); 143 return (ENOMEM); 144 } 145 146 sol_cma_ib_client->name = "sol_ofs"; 147 sol_cma_ib_client->add = sol_cma_add_dev; 148 sol_cma_ib_client->remove = sol_cma_rem_dev; 149 sol_cma_ib_client->dip = NULL; 150 151 if ((err = ib_register_client(sol_cma_ib_client)) != 0) { 152 SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str, 153 "_init() ib_register_client() failed with err %d", 154 err); 155 kmem_free(sol_cma_ib_client, sizeof (ib_client_t)); 156 avl_destroy(&sol_cma_glbl_listen_tree); 157 mutex_destroy(&sol_cma_dev_mutex); 158 mutex_destroy(&sol_cma_glob_mutex); 159 sol_ofs_dprintf_fini(); 160 return (err); 161 } 162 163 if ((err = mod_install(&sol_ofs_modlinkage)) != 0) { 164 SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str, 165 "_init() - mod_install() failed"); 166 ib_unregister_client(sol_cma_ib_client); 167 kmem_free(sol_cma_ib_client, sizeof (ib_client_t)); 168 avl_destroy(&sol_cma_glbl_listen_tree); 169 mutex_destroy(&sol_cma_dev_mutex); 170 mutex_destroy(&sol_cma_glob_mutex); 171 sol_ofs_dprintf_fini(); 172 return (err); 173 } 174 175 SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "_init() - ret"); 176 return (err); 177 } 178 179 int 180 _fini(void) 181 { 182 int err; 183 184 SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "_fini()"); 185 186 if (avl_numnodes(&sol_cma_glbl_listen_tree)) { 187 SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str, "_fini - " 188 "listen CMIDs still active"); 189 return (EBUSY); 190 } 191 if ((err = mod_remove(&sol_ofs_modlinkage)) != 0) { 192 SOL_OFS_DPRINTF_L3(sol_ofs_dbg_str, 193 "_fini: mod_remove failed"); 194 return (err); 195 } 196 197 ib_unregister_client(sol_cma_ib_client); 198 kmem_free(sol_cma_ib_client, sizeof (ib_client_t)); 199 avl_destroy(&sol_cma_glbl_listen_tree); 200 mutex_destroy(&sol_cma_dev_mutex); 201 mutex_destroy(&sol_cma_glob_mutex); 202 SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "_fini() - ret"); 203 sol_ofs_dprintf_fini(); 204 return (err); 205 } 206 207 int 208 _info(struct modinfo *modinfop) 209 { 210 return (mod_info(&sol_ofs_modlinkage, modinfop)); 211 } 212 213 typedef struct cma_device { 214 kmutex_t cma_mutex; 215 llist_head_t cma_list; 216 genlist_t cma_epchan_list; 217 struct ib_device *cma_device; 218 uint_t cma_ref_count; 219 enum { 220 SOL_CMA_DEV_ADDED, 221 SOL_CMA_DEV_REM_IN_PROGRESS 222 } cma_dev_state; 223 } cma_device_t; 224 225 static void 226 sol_cma_add_dev(struct ib_device *dev) 227 { 228 cma_device_t *new_device; 229 230 new_device = kmem_zalloc(sizeof (cma_device_t), KM_NOSLEEP); 231 if (!new_device) { 232 SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str, "sol_cma_add_dev() " 233 "alloc failed!!"); 234 return; 235 } 236 mutex_init(&new_device->cma_mutex, NULL, MUTEX_DRIVER, NULL); 237 llist_head_init(&new_device->cma_list, new_device); 238 init_genlist(&new_device->cma_epchan_list); 239 new_device->cma_device = dev; 240 241 ib_set_client_data(dev, sol_cma_ib_client, new_device); 242 243 mutex_enter(&sol_cma_dev_mutex); 244 llist_add_tail(&new_device->cma_list, &sol_cma_dev_list); 245 mutex_exit(&sol_cma_dev_mutex); 246 } 247 248 static void 249 sol_cma_rem_dev(struct ib_device *dev) 250 { 251 cma_device_t *rem_device; 252 genlist_entry_t *entry; 253 254 SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "sol_rem_dev(%p)", dev); 255 256 rem_device = (cma_device_t *)ib_get_client_data(dev, sol_cma_ib_client); 257 if (!rem_device) { 258 SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str, "sol_cma_rem_dev() " 259 "NULL cma_dev!!"); 260 return; 261 } 262 263 mutex_enter(&rem_device->cma_mutex); 264 rem_device->cma_dev_state = SOL_CMA_DEV_REM_IN_PROGRESS; 265 if (rem_device->cma_ref_count) { 266 mutex_exit(&rem_device->cma_mutex); 267 SOL_OFS_DPRINTF_L3(sol_ofs_dbg_str, "sol_cma_rem_dev() " 268 "BUSY cma_dev!!"); 269 return; 270 } 271 entry = remove_genlist_head(&rem_device->cma_epchan_list); 272 while (entry) { 273 sol_cma_chan_t *ep_chanp; 274 275 ep_chanp = (sol_cma_chan_t *)entry->data; 276 if (ibcma_fini_ep_chan(ep_chanp) == 0) { 277 genlist_entry_t *entry1; 278 sol_cma_chan_t *root_chanp; 279 280 ASSERT(ep_chanp->chan_listenp); 281 entry1 = ep_chanp->chan_listenp->listen_ep_root_entry; 282 root_chanp = (sol_cma_chan_t *)ep_chanp->listen_root; 283 root_chanp->chan_listenp->listen_eps--; 284 delete_genlist(&root_chanp->chan_listenp->listen_list, 285 entry1); 286 287 kmem_free(ep_chanp, sizeof (sol_cma_chan_t)); 288 kmem_free(entry, sizeof (genlist_entry_t)); 289 } 290 291 entry = remove_genlist_head(&rem_device->cma_epchan_list); 292 } 293 mutex_exit(&rem_device->cma_mutex); 294 295 mutex_enter(&sol_cma_dev_mutex); 296 llist_del(&rem_device->cma_list); 297 mutex_exit(&sol_cma_dev_mutex); 298 299 kmem_free(rem_device, sizeof (cma_device_t)); 300 } 301 302 struct ib_device * 303 sol_cma_acquire_device(ib_guid_t hca_guid) 304 { 305 llist_head_t *entry; 306 cma_device_t *cma_devp; 307 308 mutex_enter(&sol_cma_dev_mutex); 309 list_for_each(entry, &sol_cma_dev_list) { 310 cma_devp = (cma_device_t *)entry->ptr; 311 312 if (cma_devp->cma_device->node_guid != hca_guid) 313 continue; 314 315 mutex_enter(&cma_devp->cma_mutex); 316 if (cma_devp->cma_dev_state == SOL_CMA_DEV_REM_IN_PROGRESS) { 317 SOL_OFS_DPRINTF_L3(sol_ofs_dbg_str, 318 "sol_cma_acquire_dev() - Device getting removed!!"); 319 mutex_exit(&cma_devp->cma_mutex); 320 mutex_exit(&sol_cma_dev_mutex); 321 return (NULL); 322 } 323 cma_devp->cma_ref_count++; 324 mutex_exit(&cma_devp->cma_mutex); 325 mutex_exit(&sol_cma_dev_mutex); 326 return (cma_devp->cma_device); 327 328 } 329 mutex_exit(&sol_cma_dev_mutex); 330 return (NULL); 331 } 332 333 static void 334 sol_cma_release_device(struct rdma_cm_id *id) 335 { 336 ib_device_t *device = id->device; 337 llist_head_t *entry; 338 cma_device_t *cma_devp; 339 340 mutex_enter(&sol_cma_dev_mutex); 341 list_for_each(entry, &sol_cma_dev_list) { 342 cma_devp = (cma_device_t *)entry->ptr; 343 344 if (cma_devp->cma_device != device) 345 continue; 346 347 mutex_enter(&cma_devp->cma_mutex); 348 cma_devp->cma_ref_count--; 349 if (cma_devp->cma_dev_state == SOL_CMA_DEV_REM_IN_PROGRESS && 350 cma_devp->cma_ref_count == 0) { 351 SOL_OFS_DPRINTF_L3(sol_ofs_dbg_str, 352 "sol_cma_release_dev() - Device free removed!!"); 353 mutex_exit(&cma_devp->cma_mutex); 354 llist_del(&cma_devp->cma_list); 355 kmem_free(cma_devp, sizeof (cma_device_t)); 356 mutex_exit(&sol_cma_dev_mutex); 357 return; 358 } 359 mutex_exit(&cma_devp->cma_mutex); 360 } 361 mutex_exit(&sol_cma_dev_mutex); 362 } 363 364 void 365 sol_cma_add_hca_list(sol_cma_chan_t *ep_chanp, ib_guid_t hca_guid) 366 { 367 llist_head_t *entry; 368 cma_device_t *cma_devp; 369 370 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "add_hca_list(%p, %llx)", 371 ep_chanp, hca_guid); 372 mutex_enter(&sol_cma_dev_mutex); 373 list_for_each(entry, &sol_cma_dev_list) { 374 cma_devp = (cma_device_t *)entry->ptr; 375 376 if ((cma_devp->cma_device)->node_guid != hca_guid) 377 continue; 378 379 mutex_enter(&cma_devp->cma_mutex); 380 ep_chanp->chan_listenp->listen_ep_dev_entry = 381 add_genlist(&cma_devp->cma_epchan_list, 382 (uintptr_t)ep_chanp, NULL); 383 ep_chanp->chan_listenp->listen_ep_device = cma_devp->cma_device; 384 mutex_exit(&cma_devp->cma_mutex); 385 mutex_exit(&sol_cma_dev_mutex); 386 return; 387 } 388 mutex_exit(&sol_cma_dev_mutex); 389 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "add_hca_list(%p, %llx): " 390 "No matching HCA in list!!", ep_chanp, hca_guid); 391 } 392 393 /* 394 * rdma_cm.h API functions. 395 */ 396 struct rdma_cm_id * 397 rdma_create_id(rdma_cm_event_handler evt_hdlr, void *context, 398 enum rdma_port_space ps) 399 { 400 struct rdma_cm_id *rdma_idp; 401 402 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_create_id(%p, %p, %x)", 403 evt_hdlr, context, ps); 404 405 if (ps != RDMA_PS_TCP && ps != RDMA_PS_UDP && ps != RDMA_PS_IPOIB) { 406 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 407 "rdma_create_id: unsupported protocol %x", ps); 408 return (NULL); 409 } 410 411 rdma_idp = cma_alloc_chan(evt_hdlr, context, ps); 412 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 413 "rdma_create_id : ret %p", rdma_idp); 414 415 return (rdma_idp); 416 } 417 418 void 419 rdma_map_id2clnthdl(struct rdma_cm_id *rdma_idp, void *ib_client_hdl, 420 void *iw_client_hdl) 421 { 422 sol_cma_chan_t *chanp = (sol_cma_chan_t *)rdma_idp; 423 424 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 425 "rdma_map_id2clnthdl(%p, %p, %p)", 426 rdma_idp, ib_client_hdl, iw_client_hdl); 427 ASSERT(ib_client_hdl != NULL || iw_client_hdl != NULL); 428 chanp->chan_ib_client_hdl = ib_client_hdl; 429 chanp->chan_iw_client_hdl = iw_client_hdl; 430 } 431 432 void 433 rdma_map_id2qphdl(struct rdma_cm_id *rdma_idp, void *qp_hdl) 434 { 435 sol_cma_chan_t *chanp = (sol_cma_chan_t *)rdma_idp; 436 437 ASSERT(rdma_idp); 438 ASSERT(qp_hdl); 439 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_mapid2qphdl(%p, %p)", 440 rdma_idp, qp_hdl); 441 chanp->chan_qp_hdl = qp_hdl; 442 } 443 444 445 void 446 rdma_destroy_id(struct rdma_cm_id *rdma_idp) 447 { 448 sol_cma_chan_t *chanp, *root_chanp; 449 cma_chan_state_t state; 450 int rc, is_root_cmid, do_wait, is_passive; 451 452 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id(%p)", rdma_idp); 453 454 if (!rdma_idp) 455 return; 456 457 is_root_cmid = do_wait = is_passive = 0; 458 459 chanp = (sol_cma_chan_t *)rdma_idp; 460 root_chanp = (sol_cma_chan_t *)chanp->listen_root; 461 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id(%p), %p", 462 rdma_idp, root_chanp); 463 464 mutex_enter(&chanp->chan_mutex); 465 chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_CMID_DESTROYED; 466 467 /* 468 * Wait in destroy of CMID when rdma_resolve_addr() / rdma_listen() 469 * rdma_resolve_route() API is in progress. 470 */ 471 while (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_API_PROGRESS) 472 cv_wait(&chanp->chan_destroy_cv, &chanp->chan_mutex); 473 474 /* Wait if Event is been notified to consumer */ 475 while (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_EVENT_PROGRESS) 476 cv_wait(&chanp->chan_destroy_cv, &chanp->chan_mutex); 477 478 if (rdma_idp->device) 479 sol_cma_release_device(rdma_idp); 480 481 if (chanp->chan_listenp && chanp->chan_listenp->listen_is_root) 482 is_root_cmid = 1; 483 if (root_chanp == NULL && is_root_cmid == 0) 484 is_passive = 1; 485 486 /* 487 * Skip Active side handling for passive CMIDs and listen CMID 488 * for which REQ CMIDs have not been created. 489 */ 490 if (is_passive || (is_root_cmid && chanp->chan_req_state != 491 REQ_CMID_CREATED)) { 492 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: " 493 "Skipping passive %p, %x, %x", chanp->chan_listenp, 494 is_root_cmid, chanp->chan_req_state); 495 goto skip_passive_handling; 496 } 497 498 /* 499 * destroy_id() called for listening CMID and there are REQ 500 * CMIDs not yet notified. Reject such CMIDs and decrement 501 * the count. 502 */ 503 if (is_root_cmid && chanp->chan_req_cnt) { 504 sol_cma_chan_t *req_cmid_chan, *next_chan; 505 506 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: " 507 "not notified handling"); 508 for (req_cmid_chan = (sol_cma_chan_t *)avl_first( 509 &chanp->chan_req_avl_tree); req_cmid_chan && 510 chanp->chan_req_cnt; req_cmid_chan = next_chan) { 511 next_chan = AVL_NEXT( 512 &chanp->chan_req_avl_tree, req_cmid_chan); 513 if (req_cmid_chan->chan_req_state == 514 REQ_CMID_CREATED) { 515 avl_remove(&chanp->chan_req_avl_tree, 516 req_cmid_chan); 517 chanp->chan_req_cnt--; 518 chanp->chan_req_total_cnt--; 519 mutex_exit(&chanp->chan_mutex); 520 mutex_enter(&req_cmid_chan->chan_mutex); 521 req_cmid_chan->chan_req_state = 522 REQ_CMID_NONE; 523 mutex_exit(&req_cmid_chan->chan_mutex); 524 (void) rdma_disconnect( 525 (struct rdma_cm_id *)req_cmid_chan); 526 mutex_enter(&chanp->chan_mutex); 527 if (rdma_idp->ps == RDMA_PS_TCP) { 528 mutex_enter( 529 &req_cmid_chan->chan_mutex); 530 req_cmid_chan->listen_root = 531 rdma_idp; 532 cma_set_chan_state(req_cmid_chan, 533 SOL_CMA_CHAN_DESTROY_PENDING); 534 mutex_exit( 535 &req_cmid_chan->chan_mutex); 536 } else { 537 mutex_destroy( 538 &req_cmid_chan->chan_mutex); 539 cv_destroy( 540 &req_cmid_chan->chan_destroy_cv); 541 kmem_free(req_cmid_chan, 542 sizeof (sol_cma_chan_t)); 543 } 544 } 545 } 546 } 547 548 /* 549 * destroy_id() called for : 550 * listening CMID and all REQ CMIDs destroy_id() called 551 * REQ CMID and 1 more REQ CMID not yet destroyed. 552 * wait till the CMID is completly destroyed. 553 */ 554 if (is_root_cmid && chanp->chan_req_total_cnt == 0) { 555 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: " 556 "root idp waiting"); 557 cma_set_chan_state(chanp, SOL_CMA_CHAN_DESTROY_WAIT); 558 cv_wait(&chanp->chan_destroy_cv, &chanp->chan_mutex); 559 } 560 561 if (root_chanp) 562 mutex_enter(&root_chanp->chan_mutex); 563 #ifdef DEBUG 564 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: " 565 "root_idp %p, cnt %x, state %x", root_chanp, 566 root_chanp ? root_chanp->chan_req_total_cnt : 0, 567 root_chanp ? cma_get_chan_state(root_chanp) : 0); 568 #endif 569 570 if (root_chanp && root_chanp->chan_req_total_cnt == 1 && 571 cma_get_chan_state(root_chanp) == SOL_CMA_CHAN_DESTROY_PENDING) 572 do_wait = 1; 573 if (root_chanp) 574 mutex_exit(&root_chanp->chan_mutex); 575 576 skip_passive_handling : 577 state = cma_get_chan_state(chanp); 578 if (is_root_cmid == 0 && state != SOL_CMA_CHAN_DISCONNECT && 579 SOL_CMA_DISCONNECT_OK(chanp)) { 580 /* 581 * A connected CM ID has not been disconnected. 582 * Call rdma_disconnect() to disconnect it. 583 */ 584 mutex_exit(&chanp->chan_mutex); 585 rc = rdma_disconnect(rdma_idp); 586 if (rc) { 587 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 588 "rdma_destroy_id(%p)- disconnect failed!!", 589 rdma_idp); 590 return; 591 } 592 mutex_enter(&chanp->chan_mutex); 593 if (root_chanp && chanp->listen_root == NULL) 594 chanp->listen_root = (struct rdma_cm_id *)root_chanp; 595 mutex_exit(&chanp->chan_mutex); 596 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 597 "rdma_destroy_id(chanp %p, connect %x, ps %x)", 598 chanp, chanp->chan_connect_flag, rdma_idp->ps); 599 if ((SOL_CMAID_IS_CONNECTED(chanp) && 600 rdma_idp->ps == RDMA_PS_TCP) || 601 (IS_UDP_CMID(rdma_idp) && 602 chanp->chan_connect_flag == SOL_CMA_CONNECT_INITIATED)) { 603 if (do_wait) { 604 mutex_enter(&chanp->chan_mutex); 605 cma_set_chan_state(chanp, 606 SOL_CMA_CHAN_DESTROY_WAIT); 607 cv_wait(&chanp->chan_destroy_cv, 608 &chanp->chan_mutex); 609 mutex_exit(&chanp->chan_mutex); 610 cma_destroy_id(rdma_idp); 611 } else { 612 mutex_enter(&chanp->chan_mutex); 613 cma_set_chan_state(chanp, 614 SOL_CMA_CHAN_DESTROY_PENDING); 615 mutex_exit(&chanp->chan_mutex); 616 } 617 } else { 618 /* 619 * Disconnected a CMID for which CONNECT has been 620 * Initiated but not complete. 621 * No more callbacks are expected for this CMID. 622 * Free this CMID. 623 */ 624 cma_destroy_id(rdma_idp); 625 } 626 } else if (is_root_cmid == 0 && state == 627 SOL_CMA_CHAN_DISCONNECT && SOL_CMAID_IS_CONNECTED(chanp)) { 628 /* 629 * CM ID was connected and disconnect is process. 630 * Free of this CM ID is done for the DISCONNECT 631 * notification for this CMID. 632 */ 633 cma_set_chan_state(chanp, SOL_CMA_CHAN_DESTROY_PENDING); 634 mutex_exit(&chanp->chan_mutex); 635 } else if (state != SOL_CMA_CHAN_DESTROY_PENDING) { 636 /* CM ID, not connected, just free it. */ 637 mutex_exit(&chanp->chan_mutex); 638 cma_destroy_id(rdma_idp); 639 } else 640 mutex_exit(&chanp->chan_mutex); 641 642 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: ret"); 643 } 644 645 /* 646 * State transitions for Address resolution : 647 * Active Side (Client) : 648 * 1. CREATE_ID-->BIND_ADDR-->RESOLVE_ADDR-->RESOLVE_ROUTE 649 * 650 * Passive Side (Server) : 651 * 2. CREATE_ID-->RESOLVE_ADDR-->RESOLVE_ROUTE 652 * IF_ADDR_ANY can be passed as local address in RESOLVE_ADDR 653 */ 654 int 655 rdma_bind_addr(struct rdma_cm_id *idp, struct sockaddr *addr) 656 { 657 sol_cma_chan_t *chanp; 658 struct rdma_addr *addrp; 659 int ret; 660 661 ASSERT(idp); 662 ASSERT(addr); 663 chanp = (sol_cma_chan_t *)idp; 664 addrp = &(idp->route.addr); 665 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_bind_addr(%p, %p)", 666 idp, addr); 667 668 mutex_enter(&chanp->chan_mutex); 669 ret = cma_cas_chan_state(chanp, SOL_CMA_CHAN_IDLE, SOL_CMA_CHAN_BOUND); 670 if (ret) { 671 mutex_exit(&chanp->chan_mutex); 672 return (ret); 673 } 674 /* Copy the local address to rdma_id structure */ 675 bcopy((void *)addr, (void *)&(addrp->src_addr), 676 sizeof (struct sockaddr)); 677 mutex_exit(&chanp->chan_mutex); 678 679 /* 680 * First call rdma_ib_bind_addr() to bind this address. 681 * Next call rdma_iw_bind_addr() to bind this address. 682 * For IF_ADDR_ANY, IB address is given priority over 683 * iWARP. 684 */ 685 if (chanp->chan_ib_client_hdl == NULL) { 686 ofs_client_t *ofs_clnt; 687 688 ofs_clnt = (ofs_client_t *)sol_cma_ib_client->clnt_hdl; 689 chanp->chan_ib_client_hdl = ofs_clnt->ibt_hdl; 690 } 691 if (chanp->chan_ib_client_hdl && rdma_ib_bind_addr(idp, addr) == 0) { 692 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 693 "rdma_bind_addr: ret IB @"); 694 return (0); 695 #ifdef IWARP_SUPPORT 696 } else if (chanp->chan_iw_client_hdl && rdma_iw_bind_addr(idp, addr) 697 == 0) { 698 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 699 "rdma_bind_addr: ret iWARP @"); 700 return (0); 701 #endif /* IWARP_SUPPORT */ 702 } 703 704 mutex_enter(&chanp->chan_mutex); 705 cma_set_chan_state(chanp, SOL_CMA_CHAN_IDLE); 706 mutex_exit(&chanp->chan_mutex); 707 SOL_OFS_DPRINTF_L4(sol_rdmacm_dbg_str, "rdma_bind_addr: ret failure!"); 708 return (EINVAL); 709 } 710 711 int 712 rdma_resolve_addr(struct rdma_cm_id *idp, struct sockaddr *src_addr, 713 struct sockaddr *dst_addr, int timeout_ms) 714 { 715 sol_cma_chan_t *chanp; 716 struct rdma_addr *addrp; 717 cma_chan_state_t state; 718 719 ASSERT(idp); 720 chanp = (sol_cma_chan_t *)idp; 721 addrp = &(idp->route.addr); 722 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_resolve_addr(%p, %p, " 723 "%p, %x)", idp, src_addr, dst_addr, timeout_ms); 724 725 mutex_enter(&chanp->chan_mutex); 726 state = cma_get_chan_state(chanp); 727 if (state != SOL_CMA_CHAN_IDLE && state != SOL_CMA_CHAN_BOUND) { 728 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 729 "rdma_resolve_addr : invalid chan state %x", state); 730 mutex_exit(&chanp->chan_mutex); 731 return (EINVAL); 732 } 733 if (chanp->chan_cmid_destroy_state & 734 SOL_CMA_CALLER_CMID_DESTROYED) { 735 SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str, 736 "rdma_resolve_addr : CMID %p, destroy called", chanp); 737 mutex_exit(&chanp->chan_mutex); 738 return (EINVAL); 739 } 740 chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_API_PROGRESS; 741 742 if (chanp->chan_xport_type == SOL_CMA_XPORT_NONE) { 743 bcopy((void *)src_addr, (void *)&(addrp->src_addr), 744 sizeof (struct sockaddr)); 745 } 746 bcopy((void *)dst_addr, (void *)&(addrp->dst_addr), 747 sizeof (struct sockaddr)); 748 mutex_exit(&chanp->chan_mutex); 749 750 /* 751 * First resolve this as an @ corresponding to IB fabric 752 * if this fails, resolve this as an @ corresponding to iWARP 753 */ 754 if (chanp->chan_ib_client_hdl == NULL) { 755 ofs_client_t *ofs_clnt; 756 757 ofs_clnt = (ofs_client_t *)sol_cma_ib_client->clnt_hdl; 758 chanp->chan_ib_client_hdl = ofs_clnt->ibt_hdl; 759 } 760 if (chanp->chan_ib_client_hdl && rdma_ib_resolve_addr(idp, src_addr, 761 dst_addr, timeout_ms) == 0) { 762 SOL_OFS_DPRINTF_L4(sol_rdmacm_dbg_str, 763 "rdma_resolve_addr: ret IB @"); 764 #ifdef IWARP_SUPPORT 765 } else if (chanp->chan_iw_client_hdl && rdma_iw_resolve_addr(idp, 766 src_addr, dst_addr, timeout_ms) == 0) { 767 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 768 "rdma_resolve_addr: ret iWARP @"); 769 #endif /* IWARP_SUPPORT */ 770 } else { 771 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 772 "rdma_resolve_addr: Invalid @"); 773 return (EINVAL); 774 } 775 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_resolve_addr: ret 0"); 776 return (0); 777 } 778 779 static void cma_generate_event_sync(struct rdma_cm_id *, 780 enum rdma_cm_event_type, int, struct rdma_conn_param *, 781 struct rdma_ud_param *); 782 783 void 784 cma_resolve_addr_callback(sol_cma_chan_t *chanp, int rc) 785 { 786 enum rdma_cm_event_type event; 787 788 mutex_enter(&chanp->chan_mutex); 789 if (chanp->chan_cmid_destroy_state & 790 SOL_CMA_CALLER_CMID_DESTROYED) { 791 SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str, 792 "cma_resolve_addr : CMID %p, destroy called", chanp); 793 chanp->chan_cmid_destroy_state &= 794 ~SOL_CMA_CALLER_API_PROGRESS; 795 cv_broadcast(&chanp->chan_destroy_cv); 796 mutex_exit(&chanp->chan_mutex); 797 return; 798 } 799 if (rc == 0) { 800 cma_set_chan_state(chanp, SOL_CMA_CHAN_ADDR_RESLVD); 801 event = RDMA_CM_EVENT_ADDR_RESOLVED; 802 } else 803 event = RDMA_CM_EVENT_ADDR_ERROR; 804 805 /* 806 * Generate RDMA_CM_EVENT_ADDR_RESOLVED event 807 * This will result in RDMA_USER_CM_CMD_RESOLVE_ROUTE in 808 * userland. 809 */ 810 chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_EVENT_PROGRESS; 811 mutex_exit(&chanp->chan_mutex); 812 cma_generate_event_sync((struct rdma_cm_id *)chanp, event, 0, 813 NULL, NULL); 814 815 mutex_enter(&chanp->chan_mutex); 816 chanp->chan_cmid_destroy_state &= ~SOL_CMA_CALLER_API_PROGRESS; 817 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED) 818 cv_broadcast(&chanp->chan_destroy_cv); 819 mutex_exit(&chanp->chan_mutex); 820 } 821 822 int 823 rdma_resolve_route(struct rdma_cm_id *idp, int timeout_ms) 824 { 825 sol_cma_chan_t *chanp; 826 827 ASSERT(idp); 828 chanp = (sol_cma_chan_t *)idp; 829 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "resolve_route(%p, %x)", idp, 830 timeout_ms); 831 832 mutex_enter(&chanp->chan_mutex); 833 if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_ADDR_RESLVD, 834 SOL_CMA_CHAN_ROUTE_RESLVD) != 0) { 835 mutex_exit(&chanp->chan_mutex); 836 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 837 "resolve_route: Invalid state"); 838 return (EINVAL); 839 } 840 if (chanp->chan_cmid_destroy_state & 841 SOL_CMA_CALLER_CMID_DESTROYED) { 842 SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str, 843 "rdma_resolve_route : CMID %p, destroy called", chanp); 844 mutex_exit(&chanp->chan_mutex); 845 return (EINVAL); 846 } 847 chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_API_PROGRESS; 848 mutex_exit(&chanp->chan_mutex); 849 850 /* 851 * Generate RDMA_CM_EVENT_ROUTE_RESOLVED event 852 * This will result in RDMA_USER_CM_CMD_RESOLVE_ROUTE in 853 * userland 854 */ 855 cma_generate_event(idp, RDMA_CM_EVENT_ROUTE_RESOLVED, 0, 856 NULL, NULL); 857 858 mutex_enter(&chanp->chan_mutex); 859 chanp->chan_cmid_destroy_state &= ~SOL_CMA_CALLER_API_PROGRESS; 860 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED) 861 cv_broadcast(&chanp->chan_destroy_cv); 862 mutex_exit(&chanp->chan_mutex); 863 864 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "resolve_route: ret 0"); 865 return (0); 866 } 867 868 /* 869 * Connect or Listen request should be send after Route is resolved 870 * 871 * Active Side (Client) : 872 * 1. (State ROUTE_RESOLVED)-->CONNECT-->ACCEPT/REJECT-->DISCONNECT 873 * -->DESTROY_ID-->close(9E) 874 * 2. Same as (1), DESTROY_ID without DISCONNECT 875 * 3. Same as (1), close(9e) without DESTROY_ID. 876 * 877 * Passive Side (Server) : 878 * 4. (State ROUTE_RESOLVED)-->LISTEN->DISCONNECT 879 * -->DESTROY_ID-->close(9E) 880 * 5. Same as (4), DESTROY_ID without DISCONNECT 881 * 6. Same as (4), close(9e) without DESTROY_ID. 882 */ 883 int 884 rdma_connect(struct rdma_cm_id *idp, struct rdma_conn_param *conn_param) 885 { 886 sol_cma_chan_t *chanp; 887 int ret = EINVAL; 888 889 ASSERT(idp); 890 chanp = (sol_cma_chan_t *)idp; 891 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_connect(%p, %p)", idp, 892 conn_param); 893 894 mutex_enter(&chanp->chan_mutex); 895 if (chanp->chan_xport_type == SOL_CMA_XPORT_NONE) { 896 mutex_exit(&chanp->chan_mutex); 897 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 898 "rdma_connect, Invalid Xport"); 899 return (EINVAL); 900 } 901 if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_ROUTE_RESLVD, 902 SOL_CMA_CHAN_CONNECT)) { 903 mutex_exit(&chanp->chan_mutex); 904 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 905 "rdma_connect, Invalid state"); 906 return (EINVAL); 907 } 908 909 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) { 910 ret = rdma_ib_connect(idp, conn_param); 911 #ifdef IWARP_SUPPORT 912 } else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) { 913 ret = rdma_iw_connect(idp, conn_param); 914 #endif /* IWARP_SUPPORT */ 915 } 916 mutex_exit(&chanp->chan_mutex); 917 918 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_connect: ret %x", ret); 919 return (ret); 920 } 921 922 static int cma_init_listen_root(sol_cma_chan_t *); 923 static void cma_fini_listen_root(sol_cma_chan_t *); 924 925 int 926 rdma_listen(struct rdma_cm_id *idp, int bklog) 927 { 928 sol_cma_chan_t *chanp; 929 int ret; 930 genlist_entry_t *entry; 931 cma_chan_state_t state; 932 933 ASSERT(idp); 934 chanp = (sol_cma_chan_t *)idp; 935 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_listen(%p, %x)", 936 idp, bklog); 937 938 mutex_enter(&chanp->chan_mutex); 939 state = cma_get_chan_state(chanp); 940 if (state == SOL_CMA_CHAN_IDLE) { 941 mutex_exit(&chanp->chan_mutex); 942 return (EINVAL); 943 } 944 cma_set_chan_state(chanp, SOL_CMA_CHAN_LISTEN); 945 946 if (chanp->chan_cmid_destroy_state & 947 SOL_CMA_CALLER_CMID_DESTROYED) { 948 SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str, 949 "rdma_listen : CMID %p, destroy called", chanp); 950 mutex_exit(&chanp->chan_mutex); 951 return (EINVAL); 952 } 953 chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_API_PROGRESS; 954 955 ASSERT(chanp->chan_listenp == NULL); 956 957 chanp->chan_listenp = kmem_zalloc(sizeof (sol_cma_listen_info_t), 958 KM_SLEEP); 959 init_genlist(&(CHAN_LISTEN_LIST(chanp))); 960 (chanp->chan_listenp)->listen_is_root = 1; 961 ret = cma_init_listen_root(chanp); 962 if (ret) { 963 chanp->chan_listenp = NULL; 964 mutex_exit(&chanp->chan_mutex); 965 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "rdma_listen: " 966 "cma_init_listen_root: failed"); 967 kmem_free(chanp->chan_listenp, 968 sizeof (sol_cma_listen_info_t)); 969 return (EINVAL); 970 } 971 972 if (chanp->chan_xport_type == SOL_CMA_XPORT_NONE) { 973 ibcma_append_listen_list(idp); 974 #ifdef IWARP_SUPPORT 975 iwcma_append_listen_list(idp); 976 #endif 977 } else if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) { 978 ibcma_append_listen_list(idp); 979 #ifdef IWARP_SUPPORT 980 } else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) { 981 iwcma_append_listen_list(idp); 982 #endif /* IWARP_SUPPORT */ 983 } 984 985 if (genlist_empty(&(CHAN_LISTEN_LIST(chanp)))) { 986 cma_fini_listen_root(chanp); 987 kmem_free((void *)chanp->chan_listenp, 988 sizeof (sol_cma_listen_info_t)); 989 chanp->chan_listenp = NULL; 990 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "rdma_listen: " 991 "No listeners"); 992 mutex_exit(&chanp->chan_mutex); 993 return (0); 994 } 995 996 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED) { 997 chanp->chan_cmid_destroy_state &= 998 ~SOL_CMA_CALLER_API_PROGRESS; 999 cv_broadcast(&chanp->chan_destroy_cv); 1000 } 1001 1002 genlist_for_each(entry, &(CHAN_LISTEN_LIST(chanp))) { 1003 struct rdma_cm_id *ep_idp; 1004 sol_cma_chan_t *ep_chanp; 1005 1006 ep_idp = (struct rdma_cm_id *)entry->data; 1007 ep_chanp = (sol_cma_chan_t *)ep_idp; 1008 if (ep_chanp->chan_xport_type == SOL_CMA_XPORT_IB) 1009 ret = rdma_ib_listen(ep_idp, bklog); 1010 #ifdef IWARP_SUPPORT 1011 if (ep_chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) 1012 ret = rdma_iw_listen(ep_idp, bklog); 1013 #endif 1014 if (ret) 1015 break; 1016 } 1017 1018 chanp->chan_cmid_destroy_state &= ~SOL_CMA_CALLER_API_PROGRESS; 1019 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED) 1020 cv_broadcast(&chanp->chan_destroy_cv); 1021 mutex_exit(&chanp->chan_mutex); 1022 1023 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_listen: ret %x", ret); 1024 return (ret); 1025 } 1026 1027 int 1028 rdma_accept(struct rdma_cm_id *idp, struct rdma_conn_param *conn_param) 1029 { 1030 struct rdma_cm_id *root_idp; 1031 sol_cma_chan_t *root_chanp, *chanp; 1032 int ret = EINVAL; 1033 1034 ASSERT(idp); 1035 chanp = (sol_cma_chan_t *)idp; 1036 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_accept(%p, %p)", 1037 idp, conn_param); 1038 1039 mutex_enter(&chanp->chan_mutex); 1040 if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_LISTEN, 1041 SOL_CMA_CHAN_ACCEPT) && cma_cas_chan_state(chanp, 1042 SOL_CMA_CHAN_CONNECT, SOL_CMA_CHAN_ACCEPT)) { 1043 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1044 "rdma_accept, Invalid state"); 1045 mutex_exit(&chanp->chan_mutex); 1046 return (EINVAL); 1047 } 1048 mutex_exit(&chanp->chan_mutex); 1049 1050 root_idp = CHAN_LISTEN_ROOT(chanp); 1051 root_chanp = (sol_cma_chan_t *)root_idp; 1052 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "accept: root_idp %p", 1053 root_idp); 1054 1055 /* Delete from REQ_AVL_TREE on passive side */ 1056 if (root_idp) { 1057 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "accept: root_idp %p" 1058 "REQ AVL remove %p", root_chanp, idp); 1059 mutex_enter(&root_chanp->chan_mutex); 1060 avl_remove(&root_chanp->chan_req_avl_tree, idp); 1061 1062 /* For TCP, insert into ACPT_AVL_TREE */ 1063 if (idp->ps == RDMA_PS_TCP) { 1064 void *find_ret; 1065 avl_index_t where; 1066 1067 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 1068 "Add to ACPT AVL of %p IDP, idp %p, qp_hdl %p", 1069 root_idp, idp, chanp->chan_qp_hdl); 1070 find_ret = avl_find(&root_chanp->chan_acpt_avl_tree, 1071 (void *)chanp->chan_qp_hdl, &where); 1072 if (find_ret) { 1073 mutex_exit(&root_chanp->chan_mutex); 1074 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1075 "DUPLICATE ENTRY in ACPT AVL : root %p, " 1076 "idp %p, qp_hdl %p", 1077 root_idp, idp, chanp->chan_qp_hdl); 1078 return (EINVAL); 1079 } 1080 avl_insert(&root_chanp->chan_acpt_avl_tree, 1081 (void *)idp, where); 1082 } 1083 mutex_exit(&root_chanp->chan_mutex); 1084 1085 mutex_enter(&chanp->chan_mutex); 1086 /* Update chan_req_state to ACCEPTED */ 1087 chanp->chan_req_state = REQ_CMID_ACCEPTED; 1088 mutex_exit(&chanp->chan_mutex); 1089 } 1090 1091 if (root_idp && IS_UDP_CMID(root_idp)) { 1092 cma_chan_state_t chan_state; 1093 1094 /* 1095 * Accepting the connect request, no more events for this 1096 * connection. 1097 */ 1098 mutex_enter(&chanp->chan_mutex); 1099 cma_handle_nomore_events(chanp); 1100 chan_state = cma_get_chan_state(chanp); 1101 mutex_exit(&chanp->chan_mutex); 1102 /* If rdma_destroy_id() was called, destroy CMID */ 1103 if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING) 1104 cma_destroy_id((struct rdma_cm_id *)chanp); 1105 } 1106 1107 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) 1108 ret = rdma_ib_accept(idp, conn_param); 1109 #ifdef IWARP_SUPPORT 1110 if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) 1111 ret = rdma_iw_accept(idp, conn_param); 1112 #endif /* IWARP_SUPPORT */ 1113 1114 if (ret && root_idp && idp->ps == RDMA_PS_TCP) { 1115 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 1116 "Delete from REQ AVL of %p IDP, idp %p", 1117 root_idp, idp); 1118 mutex_enter(&root_chanp->chan_mutex); 1119 avl_remove(&root_chanp->chan_acpt_avl_tree, idp); 1120 mutex_exit(&root_chanp->chan_mutex); 1121 mutex_enter(&chanp->chan_mutex); 1122 chanp->chan_req_state = REQ_CMID_NONE; 1123 mutex_exit(&chanp->chan_mutex); 1124 } 1125 1126 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_accept: ret %x", ret); 1127 return (ret); 1128 } 1129 1130 int 1131 rdma_notify(struct rdma_cm_id *idp, enum ib_event_type evt) 1132 { 1133 sol_cma_chan_t *chanp; 1134 1135 ASSERT(idp); 1136 chanp = (sol_cma_chan_t *)idp; 1137 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_notify(%p, %x)", idp, evt); 1138 1139 mutex_enter(&chanp->chan_mutex); 1140 if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_ROUTE_RESLVD, 1141 SOL_CMA_CHAN_EVENT_NOTIFIED)) { 1142 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1143 "rdma_notify, Invalid state"); 1144 mutex_exit(&chanp->chan_mutex); 1145 return (EINVAL); 1146 } 1147 mutex_exit(&chanp->chan_mutex); 1148 1149 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_notify: ret 0"); 1150 return (0); 1151 } 1152 1153 int 1154 rdma_reject(struct rdma_cm_id *idp, const void *priv_data, 1155 uint8_t priv_data_len) 1156 { 1157 struct rdma_cm_id *root_idp; 1158 sol_cma_chan_t *root_chanp, *chanp; 1159 int ret = EINVAL; 1160 1161 ASSERT(idp); 1162 chanp = (sol_cma_chan_t *)idp; 1163 root_idp = CHAN_LISTEN_ROOT(chanp); 1164 root_chanp = (sol_cma_chan_t *)root_idp; 1165 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_reject(%p, %p)", idp, 1166 priv_data, priv_data_len); 1167 1168 mutex_enter(&chanp->chan_mutex); 1169 if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_LISTEN, 1170 SOL_CMA_CHAN_REJECT)) { 1171 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1172 "rdma_accept, Invalid state"); 1173 mutex_exit(&chanp->chan_mutex); 1174 return (EINVAL); 1175 } 1176 mutex_exit(&chanp->chan_mutex); 1177 1178 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) 1179 ret = rdma_ib_reject(idp, priv_data, priv_data_len); 1180 #ifdef IWARP_SUPPORT 1181 if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) 1182 ret = rdma_iw_reject(idp, priv_data, priv_data_len); 1183 #endif /* IWARP_SUPPORT */ 1184 1185 1186 if (!ret && root_idp) { 1187 cma_chan_state_t chan_state; 1188 1189 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "reject: root_idp %p" 1190 "REQ AVL remove %p", root_chanp, idp); 1191 /* Remove from Req AVL tree */ 1192 mutex_enter(&root_chanp->chan_mutex); 1193 avl_remove(&root_chanp->chan_req_avl_tree, idp); 1194 mutex_exit(&root_chanp->chan_mutex); 1195 1196 /* Update chan_req_state to REJECTED */ 1197 mutex_enter(&chanp->chan_mutex); 1198 chanp->chan_req_state = REQ_CMID_REJECTED; 1199 1200 /* 1201 * Rejecting connect request, no more events for this 1202 * connection. 1203 */ 1204 cma_handle_nomore_events(chanp); 1205 chan_state = cma_get_chan_state(chanp); 1206 mutex_exit(&chanp->chan_mutex); 1207 /* If rdma_destroy_id() was called, destroy CMID */ 1208 if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING) 1209 cma_destroy_id((struct rdma_cm_id *)chanp); 1210 } 1211 1212 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_reject: ret %x", ret); 1213 return (ret); 1214 } 1215 1216 int 1217 rdma_disconnect(struct rdma_cm_id *idp) 1218 { 1219 sol_cma_chan_t *chanp; 1220 int ret = EINVAL; 1221 cma_chan_state_t state; 1222 1223 chanp = (sol_cma_chan_t *)idp; 1224 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_disconnect(%p)", idp); 1225 1226 if (!idp) 1227 return (0); 1228 1229 mutex_enter(&chanp->chan_mutex); 1230 if (!(SOL_CMA_DISCONNECT_OK(chanp))) { 1231 SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str, 1232 "rdma_disconnect(%p) - Not connected!!", idp); 1233 mutex_exit(&chanp->chan_mutex); 1234 return (EINVAL); 1235 } 1236 state = cma_get_chan_state(chanp); 1237 cma_set_chan_state(chanp, SOL_CMA_CHAN_DISCONNECT); 1238 mutex_exit(&chanp->chan_mutex); 1239 1240 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) { 1241 ret = rdma_ib_disconnect(idp); 1242 #ifdef IWARP_SUPPORT 1243 } else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) { 1244 ret = rdma_iw_disconnect(idp); 1245 #endif /* IWARP_SUPPORT */ 1246 } 1247 1248 if (ret) { 1249 mutex_enter(&chanp->chan_mutex); 1250 cma_set_chan_state(chanp, state); 1251 mutex_exit(&chanp->chan_mutex); 1252 return (ret); 1253 } 1254 1255 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_disconnect: ret %x", ret); 1256 return (ret); 1257 } 1258 1259 int 1260 rdma_init_qp_attr(struct rdma_cm_id *idp, struct ib_qp_attr *qpattr, 1261 int *qp_attr_mask) 1262 { 1263 sol_cma_chan_t *chanp; 1264 int ret = EINVAL; 1265 1266 ASSERT(idp); 1267 chanp = (sol_cma_chan_t *)idp; 1268 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_init_qp_attr(%p, %p, %p)", 1269 idp, qpattr, qp_attr_mask); 1270 1271 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) { 1272 ret = rdma_ib_init_qp_attr(idp, qpattr, qp_attr_mask); 1273 #ifdef IWARP_SUPPORT 1274 } else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) 1275 ret = rdma_iw_init_qp_attr(idp, qpattr, qp_attr_mask); 1276 #endif /* IWARP_SUPPORT */ 1277 } else { 1278 ret = EINVAL; 1279 } 1280 1281 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 1282 "rdma_init_qp_attr: ret %x", ret); 1283 1284 return (ret); 1285 } 1286 1287 int 1288 rdma_join_multicast(struct rdma_cm_id *idp, struct sockaddr *addr, 1289 void *context) 1290 { 1291 sol_cma_chan_t *chanp; 1292 int ret = ENODEV; 1293 cma_chan_state_t state; 1294 1295 ASSERT(idp); 1296 chanp = (sol_cma_chan_t *)idp; 1297 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 1298 "rdma_join_multicast(%p, %p, %p)", 1299 idp, addr, context); 1300 1301 mutex_enter(&chanp->chan_mutex); 1302 state = cma_get_chan_state(chanp); 1303 if (state != SOL_CMA_CHAN_BOUND && 1304 state != SOL_CMA_CHAN_ROUTE_RESLVD && 1305 state != SOL_CMA_CHAN_ADDR_RESLVD) { 1306 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1307 "rdma_join_multicast, Invalid state"); 1308 mutex_exit(&chanp->chan_mutex); 1309 return (EINVAL); 1310 } 1311 1312 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) 1313 ret = rdma_ib_join_multicast(idp, addr, context); 1314 #ifdef IWARP_SUPPORT 1315 /* No support for Multicast on iWARP */ 1316 else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) 1317 ret = ENOTSUP; 1318 #endif /* IWARP_SUPPORT */ 1319 mutex_exit(&chanp->chan_mutex); 1320 1321 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 1322 "rdma_join_multicast: ret %x", ret); 1323 return (ret); 1324 } 1325 1326 void 1327 rdma_leave_multicast(struct rdma_cm_id *idp, struct sockaddr *addr) 1328 { 1329 sol_cma_chan_t *chanp; 1330 cma_chan_state_t state; 1331 1332 ASSERT(idp); 1333 chanp = (sol_cma_chan_t *)idp; 1334 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_leave_multicast(%p, %p)", 1335 idp, addr); 1336 1337 mutex_enter(&chanp->chan_mutex); 1338 state = cma_get_chan_state(chanp); 1339 if (state != SOL_CMA_CHAN_BOUND && 1340 state != SOL_CMA_CHAN_ROUTE_RESLVD && 1341 state != SOL_CMA_CHAN_ADDR_RESLVD) { 1342 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1343 "rdma_leave_multicast, Invalid state"); 1344 mutex_exit(&chanp->chan_mutex); 1345 return; 1346 } 1347 1348 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) 1349 rdma_ib_leave_multicast(idp, addr); 1350 #ifdef IWARP_SUPPORT 1351 /* No support for Multicast on iWARP */ 1352 else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) 1353 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1354 "rdma_leave_multicast, iWARP"); 1355 #endif /* IWARP_SUPPORT */ 1356 mutex_exit(&chanp->chan_mutex); 1357 1358 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_join_multicast: ret"); 1359 } 1360 1361 /* 1362 * Functions to compare to rdma_cm_id *, used by AVL tree 1363 * routines. 1364 */ 1365 int 1366 sol_cma_req_cmid_cmp(const void *p1, const void *p2) 1367 { 1368 sol_cma_chan_t *chanp; 1369 1370 chanp = (sol_cma_chan_t *)p2; 1371 if (chanp->chan_session_id > p1) 1372 return (+1); 1373 else if (chanp->chan_session_id < p1) 1374 return (-1); 1375 else 1376 return (0); 1377 } 1378 1379 int 1380 sol_cma_cmid_cmp(const void *p1, const void *p2) 1381 { 1382 sol_cma_chan_t *chanp; 1383 1384 chanp = (sol_cma_chan_t *)p2; 1385 if (chanp->chan_qp_hdl > p1) 1386 return (+1); 1387 else if (chanp->chan_qp_hdl < p1) 1388 return (-1); 1389 else 1390 return (0); 1391 } 1392 1393 /* 1394 * Function to compare two sol_cma_glbl_listen_t *, used by 1395 * AVL tree routines. 1396 */ 1397 int 1398 sol_cma_svc_cmp(const void *p1, const void *p2) 1399 { 1400 sol_cma_glbl_listen_t *listenp; 1401 uint64_t sid; 1402 1403 sid = *(uint64_t *)p1; 1404 listenp = (sol_cma_glbl_listen_t *)p2; 1405 if (listenp->cma_listen_chan_sid > sid) 1406 return (+1); 1407 else if (listenp->cma_listen_chan_sid < sid) 1408 return (-1); 1409 else 1410 return (0); 1411 } 1412 1413 static int 1414 cma_init_listen_root(sol_cma_chan_t *chanp) 1415 { 1416 sol_cma_glbl_listen_t *cma_listenp; 1417 sol_cma_listen_info_t *chan_listenp; 1418 int rc = 0; 1419 avl_index_t where = 0; 1420 uint64_t listen_sid; 1421 1422 ASSERT(chanp); 1423 ASSERT(chanp->chan_listenp); 1424 chan_listenp = chanp->chan_listenp; 1425 1426 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 1427 "cma_init_listen_root(%p)", chanp); 1428 1429 /* 1430 * First search for matching global listen_info for this SID. 1431 * If found with the same client handle, reuse the service 1432 * handle, if matching SID is found with different client 1433 * handle, return EINVAL. 1434 */ 1435 listen_sid = ibcma_init_root_sid(chanp); 1436 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 1437 "cma_init_listen_root: search SID 0x%llx", 1438 listen_sid); 1439 1440 mutex_enter(&sol_cma_glob_mutex); 1441 cma_listenp = avl_find(&sol_cma_glbl_listen_tree, 1442 (void *) &listen_sid, &where); 1443 if (cma_listenp && cma_listenp->cma_listen_clnt_hdl == 1444 chanp->chan_ib_client_hdl) { 1445 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 1446 "cma_init_listen_root: matching listenp %p SID 0x%llx", 1447 cma_listenp, listen_sid); 1448 chan_listenp->listen_entry = add_genlist( 1449 &cma_listenp->cma_listen_chan_list, 1450 (uintptr_t)chanp, NULL); 1451 chan_listenp->chan_glbl_listen_info = cma_listenp; 1452 ibcma_copy_srv_hdl(chanp, cma_listenp); 1453 mutex_exit(&sol_cma_glob_mutex); 1454 return (0); 1455 } else if (cma_listenp) { 1456 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1457 "cma_init_listen_root: listenp %p, SID 0x%llx match, " 1458 "client hdl prev %p, new %p mismatch", 1459 cma_listenp, listen_sid, 1460 cma_listenp->cma_listen_clnt_hdl, 1461 chanp->chan_ib_client_hdl); 1462 mutex_exit(&sol_cma_glob_mutex); 1463 return (EINVAL); 1464 } 1465 1466 cma_listenp = kmem_zalloc(sizeof (sol_cma_glbl_listen_t), KM_SLEEP); 1467 init_genlist(&cma_listenp->cma_listen_chan_list); 1468 chan_listenp->listen_entry = add_genlist( 1469 &cma_listenp->cma_listen_chan_list, (uintptr_t)chanp, NULL); 1470 chan_listenp->chan_glbl_listen_info = cma_listenp; 1471 cma_listenp->cma_listen_clnt_hdl = chanp->chan_ib_client_hdl; 1472 cma_listenp->cma_listen_chan_sid = listen_sid; 1473 1474 rc = ibcma_init_root_chan(chanp, cma_listenp); 1475 if (rc) { 1476 mutex_exit(&sol_cma_glob_mutex); 1477 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1478 "cma_init_listen_root: ibcma_init_root_chan failed!!"); 1479 delete_genlist(&cma_listenp->cma_listen_chan_list, 1480 chan_listenp->listen_entry); 1481 kmem_free(cma_listenp, sizeof (sol_cma_glbl_listen_t)); 1482 return (rc); 1483 } 1484 avl_insert(&sol_cma_glbl_listen_tree, cma_listenp, where); 1485 mutex_exit(&sol_cma_glob_mutex); 1486 return (0); 1487 } 1488 1489 static void 1490 cma_fini_listen_root(sol_cma_chan_t *chanp) 1491 { 1492 sol_cma_glbl_listen_t *cma_listenp; 1493 sol_cma_listen_info_t *chan_listenp; 1494 1495 ASSERT(chanp); 1496 ASSERT(chanp->chan_listenp); 1497 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "cma_fini_listen_root(%p)", 1498 chanp); 1499 chan_listenp = chanp->chan_listenp; 1500 cma_listenp = chan_listenp->chan_glbl_listen_info; 1501 ASSERT(cma_listenp); 1502 mutex_enter(&sol_cma_glob_mutex); 1503 delete_genlist(&cma_listenp->cma_listen_chan_list, 1504 chan_listenp->listen_entry); 1505 if (genlist_empty(&cma_listenp->cma_listen_chan_list)) { 1506 if (ibcma_fini_root_chan(chanp) == 0) { 1507 avl_remove(&sol_cma_glbl_listen_tree, 1508 cma_listenp); 1509 kmem_free(cma_listenp, 1510 sizeof (sol_cma_glbl_listen_t)); 1511 } else 1512 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1513 "cma_fini_listen_root: " 1514 "ibcma_fini_root_chan failed"); 1515 } 1516 1517 mutex_exit(&sol_cma_glob_mutex); 1518 } 1519 1520 typedef struct cma_event_async_arg { 1521 struct rdma_cm_id *idp; 1522 enum rdma_cm_event_type event; 1523 int status; 1524 union { 1525 struct rdma_conn_param conn; 1526 struct rdma_ud_param param; 1527 } un; 1528 struct rdma_conn_param *conn_param; 1529 struct rdma_ud_param *ud_paramp; 1530 } cma_event_async_arg_t; 1531 1532 static void cma_generate_event_sync(struct rdma_cm_id *, 1533 enum rdma_cm_event_type, int, struct rdma_conn_param *, 1534 struct rdma_ud_param *); 1535 1536 void 1537 cma_generate_event_thr(void *arg) 1538 { 1539 cma_event_async_arg_t *event_arg = (cma_event_async_arg_t *)arg; 1540 1541 cma_generate_event_sync(event_arg->idp, event_arg->event, 1542 event_arg->status, event_arg->conn_param, 1543 event_arg->ud_paramp); 1544 1545 if (event_arg->conn_param && event_arg->conn_param->private_data_len) 1546 kmem_free((void *)event_arg->conn_param->private_data, 1547 event_arg->conn_param->private_data_len); 1548 if (event_arg->ud_paramp && event_arg->ud_paramp->private_data_len) 1549 kmem_free((void *)event_arg->ud_paramp->private_data, 1550 event_arg->ud_paramp->private_data_len); 1551 kmem_free(arg, sizeof (cma_event_async_arg_t)); 1552 } 1553 1554 void 1555 cma_generate_event(struct rdma_cm_id *idp, enum rdma_cm_event_type event, 1556 int status, struct rdma_conn_param *conn_param, 1557 struct rdma_ud_param *ud_paramp) 1558 { 1559 cma_event_async_arg_t *event_arg; 1560 sol_cma_chan_t *chanp = (sol_cma_chan_t *)idp; 1561 1562 /* 1563 * Set SOL_CMA_CALLER_EVENT_PROGRESS to indicate event 1564 * notification is in progress, so that races between 1565 * rdma_destroy_id() and event notification is taken care. 1566 * 1567 * If rdma_destroy_id() has been called for this CMID, call 1568 * cma_generate_event_sync() which skips notification to the 1569 * consumer and handles the event. 1570 */ 1571 mutex_enter(&chanp->chan_mutex); 1572 chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_EVENT_PROGRESS; 1573 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED) { 1574 mutex_exit(&chanp->chan_mutex); 1575 cma_generate_event_sync(idp, event, status, conn_param, 1576 ud_paramp); 1577 return; 1578 } 1579 mutex_exit(&chanp->chan_mutex); 1580 1581 event_arg = kmem_zalloc(sizeof (cma_event_async_arg_t), KM_SLEEP); 1582 event_arg->idp = idp; 1583 event_arg->event = event; 1584 event_arg->status = status; 1585 event_arg->conn_param = NULL; 1586 event_arg->ud_paramp = NULL; 1587 if (conn_param && conn_param->private_data_len) { 1588 bcopy(conn_param, &(event_arg->un.conn), 1589 sizeof (struct rdma_conn_param)); 1590 event_arg->conn_param = &(event_arg->un.conn); 1591 event_arg->conn_param->private_data = kmem_zalloc( 1592 conn_param->private_data_len, KM_SLEEP); 1593 bcopy(conn_param->private_data, 1594 (void *)event_arg->conn_param->private_data, 1595 conn_param->private_data_len); 1596 } else if (conn_param && conn_param->private_data_len == 0) { 1597 bcopy(conn_param, &(event_arg->un.conn), 1598 sizeof (struct rdma_conn_param)); 1599 } else if (ud_paramp) { 1600 bcopy(ud_paramp, &(event_arg->un.param), 1601 sizeof (struct rdma_ud_param)); 1602 event_arg->ud_paramp = &(event_arg->un.param); 1603 if (ud_paramp->private_data_len) { 1604 event_arg->ud_paramp->private_data = kmem_zalloc( 1605 ud_paramp->private_data_len, KM_SLEEP); 1606 bcopy(ud_paramp->private_data, 1607 (void *)event_arg->ud_paramp->private_data, 1608 ud_paramp->private_data_len); 1609 } else if (ud_paramp->private_data) { 1610 event_arg->ud_paramp->private_data = 1611 ud_paramp->private_data; 1612 } 1613 } 1614 1615 if (taskq_dispatch(system_taskq, cma_generate_event_thr, 1616 (void *)event_arg, TQ_SLEEP) == 0) { 1617 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1618 "generate_event_async: taskq_dispatch() failed!!"); 1619 mutex_enter(&chanp->chan_mutex); 1620 chanp->chan_cmid_destroy_state &= 1621 ~SOL_CMA_CALLER_EVENT_PROGRESS; 1622 if (chanp->chan_cmid_destroy_state & 1623 SOL_CMA_CALLER_CMID_DESTROYED) 1624 cv_broadcast(&chanp->chan_destroy_cv); 1625 mutex_exit(&chanp->chan_mutex); 1626 } 1627 } 1628 1629 static void 1630 cma_generate_event_sync(struct rdma_cm_id *idp, enum rdma_cm_event_type event, 1631 int status, struct rdma_conn_param *conn_param, 1632 struct rdma_ud_param *ud_paramp) 1633 { 1634 struct rdma_cm_event cm_event; 1635 sol_cma_chan_t *chanp = (sol_cma_chan_t *)idp; 1636 struct rdma_cm_id *root_idp = NULL; 1637 sol_cma_chan_t *root_chanp; 1638 int ret; 1639 cma_chan_state_t chan_state; 1640 1641 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "generate_event_sync(%p, %x, " 1642 "%x, %p, %p", idp, event, status, conn_param, ud_paramp); 1643 1644 bzero(&cm_event, sizeof (cm_event)); 1645 cm_event.event = event; 1646 cm_event.status = status; 1647 if (conn_param) 1648 bcopy((void *)conn_param, (void *)(&(cm_event.param.conn)), 1649 sizeof (struct rdma_conn_param)); 1650 else if (ud_paramp) 1651 bcopy((void *)ud_paramp, (void *)(&(cm_event.param.ud)), 1652 sizeof (struct rdma_ud_param)); 1653 1654 /* 1655 * If the consumer has destroyed the context for this CMID - 1656 * do not notify, skip to handling the sol_ofs specific 1657 * handling of the event. 1658 */ 1659 mutex_enter(&chanp->chan_mutex); 1660 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED) { 1661 mutex_exit(&chanp->chan_mutex); 1662 goto ofs_consume_event; 1663 } 1664 mutex_exit(&chanp->chan_mutex); 1665 1666 root_idp = CHAN_LISTEN_ROOT(chanp); 1667 root_chanp = (sol_cma_chan_t *)root_idp; 1668 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "gen_event: root_idp %p", 1669 root_idp); 1670 1671 if (event == RDMA_CM_EVENT_CONNECT_REQUEST) { 1672 /* 1673 * Update chan_req_state for the REQ CMID. Decrement 1674 * count of REQ CMIDs not notifed to consumer. 1675 */ 1676 ASSERT(root_idp); 1677 mutex_enter(&root_chanp->chan_mutex); 1678 root_chanp->chan_req_cnt--; 1679 #ifdef DEBUG 1680 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, 1681 "Dec req_cnt of %p IDP, idp %p, req_cnt %x", 1682 root_idp, idp, root_chanp->chan_req_cnt); 1683 #endif 1684 mutex_exit(&root_chanp->chan_mutex); 1685 } 1686 1687 /* Pass the event to the client */ 1688 ret = (idp->event_handler) (idp, &cm_event); 1689 1690 if (ret) { 1691 if (event == RDMA_CM_EVENT_CONNECT_REQUEST) { 1692 SOL_OFS_DPRINTF_L4(sol_rdmacm_dbg_str, 1693 "cma_generate_event_async: consumer failed %d " 1694 "event", event); 1695 /* 1696 * Disconnect if the consumer returned non zero. 1697 * rdma_disconnect will send a REJ to the active 1698 * side / client. 1699 */ 1700 if (rdma_disconnect(idp)) 1701 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1702 "generate_event_async: rdma_disconnect " 1703 "failed"); 1704 } else 1705 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1706 "generate_event_async: consumer failed %d event", 1707 event); 1708 1709 mutex_enter(&chanp->chan_mutex); 1710 chanp->chan_req_state = REQ_CMID_NONE; 1711 chanp->chan_connect_flag = SOL_CMA_CONNECT_NONE; 1712 chanp->chan_cmid_destroy_state &= 1713 ~SOL_CMA_CALLER_EVENT_PROGRESS; 1714 if (chanp->chan_cmid_destroy_state & 1715 SOL_CMA_CALLER_CMID_DESTROYED) { 1716 cv_broadcast(&chanp->chan_destroy_cv); 1717 mutex_exit(&chanp->chan_mutex); 1718 } else { 1719 mutex_exit(&chanp->chan_mutex); 1720 rdma_destroy_id(idp); 1721 } 1722 return; 1723 } 1724 ofs_consume_event: 1725 if (event == RDMA_CM_EVENT_DISCONNECTED || event == 1726 RDMA_CM_EVENT_REJECTED) { 1727 mutex_enter(&chanp->chan_mutex); 1728 chanp->chan_connect_flag = SOL_CMA_CONNECT_NONE; 1729 chanp->chan_qp_hdl = NULL; 1730 mutex_exit(&chanp->chan_mutex); 1731 } 1732 if (event == RDMA_CM_EVENT_DISCONNECTED && root_idp) { 1733 cma_chan_state_t chan_state; 1734 1735 mutex_enter(&chanp->chan_mutex); 1736 cma_handle_nomore_events(chanp); 1737 chan_state = cma_get_chan_state(chanp); 1738 chanp->chan_cmid_destroy_state &= 1739 ~SOL_CMA_CALLER_EVENT_PROGRESS; 1740 if (chanp->chan_cmid_destroy_state & 1741 SOL_CMA_CALLER_CMID_DESTROYED) { 1742 cv_broadcast(&chanp->chan_destroy_cv); 1743 mutex_exit(&chanp->chan_mutex); 1744 } else if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING) { 1745 /* If rdma_destroy_id() was called, destroy CMID */ 1746 mutex_exit(&chanp->chan_mutex); 1747 cma_destroy_id((struct rdma_cm_id *)chanp); 1748 } else 1749 mutex_exit(&chanp->chan_mutex); 1750 return; 1751 } else if (event == RDMA_CM_EVENT_DISCONNECTED && !root_idp) { 1752 /* 1753 * Client side TCP CMID : 1754 * If rdma_destroy_id() was called, destroy CMID. 1755 * 1756 * If not chan_connect_flag is set to CONNECT_NONE 1757 * so it can be deleted when rdma_destroy_id is 1758 * called. 1759 */ 1760 mutex_enter(&chanp->chan_mutex); 1761 chan_state = cma_get_chan_state(chanp); 1762 chanp->chan_cmid_destroy_state &= 1763 ~SOL_CMA_CALLER_EVENT_PROGRESS; 1764 if (chanp->chan_cmid_destroy_state & 1765 SOL_CMA_CALLER_CMID_DESTROYED) { 1766 cv_broadcast(&chanp->chan_destroy_cv); 1767 mutex_exit(&chanp->chan_mutex); 1768 } else if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING) { 1769 mutex_exit(&chanp->chan_mutex); 1770 cma_destroy_id(idp); 1771 } else 1772 mutex_exit(&chanp->chan_mutex); 1773 return; 1774 } else if (IS_UDP_CMID(idp) && event == RDMA_CM_EVENT_UNREACHABLE) { 1775 /* 1776 * If rdma_destroy_id() was called, destroy CMID 1777 * If not chan_connect_flag is set to CONNECT_NONE 1778 * so it can be deleted when rdma_destroy_id is 1779 * called. 1780 */ 1781 mutex_enter(&chanp->chan_mutex); 1782 chan_state = cma_get_chan_state(chanp); 1783 chanp->chan_cmid_destroy_state &= 1784 ~SOL_CMA_CALLER_EVENT_PROGRESS; 1785 if (chanp->chan_cmid_destroy_state & 1786 SOL_CMA_CALLER_CMID_DESTROYED) { 1787 cv_broadcast(&chanp->chan_destroy_cv); 1788 mutex_exit(&chanp->chan_mutex); 1789 } else if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING) { 1790 mutex_exit(&chanp->chan_mutex); 1791 cma_destroy_id(idp); 1792 } else 1793 mutex_exit(&chanp->chan_mutex); 1794 return; 1795 } 1796 1797 mutex_enter(&chanp->chan_mutex); 1798 chanp->chan_cmid_destroy_state &= ~SOL_CMA_CALLER_EVENT_PROGRESS; 1799 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED) 1800 cv_broadcast(&chanp->chan_destroy_cv); 1801 mutex_exit(&chanp->chan_mutex); 1802 } 1803 1804 /* Local Static functions */ 1805 static struct rdma_cm_id * 1806 cma_alloc_chan(rdma_cm_event_handler evt_hdlr, void *context, 1807 enum rdma_port_space ps) 1808 { 1809 struct rdma_cm_id *rdma_idp; 1810 sol_cma_chan_t *chanp; 1811 1812 chanp = kmem_zalloc(sizeof (sol_cma_chan_t), KM_SLEEP); 1813 mutex_init(&chanp->chan_mutex, NULL, MUTEX_DRIVER, NULL); 1814 cv_init(&chanp->chan_destroy_cv, NULL, CV_DRIVER, NULL); 1815 rdma_idp = &(chanp->chan_rdma_cm); 1816 rdma_idp->context = context; 1817 rdma_idp->ps = ps; 1818 rdma_idp->event_handler = evt_hdlr; 1819 mutex_enter(&chanp->chan_mutex); 1820 cma_set_chan_state(chanp, SOL_CMA_CHAN_IDLE); 1821 avl_create(&chanp->chan_req_avl_tree, sol_cma_req_cmid_cmp, 1822 sizeof (sol_cma_chan_t), 1823 offsetof(sol_cma_chan_t, chan_req_avl_node)); 1824 avl_create(&chanp->chan_acpt_avl_tree, sol_cma_cmid_cmp, 1825 sizeof (sol_cma_chan_t), 1826 offsetof(sol_cma_chan_t, chan_acpt_avl_node)); 1827 mutex_exit(&chanp->chan_mutex); 1828 1829 return (rdma_idp); 1830 } 1831 1832 /* Change the state of sol_cma_chan_t */ 1833 static void 1834 cma_set_chan_state(sol_cma_chan_t *chanp, cma_chan_state_t newstate) 1835 { 1836 ASSERT(MUTEX_HELD(&chanp->chan_mutex)); 1837 chanp->chan_state = newstate; 1838 } 1839 1840 cma_chan_state_t 1841 cma_get_chan_state(sol_cma_chan_t *chanp) 1842 { 1843 ASSERT(MUTEX_HELD(&chanp->chan_mutex)); 1844 return (chanp->chan_state); 1845 } 1846 1847 /* Check & Swap the state of sol_ucma_chan_t */ 1848 static int 1849 cma_cas_chan_state(sol_cma_chan_t *chanp, cma_chan_state_t prevstate, 1850 cma_chan_state_t newstate) 1851 { 1852 int ret = 0; 1853 1854 ASSERT(MUTEX_HELD(&chanp->chan_mutex)); 1855 if (chanp->chan_state != prevstate) 1856 ret = -1; 1857 else 1858 chanp->chan_state = newstate; 1859 1860 return (ret); 1861 } 1862 1863 static void 1864 cma_free_listen_list(struct rdma_cm_id *idp) 1865 { 1866 genlist_entry_t *entry; 1867 sol_cma_chan_t *chanp = (sol_cma_chan_t *)idp; 1868 1869 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "cma_free_listen_list(%p)", idp); 1870 mutex_enter(&chanp->chan_mutex); 1871 entry = remove_genlist_head(&(CHAN_LISTEN_LIST(chanp))); 1872 mutex_exit(&chanp->chan_mutex); 1873 while (entry) { 1874 sol_cma_chan_t *ep_chanp; 1875 1876 ep_chanp = (sol_cma_chan_t *)entry->data; 1877 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "fini_ep_chan: %p", 1878 ep_chanp); 1879 if (ibcma_fini_ep_chan(ep_chanp) == 0) { 1880 genlist_entry_t *entry1; 1881 struct ib_device *device; 1882 cma_device_t *cma_device; 1883 1884 ASSERT(ep_chanp->chan_listenp); 1885 mutex_enter(&ep_chanp->chan_mutex); 1886 entry1 = ep_chanp->chan_listenp->listen_ep_dev_entry; 1887 device = ep_chanp->chan_listenp->listen_ep_device; 1888 ASSERT(device); 1889 cma_device = device->data; 1890 delete_genlist(&cma_device->cma_epchan_list, 1891 entry1); 1892 sol_cma_release_device( 1893 (struct rdma_cm_id *)ep_chanp); 1894 mutex_exit(&ep_chanp->chan_mutex); 1895 if (ep_chanp->chan_listenp) 1896 kmem_free(ep_chanp->chan_listenp, 1897 sizeof (sol_cma_listen_info_t)); 1898 1899 mutex_destroy(&ep_chanp->chan_mutex); 1900 cv_destroy(&ep_chanp->chan_destroy_cv); 1901 kmem_free(ep_chanp, sizeof (sol_cma_chan_t)); 1902 kmem_free(entry, sizeof (genlist_entry_t)); 1903 } 1904 1905 mutex_enter(&chanp->chan_mutex); 1906 entry = remove_genlist_head(&(CHAN_LISTEN_LIST(chanp))); 1907 mutex_exit(&chanp->chan_mutex); 1908 } 1909 } 1910 1911 /* 1912 * Destroy a listening CMID when : 1913 * a. All CONNECTION REQUEST recieved have been rejected 1914 * or closed. 1915 * b. No CONNECTION REQUEST recieved. 1916 * Do not destroy a listening CMID when : 1917 * a. CONNECTION REQUEST has been recieved and not been 1918 * accepted from the passive / server side. 1919 * b. CONNECTION REQUEST has been recieved and has been 1920 * accepted from the passive server side. 1921 * Mark the listening CMID as destroy pending. 1922 * 1923 * For CMIDs created for rdma_connect() or created for a 1924 * CONNECT request, destroy the CMID only when : 1925 * CONNECTION has been closed or rejected. 1926 * 1927 * Mark the CMID as destroy pending. 1928 * 1929 * When a connection is rejected or closed : 1930 * Check if flag indicates - destroy pending, 1931 * cma_destroy_id() is called, this also does 1932 * 1933 * If there is a listening CMID assosiated with it, 1934 * call cma_destroy_if(listen_cmid); 1935 */ 1936 void 1937 cma_destroy_id(struct rdma_cm_id *idp) 1938 { 1939 sol_cma_chan_t *chanp = (sol_cma_chan_t *)idp; 1940 cma_chan_state_t state; 1941 ulong_t acpt_nodes, req_nodes; 1942 1943 mutex_enter(&chanp->chan_mutex); 1944 acpt_nodes = avl_numnodes(&chanp->chan_acpt_avl_tree); 1945 req_nodes = avl_numnodes(&chanp->chan_req_avl_tree); 1946 state = cma_get_chan_state(chanp); 1947 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "cma_destroy_id(%p)- " 1948 "est CMIDs %ld, req CMID %ld, listen_root %p, state %x, %x", 1949 idp, acpt_nodes, req_nodes, chanp->listen_root, 1950 state, chanp->chan_req_state); 1951 1952 /* 1953 * If there are either REQ recieved or Established CMIDs just return. 1954 * rdma_destroy() for these CMIDs can be called by client later. 1955 */ 1956 if (acpt_nodes || req_nodes) { 1957 cma_set_chan_state(chanp, SOL_CMA_CHAN_DESTROY_PENDING); 1958 mutex_exit(&chanp->chan_mutex); 1959 return; 1960 } 1961 cma_set_chan_state(chanp, SOL_CMA_CHAN_DESTROYING); 1962 avl_destroy(&chanp->chan_req_avl_tree); 1963 avl_destroy(&chanp->chan_acpt_avl_tree); 1964 1965 mutex_exit(&chanp->chan_mutex); 1966 if (idp->route.path_rec) { 1967 kmem_free(idp->route.path_rec, 1968 sizeof (struct ib_sa_path_rec) * idp->route.num_paths); 1969 idp->route.path_rec = NULL; 1970 } 1971 1972 switch (chanp->chan_xport_type) { 1973 case SOL_CMA_XPORT_NONE : 1974 break; 1975 case SOL_CMA_XPORT_IB : 1976 rdma_ib_destroy_id(idp); 1977 break; 1978 #ifdef IWARP_SUPPORT 1979 case SOL_CMA_XPORT_IWARP : 1980 rdma_iw_destroy_id(idp); 1981 break; 1982 #endif /* IWARP_SUPPORT */ 1983 default : 1984 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, 1985 "cma_destroy_id: Unsupported xport type %x", 1986 chanp->chan_xport_type); 1987 break; 1988 } 1989 1990 /* 1991 * Flush out & Free all listeners wrt to this ID 1992 * No locking is required as this code is executed 1993 * all REQ CMIDs have been destroyed. listen_list 1994 * will therefore not be modified during this loop. 1995 */ 1996 if (chanp->chan_listenp) { 1997 cma_free_listen_list(idp); 1998 cma_fini_listen_root(chanp); 1999 kmem_free((void *)chanp->chan_listenp, 2000 sizeof (sol_cma_listen_info_t)); 2001 chanp->chan_listenp = NULL; 2002 } 2003 2004 if (chanp->listen_root) { 2005 struct rdma_cm_id *root_idp; 2006 sol_cma_chan_t *root_chanp; 2007 2008 root_idp = chanp->listen_root; 2009 root_chanp = (sol_cma_chan_t *)root_idp; 2010 mutex_enter(&root_chanp->chan_mutex); 2011 state = cma_get_chan_state(root_chanp); 2012 acpt_nodes = avl_numnodes(&root_chanp->chan_acpt_avl_tree); 2013 req_nodes = avl_numnodes(&root_chanp->chan_req_avl_tree); 2014 mutex_exit(&root_chanp->chan_mutex); 2015 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "cma_destroy_id(%p)-" 2016 " root idp %p, state %x, acpt_nodes %ld, req_nodes %ld", 2017 idp, root_idp, state, acpt_nodes, req_nodes); 2018 2019 if (state == SOL_CMA_CHAN_DESTROY_PENDING && 2020 req_nodes == 0UL && acpt_nodes == 0UL) { 2021 mutex_enter(&root_chanp->chan_mutex); 2022 root_chanp->chan_req_state = REQ_CMID_NONE; 2023 mutex_exit(&root_chanp->chan_mutex); 2024 cma_destroy_id(root_idp); 2025 } else if (state == SOL_CMA_CHAN_DESTROY_WAIT && 2026 req_nodes == 0UL && acpt_nodes == 0UL) { 2027 mutex_enter(&root_chanp->chan_mutex); 2028 cma_set_chan_state(root_chanp, 2029 SOL_CMA_CHAN_DESTROY_PENDING); 2030 root_chanp->chan_req_state = REQ_CMID_NONE; 2031 cv_broadcast(&root_chanp->chan_destroy_cv); 2032 mutex_exit(&root_chanp->chan_mutex); 2033 } 2034 } 2035 2036 mutex_destroy(&chanp->chan_mutex); 2037 cv_destroy(&chanp->chan_destroy_cv); 2038 kmem_free(chanp, sizeof (sol_cma_chan_t)); 2039 } 2040 2041 /* 2042 * Server TCP disconnect for an established channel. 2043 * Remove from EST AVL tree. 2044 * 2045 * If destroy_id() has been called for the listening 2046 * CMID and there are no more CMIDs with pending 2047 * events corresponding to the listening CMID, free 2048 * the listening CMID. 2049 * 2050 * 2051 * If not chan_connect_flag is set to CONNECT_NONE 2052 * so it can be deleted when rdma_destroy_id is 2053 * called. 2054 */ 2055 static void 2056 cma_handle_nomore_events(sol_cma_chan_t *chanp) 2057 { 2058 struct rdma_cm_id *idp, *root_idp; 2059 sol_cma_chan_t *root_chanp; 2060 cma_chan_state_t state; 2061 ulong_t req_nodes, acpt_nodes; 2062 2063 idp = (struct rdma_cm_id *)chanp; 2064 root_idp = CHAN_LISTEN_ROOT(chanp); 2065 root_chanp = (sol_cma_chan_t *)root_idp; 2066 if (!root_chanp) 2067 return; 2068 2069 CHAN_LISTEN_ROOT(chanp) = NULL; 2070 mutex_enter(&root_chanp->chan_mutex); 2071 root_chanp->chan_req_total_cnt--; 2072 if (!root_chanp->chan_req_total_cnt) 2073 root_chanp->chan_req_state = REQ_CMID_NONE; 2074 if (root_idp->ps == RDMA_PS_TCP && chanp->chan_req_state == 2075 REQ_CMID_ACCEPTED) { 2076 avl_remove(&root_chanp->chan_acpt_avl_tree, idp); 2077 chanp->chan_req_state = REQ_CMID_NONE; 2078 } 2079 if (chanp->chan_req_state == REQ_CMID_CREATED || 2080 chanp->chan_req_state == REQ_CMID_NOTIFIED) { 2081 avl_remove(&root_chanp->chan_req_avl_tree, idp); 2082 chanp->chan_req_state = REQ_CMID_NONE; 2083 } 2084 state = cma_get_chan_state(root_chanp); 2085 req_nodes = avl_numnodes(&root_chanp->chan_req_avl_tree); 2086 acpt_nodes = avl_numnodes(&root_chanp->chan_acpt_avl_tree); 2087 mutex_exit(&root_chanp->chan_mutex); 2088 if (state == SOL_CMA_CHAN_DESTROY_PENDING && req_nodes == 0UL && 2089 acpt_nodes == 0UL) 2090 cma_destroy_id(root_idp); 2091 } 2092 2093 extern int ib_modify_qp(struct ib_qp *, struct ib_qp_attr *, int); 2094 extern int rdma_init_qp_attr(struct rdma_cm_id *, struct ib_qp_attr *, 2095 int *); 2096 2097 static int 2098 cma_init_ud_qp(sol_cma_chan_t *chanp, struct ib_qp *qp) 2099 { 2100 struct ib_qp_attr qp_attr; 2101 int qp_attr_mask, ret; 2102 2103 qp_attr.qp_state = IB_QPS_INIT; 2104 ret = rdma_init_qp_attr(&chanp->chan_rdma_cm, &qp_attr, &qp_attr_mask); 2105 if (ret) 2106 return (ret); 2107 2108 ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); 2109 if (ret) 2110 return (ret); 2111 2112 qp_attr.qp_state = IB_QPS_RTR; 2113 ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); 2114 if (ret) 2115 return (ret); 2116 2117 qp_attr.qp_state = IB_QPS_RTS; 2118 qp_attr.sq_psn = 0; 2119 ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); 2120 2121 return (ret); 2122 } 2123 2124 static int 2125 cma_init_conn_qp(sol_cma_chan_t *chanp, struct ib_qp *qp) 2126 { 2127 struct ib_qp_attr qp_attr; 2128 int qp_attr_mask, ret; 2129 2130 qp_attr.qp_state = IB_QPS_INIT; 2131 ret = rdma_init_qp_attr(&chanp->chan_rdma_cm, &qp_attr, &qp_attr_mask); 2132 if (ret) 2133 return (ret); 2134 2135 return (ib_modify_qp(qp, &qp_attr, qp_attr_mask)); 2136 } 2137 2138 static inline int 2139 cma_is_ud_ps(enum rdma_port_space ps) 2140 { 2141 return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB); 2142 } 2143 2144 int 2145 rdma_create_qp(struct rdma_cm_id *idp, struct ib_pd *pd, 2146 struct ib_qp_init_attr *qp_init_attr) 2147 { 2148 sol_cma_chan_t *chanp; 2149 struct ib_qp *qp; 2150 int ret; 2151 ofs_client_t *dev_ofs_client; 2152 2153 ASSERT(idp); 2154 chanp = (sol_cma_chan_t *)idp; 2155 if (idp->device->node_guid != pd->device->node_guid) 2156 return (-EINVAL); 2157 2158 dev_ofs_client = (ofs_client_t *)pd->device->clnt_hdl; 2159 rdma_map_id2clnthdl(idp, dev_ofs_client->ibt_hdl, NULL); 2160 2161 qp = ib_create_qp(pd, qp_init_attr); 2162 if ((uintptr_t)qp >= (uintptr_t)-0xFFF) { 2163 return ((intptr_t)qp); 2164 } 2165 rdma_map_id2qphdl(idp, (void *)qp->ibt_qp); 2166 2167 if (cma_is_ud_ps(idp->ps)) { 2168 ret = cma_init_ud_qp(chanp, qp); 2169 } else { 2170 ret = cma_init_conn_qp(chanp, qp); 2171 } 2172 2173 if (ret) { 2174 goto err; 2175 } 2176 2177 idp->qp = qp; 2178 chanp->chan_qp_num = qp->qp_num; 2179 chanp->chan_is_srq = (qp->srq != NULL); 2180 return (0); 2181 err: 2182 (void) ib_destroy_qp(qp); 2183 return (ret); 2184 } 2185 2186 void 2187 rdma_destroy_qp(struct rdma_cm_id *idp) 2188 { 2189 ASSERT(idp); 2190 (void) ib_destroy_qp(idp->qp); 2191 idp->qp = NULL; 2192 } 2193