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