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