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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 #include <sys/ib/mgt/ibcm/ibcm_impl.h>
  26 #include <sys/ib/ibtl/ibti.h>
  27 #include <sys/ib/mgt/ibcm/ibcm_arp.h>
  28 
  29 /*
  30  * ibcm_ti.c
  31  *      These routines implement the Communication Manager's interfaces to IBTL.
  32  */
  33 
  34 /* CM rc recycle task args structure definition */
  35 typedef struct ibcm_taskq_recycle_arg_s {
  36         ibt_channel_hdl_t       rc_chan;
  37         ibt_cep_flags_t         control;
  38         uint8_t                 hca_port_num;
  39         ibt_recycle_handler_t   func;
  40         void                    *arg;
  41 } ibcm_taskq_recycle_arg_t;
  42 
  43 _NOTE(READ_ONLY_DATA(ibcm_taskq_recycle_arg_s))
  44 
  45 static ibt_status_t     ibcm_init_reply_addr(ibcm_hca_info_t *hcap,
  46     ibcm_mad_addr_t *reply_addr, ibt_chan_open_args_t *chan_args,
  47     ibt_chan_open_flags_t flags, ib_time_t *cm_pkt_lt, ib_lid_t prim_slid);
  48 static void             ibcm_process_abort_via_taskq(void *args);
  49 static ibt_status_t     ibcm_process_rc_recycle_ret(void *recycle_arg);
  50 static ibt_status_t     ibcm_process_join_mcg(void *taskq_arg);
  51 static void             ibcm_process_async_join_mcg(void *tq_arg);
  52 
  53 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 static ibt_status_t ibcm_close_rc_channel(ibt_channel_hdl_t channel,
  57     ibcm_state_data_t *statep, ibt_execution_mode_t mode);
  58 
  59 /* Address Record management definitions */
  60 #define IBCM_DAPL_ATS_NAME      "DAPL Address Translation Service"
  61 #define IBCM_DAPL_ATS_SID       0x10000CE100415453ULL
  62 #define IBCM_DAPL_ATS_NBYTES    16
  63 ibcm_svc_info_t *ibcm_ar_svcinfop;
  64 ibcm_ar_t       *ibcm_ar_list;
  65 
  66 /*
  67  * Tunable parameter to turnoff the overriding of pi_path_mtu value.
  68  *      1       By default override the path record's pi_path_mtu value to
  69  *              IB_MTU_1K for all RC channels. This is done only for the
  70  *              channels established on Tavor HCA and the path's pi_path_mtu
  71  *              is greater than IB_MTU_1K.
  72  *      0       Do not override, use pi_path_mtu by default.
  73  */
  74 int     ibcm_override_path_mtu = 1;
  75 
  76 #ifdef DEBUG
  77 static void     ibcm_print_reply_addr(ibt_channel_hdl_t channel,
  78                     ibcm_mad_addr_t *cm_reply_addr);
  79 #endif
  80 
  81 _NOTE(DATA_READABLE_WITHOUT_LOCK(ibcm_port_info_s::{port_ibmf_hdl}))
  82 
  83 /* access is controlled between ibcm_sm.c and ibcm_ti.c by CVs */
  84 _NOTE(SCHEME_PROTECTS_DATA("Serialized access by CV", {ibt_rc_returns_t
  85     ibt_ud_returns_t ibt_ap_returns_t ibt_ar_t}))
  86 
  87 /*
  88  * Typically, clients initialize these args in one api call, and use in
  89  * another api
  90  */
  91 _NOTE(SCHEME_PROTECTS_DATA("Expected usage of ibtl api by client",
  92     {ibt_path_info_s ibt_cep_path_s ibt_adds_vect_s ibt_mcg_info_s ib_gid_s
  93     ibt_ud_dest_attr_s ibt_ud_dest_s ibt_srv_data_s ibt_redirect_info_s}))
  94 
  95 /*
  96  * ibt_open_rc_channel()
  97  *      ibt_open_rc_channel opens a communication channel on the specified
  98  *      channel to the specified service. For connection service type qp's
  99  *      the CM initiates the CEP to establish the connection and transitions
 100  *      the QP/EEC to the "Ready to send" State modifying the QP/EEC's
 101  *      attributes as necessary.
 102  *      The implementation of this function assumes that alt path is different
 103  *      from primary path. It is assumed that the Path functions ensure that.
 104  *
 105  * RETURN VALUES:
 106  *      IBT_SUCCESS     on success (or respective failure on error)
 107  */
 108 ibt_status_t
 109 ibt_open_rc_channel(ibt_channel_hdl_t channel, ibt_chan_open_flags_t flags,
 110     ibt_execution_mode_t mode, ibt_chan_open_args_t *chan_args,
 111     ibt_rc_returns_t *ret_args)
 112 {
 113         /* all fields that are related to REQ MAD formation */
 114 
 115         ib_pkey_t               prim_pkey;
 116         ib_lid_t                primary_slid, alternate_slid;
 117         ib_qpn_t                local_qpn = 0;
 118         ib_guid_t               hca_guid;
 119         ib_qkey_t               local_qkey = 0;
 120         ib_eecn_t               local_eecn = 0;
 121         ib_eecn_t               remote_eecn = 0;
 122         boolean_t               primary_grh;
 123         boolean_t               alternate_grh = B_FALSE;
 124         ib_lid_t                base_lid;
 125         ib_com_id_t             local_comid;
 126         ibmf_msg_t              *ibmf_msg, *ibmf_msg_dreq;
 127         ibcm_req_msg_t          *req_msgp;
 128 
 129         uint8_t                 rdma_in, rdma_out;
 130         uint8_t                 cm_retries;
 131         uint64_t                local_cm_proc_time;     /* In usec */
 132         uint8_t                 local_cm_resp_time;     /* IB time */
 133         uint64_t                remote_cm_resp_time;    /* In usec */
 134         uint32_t                starting_psn = 0;
 135 
 136         /* CM path related fields */
 137         ibmf_handle_t           ibmf_hdl;
 138         ibcm_qp_list_t          *cm_qp_entry;
 139         ibcm_mad_addr_t         cm_reply_addr;
 140 
 141         uint8_t                 cm_pkt_lt;
 142 
 143         /* Local args for ibtl/internal CM functions called within */
 144         ibt_status_t            status;
 145         ibcm_status_t           lkup_status;
 146         ibt_qp_query_attr_t     qp_query_attr;
 147 
 148         /* Other misc local args */
 149         ibt_priv_data_len_t     len;
 150         ibcm_hca_info_t         *hcap;
 151         ibcm_state_data_t       *statep;
 152         uint8_t                 port_no;
 153 
 154         IBTF_DPRINTF_L3(cmlog, "ibt_open_rc_channel(chan %p, %X, %x, %p, %p)",
 155             channel, flags, mode, chan_args, ret_args);
 156 
 157         if (IBCM_INVALID_CHANNEL(channel)) {
 158                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: invalid channel");
 159                 return (IBT_CHAN_HDL_INVALID);
 160         }
 161 
 162         /* cm handler should always be specified */
 163         if (chan_args->oc_cm_handler == NULL) {
 164                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 165                     "CM handler is not be specified", channel);
 166                 return (IBT_INVALID_PARAM);
 167         }
 168 
 169         if (mode == IBT_NONBLOCKING) {
 170                 if (ret_args != NULL) {
 171                         IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p"
 172                             " ret_args should be NULL when called in "
 173                             "non-blocking mode", channel);
 174                         return (IBT_INVALID_PARAM);
 175                 }
 176         } else if (mode == IBT_BLOCKING) {
 177                 if (ret_args == NULL) {
 178                         IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p"
 179                             " ret_args should be Non-NULL when called in "
 180                             "blocking mode", channel);
 181                         return (IBT_INVALID_PARAM);
 182                 }
 183                 if (ret_args->rc_priv_data_len > IBT_REP_PRIV_DATA_SZ) {
 184                         IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p"
 185                             " private data length is too large", channel);
 186                         return (IBT_INVALID_PARAM);
 187                 }
 188                 if ((ret_args->rc_priv_data_len > 0) &&
 189                     (ret_args->rc_priv_data == NULL)) {
 190                         IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p"
 191                             " rc_priv_data_len > 0, but rc_priv_data NULL",
 192                             channel);
 193                         return (IBT_INVALID_PARAM);
 194                 }
 195         } else { /* any other mode is not valid for ibt_open_rc_channel */
 196                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 197                     "invalid mode %x specified", channel, mode);
 198                 return (IBT_INVALID_PARAM);
 199         }
 200 
 201         /*
 202          * XXX: no support yet for ibt_chan_open_flags_t - IBT_OCHAN_DUP
 203          */
 204         if (flags & IBT_OCHAN_DUP) {
 205                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 206                     "Unsupported Flags specified: 0x%X", channel, flags);
 207                 return (IBT_INVALID_PARAM);
 208         }
 209 
 210         if ((flags & IBT_OCHAN_REDIRECTED) &&
 211             (flags & IBT_OCHAN_PORT_REDIRECTED)) {
 212                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 213                     "Illegal to specify IBT_OCHAN_REDIRECTED and "
 214                     "IBT_OCHAN_PORT_REDIRECTED flags together", channel);
 215                 return (IBT_INVALID_PARAM);
 216         }
 217 
 218         if (((flags & IBT_OCHAN_REDIRECTED) &&
 219             (chan_args->oc_cm_redirect_info == NULL)) ||
 220             ((flags & IBT_OCHAN_PORT_REDIRECTED) &&
 221             (chan_args->oc_cm_cep_path == NULL))) {
 222                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 223                     "Redirect flag specified, but respective arg is NULL",
 224                     channel);
 225                 return (IBT_INVALID_PARAM);
 226         }
 227 
 228         if ((flags & IBT_OCHAN_REDIRECTED) &&
 229             (chan_args->oc_cm_redirect_info->rdi_dlid == 0) &&
 230             (chan_args->oc_cm_redirect_info->rdi_gid.gid_guid == 0)) {
 231                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 232                     "Either rdi_dlid or rdi_gid must be specified for"
 233                     " IBT_OCHAN_REDIRECTED", channel);
 234                 return (IBT_INVALID_PARAM);
 235         }
 236 
 237         /* primary dlid and hca_port_num should never be zero */
 238         port_no = IBCM_PRIM_CEP_PATH(chan_args).cep_hca_port_num;
 239 
 240         if ((IBCM_PRIM_ADDS_VECT(chan_args).av_dlid == 0) && (port_no == 0)) {
 241                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 242                     "Primary Path's information is not valid", channel);
 243                 return (IBT_INVALID_PARAM);
 244         }
 245 
 246         /* validate SID */
 247         if (chan_args->oc_path->pi_sid == 0) {
 248                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 249                     "ERROR: Service ID in path information is 0", channel);
 250                 return (IBT_INVALID_PARAM);
 251         }
 252         IBTF_DPRINTF_L3(cmlog, "ibt_open_rc_channel: chan 0x%p  SID %llX",
 253             channel, chan_args->oc_path->pi_sid);
 254 
 255         /* validate rnr_retry_cnt (enum has more than 3 bits) */
 256         if ((uint_t)chan_args->oc_path_rnr_retry_cnt > IBT_RNR_INFINITE_RETRY) {
 257                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 258                     "ERROR: oc_path_rnr_retry_cnt(%d) is out of range",
 259                     channel, chan_args->oc_path_rnr_retry_cnt);
 260                 return (IBT_INVALID_PARAM);
 261         }
 262 
 263         /*
 264          * Ensure that client is not re-using a QP that is still associated
 265          * with a statep
 266          */
 267         IBCM_GET_CHAN_PRIVATE(channel, statep);
 268         if (statep != NULL) {
 269                 IBCM_RELEASE_CHAN_PRIVATE(channel);
 270                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 271                     "Channel being re-used on active side", channel);
 272                 return (IBT_CHAN_IN_USE);
 273         }
 274 
 275         /* Get GUID from Channel */
 276         hca_guid = ibt_channel_to_hca_guid(channel);
 277 
 278         /* validate QP's hca guid with that from primary path  */
 279         if (hca_guid != chan_args->oc_path->pi_hca_guid) {
 280                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 281                     "GUID from Channel and primary path don't match", channel);
 282                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 283                     "Channel GUID %llX primary path GUID %llX", channel,
 284                     hca_guid, chan_args->oc_path->pi_hca_guid);
 285                 return (IBT_CHAN_HDL_INVALID);
 286         }
 287 
 288         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 289             "Local HCA GUID %llX", channel, hca_guid);
 290 
 291         status = ibt_query_qp(channel, &qp_query_attr);
 292         if (status != IBT_SUCCESS) {
 293                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 294                     "ibt_query_qp failed %d", channel, status);
 295                 return (status);
 296         }
 297 
 298         /* If client specified "no port change on QP" */
 299         if ((qp_query_attr.qp_info.qp_transport.rc.rc_path.cep_hca_port_num !=
 300             port_no) && (flags & IBT_OCHAN_PORT_FIXED)) {
 301                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 302                     "chan port %d and path port %d does not match", channel,
 303                     qp_query_attr.qp_info.qp_transport.rc.rc_path. \
 304                     cep_hca_port_num, port_no);
 305                 return (IBT_INVALID_PARAM);
 306         }
 307 
 308         if (qp_query_attr.qp_info.qp_trans != IBT_RC_SRV) {
 309                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 310                     "Invalid Channel type: Applicable only to RC Channel",
 311                     channel);
 312                 return (IBT_CHAN_SRV_TYPE_INVALID);
 313         }
 314 
 315         /* Check if QP is in INIT state or not */
 316         if (qp_query_attr.qp_info.qp_state != IBT_STATE_INIT) {
 317                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 318                     "QP is not in INIT state %x", channel,
 319                     qp_query_attr.qp_info.qp_state);
 320                 return (IBT_CHAN_STATE_INVALID);
 321         }
 322 
 323         local_qpn = qp_query_attr.qp_qpn;
 324 
 325         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p Active QPN 0x%x",
 326             channel, local_qpn);
 327 
 328 #ifdef  NO_EEC_SUPPORT_YET
 329 
 330         if (flags & IBT_OCHAN_RDC_EXISTS) {
 331                 ibt_eec_query_attr_t    eec_query_attr;
 332 
 333                 local_qkey = qp_query_attr.qp_info.qp_transport.rd_qkey;
 334 
 335                 IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: RD");
 336 
 337                 status = ibt_query_eec(channel, &eec_query_attr);
 338                 if (status != IBT_SUCCESS) {
 339                         IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p"
 340                             " ibt_query_eec failed %d", channel, status);
 341                         return (status);
 342                 }
 343                 local_eecn = eec_query_attr.eec_eecn;
 344         }
 345 
 346 #endif
 347         if (chan_args->oc_path->pi_prim_pkt_lt > ibcm_max_ib_pkt_lt) {
 348                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 349                     "Huge PktLifeTime %d, Max is %d", channel,
 350                     chan_args->oc_path->pi_prim_pkt_lt, ibcm_max_ib_pkt_lt);
 351                 return (IBT_PATH_PKT_LT_TOO_HIGH);
 352         }
 353 
 354         /* If no HCA found return failure */
 355         if ((hcap = ibcm_find_hca_entry(hca_guid)) == NULL) {
 356                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 357                     "hcap is NULL. Probably hca is not in active state",
 358                     channel);
 359                 return (IBT_CHAN_HDL_INVALID);
 360         }
 361 
 362         rdma_out = chan_args->oc_rdma_ra_out;
 363         rdma_in = chan_args->oc_rdma_ra_in;
 364 
 365         if ((rdma_in > hcap->hca_max_rdma_in_qp) ||
 366             (rdma_out > hcap->hca_max_rdma_out_qp)) {
 367                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 368                     "rdma in %d/out %d values exceed hca limits(%d/%d)",
 369                     channel, rdma_in, rdma_out, hcap->hca_max_rdma_in_qp,
 370                     hcap->hca_max_rdma_out_qp);
 371                 ibcm_dec_hca_acc_cnt(hcap);
 372                 return (IBT_INVALID_PARAM);
 373         }
 374 
 375         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 376             "rdma_in %d rdma_out %d", channel, rdma_in, rdma_out);
 377 
 378         status = ibt_get_port_state_byguid(hcap->hca_guid, port_no,
 379             NULL, &base_lid);
 380         if (status != IBT_SUCCESS) {
 381                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 382                     "primary port_num %d not active", channel, port_no);
 383                 ibcm_dec_hca_acc_cnt(hcap);
 384                 return (status);
 385         }
 386 
 387         /* Validate P_KEY Index */
 388         status = ibt_index2pkey_byguid(hcap->hca_guid, port_no,
 389             IBCM_PRIM_CEP_PATH(chan_args).cep_pkey_ix, &prim_pkey);
 390         if (status != IBT_SUCCESS) {
 391                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 392                     "Invalid Primary PKeyIx %x", channel,
 393                     IBCM_PRIM_CEP_PATH(chan_args).cep_pkey_ix);
 394                 ibcm_dec_hca_acc_cnt(hcap);
 395                 return (status);
 396         }
 397 
 398         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 399             "primary_port_num %d primary_pkey 0x%x", channel, port_no,
 400             prim_pkey);
 401 
 402         if ((hcap->hca_port_info[port_no - 1].port_ibmf_hdl == NULL) &&
 403             ((status = ibcm_hca_reinit_port(hcap, port_no - 1))
 404             != IBT_SUCCESS)) {
 405                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 406                     "ibmf reg or callback setup failed during re-initialize",
 407                     channel);
 408                 ibcm_dec_hca_acc_cnt(hcap);
 409                 return (status);
 410         }
 411 
 412         ibmf_hdl = hcap->hca_port_info[port_no - 1].port_ibmf_hdl;
 413         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 414             "primary ibmf_hdl = 0x%p", channel, ibmf_hdl);
 415 
 416         primary_slid = base_lid + IBCM_PRIM_ADDS_VECT(chan_args).av_src_path;
 417 
 418         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: channel 0x%p "
 419             "primary SLID = %x", channel, primary_slid);
 420 
 421         /* check first if alternate path exists or not as it is OPTIONAL */
 422         if (IBCM_ALT_CEP_PATH(chan_args).cep_hca_port_num != 0) {
 423                 uint8_t alt_port_no;
 424 
 425                 alt_port_no = IBCM_ALT_CEP_PATH(chan_args).cep_hca_port_num;
 426 
 427                 if (chan_args->oc_path->pi_alt_pkt_lt > ibcm_max_ib_pkt_lt) {
 428                         IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 429                             "Huge Alt Pkt lt %d", channel,
 430                             chan_args->oc_path->pi_alt_pkt_lt);
 431                         ibcm_dec_hca_acc_cnt(hcap);
 432                         return (IBT_PATH_PKT_LT_TOO_HIGH);
 433                 }
 434 
 435                 if (port_no != alt_port_no) {
 436 
 437                         status = ibt_get_port_state_byguid(hcap->hca_guid,
 438                             alt_port_no, NULL, &base_lid);
 439                         if (status != IBT_SUCCESS) {
 440 
 441                                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: "
 442                                     "chan 0x%p alt_port_num %d inactive %d",
 443                                     channel, alt_port_no, status);
 444                                 ibcm_dec_hca_acc_cnt(hcap);
 445                                 return (status);
 446                         }
 447 
 448                 }
 449                 alternate_slid =
 450                     base_lid + IBCM_ALT_ADDS_VECT(chan_args).av_src_path;
 451 
 452                 IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 453                     "alternate SLID = %x", channel, alternate_slid);
 454         }
 455 
 456         /*
 457          * only pkey needs to be zero'ed, because all other fields are set in
 458          * in ibcm_init_reply_addr. But, let's bzero the complete struct for
 459          * any future modifications.
 460          */
 461         bzero(&cm_reply_addr, sizeof (cm_reply_addr));
 462 
 463         /* Initialize the MAD destination address in stored_reply_addr */
 464         if ((status = ibcm_init_reply_addr(hcap, &cm_reply_addr, chan_args,
 465             flags, &cm_pkt_lt, primary_slid)) != IBT_SUCCESS) {
 466 
 467                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 468                     "ibcm_init_reply_addr failed status %d ", channel, status);
 469                 ibcm_dec_hca_acc_cnt(hcap);
 470                 return (status);
 471         }
 472 
 473 
 474         /* Initialize the pkey for CM MAD communication */
 475         if (cm_reply_addr.rcvd_addr.ia_p_key == 0)
 476                 cm_reply_addr.rcvd_addr.ia_p_key = prim_pkey;
 477 
 478 #ifdef DEBUG
 479         ibcm_print_reply_addr(channel, &cm_reply_addr);
 480 #endif
 481 
 482         /* Retrieve an ibmf qp for sending CM MADs */
 483         if ((cm_qp_entry = ibcm_find_qp(hcap, port_no,
 484             cm_reply_addr.rcvd_addr.ia_p_key)) == NULL) {
 485                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p "
 486                     "unable to allocate ibmf qp for CM MADs", channel);
 487                 ibcm_dec_hca_acc_cnt(hcap);
 488                 return (IBT_INSUFF_RESOURCE);
 489         }
 490 
 491 
 492         if (ibcm_alloc_comid(hcap, &local_comid) != IBCM_SUCCESS) {
 493                 ibcm_release_qp(cm_qp_entry);
 494                 ibcm_dec_hca_acc_cnt(hcap);
 495                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan 0x%p"
 496                     " Unable to allocate comid", channel);
 497                 return (IBT_INSUFF_KERNEL_RESOURCE);
 498         }
 499 
 500         /* allocate an IBMF mad buffer (REQ) */
 501         if ((status = ibcm_alloc_out_msg(ibmf_hdl, &ibmf_msg,
 502             MAD_METHOD_SEND)) != IBT_SUCCESS) {
 503                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: "
 504                     "chan 0x%p ibcm_alloc_out_msg failed", channel);
 505                 ibcm_release_qp(cm_qp_entry);
 506                 ibcm_free_comid(hcap, local_comid);
 507                 ibcm_dec_hca_acc_cnt(hcap);
 508                 return (status);
 509         }
 510 
 511         /* allocate an IBMF mad buffer (DREQ) */
 512         if ((status = ibcm_alloc_out_msg(ibmf_hdl, &ibmf_msg_dreq,
 513             MAD_METHOD_SEND)) != IBT_SUCCESS) {
 514                 IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: "
 515                     "chan 0x%p ibcm_alloc_out_msg failed", channel);
 516                 (void) ibcm_free_out_msg(ibmf_hdl, &ibmf_msg);
 517                 ibcm_release_qp(cm_qp_entry);
 518                 ibcm_free_comid(hcap, local_comid);
 519                 ibcm_dec_hca_acc_cnt(hcap);
 520                 return (status);
 521         }
 522 
 523         /* Init to Init, if QP's port does not match with path information */
 524         if (qp_query_attr.qp_info.qp_transport.rc.rc_path.cep_hca_port_num !=
 525             IBCM_PRIM_CEP_PATH(chan_args).cep_hca_port_num) {
 526 
 527                 ibt_qp_info_t           qp_info;
 528                 ibt_cep_modify_flags_t  cep_flags;
 529 
 530                 IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: "
 531                     "chan 0x%p chan port %d", channel,
 532                     qp_query_attr.qp_info.qp_transport.rc.rc_path.\
 533                     cep_hca_port_num);
 534 
 535                 IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: "
 536                     "chan 0x%p path port %d", channel, port_no);
 537 
 538                 bzero(&qp_info, sizeof (qp_info));
 539                 /* For now, set it to RC type */
 540 
 541                 qp_info.qp_trans = IBT_RC_SRV;
 542                 qp_info.qp_state = IBT_STATE_INIT;
 543                 qp_info.qp_transport.rc.rc_path.cep_hca_port_num = port_no;
 544 
 545                 cep_flags = IBT_CEP_SET_STATE | IBT_CEP_SET_PORT;
 546 
 547                 status = ibt_modify_qp(channel, cep_flags, &qp_info, NULL);
 548 
 549                 if (status != IBT_SUCCESS) {
 550                         IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: "
 551                             "chan 0x%p ibt_modify_qp() = %d", channel, status);
 552                         ibcm_release_qp(cm_qp_entry);
 553                         ibcm_free_comid(hcap, local_comid);
 554                         ibcm_dec_hca_acc_cnt(hcap);
 555                         (void) ibcm_free_out_msg(ibmf_hdl, &ibmf_msg);
 556                         (void) ibcm_free_out_msg(ibmf_hdl, &ibmf_msg_dreq);
 557                         return (status);
 558                 } else
 559                         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: "
 560                             "chan 0x%p ibt_modify_qp() = %d", channel, status);
 561         }
 562 
 563         /* allocate ibcm_state_data_t before grabbing the WRITER lock */
 564         statep = kmem_zalloc(sizeof (ibcm_state_data_t), KM_SLEEP);
 565         rw_enter(&hcap->hca_state_rwlock, RW_WRITER);
 566         lkup_status = ibcm_lookup_msg(IBCM_OUTGOING_REQ, local_comid, 0, 0,
 567             hcap, &statep);
 568         rw_exit(&hcap->hca_state_rwlock);
 569 
 570         /* CM should be seeing this for the first time */
 571         ASSERT(lkup_status == IBCM_LOOKUP_NEW);
 572 
 573         /* Increment the hca's resource count */
 574         ibcm_inc_hca_res_cnt(hcap);
 575 
 576         /* Once a resource created on hca, no need to hold the acc cnt */
 577         ibcm_dec_hca_acc_cnt(hcap);
 578 
 579         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
 580 
 581         statep->timerid = 0;
 582         statep->local_hca_guid = hca_guid;
 583         statep->local_qpn = local_qpn;
 584         statep->stored_reply_addr.cm_qp_entry = cm_qp_entry;
 585         statep->prim_port = IBCM_PRIM_CEP_PATH(chan_args).cep_hca_port_num;
 586         statep->alt_port = IBCM_ALT_CEP_PATH(chan_args).cep_hca_port_num;
 587 
 588 
 589         /* Save "statep" as channel's CM private data.  */
 590         statep->channel = channel;
 591         IBCM_SET_CHAN_PRIVATE(statep->channel, statep);
 592 
 593         statep->stored_msg = ibmf_msg;
 594         statep->dreq_msg = ibmf_msg_dreq;
 595 
 596         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*req_msgp))
 597 
 598         /* Start filling in the REQ MAD */
 599         req_msgp = (ibcm_req_msg_t *)IBCM_OUT_MSGP(statep->stored_msg);
 600         req_msgp->req_local_comm_id = h2b32(local_comid);
 601         req_msgp->req_svc_id = h2b64(chan_args->oc_path->pi_sid);
 602         req_msgp->req_local_ca_guid = h2b64(hca_guid);
 603         req_msgp->req_local_qkey = h2b32(local_qkey);        /* for EEC/RD */
 604 
 605         /* Bytes 32-35 are req_local_qpn and req_off_resp_resources */
 606         req_msgp->req_local_qpn_plus = h2b32(local_qpn << 8 | rdma_in);
 607 
 608         /* Bytes 36-39 are req_local_eec_no and req_off_initiator_depth */
 609         req_msgp->req_local_eec_no_plus = h2b32(local_eecn << 8 | rdma_out);
 610 
 611         if (flags & IBT_OCHAN_REMOTE_CM_TM)
 612                 remote_cm_resp_time = chan_args->oc_remote_cm_time;
 613         else
 614                 remote_cm_resp_time = ibcm_remote_response_time;
 615 
 616         /*
 617          * Bytes 40-43 - remote_eecn, remote_cm_resp_time, tran_type,
 618          * IBT_CM_FLOW_CONTROL is always set by default.
 619          */
 620         req_msgp->req_remote_eecn_plus = h2b32(
 621             remote_eecn << 8 | (ibt_usec2ib(remote_cm_resp_time) & 0x1f) << 3 |
 622             IBT_RC_SRV << 1 | IBT_CM_FLOW_CONTROL);
 623 
 624         if (flags & IBT_OCHAN_LOCAL_CM_TM)
 625                 local_cm_proc_time = chan_args->oc_local_cm_time;
 626         else
 627                 local_cm_proc_time = ibcm_local_processing_time;
 628 
 629         local_cm_resp_time = ibt_usec2ib(local_cm_proc_time +
 630             2 * ibt_ib2usec(chan_args->oc_path->pi_prim_pkt_lt) +
 631             ibcm_sw_delay);
 632 
 633         /* save retry count */
 634         statep->cep_retry_cnt = chan_args->oc_path_retry_cnt;
 635 
 636         if (flags & IBT_OCHAN_STARTING_PSN)
 637                 starting_psn = chan_args->oc_starting_psn;
 638 
 639         if (local_cm_resp_time > 0x1f)
 640                 local_cm_resp_time = 0x1f;
 641 
 642         /* Bytes 44-47 are req_starting_psn, local_cm_resp_time and retry_cnt */
 643         req_msgp->req_starting_psn_plus = h2b32(starting_psn << 8 |
 644             local_cm_resp_time << 3 | statep->cep_retry_cnt);
 645 
 646         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 647             "Prim Pkt lt (IB time) 0x%x", channel,
 648             chan_args->oc_path->pi_prim_pkt_lt);
 649 
 650         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 651             "local_cm_proc_time(usec) %d ", channel, local_cm_proc_time);
 652 
 653         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 654             "local_cm_resp_time(ib_time) %d", channel, local_cm_resp_time);
 655 
 656         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 657             "remote_cm_resp_time (usec) %d", channel, remote_cm_resp_time);
 658 
 659         statep->starting_psn = starting_psn;
 660 
 661         /* Pkey - bytes 48-49 */
 662         req_msgp->req_part_key = h2b16(prim_pkey);
 663 
 664         if (flags & IBT_OCHAN_CM_RETRY)
 665                 cm_retries = chan_args->oc_cm_retry_cnt;
 666         else
 667                 cm_retries = ibcm_max_retries;
 668 
 669         statep->max_cm_retries = statep->remaining_retry_cnt = cm_retries;
 670         req_msgp->req_max_cm_retries_plus = statep->max_cm_retries << 4;
 671 
 672         /*
 673          * Check whether SRQ is associated with this Channel, if yes, then
 674          * set the SRQ Exists bit in the REQ.
 675          */
 676         if (qp_query_attr.qp_srq != NULL) {
 677                 req_msgp->req_max_cm_retries_plus |= (1 << 3);
 678         }
 679 
 680         /*
 681          * By default on Tavor, we override the PathMTU to 1K.
 682          * To turn this off, set ibcm_override_path_mtu = 0.
 683          */
 684         if (ibcm_override_path_mtu && IBCM_IS_HCA_TAVOR(hcap) &&
 685             (chan_args->oc_path->pi_path_mtu > IB_MTU_1K)) {
 686                 req_msgp->req_mtu_plus = IB_MTU_1K << 4 |
 687                     chan_args->oc_path_rnr_retry_cnt;
 688                 IBTF_DPRINTF_L3(cmlog, "ibt_open_rc_channel: chan 0x%p PathMTU"
 689                     " overridden to IB_MTU_1K(%d) from %d", channel, IB_MTU_1K,
 690                     chan_args->oc_path->pi_path_mtu);
 691         } else
 692                 req_msgp->req_mtu_plus = chan_args->oc_path->pi_path_mtu << 4 |
 693                     chan_args->oc_path_rnr_retry_cnt;
 694 
 695         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p CM retry cnt %d"
 696             " staring PSN %x", channel, cm_retries, starting_psn);
 697 
 698 
 699 #ifdef  NO_EEC_SUPPORT_YET
 700         if (flags & IBT_OCHAN_RDC_EXISTS)
 701                 req_msgp->req_mtu_plus |= 8;
 702 #endif
 703 
 704         /* Initialize the "primary" port stuff next - bytes 52-95 */
 705         req_msgp->req_primary_l_port_lid = h2b16(primary_slid);
 706         req_msgp->req_primary_r_port_lid =
 707             h2b16(IBCM_PRIM_ADDS_VECT(chan_args).av_dlid);
 708         req_msgp->req_primary_l_port_gid.gid_prefix =
 709             h2b64(IBCM_PRIM_ADDS_VECT(chan_args).av_sgid.gid_prefix);
 710         req_msgp->req_primary_l_port_gid.gid_guid =
 711             h2b64(IBCM_PRIM_ADDS_VECT(chan_args).av_sgid.gid_guid);
 712         req_msgp->req_primary_r_port_gid.gid_prefix =
 713             h2b64(IBCM_PRIM_ADDS_VECT(chan_args).av_dgid.gid_prefix);
 714         req_msgp->req_primary_r_port_gid.gid_guid =
 715             h2b64(IBCM_PRIM_ADDS_VECT(chan_args).av_dgid.gid_guid);
 716         primary_grh = IBCM_PRIM_ADDS_VECT(chan_args).av_send_grh;
 717 
 718         statep->remote_hca_guid = /* not correct, but helpful for debugging */
 719             IBCM_PRIM_ADDS_VECT(chan_args).av_dgid.gid_guid;
 720 
 721         /* Bytes 88-91 - primary_flowlbl, and primary_srate */
 722         req_msgp->req_primary_flow_label_plus =
 723             h2b32(((primary_grh == B_TRUE) ?
 724             (IBCM_PRIM_ADDS_VECT(chan_args).av_flow << 12) : 0) |
 725             IBCM_PRIM_ADDS_VECT(chan_args).av_srate);
 726         req_msgp->req_primary_traffic_class = (primary_grh == B_TRUE) ?
 727             IBCM_PRIM_ADDS_VECT(chan_args).av_tclass : 0;
 728         req_msgp->req_primary_hop_limit = (primary_grh == B_TRUE) ?
 729             IBCM_PRIM_ADDS_VECT(chan_args).av_hop : 1;
 730         req_msgp->req_primary_sl_plus =
 731             IBCM_PRIM_ADDS_VECT(chan_args).av_srvl << 4 |
 732             ((primary_grh == B_TRUE) ? 0 : 8);
 733 
 734         req_msgp->req_primary_localtime_plus =
 735             ibt_usec2ib((2 * ibt_ib2usec(chan_args->oc_path->pi_prim_pkt_lt)) +
 736             ibt_ib2usec(hcap->hca_ack_delay)) << 3;
 737 
 738         IBTF_DPRINTF_L2(cmlog, "ibt_open_rc_channel: chan %p statep %p",
 739             channel, statep);
 740         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 741             "active hca_ack_delay (usec) %d", channel,
 742             req_msgp->req_primary_localtime_plus);
 743 
 744         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 745             "Sent primary cep timeout (IB Time) %d", channel,
 746             hcap->hca_ack_delay);
 747 
 748         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p prim_dlid %x ",
 749             channel, IBCM_PRIM_ADDS_VECT(chan_args).av_dlid);
 750 
 751         IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 752             "prim GID %llX:%llX", channel,
 753             IBCM_PRIM_ADDS_VECT(chan_args).av_dgid.gid_prefix,
 754             IBCM_PRIM_ADDS_VECT(chan_args).av_dgid.gid_guid);
 755 
 756         /* Initialize the "alternate" port stuff - optional */
 757         if (chan_args->oc_path->pi_alt_cep_path.cep_hca_port_num != 0) {
 758                 ib_gid_t        tmp_gid;
 759 
 760                 req_msgp->req_alt_l_port_lid = h2b16(alternate_slid);
 761                 req_msgp->req_alt_r_port_lid =
 762                     h2b16(IBCM_ALT_ADDS_VECT(chan_args).av_dlid);
 763                 /*
 764                  * doing all this as req_alt_r/l_port_gid is at offset
 765                  * 100, 116 which is not divisible by 8
 766                  */
 767 
 768                 tmp_gid.gid_prefix =
 769                     h2b64(IBCM_ALT_ADDS_VECT(chan_args).av_dgid.gid_prefix);
 770                 tmp_gid.gid_guid =
 771                     h2b64(IBCM_ALT_ADDS_VECT(chan_args).av_dgid.gid_guid);
 772                 bcopy(&tmp_gid, &req_msgp->req_alt_r_port_gid[0],
 773                     sizeof (ib_gid_t));
 774                 tmp_gid.gid_prefix =
 775                     h2b64(IBCM_ALT_ADDS_VECT(chan_args).av_sgid.gid_prefix);
 776                 tmp_gid.gid_guid =
 777                     h2b64(IBCM_ALT_ADDS_VECT(chan_args).av_sgid.gid_guid);
 778 
 779                 bcopy(&tmp_gid, &req_msgp->req_alt_l_port_gid[0],
 780                     sizeof (ib_gid_t));
 781                 alternate_grh = IBCM_ALT_ADDS_VECT(chan_args).av_send_grh;
 782 
 783                 /* Bytes 132-135 - alternate_flow_label, and alternate srate */
 784                 req_msgp->req_alt_flow_label_plus = h2b32(
 785                     (((alternate_grh == B_TRUE) ?
 786                     (IBCM_ALT_ADDS_VECT(chan_args).av_flow << 12) : 0) |
 787                     IBCM_ALT_ADDS_VECT(chan_args).av_srate));
 788                 req_msgp->req_alt_traffic_class = (alternate_grh == B_TRUE) ?
 789                     IBCM_ALT_ADDS_VECT(chan_args).av_tclass : 0;
 790                 req_msgp->req_alt_hop_limit = (alternate_grh == B_TRUE) ?
 791                     IBCM_ALT_ADDS_VECT(chan_args).av_hop : 1;
 792                 req_msgp->req_alt_sl_plus =
 793                     IBCM_ALT_ADDS_VECT(chan_args).av_srvl << 4 |
 794                     ((alternate_grh == B_TRUE) ? 0 : 8);
 795                 req_msgp->req_alt_localtime_plus = ibt_usec2ib((2 *
 796                     ibt_ib2usec(chan_args->oc_path->pi_alt_pkt_lt)) +
 797                     ibt_ib2usec(hcap->hca_ack_delay)) << 3;
 798 
 799                 IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 800                     "alt_dlid %x ", channel,
 801                     IBCM_ALT_ADDS_VECT(chan_args).av_dlid);
 802 
 803                 IBTF_DPRINTF_L5(cmlog, "ibt_open_rc_channel: chan 0x%p "
 804                     "alt GID %llX:%llX", channel,
 805                     IBCM_ALT_ADDS_VECT(chan_args).av_dgid.gid_prefix,
 806                     IBCM_ALT_ADDS_VECT(chan_args).av_dgid.gid_guid);
 807         }
 808 
 809         len = min(chan_args->oc_priv_data_len, IBT_REQ_PRIV_DATA_SZ);
 810         if ((len > 0) && chan_args->oc_priv_data)
 811                 bcopy(chan_args->oc_priv_data, req_msgp->req_private_data, len);
 812 
 813         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*req_msgp))
 814 
 815         /* return_data is filled up in the state machine code */
 816         if (ret_args != NULL) {
 817                 statep->open_return_data = ret_args;
 818         }
 819 
 820         /* initialize some statep fields here */
 821         statep->mode = IBCM_ACTIVE_MODE;
 822         statep->hcap = hcap;
 823 
 824         statep->cm_handler = chan_args->oc_cm_handler;
 825         statep->state_cm_private = chan_args->oc_cm_clnt_private;
 826 
 827         statep->pkt_life_time =
 828             ibt_ib2usec(chan_args->oc_path->pi_prim_pkt_lt);
 829 
 830         statep->timer_value = ibt_ib2usec(ibt_usec2ib(
 831             2 * ibt_ib2usec(cm_pkt_lt) + remote_cm_resp_time));
 832 
 833         /* Initialize statep->stored_reply_addr */
 834         statep->stored_reply_addr.ibmf_hdl = ibmf_hdl;
 835 
 836         /* Initialize stored reply addr fields */
 837         statep->stored_reply_addr.grh_hdr = cm_reply_addr.grh_hdr;
 838         statep->stored_reply_addr.rcvd_addr = cm_reply_addr.rcvd_addr;
 839         statep->stored_reply_addr.grh_exists = cm_reply_addr.grh_exists;
 840         statep->stored_reply_addr.port_num = cm_reply_addr.port_num;
 841 
 842         /*
 843          * The IPD on local/active side is calculated by path functions,
 844          * hence available in the args of ibt_open_rc_channel
 845          */
 846         statep->local_srate = IBCM_PRIM_ADDS_VECT(chan_args).av_srate;
 847         statep->local_alt_srate = IBCM_ALT_ADDS_VECT(chan_args).av_srate;
 848 
 849         /* Store the source path bits for primary and alt paths */
 850         statep->prim_src_path_bits = IBCM_PRIM_ADDS_VECT(chan_args).av_src_path;
 851         statep->alt_src_path_bits = IBCM_ALT_ADDS_VECT(chan_args).av_src_path;
 852 
 853         statep->open_flow = 1;
 854         statep->open_done = B_FALSE;
 855         statep->state = statep->timer_stored_state = IBCM_STATE_REQ_SENT;
 856         IBCM_REF_CNT_INCR(statep);      /* Decremented before return */
 857         IBCM_REF_CNT_INCR(statep);      /* Decremented after REQ is posted */
 858         statep->send_mad_flags |= IBCM_REQ_POST_BUSY;
 859 
 860         /*
 861          * Skip moving channel to error state during close, for OFUV clients.
 862          * OFUV clients transition the channel to error state by itself.
 863          */
 864         if (flags & IBT_OCHAN_OFUV)
 865                 statep->is_this_ofuv_chan = B_TRUE;
 866 
 867         IBCM_OUT_HDRP(statep->stored_msg)->AttributeID =
 868             h2b16(IBCM_INCOMING_REQ + IBCM_ATTR_BASE_ID);
 869 
 870         IBCM_OUT_HDRP(statep->stored_msg)->TransactionID =
 871             h2b64(ibcm_generate_tranid(IBCM_INCOMING_REQ, statep->local_comid,
 872             0));
 873 
 874         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*statep))
 875 
 876         ibtl_cm_chan_is_opening(channel);
 877 
 878         ibcm_open_enqueue(statep);
 879 
 880         mutex_enter(&statep->state_mutex);
 881 
 882         if (mode == IBT_BLOCKING) {
 883 
 884                 /* wait for REQ/REP/RTU */
 885                 while (statep->open_done != B_TRUE) {
 886                         cv_wait(&statep->block_client_cv, &statep->state_mutex);
 887                 }
 888 
 889                 /*
 890                  * In the case that open_channel() fails because of a
 891                  * REJ or timeout, change retval to IBT_CM_FAILURE
 892                  */
 893                 if (statep->open_return_data->rc_status != IBT_CM_SUCCESS) {
 894                         status = IBT_CM_FAILURE;
 895                         ibtl_cm_chan_open_is_aborted(channel);
 896                 }
 897 
 898                 IBTF_DPRINTF_L3(cmlog, "ibt_open_rc_channel: chan 0x%p "
 899                     "ret status %d cm status %d", channel, status,
 900                     statep->open_return_data->rc_status);
 901         }
 902 
 903         /* decrement the ref-count before leaving here */
 904         IBCM_REF_CNT_DECR(statep);
 905 
 906         mutex_exit(&statep->state_mutex);
 907 
 908         IBTF_DPRINTF_L4(cmlog, "ibt_open_rc_channel: chan 0x%p done", channel);
 909         return (status);
 910 }
 911 
 912 /*
 913  * ibcm_init_reply_addr:
 914  *
 915  * The brief description of functionality below.
 916  *
 917  * For IBT_OCHAN_PORT_REDIRECTED (ie., port redirected case):
 918  *      Build CM path from chan_args->oc_cm_cep_path
 919  *      Set CM pkt lt (ie.,life time) to chan_args->oc_cm_pkt_lt
 920  *
 921  * For IBT_OCHAN_REDIRECTED (ie., port and CM redirected case):
 922  *      If Redirect LID is specified,
 923  *              If Redirect GID is not specified or specified to be on the same
 924  *                  subnet, then
 925  *                      Build CM path from chan_args->oc_cm_redirect_info
 926  *                      Set CM pkt lt to subnet timeout
 927  *              Else (ie., GID specified, but on a different subnet)
 928  *                      Do a path lookup to build CM Path and set CM pkt lt
 929  *
 930  */
 931 static ibt_status_t
 932 ibcm_init_reply_addr(ibcm_hca_info_t *hcap, ibcm_mad_addr_t *reply_addr,
 933     ibt_chan_open_args_t *chan_args, ibt_chan_open_flags_t flags,
 934     ib_time_t *cm_pkt_lt, ib_lid_t prim_slid)
 935 {
 936         ibt_adds_vect_t *cm_adds;
 937         ibt_path_info_t path;
 938         boolean_t       cm_grh;
 939         ibt_status_t    status;
 940 
 941         IBTF_DPRINTF_L5(cmlog, "ibcm_init_reply_addr:");
 942 
 943         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*reply_addr))
 944 
 945         /*
 946          * sending side CM lid/gid/port num are not based on any redirect
 947          * params. These values are set to primary RC path lid/gid/port num.
 948          * In the future, these values can be set based on framework policy
 949          * decisions ensuring reachability.
 950          */
 951         reply_addr->grh_hdr.ig_sender_gid =
 952             IBCM_PRIM_ADDS_VECT(chan_args).av_sgid;
 953         reply_addr->rcvd_addr.ia_local_lid = prim_slid;
 954         reply_addr->port_num = IBCM_PRIM_CEP_PATH(chan_args).cep_hca_port_num;
 955 
 956         if (flags & IBT_OCHAN_PORT_REDIRECTED) {
 957                 IBTF_DPRINTF_L4(cmlog, "ibcm_init_rely_addr: "
 958                     "IBT_OCHAN_PORT_REDIRECTED specified");
 959 
 960                 status = ibt_index2pkey_byguid(hcap->hca_guid,
 961                     chan_args->oc_cm_cep_path->cep_hca_port_num,
 962                     chan_args->oc_cm_cep_path->cep_pkey_ix,
 963                     &reply_addr->rcvd_addr.ia_p_key);
 964 
 965                 if (status != IBT_SUCCESS) {
 966                         IBTF_DPRINTF_L2(cmlog, "ibcm_init_rely_addr: Invalid "
 967                             "CM PKeyIx %x port_num %x",
 968                             chan_args->oc_cm_cep_path->cep_pkey_ix,
 969                             chan_args->oc_cm_cep_path->cep_hca_port_num);
 970                         return (status);
 971                 }
 972 
 973                 cm_adds = &(chan_args->oc_cm_cep_path->cep_adds_vect);
 974                 IBTF_DPRINTF_L4(cmlog, "ibcm_init_rely_addr: dlid = %x",
 975                     cm_adds->av_dlid);
 976 
 977                 reply_addr->rcvd_addr.ia_q_key = IB_GSI_QKEY;
 978                 reply_addr->rcvd_addr.ia_remote_qno = 1;
 979                 *cm_pkt_lt = chan_args->oc_cm_pkt_lt;
 980 
 981         } else if (flags & IBT_OCHAN_REDIRECTED) {
 982                 ibt_redirect_info_t     *redirect_info;
 983                 ibt_hca_portinfo_t      *port_infop;
 984                 uint_t                  psize, nports;
 985 
 986                 IBTF_DPRINTF_L4(cmlog, "ibcm_init_rely_addr: "
 987                     "IBT_OCHAN_REDIRECTED specified");
 988 
 989                 redirect_info = chan_args->oc_cm_redirect_info;
 990 
 991                 if ((redirect_info->rdi_gid.gid_prefix == 0) ||
 992                     (redirect_info->rdi_gid.gid_guid == 0)) {
 993                         IBTF_DPRINTF_L2(cmlog, "ibcm_init_reply_addr: "
 994                             "ERROR: Re-direct GID value NOT Provided.");
 995                         return (IBT_INVALID_PARAM);
 996                 }
 997 
 998                 /* As per spec definition 1.1, it's always IB_GSI_QKEY */
 999                 reply_addr->rcvd_addr.ia_q_key = redirect_info->rdi_qkey;
1000                 reply_addr->rcvd_addr.ia_remote_qno = redirect_info->rdi_qpn;
1001                 reply_addr->rcvd_addr.ia_p_key = redirect_info->rdi_pkey;
1002 
1003                 /*
1004                  * if LID is non-zero in classportinfo then use classportinfo
1005                  * fields to form CM MAD destination address.
1006                  */
1007                 if (redirect_info->rdi_dlid != 0) {
1008                         status = ibtl_cm_query_hca_ports_byguid(hcap->hca_guid,
1009                             reply_addr->port_num, &port_infop, &nports, &psize);
1010                         if ((status != IBT_SUCCESS) || (nports == 0)) {
1011                                 IBTF_DPRINTF_L2(cmlog, "ibcm_init_reply_addr: "
1012                                     "Query Ports Failed: %d", status);
1013                                 return (status);
1014                         } else if (port_infop->p_subnet_timeout >
1015                             ibcm_max_ib_pkt_lt) {
1016                                 IBTF_DPRINTF_L2(cmlog, "ibcm_init_reply_addr: "
1017                                     "large subnet timeout %x port_no %x",
1018                                     port_infop->p_subnet_timeout,
1019                                     reply_addr->port_num);
1020                                 ibt_free_portinfo(port_infop, psize);
1021                                 return (IBT_PATH_PKT_LT_TOO_HIGH);
1022                         } else {
1023                                 IBTF_DPRINTF_L3(cmlog, "ibcm_init_reply_addr: "
1024                                     "subnet timeout %x port_no %x",
1025                                     port_infop->p_subnet_timeout,
1026                                     reply_addr->port_num);
1027 
1028                                 *cm_pkt_lt =
1029                                     ibt_ib2usec(min(ibcm_max_ib_mad_pkt_lt,
1030                                     port_infop->p_subnet_timeout));
1031 
1032                                 ibt_free_portinfo(port_infop, psize);
1033                         }
1034 
1035                         reply_addr->rcvd_addr.ia_remote_lid =
1036                             redirect_info->rdi_dlid;
1037                         reply_addr->rcvd_addr.ia_service_level =
1038                             redirect_info->rdi_sl;
1039                         reply_addr->grh_exists = B_TRUE;
1040                         reply_addr->grh_hdr.ig_recver_gid =
1041                             redirect_info->rdi_gid;
1042                         reply_addr->grh_hdr.ig_tclass =
1043                             redirect_info->rdi_tclass;
1044                         reply_addr->grh_hdr.ig_flow_label =
1045                             redirect_info->rdi_flow;
1046 
1047                         /* Classportinfo doesn't have hoplimit field */
1048                         reply_addr->grh_hdr.ig_hop_limit = 1;
1049                         return (IBT_SUCCESS);
1050 
1051                 } else {
1052                         ibt_path_attr_t path_attr;
1053                         ib_gid_t        path_dgid[1];
1054 
1055                         /*
1056                          * If GID is specified, and LID is zero in classportinfo
1057                          * do a path lookup using specified GID, Pkey,
1058                          * in classportinfo
1059                          */
1060 
1061                         bzero(&path_attr, sizeof (path_attr));
1062 
1063                         path_attr.pa_dgids = &path_dgid[0];
1064                         path_attr.pa_dgids[0] = redirect_info->rdi_gid;
1065 
1066                         /*
1067                          * use reply_addr below, as sender_gid in reply_addr
1068                          * may have been set above based on some policy decision
1069                          * for originating end point for CM MADs above
1070                          */
1071                         path_attr.pa_sgid = reply_addr->grh_hdr.ig_sender_gid;
1072                         path_attr.pa_num_dgids = 1;
1073                         path_attr.pa_pkey = redirect_info->rdi_pkey;
1074 
1075                         if ((status = ibt_get_paths(ibcm_ibt_handle,
1076                             IBT_PATH_PKEY, &path_attr, 1, &path, NULL)) !=
1077                             IBT_SUCCESS)
1078                                 return (status);
1079 
1080                         /* Initialize cm_adds */
1081                         cm_adds = &path.pi_prim_cep_path.cep_adds_vect;
1082                         *cm_pkt_lt = path.pi_prim_pkt_lt;
1083                 }
1084 
1085         } else  { /* cm_pkey initialized in ibt_open_rc_channel */
1086                 reply_addr->rcvd_addr.ia_q_key = IB_GSI_QKEY;
1087                 reply_addr->rcvd_addr.ia_remote_qno = 1;
1088                 *cm_pkt_lt = chan_args->oc_path->pi_prim_pkt_lt;
1089                 cm_adds = &(IBCM_PRIM_ADDS_VECT(chan_args));
1090         }
1091 
1092 
1093         cm_grh = cm_adds->av_send_grh;
1094         reply_addr->grh_exists = cm_grh;
1095 
1096         reply_addr->rcvd_addr.ia_remote_lid =
1097             cm_adds->av_dlid;
1098         reply_addr->grh_hdr.ig_recver_gid =
1099             cm_adds->av_dgid;
1100         reply_addr->grh_hdr.ig_flow_label =
1101             cm_adds->av_flow & IB_GRH_FLOW_LABEL_MASK;
1102         reply_addr->grh_hdr.ig_tclass =
1103             (cm_grh == B_TRUE) ? cm_adds->av_tclass : 0;
1104         reply_addr->grh_hdr.ig_hop_limit =
1105             (cm_grh == B_TRUE) ? cm_adds->av_hop : 1;
1106         reply_addr->rcvd_addr.ia_service_level =
1107             cm_adds->av_srvl;
1108 
1109         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*reply_addr))
1110 
1111         return (IBT_SUCCESS);
1112 }
1113 
1114 
1115 /*
1116  * ibt_prime_close_rc_channel()
1117  *      It allocates resources required for close channel operation, so
1118  *      ibt_close_rc_channel can be called from interrupt routine.
1119  *
1120  * INPUTS:
1121  *      channel                 The address of an ibt_channel_t struct that
1122  *                              specifies the channel to open.
1123  *
1124  * RETURN VALUES:
1125  *      IBT_SUCCESS     on success(or respective failure on error)
1126  *
1127  * Clients are typically expected to call this function in established state
1128  */
1129 ibt_status_t
1130 ibt_prime_close_rc_channel(ibt_channel_hdl_t channel)
1131 {
1132         ibcm_state_data_t       *statep;
1133         ibt_status_t            status = IBT_SUCCESS;
1134 
1135         IBTF_DPRINTF_L3(cmlog, "ibt_prime_close_rc_channel(%p)", channel);
1136 
1137         /* validate channel, first */
1138         if (IBCM_INVALID_CHANNEL(channel)) {
1139                 IBTF_DPRINTF_L2(cmlog, "ibt_prime_close_rc_channel: chan 0x%p "
1140                     "invalid channel", channel);
1141                 return (IBT_CHAN_HDL_INVALID);
1142         }
1143 
1144         if (ibtl_cm_get_chan_type(channel) != IBT_RC_SRV) {
1145                 IBTF_DPRINTF_L2(cmlog, "ibt_prime_close_rc_channel: chan 0x%p "
1146                     "Invalid Channel type: Applicable only to RC Channel",
1147                     channel);
1148                 return (IBT_CHAN_SRV_TYPE_INVALID);
1149         }
1150 
1151         /* get the statep */
1152         IBCM_GET_CHAN_PRIVATE(channel, statep);
1153 
1154         /*
1155          * This can happen, if the statep is already gone by a DREQ from
1156          * the remote side
1157          */
1158 
1159         if (statep == NULL) {
1160                 IBTF_DPRINTF_L2(cmlog, "ibt_prime_close_rc_channel: chan 0x%p "
1161                     "statep NULL", channel);
1162                 return (IBT_SUCCESS);
1163         }
1164 
1165         mutex_enter(&statep->state_mutex);
1166         IBCM_RELEASE_CHAN_PRIVATE(channel);
1167         if (statep->state != IBCM_STATE_ESTABLISHED) {
1168                 mutex_exit(&statep->state_mutex);
1169                 return (IBT_CHAN_STATE_INVALID);
1170         }
1171         IBCM_REF_CNT_INCR(statep);
1172         IBTF_DPRINTF_L4(cmlog, "ibt_prime_close_rc_channel: chan 0x%p statep %p"
1173             " state %x", channel, statep, statep->state);
1174         mutex_exit(&statep->state_mutex);
1175 
1176         /* clients could pre-allocate dreq mad, even before connection est */
1177         if (statep->dreq_msg == NULL)
1178                 status = ibcm_alloc_out_msg(statep->stored_reply_addr.ibmf_hdl,
1179                     &statep->dreq_msg, MAD_METHOD_SEND);
1180 
1181         mutex_enter(&statep->state_mutex);
1182         IBCM_REF_CNT_DECR(statep);
1183         mutex_exit(&statep->state_mutex);
1184 
1185         if (status != IBT_SUCCESS) {
1186                 IBTF_DPRINTF_L2(cmlog, "ibt_prime_close_rc_channel: chan 0x%p "
1187                     "ibcm_alloc_out_msg failed ", channel);
1188                 return (status);
1189         }
1190 
1191         /* If this message isn't seen then ibt_prime_close_rc_channel failed */
1192         IBTF_DPRINTF_L5(cmlog, "ibt_prime_close_rc_channel: chan 0x%p done",
1193             channel);
1194 
1195         return (IBT_SUCCESS);
1196 }
1197 
1198 /*
1199  * ibt_close_rc_channel()
1200  *      It closes an established channel.
1201  *
1202  * RETURN VALUES:
1203  *      IBT_SUCCESS     on success(or respective failure on error)
1204  */
1205 ibt_status_t
1206 ibt_close_rc_channel(ibt_channel_hdl_t channel, ibt_execution_mode_t mode,
1207     void *priv_data, ibt_priv_data_len_t priv_data_len, uint8_t *ret_status,
1208     void *ret_priv_data, ibt_priv_data_len_t *ret_priv_data_len_p)
1209 {
1210         ibcm_state_data_t       *statep;
1211 
1212         IBTF_DPRINTF_L3(cmlog, "ibt_close_rc_channel(%p, %x, %p, %d, %p)",
1213             channel, mode, priv_data, priv_data_len,
1214             (ret_priv_data_len_p == NULL) ? 0 : *ret_priv_data_len_p);
1215 
1216         /* validate channel, first */
1217         if (IBCM_INVALID_CHANNEL(channel)) {
1218                 IBTF_DPRINTF_L2(cmlog, "ibt_close_rc_channel: chan 0x%p "
1219                     "invalid channel", channel);
1220                 return (IBT_CHAN_HDL_INVALID);
1221         }
1222 
1223         if (ibtl_cm_get_chan_type(channel) != IBT_RC_SRV) {
1224                 IBTF_DPRINTF_L2(cmlog, "ibt_close_rc_channel: chan 0x%p "
1225                     "Invalid Channel type: Applicable only to RC Channel",
1226                     channel);
1227                 return (IBT_CHAN_SRV_TYPE_INVALID);
1228         }
1229 
1230         if (mode == IBT_BLOCKING) {
1231                 /* valid only for BLOCKING MODE */
1232                 if ((ret_priv_data_len_p != NULL) &&
1233                     (*ret_priv_data_len_p > IBT_DREP_PRIV_DATA_SZ)) {
1234                         IBTF_DPRINTF_L2(cmlog, "ibt_close_rc_channel: chan 0x%p"
1235                             " private data len %d is too large", channel,
1236                             *ret_priv_data_len_p);
1237                         return (IBT_INVALID_PARAM);
1238                 }
1239         } else if ((mode != IBT_NONBLOCKING) && (mode != IBT_NOCALLBACKS)) {
1240                 IBTF_DPRINTF_L2(cmlog, "ibt_close_rc_channel: chan 0x%p "
1241                     "invalid mode %x specified", channel, mode);
1242                 return (IBT_INVALID_PARAM);
1243         }
1244 
1245         if (ibtl_cm_is_chan_closing(channel) ||
1246             ibtl_cm_is_chan_closed(channel)) {
1247                 if (ret_status)
1248                         *ret_status = IBT_CM_CLOSED_ALREADY;
1249 
1250                 /* No private data to return to the client */
1251                 if (ret_priv_data_len_p != NULL)
1252                         *ret_priv_data_len_p = 0;
1253 
1254                 if ((mode == IBT_BLOCKING) ||
1255                     (mode == IBT_NOCALLBACKS)) {
1256                         IBCM_GET_CHAN_PRIVATE(channel, statep);
1257                         if (statep == NULL)
1258                                 return (IBT_SUCCESS);
1259                         mutex_enter(&statep->state_mutex);
1260                         IBCM_RELEASE_CHAN_PRIVATE(channel);
1261                         IBCM_REF_CNT_INCR(statep);
1262                         while (statep->close_done != B_TRUE)
1263                                 cv_wait(&statep->block_client_cv,
1264                                     &statep->state_mutex);
1265                         IBCM_REF_CNT_DECR(statep);
1266                         mutex_exit(&statep->state_mutex);
1267                 }
1268 
1269                 IBTF_DPRINTF_L3(cmlog, "ibt_close_rc_channel: chan 0x%p "
1270                     "already marked for closing", channel);
1271 
1272                 return (IBT_SUCCESS);
1273         }
1274 
1275         /* get the statep */
1276         IBCM_GET_CHAN_PRIVATE(channel, statep);
1277         if (statep == NULL) {
1278                 IBTF_DPRINTF_L2(cmlog, "ibt_close_rc_channel: chan 0x%p "
1279                     "statep NULL", channel);
1280                 return (IBT_CHAN_STATE_INVALID);
1281         }
1282 
1283         mutex_enter(&statep->state_mutex);
1284 
1285         if (statep->dreq_msg == NULL) {
1286                 IBTF_DPRINTF_L2(cmlog, "ibt_close_rc_channel: chan 0x%p "
1287                     "Fatal Error: dreq_msg is NULL", channel);
1288                 IBCM_RELEASE_CHAN_PRIVATE(channel);
1289                 mutex_exit(&statep->state_mutex);
1290                 return (IBT_CHAN_STATE_INVALID);
1291         }
1292 
1293         if ((ret_priv_data == NULL) || (ret_priv_data_len_p == NULL)) {
1294                 statep->close_ret_priv_data = NULL;
1295                 statep->close_ret_priv_data_len = NULL;
1296         } else {
1297                 statep->close_ret_priv_data = ret_priv_data;
1298                 statep->close_ret_priv_data_len = ret_priv_data_len_p;
1299         }
1300 
1301         priv_data_len = min(priv_data_len, IBT_DREQ_PRIV_DATA_SZ);
1302         if ((priv_data != NULL) && (priv_data_len > 0)) {
1303                 bcopy(priv_data, ((ibcm_dreq_msg_t *)
1304                     IBCM_OUT_MSGP(statep->dreq_msg))->dreq_private_data,
1305                     priv_data_len);
1306         }
1307         statep->close_ret_status = ret_status;
1308 
1309         IBCM_RELEASE_CHAN_PRIVATE(channel);
1310         IBCM_REF_CNT_INCR(statep);
1311 
1312         if (mode != IBT_NONBLOCKING) {
1313                 return (ibcm_close_rc_channel(channel, statep, mode));
1314         }
1315 
1316         /* IBT_NONBLOCKING */
1317         ibcm_close_enqueue(statep);
1318         mutex_exit(&statep->state_mutex);
1319 
1320         return (IBT_SUCCESS);
1321 }
1322 
1323 void
1324 ibcm_close_start(ibcm_state_data_t *statep)
1325 {
1326         mutex_enter(&statep->state_mutex);
1327         (void) ibcm_close_rc_channel(statep->channel, statep, IBT_NONBLOCKING);
1328 }
1329 
1330 static
1331 ibt_status_t
1332 ibcm_close_rc_channel(ibt_channel_hdl_t channel, ibcm_state_data_t *statep,
1333     ibt_execution_mode_t mode)
1334 {
1335         ibcm_hca_info_t         *hcap;
1336 
1337         _NOTE(LOCK_RELEASED_AS_SIDE_EFFECT(&statep->state_mutex));
1338         ASSERT(MUTEX_HELD(&statep->state_mutex));
1339 
1340         IBTF_DPRINTF_L3(cmlog, "ibcm_close_rc_channel: chan 0x%p statep %p",
1341             channel, statep);
1342 
1343         hcap = statep->hcap;
1344 
1345         /* HCA must have been in active state. If not, it's a client bug */
1346         if (!IBCM_ACCESS_HCA_OK(hcap)) {
1347                 IBTF_DPRINTF_L2(cmlog, "ibcm_close_rc_channel: chan 0x%p "
1348                     "hcap 0x%p not active", channel, hcap);
1349                 IBCM_REF_CNT_DECR(statep);
1350                 mutex_exit(&statep->state_mutex);
1351                 return (IBT_CHAN_HDL_INVALID);
1352         }
1353 
1354         if (statep->state == IBCM_STATE_TRANSIENT_ESTABLISHED) {
1355                 while (statep->cep_in_rts == IBCM_BLOCK)
1356                         cv_wait(&statep->block_mad_cv, &statep->state_mutex);
1357         }
1358 
1359         /* Do TRANSIENT_DREQ check after TRANSIENT_ESTABLISHED check */
1360         while (statep->state == IBCM_STATE_TRANSIENT_DREQ_SENT)
1361                 cv_wait(&statep->block_mad_cv, &statep->state_mutex);
1362 
1363         IBTF_DPRINTF_L4(cmlog, "ibcm_close_rc_channel: chan 0x%p "
1364             "connection state is %x", channel, statep->state);
1365 
1366         /* If state is in pre-established states, abort the connection est */
1367         if (statep->state != IBCM_STATE_ESTABLISHED) {
1368                 statep->cm_retries++;        /* ensure connection trace is dumped */
1369 
1370                 /* No DREP private data possible */
1371                 if (statep->close_ret_priv_data_len != NULL)
1372                         *statep->close_ret_priv_data_len = 0;
1373 
1374                 /*
1375                  * If waiting for a response mad, then cancel the timer,
1376                  * and delete the connection
1377                  */
1378                 if (statep->state == IBCM_STATE_REQ_SENT ||
1379                     statep->state == IBCM_STATE_REP_SENT ||
1380                     statep->state == IBCM_STATE_REP_WAIT ||
1381                     statep->state == IBCM_STATE_MRA_REP_RCVD) {
1382                         timeout_id_t            timer_val = statep->timerid;
1383                         ibcm_conn_state_t       old_state;
1384 
1385                         IBTF_DPRINTF_L4(cmlog, "ibcm_close_rc_channel: "
1386                             "chan 0x%p connection aborted in state %x", channel,
1387                             statep->state);
1388 
1389                         old_state = statep->state;
1390                         statep->state = IBCM_STATE_DELETE;
1391 
1392                         if (mode == IBT_NONBLOCKING) {
1393                                 if (taskq_dispatch(ibcm_taskq,
1394                                     ibcm_process_abort_via_taskq, statep,
1395                                     TQ_NOSLEEP) == 0) {
1396 
1397                                         IBCM_REF_CNT_DECR(statep);
1398                                         statep->state = old_state;
1399                                         mutex_exit(&statep->state_mutex);
1400                                         return (IBT_INSUFF_KERNEL_RESOURCE);
1401                                 }       /* if taskq_dispatch succeeds */
1402                                 /* Cancel the timer */
1403                                 statep->timerid = 0;
1404                                 mutex_exit(&statep->state_mutex);
1405                         } else {
1406                                 /* Cancel the timer */
1407                                 statep->timerid = 0;
1408                                 mutex_exit(&statep->state_mutex);
1409                                 (void) taskq_dispatch(ibcm_taskq,
1410                                     ibcm_process_abort_via_taskq, statep,
1411                                     TQ_SLEEP);
1412                         }
1413 
1414                         /* cancel the currently running timer */
1415                         if (timer_val != 0)
1416                                 (void) untimeout(timer_val);
1417 
1418                         /* wait until cm handler returns for BLOCKING cases */
1419                         mutex_enter(&statep->state_mutex);
1420                         if ((mode == IBT_BLOCKING) ||
1421                             (mode == IBT_NOCALLBACKS)) {
1422                                 while (statep->close_done != B_TRUE)
1423                                         cv_wait(&statep->block_client_cv,
1424                                             &statep->state_mutex);
1425                         }
1426 
1427                         if (statep->close_ret_status)
1428                                 *statep->close_ret_status = IBT_CM_CLOSED_ABORT;
1429                         mutex_exit(&statep->state_mutex);
1430 
1431                         /*
1432                          * It would ideal to post a REJ MAD, but that would
1433                          * be non-conformance to spec. Hence, delete the state
1434                          * data. Assuming that happens quickly, any retransmits
1435                          * from the remote are replied by CM with reject
1436                          * reason " no valid com id". That would stop remote
1437                          * sending any more MADs.
1438                          */
1439                         ibcm_delete_state_data(statep);
1440                         return (IBT_SUCCESS);
1441 
1442                 /* if CM busy in cm handler, wait until cm handler returns */
1443                 } else if (statep->state == IBCM_STATE_REQ_RCVD ||
1444                     statep->state == IBCM_STATE_REP_RCVD ||
1445                     statep->state == IBCM_STATE_MRA_SENT ||
1446                     statep->state == IBCM_STATE_MRA_REP_SENT) {
1447 
1448                         /* take control of statep */
1449                         statep->abort_flag |= IBCM_ABORT_CLIENT;
1450 
1451                         IBTF_DPRINTF_L4(cmlog, "ibcm_close_rc_channel: "
1452                             "chan 0x%p connection aborted in state = %x",
1453                             channel, statep->state);
1454 
1455                         /*
1456                          * wait until state machine modifies qp state to error,
1457                          * including disassociating statep and QP
1458                          */
1459                         if ((mode == IBT_BLOCKING) || (mode == IBT_NOCALLBACKS))
1460                                 while (statep->close_done != B_TRUE)
1461                                         cv_wait(&statep->block_client_cv,
1462                                             &statep->state_mutex);
1463 
1464                         /* a sanity setting */
1465                         if (mode == IBT_NOCALLBACKS)
1466                                 statep->cm_handler = NULL;
1467                         IBCM_REF_CNT_DECR(statep);
1468 
1469                         /*
1470                          * In rare situations, connection attempt could be
1471                          * terminated for some other reason, before abort is
1472                          * processed, but CM still returns ret_status as abort
1473                          */
1474                         if (statep->close_ret_status)
1475                                 *statep->close_ret_status = IBT_CM_CLOSED_ABORT;
1476                         mutex_exit(&statep->state_mutex);
1477 
1478                         /*
1479                          * REJ MAD is posted by the CM state machine for this
1480                          * case, hence state structure is deleted in the
1481                          * state machine processing.
1482                          */
1483                         return (IBT_SUCCESS);
1484 
1485                 } else if ((statep->state == IBCM_STATE_TIMEWAIT) ||
1486                     (statep->state == IBCM_STATE_DELETE)) {
1487 
1488                         /* State already in timewait, so no return priv data */
1489                         IBCM_REF_CNT_DECR(statep);
1490 
1491                         /* The teardown has already been done */
1492                         if (statep->close_ret_status)
1493                                 *statep->close_ret_status =
1494                                     IBT_CM_CLOSED_ALREADY;
1495                         mutex_exit(&statep->state_mutex);
1496 
1497                         return (IBT_SUCCESS);
1498 
1499                 } else if ((statep->state == IBCM_STATE_DREQ_RCVD) ||
1500                     (statep->state == IBCM_STATE_DREQ_SENT) ||
1501                     (statep->state == IBCM_STATE_DREP_RCVD) ||
1502                     ((statep->state == IBCM_STATE_TIMED_OUT) &&
1503                     (statep->timedout_state == IBCM_STATE_DREQ_SENT))) {
1504 
1505                         /*
1506                          * Either the remote or local client has already
1507                          * initiated the teardown.  IBCM_STATE_DREP_RCVD is
1508                          * possible, if CM initiated teardown without client's
1509                          * knowledge, for stale handling, etc.,
1510                          */
1511                         if (mode == IBT_NOCALLBACKS) {
1512                                 if (statep->close_nocb_state == IBCM_UNBLOCK) {
1513                                         statep->close_nocb_state = IBCM_FAIL;
1514                                         /* enable free qp after return */
1515                                         ibtl_cm_chan_is_closing(
1516                                             statep->channel);
1517                                 } else while (statep->close_nocb_state ==
1518                                     IBCM_BLOCK)
1519                                         cv_wait(&statep->block_client_cv,
1520                                             &statep->state_mutex);
1521                                 statep->cm_handler = NULL; /* sanity setting */
1522                                 if (statep->close_ret_status)
1523                                         *statep->close_ret_status =
1524                                             IBT_CM_CLOSED_ALREADY;
1525                         } else if (mode == IBT_BLOCKING) {
1526                                 /* wait until state is moved to timewait */
1527                                 while (statep->close_done != B_TRUE)
1528                                         cv_wait(&statep->block_client_cv,
1529                                             &statep->state_mutex);
1530                         }
1531 
1532                         IBCM_REF_CNT_DECR(statep);
1533                         mutex_exit(&statep->state_mutex);
1534 
1535                         /* ret_status is set in state machine code */
1536                         return (IBT_SUCCESS);
1537 
1538                 } else if (statep->state == IBCM_STATE_TIMED_OUT) {
1539 
1540                         if ((mode == IBT_BLOCKING) ||
1541                             (mode == IBT_NOCALLBACKS)) {
1542 
1543                                 /*
1544                                  * wait until cm handler invocation and
1545                                  * disassociation between statep and channel
1546                                  * is complete
1547                                  */
1548                                 while (statep->close_done != B_TRUE)
1549                                         cv_wait(&statep->block_client_cv,
1550                                             &statep->state_mutex);
1551                         }
1552 
1553                         if (statep->close_ret_status)
1554                                 *statep->close_ret_status = IBT_CM_CLOSED_ABORT;
1555                         IBCM_REF_CNT_DECR(statep);
1556                         mutex_exit(&statep->state_mutex);
1557 
1558                         return (IBT_SUCCESS);
1559                 } else {
1560                         IBCM_REF_CNT_DECR(statep);
1561                         mutex_exit(&statep->state_mutex);
1562 
1563                         return (IBT_CM_FAILURE);
1564                 }
1565         }
1566 
1567         ASSERT(statep->close_nocb_state != IBCM_BLOCK);
1568 
1569         if (mode == IBT_NOCALLBACKS) {
1570                 statep->close_nocb_state = IBCM_FAIL;
1571                 statep->cm_handler = NULL;
1572                 ibtl_cm_chan_is_closing(statep->channel);
1573                 IBTF_DPRINTF_L4(cmlog, "ibcm_close_rc_channel: "
1574                     "NOCALLBACKS on in statep = %p", statep);
1575         }
1576 
1577         if (statep->state != IBCM_STATE_ESTABLISHED) {
1578                 goto lost_race;
1579         }
1580 
1581         /*
1582          * Cancel/wait for any pending ibt_set_alt_path, and
1583          * release state mutex
1584          */
1585         ibcm_sync_lapr_idle(statep);
1586 
1587         ibcm_close_enter();
1588 
1589         mutex_enter(&statep->state_mutex);
1590         if (statep->state != IBCM_STATE_ESTABLISHED) {
1591                 ibcm_close_exit();
1592                 goto lost_race;
1593         }
1594 
1595         statep->state = IBCM_STATE_TRANSIENT_DREQ_SENT;
1596         statep->timerid = 0;
1597         statep->close_done = B_FALSE;
1598         statep->close_flow = 1;
1599         mutex_exit(&statep->state_mutex);
1600 
1601         ibcm_post_dreq_mad(statep);
1602 
1603         mutex_enter(&statep->state_mutex);
1604 
1605 lost_race:
1606         if (mode == IBT_BLOCKING) {
1607 
1608                 /* wait for DREP */
1609                 while (statep->close_done != B_TRUE)
1610                         cv_wait(&statep->block_client_cv,
1611                             &statep->state_mutex);
1612 
1613                 IBTF_DPRINTF_L4(cmlog, "ibcm_close_rc_channel: chan 0x%p "
1614                     "done blocking", channel);
1615         }
1616 
1617         IBCM_REF_CNT_DECR(statep);
1618         mutex_exit(&statep->state_mutex);
1619 
1620         /* If this message isn't seen then ibt_close_rc_channel failed */
1621         IBTF_DPRINTF_L5(cmlog, "ibcm_close_rc_channel: chan 0x%p done",
1622             channel);
1623 
1624         return (IBT_SUCCESS);
1625 }
1626 
1627 ibt_status_t
1628 ibt_recycle_rc(ibt_channel_hdl_t rc_chan, ibt_cep_flags_t control,
1629     uint8_t hca_port_num, ibt_recycle_handler_t func, void *arg)
1630 {
1631         ibcm_state_data_t               *statep;
1632         ibcm_taskq_recycle_arg_t        *ibcm_tq_recycle_arg;
1633         ibt_qp_query_attr_t             qp_attr;
1634         ibt_status_t                    retval;
1635 
1636         IBTF_DPRINTF_L3(cmlog, "ibt_recycle_rc (%p, 0x%X, %d, %p, %p)", rc_chan,
1637             control, hca_port_num, func, arg);
1638 
1639         if (IBCM_INVALID_CHANNEL(rc_chan)) {
1640                 IBTF_DPRINTF_L2(cmlog, "ibt_recycle_rc: invalid channel");
1641                 return (IBT_CHAN_HDL_INVALID);
1642         }
1643 
1644         /* check qp state */
1645         retval = ibt_query_qp(rc_chan, &qp_attr);
1646 
1647         if (retval != IBT_SUCCESS)
1648                 return (retval);
1649 
1650         if (qp_attr.qp_info.qp_trans != IBT_RC_SRV)
1651                 return (IBT_CHAN_SRV_TYPE_INVALID);
1652 
1653         if (qp_attr.qp_info.qp_state != IBT_STATE_ERROR)
1654                 return (IBT_CHAN_STATE_INVALID);
1655 
1656         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ibcm_tq_recycle_arg))
1657 
1658         ibcm_tq_recycle_arg = kmem_alloc(sizeof (ibcm_taskq_recycle_arg_t),
1659             KM_SLEEP);
1660 
1661         ibcm_tq_recycle_arg->rc_chan         = rc_chan;
1662         ibcm_tq_recycle_arg->control         = control;
1663         ibcm_tq_recycle_arg->hca_port_num    = hca_port_num;
1664         ibcm_tq_recycle_arg->func            = func;
1665         ibcm_tq_recycle_arg->arg             = arg;
1666 
1667         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ibcm_tq_recycle_arg))
1668 
1669         IBCM_GET_CHAN_PRIVATE(rc_chan, statep);
1670 
1671         /*
1672          * If non-blocking ie., func specified and channel has not yet completed
1673          * the timewait, then schedule the work for later
1674          */
1675         if ((func != NULL) && (statep != NULL)) {
1676                 IBCM_RELEASE_CHAN_PRIVATE(rc_chan);
1677                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(statep->recycle_arg))
1678                 statep->recycle_arg = ibcm_tq_recycle_arg;
1679                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(statep->recycle_arg))
1680                 return (IBT_SUCCESS);
1681         }
1682 
1683         /*
1684          * if blocking ie., func specified, and channel has not yet completed
1685          * the timewait, then block until the channel completes the timewait
1686          */
1687         if (statep != NULL)
1688                 IBCM_RELEASE_CHAN_PRIVATE(rc_chan);
1689         IBCM_WAIT_CHAN_PRIVATE(rc_chan);
1690 
1691         if (func) {     /* NON BLOCKING case. Taskq for QP state change */
1692                 (void) taskq_dispatch(ibcm_taskq, ibcm_process_rc_recycle,
1693                     ibcm_tq_recycle_arg, TQ_SLEEP);
1694                 return (IBT_SUCCESS);
1695         } else  /* BLOCKING case */
1696                 return (ibcm_process_rc_recycle_ret(ibcm_tq_recycle_arg));
1697 }
1698 
1699 void
1700 ibcm_process_rc_recycle(void *recycle_arg)
1701 {
1702         (void) ibcm_process_rc_recycle_ret(recycle_arg);
1703 }
1704 
1705 static ibt_status_t
1706 ibcm_process_rc_recycle_ret(void *recycle_arg)
1707 {
1708         ibt_qp_info_t                   qp_info;
1709         ibt_status_t                    ibt_status = IBT_SUCCESS;
1710         ibt_cep_modify_flags_t          cep_flags;
1711         ibt_qp_query_attr_t             qp_attr;
1712         ibcm_taskq_recycle_arg_t        *ibcm_tq_recycle_arg =
1713             (ibcm_taskq_recycle_arg_t *)recycle_arg;
1714 
1715         /* QP must have been in error state */
1716         ibt_status = ibt_query_qp(ibcm_tq_recycle_arg->rc_chan, &qp_attr);
1717         if (ibt_status != IBT_SUCCESS)
1718                 IBTF_DPRINTF_L2(cmlog, "ibcm_process_rc_recycle_ret: "
1719                     "chanp %p ibt_query_qp() = %d",
1720                     ibcm_tq_recycle_arg->rc_chan, ibt_status);
1721         else {
1722                 /* perform the QP state change from ERROR to RESET */
1723                 bzero(&qp_info, sizeof (qp_info));
1724 
1725                 qp_info.qp_trans = IBT_RC_SRV;
1726                 qp_info.qp_state = IBT_STATE_RESET;
1727 
1728                 /* Call modify_qp to move to RESET state */
1729                 ibt_status = ibt_modify_qp(ibcm_tq_recycle_arg->rc_chan,
1730                     IBT_CEP_SET_STATE, &qp_info, NULL);
1731 
1732                 if (ibt_status != IBT_SUCCESS)
1733                         IBTF_DPRINTF_L2(cmlog, "ibcm_process_rc_recycle_ret: "
1734                             "chanp %p ibt_modify_qp() = %d for ERROR to RESET",
1735                             ibcm_tq_recycle_arg->rc_chan, ibt_status);
1736         }
1737 
1738         if (ibt_status == IBT_SUCCESS) {
1739 
1740                 qp_info.qp_state = IBT_STATE_INIT;
1741 
1742                 /* set flags for all mandatory args from RESET to INIT */
1743                 cep_flags = IBT_CEP_SET_STATE | IBT_CEP_SET_PORT;
1744                 cep_flags |= IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W;
1745                 cep_flags |= IBT_CEP_SET_ATOMIC;
1746 
1747                 qp_info.qp_transport.rc.rc_path.cep_hca_port_num =
1748                     ibcm_tq_recycle_arg->hca_port_num;
1749                 qp_info.qp_flags |=
1750                     ibcm_tq_recycle_arg->control & IBT_CEP_RDMA_RD;
1751                 qp_info.qp_flags |=
1752                     ibcm_tq_recycle_arg->control & IBT_CEP_RDMA_WR;
1753                 qp_info.qp_flags |=
1754                     ibcm_tq_recycle_arg->control & IBT_CEP_ATOMIC;
1755 
1756                 /* Always use the existing pkey */
1757                 qp_info.qp_transport.rc.rc_path.cep_pkey_ix =
1758                     qp_attr. qp_info.qp_transport.rc.rc_path.cep_pkey_ix;
1759 
1760                 /* Call modify_qp to move to INIT state */
1761                 ibt_status = ibt_modify_qp(ibcm_tq_recycle_arg->rc_chan,
1762                     cep_flags, &qp_info, NULL);
1763 
1764                 if (ibt_status != IBT_SUCCESS)
1765                         IBTF_DPRINTF_L2(cmlog, "ibcm_process_rc_recycle_ret: "
1766                             "chanp %p ibt_modify_qp() = %d for RESET to INIT",
1767                             ibcm_tq_recycle_arg->rc_chan, ibt_status);
1768         }
1769 
1770         /* Change the QP CM state to indicate QP being re-used */
1771         if (ibt_status == IBT_SUCCESS)
1772                 ibtl_cm_chan_is_reused(ibcm_tq_recycle_arg->rc_chan);
1773 
1774         /* Call func, if defined */
1775         if (ibcm_tq_recycle_arg->func)
1776                 (*(ibcm_tq_recycle_arg->func))(ibt_status,
1777                     ibcm_tq_recycle_arg->arg);
1778 
1779         kmem_free(ibcm_tq_recycle_arg, sizeof (ibcm_taskq_recycle_arg_t));
1780 
1781         return (ibt_status);
1782 }
1783 
1784 static void
1785 ibcm_process_abort_via_taskq(void *args)
1786 {
1787         ibcm_state_data_t       *statep = (ibcm_state_data_t *)args;
1788 
1789         ibcm_process_abort(statep);
1790         mutex_enter(&statep->state_mutex);
1791         IBCM_REF_CNT_DECR(statep);
1792         mutex_exit(&statep->state_mutex);
1793 }
1794 
1795 /*
1796  * Local UD CM Handler's private data, used during ibt_request_ud_dest() in
1797  * Non-Blocking mode operations.
1798  */
1799 typedef struct ibcm_local_handler_s {
1800         ibt_cm_ud_handler_t     actual_cm_handler;
1801         void                    *actual_cm_private;
1802         ibt_ud_dest_t           *dest_hdl;
1803 } ibcm_local_handler_t;
1804 
1805 _NOTE(READ_ONLY_DATA(ibcm_local_handler_s))
1806 
1807 /*
1808  * Local UD CM Handler, used when ibt_alloc_ud_dest() is issued in
1809  * NON-Blocking mode.
1810  *
1811  * Out here, we update the UD Destination handle with
1812  * the obtained DQPN and QKey (from SIDR REP) and invokes actual client
1813  * handler that was specified by the client.
1814  */
1815 static ibt_cm_status_t
1816 ibcm_local_cm_handler(void *priv, ibt_cm_ud_event_t *event,
1817     ibt_cm_ud_return_args_t *ret_args, void *priv_data, ibt_priv_data_len_t len)
1818 {
1819         ibcm_local_handler_t    *handler_priv = (ibcm_local_handler_t *)priv;
1820 
1821         IBTF_DPRINTF_L4(cmlog, "ibcm_local_cm_handler: event %d",
1822             event->cm_type);
1823 
1824         ASSERT(handler_priv != NULL);
1825 
1826         switch (event->cm_type) {
1827         case IBT_CM_UD_EVENT_SIDR_REP:
1828                 /* Update QPN & QKey from event into destination handle. */
1829                 if (handler_priv->dest_hdl != NULL) {
1830                         handler_priv->dest_hdl->ud_dst_qpn =
1831                             event->cm_event.sidr_rep.srep_remote_qpn;
1832                         handler_priv->dest_hdl->ud_qkey =
1833                             event->cm_event.sidr_rep.srep_remote_qkey;
1834                 }
1835 
1836                 /* Invoke the client handler - inform only, so ignore retval */
1837                 (void) handler_priv->actual_cm_handler(
1838                     handler_priv->actual_cm_private, event, ret_args, priv_data,
1839                     len);
1840 
1841                 /* Free memory allocated for local handler's private data. */
1842                 if (handler_priv != NULL)
1843                         kmem_free(handler_priv, sizeof (*handler_priv));
1844 
1845                 break;
1846         default:
1847                 IBTF_DPRINTF_L2(cmlog, "ibcm_local_cm_handler: ERROR");
1848                 break;
1849         }
1850 
1851         return (IBT_CM_ACCEPT);
1852 }
1853 
1854 
1855 /* Validate the input UD destination attributes.  */
1856 static ibt_status_t
1857 ibcm_validate_dqpn_data(ibt_ud_dest_attr_t *attr, ibt_execution_mode_t mode,
1858     ibt_ud_returns_t *ret_args)
1859 {
1860         /* cm handler must always be specified */
1861         if (mode == IBT_NONBLOCKING && attr->ud_cm_handler == NULL) {
1862                 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_dqpn_data: "
1863                     "CM handler is not specified ");
1864                 return (IBT_INVALID_PARAM);
1865         }
1866 
1867         if (mode == IBT_NONBLOCKING) {
1868                 if (ret_args != NULL) {
1869                         IBTF_DPRINTF_L2(cmlog, "ibcm_validate_dqpn_data: "
1870                             "ret_args should be NULL when called in "
1871                             "non-blocking mode");
1872                         return (IBT_INVALID_PARAM);
1873                 }
1874         } else if (mode == IBT_BLOCKING) {
1875                 if (ret_args == NULL) {
1876                         IBTF_DPRINTF_L2(cmlog, "ibcm_validate_dqpn_data: "
1877                             "ret_args should be Non-NULL when called in "
1878                             "blocking mode");
1879                         return (IBT_INVALID_PARAM);
1880                 }
1881         } else {
1882                 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_dqpn_data: "
1883                     "invalid mode %x specified ", mode);
1884                 return (IBT_INVALID_PARAM);
1885         }
1886 
1887         if (attr->ud_sid == 0) {
1888                 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_dqpn_data: "
1889                     "ServiceID must be specified. ");
1890                 return (IBT_INVALID_PARAM);
1891         }
1892 
1893         if (attr->ud_addr == NULL) {
1894                 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_dqpn_data: "
1895                     "Address Info NULL");
1896                 return (IBT_INVALID_PARAM);
1897         }
1898 
1899         /* Validate SGID */
1900         if ((attr->ud_addr->av_sgid.gid_prefix == 0) ||
1901             (attr->ud_addr->av_sgid.gid_guid == 0)) {
1902                 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_dqpn_data: Invalid SGID");
1903                 return (IBT_INVALID_PARAM);
1904         }
1905         IBTF_DPRINTF_L3(cmlog, "ibcm_validate_dqpn_data: SGID<%llX:%llX>",
1906             attr->ud_addr->av_sgid.gid_prefix,
1907             attr->ud_addr->av_sgid.gid_guid);
1908 
1909         /* Validate DGID */
1910         if ((attr->ud_addr->av_dgid.gid_prefix == 0) ||
1911             (attr->ud_addr->av_dgid.gid_guid == 0)) {
1912                 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_dqpn_data: Invalid DGID");
1913                 return (IBT_INVALID_PARAM);
1914         }
1915         IBTF_DPRINTF_L3(cmlog, "ibcm_validate_dqpn_data: DGID<%llX:%llX>",
1916             attr->ud_addr->av_dgid.gid_prefix,
1917             attr->ud_addr->av_dgid.gid_guid);
1918 
1919         return (IBT_SUCCESS);
1920 }
1921 
1922 
1923 /* Perform SIDR to retrieve DQPN and QKey.  */
1924 static ibt_status_t
1925 ibcm_ud_get_dqpn(ibt_ud_dest_attr_t *attr, ibt_execution_mode_t mode,
1926     ibt_ud_returns_t *ret_args)
1927 {
1928         ibt_status_t            retval;
1929         ib_pkey_t               ud_pkey;
1930         ibmf_handle_t           ibmf_hdl;
1931         ibmf_msg_t              *ibmf_msg;
1932         ibcm_hca_info_t         *hcap;
1933         ibcm_sidr_req_msg_t     *sidr_req_msgp;
1934         ibcm_ud_state_data_t    *ud_statep;
1935         ibtl_cm_hca_port_t      port;
1936         ibcm_sidr_srch_t        sidr_entry;
1937         ibcm_qp_list_t          *cm_qp_entry;
1938 
1939         /* Retrieve HCA GUID value from the available SGID info. */
1940         retval = ibtl_cm_get_hca_port(attr->ud_addr->av_sgid, 0, &port);
1941         if ((retval != IBT_SUCCESS) || (port.hp_port == 0)) {
1942                 IBTF_DPRINTF_L2(cmlog, "ibcm_ud_get_dqpn: "
1943                     "ibtl_cm_get_hca_port failed: %d", retval);
1944                 return (retval);
1945         }
1946 
1947         IBTF_DPRINTF_L4(cmlog, "ibcm_ud_get_dqpn: "
1948             "HCA GUID:%llX, port_num:%d", port.hp_hca_guid, port.hp_port);
1949 
1950         /* Lookup the HCA info for this GUID */
1951         if ((hcap = ibcm_find_hca_entry(port.hp_hca_guid)) == NULL) {
1952                 IBTF_DPRINTF_L2(cmlog, "ibcm_ud_get_dqpn: hcap is NULL");
1953                 return (IBT_HCA_INVALID);
1954         }
1955 
1956         /* Return failure if the HCA device or Port is not operational */
1957 
1958         if ((retval = ibt_get_port_state_byguid(port.hp_hca_guid, port.hp_port,
1959             NULL, NULL)) != IBT_SUCCESS) {
1960                 /* Device Port is not in good state, don't use it. */
1961                 IBTF_DPRINTF_L2(cmlog, "ibcm_ud_get_dqpn: Invalid "
1962                     "port specified or port not active");
1963                 ibcm_dec_hca_acc_cnt(hcap);
1964                 return (retval);
1965         }
1966 
1967         retval = ibt_index2pkey_byguid(port.hp_hca_guid, port.hp_port,
1968             attr->ud_pkey_ix, &ud_pkey);
1969         if (retval != IBT_SUCCESS) {
1970                 IBTF_DPRINTF_L2(cmlog, "ibcm_ud_get_dqpn: "
1971                     "Failed to convert index2pkey: %d", retval);
1972                 ibcm_dec_hca_acc_cnt(hcap);
1973                 return (retval);
1974         }
1975 
1976         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(sidr_entry))
1977 
1978         /* Allocate a new request id */
1979         if (ibcm_alloc_reqid(hcap, &sidr_entry.srch_req_id) == IBCM_FAILURE) {
1980                 IBTF_DPRINTF_L2(cmlog, "ibcm_ud_get_dqpn: "
1981                     "no req id available");
1982                 ibcm_dec_hca_acc_cnt(hcap);
1983                 return (IBT_INSUFF_KERNEL_RESOURCE);
1984         }
1985 
1986         if ((hcap->hca_port_info[port.hp_port - 1].port_ibmf_hdl == NULL) &&
1987             ((retval = ibcm_hca_reinit_port(hcap, port.hp_port - 1))
1988             != IBT_SUCCESS)) {
1989                 IBTF_DPRINTF_L2(cmlog, "ibcm_ud_get_dqpn: "
1990                     "ibmf reg or callback setup failed during re-initialize");
1991                 return (retval);
1992         }
1993 
1994         ibmf_hdl = hcap->hca_port_info[port.hp_port - 1].port_ibmf_hdl;
1995 
1996         /* find the ibmf QP to post the SIDR REQ */
1997         if ((cm_qp_entry = ibcm_find_qp(hcap, port.hp_port, ud_pkey)) ==
1998             NULL) {
1999                 IBTF_DPRINTF_L2(cmlog, "ibcm_ud_get_dqpn: IBMF QP allocation"
2000                     " failed");
2001                 ibcm_dec_hca_acc_cnt(hcap);
2002                 return (IBT_INSUFF_RESOURCE);
2003         }
2004 
2005         if ((retval = ibcm_alloc_out_msg(ibmf_hdl, &ibmf_msg, MAD_METHOD_SEND))
2006             != IBT_SUCCESS) {
2007                 IBTF_DPRINTF_L2(cmlog, "ibcm_ud_get_dqpn: IBMF MSG allocation"
2008                     " failed");
2009                 ibcm_release_qp(cm_qp_entry);
2010                 ibcm_dec_hca_acc_cnt(hcap);
2011                 return (retval);
2012         }
2013 
2014         sidr_entry.srch_lid = port.hp_base_lid;
2015         sidr_entry.srch_gid = attr->ud_addr->av_sgid;
2016         sidr_entry.srch_grh_exists = attr->ud_addr->av_send_grh;
2017         sidr_entry.srch_mode = IBCM_ACTIVE_MODE;
2018 
2019         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(sidr_entry))
2020 
2021         /* do various allocations needed here */
2022         rw_enter(&hcap->hca_sidr_list_lock, RW_WRITER);
2023 
2024         (void) ibcm_find_sidr_entry(&sidr_entry, hcap, &ud_statep,
2025             IBCM_FLAG_ADD);
2026         rw_exit(&hcap->hca_sidr_list_lock);
2027 
2028         /* Increment hca's resource count */
2029         ibcm_inc_hca_res_cnt(hcap);
2030 
2031         /* After a resource created on hca, no need to hold the acc cnt */
2032         ibcm_dec_hca_acc_cnt(hcap);
2033 
2034         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ud_statep))
2035 
2036         /* Initialize some ud_statep fields */
2037         ud_statep->ud_stored_msg = ibmf_msg;
2038         ud_statep->ud_svc_id = attr->ud_sid;
2039         ud_statep->ud_pkt_life_time =
2040             ibt_ib2usec(attr->ud_pkt_lt);
2041         ud_statep->ud_stored_reply_addr.cm_qp_entry = cm_qp_entry;
2042 
2043         /* set remaining retry cnt */
2044         ud_statep->ud_remaining_retry_cnt = ud_statep->ud_max_cm_retries;
2045 
2046         /*
2047          * Get UD handler and corresponding args which is pass it back
2048          * as first argument for the handler.
2049          */
2050         ud_statep->ud_state_cm_private = attr->ud_cm_private;
2051 
2052         if (mode == IBT_BLOCKING)
2053                 ud_statep->ud_return_data = ret_args;
2054         else
2055                 ud_statep->ud_cm_handler = attr->ud_cm_handler;
2056 
2057         /* Initialize the fields of ud_statep->ud_stored_reply_addr */
2058         ud_statep->ud_stored_reply_addr.grh_exists = attr->ud_addr->av_send_grh;
2059         ud_statep->ud_stored_reply_addr.ibmf_hdl = ibmf_hdl;
2060         ud_statep->ud_stored_reply_addr.grh_hdr.ig_hop_limit =
2061             attr->ud_addr->av_hop;
2062         ud_statep->ud_stored_reply_addr.grh_hdr.ig_sender_gid =
2063             attr->ud_addr->av_sgid;
2064         ud_statep->ud_stored_reply_addr.grh_hdr.ig_recver_gid =
2065             attr->ud_addr->av_dgid;
2066         ud_statep->ud_stored_reply_addr.grh_hdr.ig_tclass =
2067             attr->ud_addr->av_tclass;
2068         ud_statep->ud_stored_reply_addr.grh_hdr.ig_flow_label =
2069             attr->ud_addr->av_flow & IB_GRH_FLOW_LABEL_MASK;
2070 
2071         /* needs to be derived based on the base LID and path bits */
2072         ud_statep->ud_stored_reply_addr.rcvd_addr.ia_local_lid =
2073             port.hp_base_lid;
2074         ud_statep->ud_stored_reply_addr.rcvd_addr.ia_remote_lid =
2075             attr->ud_addr->av_dlid;
2076         ud_statep->ud_stored_reply_addr.rcvd_addr.ia_p_key = ud_pkey;
2077         ud_statep->ud_stored_reply_addr.rcvd_addr.ia_q_key = IB_GSI_QKEY;
2078         ud_statep->ud_stored_reply_addr.rcvd_addr.ia_service_level =
2079             attr->ud_addr->av_srvl;
2080 
2081         /*
2082          * This may be enchanced later, to use a remote qno based on past
2083          * redirect rej mad responses. This would be the place to specify
2084          * appropriate remote qno
2085          */
2086         ud_statep->ud_stored_reply_addr.rcvd_addr.ia_remote_qno = 1;
2087 
2088         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sidr_req_msgp))
2089 
2090         /* Initialize the SIDR REQ message fields */
2091         sidr_req_msgp =
2092             (ibcm_sidr_req_msg_t *)IBCM_OUT_MSGP(ud_statep->ud_stored_msg);
2093 
2094         sidr_req_msgp->sidr_req_request_id = h2b32(ud_statep->ud_req_id);
2095         sidr_req_msgp->sidr_req_service_id = h2b64(attr->ud_sid);
2096         sidr_req_msgp->sidr_req_pkey = h2b16(ud_pkey);
2097         IBCM_OUT_HDRP(ud_statep->ud_stored_msg)->AttributeID =
2098             h2b16(IBCM_INCOMING_SIDR_REQ + IBCM_ATTR_BASE_ID);
2099 
2100         if ((attr->ud_priv_data != NULL) && (attr->ud_priv_data_len > 0)) {
2101                 bcopy(attr->ud_priv_data, sidr_req_msgp->sidr_req_private_data,
2102                     min(attr->ud_priv_data_len, IBT_SIDR_REQ_PRIV_DATA_SZ));
2103         }
2104 
2105         /* Send out the SIDR REQ message */
2106         ud_statep->ud_state = IBCM_STATE_SIDR_REQ_SENT;
2107         ud_statep->ud_timer_stored_state = IBCM_STATE_SIDR_REQ_SENT;
2108         IBCM_UD_REF_CNT_INCR(ud_statep); /* for non-blocking SIDR REQ post */
2109         ud_statep->ud_timer_value = ibt_ib2usec(ibcm_max_sidr_rep_proctime) +
2110             (ud_statep->ud_pkt_life_time * 2);
2111 
2112         IBCM_OUT_HDRP(ud_statep->ud_stored_msg)->TransactionID =
2113             h2b64(ibcm_generate_tranid(IBCM_INCOMING_SIDR_REQ,
2114             ud_statep->ud_req_id, 0));
2115 
2116         IBTF_DPRINTF_L4(cmlog, "ibcm_ud_get_dqpn: timer_value in HZ = %x",
2117             ud_statep->ud_timer_value);
2118 
2119         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ud_statep))
2120         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sidr_req_msgp))
2121 
2122         ibcm_post_ud_mad(ud_statep, ud_statep->ud_stored_msg,
2123             ibcm_post_sidr_req_complete, ud_statep);
2124 
2125         mutex_enter(&ud_statep->ud_state_mutex);
2126 
2127         /* Wait for SIDR_REP */
2128         if (mode == IBT_BLOCKING) {
2129                 IBTF_DPRINTF_L4(cmlog, "ibcm_ud_get_dqpn: blocking");
2130 
2131                 while (ud_statep->ud_blocking_done != B_TRUE) {
2132                         cv_wait(&ud_statep->ud_block_client_cv,
2133                             &ud_statep->ud_state_mutex);
2134                 }
2135 
2136                 IBTF_DPRINTF_L4(cmlog, "ibcm_ud_get_dqpn: finished blocking");
2137 
2138                 if (ret_args->ud_status == IBT_CM_SREP_QPN_VALID) {
2139                         IBTF_DPRINTF_L4(cmlog, "ibcm_ud_get_dqpn: DQPN = %x, "
2140                             "status = %x, QKey = %x", ret_args->ud_dqpn,
2141                             ret_args->ud_status, ret_args->ud_qkey);
2142 
2143                 } else {
2144                         IBTF_DPRINTF_L4(cmlog, "ibcm_ud_get_dqpn: Status<%x>",
2145                             ret_args->ud_status);
2146                         retval = IBT_CM_FAILURE;
2147                 }
2148         }
2149 
2150         IBCM_UD_REF_CNT_DECR(ud_statep);
2151         mutex_exit(&ud_statep->ud_state_mutex);
2152 
2153         IBTF_DPRINTF_L4(cmlog, "ibcm_ud_get_dqpn: done");
2154 
2155         return (retval);
2156 }
2157 
2158 
2159 /*
2160  * Function:
2161  *      ibt_request_ud_dest
2162  * Input:
2163  *      ud_dest         A previously allocated UD destination handle.
2164  *      mode            This function can execute in blocking or non blocking
2165  *                      modes.
2166  *      attr            UD destination attributes to be modified.
2167  * Output:
2168  *      ud_ret_args     If the function is called in blocking mode, ud_ret_args
2169  *                      should be a pointer to an ibt_ud_returns_t struct.
2170  * Returns:
2171  *      IBT_SUCCESS
2172  * Description:
2173  *      Modify a previously allocated UD destination handle based on the
2174  *      results of doing the SIDR protocol.
2175  */
2176 ibt_status_t
2177 ibt_request_ud_dest(ibt_ud_dest_hdl_t ud_dest, ibt_execution_mode_t mode,
2178     ibt_ud_dest_attr_t *attr, ibt_ud_returns_t *ud_ret_args)
2179 {
2180         ibt_status_t            retval;
2181         ibt_ud_dest_t           *ud_destp;
2182         ibcm_local_handler_t    *local_handler_priv = NULL;
2183 
2184         IBTF_DPRINTF_L3(cmlog, "ibt_request_ud_dest(%p, %x, %p, %p)",
2185             ud_dest, mode, attr, ud_ret_args);
2186 
2187         retval = ibcm_validate_dqpn_data(attr, mode, ud_ret_args);
2188         if (retval != IBT_SUCCESS) {
2189                 return (retval);
2190         }
2191 
2192         ud_destp = ud_dest;
2193 
2194         /* Allocate an Address handle. */
2195         retval = ibt_modify_ah(ud_destp->ud_dest_hca, ud_destp->ud_ah,
2196             attr->ud_addr);
2197         if (retval != IBT_SUCCESS) {
2198                 IBTF_DPRINTF_L2(cmlog, "ibt_request_ud_dest: "
2199                     "Address Handle Modification failed: %d", retval);
2200                 return (retval);
2201         }
2202 
2203         if (mode == IBT_NONBLOCKING) {
2204                 /*
2205                  * In NON-BLOCKING mode, and we need to update the destination
2206                  * handle with the DQPN and QKey that are obtained from
2207                  * SIDR REP, hook-up our own handler, so that we can catch
2208                  * the event, and we ourselves call the actual client's
2209                  * ud_cm_handler, in our handler.
2210                  */
2211 
2212                 /* Allocate memory for local handler's private data. */
2213                 local_handler_priv =
2214                     kmem_alloc(sizeof (*local_handler_priv), KM_SLEEP);
2215 
2216                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*local_handler_priv))
2217 
2218                 local_handler_priv->actual_cm_handler = attr->ud_cm_handler;
2219                 local_handler_priv->actual_cm_private = attr->ud_cm_private;
2220                 local_handler_priv->dest_hdl = ud_destp;
2221 
2222                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*local_handler_priv))
2223 
2224                 attr->ud_cm_handler = ibcm_local_cm_handler;
2225                 attr->ud_cm_private = local_handler_priv;
2226         }
2227 
2228         /* In order to get DQPN and Destination QKey, perform SIDR */
2229         retval = ibcm_ud_get_dqpn(attr, mode, ud_ret_args);
2230         if (retval != IBT_SUCCESS) {
2231                 IBTF_DPRINTF_L2(cmlog, "ibt_request_ud_dest: "
2232                     "Failed to get DQPN: %d", retval);
2233 
2234                 /* Free memory allocated for local handler's private data. */
2235                 if (local_handler_priv != NULL)
2236                         kmem_free(local_handler_priv,
2237                             sizeof (*local_handler_priv));
2238                 return (retval);
2239         }
2240 
2241         /*
2242          * Fill in the dqpn and dqkey as obtained from ud_ret_args,
2243          * values will be valid only on BLOCKING mode.
2244          */
2245         if (mode == IBT_BLOCKING) {
2246                 ud_destp->ud_dst_qpn = ud_ret_args->ud_dqpn;
2247                 ud_destp->ud_qkey = ud_ret_args->ud_qkey;
2248         }
2249 
2250         return (retval);
2251 }
2252 
2253 /*
2254  * Function:
2255  *      ibt_ud_get_dqpn
2256  * Input:
2257  *      attr            A pointer to an ibt_ud_dest_attr_t struct that are
2258  *                      required for SIDR REQ message. Not specified attributes
2259  *                      should be set to "NULL" or "0".
2260  *                      ud_sid, ud_addr and ud_pkt_lt must be specified.
2261  *      mode            This function can execute in blocking or non blocking
2262  *                      modes.
2263  * Output:
2264  *      returns         If the function is called in blocking mode, returns
2265  *                      should be a pointer to an ibt_ud_returns_t struct.
2266  * Return:
2267  *      IBT_SUCCESS     on success or respective failure on error.
2268  * Description:
2269  *      Finds the destination QPN at the specified destination that the
2270  *      specified service can be reached on. The IBTF CM initiates the
2271  *      service ID resolution protocol (SIDR) to determine a destination QPN.
2272  *
2273  * NOTE: SIDR_REQ is initiated from active side.
2274  */
2275 ibt_status_t
2276 ibt_ud_get_dqpn(ibt_ud_dest_attr_t *attr, ibt_execution_mode_t mode,
2277     ibt_ud_returns_t *returns)
2278 {
2279         ibt_status_t            retval;
2280 
2281         IBTF_DPRINTF_L3(cmlog, "ibt_ud_get_dqpn(%p, %x, %p)",
2282             attr, mode, returns);
2283 
2284         retval = ibcm_validate_dqpn_data(attr, mode, returns);
2285         if (retval != IBT_SUCCESS) {
2286                 return (retval);
2287         }
2288 
2289         return (ibcm_ud_get_dqpn(attr, mode, returns));
2290 }
2291 
2292 
2293 /*
2294  * ibt_cm_delay:
2295  *      A client CM handler function can call this function
2296  *      to extend its response time to a CM event.
2297  * INPUTS:
2298  *      flags           Indicates what CM message processing is being delayed
2299  *                      by the CM handler, valid values are:
2300  *                              IBT_CM_DELAY_REQ
2301  *                              IBT_CM_DELAY_REP
2302  *                              IBT_CM_DELAY_LAP
2303  *      cm_session_id   The session ID that was passed to client srv_handler
2304  *                      by the CM
2305  *      service_time    The extended service time
2306  *      priv_data       Vendor specific data to be sent in the CM generated
2307  *                      MRA message. Should be NULL if not specified.
2308  *      len             The number of bytes of data specified by priv_data.
2309  *
2310  * RETURN VALUES:
2311  *      IBT_SUCCESS     on success (or respective failure on error)
2312  */
2313 ibt_status_t
2314 ibt_cm_delay(ibt_cmdelay_flags_t flags, void *cm_session_id,
2315     clock_t service_time, void *priv_data, ibt_priv_data_len_t len)
2316 {
2317         uint8_t                 msg_typ = 0;
2318         ibcm_mra_msg_t          *mra_msgp;
2319         ibcm_state_data_t       *statep;
2320         ibt_status_t            status;
2321 
2322         IBTF_DPRINTF_L3(cmlog, "ibt_cm_delay(0x%x, %p, 0x%x)",
2323             flags, cm_session_id, service_time);
2324 
2325         /*
2326          * Make sure channel is associated with a statep
2327          */
2328         statep = (ibcm_state_data_t *)cm_session_id;
2329 
2330         if (statep == NULL) {
2331                 IBTF_DPRINTF_L2(cmlog, "ibt_cm_delay: statep NULL");
2332                 return (IBT_INVALID_PARAM);
2333         }
2334 
2335         IBTF_DPRINTF_L4(cmlog, "ibt_cm_delay: statep %p", statep);
2336 
2337         /* Allocate an ibmf msg for mra, if not allocated yet */
2338         if (statep->mra_msg == NULL) {
2339                 if ((status = ibcm_alloc_out_msg(
2340                     statep->stored_reply_addr.ibmf_hdl, &statep->mra_msg,
2341                     MAD_METHOD_SEND)) != IBT_SUCCESS) {
2342                         IBTF_DPRINTF_L2(cmlog, "ibt_cm_delay: chan 0x%p"
2343                             "IBMF MSG allocation failed", statep->channel);
2344                         return (status);
2345                 }
2346         }
2347 
2348         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mra_msgp))
2349 
2350         mra_msgp = (ibcm_mra_msg_t *)IBCM_OUT_MSGP(statep->mra_msg);
2351         mra_msgp->mra_local_comm_id = h2b32(statep->local_comid);
2352         mra_msgp->mra_remote_comm_id = h2b32(statep->remote_comid);
2353 
2354         /* fill in rest of MRA's fields - Message MRAed and Service Timeout */
2355         if (flags == IBT_CM_DELAY_REQ) {
2356                 msg_typ = IBT_CM_MRA_TYPE_REQ;
2357         } else if (flags == IBT_CM_DELAY_REP) {
2358                 msg_typ = IBT_CM_MRA_TYPE_REP;
2359         } else if (flags == IBT_CM_DELAY_LAP) {
2360                 msg_typ = IBT_CM_MRA_TYPE_LAP;
2361         }
2362 
2363         mra_msgp->mra_message_type_plus = msg_typ << 6;
2364         mra_msgp->mra_service_timeout_plus = ibt_usec2ib(service_time) << 3;
2365 
2366         len = min(len, IBT_MRA_PRIV_DATA_SZ);
2367         if (priv_data && (len > 0))
2368                 bcopy(priv_data, mra_msgp->mra_private_data, len);
2369 
2370         IBCM_OUT_HDRP(statep->mra_msg)->AttributeID =
2371             h2b16(IBCM_INCOMING_MRA + IBCM_ATTR_BASE_ID);
2372 
2373         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mra_msgp))
2374 
2375         mutex_enter(&statep->state_mutex);
2376 
2377         if ((statep->mode == IBCM_ACTIVE_MODE) &&
2378             (statep->state == IBCM_STATE_REP_RCVD)) {
2379                 statep->state = IBCM_STATE_MRA_REP_SENT;
2380         } else if (statep->mode == IBCM_PASSIVE_MODE) {
2381                 if (statep->state == IBCM_STATE_REQ_RCVD) {
2382                         statep->state = IBCM_STATE_MRA_SENT;
2383                 } else if (statep->ap_state == IBCM_AP_STATE_LAP_RCVD) {
2384                         statep->ap_state = IBCM_AP_STATE_MRA_LAP_RCVD;
2385                 } else {
2386                         IBTF_DPRINTF_L2(cmlog, "ibt_cm_delay: invalid state "
2387                             "/ap_state/mode %x, %x, %x", statep->state,
2388                             statep->ap_state, statep->mode);
2389                         mutex_exit(&statep->state_mutex);
2390                         return (IBT_CHAN_STATE_INVALID);
2391                 }
2392         } else {
2393                 IBTF_DPRINTF_L2(cmlog, "ibt_cm_delay: invalid state "
2394                     "/ap_state/mode %x, %x, %x", statep->state,
2395                     statep->ap_state, statep->mode);
2396                 mutex_exit(&statep->state_mutex);
2397 
2398                 return (IBT_CHAN_STATE_INVALID);
2399         }
2400         /* service time is usecs, stale_clock is nsecs */
2401         statep->stale_clock = gethrtime() +
2402             (hrtime_t)ibt_ib2usec(ibt_usec2ib(service_time)) * (1000 *
2403             statep->max_cm_retries);
2404 
2405         statep->send_mad_flags |= IBCM_MRA_POST_BUSY;
2406         IBCM_REF_CNT_INCR(statep);      /* for ibcm_post_mra_complete */
2407         mutex_exit(&statep->state_mutex);
2408 
2409         IBCM_OUT_HDRP(statep->mra_msg)->TransactionID =
2410             IBCM_OUT_HDRP(statep->stored_msg)->TransactionID;
2411 
2412         /* post the MRA mad in blocking mode, as no timers involved */
2413         ibcm_post_rc_mad(statep, statep->mra_msg, ibcm_post_mra_complete,
2414             statep);
2415         ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_MRA);
2416         /* If this message isn't seen then ibt_cm_delay failed */
2417         IBTF_DPRINTF_L3(cmlog, "ibt_cm_delay: done !!");
2418 
2419         return (IBT_SUCCESS);
2420 }
2421 
2422 
2423 /*
2424  * ibt_register_service()
2425  *      Register a service with the IBCM
2426  *
2427  * INPUTS:
2428  *      ibt_hdl         The IBT client handle returned to the client
2429  *                      on an ibt_attach() call.
2430  *
2431  *      srv             The address of a ibt_srv_desc_t that describes
2432  *                      the service, containing the following:
2433  *
2434  *              sd_ud_handler   The Service CM UD event Handler.
2435  *              sd_handler      The Service CM RC/UC/RD event Handler.
2436  *              sd_flags        Service flags (peer-to-peer, or not).
2437  *
2438  *      sid             This tells CM if the service is local (sid is 0) or
2439  *                      wellknown (sid is the starting service id of the range).
2440  *
2441  *      num_sids        The number of contiguous service-ids to reserve.
2442  *
2443  *      srv_hdl         The address of a service identification handle, used
2444  *                      to deregister a service, and to bind GIDs to.
2445  *
2446  *      ret_sid         The address to store the Service ID return value.
2447  *                      If num_sids > 1, ret_sid is the first Service ID
2448  *                      in the range.
2449  *
2450  * ibt_register_service() returns:
2451  *      IBT_SUCCESS             - added a service successfully.
2452  *      IBT_INVALID_PARAM       - invalid input parameter.
2453  *      IBT_CM_FAILURE          - failed to add the service.
2454  *      IBT_CM_SERVICE_EXISTS   - service already exists.
2455  *      IBT_INSUFF_KERNEL_RESOURCE - ran out of local service ids (should
2456  *                                   never happen).
2457  */
2458 ibt_status_t
2459 ibt_register_service(ibt_clnt_hdl_t ibt_hdl, ibt_srv_desc_t *srv,
2460     ib_svc_id_t sid, int num_sids, ibt_srv_hdl_t *srv_hdl, ib_svc_id_t *ret_sid)
2461 {
2462         ibcm_svc_info_t         *svcinfop;
2463 
2464         IBTF_DPRINTF_L2(cmlog, "ibt_register_service(%p (%s), %p, 0x%llX, %d)",
2465             ibt_hdl, ibtl_cm_get_clnt_name(ibt_hdl), srv, (longlong_t)sid,
2466             num_sids);
2467 
2468         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*svcinfop))
2469 
2470         *srv_hdl = NULL;
2471 
2472         if (num_sids <= 0) {
2473                 IBTF_DPRINTF_L2(cmlog, "ibt_register_service: "
2474                     "Invalid number of service-ids specified (%d)", num_sids);
2475                 return (IBT_INVALID_PARAM);
2476         }
2477 
2478         if (sid == 0) {
2479                 if (ret_sid == NULL)
2480                         return (IBT_INVALID_PARAM);
2481                 sid = ibcm_alloc_local_sids(num_sids);
2482                 if (sid == 0)
2483                         return (IBT_INSUFF_KERNEL_RESOURCE);
2484 
2485         /* Make sure that the ServiceId specified is not of LOCAL AGN type. */
2486         } else if ((sid & IB_SID_AGN_MASK) == IB_SID_AGN_LOCAL) {
2487                 IBTF_DPRINTF_L2(cmlog, "ibt_register_service: "
2488                     "Invalid non-LOCAL SID specified: 0x%llX",
2489                     (longlong_t)sid);
2490                 return (IBT_INVALID_PARAM);
2491         }
2492 
2493         svcinfop = ibcm_create_svc_entry(sid, num_sids);
2494 
2495         if (svcinfop == NULL) {
2496                 IBTF_DPRINTF_L2(cmlog, "ibt_register_service: "
2497                     "Service-ID 0x%llx already registered", (longlong_t)sid);
2498                 return (IBT_CM_SERVICE_EXISTS);
2499         }
2500 
2501         /*
2502          * 'sid' and 'num_sids' are filled in ibcm_create_svc_entry()
2503          */
2504         svcinfop->svc_flags = srv->sd_flags;
2505         svcinfop->svc_rc_handler = srv->sd_handler;
2506         svcinfop->svc_ud_handler = srv->sd_ud_handler;
2507 
2508         if (ret_sid != NULL)
2509                 *ret_sid = sid;
2510 
2511         *srv_hdl = svcinfop;
2512 
2513         ibtl_cm_change_service_cnt(ibt_hdl, num_sids);
2514 
2515         /* If this message isn't seen, then ibt_register_service failed. */
2516         IBTF_DPRINTF_L2(cmlog, "ibt_register_service: done (%p, %llX)",
2517             svcinfop, sid);
2518 
2519         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*svcinfop))
2520 
2521         return (IBT_SUCCESS);
2522 }
2523 
2524 
2525 static ibt_status_t
2526 ibcm_write_service_record(ibmf_saa_handle_t saa_handle,
2527     sa_service_record_t *srv_recp, ibmf_saa_access_type_t saa_type)
2528 {
2529         int     rval;
2530         int     retry;
2531 
2532         ibcm_sa_access_enter();
2533         for (retry = 0; retry < ibcm_max_sa_retries; retry++) {
2534                 rval = ibmf_saa_update_service_record(
2535                     saa_handle, srv_recp, saa_type, 0);
2536                 if (rval != IBMF_TRANS_TIMEOUT) {
2537                         break;
2538                 }
2539                 IBTF_DPRINTF_L2(cmlog, "ibcm_write_service_record: "
2540                     "ibmf_saa_update_service_record timed out"
2541                     " SID = %llX, rval = %d, saa_type = %d",
2542                     (longlong_t)srv_recp->ServiceID, rval, saa_type);
2543                 delay(ibcm_sa_timeout_delay);
2544         }
2545         ibcm_sa_access_exit();
2546 
2547         if (rval != IBMF_SUCCESS) {
2548                 IBTF_DPRINTF_L2(cmlog, "ibcm_write_service_record: "
2549                     "ibmf_saa_update_service_record() : Failed - %d", rval);
2550                 return (ibcm_ibmf_analyze_error(rval));
2551         } else
2552                 return (IBT_SUCCESS);
2553 }
2554 
2555 
2556 static void
2557 ibcm_rem_stale_srec(ibmf_saa_handle_t saa_handle, sa_service_record_t *srec)
2558 {
2559         ibt_status_t            retval;
2560         uint_t                  num_found;
2561         size_t                  length;
2562         sa_service_record_t     *srv_resp;
2563         void                    *results_p;
2564         uint_t                  i;
2565         uint64_t                component_mask;
2566         ibmf_saa_access_args_t  access_args;
2567 
2568         component_mask =
2569             SA_SR_COMPMASK_PKEY | SA_SR_COMPMASK_NAME | SA_SR_COMPMASK_GID;
2570 
2571         /* Call in SA Access retrieve routine to get Service Records. */
2572         access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
2573         access_args.sq_access_type = IBMF_SAA_RETRIEVE;
2574         access_args.sq_component_mask = component_mask;
2575         access_args.sq_template = srec;
2576         access_args.sq_template_length = sizeof (sa_service_record_t);
2577         access_args.sq_callback = NULL;
2578         access_args.sq_callback_arg = NULL;
2579 
2580         retval = ibcm_contact_sa_access(saa_handle, &access_args, &length,
2581             &results_p);
2582         if (retval != IBT_SUCCESS) {
2583                 IBTF_DPRINTF_L2(cmlog, "ibcm_rem_stale_srec: "
2584                     "SA Access Failure");
2585                 return;
2586         }
2587 
2588         num_found = length / sizeof (sa_service_record_t);
2589 
2590         if (num_found)
2591                 IBTF_DPRINTF_L3(cmlog, "ibcm_rem_stale_srec: "
2592                     "Found %d matching Service Records.", num_found);
2593 
2594         /* Validate the returned number of records. */
2595         if ((results_p != NULL) && (num_found > 0)) {
2596 
2597                 /* Remove all the records. */
2598                 for (i = 0; i < num_found; i++) {
2599 
2600                         srv_resp = (sa_service_record_t *)
2601                             ((uchar_t *)results_p +
2602                             i * sizeof (sa_service_record_t));
2603 
2604                         /*
2605                          * Found some matching records, but check out whether
2606                          * this Record is really stale or just happens to match
2607                          * the current session records. If yes, don't remove it.
2608                          */
2609                         mutex_enter(&ibcm_svc_info_lock);
2610                         if (ibcm_find_svc_entry(srv_resp->ServiceID) != NULL) {
2611                                 /* This record is NOT STALE. */
2612                                 mutex_exit(&ibcm_svc_info_lock);
2613                                 IBTF_DPRINTF_L3(cmlog, "ibcm_rem_stale_srec: "
2614                                     "This is not Stale, it's an active record");
2615                                 continue;
2616                         }
2617                         mutex_exit(&ibcm_svc_info_lock);
2618 
2619                         IBTF_DPRINTF_L2(cmlog, "ibcm_rem_stale_srec: "
2620                             "Removing Stale Rec: %s, %llX",
2621                             srv_resp->ServiceName, srv_resp->ServiceID);
2622 
2623                         IBCM_DUMP_SERVICE_REC(srv_resp);
2624 
2625                         /*
2626                          * Remove the Service Record Entry from SA.
2627                          *
2628                          * Get ServiceID info from Response Buf, other
2629                          * attributes are already filled-in.
2630                          */
2631 
2632                          _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(srec->ServiceID))
2633 
2634                         srec->ServiceID = srv_resp->ServiceID;
2635 
2636                          _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(srec->ServiceID))
2637 
2638                         (void) ibcm_write_service_record(saa_handle, srec,
2639                             IBMF_SAA_DELETE);
2640                 }
2641 
2642                 /* Deallocate the memory for results_p. */
2643                 kmem_free(results_p, length);
2644         }
2645 }
2646 
2647 
2648 
2649 /*
2650  * ibt_bind_service()
2651  *      Register a service with the IBCM
2652  *
2653  * INPUTS:
2654  *      srv_hdl         The service id handle returned to the client
2655  *                      on an ibt_service_register() call.
2656  *
2657  *      gid             The GID to which to bind the service.
2658  *
2659  *      srv_bind        The address of a ibt_srv_bind_t that describes
2660  *                      the service record.  This should be NULL if there
2661  *                      is to be no service record.  This contains:
2662  *
2663  *              sb_lease        Lease period
2664  *              sb_pkey         Partition
2665  *              sb_name         pointer to ASCII string Service Name,
2666  *                              NULL terminated.
2667  *              sb_key[]        Key to secure the service record.
2668  *              sb_data         Service Data structure (64-byte)
2669  *
2670  *      cm_private      First argument of Service handler.
2671  *
2672  *      sb_hdl_p        The address of a service bind handle, used
2673  *                      to undo the service binding.
2674  *
2675  * ibt_bind_service() returns:
2676  *      IBT_SUCCESS             - added a service successfully.
2677  *      IBT_INVALID_PARAM       - invalid input parameter.
2678  *      IBT_CM_FAILURE          - failed to add the service.
2679  *      IBT_CM_SERVICE_EXISTS   - service already exists.
2680  */
2681 ibt_status_t
2682 ibt_bind_service(ibt_srv_hdl_t srv_hdl, ib_gid_t gid, ibt_srv_bind_t *srv_bind,
2683     void *cm_private, ibt_sbind_hdl_t *sb_hdl_p)
2684 {
2685         ibt_status_t            status;
2686         ibtl_cm_hca_port_t      port;
2687         ibcm_svc_bind_t         *sbindp, *sbp;
2688         ibcm_hca_info_t         *hcap;
2689         ib_svc_id_t             sid, start_sid, end_sid;
2690         ibmf_saa_handle_t       saa_handle;
2691         sa_service_record_t     srv_rec;
2692         uint16_t                pkey_ix;
2693 
2694         if (sb_hdl_p != NULL)
2695                 *sb_hdl_p = NULL;       /* return value for error cases */
2696 
2697         IBTF_DPRINTF_L2(cmlog, "ibt_bind_service: srv_hdl %p, gid (%llX:%llX)",
2698             srv_hdl, (longlong_t)gid.gid_prefix, (longlong_t)gid.gid_guid);
2699 
2700         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sbindp))
2701 
2702         /* Call ibtl_cm_get_hca_port to get the port number and the HCA GUID. */
2703         if ((status = ibtl_cm_get_hca_port(gid, 0, &port)) != IBT_SUCCESS) {
2704                 IBTF_DPRINTF_L2(cmlog, "ibt_bind_service: "
2705                     "ibtl_cm_get_hca_port failed: %d", status);
2706                 return (status);
2707         }
2708         IBTF_DPRINTF_L4(cmlog, "ibt_bind_service: Port:%d HCA GUID:%llX",
2709             port.hp_port, port.hp_hca_guid);
2710 
2711         hcap = ibcm_find_hca_entry(port.hp_hca_guid);
2712         if (hcap == NULL) {
2713                 IBTF_DPRINTF_L2(cmlog, "ibt_bind_service: NO HCA found");
2714                 return (IBT_HCA_BUSY_DETACHING);
2715         }
2716         IBTF_DPRINTF_L4(cmlog, "ibt_bind_service: hcap = %p", hcap);
2717 
2718         if (srv_bind != NULL) {
2719                 saa_handle = ibcm_get_saa_handle(hcap, port.hp_port);
2720                 if (saa_handle == NULL) {
2721                         IBTF_DPRINTF_L2(cmlog, "ibt_bind_service: "
2722                             "saa_handle is NULL");
2723                         ibcm_dec_hca_acc_cnt(hcap);
2724                         return (IBT_HCA_PORT_NOT_ACTIVE);
2725                 }
2726                 if (srv_bind->sb_pkey == 0) {
2727                         IBTF_DPRINTF_L2(cmlog, "ibt_bind_service: "
2728                             "P_Key must not be 0");
2729                         ibcm_dec_hca_acc_cnt(hcap);
2730                         return (IBT_INVALID_PARAM);
2731                 }
2732                 if (strlen(srv_bind->sb_name) >= IB_SVC_NAME_LEN) {
2733                         IBTF_DPRINTF_L2(cmlog, "ibt_bind_service: "
2734                             "Service Name is too long");
2735                         ibcm_dec_hca_acc_cnt(hcap);
2736                         return (IBT_INVALID_PARAM);
2737                 } else
2738                         IBTF_DPRINTF_L3(cmlog, "ibt_bind_service: "
2739                             "Service Name='%s'", srv_bind->sb_name);
2740                 status = ibt_pkey2index_byguid(port.hp_hca_guid,
2741                     port.hp_port, srv_bind->sb_pkey, &pkey_ix);
2742                 if (status != IBT_SUCCESS) {
2743                         IBTF_DPRINTF_L2(cmlog, "ibt_bind_service: "
2744                             "P_Key 0x%x not found in P_Key_Table",
2745                             srv_bind->sb_pkey);
2746                         ibcm_dec_hca_acc_cnt(hcap);
2747                         return (status);
2748                 }
2749         }
2750 
2751         /* assume success - allocate before locking */
2752         sbindp = kmem_zalloc(sizeof (*sbindp), KM_SLEEP);
2753         sbindp->sbind_cm_private = cm_private;
2754         sbindp->sbind_gid = gid;
2755         sbindp->sbind_hcaguid = port.hp_hca_guid;
2756         sbindp->sbind_port = port.hp_port;
2757 
2758         mutex_enter(&ibcm_svc_info_lock);
2759 
2760         sbp = srv_hdl->svc_bind_list;
2761         while (sbp != NULL) {
2762                 if (sbp->sbind_gid.gid_guid == gid.gid_guid &&
2763                     sbp->sbind_gid.gid_prefix == gid.gid_prefix) {
2764                         if (srv_bind == NULL ||
2765                             srv_bind->sb_pkey == sbp->sbind_pkey) {
2766                                 IBTF_DPRINTF_L2(cmlog, "ibt_bind_service: "
2767                                     "failed: GID %llX:%llX and PKEY %x is "
2768                                     "already bound", gid.gid_prefix,
2769                                     gid.gid_guid, sbp->sbind_pkey);
2770                                 mutex_exit(&ibcm_svc_info_lock);
2771                                 ibcm_dec_hca_acc_cnt(hcap);
2772                                 kmem_free(sbindp, sizeof (*sbindp));
2773                                 return (IBT_CM_SERVICE_EXISTS);
2774                         }
2775                 }
2776                 sbp = sbp->sbind_link;
2777         }
2778         /* no entry found */
2779 
2780         sbindp->sbind_link = srv_hdl->svc_bind_list;
2781         srv_hdl->svc_bind_list = sbindp;
2782 
2783         mutex_exit(&ibcm_svc_info_lock);
2784 
2785         if (srv_bind != NULL) {
2786                 bzero(&srv_rec, sizeof (srv_rec));
2787 
2788                 srv_rec.ServiceLease =
2789                     sbindp->sbind_lease = srv_bind->sb_lease;
2790                 srv_rec.ServiceP_Key =
2791                     sbindp->sbind_pkey = srv_bind->sb_pkey;
2792                 srv_rec.ServiceKey_hi =
2793                     sbindp->sbind_key[0] = srv_bind->sb_key[0];
2794                 srv_rec.ServiceKey_lo =
2795                     sbindp->sbind_key[1] = srv_bind->sb_key[1];
2796                 (void) strcpy(sbindp->sbind_name, srv_bind->sb_name);
2797                 (void) strcpy((char *)srv_rec.ServiceName, srv_bind->sb_name);
2798                 srv_rec.ServiceGID = gid;
2799 
2800                 /*
2801                  * Find out whether we have any stale Local Service records
2802                  * matching the current attributes.  If yes, we shall try to
2803                  * remove them from SA using the current request's ServiceKey.
2804                  *
2805                  * We will perform this operation only for Local Services, as
2806                  * it is handled by SA automatically for WellKnown Services.
2807                  *
2808                  * Ofcourse, clients can specify NOT to do this clean-up by
2809                  * setting IBT_SBIND_NO_CLEANUP flag (srv_bind->sb_flag).
2810                  */
2811                 if ((srv_hdl->svc_id & IB_SID_AGN_LOCAL) &&
2812                     (!(srv_bind->sb_flag & IBT_SBIND_NO_CLEANUP))) {
2813                         ibcm_rem_stale_srec(saa_handle, &srv_rec);
2814                 }
2815 
2816                 /* Handle endianess for service data. */
2817                 ibcm_swizzle_from_srv(&srv_bind->sb_data, sbindp->sbind_data);
2818 
2819                 bcopy(sbindp->sbind_data, srv_rec.ServiceData, IB_SVC_DATA_LEN);
2820 
2821                 /* insert srv record into the SA */
2822                 start_sid = srv_hdl->svc_id;
2823                 end_sid = start_sid + srv_hdl->svc_num_sids - 1;
2824                 for (sid = start_sid; sid <= end_sid; sid++) {
2825 
2826                         srv_rec.ServiceID = sid;
2827 
2828                         IBCM_DUMP_SERVICE_REC(&srv_rec);
2829 
2830                         IBTF_DPRINTF_L4(cmlog, "ibt_bind_service: "
2831                             "ibmf_saa_write_service_record, SvcId = %llX",
2832                             (longlong_t)sid);
2833 
2834                         status = ibcm_write_service_record(saa_handle, &srv_rec,
2835                             IBMF_SAA_UPDATE);
2836                         if (status != IBT_SUCCESS) {
2837                                 IBTF_DPRINTF_L2(cmlog, "ibt_bind_service:"
2838                                     " ibcm_write_service_record fails %d, "
2839                                     "sid %llX", status, (longlong_t)sid);
2840 
2841                                 if (sid != start_sid) {
2842                                         /*
2843                                          * Bind failed while bind SID other than
2844                                          * first in the sid_range.  So we need
2845                                          * to unbind those, which are passed.
2846                                          *
2847                                          * Need to increment svc count to
2848                                          * compensate for ibt_unbind_service().
2849                                          */
2850                                         ibcm_inc_hca_svc_cnt(hcap);
2851                                         ibcm_dec_hca_acc_cnt(hcap);
2852 
2853                                         (void) ibt_unbind_service(srv_hdl,
2854                                             sbindp);
2855                                 } else {
2856                                         ibcm_svc_bind_t         **sbpp;
2857 
2858                                         /*
2859                                          * Bind failed for the first SID or the
2860                                          * only SID in question, then no need
2861                                          * to unbind, just free memory and
2862                                          * return error.
2863                                          */
2864                                         mutex_enter(&ibcm_svc_info_lock);
2865 
2866                                         sbpp = &srv_hdl->svc_bind_list;
2867                                         sbp = *sbpp;
2868                                         while (sbp != NULL) {
2869                                                 if (sbp == sbindp) {
2870                                                         *sbpp = sbp->sbind_link;
2871                                                         break;
2872                                                 }
2873                                                 sbpp = &sbp->sbind_link;
2874                                                 sbp = *sbpp;
2875                                         }
2876                                         mutex_exit(&ibcm_svc_info_lock);
2877                                         ibcm_dec_hca_acc_cnt(hcap);
2878 
2879                                         kmem_free(sbindp, sizeof (*sbindp));
2880                                 }
2881                                 return (status);
2882                         }
2883                 }
2884         }
2885         ibcm_inc_hca_svc_cnt(hcap);
2886         ibcm_dec_hca_acc_cnt(hcap);
2887 
2888         /* If this message isn't seen then ibt_bind_service failed */
2889         IBTF_DPRINTF_L2(cmlog, "ibt_bind_service: DONE (%p, %llX:%llX)",
2890             srv_hdl, gid.gid_prefix, gid.gid_guid);
2891 
2892         if (sb_hdl_p != NULL)
2893                 *sb_hdl_p = sbindp;
2894 
2895         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sbindp))
2896 
2897         return (IBT_SUCCESS);
2898 }
2899 
2900 ibt_status_t
2901 ibt_unbind_service(ibt_srv_hdl_t srv_hdl, ibt_sbind_hdl_t sbindp)
2902 {
2903         ib_svc_id_t     sid, end_sid;
2904         ibt_status_t    rval;
2905         ibcm_hca_info_t *hcap;
2906         ibcm_svc_bind_t *sbp, **sbpp;
2907 
2908         IBTF_DPRINTF_L2(cmlog, "ibt_unbind_service(%p, %p)",
2909             srv_hdl, sbindp);
2910 
2911         hcap = ibcm_find_hca_entry(sbindp->sbind_hcaguid);
2912 
2913         /* If there is a service on hca, respective hcap cannot go away */
2914         ASSERT(hcap != NULL);
2915 
2916         mutex_enter(&ibcm_svc_info_lock);
2917 
2918         sbpp = &srv_hdl->svc_bind_list;
2919         sbp = *sbpp;
2920         while (sbp != NULL) {
2921                 if (sbp == sbindp) {
2922                         *sbpp = sbp->sbind_link;
2923                         break;
2924                 }
2925                 sbpp = &sbp->sbind_link;
2926                 sbp = *sbpp;
2927         }
2928         sid = srv_hdl->svc_id;
2929         end_sid = srv_hdl->svc_id + srv_hdl->svc_num_sids - 1;
2930         if (sbp != NULL)
2931                 while (sbp->sbind_rewrite_state == IBCM_REWRITE_BUSY)
2932                         cv_wait(&ibcm_svc_info_cv, &ibcm_svc_info_lock);
2933         mutex_exit(&ibcm_svc_info_lock);
2934 
2935         if (sbp == NULL) {
2936                 IBTF_DPRINTF_L2(cmlog, "ibt_unbind_service: "
2937                     "service binding not found: srv_hdl %p, srv_bind %p",
2938                     srv_hdl, sbindp);
2939                 ibcm_dec_hca_acc_cnt(hcap);
2940                 return (IBT_INVALID_PARAM);
2941         }
2942 
2943         if (sbindp->sbind_pkey != 0) {       /* Are there service records? */
2944                 ibtl_cm_hca_port_t      port;
2945                 sa_service_record_t     srv_rec;
2946                 ibmf_saa_handle_t       saa_handle;
2947                 ibt_status_t            status;
2948 
2949                 /* get the default SGID of the port */
2950                 if ((status = ibtl_cm_get_hca_port(sbindp->sbind_gid, 0, &port))
2951                     != IBT_SUCCESS) {
2952                         IBTF_DPRINTF_L2(cmlog, "ibt_unbind_service: "
2953                             "ibtl_cm_get_hca_port failed: %d", status);
2954                         /* we're done, but there may be stale service records */
2955                         goto done;
2956                 }
2957 
2958                 saa_handle = ibcm_get_saa_handle(hcap, port.hp_port);
2959                 if (saa_handle == NULL) {
2960                         IBTF_DPRINTF_L2(cmlog, "ibt_unbind_service: "
2961                             "saa_handle is NULL");
2962                         /* we're done, but there may be stale service records */
2963                         goto done;
2964                 }
2965 
2966                 /* Fill in fields of srv_rec */
2967                 bzero(&srv_rec, sizeof (srv_rec));
2968 
2969                 srv_rec.ServiceP_Key = sbindp->sbind_pkey;
2970                 srv_rec.ServiceKey_hi = sbindp->sbind_key[0];
2971                 srv_rec.ServiceKey_lo = sbindp->sbind_key[1];
2972                 srv_rec.ServiceGID = sbindp->sbind_gid;
2973                 (void) strcpy((char *)srv_rec.ServiceName, sbindp->sbind_name);
2974 
2975                 while (sid <= end_sid) {
2976 
2977                         srv_rec.ServiceID = sid;
2978                         IBCM_DUMP_SERVICE_REC(&srv_rec);
2979 
2980                         rval = ibcm_write_service_record(saa_handle, &srv_rec,
2981                             IBMF_SAA_DELETE);
2982 
2983                         IBTF_DPRINTF_L4(cmlog, "ibt_unbind_service: "
2984                             "ibcm_write_service_record rval = %d, SID %llx",
2985                             rval, sid);
2986                         if (rval != IBT_SUCCESS) {
2987                                 /* this is not considered a reason to fail */
2988                                 IBTF_DPRINTF_L2(cmlog, "ibt_unbind_service: "
2989                                     "ibcm_write_service_record fails %d, "
2990                                     "sid %llx", rval, sid);
2991                         }
2992                         sid++;
2993                 }
2994         }
2995 done:
2996         ibcm_dec_hca_svc_cnt(hcap);
2997         ibcm_dec_hca_acc_cnt(hcap);
2998         kmem_free(sbindp, sizeof (*sbindp));
2999 
3000         /* If this message isn't seen then ibt_unbind_service failed */
3001         IBTF_DPRINTF_L2(cmlog, "ibt_unbind_service: done !!");
3002 
3003         return (IBT_SUCCESS);
3004 }
3005 
3006 /*
3007  * Simply pull off each binding from the list and unbind it.
3008  * If any of the unbind calls fail, we fail.
3009  */
3010 ibt_status_t
3011 ibt_unbind_all_services(ibt_srv_hdl_t srv_hdl)
3012 {
3013         ibt_status_t    status;
3014         ibcm_svc_bind_t *sbp;
3015 
3016         mutex_enter(&ibcm_svc_info_lock);
3017         sbp = NULL;
3018 
3019         /* this compare keeps the loop from being infinite */
3020         while (sbp != srv_hdl->svc_bind_list) {
3021                 sbp = srv_hdl->svc_bind_list;
3022                 mutex_exit(&ibcm_svc_info_lock);
3023                 status = ibt_unbind_service(srv_hdl, sbp);
3024                 if (status != IBT_SUCCESS)
3025                         return (status);
3026                 mutex_enter(&ibcm_svc_info_lock);
3027                 if (srv_hdl->svc_bind_list == NULL)
3028                         break;
3029         }
3030         mutex_exit(&ibcm_svc_info_lock);
3031         return (IBT_SUCCESS);
3032 }
3033 
3034 /*
3035  * ibt_deregister_service()
3036  *      Deregister a service with the IBCM
3037  *
3038  * INPUTS:
3039  *      ibt_hdl         The IBT client handle returned to the client
3040  *                      on an ibt_attach() call.
3041  *
3042  *      srv_hdl         The address of a service identification handle, used
3043  *                      to de-register a service.
3044  * RETURN VALUES:
3045  *      IBT_SUCCESS     on success (or respective failure on error)
3046  */
3047 ibt_status_t
3048 ibt_deregister_service(ibt_clnt_hdl_t ibt_hdl, ibt_srv_hdl_t srv_hdl)
3049 {
3050         ibcm_svc_info_t         *svcp;
3051         ibcm_svc_lookup_t       svc;
3052 
3053         IBTF_DPRINTF_L2(cmlog, "ibt_deregister_service(%p (%s), %p)",
3054             ibt_hdl, ibtl_cm_get_clnt_name(ibt_hdl), srv_hdl);
3055 
3056         mutex_enter(&ibcm_svc_info_lock);
3057 
3058         if (srv_hdl->svc_bind_list != NULL) {
3059                 IBTF_DPRINTF_L2(cmlog, "ibt_deregister_service:"
3060                     " srv_hdl %p still has bindings", srv_hdl);
3061                 mutex_exit(&ibcm_svc_info_lock);
3062                 return (IBT_CM_SERVICE_BUSY);
3063         }
3064         svc.sid = srv_hdl->svc_id;
3065         svc.num_sids = 1;
3066         IBTF_DPRINTF_L3(cmlog, "ibt_deregister_service: SID 0x%llX, numsids %d",
3067             srv_hdl->svc_id, srv_hdl->svc_num_sids);
3068 
3069 #ifdef __lock_lint
3070         ibcm_svc_compare(NULL, NULL);
3071 #endif
3072         svcp = avl_find(&ibcm_svc_avl_tree, &svc, NULL);
3073         if (svcp != srv_hdl) {
3074                 mutex_exit(&ibcm_svc_info_lock);
3075                 IBTF_DPRINTF_L2(cmlog, "ibt_deregister_service(): "
3076                     "srv_hdl %p not found", srv_hdl);
3077                 return (IBT_INVALID_PARAM);
3078         }
3079         avl_remove(&ibcm_svc_avl_tree, svcp);
3080 
3081         /* wait for active REQ/SREQ handling to be done */
3082         svcp->svc_to_delete = 1;
3083         while (svcp->svc_ref_cnt != 0)
3084                 cv_wait(&ibcm_svc_info_cv, &ibcm_svc_info_lock);
3085 
3086         mutex_exit(&ibcm_svc_info_lock);
3087 
3088         if ((srv_hdl->svc_id & IB_SID_AGN_MASK) == IB_SID_AGN_LOCAL)
3089                 ibcm_free_local_sids(srv_hdl->svc_id, srv_hdl->svc_num_sids);
3090 
3091         ibtl_cm_change_service_cnt(ibt_hdl, -srv_hdl->svc_num_sids);
3092         kmem_free(srv_hdl, sizeof (*srv_hdl));
3093 
3094         /* If this message isn't seen then ibt_deregister_service failed */
3095         IBTF_DPRINTF_L2(cmlog, "ibt_deregister_service: done !!");
3096 
3097         return (IBT_SUCCESS);
3098 }
3099 
3100 ibcm_status_t
3101 ibcm_ar_init(void)
3102 {
3103         ib_svc_id_t     sid = IBCM_DAPL_ATS_SID;
3104         ibcm_svc_info_t *tmp_svcp;
3105 
3106         IBTF_DPRINTF_L3(cmlog, "ibcm_ar_init()");
3107 
3108         /* remove this special SID from the pool of available SIDs */
3109         if ((tmp_svcp = ibcm_create_svc_entry(sid, 1)) == NULL) {
3110                 IBTF_DPRINTF_L3(cmlog, "ibcm_ar_init: "
3111                     "DAPL ATS SID 0x%llx already registered", (longlong_t)sid);
3112                 return (IBCM_FAILURE);
3113         }
3114         mutex_enter(&ibcm_svc_info_lock);
3115         ibcm_ar_svcinfop = tmp_svcp;
3116         ibcm_ar_list = NULL;    /* no address records registered yet */
3117         mutex_exit(&ibcm_svc_info_lock);
3118         return (IBCM_SUCCESS);
3119 }
3120 
3121 ibcm_status_t
3122 ibcm_ar_fini(void)
3123 {
3124         ibcm_ar_t       *ar_list;
3125         ibcm_svc_info_t *tmp_svcp;
3126 
3127         mutex_enter(&ibcm_svc_info_lock);
3128         ar_list = ibcm_ar_list;
3129 
3130         if (ar_list == NULL &&
3131             avl_numnodes(&ibcm_svc_avl_tree) == 1 &&
3132             avl_first(&ibcm_svc_avl_tree) == ibcm_ar_svcinfop) {
3133                 avl_remove(&ibcm_svc_avl_tree, ibcm_ar_svcinfop);
3134                 tmp_svcp = ibcm_ar_svcinfop;
3135                 mutex_exit(&ibcm_svc_info_lock);
3136                 kmem_free(tmp_svcp, sizeof (*ibcm_ar_svcinfop));
3137                 return (IBCM_SUCCESS);
3138         }
3139         mutex_exit(&ibcm_svc_info_lock);
3140         return (IBCM_FAILURE);
3141 }
3142 
3143 
3144 /*
3145  * Return to the caller:
3146  *      IBT_SUCCESS             Found a perfect match.
3147  *                              *arpp is set to the record.
3148  *      IBT_INCONSISTENT_AR     Found a record that's inconsistent.
3149  *      IBT_AR_NOT_REGISTERED   Found no record with same GID/pkey and
3150  *                              found no record with same data.
3151  */
3152 static ibt_status_t
3153 ibcm_search_ar(ibt_ar_t *arp, ibcm_ar_t **arpp)
3154 {
3155         ibcm_ar_t       *tmp;
3156         int             i;
3157 
3158         ASSERT(MUTEX_HELD(&ibcm_svc_info_lock));
3159         tmp = ibcm_ar_list;
3160         while (tmp != NULL) {
3161                 if (tmp->ar.ar_gid.gid_prefix == arp->ar_gid.gid_prefix &&
3162                     tmp->ar.ar_gid.gid_guid == arp->ar_gid.gid_guid &&
3163                     tmp->ar.ar_pkey == arp->ar_pkey) {
3164                         for (i = 0; i < IBCM_DAPL_ATS_NBYTES; i++)
3165                                 if (tmp->ar.ar_data[i] != arp->ar_data[i])
3166                                         return (IBT_INCONSISTENT_AR);
3167                         *arpp = tmp;
3168                         return (IBT_SUCCESS);
3169                 } else {
3170                         /* if all the data bytes match, we have inconsistency */
3171                         for (i = 0; i < IBCM_DAPL_ATS_NBYTES; i++)
3172                                 if (tmp->ar.ar_data[i] != arp->ar_data[i])
3173                                         break;
3174                         if (i == IBCM_DAPL_ATS_NBYTES)
3175                                 return (IBT_INCONSISTENT_AR);
3176                         /* try next address record */
3177                 }
3178                 tmp = tmp->ar_link;
3179         }
3180         return (IBT_AR_NOT_REGISTERED);
3181 }
3182 
3183 ibt_status_t
3184 ibt_register_ar(ibt_clnt_hdl_t ibt_hdl, ibt_ar_t *arp)
3185 {
3186         ibcm_ar_t               *found;
3187         ibcm_ar_t               *tmp;
3188         ibt_status_t            status;
3189         ibt_status_t            s1, s2;
3190         char                    *s;
3191         ibcm_ar_ref_t           *hdlp;
3192         ibcm_ar_t               *new;
3193         ibcm_ar_t               **linkp;
3194         ibtl_cm_hca_port_t      cm_port;
3195         uint16_t                pkey_ix;
3196         ibcm_hca_info_t         *hcap;
3197         ibmf_saa_handle_t       saa_handle;
3198         sa_service_record_t     *srv_recp;
3199         uint64_t                gid_ored;
3200 
3201         IBTF_DPRINTF_L3(cmlog, "ibt_register_ar: PKey 0x%X GID %llX:%llX",
3202             arp->ar_pkey, (longlong_t)arp->ar_gid.gid_prefix,
3203             (longlong_t)arp->ar_gid.gid_guid);
3204 
3205         /*
3206          * If P_Key is 0, but GID is not, this query is invalid.
3207          * If GID is 0, but P_Key is not, this query is invalid.
3208          */
3209         gid_ored = arp->ar_gid.gid_guid | arp->ar_gid.gid_prefix;
3210         if ((arp->ar_pkey == 0 && gid_ored != 0ULL) ||
3211             (arp->ar_pkey != 0 && gid_ored == 0ULL)) {
3212                 IBTF_DPRINTF_L2(cmlog, "ibt_register_ar: "
3213                     "GID/P_Key is not valid");
3214                 return (IBT_INVALID_PARAM);
3215         }
3216 
3217         /* assume success, so these might be needed */
3218         hdlp = kmem_alloc(sizeof (*hdlp), KM_SLEEP);
3219         new = kmem_zalloc(sizeof (*new), KM_SLEEP);
3220 
3221         mutex_enter(&ibcm_svc_info_lock);
3222         /* search for existing GID/pkey (there can be at most 1) */
3223         status = ibcm_search_ar(arp, &found);
3224         if (status == IBT_INCONSISTENT_AR) {
3225                 mutex_exit(&ibcm_svc_info_lock);
3226                 kmem_free(new, sizeof (*new));
3227                 kmem_free(hdlp, sizeof (*hdlp));
3228                 IBTF_DPRINTF_L2(cmlog, "ibt_register_ar: "
3229                     "address record is inconsistent with a known one");
3230                 return (IBT_INCONSISTENT_AR);
3231         } else if (status == IBT_SUCCESS) {
3232                 if (found->ar_flags == IBCM_AR_INITING) {
3233                         found->ar_waiters++;
3234                         cv_wait(&found->ar_cv, &ibcm_svc_info_lock);
3235                         found->ar_waiters--;
3236                 }
3237                 if (found->ar_flags == IBCM_AR_FAILED) {
3238                         if (found->ar_waiters == 0) {
3239                                 cv_destroy(&found->ar_cv);
3240                                 kmem_free(found, sizeof (*found));
3241                         }
3242                         mutex_exit(&ibcm_svc_info_lock);
3243                         kmem_free(new, sizeof (*new));
3244                         kmem_free(hdlp, sizeof (*hdlp));
3245                         return (ibt_get_module_failure(IBT_FAILURE_IBCM, 0));
3246                 }
3247                 hdlp->ar_ibt_hdl = ibt_hdl;
3248                 hdlp->ar_ref_link = found->ar_ibt_hdl_list;
3249                 found->ar_ibt_hdl_list = hdlp;
3250                 mutex_exit(&ibcm_svc_info_lock);
3251                 kmem_free(new, sizeof (*new));
3252                 ibtl_cm_change_service_cnt(ibt_hdl, 1);
3253                 return (IBT_SUCCESS);
3254         } else {
3255                 ASSERT(status == IBT_AR_NOT_REGISTERED);
3256         }
3257         hdlp->ar_ref_link = NULL;
3258         hdlp->ar_ibt_hdl = ibt_hdl;
3259         new->ar_ibt_hdl_list = hdlp;
3260         new->ar = *arp;
3261         new->ar_flags = IBCM_AR_INITING;
3262         new->ar_waiters = 0;
3263         cv_init(&new->ar_cv, NULL, CV_DEFAULT, NULL);
3264         new->ar_link = ibcm_ar_list;
3265         ibcm_ar_list = new;
3266 
3267         /* verify GID/pkey is valid for a local port, etc. */
3268         hcap = NULL;
3269         if ((s1 = ibtl_cm_get_hca_port(arp->ar_gid, 0, &cm_port))
3270             != IBT_SUCCESS ||
3271             (s2 = ibt_pkey2index_byguid(cm_port.hp_hca_guid, cm_port.hp_port,
3272             arp->ar_pkey, &pkey_ix)) != IBT_SUCCESS ||
3273             (hcap = ibcm_find_hca_entry(cm_port.hp_hca_guid)) == NULL) {
3274                 cv_destroy(&new->ar_cv);
3275                 ibcm_ar_list = new->ar_link;
3276                 mutex_exit(&ibcm_svc_info_lock);
3277                 kmem_free(new, sizeof (*new));
3278                 kmem_free(hdlp, sizeof (*hdlp));
3279                 status = IBT_INVALID_PARAM;
3280                 if (s1 == IBT_HCA_PORT_NOT_ACTIVE) {
3281                         s = "PORT DOWN";
3282                         status = IBT_HCA_PORT_NOT_ACTIVE;
3283                 } else if (s1 != IBT_SUCCESS)
3284                         s = "GID not found";
3285                 else if (s2 != IBT_SUCCESS)
3286                         s = "PKEY not found";
3287                 else
3288                         s = "CM could not find its HCA entry";
3289                 IBTF_DPRINTF_L2(cmlog, "ibt_register_ar: %s, status = %d",
3290                     s, status);
3291                 return (status);
3292         }
3293         mutex_exit(&ibcm_svc_info_lock);
3294         saa_handle = ibcm_get_saa_handle(hcap, cm_port.hp_port);
3295 
3296         /* create service record */
3297         srv_recp = kmem_zalloc(sizeof (*srv_recp), KM_SLEEP);
3298         srv_recp->ServiceLease = 0xFFFFFFFF; /* infinite */
3299         srv_recp->ServiceP_Key = arp->ar_pkey;
3300         srv_recp->ServiceKey_hi = 0xDA410000ULL;     /* DAPL */
3301         srv_recp->ServiceKey_lo = 0xA7500000ULL;     /* ATS */
3302         (void) strcpy((char *)srv_recp->ServiceName, IBCM_DAPL_ATS_NAME);
3303         srv_recp->ServiceGID = arp->ar_gid;
3304         bcopy(arp->ar_data, srv_recp->ServiceData, IBCM_DAPL_ATS_NBYTES);
3305         srv_recp->ServiceID = IBCM_DAPL_ATS_SID;
3306 
3307         /* insert service record into the SA */
3308 
3309         IBCM_DUMP_SERVICE_REC(srv_recp);
3310 
3311         if (saa_handle != NULL)
3312                 status = ibcm_write_service_record(saa_handle, srv_recp,
3313                     IBMF_SAA_UPDATE);
3314         else
3315                 status = IBT_HCA_PORT_NOT_ACTIVE;
3316 
3317         if (status != IBT_SUCCESS) {
3318                 IBTF_DPRINTF_L2(cmlog, "ibt_register_ar: sa access fails %d, "
3319                     "sid %llX", status, (longlong_t)srv_recp->ServiceID);
3320                 IBTF_DPRINTF_L2(cmlog, "ibt_register_ar: FAILED for gid "
3321                     "%llX:%llX pkey 0x%X", (longlong_t)arp->ar_gid.gid_prefix,
3322                     (longlong_t)arp->ar_gid.gid_guid, arp->ar_pkey);
3323 
3324                 kmem_free(srv_recp, sizeof (*srv_recp));
3325                 kmem_free(hdlp, sizeof (*hdlp));
3326 
3327                 mutex_enter(&ibcm_svc_info_lock);
3328                 linkp = &ibcm_ar_list;
3329                 tmp = *linkp;
3330                 while (tmp != NULL) {
3331                         if (tmp == new) {
3332                                 *linkp = new->ar_link;
3333                                 break;
3334                         }
3335                         linkp = &tmp->ar_link;
3336                         tmp = *linkp;
3337                 }
3338                 if (new->ar_waiters > 0) {
3339                         new->ar_flags = IBCM_AR_FAILED;
3340                         cv_broadcast(&new->ar_cv);
3341                         mutex_exit(&ibcm_svc_info_lock);
3342                 } else {
3343                         cv_destroy(&new->ar_cv);
3344                         mutex_exit(&ibcm_svc_info_lock);
3345                         kmem_free(new, sizeof (*new));
3346                 }
3347                 ibcm_dec_hca_acc_cnt(hcap);
3348                 IBTF_DPRINTF_L2(cmlog, "ibt_register_ar: "
3349                     "IBMF_SAA failed to write address record");
3350         } else {                                        /* SUCCESS */
3351                 uint8_t         *b;
3352 
3353                 IBTF_DPRINTF_L3(cmlog, "ibt_register_ar: SUCCESS for gid "
3354                     "%llx:%llx pkey %x", (longlong_t)arp->ar_gid.gid_prefix,
3355                     (longlong_t)arp->ar_gid.gid_guid, arp->ar_pkey);
3356                 b = arp->ar_data;
3357 
3358                 IBTF_DPRINTF_L3(cmlog, "ibt_register_ar:"
3359                     " data %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
3360                     b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9],
3361                     b[10], b[11], b[12], b[13], b[14], b[15]);
3362                 mutex_enter(&ibcm_svc_info_lock);
3363                 new->ar_srv_recp = srv_recp;
3364                 new->ar_saa_handle = saa_handle;
3365                 new->ar_port = cm_port.hp_port;
3366                 new->ar_hcap = hcap;
3367                 new->ar_flags = IBCM_AR_SUCCESS;
3368                 if (new->ar_waiters > 0)
3369                         cv_broadcast(&new->ar_cv);
3370                 mutex_exit(&ibcm_svc_info_lock);
3371                 ibtl_cm_change_service_cnt(ibt_hdl, 1);
3372                 /* do not call ibcm_dec_hca_acc_cnt(hcap) until deregister */
3373         }
3374         return (status);
3375 }
3376 
3377 ibt_status_t
3378 ibt_deregister_ar(ibt_clnt_hdl_t ibt_hdl, ibt_ar_t *arp)
3379 {
3380         ibcm_ar_t               *found;
3381         ibcm_ar_t               *tmp;
3382         ibcm_ar_t               **linkp;
3383         ibcm_ar_ref_t           *hdlp;
3384         ibcm_ar_ref_t           **hdlpp;
3385         ibt_status_t            status;
3386         ibmf_saa_handle_t       saa_handle;
3387         sa_service_record_t     *srv_recp;
3388         uint64_t                gid_ored;
3389 
3390         IBTF_DPRINTF_L3(cmlog, "ibt_deregister_ar: pkey %x", arp->ar_pkey);
3391         IBTF_DPRINTF_L3(cmlog, "ibt_deregister_ar: gid %llx:%llx",
3392             (longlong_t)arp->ar_gid.gid_prefix,
3393             (longlong_t)arp->ar_gid.gid_guid);
3394 
3395         /*
3396          * If P_Key is 0, but GID is not, this query is invalid.
3397          * If GID is 0, but P_Key is not, this query is invalid.
3398          */
3399         gid_ored = arp->ar_gid.gid_guid | arp->ar_gid.gid_prefix;
3400         if ((arp->ar_pkey == 0 && gid_ored != 0ULL) ||
3401             (arp->ar_pkey != 0 && gid_ored == 0ULL)) {
3402                 IBTF_DPRINTF_L2(cmlog, "ibt_deregister_ar: "
3403                     "GID/P_Key is not valid");
3404                 return (IBT_INVALID_PARAM);
3405         }
3406 
3407         mutex_enter(&ibcm_svc_info_lock);
3408         /* search for existing GID/pkey (there can be at most 1) */
3409         status = ibcm_search_ar(arp, &found);
3410         if (status == IBT_INCONSISTENT_AR || status == IBT_AR_NOT_REGISTERED) {
3411                 mutex_exit(&ibcm_svc_info_lock);
3412                 IBTF_DPRINTF_L2(cmlog, "ibt_deregister_ar: "
3413                     "address record not found");
3414                 return (IBT_AR_NOT_REGISTERED);
3415         }
3416         ASSERT(status == IBT_SUCCESS);
3417 
3418         hdlpp = &found->ar_ibt_hdl_list;
3419         hdlp = *hdlpp;
3420         while (hdlp != NULL) {
3421                 if (hdlp->ar_ibt_hdl == ibt_hdl)
3422                         break;
3423                 hdlpp = &hdlp->ar_ref_link;
3424                 hdlp = *hdlpp;
3425         }
3426         if (hdlp == NULL) {     /* could not find ibt_hdl on list */
3427                 mutex_exit(&ibcm_svc_info_lock);
3428                 IBTF_DPRINTF_L2(cmlog, "ibt_deregister_ar: "
3429                     "address record found, but not for this client");
3430                 return (IBT_AR_NOT_REGISTERED);
3431         }
3432         *hdlpp = hdlp->ar_ref_link;  /* remove ref for this client */
3433         if (found->ar_ibt_hdl_list == NULL && found->ar_waiters == 0) {
3434                 /* last entry was removed */
3435                 found->ar_flags = IBCM_AR_INITING; /* hold off register_ar */
3436                 saa_handle = found->ar_saa_handle;
3437                 srv_recp = found->ar_srv_recp;
3438 
3439                 /* wait if this service record is being rewritten */
3440                 while (found->ar_rewrite_state == IBCM_REWRITE_BUSY)
3441                         cv_wait(&ibcm_svc_info_cv, &ibcm_svc_info_lock);
3442                 mutex_exit(&ibcm_svc_info_lock);
3443 
3444                 /* remove service record */
3445                 status = ibcm_write_service_record(saa_handle, srv_recp,
3446                     IBMF_SAA_DELETE);
3447                 if (status != IBT_SUCCESS)
3448                         IBTF_DPRINTF_L2(cmlog, "ibt_deregister_ar: "
3449                             "IBMF_SAA failed to delete address record");
3450                 mutex_enter(&ibcm_svc_info_lock);
3451                 if (found->ar_waiters == 0) {        /* still no waiters */
3452                         linkp = &ibcm_ar_list;
3453                         tmp = *linkp;
3454                         while (tmp != found) {
3455                                 linkp = &tmp->ar_link;
3456                                 tmp = *linkp;
3457                         }
3458                         *linkp = tmp->ar_link;
3459                         ibcm_dec_hca_acc_cnt(found->ar_hcap);
3460                         kmem_free(srv_recp, sizeof (*srv_recp));
3461                         cv_destroy(&found->ar_cv);
3462                         kmem_free(found, sizeof (*found));
3463                 } else {
3464                         /* add service record back in for the waiters */
3465                         mutex_exit(&ibcm_svc_info_lock);
3466                         status = ibcm_write_service_record(saa_handle, srv_recp,
3467                             IBMF_SAA_UPDATE);
3468                         mutex_enter(&ibcm_svc_info_lock);
3469                         if (status == IBT_SUCCESS)
3470                                 found->ar_flags = IBCM_AR_SUCCESS;
3471                         else {
3472                                 found->ar_flags = IBCM_AR_FAILED;
3473                                 IBTF_DPRINTF_L2(cmlog, "ibt_deregister_ar: "
3474                                     "IBMF_SAA failed to write address record");
3475                         }
3476                         cv_broadcast(&found->ar_cv);
3477                 }
3478         }
3479         mutex_exit(&ibcm_svc_info_lock);
3480         kmem_free(hdlp, sizeof (*hdlp));
3481         ibtl_cm_change_service_cnt(ibt_hdl, -1);
3482         return (status);
3483 }
3484 
3485 ibt_status_t
3486 ibt_query_ar(ib_gid_t *sgid, ibt_ar_t *queryp, ibt_ar_t *resultp)
3487 {
3488         sa_service_record_t     svcrec_req;
3489         sa_service_record_t     *svcrec_resp;
3490         void                    *results_p;
3491         uint64_t                component_mask = 0;
3492         uint64_t                gid_ored;
3493         size_t                  length;
3494         int                     num_rec;
3495         int                     i;
3496         ibmf_saa_access_args_t  access_args;
3497         ibt_status_t            retval;
3498         ibtl_cm_hca_port_t      cm_port;
3499         ibcm_hca_info_t         *hcap;
3500         ibmf_saa_handle_t       saa_handle;
3501 
3502         IBTF_DPRINTF_L3(cmlog, "ibt_query_ar(%p, %p)", queryp, resultp);
3503         IBTF_DPRINTF_L3(cmlog, "ibt_query_ar: sgid %llx:%llx",
3504             (longlong_t)sgid->gid_prefix, (longlong_t)sgid->gid_guid);
3505         IBTF_DPRINTF_L3(cmlog, "ibt_query_ar: query_pkey %x", queryp->ar_pkey);
3506         IBTF_DPRINTF_L3(cmlog, "ibt_query_ar: query_gid %llx:%llx",
3507             (longlong_t)queryp->ar_gid.gid_prefix,
3508             (longlong_t)queryp->ar_gid.gid_guid);
3509 
3510         /*
3511          * If P_Key is 0, but GID is not, this query is invalid.
3512          * If GID is 0, but P_Key is not, this query is invalid.
3513          */
3514         gid_ored = queryp->ar_gid.gid_guid | queryp->ar_gid.gid_prefix;
3515         if ((queryp->ar_pkey == 0 && gid_ored != 0ULL) ||
3516             (queryp->ar_pkey != 0 && gid_ored == 0ULL)) {
3517                 IBTF_DPRINTF_L2(cmlog, "ibt_query_ar: GID/P_Key is not valid");
3518                 return (IBT_INVALID_PARAM);
3519         }
3520 
3521         hcap = NULL;
3522         if (ibtl_cm_get_hca_port(*sgid, 0, &cm_port) != IBT_SUCCESS ||
3523             (hcap = ibcm_find_hca_entry(cm_port.hp_hca_guid)) == NULL ||
3524             (saa_handle = ibcm_get_saa_handle(hcap, cm_port.hp_port)) == NULL) {
3525                 if (hcap != NULL)
3526                         ibcm_dec_hca_acc_cnt(hcap);
3527                 IBTF_DPRINTF_L2(cmlog, "ibt_query_ar: sgid is not valid");
3528                 return (IBT_INVALID_PARAM);
3529         }
3530 
3531         bzero(&svcrec_req, sizeof (svcrec_req));
3532 
3533         /* Is GID/P_Key Specified. */
3534         if (queryp->ar_pkey != 0) {  /* GID is non-zero from check above */
3535                 svcrec_req.ServiceP_Key = queryp->ar_pkey;
3536                 component_mask |= SA_SR_COMPMASK_PKEY;
3537                 IBTF_DPRINTF_L3(cmlog, "ibt_query_ar: P_Key %X",
3538                     queryp->ar_pkey);
3539                 svcrec_req.ServiceGID = queryp->ar_gid;
3540                 component_mask |= SA_SR_COMPMASK_GID;
3541                 IBTF_DPRINTF_L3(cmlog, "ibt_query_ar: GID %llX:%llX",
3542                     (longlong_t)queryp->ar_gid.gid_prefix,
3543                     (longlong_t)queryp->ar_gid.gid_guid);
3544         }
3545 
3546         /* Is ServiceData Specified. */
3547         for (i = 0; i < IBCM_DAPL_ATS_NBYTES; i++) {
3548                 if (queryp->ar_data[i] != 0) {
3549                         bcopy(queryp->ar_data, svcrec_req.ServiceData,
3550                             IBCM_DAPL_ATS_NBYTES);
3551                         component_mask |= 0xFFFF << 7;    /* all 16 Data8 */
3552                                                         /* components */
3553                         break;
3554                 }
3555         }
3556 
3557         /* Service Name */
3558         (void) strcpy((char *)svcrec_req.ServiceName, IBCM_DAPL_ATS_NAME);
3559         component_mask |= SA_SR_COMPMASK_NAME;
3560 
3561         svcrec_req.ServiceID = IBCM_DAPL_ATS_SID;
3562         component_mask |= SA_SR_COMPMASK_ID;
3563 
3564         IBTF_DPRINTF_L3(cmlog, "ibt_query_ar: "
3565             "Perform SA Access: Mask: 0x%X", component_mask);
3566 
3567         /*
3568          * Call in SA Access retrieve routine to get Service Records.
3569          *
3570          * SA Access framework allocated memory for the "results_p".
3571          * Make sure to deallocate once we are done with the results_p.
3572          * The size of the buffer allocated will be as returned in
3573          * "length" field.
3574          */
3575         access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
3576         access_args.sq_access_type = IBMF_SAA_RETRIEVE;
3577         access_args.sq_component_mask = component_mask;
3578         access_args.sq_template = &svcrec_req;
3579         access_args.sq_template_length = sizeof (sa_service_record_t);
3580         access_args.sq_callback = NULL;
3581         access_args.sq_callback_arg = NULL;
3582 
3583         retval = ibcm_contact_sa_access(saa_handle, &access_args, &length,
3584             &results_p);
3585 
3586         ibcm_dec_hca_acc_cnt(hcap);
3587         if (retval != IBT_SUCCESS) {
3588                 IBTF_DPRINTF_L2(cmlog, "ibt_query_ar: SA Access Failed");
3589                 return (retval);
3590         }
3591 
3592         num_rec = length / sizeof (sa_service_record_t);
3593 
3594         IBTF_DPRINTF_L3(cmlog, "ibt_query_ar: "
3595             "Found %d Service Records.", num_rec);
3596 
3597         /* Validate the returned number of records. */
3598         if ((results_p != NULL) && (num_rec > 0)) {
3599                 uint8_t         *b;
3600 
3601                 /* Just return info from the first service record. */
3602                 svcrec_resp = (sa_service_record_t *)results_p;
3603 
3604                 /* The Service GID and Service ID */
3605                 resultp->ar_gid = svcrec_resp->ServiceGID;
3606                 resultp->ar_pkey = svcrec_resp->ServiceP_Key;
3607                 bcopy(svcrec_resp->ServiceData,
3608                     resultp->ar_data, IBCM_DAPL_ATS_NBYTES);
3609 
3610                 IBTF_DPRINTF_L3(cmlog, "ibt_query_ar: "
3611                     "Found: pkey %x dgid %llX:%llX", resultp->ar_pkey,
3612                     (longlong_t)resultp->ar_gid.gid_prefix,
3613                     (longlong_t)resultp->ar_gid.gid_guid);
3614                 b = resultp->ar_data;
3615                 IBTF_DPRINTF_L3(cmlog, "ibt_query_ar:"
3616                     " data %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
3617                     b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9],
3618                     b[10], b[11], b[12], b[13], b[14], b[15]);
3619 
3620                 /* Deallocate the memory for results_p. */
3621                 kmem_free(results_p, length);
3622                 if (num_rec > 1)
3623                         retval = IBT_MULTIPLE_AR;
3624                 else
3625                         retval = IBT_SUCCESS;
3626         } else {
3627                 IBTF_DPRINTF_L2(cmlog, "ibt_query_ar: "
3628                     "ibmf_sa_access found 0 matching records");
3629                 retval = IBT_AR_NOT_REGISTERED;
3630         }
3631         return (retval);
3632 }
3633 
3634 /* mark all ATS service records associated with the port */
3635 static void
3636 ibcm_mark_ar(ib_guid_t hca_guid, uint8_t port)
3637 {
3638         ibcm_ar_t       *tmp;
3639 
3640         ASSERT(MUTEX_HELD(&ibcm_svc_info_lock));
3641         for (tmp = ibcm_ar_list; tmp != NULL; tmp = tmp->ar_link) {
3642                 if (tmp->ar_hcap == NULL)
3643                         continue;
3644                 if (tmp->ar_hcap->hca_guid == hca_guid &&
3645                     tmp->ar_port == port) {
3646                         /* even if it's busy, we mark it for rewrite */
3647                         tmp->ar_rewrite_state = IBCM_REWRITE_NEEDED;
3648                 }
3649         }
3650 }
3651 
3652 /* rewrite all ATS service records */
3653 static int
3654 ibcm_rewrite_ar(void)
3655 {
3656         ibcm_ar_t               *tmp;
3657         ibmf_saa_handle_t       saa_handle;
3658         sa_service_record_t     *srv_recp;
3659         ibt_status_t            rval;
3660         int                     did_something = 0;
3661 
3662         ASSERT(MUTEX_HELD(&ibcm_svc_info_lock));
3663 check_for_work:
3664         for (tmp = ibcm_ar_list; tmp != NULL; tmp = tmp->ar_link) {
3665                 if (tmp->ar_rewrite_state == IBCM_REWRITE_NEEDED) {
3666                         tmp->ar_rewrite_state = IBCM_REWRITE_BUSY;
3667                         saa_handle = tmp->ar_saa_handle;
3668                         srv_recp = tmp->ar_srv_recp;
3669                         mutex_exit(&ibcm_svc_info_lock);
3670                         IBTF_DPRINTF_L3(cmlog, "ibcm_rewrite_ar: "
3671                             "rewriting ar @ %p", tmp);
3672                         did_something = 1;
3673                         rval = ibcm_write_service_record(saa_handle, srv_recp,
3674                             IBMF_SAA_UPDATE);
3675                         if (rval != IBT_SUCCESS)
3676                                 IBTF_DPRINTF_L2(cmlog, "ibcm_rewrite_ar: "
3677                                     "ibcm_write_service_record failed: "
3678                                     "status = %d", rval);
3679                         mutex_enter(&ibcm_svc_info_lock);
3680                         /* if it got marked again, then we want to rewrite */
3681                         if (tmp->ar_rewrite_state == IBCM_REWRITE_BUSY)
3682                                 tmp->ar_rewrite_state = IBCM_REWRITE_IDLE;
3683                         /* in case there was a waiter... */
3684                         cv_broadcast(&ibcm_svc_info_cv);
3685                         goto check_for_work;
3686                 }
3687         }
3688         return (did_something);
3689 }
3690 
3691 static void
3692 ibcm_rewrite_svc_record(ibcm_svc_info_t *srv_hdl, ibcm_svc_bind_t *sbindp)
3693 {
3694         ibcm_hca_info_t         *hcap;
3695         ib_svc_id_t             sid, start_sid, end_sid;
3696         ibmf_saa_handle_t       saa_handle;
3697         sa_service_record_t     srv_rec;
3698         ibt_status_t            rval;
3699 
3700         hcap = ibcm_find_hca_entry(sbindp->sbind_hcaguid);
3701         if (hcap == NULL) {
3702                 IBTF_DPRINTF_L2(cmlog, "ibcm_rewrite_svc_record: "
3703                     "NO HCA found for HCA GUID %llX", sbindp->sbind_hcaguid);
3704                 return;
3705         }
3706 
3707         saa_handle = ibcm_get_saa_handle(hcap, sbindp->sbind_port);
3708         if (saa_handle == NULL) {
3709                 IBTF_DPRINTF_L2(cmlog, "ibcm_rewrite_svc_record: "
3710                     "saa_handle is NULL");
3711                 ibcm_dec_hca_acc_cnt(hcap);
3712                 return;
3713         }
3714 
3715         IBTF_DPRINTF_L3(cmlog, "ibcm_rewrite_svc_record: "
3716             "rewriting svc '%s', port_guid = %llX", sbindp->sbind_name,
3717             sbindp->sbind_gid.gid_guid);
3718 
3719         bzero(&srv_rec, sizeof (srv_rec));
3720 
3721         srv_rec.ServiceLease = sbindp->sbind_lease;
3722         srv_rec.ServiceP_Key = sbindp->sbind_pkey;
3723         srv_rec.ServiceKey_hi = sbindp->sbind_key[0];
3724         srv_rec.ServiceKey_lo = sbindp->sbind_key[1];
3725         (void) strcpy((char *)srv_rec.ServiceName, sbindp->sbind_name);
3726         srv_rec.ServiceGID = sbindp->sbind_gid;
3727 
3728         bcopy(sbindp->sbind_data, srv_rec.ServiceData, IB_SVC_DATA_LEN);
3729 
3730         /* insert srv record into the SA */
3731         start_sid = srv_hdl->svc_id;
3732         end_sid = start_sid + srv_hdl->svc_num_sids - 1;
3733         for (sid = start_sid; sid <= end_sid; sid++) {
3734                 srv_rec.ServiceID = sid;
3735 
3736                 rval = ibcm_write_service_record(saa_handle, &srv_rec,
3737                     IBMF_SAA_UPDATE);
3738 
3739                 IBTF_DPRINTF_L4(cmlog, "ibcm_rewrite_svc_record: "
3740                     "ibcm_write_service_record, SvcId = %llX, "
3741                     "rval = %d", (longlong_t)sid, rval);
3742                 if (rval != IBT_SUCCESS) {
3743                         IBTF_DPRINTF_L2(cmlog, "ibcm_rewrite_svc_record:"
3744                             " ibcm_write_service_record fails %d sid %llX",
3745                             rval, (longlong_t)sid);
3746                 }
3747         }
3748         ibcm_dec_hca_acc_cnt(hcap);
3749 }
3750 
3751 /*
3752  * Task to mark all service records as needing to be rewritten to the SM/SA.
3753  * This task does not return until all of them have been rewritten.
3754  */
3755 void
3756 ibcm_service_record_rewrite_task(void *arg)
3757 {
3758         ibcm_port_up_t  *pup = (ibcm_port_up_t *)arg;
3759         ib_guid_t       hca_guid = pup->pup_hca_guid;
3760         uint8_t         port = pup->pup_port;
3761         ibcm_svc_info_t *svcp;
3762         ibcm_svc_bind_t *sbp;
3763         avl_tree_t      *avl_tree = &ibcm_svc_avl_tree;
3764         static int      task_is_running = 0;
3765 
3766         IBTF_DPRINTF_L3(cmlog, "ibcm_service_record_rewrite_task STARTED "
3767             "for hca_guid %llX, port %d", hca_guid, port);
3768 
3769         mutex_enter(&ibcm_svc_info_lock);
3770         ibcm_mark_ar(hca_guid, port);
3771         for (svcp = avl_first(avl_tree); svcp != NULL;
3772             svcp = avl_walk(avl_tree, svcp, AVL_AFTER)) {
3773                 sbp = svcp->svc_bind_list;
3774                 while (sbp != NULL) {
3775                         if (sbp->sbind_pkey != 0 &&
3776                             sbp->sbind_port == port &&
3777                             sbp->sbind_hcaguid == hca_guid) {
3778                                 /* even if it's busy, we mark it for rewrite */
3779                                 sbp->sbind_rewrite_state = IBCM_REWRITE_NEEDED;
3780                         }
3781                         sbp = sbp->sbind_link;
3782                 }
3783         }
3784         if (task_is_running) {
3785                 /* let the other task thread finish the work */
3786                 mutex_exit(&ibcm_svc_info_lock);
3787                 return;
3788         }
3789         task_is_running = 1;
3790 
3791         (void) ibcm_rewrite_ar();
3792 
3793 check_for_work:
3794         for (svcp = avl_first(avl_tree); svcp != NULL;
3795             svcp = avl_walk(avl_tree, svcp, AVL_AFTER)) {
3796                 sbp = svcp->svc_bind_list;
3797                 while (sbp != NULL) {
3798                         if (sbp->sbind_rewrite_state == IBCM_REWRITE_NEEDED) {
3799                                 sbp->sbind_rewrite_state = IBCM_REWRITE_BUSY;
3800                                 mutex_exit(&ibcm_svc_info_lock);
3801                                 ibcm_rewrite_svc_record(svcp, sbp);
3802                                 mutex_enter(&ibcm_svc_info_lock);
3803                                 /* if it got marked again, we want to rewrite */
3804                                 if (sbp->sbind_rewrite_state ==
3805                                     IBCM_REWRITE_BUSY)
3806                                         sbp->sbind_rewrite_state =
3807                                             IBCM_REWRITE_IDLE;
3808                                 /* in case there was a waiter... */
3809                                 cv_broadcast(&ibcm_svc_info_cv);
3810                                 goto check_for_work;
3811                         }
3812                         sbp = sbp->sbind_link;
3813                 }
3814         }
3815         /*
3816          * If there were no service records to write, and we failed to
3817          * have to rewrite any more ATS service records, then we're done.
3818          */
3819         if (ibcm_rewrite_ar() != 0)
3820                 goto check_for_work;
3821         task_is_running = 0;
3822         mutex_exit(&ibcm_svc_info_lock);
3823 
3824         IBTF_DPRINTF_L3(cmlog, "ibcm_service_record_rewrite_task DONE");
3825         kmem_free(pup, sizeof (ibcm_port_up_t));
3826 }
3827 
3828 ibt_status_t
3829 ibt_ofuvcm_get_req_data(void *session_id, ibt_ofuvcm_req_data_t *req_data)
3830 {
3831         ibcm_state_data_t       *statep = (ibcm_state_data_t *)session_id;
3832         ibcm_req_msg_t          *req_msgp;
3833 
3834         IBTF_DPRINTF_L3(cmlog, "ibt_get_ofuvcm_req_data: session_id %p",
3835             session_id);
3836         mutex_enter(&statep->state_mutex);
3837         if ((statep->state != IBCM_STATE_REQ_RCVD) &&
3838             (statep->state != IBCM_STATE_MRA_SENT)) {
3839                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ofuvcm_req_data: Invalid "
3840                     "State %x", statep->state);
3841                 mutex_exit(&statep->state_mutex);
3842                 return (IBT_CHAN_STATE_INVALID);
3843         }
3844         if (statep->mode == IBCM_ACTIVE_MODE) {
3845                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ofuvcm_req_data: Active mode "
3846                     "not supported");
3847                 mutex_exit(&statep->state_mutex);
3848                 return (IBT_INVALID_PARAM);
3849         }
3850         ASSERT(statep->req_msgp);
3851 
3852         /*
3853          * Fill in the additional req message values reqired for
3854          * RTR transition.
3855          * Should the PSN be same as the active side??
3856          */
3857         req_msgp = (ibcm_req_msg_t *)statep->req_msgp;
3858         req_data->req_rnr_nak_time = ibcm_default_rnr_nak_time;
3859         req_data->req_path_mtu = req_msgp->req_mtu_plus >> 4;
3860         req_data->req_rq_psn = b2h32(req_msgp->req_starting_psn_plus) >> 8;
3861         mutex_exit(&statep->state_mutex);
3862         return (IBT_SUCCESS);
3863 }
3864 
3865 ibt_status_t
3866 ibt_ofuvcm_proceed(ibt_cm_event_type_t event, void *session_id,
3867     ibt_cm_status_t status, ibt_cm_proceed_reply_t *cm_event_data,
3868     void *priv_data, ibt_priv_data_len_t priv_data_len)
3869 {
3870         ibcm_state_data_t *statep = (ibcm_state_data_t *)session_id;
3871         ibt_status_t            ret;
3872 
3873         IBTF_DPRINTF_L3(cmlog, "ibt_ofuvcm_proceed chan 0x%p event %x "
3874             "status %x session_id %p", statep->channel, event, status,
3875             session_id);
3876 
3877         IBTF_DPRINTF_L5(cmlog, "ibt_ofuvcm_proceed chan 0x%p "
3878             "cm_event_data %p, priv_data %p priv_data_len %x",
3879             statep->channel, cm_event_data, priv_data, priv_data_len);
3880 
3881         /* validate session_id and status */
3882         if ((statep == NULL) || (status == IBT_CM_DEFER)) {
3883                 IBTF_DPRINTF_L2(cmlog, "ibt_ofuvcm_proceed : Invalid Args");
3884                 return (IBT_INVALID_PARAM);
3885         }
3886 
3887         if (event != IBT_CM_EVENT_REQ_RCV) {
3888                 IBTF_DPRINTF_L2(cmlog, "ibt_ofuvcm_proceed : only for REQ_RCV");
3889                 return (IBT_INVALID_PARAM);
3890         }
3891         mutex_enter(&statep->state_mutex);
3892         statep->is_this_ofuv_chan = B_TRUE;
3893         mutex_exit(&statep->state_mutex);
3894 
3895         ret = ibt_cm_proceed(event, session_id, status, cm_event_data,
3896             priv_data, priv_data_len);
3897         return (ret);
3898 }
3899 
3900 /*
3901  * Function:
3902  *      ibt_cm_proceed
3903  *
3904  * Verifies the arguments and dispatches the cm state machine processing
3905  * via taskq
3906  */
3907 
3908 ibt_status_t
3909 ibt_cm_proceed(ibt_cm_event_type_t event, void *session_id,
3910     ibt_cm_status_t status, ibt_cm_proceed_reply_t *cm_event_data,
3911     void *priv_data, ibt_priv_data_len_t priv_data_len)
3912 {
3913         ibcm_state_data_t *statep = (ibcm_state_data_t *)session_id;
3914         ibcm_proceed_targs_t    *proceed_targs;
3915         ibcm_proceed_error_t    proceed_error;
3916 
3917         IBTF_DPRINTF_L3(cmlog, "ibt_cm_proceed chan 0x%p event %x status %x "
3918             "session_id %p", statep->channel, event, status, session_id);
3919 
3920         IBTF_DPRINTF_L5(cmlog, "ibt_cm_proceed chan 0x%p cm_event_data %p, "
3921             "priv_data %p priv_data_len %x", statep->channel, cm_event_data,
3922             priv_data, priv_data_len);
3923 
3924         /* validate session_id and status */
3925         if ((statep == NULL) || (status == IBT_CM_DEFER)) {
3926                 IBTF_DPRINTF_L2(cmlog, "ibt_cm_proceed : Invalid Args");
3927                 return (IBT_INVALID_PARAM);
3928         }
3929 
3930         /* If priv data len specified, then priv_data cannot be NULL */
3931         if ((priv_data_len > 0) && (priv_data == NULL))
3932                 return (IBT_INVALID_PARAM);
3933 
3934         proceed_error = IBCM_PROCEED_INVALID_NONE;
3935 
3936         mutex_enter(&statep->state_mutex);
3937         if (event == IBT_CM_EVENT_REQ_RCV) {
3938 
3939                 if ((statep->state != IBCM_STATE_REQ_RCVD) &&
3940                     (statep->state != IBCM_STATE_MRA_SENT))
3941                         proceed_error = IBCM_PROCEED_INVALID_EVENT_STATE;
3942                 else if (priv_data_len > IBT_REP_PRIV_DATA_SZ)
3943                         proceed_error = IBCM_PROCEED_INVALID_PRIV_SZ;
3944 
3945         } else if (event == IBT_CM_EVENT_REP_RCV) {
3946                 if ((statep->state != IBCM_STATE_REP_RCVD) &&
3947                     (statep->state != IBCM_STATE_MRA_REP_SENT))
3948                         proceed_error = IBCM_PROCEED_INVALID_EVENT_STATE;
3949                 else if (priv_data_len > IBT_RTU_PRIV_DATA_SZ)
3950                         proceed_error = IBCM_PROCEED_INVALID_PRIV_SZ;
3951         } else if (event == IBT_CM_EVENT_LAP_RCV) {
3952                 if ((statep->ap_state != IBCM_AP_STATE_LAP_RCVD) &&
3953                     (statep->ap_state != IBCM_AP_STATE_MRA_LAP_SENT))
3954                         proceed_error = IBCM_PROCEED_INVALID_EVENT_STATE;
3955                 else if (priv_data_len > IBT_APR_PRIV_DATA_SZ)
3956                         proceed_error = IBCM_PROCEED_INVALID_PRIV_SZ;
3957         } else if (event == IBT_CM_EVENT_CONN_CLOSED) {
3958                 if (statep->state != IBCM_STATE_DREQ_RCVD)
3959                         proceed_error = IBCM_PROCEED_INVALID_EVENT_STATE;
3960                 else if (priv_data_len > IBT_DREP_PRIV_DATA_SZ)
3961                         proceed_error = IBCM_PROCEED_INVALID_PRIV_SZ;
3962         } else {
3963                         proceed_error = IBCM_PROCEED_INVALID_EVENT;
3964         }
3965 
3966         /* if there is an error, print an error message and return */
3967         if (proceed_error != IBCM_PROCEED_INVALID_NONE) {
3968                 mutex_exit(&statep->state_mutex);
3969                 if (proceed_error == IBCM_PROCEED_INVALID_EVENT_STATE) {
3970                         IBTF_DPRINTF_L2(cmlog, "ibt_cm_proceed : chan 0x%p"
3971                             "Invalid Event/State combination specified",
3972                             statep->channel);
3973                         return (IBT_INVALID_PARAM);
3974                 } else if (proceed_error == IBCM_PROCEED_INVALID_PRIV_SZ) {
3975                         IBTF_DPRINTF_L2(cmlog, "ibt_cm_proceed : chan 0x%p"
3976                             "Invalid Event/priv len combination specified",
3977                             statep->channel);
3978                         return (IBT_INVALID_PARAM);
3979                 } else if (proceed_error == IBCM_PROCEED_INVALID_EVENT) {
3980                         IBTF_DPRINTF_L2(cmlog, "ibt_cm_proceed : chan 0x%p"
3981                             "Invalid Event specified", statep->channel);
3982                         return (IBT_INVALID_PARAM);
3983                 } else {
3984                         ASSERT(proceed_error == IBCM_PROCEED_INVALID_LAP);
3985                         IBTF_DPRINTF_L2(cmlog, "ibt_cm_proceed : chan 0x%p"
3986                             "IBT_CM_EVENT_LAP_RCV not supported",
3987                             statep->channel);
3988                         /* UNTIL HCA DRIVER ENABLES AP SUPPORT, FAIL THE CALL */
3989                         return (IBT_APM_NOT_SUPPORTED);
3990                 }
3991         }
3992 
3993 
3994         /* wait until client's CM handler returns DEFER status back to CM */
3995 
3996         while (statep->clnt_proceed == IBCM_BLOCK) {
3997                 IBTF_DPRINTF_L5(cmlog, "ibt_cm_proceed : chan 0x%p blocked for "
3998                     "return of client's cm handler", statep->channel);
3999                 cv_wait(&statep->block_client_cv, &statep->state_mutex);
4000         }
4001 
4002         if (statep->clnt_proceed == IBCM_FAIL) {
4003                 mutex_exit(&statep->state_mutex);
4004                 IBTF_DPRINTF_L2(cmlog, "ibt_cm_proceed : chan 0x%p Failed as "
4005                     "client returned non-DEFER status from cm handler",
4006                     statep->channel);
4007                 return (IBT_CHAN_STATE_INVALID);
4008         }
4009 
4010         ASSERT(statep->clnt_proceed == IBCM_UNBLOCK);
4011         statep->clnt_proceed = IBCM_FAIL;
4012         mutex_exit(&statep->state_mutex);
4013 
4014         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*proceed_targs))
4015 
4016         /* the state machine processing is done in a separate thread */
4017 
4018         /* proceed_targs is freed in ibcm_proceed_via_taskq */
4019         proceed_targs = kmem_alloc(sizeof (ibcm_proceed_targs_t),
4020             KM_SLEEP);
4021 
4022         proceed_targs->event  = event;
4023         proceed_targs->status = status;
4024         proceed_targs->priv_data_len = priv_data_len;
4025 
4026         bcopy(priv_data, proceed_targs->priv_data, priv_data_len);
4027 
4028         proceed_targs->tst.rc.statep = statep;
4029         bcopy(cm_event_data, &proceed_targs->tst.rc.rc_cm_event_data,
4030             sizeof (ibt_cm_proceed_reply_t));
4031 
4032         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*proceed_targs))
4033 
4034         (void) taskq_dispatch(ibcm_taskq, ibcm_proceed_via_taskq,
4035             proceed_targs, TQ_SLEEP);
4036 
4037         return (IBT_SUCCESS);
4038 }
4039 
4040 /*
4041  * Function:
4042  *      ibcm_proceed_via_taskq
4043  *
4044  * Called from taskq, dispatched by ibt_cm_proceed
4045  * Completes the cm state processing for ibt_cm_proceed
4046  */
4047 void
4048 ibcm_proceed_via_taskq(void *targs)
4049 {
4050         ibcm_proceed_targs_t    *proceed_targs = (ibcm_proceed_targs_t *)targs;
4051         ibcm_state_data_t *statep = proceed_targs->tst.rc.statep;
4052         ibt_cm_reason_t reject_reason;
4053         uint8_t arej_len;
4054         ibcm_status_t response;
4055         ibcm_clnt_reply_info_t clnt_info;
4056 
4057         clnt_info.reply_event = &proceed_targs->tst.rc.rc_cm_event_data;
4058         clnt_info.priv_data = proceed_targs->priv_data;
4059         clnt_info.priv_data_len = proceed_targs->priv_data_len;
4060 
4061         IBTF_DPRINTF_L4(cmlog, "ibcm_proceed_via_taskq chan 0x%p targs %x",
4062             statep->channel, targs);
4063 
4064         if (proceed_targs->event == IBT_CM_EVENT_REQ_RCV) {
4065                 response =
4066                     ibcm_process_cep_req_cm_hdlr(statep, proceed_targs->status,
4067                     &clnt_info, &reject_reason, &arej_len,
4068                     (ibcm_req_msg_t *)statep->defer_cm_msg);
4069 
4070                 ibcm_handle_cep_req_response(statep, response, reject_reason,
4071                     arej_len);
4072 
4073         } else if (proceed_targs->event == IBT_CM_EVENT_REP_RCV) {
4074                 response =
4075                     ibcm_process_cep_rep_cm_hdlr(statep, proceed_targs->status,
4076                     &clnt_info, &reject_reason, &arej_len,
4077                     (ibcm_rep_msg_t *)statep->defer_cm_msg);
4078 
4079                 ibcm_handle_cep_rep_response(statep, response, reject_reason,
4080                     arej_len, (ibcm_rep_msg_t *)statep->defer_cm_msg);
4081 
4082         } else if (proceed_targs->event == IBT_CM_EVENT_LAP_RCV) {
4083                 ibcm_process_cep_lap_cm_hdlr(statep, proceed_targs->status,
4084                     &clnt_info, (ibcm_lap_msg_t *)statep->defer_cm_msg,
4085                     (ibcm_apr_msg_t *)IBCM_OUT_MSGP(statep->lapr_msg));
4086 
4087                 ibcm_post_apr_mad(statep);
4088 
4089         } else {
4090                 ASSERT(proceed_targs->event == IBT_CM_EVENT_CONN_CLOSED);
4091                 ibcm_handle_cep_dreq_response(statep, proceed_targs->priv_data,
4092                     proceed_targs->priv_data_len);
4093         }
4094 
4095         kmem_free(targs, sizeof (ibcm_proceed_targs_t));
4096 }
4097 
4098 /*
4099  * Function:
4100  *      ibt_cm_ud_proceed
4101  *
4102  * Verifies the arguments and dispatches the cm state machine processing
4103  * via taskq
4104  */
4105 ibt_status_t
4106 ibt_cm_ud_proceed(void *session_id, ibt_channel_hdl_t ud_channel,
4107     ibt_cm_status_t status, ibt_redirect_info_t *redirect_infop,
4108     void *priv_data, ibt_priv_data_len_t priv_data_len)
4109 {
4110         ibcm_ud_state_data_t *ud_statep = (ibcm_ud_state_data_t *)session_id;
4111         ibcm_proceed_targs_t    *proceed_targs;
4112         ibt_qp_query_attr_t     qp_attr;
4113         ibt_status_t            retval;
4114 
4115         IBTF_DPRINTF_L3(cmlog, "ibt_cm_ud_proceed session_id %p "
4116             "ud_channel %p ", session_id, ud_channel);
4117 
4118         IBTF_DPRINTF_L4(cmlog, "ibt_cm_ud_proceed status %x priv_data %p "
4119             "priv_data_len %x",  status, priv_data, priv_data_len);
4120 
4121         /* validate session_id and status */
4122         if ((ud_statep == NULL) || (status == IBT_CM_DEFER)) {
4123                 IBTF_DPRINTF_L2(cmlog, "ibt_cm_ud_proceed : Invalid Args");
4124                 return (IBT_INVALID_PARAM);
4125         }
4126 
4127         /* If priv data len specified, then priv_data cannot be NULL */
4128         if ((priv_data_len > 0) && (priv_data == NULL))
4129                 return (IBT_INVALID_PARAM);
4130 
4131         if (priv_data_len > IBT_SIDR_REP_PRIV_DATA_SZ)
4132                 return (IBT_INVALID_PARAM);
4133 
4134         /* retrieve qpn and qkey from ud channel */
4135 
4136         /* validate event and statep's state */
4137 
4138         if (status == IBT_CM_ACCEPT) {
4139                 retval = ibt_query_qp(ud_channel, &qp_attr);
4140                 if ((retval != IBT_SUCCESS) ||
4141                     (qp_attr.qp_info.qp_trans != IBT_UD_SRV)) {
4142                         IBTF_DPRINTF_L2(cmlog, "ibt_cm_ud_proceed: "
4143                             "Failed to retrieve QPN from the channel: %d",
4144                             retval);
4145                         return (IBT_INVALID_PARAM);
4146                 }
4147         }
4148 
4149 
4150         mutex_enter(&ud_statep->ud_state_mutex);
4151 
4152         if (ud_statep->ud_state != IBCM_STATE_SIDR_REQ_RCVD) {
4153                 mutex_exit(&ud_statep->ud_state_mutex);
4154                 IBTF_DPRINTF_L2(cmlog, "ibt_cm_ud_proceed : Invalid State "
4155                     "specified");
4156                 return (IBT_INVALID_PARAM);
4157         }
4158 
4159         /* wait until client's CM handler returns DEFER status back to CM */
4160 
4161         while (ud_statep->ud_clnt_proceed == IBCM_BLOCK) {
4162                 IBTF_DPRINTF_L5(cmlog, "ibt_cm_ud_proceed : Blocked for return"
4163                     " of client's ud cm handler");
4164                 cv_wait(&ud_statep->ud_block_client_cv,
4165                     &ud_statep->ud_state_mutex);
4166         }
4167 
4168         if (ud_statep->ud_clnt_proceed == IBCM_FAIL) {
4169                 mutex_exit(&ud_statep->ud_state_mutex);
4170                 IBTF_DPRINTF_L2(cmlog, "ibt_cm_ud_proceed : Failed as client "
4171                     "returned non-DEFER status from cm handler");
4172                 return (IBT_INVALID_PARAM);
4173         }
4174 
4175         ASSERT(ud_statep->ud_clnt_proceed == IBCM_UNBLOCK);
4176         ud_statep->ud_clnt_proceed = IBCM_FAIL;
4177         mutex_exit(&ud_statep->ud_state_mutex);
4178 
4179         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*proceed_targs))
4180 
4181         /* the state machine processing is done in a separate thread */
4182 
4183         /* proceed_targs is freed in ibcm_proceed_via_taskq */
4184         proceed_targs = kmem_zalloc(sizeof (ibcm_proceed_targs_t),
4185             KM_SLEEP);
4186 
4187         proceed_targs->status = status;
4188         proceed_targs->priv_data_len = priv_data_len;
4189 
4190         bcopy(priv_data, proceed_targs->priv_data, priv_data_len);
4191 
4192         if (status == IBT_CM_ACCEPT) {
4193                 proceed_targs->tst.ud.ud_qkey =
4194                     qp_attr.qp_info.qp_transport.ud.ud_qkey;
4195                 proceed_targs->tst.ud.ud_qpn = qp_attr.qp_qpn;
4196         }
4197 
4198         proceed_targs->tst.ud.ud_statep = ud_statep;
4199 
4200         /* copy redirect info based on status */
4201         if (status == IBT_CM_REDIRECT)
4202                 bcopy(redirect_infop, &proceed_targs->tst.ud.ud_redirect_info,
4203                     sizeof (ibt_redirect_info_t));
4204 
4205         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*proceed_targs))
4206 
4207         (void) taskq_dispatch(ibcm_taskq, ibcm_ud_proceed_via_taskq,
4208             proceed_targs, TQ_SLEEP);
4209 
4210         return (IBT_SUCCESS);
4211 }
4212 
4213 /*
4214  * Function:
4215  *      ibcm_ud_proceed_via_taskq
4216  *
4217  * Called from taskq, dispatched by ibt_cm_ud_proceed
4218  * Completes the cm state processing for ibt_cm_ud_proceed
4219  */
4220 void
4221 ibcm_ud_proceed_via_taskq(void *targs)
4222 {
4223         ibcm_proceed_targs_t    *proceed_targs = (ibcm_proceed_targs_t *)targs;
4224         ibcm_ud_state_data_t    *ud_statep = proceed_targs->tst.ud.ud_statep;
4225         ibcm_ud_clnt_reply_info_t ud_clnt_info;
4226         ibt_sidr_status_t       sidr_status;
4227 
4228         IBTF_DPRINTF_L4(cmlog, "ibcm_ud_proceed_via_taskq(%p)", targs);
4229 
4230         ud_clnt_info.ud_qpn  = proceed_targs->tst.ud.ud_qpn;
4231         ud_clnt_info.ud_qkey  = proceed_targs->tst.ud.ud_qkey;
4232         ud_clnt_info.priv_data = proceed_targs->priv_data;
4233         ud_clnt_info.priv_data_len = proceed_targs->priv_data_len;
4234         ud_clnt_info.redirect_infop = &proceed_targs->tst.ud.ud_redirect_info;
4235 
4236         /* validate event and statep's state */
4237         ibcm_process_sidr_req_cm_hdlr(ud_statep, proceed_targs->status,
4238             &ud_clnt_info, &sidr_status,
4239             (ibcm_sidr_rep_msg_t *)IBCM_OUT_MSGP(ud_statep->ud_stored_msg));
4240 
4241         ibcm_post_sidr_rep_mad(ud_statep, sidr_status);
4242 
4243         /* decr the statep ref cnt incremented in ibcm_process_sidr_req_msg */
4244         mutex_enter(&ud_statep->ud_state_mutex);
4245         IBCM_UD_REF_CNT_DECR(ud_statep);
4246         mutex_exit(&ud_statep->ud_state_mutex);
4247 
4248         kmem_free(targs, sizeof (ibcm_proceed_targs_t));
4249 }
4250 
4251 /*
4252  * Function:
4253  *      ibt_set_alt_path
4254  * Input:
4255  *      channel         Channel handle returned from ibt_alloc_rc_channel(9F).
4256  *
4257  *      mode            Execute in blocking or non blocking mode.
4258  *
4259  *      alt_path        A pointer to an ibt_alt_path_info_t as returned from an
4260  *                      ibt_get_alt_path(9F) call that specifies the new
4261  *                      alternate path.
4262  *
4263  *      priv_data       A pointer to a buffer specified by caller for the
4264  *                      private data in the outgoing CM Load Alternate Path
4265  *                      (LAP) message sent to the remote host. This can be NULL
4266  *                      if no private data is available to communicate to the
4267  *                      remote node.
4268  *
4269  *      priv_data_len   Length of valid data in priv_data, this should be less
4270  *                      than or equal to IBT_LAP_PRIV_DATA_SZ.
4271  *
4272  * Output:
4273  *      ret_args        If called in blocking mode, points to a return argument
4274  *                      structure of type ibt_ap_returns_t.
4275  *
4276  * Returns:
4277  *      IBT_SUCCESS on Success else appropriate error.
4278  * Description:
4279  *      Load the specified alternate path. Causes the CM to send an LAP message
4280  *      to the remote node.
4281  *      Can only be called on a previously opened RC channel.
4282  */
4283 ibt_status_t
4284 ibt_set_alt_path(ibt_channel_hdl_t channel, ibt_execution_mode_t mode,
4285     ibt_alt_path_info_t *alt_path, void *priv_data,
4286     ibt_priv_data_len_t priv_data_len, ibt_ap_returns_t *ret_args)
4287 {
4288         ibmf_handle_t           ibmf_hdl;
4289         ibt_status_t            status = IBT_SUCCESS;
4290         ibcm_lap_msg_t          *lap_msgp;
4291         ibcm_hca_info_t         *hcap;
4292         ibcm_state_data_t       *statep;
4293         uint8_t                 port_no;
4294         ib_lid_t                alternate_slid;
4295         ibt_priv_data_len_t     len;
4296         ib_lid_t                base_lid;
4297         boolean_t               alt_grh;
4298 
4299         IBTF_DPRINTF_L3(cmlog, "ibt_set_alt_path(%p, %x, %p, %p, %x, %p)",
4300             channel, mode, alt_path, priv_data, priv_data_len, ret_args);
4301 
4302         /* validate channel */
4303         if (IBCM_INVALID_CHANNEL(channel)) {
4304                 IBTF_DPRINTF_L2(cmlog, "ibt_set_alt_path: invalid channel");
4305                 return (IBT_CHAN_HDL_INVALID);
4306         }
4307 
4308         if (ibtl_cm_get_chan_type(channel) != IBT_RC_SRV) {
4309                 IBTF_DPRINTF_L2(cmlog, "ibt_set_alt_path: "
4310                     "Invalid Channel type: Applicable only to RC Channel");
4311                 return (IBT_CHAN_SRV_TYPE_INVALID);
4312         }
4313 
4314         if (mode == IBT_NONBLOCKING) {
4315                 if (ret_args != NULL) {
4316                         IBTF_DPRINTF_L2(cmlog, "ibt_set_alt_path: "
4317                             "ret_args should be NULL when called in "
4318                             "non-blocking mode");
4319                         return (IBT_INVALID_PARAM);
4320                 }
4321         } else if (mode == IBT_BLOCKING) {
4322                 if (ret_args == NULL) {
4323                         IBTF_DPRINTF_L2(cmlog, "ibt_set_alt_path: "
4324                             "ret_args should be Non-NULL when called in "
4325                             "blocking mode");
4326                         return (IBT_INVALID_PARAM);
4327                 }
4328                 if (ret_args->ap_priv_data_len > IBT_APR_PRIV_DATA_SZ) {
4329                         IBTF_DPRINTF_L2(cmlog, "ibt_set_alt_path: "
4330                             "expected private data length is too large");
4331                         return (IBT_INVALID_PARAM);
4332                 }
4333                 if ((ret_args->ap_priv_data_len > 0) &&
4334                     (ret_args->ap_priv_data == NULL)) {
4335                         IBTF_DPRINTF_L2(cmlog, "ibt_set_alt_path: "
4336                             "apr_priv_data_len > 0, but apr_priv_data NULL");
4337                         return (IBT_INVALID_PARAM);
4338                 }
4339         } else { /* any other mode is not valid for ibt_set_alt_path */
4340                 IBTF_DPRINTF_L2(cmlog, "ibt_set_alt_path: "
4341                     "invalid mode %x specified", mode);
4342                 return (IBT_INVALID_PARAM);
4343         }
4344 
4345         if ((port_no = alt_path->ap_alt_cep_path.cep_hca_port_num) == 0)
4346                 return (IBT_INVALID_PARAM);
4347 
4348         /* get the statep */
4349         IBCM_GET_CHAN_PRIVATE(channel, statep);
4350         if (statep == NULL) {
4351                 IBTF_DPRINTF_L2(cmlog, "ibt_set_alt_path: statep NULL");
4352                 return (IBT_CM_FAILURE);
4353         }
4354 
4355         mutex_enter(&statep->state_mutex);
4356         IBCM_RELEASE_CHAN_PRIVATE(channel);
4357         IBCM_REF_CNT_INCR(statep);
4358         mutex_exit(&statep->state_mutex);
4359 
4360         IBTF_DPRINTF_L4(cmlog, "ibt_set_alt_path: statep %p", statep);
4361 
4362         hcap = statep->hcap;
4363 
4364         /* HCA must have been in active state. If not, it's a client bug */
4365         if (!IBCM_ACCESS_HCA_OK(hcap))
4366                 IBTF_DPRINTF_L2(cmlog, "ibt_set_alt_path: hca in error state");
4367 
4368         ASSERT(statep->cm_handler != NULL);
4369 
4370         /* Check Alternate port */
4371         status = ibt_get_port_state_byguid(hcap->hca_guid, port_no, NULL,
4372             &base_lid);
4373         if (status != IBT_SUCCESS) {
4374                 IBTF_DPRINTF_L2(cmlog, "ibt_set_alt_path: "
4375                     "ibt_get_port_state_byguid status %d ", status);
4376                 mutex_enter(&statep->state_mutex);
4377                 IBCM_REF_CNT_DECR(statep);
4378                 mutex_exit(&statep->state_mutex);
4379                 return (status);
4380         }
4381 
4382         if ((hcap->hca_port_info[port_no - 1].port_ibmf_hdl == NULL) &&
4383             ((status = ibcm_hca_reinit_port(hcap, port_no - 1))
4384             != IBT_SUCCESS)) {
4385                 IBTF_DPRINTF_L2(cmlog, "ibt_set_alt_path: "
4386                     "ibmf reg or callback setup failed during re-initialize");
4387                 mutex_enter(&statep->state_mutex);
4388                 IBCM_REF_CNT_DECR(statep);
4389                 mutex_exit(&statep->state_mutex);
4390                 return (status);
4391         }
4392 
4393         ibmf_hdl = statep->stored_reply_addr.ibmf_hdl;
4394 
4395         alternate_slid = base_lid +
4396             alt_path->ap_alt_cep_path.cep_adds_vect.av_src_path;
4397 
4398         IBTF_DPRINTF_L4(cmlog, "ibt_set_alt_path: alternate SLID = %x",
4399             h2b16(alternate_slid));
4400 
4401         ibcm_lapr_enter();      /* limit how many run simultaneously */
4402 
4403         /* Allocate MAD for LAP */
4404         if (statep->lapr_msg == NULL)
4405                 if ((status = ibcm_alloc_out_msg(ibmf_hdl, &statep->lapr_msg,
4406                     MAD_METHOD_SEND)) != IBT_SUCCESS) {
4407                         ibcm_lapr_exit();
4408                         IBTF_DPRINTF_L2(cmlog, "ibt_set_alt_path: "
4409                             "chan 0x%p ibcm_alloc_out_msg failed", channel);
4410                         mutex_enter(&statep->state_mutex);
4411                         IBCM_REF_CNT_DECR(statep);
4412                         mutex_exit(&statep->state_mutex);
4413                         return (status);
4414                 }
4415 
4416         mutex_enter(&statep->state_mutex);
4417 
4418         IBTF_DPRINTF_L4(cmlog, "ibt_set_alt_path: connection state is"
4419             " %x", statep->state);
4420 
4421         /* Check state */
4422         if ((statep->state != IBCM_STATE_ESTABLISHED) ||
4423             (statep->ap_state != IBCM_AP_STATE_IDLE)) {
4424                 IBCM_REF_CNT_DECR(statep);
4425                 mutex_exit(&statep->state_mutex);
4426                 (void) ibcm_free_out_msg(ibmf_hdl, &statep->lapr_msg);
4427                 ibcm_lapr_exit();
4428                 return (IBT_CHAN_STATE_INVALID);
4429         } else {
4430                 /* Set to LAP Sent state */
4431                 statep->ap_state = IBCM_AP_STATE_LAP_SENT;
4432                 statep->ap_done = B_FALSE;
4433                 statep->remaining_retry_cnt = statep->max_cm_retries;
4434                 statep->timer_stored_state = statep->state;
4435                 statep->timer_stored_ap_state = statep->ap_state;
4436                 IBCM_REF_CNT_INCR(statep); /* for ibcm_post_lap_complete */
4437         }
4438 
4439         mutex_exit(&statep->state_mutex);
4440 
4441         /* No more failure returns below */
4442 
4443         /* Allocate MAD for LAP */
4444         IBTF_DPRINTF_L5(cmlog, "ibt_set_alt_path:"
4445             " statep's mad addr = 0x%p", IBCM_OUT_HDRP(statep->lapr_msg));
4446 
4447         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lap_msgp))
4448 
4449         lap_msgp = (ibcm_lap_msg_t *)IBCM_OUT_MSGP(statep->lapr_msg);
4450 
4451         lap_msgp->lap_alt_l_port_lid = h2b16(alternate_slid);
4452         lap_msgp->lap_alt_r_port_lid =
4453             h2b16(alt_path->ap_alt_cep_path.cep_adds_vect.av_dlid);
4454 
4455         /* Fill in remote port gid */
4456         lap_msgp->lap_alt_r_port_gid.gid_prefix =
4457             h2b64(alt_path->ap_alt_cep_path.cep_adds_vect.av_dgid.gid_prefix);
4458         lap_msgp->lap_alt_r_port_gid.gid_guid =
4459             h2b64(alt_path->ap_alt_cep_path.cep_adds_vect.av_dgid.gid_guid);
4460 
4461         /* Fill in local port gid */
4462         lap_msgp->lap_alt_l_port_gid.gid_prefix =
4463             h2b64(alt_path->ap_alt_cep_path.cep_adds_vect.av_sgid.gid_prefix);
4464         lap_msgp->lap_alt_l_port_gid.gid_guid =
4465             h2b64(alt_path->ap_alt_cep_path.cep_adds_vect.av_sgid.gid_guid);
4466 
4467         alt_grh = alt_path->ap_alt_cep_path.cep_adds_vect.av_send_grh;
4468 
4469         /* alternate_flow_label, and alternate srate, alternate traffic class */
4470         lap_msgp->lap_alt_srate_plus =
4471             alt_path->ap_alt_cep_path.cep_adds_vect.av_srate & 0x3f;
4472         lap_msgp->lap_alt_flow_label_plus = h2b32(((alt_grh == B_TRUE) ?
4473             (alt_path->ap_alt_cep_path.cep_adds_vect.av_flow << 12) : 0) |
4474             alt_path->ap_alt_cep_path.cep_adds_vect.av_tclass);
4475 
4476         /* Alternate hop limit, service level */
4477         lap_msgp->lap_alt_hop_limit = (alt_grh == B_TRUE) ?
4478             alt_path->ap_alt_cep_path.cep_adds_vect.av_hop : 1;
4479         lap_msgp->lap_alt_sl_plus =
4480             alt_path->ap_alt_cep_path.cep_adds_vect.av_srvl << 4 |
4481             ((alt_grh == B_FALSE) ? 0x8 : 0);
4482 
4483         lap_msgp->lap_alt_local_acktime_plus = ibt_usec2ib(
4484             (2 * statep->rc_alt_pkt_lt) +
4485             ibt_ib2usec(hcap->hca_ack_delay)) << 3;
4486 
4487         lap_msgp->lap_local_comm_id = h2b32(statep->local_comid);
4488         lap_msgp->lap_remote_comm_id = h2b32(statep->remote_comid);
4489 
4490         lap_msgp->lap_remote_qpn_eecn_plus =
4491             h2b32((statep->remote_qpn << 8) |
4492             ibt_usec2ib(ibcm_remote_response_time) << 3);
4493 
4494         len = min(priv_data_len, IBT_LAP_PRIV_DATA_SZ);
4495         if ((len > 0) && priv_data) {
4496                 bcopy(priv_data, lap_msgp->lap_private_data, len);
4497         }
4498 
4499         /* only rc_alt_pkt_lt and ap_return_data fields are initialized */
4500         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
4501 
4502         statep->rc_alt_pkt_lt = ibt_ib2usec(alt_path->ap_alt_pkt_lt);
4503 
4504         /* return_data is filled up in the state machine code */
4505         statep->ap_return_data = ret_args;
4506 
4507         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*statep))
4508 
4509         IBCM_OUT_HDRP(statep->lapr_msg)->AttributeID =
4510             h2b16(IBCM_INCOMING_LAP + IBCM_ATTR_BASE_ID);
4511 
4512         IBCM_OUT_HDRP(statep->lapr_msg)->TransactionID =
4513             h2b64(ibcm_generate_tranid(IBCM_INCOMING_LAP, statep->local_comid,
4514             0));
4515         IBTF_DPRINTF_L3(cmlog, "ibt_set_alt_path: statep %p, tid %llx",
4516             statep, IBCM_OUT_HDRP(statep->lapr_msg)->TransactionID);
4517 
4518         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*lap_msgp))
4519 
4520         /* Send LAP */
4521         ibcm_post_rc_mad(statep, statep->lapr_msg, ibcm_post_lap_complete,
4522             statep);
4523 
4524         mutex_enter(&statep->state_mutex);
4525 
4526         if (mode == IBT_BLOCKING) {
4527                 IBTF_DPRINTF_L4(cmlog, "ibt_set_alt_path: blocking");
4528 
4529                 /* wait for APR */
4530                 while (statep->ap_done != B_TRUE) {
4531                         cv_wait(&statep->block_client_cv,
4532                             &statep->state_mutex);
4533                 }
4534 
4535                 IBTF_DPRINTF_L4(cmlog, "ibt_set_alt_path: done blocking");
4536 
4537                 /*
4538                  * In the case that ibt_set_alt_path fails,
4539                  * change retval to IBT_CM_FAILURE
4540                  */
4541                 if (statep->ap_return_data->ap_status != IBT_CM_AP_LOADED)
4542                         status = IBT_CM_FAILURE;
4543 
4544         }
4545 
4546         /* decrement the ref-count before leaving here */
4547         IBCM_REF_CNT_DECR(statep);
4548 
4549         mutex_exit(&statep->state_mutex);
4550 
4551         ibcm_lapr_exit();
4552 
4553         /* If this message isn't seen then ibt_set_alt_path failed */
4554         IBTF_DPRINTF_L4(cmlog, "ibt_set_alt_path: done");
4555 
4556         return (status);
4557 }
4558 
4559 
4560 #ifdef DEBUG
4561 
4562 /*
4563  * ibcm_query_classport_info:
4564  *      Query classportinfo
4565  *
4566  * INPUTS:
4567  *      channel         - Channel that is associated with a statep
4568  *
4569  * RETURN VALUE: NONE
4570  * This function is currently used to generate a valid get method classport
4571  * info, and test CM functionality. There is no ibtl client interface to
4572  * generate a classportinfo. It is possible that CM may use classportinfo
4573  * from other nodes in the future, and most of the code below could be re-used.
4574  */
4575 void
4576 ibcm_query_classport_info(ibt_channel_hdl_t channel)
4577 {
4578         ibcm_state_data_t       *statep;
4579         ibmf_msg_t              *msgp;
4580 
4581         IBTF_DPRINTF_L3(cmlog, "ibcm_query_classport_info(%p)", channel);
4582 
4583         /* validate channel, first */
4584         if (IBCM_INVALID_CHANNEL(channel)) {
4585                 IBTF_DPRINTF_L2(cmlog, "ibcm_query_classport_info: "
4586                     "invalid channel (%p)", channel);
4587                 return;
4588         }
4589 
4590         /* get the statep */
4591         IBCM_GET_CHAN_PRIVATE(channel, statep);
4592 
4593         /*
4594          * This can happen, if the statep is already gone by a DREQ from
4595          * the remote side
4596          */
4597         if (statep == NULL) {
4598                 IBTF_DPRINTF_L2(cmlog, "ibcm_query_classport_info: "
4599                     "statep NULL");
4600                 return;
4601         }
4602 
4603         mutex_enter(&statep->state_mutex);
4604         IBCM_RELEASE_CHAN_PRIVATE(channel);
4605         IBCM_REF_CNT_INCR(statep);
4606         mutex_exit(&statep->state_mutex);
4607 
4608         /* Debug/test code, so don't care about return status */
4609         (void) ibcm_alloc_out_msg(statep->stored_reply_addr.ibmf_hdl, &msgp,
4610             MAD_METHOD_GET);
4611 
4612         IBCM_OUT_HDRP(msgp)->TransactionID = h2b64(ibcm_generate_tranid(
4613             MAD_ATTR_ID_CLASSPORTINFO, statep->local_comid, 0));
4614         IBCM_OUT_HDRP(msgp)->AttributeID = h2b16(MAD_ATTR_ID_CLASSPORTINFO);
4615 
4616         (void) ibcm_post_mad(msgp, &statep->stored_reply_addr, NULL, NULL);
4617 
4618         IBTF_DPRINTF_L3(cmlog, "ibcm_query_classport_info(%p) "
4619             "Get method MAD posted ", channel);
4620 
4621         (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl, &msgp);
4622 
4623         mutex_enter(&statep->state_mutex);
4624         IBCM_REF_CNT_DECR(statep);
4625         mutex_exit(&statep->state_mutex);
4626 }
4627 
4628 static void
4629 ibcm_print_reply_addr(ibt_channel_hdl_t channel, ibcm_mad_addr_t *cm_reply_addr)
4630 {
4631         IBTF_DPRINTF_L4(cmlog, "ibcm_print_reply_addr: chan 0x%p, SLID %x, "
4632             "DLID %x", channel, cm_reply_addr->rcvd_addr.ia_local_lid,
4633             cm_reply_addr->rcvd_addr.ia_remote_lid);
4634 
4635         IBTF_DPRINTF_L4(cmlog, "ibcm_print_reply_addr: QKEY %x, PKEY %x, "
4636             "RQPN %x SL %x", cm_reply_addr->rcvd_addr.ia_q_key,
4637             cm_reply_addr->rcvd_addr.ia_p_key,
4638             cm_reply_addr->rcvd_addr.ia_remote_qno,
4639             cm_reply_addr->rcvd_addr.ia_service_level);
4640 
4641         IBTF_DPRINTF_L4(cmlog, "ibcm_print_reply_addr: CM SGID %llX:%llX ",
4642             cm_reply_addr->grh_hdr.ig_sender_gid.gid_prefix,
4643             cm_reply_addr->grh_hdr.ig_sender_gid.gid_guid);
4644 
4645         IBTF_DPRINTF_L4(cmlog, "ibcm_print_reply_addr: CM DGID %llX:%llX",
4646             cm_reply_addr->grh_hdr.ig_recver_gid.gid_prefix,
4647             cm_reply_addr->grh_hdr.ig_recver_gid.gid_guid);
4648 
4649         IBTF_DPRINTF_L4(cmlog, "ibcm_print_reply_addr: CM FL %x TC %x HL %x",
4650             cm_reply_addr->grh_hdr.ig_flow_label,
4651             cm_reply_addr->grh_hdr.ig_tclass,
4652             cm_reply_addr->grh_hdr.ig_hop_limit);
4653 }
4654 
4655 #endif
4656 
4657 /* For MCG List search */
4658 typedef struct ibcm_mcg_list_s {
4659         struct ibcm_mcg_list_s  *ml_next;
4660         ib_gid_t                ml_sgid;
4661         ib_gid_t                ml_mgid;
4662         ib_pkey_t               ml_pkey;
4663         ib_qkey_t               ml_qkey;
4664         uint_t                  ml_refcnt;
4665         uint8_t                 ml_jstate;
4666 } ibcm_mcg_list_t;
4667 
4668 ibcm_mcg_list_t *ibcm_mcglist = NULL;
4669 
4670 _NOTE(MUTEX_PROTECTS_DATA(ibcm_mcglist_lock, ibcm_mcg_list_s))
4671 _NOTE(MUTEX_PROTECTS_DATA(ibcm_mcglist_lock, ibcm_mcglist))
4672 
4673 typedef struct ibcm_join_mcg_tqarg_s {
4674         ib_gid_t                rgid;
4675         ibt_mcg_attr_t          mcg_attr;
4676         ibt_mcg_info_t          *mcg_infop;
4677         ibt_mcg_handler_t       func;
4678         void                    *arg;
4679 } ibcm_join_mcg_tqarg_t;
4680 
4681 _NOTE(READ_ONLY_DATA(ibcm_join_mcg_tqarg_s))
4682 
4683 void
4684 ibcm_add_incr_mcg_entry(sa_mcmember_record_t *mcg_req,
4685     sa_mcmember_record_t *mcg_resp)
4686 {
4687         ibcm_mcg_list_t *new = NULL;
4688         ibcm_mcg_list_t *head = NULL;
4689 
4690         IBTF_DPRINTF_L3(cmlog, "ibcm_add_incr_mcg_entry: MGID %llX:%llX"
4691             "\n SGID %llX:%llX, JState %X)", mcg_req->MGID.gid_prefix,
4692             mcg_req->MGID.gid_guid, mcg_req->PortGID.gid_prefix,
4693             mcg_req->PortGID.gid_guid, mcg_req->JoinState);
4694 
4695         mutex_enter(&ibcm_mcglist_lock);
4696         head = ibcm_mcglist;
4697 
4698         while (head != NULL) {
4699                 if ((head->ml_mgid.gid_guid == mcg_resp->MGID.gid_guid) &&
4700                     (head->ml_mgid.gid_prefix == mcg_resp->MGID.gid_prefix) &&
4701                     (head->ml_sgid.gid_guid == mcg_resp->PortGID.gid_guid)) {
4702                         /* Increment the count */
4703                         head->ml_refcnt++;
4704                         /* OR the join_state value, we need this during leave */
4705                         head->ml_jstate |= mcg_req->JoinState;
4706 
4707                         IBTF_DPRINTF_L3(cmlog, "ibcm_add_incr_mcg_entry: Entry "
4708                             "FOUND: refcnt %d JState %X", head->ml_refcnt,
4709                             head->ml_jstate);
4710 
4711                         mutex_exit(&ibcm_mcglist_lock);
4712                         return;
4713                 }
4714                 head = head->ml_next;
4715         }
4716         mutex_exit(&ibcm_mcglist_lock);
4717 
4718         IBTF_DPRINTF_L3(cmlog, "ibcm_add_incr_mcg_entry: Create NEW Entry ");
4719 
4720         /* If we are here, either list is empty or match couldn't be found */
4721         new = kmem_zalloc(sizeof (ibcm_mcg_list_t), KM_SLEEP);
4722 
4723         mutex_enter(&ibcm_mcglist_lock);
4724         /* Initialize the fields */
4725         new->ml_sgid = mcg_resp->PortGID;
4726         new->ml_mgid = mcg_resp->MGID;
4727         new->ml_qkey = mcg_req->Q_Key;
4728         new->ml_pkey = mcg_req->P_Key;
4729         new->ml_refcnt = 1; /* As this is the first entry */
4730         new->ml_jstate = mcg_req->JoinState;
4731         new->ml_next = NULL;
4732 
4733         new->ml_next = ibcm_mcglist;
4734         ibcm_mcglist = new;
4735         mutex_exit(&ibcm_mcglist_lock);
4736 }
4737 
4738 /*
4739  * ibcm_del_decr_mcg_entry
4740  *
4741  * Return value:
4742  * IBCM_SUCCESS         Entry found and ref_cnt is now zero. So go-ahead and
4743  *                      leave the MCG group. The return arg *jstate will have
4744  *                      a valid join_state value that needed to be used by
4745  *                      xxx_leave_mcg().
4746  * IBCM_LOOKUP_EXISTS   Entry found and ref_cnt is decremented but is NOT zero.
4747  *                      So do not leave the MCG group yet.
4748  * IBCM_LOOKUP_FAIL     Entry is NOT found.
4749  */
4750 ibcm_status_t
4751 ibcm_del_decr_mcg_entry(sa_mcmember_record_t *mcg_req, uint8_t *jstate)
4752 {
4753         ibcm_mcg_list_t *head, *prev;
4754 
4755         IBTF_DPRINTF_L3(cmlog, "ibcm_del_decr_mcg_entry: MGID %llX:%llX"
4756             "\n SGID %llX:%llX, JState %X)", mcg_req->MGID.gid_prefix,
4757             mcg_req->MGID.gid_guid, mcg_req->PortGID.gid_prefix,
4758             mcg_req->PortGID.gid_guid, mcg_req->JoinState);
4759 
4760         *jstate = 0;
4761 
4762         mutex_enter(&ibcm_mcglist_lock);
4763         head = ibcm_mcglist;
4764         prev = NULL;
4765 
4766         while (head != NULL) {
4767                 if ((head->ml_mgid.gid_guid == mcg_req->MGID.gid_guid) &&
4768                     (head->ml_mgid.gid_prefix == mcg_req->MGID.gid_prefix) &&
4769                     (head->ml_sgid.gid_guid == mcg_req->PortGID.gid_guid)) {
4770                         if (!(head->ml_jstate & mcg_req->JoinState)) {
4771                                 IBTF_DPRINTF_L2(cmlog, "ibcm_del_decr_mcg_entry"
4772                                     ": JoinState mismatch %X %X)",
4773                                     head->ml_jstate, mcg_req->JoinState);
4774                         }
4775                         /* Decrement the count */
4776                         head->ml_refcnt--;
4777 
4778                         if (head->ml_refcnt == 0) {
4779                                 *jstate = head->ml_jstate;
4780 
4781                                 IBTF_DPRINTF_L3(cmlog, "ibcm_del_decr_mcg_entry"
4782                                     ": refcnt is ZERO, so delete the entry ");
4783                                 if ((head == ibcm_mcglist) || (prev == NULL)) {
4784                                         ibcm_mcglist = head->ml_next;
4785                                 } else if (prev != NULL) {
4786                                         prev->ml_next = head->ml_next;
4787                                 }
4788                                 mutex_exit(&ibcm_mcglist_lock);
4789 
4790                                 kmem_free(head, sizeof (ibcm_mcg_list_t));
4791                                 return (IBCM_SUCCESS);
4792                         }
4793                         mutex_exit(&ibcm_mcglist_lock);
4794                         return (IBCM_LOOKUP_EXISTS);
4795                 }
4796                 prev = head;
4797                 head = head->ml_next;
4798         }
4799         mutex_exit(&ibcm_mcglist_lock);
4800 
4801         /*
4802          * If we are here, something went wrong, we don't have the entry
4803          * for that MCG being joined.
4804          */
4805         IBTF_DPRINTF_L2(cmlog, "ibcm_del_decr_mcg_entry: Match NOT "
4806             "Found ");
4807 
4808         return (IBCM_LOOKUP_FAIL);
4809 }
4810 
4811 
4812 /*
4813  * Function:
4814  *      ibt_join_mcg
4815  * Input:
4816  *      rgid            The request GID that defines the HCA port from which a
4817  *                      contact to SA Access is performed to add the specified
4818  *                      endport GID ((mcg_attr->mc_pgid) to a multicast group.
4819  *                      If mcg_attr->mc_pgid is null, then this (rgid) will be
4820  *                      treated as endport GID that is to be added to the
4821  *                      multicast group.
4822  *
4823  *      mcg_attr        A pointer to an ibt_mcg_attr_t structure that defines
4824  *                      the attributes of the desired multicast group to be
4825  *                      created or joined.
4826  *
4827  *      func            NULL or a pointer to a function to call when
4828  *                      ibt_join_mcg() completes. If 'func' is not NULL then
4829  *                      ibt_join_mcg() will return as soon as possible after
4830  *                      initiating the multicast group join/create process.
4831  *                      'func' is then called when the process completes.
4832  *
4833  *      arg             Argument to the 'func'.
4834  *
4835  * Output:
4836  *      mcg_info_p      A pointer to the ibt_mcg_info_t structure, allocated
4837  *                      by the caller, where the attributes of the created or
4838  *                      joined multicast group are copied.
4839  * Returns:
4840  *      IBT_SUCCESS
4841  *      IBT_INVALID_PARAM
4842  *      IBT_MCG_RECORDS_NOT_FOUND
4843  *      IBT_INSUFF_RESOURCE
4844  * Description:
4845  *      Join a multicast group.  The first full member "join" causes the MCG
4846  *      to be created.
4847  */
4848 ibt_status_t
4849 ibt_join_mcg(ib_gid_t rgid, ibt_mcg_attr_t *mcg_attr,
4850     ibt_mcg_info_t *mcg_info_p, ibt_mcg_handler_t func, void  *arg)
4851 {
4852         ibcm_join_mcg_tqarg_t   *mcg_tq;
4853         int                     flag = ((func == NULL) ? KM_SLEEP : KM_NOSLEEP);
4854 
4855         IBTF_DPRINTF_L3(cmlog, "ibt_join_mcg(%llX:%llX, %p)", rgid.gid_prefix,
4856             rgid.gid_guid, mcg_attr);
4857 
4858         if ((rgid.gid_prefix == 0) || (rgid.gid_guid == 0)) {
4859                 IBTF_DPRINTF_L2(cmlog, "ibt_join_mcg: Request GID is required");
4860                 return (IBT_INVALID_PARAM);
4861         }
4862 
4863         if ((mcg_attr->mc_pkey == IB_PKEY_INVALID_LIMITED) ||
4864             (mcg_attr->mc_pkey == IB_PKEY_INVALID_FULL)) {
4865                 IBTF_DPRINTF_L2(cmlog, "ibt_join_mcg: Invalid P_Key specified");
4866                 return (IBT_INVALID_PARAM);
4867         }
4868 
4869         if (mcg_attr->mc_join_state == 0) {
4870                 IBTF_DPRINTF_L2(cmlog, "ibt_join_mcg: JoinState not specified");
4871                 return (IBT_INVALID_PARAM);
4872         }
4873 
4874         if (mcg_info_p == NULL) {
4875                 IBTF_DPRINTF_L2(cmlog, "ibt_join_mcg: mcg_info_p is NULL");
4876                 return (IBT_INVALID_PARAM);
4877         }
4878 
4879         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mcg_tq))
4880 
4881         mcg_tq = kmem_alloc(sizeof (ibcm_join_mcg_tqarg_t), flag);
4882         if (mcg_tq == NULL) {
4883                 IBTF_DPRINTF_L2(cmlog, "ibt_join_mcg: "
4884                     "Unable to allocate memory for local usage.");
4885                 return (IBT_INSUFF_KERNEL_RESOURCE);
4886         }
4887 
4888         mcg_tq->rgid = rgid;
4889         bcopy(mcg_attr, &mcg_tq->mcg_attr, sizeof (ibt_mcg_attr_t));
4890         mcg_tq->mcg_infop = mcg_info_p;
4891         mcg_tq->func = func;
4892         mcg_tq->arg = arg;
4893 
4894         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mcg_tq))
4895 
4896         if (func != NULL) {     /* Non-Blocking */
4897                 IBTF_DPRINTF_L3(cmlog, "ibt_join_mcg: Non-Blocking Call");
4898                 if (taskq_dispatch(ibcm_taskq, ibcm_process_async_join_mcg,
4899                     mcg_tq, TQ_NOSLEEP) == 0) {
4900                         IBTF_DPRINTF_L2(cmlog, "ibt_join_mcg: Failed to "
4901                             "Dispatch the TaskQ");
4902                         kmem_free(mcg_tq, sizeof (ibcm_join_mcg_tqarg_t));
4903                         return (IBT_INSUFF_KERNEL_RESOURCE);
4904                 } else
4905                         return (IBT_SUCCESS);
4906         } else {                /* Blocking */
4907                 return (ibcm_process_join_mcg(mcg_tq));
4908         }
4909 }
4910 
4911 static void
4912 ibcm_process_async_join_mcg(void *tq_arg)
4913 {
4914         (void) ibcm_process_join_mcg(tq_arg);
4915 }
4916 
4917 static ibt_status_t
4918 ibcm_process_join_mcg(void *taskq_arg)
4919 {
4920         sa_mcmember_record_t    mcg_req;
4921         sa_mcmember_record_t    *mcg_resp;
4922         ibmf_saa_access_args_t  access_args;
4923         ibmf_saa_handle_t       saa_handle;
4924         uint64_t                component_mask = 0;
4925         ibt_status_t            retval;
4926         ibtl_cm_hca_port_t      hca_port;
4927         uint_t                  num_records;
4928         size_t                  length;
4929         ibcm_hca_info_t         *hcap;
4930         ibcm_join_mcg_tqarg_t   *mcg_arg = (ibcm_join_mcg_tqarg_t *)taskq_arg;
4931         ibt_mcg_info_t          *mcg_info_p = mcg_arg->mcg_infop;
4932 
4933         IBTF_DPRINTF_L3(cmlog, "ibcm_process_join_mcg(%p)", mcg_arg);
4934 
4935         retval = ibtl_cm_get_hca_port(mcg_arg->rgid, 0, &hca_port);
4936         if (retval != IBT_SUCCESS) {
4937                 IBTF_DPRINTF_L2(cmlog, "ibcm_process_join_mcg: Failed to get "
4938                     "port info from specified RGID: status = %d", retval);
4939                 goto ibcm_join_mcg_exit1;
4940         }
4941 
4942         bzero(&mcg_req, sizeof (sa_mcmember_record_t));
4943 
4944         if ((mcg_arg->mcg_attr.mc_pgid.gid_prefix == 0) ||
4945             (mcg_arg->mcg_attr.mc_pgid.gid_guid == 0)) {
4946                 IBTF_DPRINTF_L3(cmlog, "ibcm_process_join_mcg: "
4947                     "Request GID is Port GID");
4948                 mcg_req.PortGID = mcg_arg->rgid;
4949         } else {
4950                 mcg_req.PortGID = mcg_arg->mcg_attr.mc_pgid;
4951         }
4952         component_mask |= SA_MC_COMPMASK_PORTGID;
4953 
4954         mcg_req.Q_Key = mcg_arg->mcg_attr.mc_qkey;
4955         mcg_req.P_Key = mcg_arg->mcg_attr.mc_pkey;
4956         mcg_req.JoinState = mcg_arg->mcg_attr.mc_join_state;
4957         mcg_req.TClass = mcg_arg->mcg_attr.mc_tclass;
4958         mcg_req.FlowLabel = mcg_arg->mcg_attr.mc_flow;
4959         mcg_req.SL = mcg_arg->mcg_attr.mc_sl;
4960 
4961         component_mask |= SA_MC_COMPMASK_QKEY | SA_MC_COMPMASK_PKEY |
4962             SA_MC_COMPMASK_JOINSTATE | SA_MC_COMPMASK_TCLASS |
4963             SA_MC_COMPMASK_FLOWLABEL | SA_MC_COMPMASK_SL;
4964 
4965         /* If client has specified MGID, use it else SA will assign one. */
4966         if ((mcg_arg->mcg_attr.mc_mgid.gid_prefix >> 56ULL & 0xFF) == 0xFF) {
4967                 mcg_req.MGID = mcg_arg->mcg_attr.mc_mgid;
4968                 component_mask |= SA_MC_COMPMASK_MGID;
4969         }
4970 
4971         IBTF_DPRINTF_L3(cmlog, "ibcm_process_join_mcg: ");
4972         IBTF_DPRINTF_L3(cmlog, "PGID=%016llX:%016llX, ",
4973             mcg_req.PortGID.gid_prefix, mcg_req.PortGID.gid_guid);
4974         IBTF_DPRINTF_L3(cmlog, "MGID=%016llX:%016llX",
4975             mcg_req.MGID.gid_prefix, mcg_req.MGID.gid_guid);
4976         IBTF_DPRINTF_L3(cmlog, "JoinState = %X",
4977             mcg_arg->mcg_attr.mc_join_state);
4978         IBTF_DPRINTF_L5(cmlog, "QKey %lX, PKey %lX",
4979             mcg_arg->mcg_attr.mc_qkey, mcg_arg->mcg_attr.mc_pkey);
4980         IBTF_DPRINTF_L5(cmlog, "Scope %X, MLID %X",
4981             mcg_arg->mcg_attr.mc_scope, mcg_arg->mcg_attr.mc_mlid);
4982 
4983         /* Is MTU specified. */
4984         if (mcg_arg->mcg_attr.mc_mtu_req.r_mtu) {
4985                 mcg_req.MTU = mcg_arg->mcg_attr.mc_mtu_req.r_mtu;
4986                 mcg_req.MTUSelector = mcg_arg->mcg_attr.mc_mtu_req.r_selector;
4987 
4988                 component_mask |= SA_MC_COMPMASK_MTUSELECTOR |
4989                     SA_MC_COMPMASK_MTU;
4990         }
4991 
4992         /* Is RATE specified. */
4993         if (mcg_arg->mcg_attr.mc_rate_req.r_srate) {
4994                 mcg_req.Rate = mcg_arg->mcg_attr.mc_rate_req.r_srate;
4995                 mcg_req.RateSelector =
4996                     mcg_arg->mcg_attr.mc_rate_req.r_selector;
4997 
4998                 component_mask |= SA_MC_COMPMASK_RATESELECTOR |
4999                     SA_MC_COMPMASK_RATE;
5000         }
5001 
5002         /* Is Packet Life Time specified. */
5003         if (mcg_arg->mcg_attr.mc_pkt_lt_req.p_pkt_lt) {
5004                 mcg_req.Rate = mcg_arg->mcg_attr.mc_pkt_lt_req.p_pkt_lt;
5005                 mcg_req.RateSelector =
5006                     mcg_arg->mcg_attr.mc_pkt_lt_req.p_selector;
5007 
5008                 component_mask |= SA_MC_COMPMASK_PKTLTSELECTOR |
5009                     SA_MC_COMPMASK_PKTLT;
5010         }
5011 
5012         if (mcg_arg->mcg_attr.mc_hop) {
5013                 mcg_req.HopLimit = mcg_arg->mcg_attr.mc_hop;
5014                 component_mask |= SA_MC_COMPMASK_HOPLIMIT;
5015         }
5016 
5017         if (mcg_arg->mcg_attr.mc_scope) {
5018                 mcg_req.Scope = mcg_arg->mcg_attr.mc_scope;
5019                 component_mask |= SA_MC_COMPMASK_SCOPE;
5020         }
5021 
5022         if (mcg_arg->mcg_attr.mc_mlid) {
5023                 mcg_req.MLID = mcg_arg->mcg_attr.mc_mlid;
5024                 component_mask |= SA_MC_COMPMASK_MLID;
5025         }
5026 
5027         /* Get SA Access Handle. */
5028         hcap = ibcm_find_hca_entry(hca_port.hp_hca_guid);
5029         if (hcap == NULL) {
5030                 IBTF_DPRINTF_L2(cmlog, "ibcm_process_join_mcg: NO HCA found");
5031 
5032                 retval = IBT_HCA_BUSY_DETACHING;
5033                 goto ibcm_join_mcg_exit1;
5034         }
5035 
5036         saa_handle = ibcm_get_saa_handle(hcap, hca_port.hp_port);
5037         if (saa_handle == NULL) {
5038                 IBTF_DPRINTF_L2(cmlog, "ibcm_process_join_mcg: SA Handle NULL");
5039 
5040                 retval = IBT_HCA_PORT_NOT_ACTIVE;
5041                 goto ibcm_join_mcg_exit;
5042         }
5043 
5044         if ((mcg_arg->mcg_attr.mc_pgid.gid_prefix != 0) &&
5045             (mcg_arg->mcg_attr.mc_pgid.gid_guid != 0)) {
5046                 retval = ibtl_cm_get_hca_port(mcg_arg->mcg_attr.mc_pgid, 0,
5047                     &hca_port);
5048                 if (retval != IBT_SUCCESS) {
5049                         IBTF_DPRINTF_L2(cmlog, "ibcm_process_join_mcg: Failed "
5050                             "to get PortInfo of specified PGID: status = %d",
5051                             retval);
5052                         goto ibcm_join_mcg_exit1;
5053                 }
5054         }
5055 
5056         /* Contact SA Access */
5057         access_args.sq_attr_id = SA_MCMEMBERRECORD_ATTRID;
5058         access_args.sq_access_type = IBMF_SAA_UPDATE;
5059         access_args.sq_component_mask = component_mask;
5060         access_args.sq_template = &mcg_req;
5061         access_args.sq_template_length = sizeof (sa_mcmember_record_t);
5062         access_args.sq_callback = NULL;
5063         access_args.sq_callback_arg = NULL;
5064 
5065         retval = ibcm_contact_sa_access(saa_handle, &access_args, &length,
5066             (void **)&mcg_resp);
5067         if (retval != IBT_SUCCESS) {
5068                 IBTF_DPRINTF_L2(cmlog, "ibcm_process_join_mcg: "
5069                     "SA Access Failed");
5070                 goto ibcm_join_mcg_exit;
5071         }
5072 
5073         num_records = length/sizeof (sa_mcmember_record_t);
5074 
5075         IBTF_DPRINTF_L4(cmlog, "ibcm_process_join_mcg: "
5076             "Found %d MCMember Records", num_records);
5077 
5078         /* Validate the returned number of records. */
5079         if ((mcg_resp != NULL) && (num_records > 0)) {
5080                 /* Update the return values. */
5081                 mcg_info_p->mc_adds_vect.av_dgid = mcg_resp->MGID;
5082                 mcg_info_p->mc_adds_vect.av_sgid = mcg_resp->PortGID;
5083                 mcg_info_p->mc_adds_vect.av_srate = mcg_resp->Rate;
5084                 mcg_info_p->mc_adds_vect.av_srvl = mcg_resp->SL;
5085                 mcg_info_p->mc_adds_vect.av_flow = mcg_resp->FlowLabel;
5086                 mcg_info_p->mc_adds_vect.av_tclass = mcg_resp->TClass;
5087                 mcg_info_p->mc_adds_vect.av_hop = mcg_resp->HopLimit;
5088                 mcg_info_p->mc_adds_vect.av_send_grh = B_TRUE;
5089                 mcg_info_p->mc_adds_vect.av_dlid = mcg_resp->MLID;
5090                 mcg_info_p->mc_mtu = mcg_resp->MTU;
5091                 mcg_info_p->mc_qkey = mcg_resp->Q_Key;
5092 
5093                 retval = ibt_pkey2index_byguid(hca_port.hp_hca_guid,
5094                     hca_port.hp_port, mcg_resp->P_Key, &mcg_info_p->mc_pkey_ix);
5095                 if (retval != IBT_SUCCESS) {
5096                         IBTF_DPRINTF_L3(cmlog, "ibcm_process_join_mcg: "
5097                             "Pkey2Index Conversion failed<%d>", retval);
5098                         mcg_info_p->mc_pkey_ix = 0;
5099                 }
5100 
5101                 mcg_info_p->mc_scope = mcg_resp->Scope;
5102                 mcg_info_p->mc_pkt_lt = mcg_resp->PacketLifeTime;
5103 
5104                 mcg_info_p->mc_adds_vect.av_port_num = hca_port.hp_port;
5105                 mcg_info_p->mc_adds_vect.av_sgid_ix = hca_port.hp_sgid_ix;
5106                 mcg_info_p->mc_adds_vect.av_src_path = 0;
5107 
5108                 /* Add or Incr the matching MCG entry. */
5109                 ibcm_add_incr_mcg_entry(&mcg_req, mcg_resp);
5110                 /* Deallocate the memory allocated by SA for mcg_resp. */
5111                 kmem_free(mcg_resp, length);
5112 
5113                 retval = IBT_SUCCESS;
5114         } else {
5115                 retval = IBT_MCG_RECORDS_NOT_FOUND;
5116                 IBTF_DPRINTF_L3(cmlog, "ibcm_process_join_mcg: "
5117                     "MCG RECORDS NOT FOUND");
5118         }
5119 
5120 ibcm_join_mcg_exit:
5121         ibcm_dec_hca_acc_cnt(hcap);
5122 
5123 ibcm_join_mcg_exit1:
5124         if (mcg_arg->func)
5125                 (*(mcg_arg->func))(mcg_arg->arg, retval, mcg_info_p);
5126 
5127         kmem_free(mcg_arg, sizeof (ibcm_join_mcg_tqarg_t));
5128 
5129         return (retval);
5130 }
5131 
5132 
5133 /*
5134  * Function:
5135  *      ibt_leave_mcg
5136  * Input:
5137  *      rgid            The request GID that defines the HCA port upon which
5138  *                      to send the request to the Subnet Administrator, to
5139  *                      remove the specified port (port_gid) from the multicast
5140  *                      group.  If 'port_gid' is the Reserved GID (i.e.
5141  *                      port_gid.gid_prefix = 0 and port_gid.gid_guid = 0),
5142  *                      then the end-port associated with 'rgid' is removed
5143  *                      from the multicast group.
5144  *
5145  *      mc_gid          A multicast group GID as returned from ibt_join_mcg()
5146  *                      call.  This is optional, if not specified (i.e.
5147  *                      mc_gid.gid_prefix has 0xFF in its upper 8 bits to
5148  *                      identify this as being a multicast GID), then the
5149  *                      port is removed from all the multicast groups of
5150  *                      which it is a member.
5151  *
5152  *      port_gid        This is optional, if not the Reserved GID (gid_prefix
5153  *                      and gid_guid not equal to 0), then this specifies the
5154  *                      endport GID of the multicast group member being deleted
5155  *                      from the group. If it is the Reserved GID (gid_prefix
5156  *                      and gid_guid equal to 0) then the member endport GID is
5157  *                      determined from 'rgid'.
5158  *
5159  *      mc_join_state   The Join State attribute used when the group was joined
5160  *                      using ibt_join_mcg(). This Join State component must
5161  *                      contains at least one bit set to 1 in the same position
5162  *                      as that used during ibt_join_mcg(). i.e. the logical
5163  *                      AND of the two JoinState components is not all zeros.
5164  *                      This Join State component must not have some bits set
5165  *                      which are not set using ibt_join_mcg().
5166  * Output:
5167  *      None.
5168  * Returns:
5169  *      IBT_SUCCESS
5170  *      IBT_INVALID_PARAM
5171  *      IBT_MC_GROUP_INVALID
5172  *      IBT_INSUFF_RESOURCE
5173  * Description:
5174  *      The port associated with the port GID shall be removed from the
5175  *      multicast group specified by MGID (mc_gid) or from all the multicast
5176  *      groups of which it is a member if the MGID (mc_gid) is not specified.
5177  *
5178  *      The last full member to leave causes the destruction of the Multicast
5179  *      Group.
5180  */
5181 ibt_status_t
5182 ibt_leave_mcg(ib_gid_t rgid, ib_gid_t mc_gid, ib_gid_t port_gid,
5183     uint8_t mc_join_state)
5184 {
5185         sa_mcmember_record_t    mcg_req;
5186         ibmf_saa_access_args_t  access_args;
5187         ibmf_saa_handle_t       saa_handle;
5188         uint64_t                component_mask = 0;
5189         int                     sa_retval;
5190         ibt_status_t            retval;
5191         ibcm_status_t           ret;
5192         ibtl_cm_hca_port_t      hca_port;
5193         size_t                  length;
5194         void                    *results_p;
5195         ibcm_hca_info_t         *hcap;
5196         uint8_t                 jstate = 0;
5197 
5198         IBTF_DPRINTF_L3(cmlog, "ibt_leave_mcg(%llX:%llX, %llX:%llX)",
5199             rgid.gid_prefix, rgid.gid_guid, mc_gid.gid_prefix, mc_gid.gid_guid);
5200 
5201         IBTF_DPRINTF_L3(cmlog, "ibt_leave_mcg(%llX:%llX, 0x%X)",
5202             port_gid.gid_prefix, port_gid.gid_guid, mc_join_state);
5203 
5204         if ((rgid.gid_prefix == 0) || (rgid.gid_guid == 0)) {
5205                 IBTF_DPRINTF_L2(cmlog, "ibt_leave_mcg: RequestGID is required");
5206                 return (IBT_INVALID_PARAM);
5207         }
5208 
5209         bzero(&mcg_req, sizeof (sa_mcmember_record_t));
5210 
5211         IBTF_DPRINTF_L3(cmlog, "ibt_leave_mcg: MGID: %llX%llX",
5212             mc_gid.gid_prefix, mc_gid.gid_guid);
5213 
5214         /* Validate MGID */
5215         if ((mc_gid.gid_prefix >> 56ULL & 0xFF) == 0xFF) {
5216                 mcg_req.MGID = mc_gid;
5217                 component_mask |= SA_MC_COMPMASK_MGID;
5218         } else if ((mc_gid.gid_prefix != 0) || (mc_gid.gid_guid != 0)) {
5219                 IBTF_DPRINTF_L3(cmlog, "ibt_leave_mcg: Invalid MGID specified");
5220                 return (IBT_MC_MGID_INVALID);
5221         }
5222 
5223         if ((port_gid.gid_prefix == 0) || (port_gid.gid_guid == 0)) {
5224                 mcg_req.PortGID = rgid;
5225         } else {
5226                 IBTF_DPRINTF_L3(cmlog, "ibt_leave_mcg: Performing PROXY Leave");
5227                 mcg_req.PortGID = port_gid;
5228         }
5229         component_mask |= SA_MC_COMPMASK_PORTGID;
5230 
5231         IBTF_DPRINTF_L3(cmlog, "ibt_leave_mcg: Port GID <%llX:%llX>",
5232             mcg_req.PortGID.gid_prefix, mcg_req.PortGID.gid_guid);
5233 
5234         /* Join State */
5235         mcg_req.JoinState = mc_join_state;
5236         component_mask |= SA_MC_COMPMASK_JOINSTATE;
5237 
5238         ret = ibcm_del_decr_mcg_entry(&mcg_req, &jstate);
5239         if (ret == IBCM_LOOKUP_EXISTS) {
5240                 IBTF_DPRINTF_L3(cmlog, "ibt_leave_mcg: Multiple JoinMCG record "
5241                     " still exists, we shall leave for last leave_mcg call");
5242                 return (IBT_SUCCESS);
5243         } else if (ret == IBCM_LOOKUP_FAIL) {
5244                 IBTF_DPRINTF_L2(cmlog, "ibt_leave_mcg: No Record found, "
5245                     "continue with leave_mcg call");
5246         } else if ((ret == IBCM_SUCCESS) && (jstate != 0)) {
5247                 /*
5248                  * Update with cached "jstate", as this will be OR'ed of
5249                  * all ibt_join_mcg() calls for this record.
5250                  */
5251                 mcg_req.JoinState = jstate;
5252         }
5253 
5254         retval = ibtl_cm_get_hca_port(rgid, 0, &hca_port);
5255         if (retval != IBT_SUCCESS) {
5256                 IBTF_DPRINTF_L2(cmlog, "ibt_leave_mcg: Failed to get port info "
5257                     "from specified RGID : status = %d", retval);
5258                 return (retval);
5259         }
5260 
5261         /* Get SA Access Handle. */
5262         hcap = ibcm_find_hca_entry(hca_port.hp_hca_guid);
5263         if (hcap == NULL) {
5264                 IBTF_DPRINTF_L2(cmlog, "ibt_leave_mcg: "
5265                     "NO HCA found");
5266                 return (IBT_HCA_BUSY_DETACHING);
5267         }
5268 
5269         saa_handle = ibcm_get_saa_handle(hcap, hca_port.hp_port);
5270         if (saa_handle == NULL) {
5271                 IBTF_DPRINTF_L2(cmlog, "ibt_leave_mcg: saa_handle is NULL");
5272                 ibcm_dec_hca_acc_cnt(hcap);
5273                 return (IBT_HCA_PORT_NOT_ACTIVE);
5274         }
5275 
5276         /* Contact SA Access */
5277         access_args.sq_attr_id = SA_MCMEMBERRECORD_ATTRID;
5278         access_args.sq_access_type = IBMF_SAA_DELETE;
5279         access_args.sq_component_mask = component_mask;
5280         access_args.sq_template = &mcg_req;
5281         access_args.sq_template_length = sizeof (sa_mcmember_record_t);
5282         access_args.sq_callback = NULL;
5283         access_args.sq_callback_arg = NULL;
5284 
5285         ibcm_sa_access_enter();
5286 
5287         sa_retval = ibmf_sa_access(saa_handle, &access_args, 0, &length,
5288             &results_p);
5289         if (sa_retval != IBMF_SUCCESS) {
5290                 IBTF_DPRINTF_L2(cmlog, "ibt_leave_mcg: SA access Failed: %d",
5291                     sa_retval);
5292                 (void) ibcm_ibmf_analyze_error(sa_retval);
5293                 retval = IBT_MC_GROUP_INVALID;
5294         }
5295 
5296         ibcm_sa_access_exit();
5297 
5298         ibcm_dec_hca_acc_cnt(hcap);
5299 
5300         return (retval);
5301 }
5302 
5303 
5304 /*
5305  * Function:
5306  *      ibt_query_mcg
5307  * Input:
5308  *      rgid            The request GID that defines the HCA port upon which
5309  *                      to send the request to the Subnet Administrator, to
5310  *                      retrieve Multicast Records matching attributes as
5311  *                      specified through 'mcg_attr' argument.
5312  *
5313  *      mcg_attr        NULL or a pointer to an ibt_mcg_attr_t structure that
5314  *                      specifies MCG attributes that are to be matched.
5315  *                      Attributes that are not required can be wild carded
5316  *                      by specifying as '0'.
5317  *
5318  *      mcgs_max_num    The maximum number of matching multicast groups to
5319  *                      return.  If zero, then all available matching multicast
5320  *                      groups are returned.
5321  * Output:
5322  *      mcgs_info_p     The address of an ibt_mcg_info_t pointer, where
5323  *                      multicast group information is returned. The actual
5324  *                      number of entries filled in the array is returned in
5325  *                      entries_p.
5326  *
5327  *      entries_p       The number of ibt_mcg_attr_t entries returned.
5328  * Returns:
5329  *      IBT_SUCCESS
5330  *      IBT_INVALID_PARAM
5331  *      IBT_MCG_RECORDS_NOT_FOUND
5332  * Description:
5333  *      Request information on multicast groups that match the parameters
5334  *      specified in mcg_attr. Information on each multicast group is returned
5335  *      to the caller in the form of an array of ibt_mcg_info_t.
5336  *      ibt_query_mcg() allocates the memory for this array and returns a
5337  *      pointer to the array (mcgs_p) and the number of entries in the array
5338  *      (entries_p). This memory should be freed by the client using
5339  *      ibt_free_mcg_info().
5340  */
5341 ibt_status_t
5342 ibt_query_mcg(ib_gid_t rgid, ibt_mcg_attr_t *mcg_attr, uint_t mcgs_max_num,
5343     ibt_mcg_info_t **mcgs_info_p, uint_t *entries_p)
5344 {
5345         sa_mcmember_record_t    mcg_req;
5346         sa_mcmember_record_t    *mcg_resp;
5347         ibt_mcg_info_t          *mcg_infop;
5348         ibmf_saa_access_args_t  access_args;
5349         ibmf_saa_handle_t       saa_handle;
5350         uint64_t                component_mask = 0;
5351         ibt_status_t            retval;
5352         ibtl_cm_hca_port_t      hport;
5353         uint_t                  num_records;
5354         size_t                  length;
5355         void                    *results_p;
5356         ib_gid_t                port_gid;
5357         ibcm_hca_info_t         *hcap;
5358 
5359         IBTF_DPRINTF_L3(cmlog, "ibt_query_mcg(%p, %d)", mcg_attr, mcgs_max_num);
5360 
5361         if ((entries_p == NULL) || (mcgs_info_p == NULL)) {
5362                 IBTF_DPRINTF_L2(cmlog, "ibt_query_mcg: "
5363                     "entries_p or mcgs_info_p is NULL");
5364                 return (IBT_INVALID_PARAM);
5365         }
5366 
5367         if ((rgid.gid_prefix == 0) || (rgid.gid_guid == 0)) {
5368                 IBTF_DPRINTF_L2(cmlog, "ibt_query_mcg: RequestGID is required");
5369                 return (IBT_INVALID_PARAM);
5370         }
5371         IBTF_DPRINTF_L4(cmlog, "ibt_query_mcg: Request GID <%llX:%llX>",
5372             rgid.gid_prefix, rgid.gid_guid);
5373 
5374         bzero(&mcg_req, sizeof (sa_mcmember_record_t));
5375         port_gid.gid_prefix = port_gid.gid_guid = 0;
5376 
5377         if (mcg_attr != NULL) {
5378                 port_gid = mcg_attr->mc_pgid;
5379 
5380                 if ((port_gid.gid_prefix != 0) && (port_gid.gid_guid != 0)) {
5381                         mcg_req.PortGID = mcg_attr->mc_pgid;
5382                         component_mask |= SA_MC_COMPMASK_PORTGID;
5383 
5384                         IBTF_DPRINTF_L4(cmlog, "ibt_query_mcg: PGID %llX:%llX",
5385                             port_gid.gid_prefix, port_gid.gid_guid);
5386                 }
5387 
5388                 /* Is Q_Key specified. */
5389                 if (mcg_attr->mc_qkey != 0) {
5390                         mcg_req.Q_Key = mcg_attr->mc_qkey;
5391                         component_mask |= SA_MC_COMPMASK_QKEY;
5392                 }
5393 
5394                 /* Is P_Key specified. */
5395                 if (mcg_attr->mc_pkey != 0) {
5396                         mcg_req.P_Key = mcg_attr->mc_pkey;
5397                         component_mask |= SA_MC_COMPMASK_PKEY;
5398                 }
5399 
5400                 /* Is MGID specified. */
5401                 if ((mcg_attr->mc_mgid.gid_prefix >> 56ULL & 0xFF) == 0xFF) {
5402                         mcg_req.MGID = mcg_attr->mc_mgid;
5403                         component_mask |= SA_MC_COMPMASK_MGID;
5404                 }
5405 
5406                 /* Is MTU specified. */
5407                 if (mcg_attr->mc_mtu_req.r_mtu) {
5408                         mcg_req.MTU = mcg_attr->mc_mtu_req.r_mtu;
5409                         mcg_req.MTUSelector = mcg_attr->mc_mtu_req.r_selector;
5410 
5411                         component_mask |= SA_MC_COMPMASK_MTUSELECTOR |
5412                             SA_MC_COMPMASK_MTU;
5413                 }
5414 
5415                 if (mcg_attr->mc_tclass) {
5416                         mcg_req.TClass = mcg_attr->mc_tclass;
5417                         component_mask |= SA_MC_COMPMASK_TCLASS;
5418                 }
5419 
5420                 /* Is RATE specified. */
5421                 if (mcg_attr->mc_rate_req.r_srate) {
5422                         mcg_req.Rate = mcg_attr->mc_rate_req.r_srate;
5423                         mcg_req.RateSelector = mcg_attr->mc_rate_req.r_selector;
5424 
5425                         component_mask |= SA_MC_COMPMASK_RATESELECTOR |
5426                             SA_MC_COMPMASK_RATE;
5427                 }
5428 
5429                 /* Is Packet Life Time specified. */
5430                 if (mcg_attr->mc_pkt_lt_req.p_pkt_lt) {
5431                         mcg_req.Rate = mcg_attr->mc_pkt_lt_req.p_pkt_lt;
5432                         mcg_req.RateSelector =
5433                             mcg_attr->mc_pkt_lt_req.p_selector;
5434 
5435                         component_mask |= SA_MC_COMPMASK_PKTLTSELECTOR |
5436                             SA_MC_COMPMASK_PKTLT;
5437                 }
5438 
5439                 if (mcg_attr->mc_hop) {
5440                         mcg_req.HopLimit = mcg_attr->mc_hop;
5441                         component_mask |= SA_MC_COMPMASK_HOPLIMIT;
5442                 }
5443 
5444                 if (mcg_attr->mc_flow) {
5445                         mcg_req.FlowLabel = mcg_attr->mc_flow;
5446                         component_mask |= SA_MC_COMPMASK_FLOWLABEL;
5447                 }
5448 
5449                 if (mcg_attr->mc_sl) {
5450                         mcg_req.SL = mcg_attr->mc_sl;
5451                         component_mask |= SA_MC_COMPMASK_SL;
5452                 }
5453 
5454                 if (mcg_attr->mc_scope) {
5455                         mcg_req.Scope = mcg_attr->mc_scope;
5456                         component_mask |= SA_MC_COMPMASK_SCOPE;
5457                 }
5458 
5459                 if (mcg_attr->mc_join_state) {
5460                         mcg_req.JoinState = mcg_attr->mc_join_state;
5461                         component_mask |= SA_MC_COMPMASK_JOINSTATE;
5462                 }
5463 
5464                 if (mcg_attr->mc_mlid) {
5465                         mcg_req.MLID = mcg_attr->mc_mlid;
5466                         component_mask |= SA_MC_COMPMASK_MLID;
5467                 }
5468         }
5469 
5470         retval = ibtl_cm_get_hca_port(rgid, 0, &hport);
5471         if (retval != IBT_SUCCESS) {
5472                 IBTF_DPRINTF_L2(cmlog, "ibt_query_mcg: Failed to get port info "
5473                     "from specified RGID : status = %d", retval);
5474                 return (retval);
5475         }
5476 
5477         /* Get SA Access Handle. */
5478         hcap = ibcm_find_hca_entry(hport.hp_hca_guid);
5479         if (hcap == NULL) {
5480                 IBTF_DPRINTF_L2(cmlog, "ibt_query_mcg: NO HCA found");
5481                 return (IBT_HCA_BUSY_DETACHING);
5482         }
5483 
5484         saa_handle = ibcm_get_saa_handle(hcap, hport.hp_port);
5485         if (saa_handle == NULL) {
5486                 IBTF_DPRINTF_L2(cmlog, "ibt_query_mcg: saa_handle is NULL");
5487                 ibcm_dec_hca_acc_cnt(hcap);
5488                 return (IBT_HCA_PORT_NOT_ACTIVE);
5489         }
5490 
5491         /* Contact SA Access */
5492         access_args.sq_attr_id = SA_MCMEMBERRECORD_ATTRID;
5493         access_args.sq_access_type = IBMF_SAA_RETRIEVE;
5494         access_args.sq_component_mask = component_mask;
5495         access_args.sq_template = &mcg_req;
5496         access_args.sq_template_length = sizeof (sa_mcmember_record_t);
5497         access_args.sq_callback = NULL;
5498         access_args.sq_callback_arg = NULL;
5499 
5500         retval = ibcm_contact_sa_access(saa_handle, &access_args, &length,
5501             &results_p);
5502         if (retval != IBT_SUCCESS) {
5503                 IBTF_DPRINTF_L2(cmlog, "ibt_query_mcg: SA access Failed");
5504                 ibcm_dec_hca_acc_cnt(hcap);
5505                 return (retval);
5506         }
5507 
5508         num_records = length/sizeof (sa_mcmember_record_t);
5509 
5510         IBTF_DPRINTF_L4(cmlog, "ibt_query_mcg: Found %d MCMember Records",
5511             num_records);
5512 
5513         /* Validate the returned number of records. */
5514         if ((results_p != NULL) && (num_records > 0)) {
5515                 uint_t  i;
5516 
5517                 /*
5518                  * If mcgs_max_num is zero, then return all records else
5519                  * return only requested number of records
5520                  */
5521                 if ((mcgs_max_num != 0) && (num_records > mcgs_max_num)) {
5522                         /* we are interested in only mcgs_max_num records */
5523                         num_records = mcgs_max_num;
5524                 }
5525 
5526                 /*
5527                  * The SGID returned in "mcg_info_p" buffer should be PortGID,
5528                  * (mcg_attr->mc_pgid), if 'mcg_attr->mc_pgid' was specified,
5529                  * else RequestGID (rgid) should be returned.
5530                  */
5531                 if ((port_gid.gid_prefix != 0) && (port_gid.gid_guid != 0)) {
5532 
5533                         /* Get sgid_ix and port number of 'port_gid' */
5534                         retval = ibtl_cm_get_hca_port(port_gid, 0, &hport);
5535                         if (retval != IBT_SUCCESS) {
5536                                 IBTF_DPRINTF_L2(cmlog, "ibt_query_mcg: "
5537                                     "Failed to Get Portinfo for PortGID :"
5538                                     "status = %d", retval);
5539                                 return (retval);
5540                         }
5541                 } else {
5542                         /*
5543                          * The sgid_ix and port number related to RequestGID
5544                          * are already obtained at the beginning.
5545                          */
5546                         port_gid = rgid;
5547                 }
5548 
5549                 /*
5550                  * Allocate memory for return buffer, to be freed in
5551                  * ibt_free_mcg_info().
5552                  */
5553                 mcg_infop = kmem_alloc((num_records * sizeof (ibt_mcg_info_t)),
5554                     KM_SLEEP);
5555 
5556                 *mcgs_info_p = mcg_infop;
5557                 *entries_p = num_records;
5558 
5559                 /* Update the return values. */
5560                 for (i = 0; i < num_records; i++) {
5561 
5562                         mcg_resp = (sa_mcmember_record_t *)((uchar_t *)
5563                             results_p + i * sizeof (sa_mcmember_record_t));
5564 
5565                         mcg_infop[i].mc_adds_vect.av_dgid = mcg_resp->MGID;
5566                         mcg_infop[i].mc_adds_vect.av_sgid = port_gid;
5567                         mcg_infop[i].mc_adds_vect.av_srate = mcg_resp->Rate;
5568                         mcg_infop[i].mc_adds_vect.av_srvl = mcg_resp->SL;
5569                         mcg_infop[i].mc_adds_vect.av_flow = mcg_resp->FlowLabel;
5570                         mcg_infop[i].mc_adds_vect.av_tclass = mcg_resp->TClass;
5571                         mcg_infop[i].mc_adds_vect.av_hop = mcg_resp->HopLimit;
5572                         mcg_infop[i].mc_adds_vect.av_port_num = hport.hp_port;
5573                         mcg_infop[i].mc_adds_vect.av_send_grh = B_TRUE;
5574                         mcg_infop[i].mc_adds_vect.av_dlid = mcg_resp->MLID;
5575                         mcg_infop[i].mc_adds_vect.av_sgid_ix = hport.hp_sgid_ix;
5576                         mcg_infop[i].mc_adds_vect.av_src_path = 0;
5577                         mcg_infop[i].mc_mtu = mcg_resp->MTU;
5578                         mcg_infop[i].mc_qkey = mcg_resp->Q_Key;
5579                         mcg_infop[i].mc_scope = mcg_resp->Scope;
5580                         mcg_infop[i].mc_pkt_lt = mcg_resp->PacketLifeTime;
5581 
5582                         if (ibt_pkey2index_byguid(hport.hp_hca_guid,
5583                             hport.hp_port, mcg_resp->P_Key,
5584                             &mcg_infop[i].mc_pkey_ix) != IBT_SUCCESS) {
5585                                 IBTF_DPRINTF_L3(cmlog, "ibt_query_mcg: "
5586                                     "Pkey2Index Conversion failed");
5587                                 mcg_infop[i].mc_pkey_ix = 0;
5588                         }
5589                 }
5590 
5591                 /*
5592                  * Deallocate the memory allocated by SA for results_p.
5593                  */
5594                 kmem_free(results_p, length);
5595                 retval = IBT_SUCCESS;
5596 
5597                 IBTF_DPRINTF_L3(cmlog, "ibt_query_mcg: returning %d MCGRecords",
5598                     num_records);
5599 
5600         } else {
5601                 retval = IBT_MCG_RECORDS_NOT_FOUND;
5602                 *entries_p = 0;
5603 
5604                 IBTF_DPRINTF_L3(cmlog, "ibt_query_mcg: MCG RECORDS NOT FOUND");
5605         }
5606 
5607         ibcm_dec_hca_acc_cnt(hcap);
5608 
5609         return (retval);
5610 }
5611 
5612 
5613 /*
5614  * ibt_free_mcg_info()
5615  *      Free the memory allocated by successful ibt_query_mcg()
5616  *
5617  *      mcgs_info       Pointer returned by ibt_query_mcg().
5618  *
5619  *      entries         The number of ibt_mcg_info_t entries to free.
5620  */
5621 void
5622 ibt_free_mcg_info(ibt_mcg_info_t *mcgs_info, uint_t entries)
5623 {
5624         IBTF_DPRINTF_L3(cmlog, "ibt_free_mcg_info: "
5625             "Free <%d> entries from 0x%p", entries, mcgs_info);
5626 
5627         if ((mcgs_info != NULL) && (entries > 0))
5628                 kmem_free(mcgs_info, entries * sizeof (ibt_mcg_info_t));
5629         else
5630                 IBTF_DPRINTF_L2(cmlog, "ibt_free_mcg_info: "
5631                     "ERROR: NULL buf pointer or length specified.");
5632 }
5633 
5634 
5635 /*
5636  * Function:
5637  *      ibt_gid_to_node_info()
5638  * Input:
5639  *      gid             Identifies the IB Node and port for which to obtain
5640  *                      Node information.
5641  * Output:
5642  *      node_info_p     A pointer to an ibt_node_info_t structure (allocated
5643  *                      by the caller) in which to return the node information.
5644  * Returns:
5645  *      IBT_SUCCESS
5646  *      IBT_INVALID_PARAM
5647  *      IBT_NODE_RECORDS_NOT_FOUND
5648  *      IBT_NO_HCAS_AVAILABLE
5649  * Description:
5650  *      Retrieve Node Information for the specified GID.
5651  */
5652 ibt_status_t
5653 ibt_gid_to_node_info(ib_gid_t gid, ibt_node_info_t *node_info_p)
5654 {
5655         sa_node_record_t        nr_req, *nr_resp;
5656         ibmf_saa_handle_t       saa_handle;
5657         ibt_status_t            retval;
5658         ibcm_hca_info_t         *hcap;
5659         ibtl_cm_hca_port_t      hport;
5660         int                     i, j;
5661         uint_t                  num_rec;
5662         ib_guid_t               *guid_array = NULL;
5663         sa_path_record_t        *path;
5664         size_t                  len;
5665         uint8_t                 npaths;
5666         uint32_t                num_hcas = 0;
5667         ib_lid_t                node_lid;
5668         boolean_t               local_node = B_FALSE;
5669         void                    *res_p;
5670         uint8_t                 num_ports = 0;
5671 
5672 
5673         IBTF_DPRINTF_L4(cmlog, "ibt_gid_to_node_info(%llX:%llX, %p)",
5674             gid.gid_prefix, gid.gid_guid, node_info_p);
5675 
5676         if ((gid.gid_prefix == 0) || (gid.gid_guid == 0)) {
5677                 IBTF_DPRINTF_L2(cmlog, "ibt_gid_to_node_info: GID is required");
5678                 return (IBT_INVALID_PARAM);
5679         }
5680 
5681         if (node_info_p == NULL) {
5682                 IBTF_DPRINTF_L2(cmlog, "ibt_gid_to_node_info: "
5683                     "Return Buf (node_info_p) is NULL.");
5684                 return (IBT_INVALID_PARAM);
5685         }
5686 
5687         /*
5688          * If 'gid' is on local node, then get node lid (i.e. base lid of the
5689          * associated port) info via ibtl_cm_get_hca_port() call.
5690          */
5691         bzero(&hport, sizeof (ibtl_cm_hca_port_t));
5692         if (ibtl_cm_get_hca_port(gid, 0, &hport) == IBT_SUCCESS) {
5693 
5694                 hcap = ibcm_find_hca_entry(hport.hp_hca_guid);
5695                 if (hcap == NULL) {
5696                         IBTF_DPRINTF_L3(cmlog, "ibt_gid_to_node_info: "
5697                             "HCA(%llX) info not found", hport.hp_hca_guid);
5698                         return (IBT_NO_HCAS_AVAILABLE);
5699                 }
5700                 num_ports = 1;
5701                 num_hcas = 1;
5702                 node_lid = hport.hp_base_lid;
5703                 local_node = B_TRUE;
5704                 IBTF_DPRINTF_L4(cmlog, "ibt_gid_to_node_info: Local Node: "
5705                     "LID = 0x%X", node_lid);
5706         } else {
5707                 /* Get the number of HCAs and their GUIDs */
5708                 num_hcas = ibt_get_hca_list(&guid_array);
5709                 IBTF_DPRINTF_L4(cmlog, "ibt_gid_to_node_info: ibt_get_hca_list "
5710                     "returned %d hcas", num_hcas);
5711 
5712                 if (num_hcas == 0) {
5713                         IBTF_DPRINTF_L2(cmlog, "ibt_gid_to_node_info: "
5714                             "NO HCA's Found on this system");
5715                         return (IBT_NO_HCAS_AVAILABLE);
5716                 }
5717         }
5718 
5719         for (i = 0; i < num_hcas; i++) {
5720                 if (local_node == B_FALSE) {
5721                         hcap = ibcm_find_hca_entry(guid_array[i]);
5722                         if (hcap == NULL) {
5723                                 IBTF_DPRINTF_L3(cmlog, "ibt_gid_to_node_info: "
5724                                     "HCA(%llX) info not found", guid_array[i]);
5725                                 retval = IBT_NO_HCAS_AVAILABLE;
5726                                 continue;
5727                         }
5728                         num_ports = hcap->hca_num_ports;
5729                 }
5730 
5731                 for (j = 0; j < num_ports; j++) {
5732                         uint8_t         port = 0;
5733 
5734                         if (local_node == B_TRUE)
5735                                 port = hport.hp_port;
5736                         else
5737                                 port = j + 1;
5738 
5739                         /* Get SA Access Handle. */
5740                         saa_handle = ibcm_get_saa_handle(hcap, port);
5741                         if (saa_handle == NULL) {
5742                                 IBTF_DPRINTF_L3(cmlog, "ibt_gid_to_node_info: "
5743                                     "Port %d of HCA (%llX) is NOT ACTIVE",
5744                                     port, hport.hp_hca_guid);
5745                                 retval = IBT_NODE_RECORDS_NOT_FOUND;
5746                                 continue;
5747                         }
5748 
5749                         if (local_node == B_FALSE) {
5750                                 ib_gid_t        sgid;
5751                                 int             sa_ret;
5752 
5753                                 /*
5754                                  * Check whether 'gid' and this port has same
5755                                  * subnet prefix. If not, then there is no use
5756                                  * in searching from this port.
5757                                  */
5758                                 sgid = hcap->hca_port_info[j].port_sgid0;
5759                                 if (gid.gid_prefix != sgid.gid_prefix) {
5760                                         IBTF_DPRINTF_L3(cmlog,
5761                                             "ibt_gid_to_node_info:Sn_Prefix of "
5762                                             "GID(%llX) and Port's(%llX) differ",
5763                                             gid.gid_prefix, sgid.gid_prefix);
5764                                         retval = IBT_NODE_RECORDS_NOT_FOUND;
5765                                         continue;
5766                                 }
5767 
5768                                 /*
5769                                  * First Get Path Records for the specified DGID
5770                                  * from this port (SGID). From Path Records,
5771                                  * note down DLID, then use this DLID as Input
5772                                  * attribute to get NodeRecords from SA Access.
5773                                  */
5774                                 npaths = 1;
5775                                 path = NULL;
5776 
5777                                 sa_ret = ibmf_saa_gid_to_pathrecords(saa_handle,
5778                                     sgid, gid, 0, 0, B_TRUE, &npaths, 0, &len,
5779                                     &path);
5780                                 if (sa_ret != IBMF_SUCCESS) {
5781                                         IBTF_DPRINTF_L2(cmlog,
5782                                             "ibt_gid_to_node_info: "
5783                                             "ibmf_saa_gid_to_pathrecords() "
5784                                             "returned error: %d ", sa_ret);
5785                                         retval =
5786                                             ibcm_ibmf_analyze_error(sa_ret);
5787                                         continue;
5788                                 } else if ((npaths == 0) || (path == NULL)) {
5789                                         IBTF_DPRINTF_L3(cmlog,
5790                                             "ibt_gid_to_node_info: failed (%d) "
5791                                             "to get path records for the DGID "
5792                                             "0x%llX from SGID 0x%llX", sa_ret,
5793                                             gid.gid_guid, sgid.gid_guid);
5794                                         retval = IBT_NODE_RECORDS_NOT_FOUND;
5795                                         continue;
5796                                 }
5797                                 node_lid = path->DLID;       /* LID */
5798 
5799                                 IBTF_DPRINTF_L3(cmlog, "ibt_gid_to_node_info: "
5800                                     "Remote Node: LID = 0x%X", node_lid);
5801 
5802                                 /* Free SA_Access memory for path record. */
5803                                 kmem_free(path, len);
5804                         }
5805 
5806                         /* Retrieve Node Records from SA Access. */
5807                         bzero(&nr_req, sizeof (sa_node_record_t));
5808 
5809                         nr_req.LID = node_lid;  /* LID */
5810 
5811                         retval = ibcm_get_node_rec(saa_handle, &nr_req,
5812                             SA_NODEINFO_COMPMASK_NODELID, &res_p, &len);
5813                         if (retval == IBT_NODE_RECORDS_NOT_FOUND) {
5814                                 IBTF_DPRINTF_L2(cmlog, "ibt_gid_to_node_info: "
5815                                     "failed (%d) to get Node records", retval);
5816                                 continue;
5817                         } else if (retval != IBT_SUCCESS) {
5818                                 IBTF_DPRINTF_L2(cmlog, "ibt_gid_to_node_info: "
5819                                     "failed (%d) to get Node records", retval);
5820                                 ibcm_dec_hca_acc_cnt(hcap);
5821                                 goto gid_to_ni_exit;
5822                         }
5823 
5824                         num_rec = len/sizeof (sa_node_record_t);
5825                         nr_resp = (sa_node_record_t *)(uchar_t *)res_p;
5826 
5827                         /* Validate the returned number of records. */
5828                         if ((nr_resp != NULL) && (num_rec > 0)) {
5829 
5830                                 IBCM_DUMP_NODE_REC(nr_resp);
5831 
5832                                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(
5833                                     *node_info_p))
5834 
5835                                 node_info_p->n_sys_img_guid =
5836                                     nr_resp->NodeInfo.SystemImageGUID;
5837                                 node_info_p->n_node_guid =
5838                                     nr_resp->NodeInfo.NodeGUID;
5839                                 node_info_p->n_port_guid =
5840                                     nr_resp->NodeInfo.PortGUID;
5841                                 node_info_p->n_dev_id =
5842                                     nr_resp->NodeInfo.DeviceID;
5843                                 node_info_p->n_revision =
5844                                     nr_resp->NodeInfo.Revision;
5845                                 node_info_p->n_vendor_id =
5846                                     nr_resp->NodeInfo.VendorID;
5847                                 node_info_p->n_num_ports =
5848                                     nr_resp->NodeInfo.NumPorts;
5849                                 node_info_p->n_port_num =
5850                                     nr_resp->NodeInfo.LocalPortNum;
5851                                 node_info_p->n_node_type =
5852                                     nr_resp->NodeInfo.NodeType;
5853                                 (void) strncpy(node_info_p->n_description,
5854                                     (char *)&nr_resp->NodeDescription, 64);
5855 
5856                                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(
5857                                     *node_info_p))
5858 
5859                                 /*
5860                                  * Deallocate the memory allocated by SA for
5861                                  * 'nr_resp'.
5862                                  */
5863                                 ibcm_dec_hca_acc_cnt(hcap);
5864                                 kmem_free(nr_resp, len);
5865                                 retval = IBT_SUCCESS;
5866 
5867                                 goto gid_to_ni_exit;
5868                         } else {
5869                                 retval = IBT_NODE_RECORDS_NOT_FOUND;
5870                                 IBTF_DPRINTF_L3(cmlog, "ibt_gid_to_node_info: "
5871                                     "Node Records NOT found - PortGUID %016llX",
5872                                     gid.gid_guid);
5873                         }
5874                 }
5875                 ibcm_dec_hca_acc_cnt(hcap);
5876 
5877                 if (local_node == B_TRUE)
5878                         break;
5879         }
5880 
5881 gid_to_ni_exit:
5882         if (guid_array)
5883                 ibt_free_hca_list(guid_array, num_hcas);
5884 
5885         IBTF_DPRINTF_L3(cmlog, "ibt_gid_to_node_info: done. Status %d", retval);
5886 
5887         return (retval);
5888 }
5889 
5890 
5891 ibt_status_t
5892 ibcm_get_node_rec(ibmf_saa_handle_t saa_handle, sa_node_record_t *nr_req,
5893     uint64_t component_mask, void *result_p, size_t *len)
5894 {
5895         ibmf_saa_access_args_t  args;
5896         size_t                  length;
5897         ibt_status_t            retval;
5898 
5899         args.sq_attr_id = SA_NODERECORD_ATTRID;
5900         args.sq_template = nr_req;
5901         args.sq_access_type = IBMF_SAA_RETRIEVE;
5902         args.sq_template_length = sizeof (sa_node_record_t);
5903         args.sq_component_mask = component_mask;
5904         args.sq_callback = NULL;
5905         args.sq_callback_arg = NULL;
5906 
5907         retval = ibcm_contact_sa_access(saa_handle, &args, &length, result_p);
5908         if (retval != IBT_SUCCESS) {
5909                 IBTF_DPRINTF_L2(cmlog, "ibcm_get_node_rec: SA Call Failed");
5910                 return (retval);
5911         }
5912 
5913         *len = length;
5914 
5915         /* Validate the returned number of records. */
5916         if ((result_p != NULL) && (length > 0)) {
5917                 IBTF_DPRINTF_L3(cmlog, "ibcm_get_node_rec: Node Records FOUND");
5918 
5919                 /* Got it, done!. */
5920                 return (IBT_SUCCESS);
5921         } else {
5922                 IBTF_DPRINTF_L2(cmlog, "ibcm_get_node_rec: Node Rec NOT found");
5923                 return (IBT_NODE_RECORDS_NOT_FOUND);
5924         }
5925 }
5926 
5927 
5928 /*
5929  * Function:
5930  *      ibt_lid_to_node_info()
5931  * Input:
5932  *      lid             Identifies the IB Node and port for which to obtain
5933  *                      Node information.
5934  * Output:
5935  *      node_info_p     A pointer to an ibt_node_info_t structure (allocated
5936  *                      by the caller) in which to return the node information.
5937  * Returns:
5938  *      IBT_SUCCESS
5939  *      IBT_INVALID_PARAM
5940  *      IBT_NODE_RECORDS_NOT_FOUND
5941  *      IBT_NO_HCAS_AVAILABLE
5942  * Description:
5943  *      Retrieve Node Information for the specified LID.
5944  */
5945 ibt_status_t
5946 ibt_lid_to_node_info(ib_lid_t lid, ibt_node_info_t *node_info_p)
5947 {
5948         ibt_status_t    retval;
5949         ibcm_hca_info_t *hcap;
5950         uint8_t         i, j;
5951         ib_guid_t       *guid_array = NULL;
5952         uint_t          num_hcas = 0;
5953 
5954 
5955         IBTF_DPRINTF_L4(cmlog, "ibt_lid_to_node_info(0x%lX, %p)",
5956             lid, node_info_p);
5957 
5958         if ((lid == 0) || (node_info_p == NULL)) {
5959                 IBTF_DPRINTF_L2(cmlog, "ibt_lid_to_node_info: "
5960                     "Lid is zero, or node_info_p is NULL.");
5961                 return (IBT_INVALID_PARAM);
5962         }
5963 
5964         /* Get the number of HCAs and their GUIDs */
5965         num_hcas = ibt_get_hca_list(&guid_array);
5966         IBTF_DPRINTF_L4(cmlog, "ibt_lid_to_node_info: ibt_get_hca_list "
5967             "returned %d hcas", num_hcas);
5968 
5969         if (num_hcas == 0) {
5970                 IBTF_DPRINTF_L2(cmlog, "ibt_lid_to_node_info: "
5971                     "NO HCA's Found on this system");
5972                 return (IBT_NO_HCAS_AVAILABLE);
5973         }
5974 
5975         for (i = 0; i < num_hcas; i++) {
5976                 hcap = ibcm_find_hca_entry(guid_array[i]);
5977                 if (hcap == NULL) {
5978                         IBTF_DPRINTF_L3(cmlog, "ibt_lid_to_node_info: "
5979                             "HCA(%llX) info not found", guid_array[i]);
5980                         retval = IBT_NO_HCAS_AVAILABLE;
5981                         continue;
5982                 }
5983 
5984                 for (j = 0; j < hcap->hca_num_ports; j++) {
5985                         uint8_t                 port;
5986                         ibmf_saa_handle_t       saa_handle;
5987                         uint_t                  num_rec;
5988                         size_t                  len;
5989                         void                    *res_p;
5990                         sa_node_record_t        nr_req, *nr_resp;
5991 
5992                         port = j + 1;
5993 
5994                         /* Get SA Access Handle. */
5995                         saa_handle = ibcm_get_saa_handle(hcap, port);
5996                         if (saa_handle == NULL) {
5997                                 IBTF_DPRINTF_L3(cmlog, "ibt_lid_to_node_info: "
5998                                     "Port %d of HCA (%llX) is NOT ACTIVE",
5999                                     port, guid_array[i]);
6000                                 retval = IBT_NODE_RECORDS_NOT_FOUND;
6001                                 continue;
6002                         }
6003 
6004                         /* Retrieve Node Records from SA Access. */
6005                         bzero(&nr_req, sizeof (sa_node_record_t));
6006 
6007                         nr_req.LID = lid;       /* LID */
6008 
6009                         retval = ibcm_get_node_rec(saa_handle, &nr_req,
6010                             SA_NODEINFO_COMPMASK_NODELID, &res_p, &len);
6011                         if (retval == IBT_NODE_RECORDS_NOT_FOUND) {
6012                                 IBTF_DPRINTF_L2(cmlog, "ibt_lid_to_node_info: "
6013                                     "failed (%d) to get Node records", retval);
6014                                 continue;
6015                         } else if (retval != IBT_SUCCESS) {
6016                                 IBTF_DPRINTF_L2(cmlog, "ibt_lid_to_node_info: "
6017                                     "failed (%d) to get Node records", retval);
6018                                 ibcm_dec_hca_acc_cnt(hcap);
6019                                 goto lid_to_ni_exit;
6020                         }
6021 
6022                         num_rec = len/sizeof (sa_node_record_t);
6023                         nr_resp = (sa_node_record_t *)(uchar_t *)res_p;
6024 
6025                         /* Validate the returned number of records. */
6026                         if ((nr_resp != NULL) && (num_rec > 0)) {
6027 
6028                                 IBCM_DUMP_NODE_REC(nr_resp);
6029 
6030                                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(
6031                                     *node_info_p))
6032 
6033                                 node_info_p->n_sys_img_guid =
6034                                     nr_resp->NodeInfo.SystemImageGUID;
6035                                 node_info_p->n_node_guid =
6036                                     nr_resp->NodeInfo.NodeGUID;
6037                                 node_info_p->n_port_guid =
6038                                     nr_resp->NodeInfo.PortGUID;
6039                                 node_info_p->n_dev_id =
6040                                     nr_resp->NodeInfo.DeviceID;
6041                                 node_info_p->n_revision =
6042                                     nr_resp->NodeInfo.Revision;
6043                                 node_info_p->n_vendor_id =
6044                                     nr_resp->NodeInfo.VendorID;
6045                                 node_info_p->n_num_ports =
6046                                     nr_resp->NodeInfo.NumPorts;
6047                                 node_info_p->n_port_num =
6048                                     nr_resp->NodeInfo.LocalPortNum;
6049                                 node_info_p->n_node_type =
6050                                     nr_resp->NodeInfo.NodeType;
6051                                 (void) strncpy(node_info_p->n_description,
6052                                     (char *)&nr_resp->NodeDescription, 64);
6053 
6054                                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(
6055                                     *node_info_p))
6056 
6057                                 /*
6058                                  * Deallocate the memory allocated by SA for
6059                                  * 'nr_resp'.
6060                                  */
6061                                 ibcm_dec_hca_acc_cnt(hcap);
6062                                 kmem_free(nr_resp, len);
6063                                 retval = IBT_SUCCESS;
6064 
6065                                 goto lid_to_ni_exit;
6066                         } else {
6067                                 retval = IBT_NODE_RECORDS_NOT_FOUND;
6068                                 IBTF_DPRINTF_L3(cmlog, "ibt_lid_to_node_info: "
6069                                     "Node Records NOT found - LID 0x%lX",
6070                                     lid);
6071                         }
6072                 }
6073                 ibcm_dec_hca_acc_cnt(hcap);
6074         }
6075 
6076 lid_to_ni_exit:
6077         if (guid_array)
6078                 ibt_free_hca_list(guid_array, num_hcas);
6079 
6080         IBTF_DPRINTF_L3(cmlog, "ibt_lid_to_node_info: done. Status %d", retval);
6081 
6082         return (retval);
6083 }
6084 
6085 /*
6086  * Function:
6087  *      ibt_get_companion_port_gids()
6088  * Description:
6089  *      Get list of GID's available on a companion port(s) of the specified
6090  *      GID or list of GIDs available on a specified Node GUID/SystemImage GUID.
6091  */
6092 ibt_status_t
6093 ibt_get_companion_port_gids(ib_gid_t gid, ib_guid_t hca_guid,
6094     ib_guid_t sysimg_guid, ib_gid_t **gids_p, uint_t *num_gids_p)
6095 {
6096         sa_node_record_t        nr_req, *nr_resp;
6097         void                    *res_p;
6098         ibmf_saa_handle_t       saa_handle;
6099         int                     sa_ret;
6100         ibt_status_t            retval = IBT_SUCCESS;
6101         ibcm_hca_info_t         *hcap;
6102         ibtl_cm_hca_port_t      hport;
6103         int                     i, j;
6104         uint_t                  num_rec;
6105         ib_guid_t               *guid_array = NULL;
6106         sa_path_record_t        *path;
6107         size_t                  len;
6108         uint8_t                 npaths;
6109         uint32_t                num_hcas = 0;
6110         boolean_t               local_node = B_FALSE;
6111         boolean_t               local_hca = B_FALSE;
6112         ib_guid_t               h_guid = hca_guid;
6113         ib_gid_t                *gidp = NULL, *t_gidp = NULL;
6114         int                     multi_hca_loop = 0;
6115 
6116         IBTF_DPRINTF_L4(cmlog, "ibt_get_companion_port_gids(%llX:%llX, %llX, "
6117             "%llX)", gid.gid_prefix, gid.gid_guid, hca_guid, sysimg_guid);
6118 
6119         if (((gid.gid_prefix == 0) || (gid.gid_guid == 0)) && (hca_guid == 0) &&
6120             (sysimg_guid == 0)) {
6121                 IBTF_DPRINTF_L2(cmlog, "ibt_get_companion_port_gids: "
6122                     "Null Input attribute specified.");
6123                 return (IBT_INVALID_PARAM);
6124         }
6125 
6126         if ((num_gids_p == NULL) || (gids_p == NULL)) {
6127                 IBTF_DPRINTF_L2(cmlog, "ibt_get_companion_port_gids: "
6128                     "num_gids_p or gids_p is NULL");
6129                 return (IBT_INVALID_PARAM);
6130         }
6131 
6132         *num_gids_p = 0;
6133 
6134         /* Get the number of HCAs and their GUIDs */
6135         if ((num_hcas = ibt_get_hca_list(&guid_array)) == 0) {
6136                 IBTF_DPRINTF_L2(cmlog, "ibt_get_companion_port_gids: "
6137                     "NO HCA's Found on this system");
6138                 return (IBT_NO_HCAS_AVAILABLE);
6139         }
6140 
6141         IBTF_DPRINTF_L4(cmlog, "ibt_get_companion_port_gids: "
6142             "ibt_get_hca_list() returned %d hcas", num_hcas);
6143 
6144         /*
6145          * If 'gid' is on local node, then get node lid (i.e. base lid of the
6146          * associated port) info via ibtl_cm_get_hca_port() call.
6147          */
6148         bzero(&hport, sizeof (ibtl_cm_hca_port_t));
6149         if ((gid.gid_prefix != 0) && (gid.gid_guid != 0) &&
6150             (ibtl_cm_get_hca_port(gid, 0, &hport) == IBT_SUCCESS)) {
6151 
6152                 if ((hca_guid != 0) && (hca_guid != hport.hp_hca_guid)) {
6153                         IBTF_DPRINTF_L2(cmlog, "ibt_get_companion_port_gids: "
6154                             "Invalid GID<->HCAGUID combination specified.");
6155                         retval = IBT_INVALID_PARAM;
6156                         goto get_comp_pgid_exit;
6157                 }
6158                 h_guid = hport.hp_hca_guid;
6159                 local_node = B_TRUE;
6160 
6161                 IBTF_DPRINTF_L4(cmlog, "ibt_get_companion_port_gids: "
6162                     "Local Node: HCA (0x%llX)", h_guid);
6163         } else if (h_guid) {    /* Is specified HCA GUID - local? */
6164                 for (i = 0; i < num_hcas; i++) {
6165                         if (h_guid == guid_array[i]) {
6166                                 local_hca = B_TRUE;
6167                                 break;
6168                         }
6169                 }
6170         } else if (sysimg_guid) { /* Is specified SystemImage GUID - local? */
6171                 for (i = 0; i < num_hcas; i++) {
6172                         ibt_status_t    ret;
6173                         ibt_hca_attr_t  hca_attr;
6174 
6175                         ret = ibt_query_hca_byguid(guid_array[i], &hca_attr);
6176                         if (ret != IBT_SUCCESS) {
6177                                 IBTF_DPRINTF_L2(cmlog,
6178                                     "ibt_get_companion_port_gids: HCA(%llX) "
6179                                     "info not found", guid_array[i]);
6180                                 retval = IBT_NO_HCAS_AVAILABLE;
6181                                 continue;
6182                         }
6183                         if (hca_attr.hca_si_guid == sysimg_guid) {
6184                                 if ((hca_guid != 0) &&
6185                                     (hca_guid != hca_attr.hca_node_guid)) {
6186                                         IBTF_DPRINTF_L2(cmlog,
6187                                             "ibt_get_companion_port_gids: "
6188                                             "Invalid SysImg<->HCA GUID "
6189                                             "combination specified.");
6190                                         retval = IBT_INVALID_PARAM;
6191                                         goto get_comp_pgid_exit;
6192                                 }
6193                                 local_hca = B_TRUE;
6194                                 h_guid = hca_attr.hca_node_guid;
6195                                 break;
6196                         }
6197                 }
6198         }
6199 
6200         if ((local_node == B_TRUE) || (local_hca == B_TRUE)) {
6201                 retval = ibtl_cm_get_local_comp_gids(h_guid, gid, gids_p,
6202                     num_gids_p);
6203                 goto get_comp_pgid_exit;
6204         }
6205 
6206 get_comp_for_multihca:
6207         /* We will be here, if request is for remote node */
6208         for (i = 0; i < num_hcas; i++) {
6209                 int             multism;
6210                 uint_t          count = 0;
6211                 int             multi_sm_loop = 0;
6212                 uint_t          k = 0, l;
6213 
6214                 hcap = ibcm_find_hca_entry(guid_array[i]);
6215                 if (hcap == NULL) {
6216                         IBTF_DPRINTF_L3(cmlog, "ibt_get_companion_port_gids: "
6217                             "HCA(%llX) info not found", guid_array[i]);
6218                         retval = IBT_NO_HCAS_AVAILABLE;
6219                         continue;
6220                 }
6221 
6222                 /* 1 - MultiSM, 0 - Single SM */
6223                 multism = ibtl_cm_is_multi_sm(guid_array[i]);
6224 
6225                 for (j = 0; j < hcap->hca_num_ports; j++) {
6226                         ib_gid_t        sgid;
6227                         uint64_t        c_mask = 0;
6228                         ib_guid_t       pg;
6229                         uint_t          port = j;
6230 
6231 get_comp_for_multism:
6232                         IBTF_DPRINTF_L3(cmlog, "ibt_get_companion_port_gids: "
6233                             "Port %d, HCA %llX, MultiSM= %d, Loop=%d",
6234                             port + 1, h_guid, multism, multi_sm_loop);
6235 
6236                         /* Get SA Access Handle. */
6237                         saa_handle = ibcm_get_saa_handle(hcap, port + 1);
6238                         if (saa_handle == NULL) {
6239                                 IBTF_DPRINTF_L2(cmlog,
6240                                     "ibt_get_companion_port_gids: "
6241                                     "Port (%d)  - NOT ACTIVE", port + 1);
6242                                 retval = IBT_GIDS_NOT_FOUND;
6243                                 continue;
6244                         }
6245 
6246                         /*
6247                          * Check whether 'gid' and this port has same subnet
6248                          * prefix. If not, then there is no use in searching
6249                          * from this port.
6250                          */
6251                         sgid = hcap->hca_port_info[port].port_sgid0;
6252                         if ((h_guid == 0) && (gid.gid_prefix != 0) &&
6253                             (multi_sm_loop == 0) &&
6254                             (gid.gid_prefix != sgid.gid_prefix)) {
6255                                 IBTF_DPRINTF_L2(cmlog,
6256                                     "ibt_get_companion_port_gids: SnPrefix of "
6257                                     "GID(%llX) and Port SN_Pfx(%llX) differ",
6258                                     gid.gid_prefix, sgid.gid_prefix);
6259                                 retval = IBT_GIDS_NOT_FOUND;
6260                                 continue;
6261                         }
6262 
6263                         /*
6264                          * If HCA GUID or System Image GUID is specified, then
6265                          * we can achieve our goal sooner!.
6266                          */
6267                         if ((h_guid == 0) && (sysimg_guid == 0)) {
6268                                 /* So only GID info is provided. */
6269 
6270                                 /*
6271                                  * First Get Path Records for the specified DGID
6272                                  * from this port (SGID). From Path Records,
6273                                  * note down DLID, then use this DLID as Input
6274                                  * attribute to get NodeRecords.
6275                                  */
6276                                 npaths = 1;
6277                                 path = NULL;
6278 
6279                                 sa_ret = ibmf_saa_gid_to_pathrecords(saa_handle,
6280                                     sgid, gid, 0, 0, B_TRUE, &npaths, 0, &len,
6281                                     &path);
6282                                 if (sa_ret != IBMF_SUCCESS) {
6283                                         IBTF_DPRINTF_L2(cmlog,
6284                                             "ibt_get_companion_port_gids: "
6285                                             "ibmf_saa_gid_to_pathrecords() "
6286                                             "returned error: %d ", sa_ret);
6287                                         retval =
6288                                             ibcm_ibmf_analyze_error(sa_ret);
6289                                         ibcm_dec_hca_acc_cnt(hcap);
6290                                         goto get_comp_pgid_exit;
6291                                 } else if ((npaths == 0) || (path == NULL)) {
6292                                         IBTF_DPRINTF_L2(cmlog,
6293                                             "ibt_get_companion_port_gids: "
6294                                             "failed (%d) to get path records "
6295                                             "for the DGID (0x%llX) from SGID "
6296                                             "(0x%llX)", sa_ret, gid.gid_guid,
6297                                             sgid.gid_guid);
6298                                         retval = IBT_GIDS_NOT_FOUND;
6299                                         continue;
6300                                 }
6301 
6302                                 bzero(&nr_req, sizeof (sa_node_record_t));
6303                                 nr_req.LID = path->DLID;     /* LID */
6304 
6305                                 IBTF_DPRINTF_L3(cmlog,
6306                                     "ibt_get_companion_port_gids: "
6307                                     "Remote Node: LID = 0x%X", nr_req.LID);
6308 
6309                                 /* Free SA_Access memory for path record. */
6310                                 kmem_free(path, len);
6311 
6312                                 IBTF_DPRINTF_L3(cmlog,
6313                                     "ibt_get_companion_port_gids: SAA Call: "
6314                                     "based on LID ");
6315 
6316                                 retval = ibcm_get_node_rec(saa_handle, &nr_req,
6317                                     SA_NODEINFO_COMPMASK_NODELID, &res_p, &len);
6318                                 if (retval == IBT_NODE_RECORDS_NOT_FOUND) {
6319                                         IBTF_DPRINTF_L2(cmlog,
6320                                             "ibt_get_companion_port_gids: "
6321                                             "failed (%d) to get Node records",
6322                                             retval);
6323                                         continue;
6324                                 } else if (retval != IBT_SUCCESS) {
6325                                         IBTF_DPRINTF_L2(cmlog,
6326                                             "ibt_get_companion_port_gids: "
6327                                             "failed (%d) to get Node records",
6328                                             retval);
6329                                         ibcm_dec_hca_acc_cnt(hcap);
6330                                         goto get_comp_pgid_exit;
6331                                 }
6332 
6333                                 nr_resp = (sa_node_record_t *)(uchar_t *)res_p;
6334                                 /* Note down HCA GUID info. */
6335                                 h_guid = nr_resp->NodeInfo.NodeGUID;
6336 
6337                                 IBTF_DPRINTF_L3(cmlog,
6338                                     "ibt_get_companion_port_gids: "
6339                                     "Remote HCA GUID: 0x%llX", h_guid);
6340 
6341                                 IBCM_DUMP_NODE_REC(nr_resp);
6342 
6343                                 kmem_free(res_p, len);
6344                         }
6345 
6346                         bzero(&nr_req, sizeof (sa_node_record_t));
6347                         if (h_guid != 0) {
6348                                 nr_req.NodeInfo.NodeGUID = h_guid;
6349                                 c_mask = SA_NODEINFO_COMPMASK_NODEGUID;
6350                         }
6351 
6352                         if (sysimg_guid != 0) {
6353                                 nr_req.NodeInfo.SystemImageGUID = sysimg_guid;
6354                                 c_mask |= SA_NODEINFO_COMPMASK_SYSIMAGEGUID;
6355                         }
6356 
6357                         IBTF_DPRINTF_L3(cmlog, "ibt_get_companion_port_gids: "
6358                             "SAA Call: CMASK= 0x%llX", c_mask);
6359 
6360                         retval = ibcm_get_node_rec(saa_handle, &nr_req, c_mask,
6361                             &res_p, &len);
6362                         if (retval == IBT_NODE_RECORDS_NOT_FOUND) {
6363                                 IBTF_DPRINTF_L3(cmlog,
6364                                     "ibt_get_companion_port_gids: "
6365                                     "failed (%d) to get Node records", retval);
6366                                 continue;
6367                         } else if (retval != IBT_SUCCESS) {
6368                                 IBTF_DPRINTF_L2(cmlog,
6369                                     "ibt_get_companion_port_gids: Error: (%d) "
6370                                     "while getting Node records", retval);
6371                                 ibcm_dec_hca_acc_cnt(hcap);
6372                                 goto get_comp_pgid_exit;
6373                         }
6374 
6375                         num_rec = len/sizeof (sa_node_record_t);
6376 
6377                         /* We will be here, only if we found some NodeRec */
6378                         if (gid.gid_prefix && gid.gid_guid) {
6379                                 nr_resp = (sa_node_record_t *)res_p;
6380                                 for (l = 0; l < num_rec; l++, nr_resp++) {
6381                                         pg = nr_resp->NodeInfo.PortGUID;
6382                                         if (gid.gid_guid != pg)
6383                                                 count++;
6384                                 }
6385                         } else {
6386                                 count = num_rec;
6387                         }
6388 
6389                         if (count != 0) {
6390                                 if (multi_sm_loop == 1) {
6391                                         count += k;
6392                                         t_gidp = kmem_zalloc(count *
6393                                             sizeof (ib_gid_t), KM_SLEEP);
6394 
6395                                         if ((k != 0) && (gidp != NULL)) {
6396                                                 bcopy(gidp, t_gidp,
6397                                                     k * sizeof (ib_gid_t));
6398                                                 kmem_free(gidp,
6399                                                     k * sizeof (ib_gid_t));
6400                                         }
6401                                         gidp = t_gidp;
6402                                 } else {
6403                                         gidp = kmem_zalloc(count *
6404                                             sizeof (ib_gid_t), KM_SLEEP);
6405                                 }
6406                                 *num_gids_p = count;
6407                                 *gids_p = gidp;
6408 
6409                                 nr_resp = (sa_node_record_t *)res_p;
6410                                 for (l = 0; l < num_rec; l++, nr_resp++) {
6411                                         IBCM_DUMP_NODE_REC(nr_resp);
6412 
6413                                         pg = nr_resp->NodeInfo.PortGUID;
6414                                         IBTF_DPRINTF_L4(cmlog,
6415                                             "ibt_get_companion_port_gids: "
6416                                             "PortGID %llX", pg);
6417 
6418                                         if (pg != gid.gid_guid) {
6419                                                 gidp[k].gid_prefix =
6420                                                     sgid.gid_prefix;
6421                                                 gidp[k].gid_guid = pg;
6422 
6423                                                 IBTF_DPRINTF_L3(cmlog,
6424                                                     "ibt_get_companion_pgids: "
6425                                                     "GID[%d] = %llX:%llX", k,
6426                                                     gidp[k].gid_prefix,
6427                                                     gidp[k].gid_guid);
6428 
6429                                                 k++;
6430                                                 if (k == count)
6431                                                         break;
6432                                         }
6433                                 }
6434                                 retval = IBT_SUCCESS;   /* done!. */
6435                                 kmem_free(res_p, len);
6436                                 ibcm_dec_hca_acc_cnt(hcap);
6437                                 goto get_comp_pgid_exit;
6438                         } else {
6439                                 IBTF_DPRINTF_L2(cmlog,
6440                                     "ibt_get_companion_port_gids: "
6441                                     "Companion PortGIDs not available");
6442                                 retval = IBT_GIDS_NOT_FOUND;
6443                         }
6444                         /* Deallocate the memory for 'res_p'. */
6445                         kmem_free(res_p, len);
6446 
6447                         /*
6448                          * If we are on MultiSM setup, then we need to lookout
6449                          * from that subnet port too.
6450                          */
6451                         if (multism) {
6452                                 /* break if already searched both the subnet */
6453                                 if (multi_sm_loop == 1)
6454                                         break;
6455 
6456                                 port = (j == 0) ? 1 : 0;
6457                                 multi_sm_loop = 1;
6458                                 goto get_comp_for_multism;
6459                         } else {
6460                                 break;
6461                         }
6462                 }
6463                 ibcm_dec_hca_acc_cnt(hcap);
6464 
6465                 /*
6466                  * We may be on dual HCA with dual SM configured system.  And
6467                  * the input attr GID was visible from second HCA. So in order
6468                  * to get the companion portgid we need to re-look from the
6469                  * first HCA ports.
6470                  */
6471                 if ((num_hcas > 1) && (i > 0) && (h_guid != 0) &&
6472                     (multi_hca_loop != 1)) {
6473                         multi_hca_loop = 1;
6474                         goto get_comp_for_multihca;
6475                 }
6476         }
6477         if (*num_gids_p == 0)
6478                 retval = IBT_GIDS_NOT_FOUND;
6479 
6480 get_comp_pgid_exit:
6481         if (guid_array)
6482                 ibt_free_hca_list(guid_array, num_hcas);
6483 
6484         if ((retval != IBT_SUCCESS) && (*num_gids_p != 0)) {
6485                 retval = IBT_SUCCESS;
6486         }
6487 
6488         IBTF_DPRINTF_L3(cmlog, "ibt_get_companion_port_gids: done. Status %d, "
6489             "Found %d GIDs", retval, *num_gids_p);
6490 
6491         return (retval);
6492 }
6493 
6494 /* RDMA IP CM Support routines */
6495 ibt_status_t
6496 ibt_get_src_ip(ibt_srcip_attr_t *sattr, ibt_srcip_info_t **src_info_p,
6497     uint_t *entries_p)
6498 {
6499         ibt_srcip_info_t        *s_ip;
6500         ibcm_arp_ip_t           *ipp;
6501         ibcm_arp_ibd_insts_t    ibds;
6502         uint8_t                 i, j;
6503         uint_t                  count;
6504         ibt_status_t            retval = IBT_SUCCESS;
6505 
6506         IBTF_DPRINTF_L4(cmlog, "ibt_get_src_ip(%p, %p, %p)",
6507             sattr, src_info_p, entries_p);
6508 
6509         if (sattr == NULL || entries_p == NULL) {
6510                 IBTF_DPRINTF_L3(cmlog, "ibt_get_src_ip: Invalid I/P Args.");
6511                 return (IBT_INVALID_PARAM);
6512         }
6513 
6514         if (sattr->sip_gid.gid_prefix == 0 || sattr->sip_gid.gid_guid == 0) {
6515                 IBTF_DPRINTF_L3(cmlog, "ibt_get_src_ip: Invalid GID.");
6516                 return (IBT_INVALID_PARAM);
6517         }
6518 
6519         /* TBD: Zoneid */
6520         retval = ibcm_arp_get_ibds(&ibds, sattr->sip_family);
6521         if (retval != IBT_SUCCESS) {
6522                 IBTF_DPRINTF_L2(cmlog, "ibt_get_src_ip: ibcm_arp_get_ibds "
6523                     "failed to get IBD Instances: ret 0x%x", retval);
6524                 goto get_src_ip_end;
6525         }
6526 
6527         count = 0;
6528         for (i = 0, ipp = ibds.ibcm_arp_ip; i < ibds.ibcm_arp_ibd_cnt;
6529             i++, ipp++) {
6530                 if (ipp->ip_inet_family == AF_UNSPEC)
6531                         continue;
6532                 if (ipp->ip_port_gid.gid_prefix == sattr->sip_gid.gid_prefix &&
6533                     ipp->ip_port_gid.gid_guid == sattr->sip_gid.gid_guid) {
6534                         if ((sattr->sip_pkey) &&
6535                             (ipp->ip_pkey != sattr->sip_pkey))
6536                                 continue;
6537 
6538                         if ((sattr->sip_zoneid != ALL_ZONES) &&
6539                             (sattr->sip_zoneid != ipp->ip_zoneid))
6540                                 continue;
6541 
6542                         count++;
6543                         break;
6544                 }
6545         }
6546 
6547         if (count) {
6548                 /*
6549                  * Allocate memory for return buffer, to be freed by
6550                  * ibt_free_srcip_info().
6551                  */
6552                 s_ip = kmem_alloc((count * sizeof (ibt_srcip_info_t)),
6553                     KM_SLEEP);
6554 
6555                 *src_info_p = s_ip;
6556                 *entries_p = count;
6557 
6558                 j = 0;
6559                 for (i = 0, ipp = ibds.ibcm_arp_ip; i < ibds.ibcm_arp_ibd_cnt;
6560                     i++, ipp++) {
6561                         if (ipp->ip_inet_family == AF_UNSPEC)
6562                                 continue;
6563                         if ((ipp->ip_port_gid.gid_prefix ==
6564                             sattr->sip_gid.gid_prefix) &&
6565                             (ipp->ip_port_gid.gid_guid ==
6566                             sattr->sip_gid.gid_guid)) {
6567                                 if ((sattr->sip_pkey) &&
6568                                     (ipp->ip_pkey != sattr->sip_pkey))
6569                                         continue;
6570 
6571                                 if ((sattr->sip_zoneid != ALL_ZONES) &&
6572                                     (sattr->sip_zoneid != ipp->ip_zoneid))
6573                                         continue;
6574 
6575                                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*s_ip))
6576                                 s_ip[j].ip_addr.family = ipp->ip_inet_family;
6577                                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*s_ip))
6578                                 if (s_ip[j].ip_addr.family == AF_INET) {
6579                                         bcopy(&ipp->ip_cm_sin.sin_addr,
6580                                             &s_ip[j].ip_addr.un.ip4addr,
6581                                             sizeof (in_addr_t));
6582                                 } else if (s_ip[j].ip_addr.family == AF_INET6) {
6583                                         bcopy(&ipp->ip_cm_sin6.sin6_addr,
6584                                             &s_ip[j].ip_addr.un.ip6addr,
6585                                             sizeof (in6_addr_t));
6586                                         /* TBD: scope_id */
6587                                 }
6588                                 IBCM_PRINT_IP("ibt_get_src_ip",
6589                                     &s_ip[j].ip_addr);
6590                                 j++;
6591                         }
6592                 }
6593         } else {
6594                 retval = IBT_SRC_IP_NOT_FOUND;
6595         }
6596 
6597 get_src_ip_end:
6598         ibcm_arp_free_ibds(&ibds);
6599         return (retval);
6600 }
6601 
6602 /*
6603  * ibt_free_srcip_info()
6604  *      Free the memory allocated by successful ibt_get_src_ip()
6605  *
6606  *      src_info        Pointer returned by ibt_get_src_ip().
6607  *
6608  *      entries         The number of ibt_ip_addr_t entries to free.
6609  */
6610 void
6611 ibt_free_srcip_info(ibt_srcip_info_t *src_info, uint_t entries)
6612 {
6613         IBTF_DPRINTF_L3(cmlog, "ibt_free_srcip_info: "
6614             "Free <%d> entries from 0x%p", entries, src_info);
6615 
6616         if ((src_info != NULL) && (entries > 0))
6617                 kmem_free(src_info, entries * sizeof (ibt_srcip_info_t));
6618         else
6619                 IBTF_DPRINTF_L2(cmlog, "ibt_free_srcip_info: "
6620                     "ERROR: NULL buf pointer or ZERO length specified.");
6621 }
6622 
6623 
6624 ib_svc_id_t
6625 ibt_get_ip_sid(uint8_t protocol_num, in_port_t dst_port)
6626 {
6627         ib_svc_id_t     sid;
6628 
6629         IBTF_DPRINTF_L4(cmlog, "ibt_get_ip_sid(%X, %lX)", protocol_num,
6630             dst_port);
6631 
6632         /*
6633          * If protocol_num is non-zero, then formulate the SID and return it.
6634          * If protocol_num is zero, then we need to assign a locally generated
6635          * IP SID with IB_SID_IPADDR_PREFIX.
6636          */
6637         if (protocol_num) {
6638                 sid = IB_SID_IPADDR_PREFIX | protocol_num << 16 | dst_port;
6639         } else {
6640                 sid = ibcm_alloc_ip_sid();
6641         }
6642 
6643         IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_sid: SID: 0x%016llX", sid);
6644         return (sid);
6645 }
6646 
6647 ibt_status_t
6648 ibt_release_ip_sid(ib_svc_id_t ip_sid)
6649 {
6650         IBTF_DPRINTF_L4(cmlog, "ibt_release_ip_sid(%llX)", ip_sid);
6651 
6652         if (((ip_sid & IB_SID_IPADDR_PREFIX_MASK) != 0) ||
6653             (!(ip_sid & IB_SID_IPADDR_PREFIX))) {
6654                 IBTF_DPRINTF_L2(cmlog, "ibt_release_ip_sid(0x%016llX): ERROR: "
6655                     "Called for Non-RDMA IP SID", ip_sid);
6656                 return (IBT_INVALID_PARAM);
6657         }
6658 
6659         /*
6660          * If protocol_num in ip_sid are all ZEROs, then this SID is allocated
6661          * by IBTF. If not, then the specified ip_sid is invalid.
6662          */
6663         if (ip_sid & IB_SID_IPADDR_IPNUM_MASK) {
6664                 IBTF_DPRINTF_L2(cmlog, "ibt_release_ip_sid(0x%016llX): ERROR: "
6665                     "Called for Non-IBTF assigned RDMA IP SID", ip_sid);
6666                 return (IBT_INVALID_PARAM);
6667         }
6668 
6669         ibcm_free_ip_sid(ip_sid);
6670 
6671         return (IBT_SUCCESS);
6672 }
6673 
6674 
6675 uint8_t
6676 ibt_get_ip_protocol_num(ib_svc_id_t sid)
6677 {
6678         return ((sid & IB_SID_IPADDR_IPNUM_MASK) >> 16);
6679 }
6680 
6681 in_port_t
6682 ibt_get_ip_dst_port(ib_svc_id_t sid)
6683 {
6684         return (sid & IB_SID_IPADDR_PORTNUM_MASK);
6685 }
6686 
6687 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibt_ip_cm_info_t))
6688 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibcm_ip_pvtdata_t))
6689 
6690 ibt_status_t
6691 ibt_format_ip_private_data(ibt_ip_cm_info_t *ip_cm_info,
6692     ibt_priv_data_len_t priv_data_len, void *priv_data_p)
6693 {
6694         ibcm_ip_pvtdata_t       ip_data;
6695 
6696         IBTF_DPRINTF_L4(cmlog, "ibt_format_ip_private_data(%p, %d, %p)",
6697             ip_cm_info, priv_data_len, priv_data_p);
6698 
6699         if ((ip_cm_info == NULL) || (priv_data_p == NULL) ||
6700             (priv_data_len < IBT_IP_HDR_PRIV_DATA_SZ)) {
6701                 IBTF_DPRINTF_L2(cmlog, "ibt_format_ip_private_data: ERROR "
6702                     "Invalid Inputs.");
6703                 return (IBT_INVALID_PARAM);
6704         }
6705 
6706         bzero(&ip_data, sizeof (ibcm_ip_pvtdata_t));
6707         ip_data.ip_srcport = ip_cm_info->src_port; /* Source Port */
6708 
6709         IBCM_PRINT_IP("format_ip_pvt: src", &ip_cm_info->src_addr);
6710         IBCM_PRINT_IP("format_ip_pvt: dst", &ip_cm_info->dst_addr);
6711         /* IPV = 0x4, if IP-Addr are IPv4 format, else 0x6 for IPv6 */
6712         if (ip_cm_info->src_addr.family == AF_INET) {
6713                 ip_data.ip_ipv = IBT_CM_IP_IPV_V4;
6714                 ip_data.ip_srcv4 = ip_cm_info->src_addr.un.ip4addr;
6715                 ip_data.ip_dstv4 = ip_cm_info->dst_addr.un.ip4addr;
6716         } else if (ip_cm_info->src_addr.family == AF_INET6) {
6717                 ip_data.ip_ipv = IBT_CM_IP_IPV_V6;
6718                 bcopy(&ip_cm_info->src_addr.un.ip6addr,
6719                     &ip_data.ip_srcv6, sizeof (in6_addr_t));
6720                 bcopy(&ip_cm_info->dst_addr.un.ip6addr,
6721                     &ip_data.ip_dstv6, sizeof (in6_addr_t));
6722         } else {
6723                 IBTF_DPRINTF_L2(cmlog, "ibt_format_ip_private_data: ERROR "
6724                     "IP Addr needs to be either AF_INET or AF_INET6 family.");
6725                 return (IBT_INVALID_PARAM);
6726         }
6727 
6728         ip_data.ip_MajV = IBT_CM_IP_MAJ_VER;
6729         ip_data.ip_MinV = IBT_CM_IP_MIN_VER;
6730 
6731         bcopy(&ip_data, priv_data_p, IBT_IP_HDR_PRIV_DATA_SZ);
6732 
6733         return (IBT_SUCCESS);
6734 }
6735 
6736 
6737 ibt_status_t
6738 ibt_get_ip_data(ibt_priv_data_len_t priv_data_len, void *priv_data,
6739     ibt_ip_cm_info_t *ip_cm_infop)
6740 {
6741         ibcm_ip_pvtdata_t       ip_data;
6742 
6743         IBTF_DPRINTF_L4(cmlog, "ibt_get_ip_data(%d, %p, %p)",
6744             priv_data_len, priv_data, ip_cm_infop);
6745 
6746         if ((ip_cm_infop == NULL) || (priv_data == NULL) ||
6747             (priv_data_len < IBT_IP_HDR_PRIV_DATA_SZ)) {
6748                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_data: ERROR Invalid Inputs");
6749                 return (IBT_INVALID_PARAM);
6750         }
6751 
6752         bcopy(priv_data, &ip_data, IBT_IP_HDR_PRIV_DATA_SZ);
6753         ip_cm_infop->src_port = ip_data.ip_srcport; /* Source Port */
6754 
6755         /* IPV = 0x4, if IP Address are IPv4 format, else 0x6 for IPv6 */
6756         if (ip_data.ip_ipv == IBT_CM_IP_IPV_V4) {
6757                 /* Copy IPv4 Addr */
6758                 ip_cm_infop->src_addr.family = ip_cm_infop->dst_addr.family =
6759                     AF_INET;
6760                 ip_cm_infop->src_addr.un.ip4addr = ip_data.ip_srcv4;
6761                 ip_cm_infop->dst_addr.un.ip4addr = ip_data.ip_dstv4;
6762         } else if (ip_data.ip_ipv == IBT_CM_IP_IPV_V6) {
6763                 /* Copy IPv6 Addr */
6764                 ip_cm_infop->src_addr.family = ip_cm_infop->dst_addr.family =
6765                     AF_INET6;
6766                 bcopy(&ip_data.ip_srcv6, &ip_cm_infop->src_addr.un.ip6addr,
6767                     sizeof (in6_addr_t));
6768                 bcopy(&ip_data.ip_dstv6, &ip_cm_infop->dst_addr.un.ip6addr,
6769                     sizeof (in6_addr_t));
6770         } else {
6771                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_data: ERROR: IP Addr needs"
6772                     " to be either AF_INET or AF_INET6 family.");
6773                 return (IBT_INVALID_PARAM);
6774         }
6775         IBCM_PRINT_IP("ibt_get_ip_data: src", &ip_cm_infop->src_addr);
6776         IBCM_PRINT_IP("ibt_get_ip_data: dst", &ip_cm_infop->dst_addr);
6777 
6778         return (IBT_SUCCESS);
6779 }
6780 
6781 
6782 /* Routines for warlock */
6783 
6784 /* ARGSUSED */
6785 static void
6786 ibcm_dummy_mcg_handler(void *arg, ibt_status_t retval, ibt_mcg_info_t *minfo)
6787 {
6788         ibcm_join_mcg_tqarg_t   dummy_mcg;
6789 
6790         dummy_mcg.func = ibcm_dummy_mcg_handler;
6791 
6792         IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_mcg_handler: "
6793             "dummy_mcg.func %p", dummy_mcg.func);
6794 }
6795 
6796 
6797 /* ARGSUSED */
6798 static void
6799 ibcm_dummy_recycle_rc_handler(ibt_status_t retval, void *arg)
6800 {
6801         ibcm_taskq_recycle_arg_t        dummy_rc_recycle;
6802 
6803         dummy_rc_recycle.func = ibcm_dummy_recycle_rc_handler;
6804 
6805         IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_recycle_rc_handler: "
6806             "dummy_rc_recycle.func %p", dummy_rc_recycle.func);
6807 }
6808 
6809 
6810 /* ARGSUSED */
6811 static ibt_cm_status_t
6812 ibcm_dummy_ud_handler(void *priv, ibt_cm_ud_event_t *event,
6813     ibt_cm_ud_return_args_t *ret_args,
6814     void *priv_data, ibt_priv_data_len_t len)
6815 {
6816         /*
6817          * Let warlock see that ibcm_local_handler_s::actual_cm_handler
6818          * points to this routine.
6819          */
6820         ibcm_local_handler_t    p;
6821         ibcm_ud_state_data_t    dummy_ud;
6822 
6823         p.actual_cm_handler = ibcm_dummy_ud_handler;
6824         dummy_ud.ud_cm_handler = ibcm_dummy_ud_handler;
6825 
6826         IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_ud_handler: p.actual_cm_handler %p"
6827             "dummy_ud.ud_cm_handler %p", p.actual_cm_handler,
6828             dummy_ud.ud_cm_handler);
6829         /*
6830          * Call all routines that the client's callback routine could call.
6831          */
6832 
6833         return (IBT_CM_ACCEPT);
6834 }
6835 
6836 /* ARGSUSED */
6837 static ibt_cm_status_t
6838 ibcm_dummy_rc_handler(void *priv, ibt_cm_event_t *event,
6839     ibt_cm_return_args_t *ret_args, void *priv_data, ibt_priv_data_len_t len)
6840 {
6841         ibcm_state_data_t       dummy_rc;
6842 
6843         dummy_rc.cm_handler = ibcm_dummy_rc_handler;
6844 
6845         IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_rc_handler: "
6846             "dummy_ud.ud_cm_handler %p", dummy_rc.cm_handler);
6847         /*
6848          * Call all routines that the client's callback routine could call.
6849          */
6850 
6851         return (IBT_CM_ACCEPT);
6852 }