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 }