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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * ibcm_utils.c
  28  *
  29  * contains internal lookup functions of IB CM module
  30  * along with some other miscellaneous stuff
  31  *
  32  * TBD:
  33  * 1. Code needed to ensure that if any clients are using a service then
  34  * don't de-register it.
  35  */
  36 
  37 #include <sys/ib/mgt/ibcm/ibcm_impl.h>
  38 #include <sys/ddi.h>
  39 
  40 
  41 /* statics */
  42 static vmem_t           *ibcm_local_sid_arena;
  43 static vmem_t           *ibcm_ip_sid_arena;
  44 static ib_svc_id_t      ibcm_local_sid_seed;
  45 static ib_com_id_t      ibcm_local_cid_seed;
  46 _NOTE(READ_ONLY_DATA({ibcm_local_sid_arena ibcm_local_sid_seed
  47     ibcm_ip_sid_arena ibcm_local_cid_seed}))
  48 static void             ibcm_delete_state_from_avl(ibcm_state_data_t *statep);
  49 static void             ibcm_init_conn_trace(ibcm_state_data_t *statep);
  50 static void             ibcm_fini_conn_trace(ibcm_state_data_t *statep);
  51 static void             ibcm_dump_conn_trbuf(void *statep, char *line_prefix,
  52                             char *buf, int buf_size);
  53 extern ibt_status_t     ibcm_get_node_rec(ibmf_saa_handle_t, sa_node_record_t *,
  54                             uint64_t c_mask, void *, size_t *);
  55 
  56 /*
  57  * ibcm_lookup_msg:
  58  *
  59  * Retrieves an existing state structure or creates a new one if none found.
  60  * This function is used during
  61  *      Passive connection side for INCOMING REQ/REJ/RTU/MRA/DREQ/DREP/LAP msgs
  62  *      Active connection side for INCOMING REP/REJ/MRA/DREQ/DREP/APR msgs
  63  *      Active side CM for outgoing REQ message.
  64  *
  65  * NOTE: Only return IBCM_LOOKUP_FAIL if lookup failed to find a match.
  66  *
  67  * Arguments are:-
  68  *      event_type      - type of message
  69  *                      incoming REQ, REP, REJ, MRA, RTU
  70  *      remote_qpn      - Remote QP number
  71  *      comid           - local/remote comid
  72  *      remote_hca_guid - Remote HCA GUID
  73  *      hcap            - HCA entry ptr
  74  *      rstatep         - return statep pointer
  75  *
  76  * Return Values:
  77  *      IBCM_LOOKUP_NEW         - new statep allocated
  78  *      IBCM_LOOKUP_EXISTS      - found an existing entry
  79  *      IBCM_LOOKUP_FAIL        - No lookup entry found
  80  *      IBCM_MEMORY_FAILURE     - Memory allocs failed
  81  */
  82 ibcm_status_t
  83 ibcm_lookup_msg(ibcm_event_type_t event_type, ib_com_id_t comid,
  84     ib_qpn_t remote_qpn, ib_guid_t remote_hca_guid, ibcm_hca_info_t *hcap,
  85     ibcm_state_data_t **rstatep)
  86 {
  87         avl_index_t             where;
  88         ibcm_state_data_t       *sp;
  89 
  90         IBTF_DPRINTF_L4(cmlog, "ibcm_lookup_msg: event = 0x%x, comid = 0x%x",
  91             event_type, comid);
  92         IBTF_DPRINTF_L4(cmlog, "ibcm_lookup_msg: rem_qpn = 0x%lX, "
  93             "rem_hca_guid = 0x%llX", remote_qpn, remote_hca_guid);
  94 
  95         ASSERT(rw_lock_held(&hcap->hca_state_rwlock));
  96 
  97         /*
  98          * Lookup in "hca_passive_tree" for IBCM_INCOMING_REQ and
  99          * IBCM_INCOMING_REP_STALE;
 100          *
 101          * Lookup in "hca_passive_comid_tree" for IBCM_INCOMING_REQ_STALE
 102          *
 103          * All other lookups in "hca_active_tree".
 104          *
 105          * NOTE: "hca_active_tree" lookups are based on the local comid.
 106          * "hca_passive_state_tree" lookups are based on remote QPN
 107          * and remote hca GUID.
 108          *
 109          * Call avl_find to lookup in the respective tree and save result in
 110          * "sp". If "sp" is null it implies that no match was found. If so,
 111          * allocate a new ibcm_state_data_t and insert it into the AVL tree(s).
 112          */
 113         if ((event_type == IBCM_INCOMING_REQ) ||
 114             (event_type == IBCM_INCOMING_REP_STALE)) {
 115                 ibcm_passive_node_info_t        info;
 116 
 117                 info.info_qpn = remote_qpn;
 118                 info.info_hca_guid = remote_hca_guid;
 119 
 120                 /* Lookup based on Remote QPN and Remote GUID in Passive Tree */
 121                 sp = avl_find(&hcap->hca_passive_tree, &info, &where);
 122         } else if ((event_type == IBCM_INCOMING_REQ_STALE) ||
 123             (event_type == IBCM_INCOMING_REJ_RCOMID)) {
 124                 ibcm_passive_comid_node_info_t  info;
 125 
 126                 info.info_comid = comid;
 127                 info.info_hca_guid = remote_hca_guid;
 128 
 129                 /* Lookup based on Remote COMID in Passive Tree */
 130                 sp = avl_find(&hcap->hca_passive_comid_tree, &info, &where);
 131         } else {        /* any other event including IBCM_OUTGOING_REQ */
 132                 /* Lookup based on Local comid in Active Tree */
 133                 sp = avl_find(&hcap->hca_active_tree, &comid, &where);
 134         }
 135 
 136         /* matching entry found !! */
 137         if (sp != NULL) {
 138                 IBTF_DPRINTF_L4(cmlog, "ibcm_lookup_msg: match found "
 139                     "statep = %p", sp);
 140                 if (event_type == IBCM_INCOMING_REQ)
 141                         kmem_free(*rstatep, sizeof (ibcm_state_data_t));
 142                 *rstatep = sp;          /* return the matched statep */
 143 
 144                 mutex_enter(&(sp->state_mutex));
 145                 IBCM_REF_CNT_INCR(sp); /* increment the ref count */
 146                 mutex_exit(&(sp->state_mutex));
 147 
 148                 return (IBCM_LOOKUP_EXISTS);
 149         }
 150 
 151         /*
 152          * If we came here then it implies that CM didn't
 153          * find a matching entry. We will create a new entry in avl tree,
 154          * if event_type is INCOMING/OUTGOING REQ, REQ_STALE/REP_STALE.
 155          * statep is created for INCOMING/OUTGOING REQ.
 156          * For all other event_types we return lookup failure
 157          */
 158         if (!((event_type == IBCM_INCOMING_REQ) ||
 159             (event_type == IBCM_INCOMING_REQ_STALE) ||
 160             (event_type == IBCM_INCOMING_REP_STALE) ||
 161             (event_type == IBCM_OUTGOING_REQ))) {
 162                 IBTF_DPRINTF_L2(cmlog, "ibcm_lookup_msg: failed for "
 163                     "event type %x remote_comid = 0x%x",
 164                     event_type, comid);
 165 
 166                 return (IBCM_LOOKUP_FAIL);
 167         }
 168 
 169         if ((event_type == IBCM_INCOMING_REQ) ||
 170             (event_type == IBCM_OUTGOING_REQ)) {
 171 
 172                 /* fill in the new ibcm_state_data */
 173                 sp = *rstatep;
 174 
 175                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sp))
 176 
 177                 /* initialize statep */
 178                 mutex_init(&sp->state_mutex, NULL, MUTEX_DEFAULT, NULL);
 179                 cv_init(&sp->block_client_cv, NULL, CV_DRIVER, NULL);
 180                 cv_init(&sp->block_mad_cv, NULL, CV_DRIVER, NULL);
 181 
 182                 sp->hcap = hcap;
 183                 IBCM_REF_CNT_INCR(sp);
 184                 sp->local_comid = comid;
 185 
 186                 if (ibcm_enable_trace != 0)
 187                         ibcm_init_conn_trace(sp);
 188 
 189                 if (event_type == IBCM_INCOMING_REQ) {  /* Passive side */
 190                         sp->state = IBCM_STATE_REQ_RCVD;
 191                         sp->clnt_proceed = IBCM_BLOCK;
 192                         sp->close_nocb_state = IBCM_UNBLOCK;
 193                         sp->remote_hca_guid = remote_hca_guid;
 194                         sp->remote_qpn = remote_qpn;
 195 
 196                 } else if (event_type == IBCM_OUTGOING_REQ) { /* Active side */
 197                         sp->close_nocb_state = IBCM_UNBLOCK;
 198                         sp->state = IBCM_STATE_IDLE;
 199                 }
 200 
 201                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sp))
 202 
 203         } else {
 204                 sp = *rstatep;  /* for incoming REQ/REP STALE only */
 205         }
 206 
 207         if ((event_type == IBCM_INCOMING_REQ) ||
 208             (event_type == IBCM_INCOMING_REP_STALE)) {
 209 
 210                 /* First, insert a new "sp" into "hca_passive_tree" @ "where" */
 211                 avl_insert(&(hcap->hca_passive_tree), (void *)sp, where);
 212 
 213                 if (event_type == IBCM_INCOMING_REQ) {  /* Only INCOMING_REQ */
 214                         /*
 215                          * We have to do an avl_find() to figure out
 216                          * "where" to insert the statep into the active tree.
 217                          *
 218                          * CM doesn't care for avl_find's retval.
 219                          */
 220                         (void) avl_find(&hcap->hca_active_tree,
 221                             &sp->local_comid, &where);
 222 
 223                         /* Next, insert the "sp" into "hca_active_tree" */
 224                         avl_insert(&hcap->hca_active_tree, (void *)sp, where);
 225                 }
 226         } else if (event_type == IBCM_INCOMING_REQ_STALE) {
 227                 avl_insert(&(hcap->hca_passive_comid_tree), (void *)sp, where);
 228         } else {        /* IBCM_OUTGOING_REQ */
 229                 /* Insert the new sp only into "hca_active_tree", @ "where" */
 230                 avl_insert(&(hcap->hca_active_tree), (void *)sp, where);
 231         }
 232 
 233         return (IBCM_LOOKUP_NEW);       /* return new lookup */
 234 }
 235 
 236 
 237 /*
 238  * ibcm_active_node_compare:
 239  *      - AVL active tree node compare
 240  *
 241  * Arguments:
 242  *      p1      : pointer to local comid
 243  *      p2      : pointer to passed ibcm_state_data_t
 244  *
 245  * Return values:
 246  *      0       : match found
 247  *      -1      : no match but insert to left side of the tree
 248  *      +1      : no match but insert to right side of the tree
 249  */
 250 int
 251 ibcm_active_node_compare(const void *p1, const void *p2)
 252 {
 253         ib_com_id_t             *local_comid = (ib_com_id_t *)p1;
 254         ibcm_state_data_t       *statep = (ibcm_state_data_t *)p2;
 255 
 256         IBTF_DPRINTF_L5(cmlog, "ibcm_active_node_compare: "
 257             "comid: 0x%x, statep: 0x%p", *local_comid, statep);
 258 
 259         if (*local_comid > statep->local_comid) {
 260                 return (+1);
 261         } else if (*local_comid < statep->local_comid) {
 262                 return (-1);
 263         } else {
 264                 return (0);
 265         }
 266 }
 267 
 268 
 269 /*
 270  * ibcm_passive_node_compare:
 271  *      - AVL passive tree node compare (passive side)
 272  *
 273  * Arguments:
 274  *      p1      : pointer to ibcm_passive_node_info (remote qpn and remote guid)
 275  *      p2      : pointer to passed ibcm_state_data_t
 276  *
 277  * Return values:
 278  *      0       : match found
 279  *      -1      : no match but insert to left side of the tree
 280  *      +1      : no match but insert to right side of the tree
 281  */
 282 int
 283 ibcm_passive_node_compare(const void *p1, const void *p2)
 284 {
 285         ibcm_state_data_t               *statep = (ibcm_state_data_t *)p2;
 286         ibcm_passive_node_info_t        *infop = (ibcm_passive_node_info_t *)p1;
 287 
 288         IBTF_DPRINTF_L5(cmlog, "ibcm_passive_node_compare: "
 289             "statep: 0x%p, p1: 0x%p", statep, p1);
 290 
 291         /*
 292          * PASSIVE SIDE: (REQ, REP, MRA, REJ)
 293          *      always search by active COMID
 294          */
 295         if (infop->info_qpn > statep->remote_qpn) {
 296                 return (+1);
 297         } else if (infop->info_qpn < statep->remote_qpn) {
 298                 return (-1);
 299         } else {
 300                 if (infop->info_hca_guid < statep->remote_hca_guid) {
 301                         return (-1);
 302                 } else if (infop->info_hca_guid > statep->remote_hca_guid) {
 303                         return (+1);
 304                 } else {
 305                         return (0);
 306                 }
 307         }
 308 }
 309 
 310 /*
 311  * ibcm_passive_comid_node_compare:
 312  *      - AVL passive comid tree node compare (passive side)
 313  *
 314  * Arguments:
 315  *      p1      : pointer to ibcm_passive_comid_node_info
 316  *                (remote comid and remote guid)
 317  *      p2      : pointer to passed ibcm_state_data_t
 318  *
 319  * Return values:
 320  *      0       : match found
 321  *      -1      : no match but insert to left side of the tree
 322  *      +1      : no match but insert to right side of the tree
 323  */
 324 int
 325 ibcm_passive_comid_node_compare(const void *p1, const void *p2)
 326 {
 327         ibcm_state_data_t               *statep = (ibcm_state_data_t *)p2;
 328         ibcm_passive_comid_node_info_t  *infop =
 329             (ibcm_passive_comid_node_info_t *)p1;
 330 
 331         IBTF_DPRINTF_L5(cmlog, "ibcm_passive_comid_node_compare: "
 332             "statep: 0x%p, p1: 0x%p", statep, p1);
 333 
 334         if (infop->info_comid > statep->remote_comid) {
 335                 return (+1);
 336         } else if (infop->info_comid < statep->remote_comid) {
 337                 return (-1);
 338         } else {
 339                 if (infop->info_hca_guid < statep->remote_hca_guid) {
 340                         return (-1);
 341                 } else if (infop->info_hca_guid > statep->remote_hca_guid) {
 342                         return (+1);
 343                 } else {
 344                         return (0);
 345                 }
 346         }
 347 }
 348 
 349 
 350 void
 351 ibcm_delete_state_from_avl(ibcm_state_data_t *statep)
 352 {
 353         avl_index_t                     a_where = 0;
 354         avl_index_t                     p_where = 0;
 355         avl_index_t                     pcomid_where = 0;
 356         ibcm_hca_info_t                 *hcap;
 357         ibcm_state_data_t               *active_nodep, *passive_nodep;
 358         ibcm_state_data_t               *passive_comid_nodep;
 359         ibcm_passive_node_info_t        info;
 360         ibcm_passive_comid_node_info_t  info_comid;
 361 
 362         IBTF_DPRINTF_L4(cmlog, "ibcm_delete_state_from_avl: statep 0x%p",
 363             statep);
 364 
 365         if (statep == NULL) {
 366                 IBTF_DPRINTF_L2(cmlog, "ibcm_delete_state_from_avl: statep"
 367                     " NULL");
 368                 return;
 369         }
 370 
 371         hcap = statep->hcap;
 372 
 373         /*
 374          * Once the avl tree lock is acquired, no other thread can increment
 375          * ref cnt, until tree lock is exit'ed. Since the statep is removed
 376          * from the avl's after acquiring lock below, no other thread can
 377          * increment the ref cnt after acquiring the lock below
 378          */
 379 
 380         rw_enter(&hcap->hca_state_rwlock, RW_WRITER);
 381 
 382         /* Lookup based on Local comid in the active tree */
 383         active_nodep = avl_find(&hcap->hca_active_tree, &(statep->local_comid),
 384             &a_where);
 385 
 386         /* Lookup based on Remote QPN and Remote GUID in the passive tree */
 387         info.info_qpn = statep->remote_qpn;
 388         info.info_hca_guid = statep->remote_hca_guid;
 389         passive_nodep =  avl_find(&hcap->hca_passive_tree, &info, &p_where);
 390 
 391         /* Lookup based on Remote Comid and Remote GUID in the passive tree */
 392         info_comid.info_comid = statep->remote_comid;
 393         info_comid.info_hca_guid = statep->remote_hca_guid;
 394         passive_comid_nodep =  avl_find(&hcap->hca_passive_comid_tree,
 395             &info_comid, &pcomid_where);
 396 
 397         /* remove it from the tree, destroy record and the nodep */
 398         if (active_nodep == statep) {
 399                 avl_remove(&hcap->hca_active_tree, active_nodep);
 400         }
 401 
 402         if (passive_nodep == statep) {
 403                 avl_remove(&hcap->hca_passive_tree, passive_nodep);
 404         }
 405 
 406         if (passive_comid_nodep == statep) {
 407                 avl_remove(&hcap->hca_passive_comid_tree, passive_comid_nodep);
 408         }
 409 
 410         rw_exit(&hcap->hca_state_rwlock);
 411 }
 412 
 413 /*
 414  * ibcm_dealloc_state_data:
 415  *      Deallocates all buffers and the memory of state structure
 416  * This routine can be called on statep that has ref_cnt of 0, and that is
 417  * already deleted from the avl tree's
 418  *
 419  * Arguments are:-
 420  *      statep  - statep to be deleted
 421  *
 422  * Return Values:       NONE
 423  */
 424 void
 425 ibcm_dealloc_state_data(ibcm_state_data_t *statep)
 426 {
 427         timeout_id_t timer_val;
 428         int dump_trace;
 429         IBTF_DPRINTF_L4(cmlog, "ibcm_dealloc_state_data: statep 0x%p", statep);
 430 
 431         if (statep == NULL) {
 432                 IBTF_DPRINTF_L2(cmlog, "ibcm_dealloc_state_data: statep NULL");
 433                 return;
 434         }
 435 
 436         /* ref_cnt is 0 */
 437         /* If timer is running - expire it */
 438         mutex_enter(&statep->state_mutex);
 439         timer_val = statep->timerid;
 440         if (timer_val != 0) {
 441                 statep->timerid = 0;
 442                 mutex_exit(&statep->state_mutex);
 443                 (void) untimeout(timer_val);
 444         } else
 445                 mutex_exit(&statep->state_mutex);
 446 
 447         /* release the ref cnt on the associated ibmf qp */
 448         if (statep->stored_reply_addr.cm_qp_entry != NULL)
 449                 ibcm_release_qp(statep->stored_reply_addr.cm_qp_entry);
 450 
 451         if (statep->stored_msg != NULL)
 452                 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
 453                     &statep->stored_msg);
 454 
 455         if (statep->dreq_msg != NULL)
 456                 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
 457                     &statep->dreq_msg);
 458 
 459         if (statep->drep_msg != NULL)
 460                 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
 461                     &statep->drep_msg);
 462 
 463         if (statep->mra_msg != NULL)
 464                 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
 465                     &statep->mra_msg);
 466 
 467         if (statep->lapr_msg != NULL)
 468                 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
 469                     &statep->lapr_msg);
 470 
 471         if (statep->defer_cm_msg != NULL)
 472                 kmem_free(statep->defer_cm_msg, IBCM_MSG_SIZE);
 473 
 474         IBTF_DPRINTF_L4(cmlog, "ibcm_dealloc_state_data: done for sp = 0x%p",
 475             statep);
 476 
 477         /* Ensure the thread doing ref cnt decr releases the mutex */
 478         mutex_enter(&statep->state_mutex);
 479         dump_trace = statep->cm_retries > 0;
 480         mutex_exit(&statep->state_mutex);
 481 
 482         /*
 483          * now call the mutex_destroy() and cv_destroy()
 484          */
 485         mutex_destroy(&statep->state_mutex);
 486 
 487         cv_destroy(&statep->block_client_cv);
 488         cv_destroy(&statep->block_mad_cv);
 489 
 490         /* free the comid */
 491         ibcm_free_comid(statep->hcap, statep->local_comid);
 492 
 493         /* Decrement the resource on hcap */
 494         ibcm_dec_hca_res_cnt(statep->hcap);
 495 
 496         /* dump the trace data into ibtf_debug_buf */
 497         if ((ibcm_enable_trace & 4) || dump_trace)
 498                 ibcm_dump_conn_trace(statep);
 499 
 500         ibcm_fini_conn_trace(statep);
 501 
 502         /* free the statep */
 503         kmem_free(statep, sizeof (ibcm_state_data_t));
 504 }
 505 
 506 /*
 507  * ibcm_delete_state_data:
 508  *      Deletes the state from avl trees, and tries to deallocate state
 509  *
 510  * Arguments are:-
 511  *      statep  - statep to be deleted
 512  *
 513  * Return Values:       NONE
 514  */
 515 void
 516 ibcm_delete_state_data(ibcm_state_data_t *statep)
 517 {
 518         IBTF_DPRINTF_L4(cmlog, "ibcm_delete_state_data:");
 519 
 520         ibcm_delete_state_from_avl(statep);
 521 
 522         /* Must acquire the state mutex to set delete_state_data */
 523         mutex_enter(&statep->state_mutex);
 524         if (statep->ref_cnt > 0) {
 525                 statep->delete_state_data = B_TRUE;
 526                 IBTF_DPRINTF_L4(cmlog, "ibcm_delete_state_data: statep 0x%p "
 527                     "ref_cnt = %x", statep, statep->ref_cnt);
 528                 mutex_exit(&statep->state_mutex);
 529                 return;
 530         }
 531         mutex_exit(&statep->state_mutex);
 532 
 533         ibcm_dealloc_state_data(statep);
 534 }
 535 
 536 /*
 537  * ibcm_find_sidr_entry:
 538  *      Routines for CM SIDR state structure list manipulation.
 539  *      Finds an entry based on lid, gid and grh exists fields
 540  *
 541  * INPUTS:
 542  *      lid:            LID of incoming SIDR REQ
 543  *      gid:            GID of incoming SIDR REQ
 544  *      grh_exists:     TRUE if GRH exists in the incoming SIDR REQ
 545  *      req_id:         Request ID
 546  *      hcap:           CM State table to search for SIDR state structure
 547  *      statep:         Returns a valid state structure, if one exists based
 548  *                      on lid, gid and grh_exists fields
 549  *      flag:           IBCM_FLAG_LOOKUP - just lookup
 550  *                      IBCM_FLAG_LOOKUP_AND_ADD - if lookup fails, add it.
 551  * Return Values:
 552  *      IBCM_LOOKUP_EXISTS      - found an existing entry
 553  *      IBCM_LOOKUP_FAIL        - failed to find an entry
 554  *      IBCM_LOOKUP_NEW         - created a new entry
 555  */
 556 ibcm_status_t
 557 ibcm_find_sidr_entry(ibcm_sidr_srch_t *srch_param, ibcm_hca_info_t *hcap,
 558     ibcm_ud_state_data_t **ud_statep, ibcm_lookup_flag_t flag)
 559 {
 560         ibcm_status_t           status;
 561         ibcm_ud_state_data_t    *usp;
 562 
 563         IBTF_DPRINTF_L5(cmlog, "ibcm_find_sidr_entry: srch_params are:"
 564             "lid=%x, (%llX, %llX), grh: %x, id: %x",
 565             srch_param->srch_lid, srch_param->srch_gid.gid_prefix,
 566             srch_param->srch_gid.gid_guid, srch_param->srch_grh_exists,
 567             srch_param->srch_req_id);
 568 
 569         if (flag == IBCM_FLAG_ADD) {
 570                 *ud_statep = ibcm_add_sidr_entry(srch_param, hcap);
 571                 return (IBCM_LOOKUP_NEW);
 572         }
 573 
 574         usp = hcap->hca_sidr_list;   /* Point to the list */
 575 
 576         /* traverse the list for a matching entry */
 577         while (usp != NULL) {
 578                 IBTF_DPRINTF_L5(cmlog, "ibcm_find_sidr_entry: "
 579                     "lid=%x, (%llX, %llX), grh: %x, id: %x",
 580                     usp->ud_sidr_req_lid, usp->ud_sidr_req_gid.gid_prefix,
 581                     usp->ud_sidr_req_gid.gid_guid, usp->ud_grh_exists,
 582                     usp->ud_req_id);
 583 
 584                 if ((usp->ud_sidr_req_lid == srch_param->srch_lid) &&
 585                     ((srch_param->srch_gid.gid_prefix == 0) ||
 586                     (srch_param->srch_gid.gid_prefix ==
 587                     usp->ud_sidr_req_gid.gid_prefix)) &&
 588                     ((srch_param->srch_gid.gid_guid == 0) ||
 589                     (srch_param->srch_gid.gid_guid ==
 590                     usp->ud_sidr_req_gid.gid_guid)) &&
 591                     (srch_param->srch_req_id == usp->ud_req_id) &&
 592                     (usp->ud_grh_exists == srch_param->srch_grh_exists) &&
 593                     (usp->ud_mode == srch_param->srch_mode)) { /* found match */
 594                         *ud_statep = usp;
 595                         IBTF_DPRINTF_L5(cmlog, "ibcm_find_sidr_entry: "
 596                             "found usp = %p", usp);
 597                         mutex_enter(&usp->ud_state_mutex);
 598                         IBCM_UD_REF_CNT_INCR(usp);
 599                         mutex_exit(&usp->ud_state_mutex);
 600 
 601                         return (IBCM_LOOKUP_EXISTS);
 602                 }
 603                 usp = usp->ud_nextp;
 604         }
 605 
 606         /*
 607          * If code came here --> it couldn't find a match.
 608          *      OR
 609          * the "hcap->hca_sidr_list" was NULL
 610          */
 611         if (flag == IBCM_FLAG_LOOKUP) {
 612                 IBTF_DPRINTF_L3(cmlog, "ibcm_find_sidr_entry: no match found "
 613                     "lid=%x, (%llX, %llX), grh: %x, id: %x",
 614                     srch_param->srch_lid, srch_param->srch_gid.gid_prefix,
 615                     srch_param->srch_gid.gid_guid, srch_param->srch_grh_exists,
 616                     srch_param->srch_req_id);
 617                 status = IBCM_LOOKUP_FAIL;
 618         } else {
 619                 *ud_statep = ibcm_add_sidr_entry(srch_param, hcap);
 620                 status = IBCM_LOOKUP_NEW;
 621         }
 622 
 623         return (status);
 624 }
 625 
 626 
 627 /*
 628  * ibcm_add_sidr_entry:
 629  *      Adds a SIDR entry. Called *ONLY* from ibcm_find_sidr_entry()
 630  *
 631  * INPUTS:
 632  *      lid:            LID of incoming SIDR REQ
 633  *      gid:            GID of incoming SIDR REQ
 634  *      grh_exists:     TRUE if GRH exists in the incoming SIDR REQ
 635  *      req_id:         Request ID
 636  *      hcap:           CM State table to search for SIDR state structure
 637  * Return Values: NONE
 638  */
 639 ibcm_ud_state_data_t *
 640 ibcm_add_sidr_entry(ibcm_sidr_srch_t *srch_param, ibcm_hca_info_t *hcap)
 641 {
 642         ibcm_ud_state_data_t    *ud_statep;
 643 
 644         IBTF_DPRINTF_L5(cmlog, "ibcm_add_sidr_entry: lid=%x, guid=%llX, "
 645             "grh = %x req_id = %x", srch_param->srch_lid,
 646             srch_param->srch_gid.gid_guid, srch_param->srch_grh_exists,
 647             srch_param->srch_req_id);
 648 
 649         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ud_statep))
 650 
 651         /* didn't find the entry - so create new */
 652         ud_statep = kmem_zalloc(sizeof (ibcm_ud_state_data_t), KM_SLEEP);
 653 
 654         mutex_init(&ud_statep->ud_state_mutex, NULL, MUTEX_DEFAULT, NULL);
 655         cv_init(&ud_statep->ud_block_client_cv, NULL, CV_DRIVER, NULL);
 656 
 657         /* Initialize some ud_statep fields */
 658         mutex_enter(&ud_statep->ud_state_mutex);
 659         ud_statep->ud_hcap           = hcap;
 660         ud_statep->ud_req_id         = srch_param->srch_req_id;
 661         ud_statep->ud_ref_cnt                = 1;
 662         ud_statep->ud_grh_exists     = srch_param->srch_grh_exists;
 663         ud_statep->ud_sidr_req_lid   = srch_param->srch_lid;
 664         ud_statep->ud_sidr_req_gid   = srch_param->srch_gid;
 665         ud_statep->ud_mode           = srch_param->srch_mode;
 666         ud_statep->ud_max_cm_retries = ibcm_max_retries;
 667         mutex_exit(&ud_statep->ud_state_mutex);
 668 
 669         /* Update the list */
 670         ud_statep->ud_nextp = hcap->hca_sidr_list;
 671         hcap->hca_sidr_list = ud_statep;
 672 
 673         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ud_statep))
 674 
 675         return (ud_statep);
 676 }
 677 
 678 
 679 /*
 680  * ibcm_delete_ud_state_data:
 681  *      Deletes a given state structure
 682  *
 683  * Arguments are:-
 684  *      statep  - statep to be deleted
 685  *
 686  * Return Values:       NONE
 687  */
 688 void
 689 ibcm_delete_ud_state_data(ibcm_ud_state_data_t *ud_statep)
 690 {
 691         ibcm_ud_state_data_t    *prevp, *headp;
 692         ibcm_hca_info_t         *hcap;
 693 
 694         IBTF_DPRINTF_L4(cmlog, "ibcm_delete_ud_state_data: ud_statep 0x%p",
 695             ud_statep);
 696 
 697         if (ud_statep == NULL || ud_statep->ud_hcap == NULL) {
 698                 IBTF_DPRINTF_L2(cmlog, "ibcm_delete_ud_state_data: "
 699                     "ud_statep or hcap is NULL");
 700                 return;
 701         }
 702 
 703         hcap = ud_statep->ud_hcap;
 704 
 705         rw_enter(&hcap->hca_sidr_list_lock, RW_WRITER);
 706 
 707         /* Next, remove this from the HCA SIDR list */
 708         if (hcap->hca_sidr_list != NULL) {
 709                 prevp = NULL;
 710                 headp = hcap->hca_sidr_list;
 711 
 712                 while (headp != NULL) {
 713                         /* delete the matching entry */
 714                         if (headp == ud_statep) {
 715                                 if (prevp) {
 716                                         prevp->ud_nextp = headp->ud_nextp;
 717                                 } else {
 718                                         prevp = headp->ud_nextp;
 719                                         hcap->hca_sidr_list = prevp;
 720                                 }
 721                                 break;
 722                         }
 723                         prevp = headp;
 724                         headp = headp->ud_nextp;
 725                 }
 726         }
 727 
 728         rw_exit(&hcap->hca_sidr_list_lock);
 729 
 730         /*
 731          * While ref_cnt >  0
 732          * - implies someone else is accessing the statep (possibly in
 733          * a timeout function handler etc.)
 734          * - don't delete statep unless they are done otherwise potentially
 735          * one could access released memory and panic.
 736          */
 737         mutex_enter(&ud_statep->ud_state_mutex);
 738         if (ud_statep->ud_ref_cnt > 0) {
 739                 ud_statep->ud_delete_state_data = B_TRUE;
 740                 IBTF_DPRINTF_L4(cmlog, "ibcm_delete_ud_state_data: "
 741                     "ud_statep 0x%p ud_ref_cnt = %x", ud_statep,
 742                     ud_statep->ud_ref_cnt);
 743                 mutex_exit(&ud_statep->ud_state_mutex);
 744                 return;
 745         }
 746         mutex_exit(&ud_statep->ud_state_mutex);
 747 
 748         ibcm_dealloc_ud_state_data(ud_statep);
 749 }
 750 
 751 /*
 752  * ibcm_ud_dealloc_state_data:
 753  *      Deallocates a given ud state structure
 754  *
 755  * Arguments are:-
 756  *      ud statep       - ud statep to be deleted
 757  *
 758  * Return Values:       NONE
 759  */
 760 void
 761 ibcm_dealloc_ud_state_data(ibcm_ud_state_data_t *ud_statep)
 762 {
 763         timeout_id_t            timer_val;
 764 
 765         IBTF_DPRINTF_L4(cmlog, "ibcm_dealloc_ud_state_data: ud_statep 0x%p",
 766             ud_statep);
 767 
 768         /* If timer is running - expire it */
 769         mutex_enter(&ud_statep->ud_state_mutex);
 770         if (ud_statep->ud_timerid) {
 771                 timer_val = ud_statep->ud_timerid;
 772                 ud_statep->ud_timerid = 0;
 773                 mutex_exit(&ud_statep->ud_state_mutex);
 774                 (void) untimeout(timer_val);
 775                 IBTF_DPRINTF_L2(cmlog, "ibcm_dealloc_ud_state_data: "
 776                     "Unexpected timer id 0x%p ud_statep 0x%p", timer_val,
 777                     ud_statep);
 778         } else
 779                 mutex_exit(&ud_statep->ud_state_mutex);
 780 
 781         if (ud_statep->ud_stored_msg != NULL) {
 782                 (void) ibcm_free_out_msg(
 783                     ud_statep->ud_stored_reply_addr.ibmf_hdl,
 784                     &ud_statep->ud_stored_msg);
 785         }
 786 
 787         /* release the ref cnt on the associated ibmf qp */
 788         ASSERT(ud_statep->ud_stored_reply_addr.cm_qp_entry != NULL);
 789         ibcm_release_qp(ud_statep->ud_stored_reply_addr.cm_qp_entry);
 790 
 791         /* Ensure the thread doing ref cnt decr releases the mutex */
 792         mutex_enter(&ud_statep->ud_state_mutex);
 793         mutex_exit(&ud_statep->ud_state_mutex);
 794 
 795         /* now do the mutex_destroy() and cv_destroy() */
 796         mutex_destroy(&ud_statep->ud_state_mutex);
 797 
 798         cv_destroy(&ud_statep->ud_block_client_cv);
 799 
 800         /* free the req id on SIDR REQ sender side */
 801         if (ud_statep->ud_mode == IBCM_ACTIVE_MODE)
 802                 ibcm_free_reqid(ud_statep->ud_hcap, ud_statep->ud_req_id);
 803 
 804         /* Decrement the resource on hcap */
 805         ibcm_dec_hca_res_cnt(ud_statep->ud_hcap);
 806 
 807         /* free the statep */
 808         kmem_free(ud_statep, sizeof (ibcm_ud_state_data_t));
 809 }
 810 
 811 
 812 /*
 813  * ibcm_init_ids:
 814  *      Create the vmem arenas for the various global ids
 815  *
 816  * Arguments are:-
 817  *      NONE
 818  *
 819  * Return Values:       ibcm_status_t
 820  */
 821 
 822 ibcm_status_t
 823 ibcm_init_ids(void)
 824 {
 825         timespec_t tv;
 826 
 827         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_local_sid_arena))
 828         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_ip_sid_arena))
 829         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_local_sid_seed))
 830         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_local_cid_seed))
 831 
 832         ibcm_local_sid_arena = vmem_create("ibcm_local_sid",
 833             (void *)IBCM_INITIAL_SID, IBCM_MAX_LOCAL_SIDS, 1, NULL, NULL, NULL,
 834             0, VM_SLEEP | VMC_IDENTIFIER);
 835 
 836         if (!ibcm_local_sid_arena)
 837                 return (IBCM_FAILURE);
 838 
 839         ibcm_ip_sid_arena = vmem_create("ibcm_ip_sid", (void *)IBCM_INITIAL_SID,
 840             IBCM_MAX_IP_SIDS, 1, NULL, NULL, NULL, 0,
 841             VM_SLEEP | VMC_IDENTIFIER);
 842 
 843         if (!ibcm_ip_sid_arena)
 844                 return (IBCM_FAILURE);
 845 
 846         /* create a random starting value for local service ids */
 847         gethrestime(&tv);
 848         ibcm_local_sid_seed = ((uint64_t)tv.tv_sec << 20) & 0x007FFFFFFFF00000;
 849         ASSERT((ibcm_local_sid_seed & IB_SID_AGN_MASK) == 0);
 850         ibcm_local_sid_seed |= IB_SID_AGN_LOCAL;
 851 
 852         ibcm_local_cid_seed = (ib_com_id_t)tv.tv_sec;
 853         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_local_sid_arena))
 854         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_local_sid_seed))
 855         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_ip_sid_arena))
 856         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_local_cid_seed))
 857 
 858         return (IBCM_SUCCESS);
 859 }
 860 
 861 
 862 /*
 863  * ibcm_init_hca_ids:
 864  *      Create the vmem arenas for the various hca level ids
 865  *
 866  * Arguments are:-
 867  *      hcap            pointer to ibcm_hca_info_t
 868  *
 869  * Return Values:       ibcm_status_t
 870  */
 871 ibcm_status_t
 872 ibcm_init_hca_ids(ibcm_hca_info_t *hcap)
 873 {
 874         hcap->hca_comid_arena = vmem_create("ibcm_com_ids",
 875             (void *)IBCM_INITIAL_COMID, IBCM_MAX_COMIDS,
 876             1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER);
 877 
 878         if (!hcap->hca_comid_arena)
 879                 return (IBCM_FAILURE);
 880 
 881         hcap->hca_reqid_arena = vmem_create("ibcm_req_ids",
 882             (void *)IBCM_INITIAL_REQID, IBCM_MAX_REQIDS,
 883             1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER);
 884 
 885         if (!hcap->hca_reqid_arena) {
 886                 vmem_destroy(hcap->hca_comid_arena);
 887                 return (IBCM_FAILURE);
 888         }
 889 
 890         return (IBCM_SUCCESS);
 891 }
 892 
 893 /*
 894  * ibcm_free_ids:
 895  *      Destroy the vmem arenas for the various ids
 896  *
 897  * Arguments are:-
 898  *      NONE
 899  *
 900  * Return Values:       NONE
 901  */
 902 void
 903 ibcm_fini_ids(void)
 904 {
 905         /* All arenas shall be valid */
 906         vmem_destroy(ibcm_local_sid_arena);
 907         vmem_destroy(ibcm_ip_sid_arena);
 908 }
 909 
 910 /*
 911  * ibcm_free_hca_ids:
 912  *      Destroy the vmem arenas for the various ids
 913  *
 914  * Arguments are:-
 915  *      hcap            pointer to ibcm_hca_info_t
 916  *
 917  * Return Values:       NONE
 918  */
 919 void
 920 ibcm_fini_hca_ids(ibcm_hca_info_t *hcap)
 921 {
 922         /* All arenas shall be valid */
 923         vmem_destroy(hcap->hca_comid_arena);
 924         vmem_destroy(hcap->hca_reqid_arena);
 925 }
 926 
 927 /* Communication id management routines ie., allocate, free up comids */
 928 
 929 /*
 930  * ibcm_alloc_comid:
 931  *      Allocate a new communication id
 932  *
 933  * Arguments are:-
 934  *      hcap    :       pointer to ibcm_hca_info_t
 935  *      comid:          pointer to the newly allocated communication id
 936  *
 937  * Return Values:       ibt_status_t
 938  */
 939 ibcm_status_t
 940 ibcm_alloc_comid(ibcm_hca_info_t *hcap, ib_com_id_t *comidp)
 941 {
 942         ib_com_id_t comid;
 943 
 944         /* Use next fit, so least recently used com id is allocated */
 945         comid = (ib_com_id_t)(uintptr_t)vmem_alloc(hcap->hca_comid_arena, 1,
 946             VM_SLEEP | VM_NEXTFIT);
 947 
 948         IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_comid: hcap 0x%p comid 0x%lX", hcap,
 949             comid);
 950 
 951         /*
 952          * As comid is 32 bits, and maximum connections possible are 2^24
 953          * per hca, comid allocation would never fail
 954          */
 955         *comidp = comid + ibcm_local_cid_seed;
 956         if (comid == 0) {
 957                 IBTF_DPRINTF_L2(cmlog, "ibcm_alloc_comid: hcap 0x%p"
 958                     "no more comids available", hcap);
 959                 return (IBCM_FAILURE);
 960         }
 961 
 962         return (IBCM_SUCCESS);
 963 }
 964 
 965 /*
 966  * ibcm_free_comid:
 967  *      Releases the given Communication Id
 968  *
 969  * Arguments are:
 970  *      hcap    :       pointer to ibcm_hca_info_t
 971  *      comid   :       Communication id to be free'd
 972  *
 973  * Return Values:       NONE
 974  */
 975 void
 976 ibcm_free_comid(ibcm_hca_info_t *hcap, ib_com_id_t comid)
 977 {
 978         IBTF_DPRINTF_L4(cmlog, "ibcm_free_comid: hcap 0x%p"
 979             "comid %x", hcap, comid);
 980         comid -= ibcm_local_cid_seed;
 981         vmem_free(hcap->hca_comid_arena, (void *)(uintptr_t)comid, 1);
 982 }
 983 
 984 /* Allocate and Free local service ids */
 985 
 986 /*
 987  * ibcm_alloc_local_sids:
 988  *      Create and destroy the vmem arenas for the service ids
 989  *
 990  * Arguments are:-
 991  *      Number of contiguous SIDs needed
 992  *
 993  * Return Values:       starting SID
 994  */
 995 ib_svc_id_t
 996 ibcm_alloc_local_sids(int num_sids)
 997 {
 998         ib_svc_id_t sid;
 999 
1000         sid = (ib_svc_id_t)(uintptr_t)vmem_alloc(ibcm_local_sid_arena,
1001             num_sids, VM_SLEEP | VM_NEXTFIT);
1002 
1003         IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_local_sids: ServiceID 0x%llX "
1004             "num_sids %d", sid, num_sids);
1005         if (sid == 0) {
1006                 IBTF_DPRINTF_L2(cmlog, "ibcm_alloc_local_sids: "
1007                     "no more local sids available");
1008         } else {
1009                 ASSERT((ibcm_local_sid_seed & IB_SID_AGN_MASK) ==
1010                     IB_SID_AGN_LOCAL);
1011                 sid += ibcm_local_sid_seed;
1012                 IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_local_sids: Success: "
1013                     "allocated 0x%llX:%d", sid, num_sids);
1014         }
1015         return (sid);
1016 }
1017 
1018 /*
1019  * ibcm_free_local_sids:
1020  *      Releases the given Local service id
1021  *
1022  * Arguments are:
1023  *      num_sids:       Number of local service id's to be free'd
1024  *      service_id:     Starting local service id that needs to be free'd
1025  *
1026  * Return Values:       NONE
1027  */
1028 void
1029 ibcm_free_local_sids(ib_svc_id_t service_id, int num_sids)
1030 {
1031         service_id -= ibcm_local_sid_seed;
1032         IBTF_DPRINTF_L4(cmlog, "ibcm_free_local_sids: "
1033             "service_id 0x%llX num_sids %d", service_id, num_sids);
1034         vmem_free(ibcm_local_sid_arena,
1035             (void *)(uintptr_t)service_id, num_sids);
1036 }
1037 
1038 /*
1039  * ibcm_alloc_ip_sid:
1040  *      Allocate a local IP SID.
1041  */
1042 ib_svc_id_t
1043 ibcm_alloc_ip_sid()
1044 {
1045         ib_svc_id_t sid;
1046 
1047         sid = (ib_svc_id_t)(uintptr_t)vmem_alloc(ibcm_ip_sid_arena, 1,
1048             VM_SLEEP | VM_NEXTFIT);
1049         if (sid == 0) {
1050                 IBTF_DPRINTF_L2(cmlog, "ibcm_alloc_ip_sid: no more RDMA IP "
1051                     "SIDs available");
1052         } else {
1053                 sid += IB_SID_IPADDR_PREFIX;
1054                 IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_ip_sid: Success: RDMA IP SID"
1055                     " allocated : 0x%016llX", sid);
1056         }
1057         return (sid);
1058 }
1059 
1060 /*
1061  * ibcm_free_ip_sid:
1062  *      Releases the given IP Service ID
1063  */
1064 void
1065 ibcm_free_ip_sid(ib_svc_id_t sid)
1066 {
1067         sid -= IB_SID_IPADDR_PREFIX;
1068         vmem_free(ibcm_ip_sid_arena, (void *)(uintptr_t)sid, 1);
1069 }
1070 
1071 
1072 /* Allocate and free request id routines for SIDR */
1073 
1074 /*
1075  * ibcm_alloc_reqid:
1076  *      Allocate a new SIDR REQ request id
1077  *
1078  * Arguments are:-
1079  *      hcap    :       pointer to ibcm_hca_info_t
1080  *      *reqid  :       pointer to the new request id returned
1081  *
1082  * Return Values:       ibcm_status_t
1083  */
1084 ibcm_status_t
1085 ibcm_alloc_reqid(ibcm_hca_info_t *hcap, uint32_t *reqid)
1086 {
1087         /* Use next fit, so least recently used com id is allocated */
1088         *reqid = (uint32_t)(uintptr_t)vmem_alloc(hcap->hca_reqid_arena, 1,
1089             VM_SLEEP | VM_NEXTFIT);
1090 
1091         IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_reqid: hcap 0x%p reqid %x", hcap,
1092             *reqid);
1093         if (!(*reqid)) {
1094                 IBTF_DPRINTF_L2(cmlog, "ibcm_alloc_reqid: "
1095                     "no more req ids available");
1096                 return (IBCM_FAILURE);
1097         }
1098         return (IBCM_SUCCESS);
1099 }
1100 
1101 /*
1102  * ibcm_free_reqid:
1103  *      Releases the given SIDR REQ request id
1104  *
1105  * Arguments are:
1106  *      hcap    :       pointer to ibcm_hca_info_t
1107  *      reqid   :       Request id to be free'd
1108  *
1109  * Return Values:       NONE
1110  */
1111 void
1112 ibcm_free_reqid(ibcm_hca_info_t *hcap, uint32_t reqid)
1113 {
1114         IBTF_DPRINTF_L4(cmlog, "ibcm_free_reqid: hcap 0x%p reqid %x", hcap,
1115             reqid);
1116         vmem_free(hcap->hca_reqid_arena, (void *)(uintptr_t)reqid, 1);
1117 }
1118 
1119 /*
1120  * ibcm_generate_tranid:
1121  *      Generate a new transaction id based on args
1122  *
1123  * Arguments are:-
1124  *      event_type      CM Message REQ/DREQ/LAP
1125  *      id              32 bit identifier
1126  *      cm_tran_priv    CM private data to be filled in top 28 MSB bits of
1127  *                      tran id
1128  *
1129  *
1130  * Return Value:        uint64_t
1131  */
1132 uint64_t
1133 ibcm_generate_tranid(uint8_t event, uint32_t id, uint32_t cm_tran_priv)
1134 {
1135         /*
1136          * copy comid to bits 31-0 of tran id,
1137          * attr id to bits 35-32 of tran id,
1138          * cm_priv to bits 63-36 of tran id
1139          */
1140         if (cm_tran_priv == 0)
1141                 /*
1142                  * The below ensures that no duplicate transaction id is
1143                  * generated atleast for next 6 months. Calculations:
1144                  * (2^28)/(1000 * 60 * 24 * 30) = 6 approx
1145                  */
1146                 cm_tran_priv = gethrtime() >> 20; /* ~time in ms */
1147 
1148         return ((((uint64_t)cm_tran_priv << 36) | (uint64_t)event << 32) | id);
1149 }
1150 
1151 #ifdef DEBUG
1152 
1153 /*
1154  * ibcm_decode_tranid:
1155  *      Decodes a given transaction id, assuming certain format.
1156  *
1157  * Arguments are:-
1158  *      tran_id         Transaction id to be decoded
1159  *      cm_tran_priv    CM private data retrieved from transaction id
1160  *
1161  * Return Value:        None
1162  */
1163 void
1164 ibcm_decode_tranid(uint64_t tran_id, uint32_t *cm_tran_priv)
1165 {
1166         ib_com_id_t             id;
1167         ibcm_event_type_t       event;
1168 
1169         id = tran_id & 0xFFFFFFFF;
1170         event = (tran_id >> 32) & 0xF;
1171 
1172         IBTF_DPRINTF_L5(cmlog, "ibcm_decode_tranid: id = 0x%x, event = %x",
1173             id, event);
1174 
1175         if (cm_tran_priv) {
1176                 *cm_tran_priv = tran_id >> 36;
1177                 IBTF_DPRINTF_L5(cmlog, "ibcm_decode_tranid: "
1178                     "cm_tran_priv = %x", *cm_tran_priv);
1179         }
1180 }
1181 
1182 #endif
1183 
1184 /*
1185  * Service ID entry create and lookup functions
1186  */
1187 
1188 /*
1189  * ibcm_svc_compare:
1190  *      - AVL svc tree node compare
1191  *
1192  * Arguments:
1193  *      p1      : pointer to local comid
1194  *      p2      : pointer to passed ibcm_state_data_t
1195  *
1196  * Return values:
1197  *      0       : match found
1198  *      -1      : no match but insert to left side of the tree
1199  *      +1      : no match but insert to right side of the tree
1200  */
1201 int
1202 ibcm_svc_compare(const void *p1, const void *p2)
1203 {
1204         ibcm_svc_lookup_t       *sidp = (ibcm_svc_lookup_t *)p1;
1205         ibcm_svc_info_t         *svcp = (ibcm_svc_info_t *)p2;
1206         ib_svc_id_t             start_sid = sidp->sid;
1207         ib_svc_id_t             end_sid = start_sid + sidp->num_sids - 1;
1208 
1209         IBTF_DPRINTF_L5(cmlog, "ibcm_svc_compare: "
1210             "sid: 0x%llx, numsids: %d, node_sid: 0x%llx node_num_sids: %d",
1211             sidp->sid, sidp->num_sids, svcp->svc_id, svcp->svc_num_sids);
1212 
1213         ASSERT(MUTEX_HELD(&ibcm_svc_info_lock));
1214 
1215         if (svcp->svc_id > end_sid)
1216                 return (-1);
1217         if (svcp->svc_id + svcp->svc_num_sids - 1 < start_sid)
1218                 return (+1);
1219         return (0);     /* means there is some overlap of SIDs */
1220 }
1221 
1222 
1223 /*
1224  * ibcm_create_svc_entry:
1225  *      Make sure no conflicting entry exists, then allocate it.
1226  *      Fill in the critical "look up" details that are provided
1227  *      in the arguments before dropping the lock.
1228  *
1229  * Return values:
1230  *      Pointer to ibcm_svc_info_t, if created, otherwise NULL.
1231  */
1232 ibcm_svc_info_t *
1233 ibcm_create_svc_entry(ib_svc_id_t sid, int num_sids)
1234 {
1235         ibcm_svc_info_t *svcp;
1236         ibcm_svc_info_t *svcinfop;
1237         ibcm_svc_lookup_t svc;
1238         avl_index_t where = 0;
1239 
1240         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*svcinfop))
1241 
1242         /* assume success, and avoid kmem while holding the writer lock */
1243         svcinfop = kmem_zalloc(sizeof (*svcinfop), KM_SLEEP);
1244         svcinfop->svc_id = sid;
1245         svcinfop->svc_num_sids = num_sids;
1246 
1247         svc.sid = sid;
1248         svc.num_sids = num_sids;
1249 
1250         mutex_enter(&ibcm_svc_info_lock);
1251 #ifdef __lock_lint
1252         ibcm_svc_compare(NULL, NULL);
1253 #endif
1254         svcp = avl_find(&ibcm_svc_avl_tree, &svc, &where);
1255         if (svcp != NULL) {     /* overlab exists */
1256                 mutex_exit(&ibcm_svc_info_lock);
1257                 kmem_free(svcinfop, sizeof (*svcinfop));
1258                 return (NULL);
1259         }
1260         avl_insert(&ibcm_svc_avl_tree, (void *)svcinfop, where);
1261         mutex_exit(&ibcm_svc_info_lock);
1262 
1263         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*svcinfop))
1264 
1265         return (svcinfop);
1266 }
1267 
1268 /*
1269  * ibcm_find_svc_entry:
1270  *      Finds a ibcm_svc_info_t entry into the CM's global table.
1271  *      The search done here assumes the list is sorted by SID.
1272  *
1273  * Arguments are:
1274  *      sid             - Service ID to look up
1275  *
1276  * Return values:
1277  *      Pointer to ibcm_svc_info_t, if found, otherwise NULL.
1278  */
1279 ibcm_svc_info_t *
1280 ibcm_find_svc_entry(ib_svc_id_t sid)
1281 {
1282         ibcm_svc_info_t *svcp;
1283         ibcm_svc_lookup_t svc;
1284 
1285         IBTF_DPRINTF_L3(cmlog, "ibcm_find_svc_entry: finding SID 0x%llX", sid);
1286 
1287         ASSERT(MUTEX_HELD(&ibcm_svc_info_lock));
1288 
1289         svc.sid = sid;
1290         svc.num_sids = 1;
1291 #ifdef __lock_lint
1292         ibcm_svc_compare(NULL, NULL);
1293 #endif
1294         svcp = avl_find(&ibcm_svc_avl_tree, &svc, NULL);
1295         if (svcp != NULL) {
1296                 IBTF_DPRINTF_L3(cmlog, "ibcm_find_svc_entry: "
1297                     "found SID = 0x%llX", sid);
1298                 return (svcp);  /* found it */
1299         }
1300         IBTF_DPRINTF_L3(cmlog, "ibcm_find_svc_entry: SID %llX not found", sid);
1301         return (NULL);
1302 }
1303 
1304 /*
1305  * ibcm_alloc_ibmf_msg:
1306  * Allocate an ibmf message structure and the additional memory required for
1307  * sending an outgoing CM mad.  The ibmf message structure contains two
1308  * ibmf_msg_bufs_t fields, one for the incoming MAD and one for the outgoing
1309  * MAD.  The CM must allocate the memory for the outgoing MAD.  The msg_buf
1310  * field has three buffers: the mad header, the class header, and the class
1311  * data.  To simplify the code and reduce the number of kmem_zalloc() calls,
1312  * ibcm_alloc_ibmf_msg will allocate one buffer and set the pointers to the
1313  * right offsets.  No class header is needed so only the mad header and class
1314  * data fields are used.
1315  */
1316 ibt_status_t
1317 ibcm_alloc_out_msg(ibmf_handle_t ibmf_handle, ibmf_msg_t **ibmf_msgpp,
1318     uint8_t method)
1319 {
1320         ib_mad_hdr_t    *output_mad_hdr;
1321         int             sa_retval;
1322 
1323         if ((sa_retval =
1324             ibmf_alloc_msg(ibmf_handle, IBMF_ALLOC_SLEEP, ibmf_msgpp)) !=
1325             IBMF_SUCCESS) {
1326                 IBTF_DPRINTF_L1(cmlog, "ibcm_alloc_out_msg: "
1327                     "ibmf_alloc_msg failed with IBMF_ALLOC_SLEEP");
1328                 return (ibcm_ibmf_analyze_error(sa_retval));
1329         }
1330 
1331         (*ibmf_msgpp)->im_msgbufs_send.im_bufs_mad_hdr = kmem_zalloc(
1332             IBCM_MAD_SIZE, KM_SLEEP);
1333 
1334         (*ibmf_msgpp)->im_msgbufs_send.im_bufs_cl_data_len = IBCM_MSG_SIZE;
1335         (*ibmf_msgpp)->im_msgbufs_send.im_bufs_cl_data =
1336             (uchar_t *)((*ibmf_msgpp)->im_msgbufs_send.im_bufs_mad_hdr) +
1337             IBCM_MAD_HDR_SIZE;
1338 
1339         /* initialize generic CM MAD header fields */
1340         output_mad_hdr = IBCM_OUT_HDRP((*ibmf_msgpp));
1341         output_mad_hdr->BaseVersion = IBCM_MAD_BASE_VERSION;
1342         output_mad_hdr->MgmtClass = MAD_MGMT_CLASS_COMM_MGT;
1343         output_mad_hdr->ClassVersion = IBCM_MAD_CLASS_VERSION;
1344         output_mad_hdr->R_Method = method;
1345 
1346         return (IBT_SUCCESS);
1347 }
1348 
1349 /*
1350  * ibcm_free_ibmf_msg:
1351  * Frees the buffer and ibmf message associated with an outgoing CM message.
1352  * This function should only be used to free messages created by
1353  * ibcm_alloc_out_msg.  Will return IBCM_FAILURE if the ibmf_free_msg() call
1354  * fails and IBCM_SUCCESS otherwise.
1355  */
1356 ibcm_status_t
1357 ibcm_free_out_msg(ibmf_handle_t ibmf_handle, ibmf_msg_t **ibmf_msgpp)
1358 {
1359         int ibmf_status;
1360 
1361         kmem_free((*ibmf_msgpp)->im_msgbufs_send.im_bufs_mad_hdr,
1362             IBCM_MAD_SIZE);
1363 
1364         if ((ibmf_status = ibmf_free_msg(ibmf_handle, ibmf_msgpp)) !=
1365             IBMF_SUCCESS) {
1366                 IBTF_DPRINTF_L2(cmlog, "ibcm_free_out_msg: "
1367                     "ibmf_free_msg failed %d", ibmf_status);
1368                 return (IBCM_FAILURE);
1369         } else
1370                 return (IBCM_SUCCESS);
1371 }
1372 
1373 ibcm_qp_list_t *
1374 ibcm_find_qp(ibcm_hca_info_t *hcap, int port_no, ib_pkey_t pkey)
1375 {
1376         ibcm_qp_list_t          *entry;
1377         ibmf_qp_handle_t        ibmf_qp;
1378         int                     ibmf_status;
1379 
1380         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*entry))
1381 
1382         mutex_enter(&ibcm_qp_list_lock);
1383 
1384         /*
1385          * CM currently does not track port up and down status. If tracking of
1386          * " port status" is added in the future, then CM could be optimized to
1387          * re-use other ports on hcap, if the port associated with the above
1388          * port_no is down. But, the issue of "reachability" needs to be
1389          * handled, before selecting an alternative port different from above.
1390          */
1391         entry = hcap->hca_port_info[port_no-1].port_qplist;
1392         while (entry != NULL) {
1393                 if (entry->qp_pkey == pkey) {
1394                         ++entry->qp_ref_cnt;
1395                         mutex_exit(&ibcm_qp_list_lock);
1396                         return (entry);
1397                 }
1398                 entry = entry->qp_next;
1399         }
1400 
1401         /*
1402          * entry not found, attempt to alloc a qp
1403          * This may be optimized in the future, to allocate ibmf qp's
1404          * once the "CM mgmt pkeys" are precisely known.
1405          */
1406         ibmf_status = ibmf_alloc_qp(
1407             hcap->hca_port_info[port_no-1].port_ibmf_hdl, pkey, IB_GSI_QKEY,
1408             IBMF_ALT_QP_MAD_NO_RMPP, &ibmf_qp);
1409 
1410         if (ibmf_status != IBMF_SUCCESS) {
1411                 mutex_exit(&ibcm_qp_list_lock);
1412                 IBTF_DPRINTF_L2(cmlog, "ibcm_find_qp: failed to alloc IBMF QP"
1413                     "for Pkey = %x port_no = %x status = %d hcaguid = %llXp",
1414                     pkey, port_no, ibmf_status, hcap->hca_guid);
1415                 /*
1416                  * This may be optimized in the future, so as CM would attempt
1417                  * to re-use other QP's whose ref cnt is 0 in the respective
1418                  * port_qplist, by doing an ibmf_modify_qp with pkey above.
1419                  */
1420                 return (NULL);
1421         }
1422 
1423         entry = kmem_alloc(sizeof (ibcm_qp_list_t), KM_SLEEP);
1424         entry->qp_next = hcap->hca_port_info[port_no-1].port_qplist;
1425         hcap->hca_port_info[port_no-1].port_qplist = entry;
1426         entry->qp_cm = ibmf_qp;
1427         entry->qp_ref_cnt = 1;
1428         entry->qp_pkey = pkey;
1429         entry->qp_port = &(hcap->hca_port_info[port_no-1]);
1430 
1431         mutex_exit(&ibcm_qp_list_lock);
1432 
1433         /* set-up the handler */
1434         ibmf_status = ibmf_setup_async_cb(
1435             hcap->hca_port_info[port_no-1].port_ibmf_hdl, ibmf_qp,
1436             ibcm_recv_cb, entry, 0);
1437 
1438         ASSERT(ibmf_status == IBMF_SUCCESS);
1439 
1440 #ifdef  DEBUG
1441         ibcm_query_qp(hcap->hca_port_info[port_no-1].port_ibmf_hdl, ibmf_qp);
1442 #endif
1443 
1444         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*entry))
1445 
1446         return (entry);
1447 }
1448 
1449 void
1450 ibcm_release_qp(ibcm_qp_list_t *cm_qp_entry)
1451 {
1452         mutex_enter(&ibcm_qp_list_lock);
1453         --cm_qp_entry->qp_ref_cnt;
1454         ASSERT(cm_qp_entry->qp_ref_cnt >= 0);
1455         mutex_exit(&ibcm_qp_list_lock);
1456 }
1457 
1458 
1459 /* called holding the ibcm_qp_list_lock mutex */
1460 ibcm_status_t
1461 ibcm_free_qp(ibcm_qp_list_t *cm_qp_entry)
1462 {
1463         int     ibmf_status;
1464 
1465         IBTF_DPRINTF_L5(cmlog, "ibcm_free_qp: qp_hdl %p ref_cnt %d pkey %x",
1466             cm_qp_entry->qp_cm, cm_qp_entry->qp_ref_cnt, cm_qp_entry->qp_pkey);
1467 
1468         /* check, there are no users of this ibmf qp */
1469         if (cm_qp_entry->qp_ref_cnt != 0)
1470                 return (IBCM_FAILURE);
1471 
1472         /* Tear down the receive callback */
1473         ibmf_status = ibmf_tear_down_async_cb(
1474             cm_qp_entry->qp_port->port_ibmf_hdl, cm_qp_entry->qp_cm, 0);
1475         if (ibmf_status != IBMF_SUCCESS) {
1476                 IBTF_DPRINTF_L2(cmlog, "ibcm_free_qp: "
1477                     "ibmf_tear_down_async_cb failed %d port_num %d",
1478                     ibmf_status, cm_qp_entry->qp_port->port_num);
1479                 return (IBCM_FAILURE);
1480         }
1481 
1482         ibmf_status = ibmf_free_qp(cm_qp_entry->qp_port->port_ibmf_hdl,
1483             &cm_qp_entry->qp_cm, 0);
1484         if (ibmf_status != IBMF_SUCCESS) {
1485                 IBTF_DPRINTF_L2(cmlog, "ibcm_free_qp: ibmf_free_qp failed for"
1486                     " ibmf_status %d qp hdl %p port_no %x", ibmf_status,
1487                     cm_qp_entry->qp_cm, cm_qp_entry->qp_port->port_num);
1488                 return (IBCM_FAILURE);
1489         }
1490 
1491         return (IBCM_SUCCESS);
1492 }
1493 
1494 ibcm_status_t
1495 ibcm_free_allqps(ibcm_hca_info_t *hcap, int port_no)
1496 {
1497         ibcm_qp_list_t          *entry, *freed;
1498         ibcm_status_t           ibcm_status = IBCM_SUCCESS;
1499 
1500         IBTF_DPRINTF_L5(cmlog, "ibcm_free_allqps: hcap %p port_no %d", hcap,
1501             port_no);
1502 
1503         mutex_enter(&ibcm_qp_list_lock);
1504         entry = hcap->hca_port_info[port_no-1].port_qplist;
1505         while ((entry != NULL) &&
1506             ((ibcm_status = ibcm_free_qp(entry)) == IBCM_SUCCESS)) {
1507                 freed = entry;
1508                 entry = entry->qp_next;
1509                 kmem_free(freed, sizeof (ibcm_qp_list_t));
1510         }
1511 
1512         if (ibcm_status != IBCM_SUCCESS)        /* sanity the linked list */
1513                 hcap->hca_port_info[port_no-1].port_qplist = entry;
1514         else    /* all ibmf qp's of port must have been free'd successfully */
1515                 hcap->hca_port_info[port_no-1].port_qplist = NULL;
1516 
1517         mutex_exit(&ibcm_qp_list_lock);
1518         return (ibcm_status);
1519 }
1520 
1521 /*
1522  * ibt_bind_service() and ibt_get_paths() needs the following helper function
1523  * to handle endianess in case of Service Data.
1524  */
1525 void
1526 ibcm_swizzle_from_srv(ibt_srv_data_t *sb_data, uint8_t *service_bytes)
1527 {
1528         uint8_t         *p8 = service_bytes;
1529         uint16_t        *p16;
1530         uint32_t        *p32;
1531         uint64_t        *p64;
1532         int             i;
1533 
1534         for (i = 0; i < 16; i++)
1535                 *p8++ = sb_data->s_data8[i];
1536 
1537         p16 = (uint16_t *)p8;
1538         for (i = 0; i < 8; i++)
1539                 *p16++ = h2b16(sb_data->s_data16[i]);
1540 
1541         p32 = (uint32_t *)p16;
1542         for (i = 0; i < 4; i++)
1543                 *p32++ = h2b32(sb_data->s_data32[i]);
1544 
1545         p64 = (uint64_t *)p32;
1546         for (i = 0; i < 2; i++)
1547                 *p64++ = h2b64(sb_data->s_data64[i]);
1548 }
1549 
1550 void
1551 ibcm_swizzle_to_srv(uint8_t *service_bytes, ibt_srv_data_t *sb_data)
1552 {
1553         uint8_t         *p8 = service_bytes;
1554         uint16_t        *p16;
1555         uint32_t        *p32;
1556         uint64_t        *p64;
1557         int             i;
1558 
1559         for (i = 0; i < 16; i++)
1560                 sb_data->s_data8[i] = *p8++;
1561 
1562         p16 = (uint16_t *)p8;
1563         for (i = 0; i < 8; i++)
1564                 sb_data->s_data16[i] = h2b16(*p16++);
1565 
1566         p32 = (uint32_t *)p16;
1567         for (i = 0; i < 4; i++)
1568                 sb_data->s_data32[i] = h2b32(*p32++);
1569         p64 = (uint64_t *)p32;
1570 
1571         for (i = 0; i < 2; i++)
1572                 sb_data->s_data64[i] = h2b64(*p64++);
1573 }
1574 
1575 /* Trace related functions */
1576 
1577 void
1578 ibcm_init_conn_trace(ibcm_state_data_t *sp)
1579 {
1580         IBTF_DPRINTF_L5(cmlog, "ibcm_init_conn_trace: statep %p", sp);
1581 
1582         /* Initialize trace related fields */
1583 
1584         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sp->conn_trace))
1585         sp->conn_trace = kmem_zalloc(sizeof (ibcm_conn_trace_t), KM_SLEEP);
1586         if ((ibcm_enable_trace & 1) == 0)
1587                 sp->conn_trace->conn_base_tm = gethrtime();
1588         sp->conn_trace->conn_allocated_trcnt = ibcm_conn_max_trcnt;
1589         sp->conn_trace->conn_trace_events =
1590             kmem_zalloc(sp->conn_trace->conn_allocated_trcnt, KM_SLEEP);
1591         sp->conn_trace->conn_trace_event_times =
1592             kmem_zalloc(sp->conn_trace->conn_allocated_trcnt *
1593             sizeof (tm_diff_type), KM_SLEEP);
1594         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sp->conn_trace))
1595 }
1596 
1597 void
1598 ibcm_fini_conn_trace(ibcm_state_data_t *statep)
1599 {
1600         IBTF_DPRINTF_L5(cmlog, "ibcm_fini_conn_trace: statep %p tracep %p",
1601             statep, statep->conn_trace);
1602 
1603         /* free the trace data */
1604         if (statep->conn_trace) {
1605                 if (statep->conn_trace->conn_trace_events)
1606                         kmem_free(statep->conn_trace->conn_trace_events,
1607                             statep->conn_trace->conn_allocated_trcnt);
1608                 if (statep->conn_trace->conn_trace_event_times)
1609                         kmem_free(statep->conn_trace->conn_trace_event_times,
1610                             statep->conn_trace->conn_allocated_trcnt *
1611                             sizeof (tm_diff_type));
1612 
1613                 kmem_free(statep->conn_trace, sizeof (ibcm_conn_trace_t));
1614         }
1615 }
1616 
1617 /* mostly used to profile connection establishment times with dtrace */
1618 void
1619 ibcm_established(hrtime_t time_diff)
1620 {
1621         if (time_diff > 1000000000LL)        /* 1 second */
1622                 IBTF_DPRINTF_L2(cmlog, "slow connection time (%d seconds)",
1623                     (uint_t)(time_diff >> 30));
1624 }
1625 
1626 void
1627 ibcm_insert_trace(void *statep, ibcm_state_rc_trace_qualifier_t event_qualifier)
1628 {
1629         ibcm_conn_trace_t       *conn_trace;
1630         uint8_t                 conn_trace_ind;
1631         hrtime_t                time_diff;
1632         hrtime_t                hrt;
1633 
1634         if (!(((ibcm_state_data_t *)statep)->conn_trace))
1635                 return;
1636 
1637         conn_trace = ((ibcm_state_data_t *)statep)->conn_trace;
1638 
1639         if (!conn_trace->conn_trace_events)
1640                 return;
1641 
1642         IBTF_DPRINTF_L5(cmlog, "ibcm_insert_trace: statep %p event %d",
1643             statep, event_qualifier);
1644 
1645         mutex_enter(&ibcm_trace_mutex);
1646 
1647         /* No more trace memory available, hence return */
1648         if (conn_trace->conn_trace_ind == conn_trace->conn_allocated_trcnt) {
1649                 mutex_exit(&ibcm_trace_mutex);
1650                 return;
1651         } else
1652                 ++conn_trace->conn_trace_ind;
1653 
1654         conn_trace_ind = conn_trace->conn_trace_ind - 1;
1655 
1656         conn_trace->conn_trace_events[conn_trace_ind] = event_qualifier;
1657 
1658         if ((ibcm_enable_trace & 1) == 0) {
1659                 hrt = gethrtime();
1660                 time_diff = hrt - conn_trace->conn_base_tm;
1661                 if (event_qualifier == IBCM_TRACE_CALLED_CONN_EST_EVENT)
1662                         ibcm_established(time_diff);
1663                 time_diff >>= 10;
1664                 if (time_diff >= TM_DIFF_MAX) {
1665                         /* RESET, future times are relative to new base time. */
1666                         conn_trace->conn_base_tm = hrt;
1667                         time_diff = 0;
1668                 }
1669                 conn_trace->conn_trace_event_times[conn_trace_ind] = time_diff;
1670         }
1671 
1672         mutex_exit(&ibcm_trace_mutex);
1673 
1674         IBTF_DPRINTF_L5(cmlog, "ibcm_insert_trace: statep %p inserted event %d",
1675             statep, event_qualifier);
1676 }
1677 
1678 void
1679 ibcm_dump_conn_trace(void *statep)
1680 {
1681         IBTF_DPRINTF_L5(cmlog, "ibcm_dump_conn_trace: statep %p",
1682             statep);
1683 
1684         mutex_enter(&ibcm_trace_print_mutex);
1685         ibcm_debug_buf[0] = '\0';
1686         ibcm_dump_conn_trbuf(statep, "ibcm: ", ibcm_debug_buf,
1687             IBCM_DEBUG_BUF_SIZE);
1688         if (ibcm_debug_buf[0] != '\0')
1689                 IBTF_DPRINTF_L2(cmlog, "\n%s", ibcm_debug_buf);
1690 
1691 #ifdef  DEBUG
1692 
1693         if (ibcm_test_mode > 1)
1694                 cmn_err(CE_CONT, "IBCM DEBUG TRACE:\n%s", ibcm_debug_buf);
1695 #endif
1696 
1697         mutex_exit(&ibcm_trace_print_mutex);
1698 }
1699 
1700 void
1701 ibcm_dump_conn_trbuf(void *statep, char *line_prefix, char *buf, int buf_size)
1702 {
1703         ibcm_conn_trace_t       *conn_trace;
1704         int                     tr_ind;
1705         ibcm_state_data_t       *sp;
1706         int     cur_size = 0;   /* size of item copied */
1707         int     rem_size;       /* remaining size in trace buffer */
1708         int     next_data = 0;  /* location where next item copied */
1709 
1710         if ((buf == NULL) || (buf_size <= 0))
1711                 return;
1712 
1713         sp = (ibcm_state_data_t *)statep;
1714 
1715         if (!sp->conn_trace)
1716                 return;
1717 
1718         conn_trace = sp->conn_trace;
1719 
1720         if (!conn_trace->conn_trace_events)
1721                 return;
1722 
1723         rem_size = buf_size;
1724 
1725         /* Print connection level global data */
1726 
1727         /* Print statep, local comid, local qpn */
1728         cur_size = snprintf(&buf[next_data], rem_size, "%s%s0x%p\n%s%s0x%p\n"
1729             "%s%s0x%x/%llx/%d\n%s%s0x%x\n%s%s0x%x/%llx\n%s%s0x%x\n%s%s%llu\n",
1730             line_prefix, event_str[IBCM_DISPLAY_SID], (void *)sp,
1731             line_prefix, event_str[IBCM_DISPLAY_CHAN], (void *)sp->channel,
1732             line_prefix, event_str[IBCM_DISPLAY_LCID], sp->local_comid,
1733             (longlong_t)sp->local_hca_guid, sp->prim_port,
1734             line_prefix, event_str[IBCM_DISPLAY_LQPN], sp->local_qpn,
1735             line_prefix, event_str[IBCM_DISPLAY_RCID], sp->remote_comid,
1736             (longlong_t)sp->remote_hca_guid,
1737             line_prefix, event_str[IBCM_DISPLAY_RQPN], sp->remote_qpn,
1738             line_prefix, event_str[IBCM_DISPLAY_TM], conn_trace->conn_base_tm);
1739 
1740         rem_size = rem_size - cur_size;
1741         if (rem_size <= 0) {
1742                 buf[buf_size-1] = '\n';
1743                 return;
1744         }
1745 
1746         next_data = next_data + cur_size;
1747 
1748         for (tr_ind = 0; tr_ind < conn_trace->conn_trace_ind; tr_ind++) {
1749                 cur_size = snprintf(&buf[next_data], rem_size,
1750                     "%s%sTM_DIFF %u\n", line_prefix,
1751                     event_str[conn_trace->conn_trace_events[tr_ind]],
1752                     conn_trace->conn_trace_event_times[tr_ind]);
1753                 rem_size = rem_size - cur_size;
1754                 if (rem_size <= 0) {
1755                         buf[buf_size-1] = '\n';
1756                         return;
1757                 }
1758                 next_data = next_data + cur_size;
1759         }
1760 
1761         buf[next_data] = '\0';
1762         IBTF_DPRINTF_L5(cmlog, "ibcm_dump_conn_trbuf: statep %p "
1763             "debug buf size %d bytes", statep, next_data);
1764 }
1765 
1766 
1767 #ifdef  DEBUG
1768 
1769 void
1770 ibcm_query_qp(ibmf_handle_t ibmf_hdl, ibmf_qp_handle_t ibmf_qp)
1771 {
1772         uint8_t         qp_port_num;
1773         ib_qpn_t        qp_num;
1774         ib_pkey_t       qp_pkey;
1775         ib_qkey_t       qp_qkey;
1776         int             ibmf_status;
1777 
1778         if (ibmf_qp == IBMF_QP_HANDLE_DEFAULT) {
1779                 IBTF_DPRINTF_L4(cmlog, "ibcm_query_qp: QP1");
1780                 return;
1781         }
1782 
1783         ibmf_status =
1784             ibmf_query_qp(ibmf_hdl, ibmf_qp, &qp_num, &qp_pkey, &qp_qkey,
1785             &qp_port_num, 0);
1786 
1787         ASSERT(ibmf_status == IBMF_SUCCESS);
1788 
1789         IBTF_DPRINTF_L5(cmlog, "ibcm_query_qp: qpn %x qkey %x pkey %x port %d",
1790             qp_num, qp_qkey, qp_pkey, qp_port_num);
1791 }
1792 
1793 /*
1794  * ibcm_dump_raw_message:
1795  *      dumps 256 bytes of data of a raw message (REP/REQ/DREQ ...)
1796  *      (can be called from the kernel debugger w/ the message pointer)
1797  *
1798  * Arguments:
1799  *      msgp    - the messages that needs to be dumped
1800  *
1801  * Return values: NONE
1802  */
1803 void
1804 ibcm_dump_raw_message(uchar_t *c)
1805 {
1806         int     i;
1807 
1808         for (i = 0; i < IBCM_MAD_SIZE; i += 16) {
1809                 /* print in batches of 16 chars at a time */
1810                 IBTF_DPRINTF_L4(cmlog,
1811                     "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
1812                     c[i], c[i + 1], c[i + 2], c[i + 3], c[i + 4], c[i + 5],
1813                     c[i + 6], c[i + 7], c[i + 8], c[i + 9], c[i + 10],
1814                     c[i + 11], c[i + 12], c[i + 13], c[i + 14], c[i + 15]);
1815         }
1816 }
1817 
1818 
1819 /*
1820  * ibcm_dump_srv_rec:
1821  *      Dumps Service Records.
1822  *
1823  * Arguments:
1824  *      srv_rec - the pointer to sa_service_record_t struct.
1825  *
1826  * Return values: NONE
1827  */
1828 void
1829 ibcm_dump_srvrec(sa_service_record_t *srv_rec)
1830 {
1831         uint8_t         i;
1832 
1833         IBTF_DPRINTF_L4(cmlog, "ibcm_dump_srvrec: Service Records");
1834         IBTF_DPRINTF_L4(cmlog, "SID       : 0x%016llX", srv_rec->ServiceID);
1835         IBTF_DPRINTF_L4(cmlog, "Svc GID   : 0x%016llX:0x%016llX",
1836             srv_rec->ServiceGID.gid_prefix, srv_rec->ServiceGID.gid_guid);
1837         IBTF_DPRINTF_L4(cmlog, "Svc PKey  : 0x%X", srv_rec->ServiceP_Key);
1838 
1839         IBTF_DPRINTF_L4(cmlog, "Svc Lease : 0x%lX", srv_rec->ServiceLease);
1840         IBTF_DPRINTF_L4(cmlog, "Svc Key-hi: 0x%016llX", srv_rec->ServiceKey_hi);
1841         IBTF_DPRINTF_L4(cmlog, "Svc Key-lo: 0x%016llX", srv_rec->ServiceKey_lo);
1842         IBTF_DPRINTF_L4(cmlog, "Svc Name  : %s", srv_rec->ServiceName);
1843         IBTF_DPRINTF_L4(cmlog, "Svc Data  : ");
1844         for (i = 0; i < IB_SVC_DATA_LEN; i += 8) {
1845                 IBTF_DPRINTF_L4(cmlog,
1846                     "\t 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X",
1847                     srv_rec->ServiceData[i], srv_rec->ServiceData[i+1],
1848                     srv_rec->ServiceData[i+2], srv_rec->ServiceData[i+3],
1849                     srv_rec->ServiceData[i+4], srv_rec->ServiceData[i+5],
1850                     srv_rec->ServiceData[i+6], srv_rec->ServiceData[i+7]);
1851         }
1852 }
1853 
1854 
1855 /*
1856  * ibcm_dump_pathrec:
1857  *      Dumps Path Records.
1858  *
1859  * Arguments:
1860  *      path_rec - the pointer to sa_path_record_t struct.
1861  *
1862  * Return values: NONE
1863  */
1864 void
1865 ibcm_dump_pathrec(sa_path_record_t *path_rec)
1866 {
1867         IBTF_DPRINTF_L5(cmlog, "Path Record:");
1868         IBTF_DPRINTF_L5(cmlog, "SGID: (sn_prefix)  %016llX",
1869             path_rec->SGID.gid_prefix);
1870         IBTF_DPRINTF_L5(cmlog, "SGID: (GUID)       %016llX",
1871             path_rec->SGID.gid_guid);
1872         IBTF_DPRINTF_L5(cmlog, "DGID: (sn_prefix)  %016llX",
1873             path_rec->DGID.gid_prefix);
1874         IBTF_DPRINTF_L5(cmlog, "DGID: (GUID)       %016llX",
1875             path_rec->DGID.gid_guid);
1876         IBTF_DPRINTF_L5(cmlog, "SLID:              %04X", path_rec->SLID);
1877         IBTF_DPRINTF_L5(cmlog, "DLID:              %04X", path_rec->DLID);
1878         IBTF_DPRINTF_L5(cmlog, "Raw Traffic:       %01X", path_rec->RawTraffic);
1879         IBTF_DPRINTF_L5(cmlog, "Flow Label:        %05X", path_rec->FlowLabel);
1880         IBTF_DPRINTF_L5(cmlog, "Hop Limit:         %02X", path_rec->HopLimit);
1881         IBTF_DPRINTF_L5(cmlog, "TClass:            %02X", path_rec->TClass);
1882         IBTF_DPRINTF_L5(cmlog, "Reversible:        %01X", path_rec->Reversible);
1883         IBTF_DPRINTF_L5(cmlog, "Numb Paths:        %02d", path_rec->NumbPath);
1884         IBTF_DPRINTF_L5(cmlog, "P_Key:             %04X", path_rec->P_Key);
1885         IBTF_DPRINTF_L5(cmlog, "SL:                %02X", path_rec->SL);
1886         IBTF_DPRINTF_L5(cmlog, "Path MTU Selector: %01X",
1887             path_rec->MtuSelector);
1888         IBTF_DPRINTF_L5(cmlog, "Path MTU:          %02X", path_rec->Mtu);
1889         IBTF_DPRINTF_L5(cmlog, "Path Rate Selector:%01X",
1890             path_rec->RateSelector);
1891         IBTF_DPRINTF_L5(cmlog, "Path Rate:         %02X", path_rec->Rate);
1892         IBTF_DPRINTF_L5(cmlog, "Packet LT Selector:%01X",
1893             path_rec->PacketLifeTimeSelector);
1894         IBTF_DPRINTF_L5(cmlog, "Packet Life Time:  %d (dec)",
1895             path_rec->PacketLifeTime);
1896         IBTF_DPRINTF_L5(cmlog, "Preference Bit:    %02X", path_rec->Preference);
1897 }
1898 
1899 /*
1900  * ibcm_dump_node_rec:
1901  *      Dumps Node Records.
1902  *
1903  * Arguments:
1904  *      nrec - the pointer to sa_node_record_t struct.
1905  *
1906  * Return values: NONE
1907  */
1908 void
1909 ibcm_dump_noderec(sa_node_record_t *nrec)
1910 {
1911         IBTF_DPRINTF_L5(cmlog, "ibcm_dump_noderec: Node Info Record");
1912         IBTF_DPRINTF_L5(cmlog, "LID       : %04X", nrec->LID);
1913         IBTF_DPRINTF_L5(cmlog, "Base Ver  : %02X", nrec->NodeInfo.BaseVersion);
1914         IBTF_DPRINTF_L5(cmlog, "Class Ver : %02X", nrec->NodeInfo.ClassVersion);
1915         IBTF_DPRINTF_L5(cmlog, "Node Type : %02d", nrec->NodeInfo.NodeType);
1916         IBTF_DPRINTF_L5(cmlog, "Num Ports : %02X", nrec->NodeInfo.NumPorts);
1917         IBTF_DPRINTF_L5(cmlog, "SysImgGUID: %016llX",
1918             nrec->NodeInfo.SystemImageGUID);
1919         IBTF_DPRINTF_L5(cmlog, "NODE GUID : %016llX", nrec->NodeInfo.NodeGUID);
1920         IBTF_DPRINTF_L5(cmlog, "Port GUID : %016llX", nrec->NodeInfo.PortGUID);
1921         IBTF_DPRINTF_L5(cmlog, "PartionCap: %04X", nrec->NodeInfo.PartitionCap);
1922         IBTF_DPRINTF_L5(cmlog, "Device ID : %04X", nrec->NodeInfo.DeviceID);
1923         IBTF_DPRINTF_L5(cmlog, "Revision  : %06X", nrec->NodeInfo.Revision);
1924         IBTF_DPRINTF_L5(cmlog, "LocalPort#: %02X", nrec->NodeInfo.LocalPortNum);
1925         IBTF_DPRINTF_L5(cmlog, "Vendor ID : %06X", nrec->NodeInfo.VendorID);
1926         IBTF_DPRINTF_L5(cmlog, "Description: %s",
1927             (char *)&nrec->NodeDescription);
1928 }
1929 #endif
1930 
1931 /*
1932  * ibcm_ibtl_node_info:
1933  *      Get the node record of the destination specified by lid via the HCA
1934  *      and port specified.
1935  *
1936  * Arguments:
1937  *      hca_guid - GUID of the local HCA.
1938  *      port     - port in the HCA to be used.
1939  *      lid      - destination LID
1940  *      node_info_p - pointer to the Node Info to be returned.
1941  *
1942  * Return values:
1943  *      IBT_SUCCESS : Got the node record sucessfully
1944  *      IBT_FILURE  : Failed to get the node record.
1945  */
1946 ibt_status_t
1947 ibcm_ibtl_node_info(ib_guid_t hca_guid, uint8_t port, ib_lid_t lid,
1948     ibt_node_info_t *node_info_p)
1949 {
1950         sa_node_record_t        nr_req, *nr_resp;
1951         void                    *res_p;
1952         ibmf_saa_handle_t       saa_handle;
1953         ibt_status_t            ibt_status;
1954         ibcm_hca_info_t         *hcap;
1955         uint_t                  num_rec;
1956         size_t                  len;
1957 
1958         IBTF_DPRINTF_L3(cmlog, "ibcm_ibtl_node_info: ENTER: port %x "
1959             "guid %llx\n", port, hca_guid);
1960 
1961         hcap = ibcm_find_hca_entry(hca_guid);
1962         if (hcap == NULL) {
1963                 IBTF_DPRINTF_L2(cmlog, "ibcm_ibtl_node_info: "
1964                     "HCA(%llX) info not found", hca_guid);
1965                 return (IBT_FAILURE);
1966         }
1967 
1968         /* Get SA Access Handle. */
1969         saa_handle = ibcm_get_saa_handle(hcap, port);
1970         if (saa_handle == NULL) {
1971                 IBTF_DPRINTF_L2(cmlog, "ibcm_ibtl_node_info: "
1972                     "Port %d of HCA (%llX) is NOT ACTIVE", port, hca_guid);
1973                 ibcm_dec_hca_acc_cnt(hcap);
1974                 return (IBT_FAILURE);
1975         }
1976 
1977         /* Retrieve Node Records from SA Access. */
1978         bzero(&nr_req, sizeof (sa_node_record_t));
1979         nr_req.LID =  lid;
1980 
1981         ibt_status = ibcm_get_node_rec(saa_handle, &nr_req,
1982             SA_NODEINFO_COMPMASK_NODELID, &res_p, &len);
1983         if (ibt_status != IBT_SUCCESS) {
1984                 IBTF_DPRINTF_L2(cmlog, "ibcm_ibtl_node_info: "
1985                     "failed (%d) to get Node records", ibt_status);
1986                 ibcm_dec_hca_acc_cnt(hcap);
1987                 return (IBT_FAILURE);
1988         }
1989 
1990         num_rec = len/sizeof (sa_node_record_t);
1991         nr_resp = (sa_node_record_t *)(uchar_t *)res_p;
1992 
1993         if ((nr_resp != NULL) && (num_rec > 0)) {
1994                 IBCM_DUMP_NODE_REC(nr_resp);
1995 
1996                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(
1997                     *node_info_p))
1998 
1999                 node_info_p->n_sys_img_guid =
2000                     nr_resp->NodeInfo.SystemImageGUID;
2001                 node_info_p->n_node_guid =
2002                     nr_resp->NodeInfo.NodeGUID;
2003                 node_info_p->n_port_guid =
2004                     nr_resp->NodeInfo.PortGUID;
2005                 node_info_p->n_dev_id =
2006                     nr_resp->NodeInfo.DeviceID;
2007                 node_info_p->n_revision =
2008                     nr_resp->NodeInfo.Revision;
2009                 node_info_p->n_vendor_id =
2010                     nr_resp->NodeInfo.VendorID;
2011                 node_info_p->n_num_ports =
2012                     nr_resp->NodeInfo.NumPorts;
2013                 node_info_p->n_port_num =
2014                     nr_resp->NodeInfo.LocalPortNum;
2015                 node_info_p->n_node_type =
2016                     nr_resp->NodeInfo.NodeType;
2017                 (void) strncpy(node_info_p->n_description,
2018                     (char *)&nr_resp->NodeDescription, 64);
2019                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(
2020                     *node_info_p))
2021 
2022 
2023                 kmem_free(nr_resp, len);
2024         }
2025         ibcm_dec_hca_acc_cnt(hcap);
2026         return (IBT_SUCCESS);
2027 }
2028 
2029 /*
2030  * ibcm_ibmf_analyze_error:
2031  *      Checks IBMF status and determines appropriate ibt status.
2032  *
2033  * Arguments:
2034  *      ibmf_status - IBMF Status
2035  *
2036  * Return values:
2037  *      ibt_status_t
2038  */
2039 ibt_status_t
2040 ibcm_ibmf_analyze_error(int ibmf_status)
2041 {
2042         if (ibt_check_failure(ibmf_status, NULL) != IBT_FAILURE_STANDARD) {
2043                 /*
2044                  * IBMF specific failure, return special error code
2045                  * to the client so that it can retrieve any associated ENA.
2046                  */
2047                 return (ibmf_status);
2048         } else if (ibmf_status == IBMF_TRANS_TIMEOUT) {
2049                 return (IBT_IBMF_TIMEOUT);
2050         } else {
2051                 /*
2052                  * IBMF failed for some other reason, invalid arguments etc.
2053                  * Analyze, log ENA with IBTF and obtain a special ibt_status_t
2054                  * that indicates IBMF failure.
2055                  */
2056                 if ((ibmf_status == IBMF_BAD_CLASS) ||
2057                     (ibmf_status == IBMF_BAD_HANDLE) ||
2058                     (ibmf_status == IBMF_BAD_QP_HANDLE) ||
2059                     (ibmf_status == IBMF_BAD_NODE) ||
2060                     (ibmf_status == IBMF_BAD_PORT) ||
2061                     (ibmf_status == IBMF_BAD_VERSION) ||
2062                     (ibmf_status == IBMF_BAD_FLAGS) ||
2063                     (ibmf_status == IBMF_BAD_SIZE) ||
2064                     (ibmf_status == IBMF_INVALID_GID) ||
2065                     (ibmf_status == IBMF_INVALID_ARG) ||
2066                     (ibmf_status == IBMF_INVALID_FIELD) ||
2067                     (ibmf_status == IBMF_UNSUPP_METHOD) ||
2068                     (ibmf_status == IBMF_UNSUPP_METHOD_ATTR)) {
2069 
2070                         /*
2071                          * These errors, we should not see...
2072                          * something really bad happened!.
2073                          */
2074                         IBTF_DPRINTF_L2(cmlog, "ibcm_ibmf_analyze_error: "
2075                             "Unexpected ERROR from IBMF - %d", ibmf_status);
2076                 }
2077                 return (ibt_get_module_failure(IBT_FAILURE_IBMF, 0));
2078         }
2079 }