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