1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * This file implements the client interfaces of the IBMF.
  28  */
  29 
  30 #include <sys/ib/mgt/ibmf/ibmf_impl.h>
  31 
  32 #define IBMF_SET_CLIENT_SIGNATURE(clientp) {                    \
  33                 (clientp)->ic_client_sig = (void *)0xf00DdEaD;       \
  34 }
  35 
  36 #define IBMF_VERIFY_CLIENT_SIGNATURE(clientp)                   \
  37         (((clientp) != NULL && (clientp)->ic_client_sig ==   \
  38             (void *)0xf00DdEaD) ? B_TRUE: B_FALSE)
  39 
  40 #define IBMF_INVALID_PKEY(pkey) (((pkey) & 0x7FFF) == 0)
  41 #define QP1 1
  42 
  43 extern ibmf_state_t *ibmf_statep;
  44 extern int ibmf_trace_level;
  45 
  46 /* ARGSUSED */
  47 int
  48 ibmf_register(ibmf_register_info_t *client_infop, uint_t ibmf_version,
  49     uint_t flags, ibmf_async_event_cb_t client_cb, void  *client_cb_args,
  50     ibmf_handle_t *ibmf_handlep, ibmf_impl_caps_t *ibmf_impl_features)
  51 {
  52         ibmf_ci_t       *ibmf_cip;
  53         ibmf_qp_t       *ibmf_qpp;
  54         ibmf_client_t   *ibmf_clientp;
  55         boolean_t       error = B_FALSE;
  56         int             status = IBMF_SUCCESS;
  57         char            errmsg[128];
  58 
  59         IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_start,
  60             IBMF_TNF_TRACE, "", "ibmf_register() enter, client_infop = %p "
  61             " ibmf_version = %d, flags = 0x%x, ibmf_impl_featuresp = %p\n",
  62             tnf_opaque, client_infop, client_infop,
  63             tnf_uint, ibmf_version, ibmf_version, tnf_uint, flags, flags,
  64             tnf_opaque, ibmf_impl_features, ibmf_impl_features);
  65 
  66         /* validate client_infop and ibmf_handlep */
  67         if ((client_infop == NULL) || (ibmf_handlep == NULL) ||
  68             (ibmf_impl_features == NULL)) {
  69                 (void) sprintf(errmsg,
  70                     "invalid argument, NULL pointer argument");
  71                 error = B_TRUE;
  72                 status = IBMF_INVALID_ARG;
  73                 goto bail;
  74         }
  75 
  76         /* check IBMF version */
  77         if (ibmf_version != IBMF_VERSION) {
  78                 (void) sprintf(errmsg, "Bad version");
  79                 error = B_TRUE;
  80                 status = IBMF_BAD_VERSION;
  81                 goto bail;
  82         }
  83 
  84         /* check flags validity */
  85         if ((flags & IBMF_REG_FLAG_NO_OFFLOAD) &&
  86             (flags & IBMF_REG_FLAG_SINGLE_OFFLOAD)) {
  87                 (void) sprintf(errmsg, "Bad flags");
  88                 error = B_TRUE;
  89                 status = IBMF_BAD_FLAGS;
  90                 goto bail;
  91         }
  92 
  93         /* check client mask and size */
  94         status = ibmf_i_validate_class_mask(client_infop);
  95         if (status != IBMF_SUCCESS) {
  96                 (void) sprintf(errmsg, "invalid class");
  97                 error = B_TRUE;
  98                 goto bail;
  99         }
 100         /*
 101          * verify the node identified by ir_ci_guid exists and that the
 102          * port ir_port_num is valid.
 103          */
 104         status = ibmf_i_validate_ci_guid_and_port(client_infop->ir_ci_guid,
 105             client_infop->ir_port_num);
 106         if (status != IBMF_SUCCESS) {
 107                 (void) sprintf(errmsg, "guid/port validation failed");
 108                 error = B_TRUE;
 109                 goto bail;
 110         }
 111 
 112         /* get the ci */
 113         status = ibmf_i_get_ci(client_infop, &ibmf_cip);
 114         if (status != IBMF_SUCCESS) {
 115                 IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
 116                     ibmf_register_error, IBMF_TNF_ERROR, "",
 117                     "ibmf_register(): %s, guid = 0x%p\n",
 118                     tnf_string, msg, "unable to get ci",
 119                     tnf_ulonglong, guid, client_infop->ir_ci_guid);
 120                 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_end,
 121                     IBMF_TNF_TRACE, "", "ibmf_register() exit\n");
 122                 return (status);
 123         }
 124 
 125         /*
 126          * check if classes and port are already registered for.
 127          */
 128         status = ibmf_i_validate_classes_and_port(ibmf_cip, client_infop);
 129         if (status != IBMF_SUCCESS) {
 130                 mutex_enter(&ibmf_cip->ci_mutex);
 131                 IBMF_ADD32_PORT_KSTATS(ibmf_cip, client_regs_failed, 1);
 132                 mutex_exit(&ibmf_cip->ci_mutex);
 133                 /* release ci */
 134                 ibmf_i_release_ci(ibmf_cip);
 135                 (void) sprintf(errmsg,
 136                     "class and port already registered for or unsupported");
 137                 error = B_TRUE;
 138                 goto bail;
 139         }
 140 
 141         /*
 142          * the class is valid, get qp and alloc the client
 143          */
 144         /* obtain the qp corresponding to the port and classes */
 145         status = ibmf_i_get_qp(ibmf_cip, client_infop->ir_port_num,
 146             client_infop->ir_client_class, &ibmf_qpp);
 147         if (status != IBMF_SUCCESS) {
 148                 mutex_enter(&ibmf_cip->ci_mutex);
 149                 IBMF_ADD32_PORT_KSTATS(ibmf_cip, client_regs_failed, 1);
 150                 mutex_exit(&ibmf_cip->ci_mutex);
 151                 ibmf_i_release_ci(ibmf_cip);
 152                 IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
 153                     ibmf_register_error, IBMF_TNF_ERROR, "",
 154                     "ibmf_register(): %s, class = 0x%x\n",
 155                     tnf_string, msg, "can't get qp",
 156                     tnf_int, class, client_infop->ir_client_class);
 157                 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_end,
 158                     IBMF_TNF_TRACE, "", "ibmf_register() exit\n");
 159                 return (status);
 160         }
 161 
 162         /* alloc the client */
 163         status = ibmf_i_alloc_client(client_infop, flags, &ibmf_clientp);
 164         if (status != IBMF_SUCCESS) {
 165                 mutex_enter(&ibmf_cip->ci_mutex);
 166                 IBMF_ADD32_PORT_KSTATS(ibmf_cip, client_regs_failed, 1);
 167                 mutex_exit(&ibmf_cip->ci_mutex);
 168                 ibmf_i_release_ci(ibmf_cip);
 169                 IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
 170                     ibmf_register_error, IBMF_TNF_ERROR, "",
 171                     "ibmf_register(): %s, class = 0x%x\n",
 172                     tnf_string, msg, "can't alloc client",
 173                     tnf_int, class, client_infop->ir_client_class);
 174                 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_end,
 175                     IBMF_TNF_TRACE, "", "ibmf_register() exit\n");
 176                 return (status);
 177         }
 178 
 179         ASSERT(ibmf_clientp != NULL);
 180 
 181         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ibmf_clientp))
 182 
 183         /* initialize the IBMF client context */
 184         ibmf_clientp->ic_myci = ibmf_cip;
 185         ibmf_clientp->ic_qp = ibmf_qpp;
 186         ibmf_clientp->ic_ci_handle = ibmf_cip->ci_ci_handle;
 187 
 188         ibmf_clientp->ic_reg_flags = flags;
 189 
 190         ibmf_clientp->ic_async_cb = client_cb;
 191         ibmf_clientp->ic_async_cb_arg = client_cb_args;
 192 
 193         IBMF_SET_CLIENT_SIGNATURE(ibmf_clientp);
 194 
 195         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ibmf_clientp))
 196 
 197         /* add the client to the list of clients */
 198         ibmf_i_add_client(ibmf_cip, ibmf_clientp);
 199 
 200         /* increment kstats for number of registered clients */
 201         mutex_enter(&ibmf_cip->ci_mutex);
 202         IBMF_ADD32_PORT_KSTATS(ibmf_cip, clients_registered, 1);
 203         mutex_exit(&ibmf_cip->ci_mutex);
 204 
 205         /* Setup ibmf_handlep -- handle is last allocated clientp */
 206         *ibmf_handlep = (ibmf_handle_t)ibmf_clientp;
 207         *ibmf_impl_features = 0;
 208 
 209 bail:
 210         if (error) {
 211                 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
 212                     ibmf_register_error, IBMF_TNF_ERROR, "",
 213                     "ibmf_register(): %s\n", tnf_string, msg, errmsg);
 214         }
 215 
 216         IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_end,
 217             IBMF_TNF_TRACE, "", "ibmf_register() exit, ibmf_handle = %p\n",
 218             tnf_opaque, ibmf_handle, *ibmf_handlep);
 219 
 220         return (status);
 221 }
 222 
 223 /* ARGSUSED */
 224 int
 225 ibmf_unregister(ibmf_handle_t *ibmf_handlep, uint_t flags)
 226 {
 227         ibmf_ci_t       *cip;
 228         ibmf_client_t   *clientp;
 229         boolean_t       error = B_FALSE;
 230         int             status = IBMF_SUCCESS;
 231         char            errmsg[128];
 232         int             secs;
 233 
 234         clientp = (ibmf_client_t *)*ibmf_handlep;
 235 
 236         IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_unregister_start,
 237             IBMF_TNF_TRACE, "", "ibmf_unregister() enter, "
 238             "ibmf_handlep = %p, flags = 0x%x\n",
 239             tnf_opaque, ibmf_handle, *ibmf_handlep, tnf_uint, flags, flags);
 240 
 241         /* check for null ibmf_handlep */
 242         if (ibmf_handlep == NULL) {
 243                 (void) sprintf(errmsg,
 244                     "invalid argument, NULL pointer argument");
 245                 error = B_TRUE;
 246                 status = IBMF_INVALID_ARG;
 247                 goto bail;
 248         }
 249 
 250         /* validate ibmf_handlep */
 251         if (ibmf_i_is_ibmf_handle_valid(*ibmf_handlep) != IBMF_SUCCESS) {
 252                 (void) sprintf(errmsg, "bad ibmf registration handle");
 253                 error = B_TRUE;
 254                 status = IBMF_BAD_HANDLE;
 255                 goto bail;
 256         }
 257 
 258         /* check signature */
 259         if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
 260                 (void) sprintf(errmsg, "bad client signature");
 261                 error = B_TRUE;
 262                 status = IBMF_BAD_HANDLE;
 263                 goto bail;
 264         }
 265 
 266         /*
 267          * Verify the client does not have a receive callback registered.
 268          * If there are messages, give some time for the messages to be
 269          * cleaned up.
 270          */
 271         secs = 60;
 272         mutex_enter(&clientp->ic_mutex);
 273         while (clientp->ic_recv_cb == NULL && clientp->ic_msgs_alloced != 0 &&
 274             secs > 0) {
 275                 mutex_exit(&clientp->ic_mutex);
 276                 delay(drv_usectohz(1000000)); /* one second delay */
 277                 secs--;
 278                 mutex_enter(&clientp->ic_mutex);
 279         }
 280 
 281         if (clientp->ic_recv_cb != NULL || clientp->ic_msgs_alloced != 0) {
 282                 IBMF_TRACE_4(IBMF_TNF_NODEBUG, DPRINT_L1,
 283                     ibmf_unregister_err, IBMF_TNF_ERROR, "",
 284                     "ibmf_unregister(): %s, flags = 0x%x, recv_cb = 0x%p, "
 285                     "msgs_alloced = %d\n",
 286                     tnf_string, msg, "busy with resources", tnf_uint, ic_flags,
 287                     clientp->ic_flags, tnf_opaque, recv_cb, clientp->ic_recv_cb,
 288                     tnf_uint, msgs_allocd, clientp->ic_msgs_alloced);
 289                 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_unregister_end,
 290                     IBMF_TNF_TRACE, "", "ibmf_unregister() exit\n");
 291                 mutex_exit(&clientp->ic_mutex);
 292                 return (IBMF_BUSY);
 293         }
 294 
 295         mutex_exit(&clientp->ic_mutex);
 296 
 297         cip = clientp->ic_myci;
 298 
 299         /* remove the client from the list of clients */
 300         ibmf_i_delete_client(cip, clientp);
 301 
 302         /* release the reference to the qp */
 303         ibmf_i_release_qp(cip, &clientp->ic_qp);
 304 
 305         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*clientp))
 306 
 307         /* and free the client structure */
 308         ibmf_i_free_client(clientp);
 309 
 310         /* release the ci; this may delete & free the ci structure */
 311         ibmf_i_release_ci(cip);
 312 
 313         /* decrement kstats for number of registered clients */
 314         mutex_enter(&cip->ci_mutex);
 315         IBMF_SUB32_PORT_KSTATS(cip, clients_registered, 1);
 316         mutex_exit(&cip->ci_mutex);
 317 
 318         *ibmf_handlep = NULL;
 319 
 320 bail:
 321         if (error) {
 322                 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
 323                     ibmf_unregister_err, IBMF_TNF_ERROR, "",
 324                     "ibmf_unregister(): %s\n", tnf_string, msg, errmsg);
 325         }
 326 
 327         IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_unregister_end,
 328             IBMF_TNF_TRACE, "", "ibmf_unregister() exit\n");
 329 
 330         return (status);
 331 }
 332 
 333 
 334 /* ARGSUSED */
 335 int
 336 ibmf_setup_async_cb(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
 337     ibmf_msg_cb_t async_msg_cb, void *async_msg_cb_args, uint_t flags)
 338 {
 339         ibmf_client_t   *clientp;
 340         boolean_t       error = B_FALSE;
 341         int             status = IBMF_SUCCESS;
 342         char            errmsg[128];
 343 
 344         clientp = (ibmf_client_t *)ibmf_handle;
 345 
 346         IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_setup_async_cb_start,
 347             IBMF_TNF_TRACE, "", "ibmf_setup_async_cb() enter, "
 348             "ibmf_handlep = %p, cb = 0x%p, cb_args = 0x%p, flags = 0x%x\n",
 349             tnf_opaque, ibmf_handle, ibmf_handle, tnf_opaque, cb,
 350             async_msg_cb, tnf_opaque, cb_args, async_msg_cb_args,
 351             tnf_uint, flags, flags);
 352 
 353         /* check for null ibmf_handlep */
 354         if (ibmf_handle == NULL) {
 355                 (void) sprintf(errmsg,
 356                     "invalid argument, NULL pointer argument");
 357                 error = B_TRUE;
 358                 status = IBMF_INVALID_ARG;
 359                 goto bail;
 360         }
 361 
 362         /* validate ibmf_handle */
 363         if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
 364                 (void) sprintf(errmsg, "bad ibmf registration handle");
 365                 error = B_TRUE;
 366                 status = IBMF_BAD_HANDLE;
 367                 goto bail;
 368         }
 369 
 370         /* validate ibmf_qp_handle */
 371         if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
 372             IBMF_SUCCESS) {
 373                 (void) sprintf(errmsg, "bad qp handle");
 374                 error = B_TRUE;
 375                 status = IBMF_BAD_QP_HANDLE;
 376                 goto bail;
 377         }
 378 
 379         /* check signature */
 380         if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
 381                 (void) sprintf(errmsg, "bad signature");
 382                 error = B_TRUE;
 383                 status = IBMF_BAD_HANDLE;
 384                 goto bail;
 385         }
 386 
 387         ASSERT(clientp->ic_myci != NULL);
 388 
 389         /* store the registered callback in the appropriate context */
 390         if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
 391 
 392                 /*
 393                  * if using the default QP handle, store the callback in
 394                  * the client context
 395                  */
 396                 mutex_enter(&clientp->ic_mutex);
 397 
 398                 /* check if the callback has already been registered */
 399                 if (clientp->ic_recv_cb != NULL) {
 400                         mutex_exit(&clientp->ic_mutex);
 401                         (void) sprintf(errmsg, "cb already exists");
 402                         error = B_TRUE;
 403                         status = IBMF_CB_REGISTERED;
 404                         goto bail;
 405                 }
 406 
 407                 clientp->ic_recv_cb = async_msg_cb;
 408                 clientp->ic_recv_cb_arg = async_msg_cb_args;
 409                 mutex_exit(&clientp->ic_mutex);
 410 
 411         } else {
 412                 ibmf_alt_qp_t *qp_ctxp = (ibmf_alt_qp_t *)ibmf_qp_handle;
 413 
 414                 /*
 415                  * if using an alternate QP handle, store the callback in
 416                  * the alternate QP context because there can be more than
 417                  * one alternate QP associated with a client
 418                  */
 419                 mutex_enter(&qp_ctxp->isq_mutex);
 420 
 421                 /* check if the callback has already been registered */
 422                 if (qp_ctxp->isq_recv_cb != NULL) {
 423                         mutex_exit(&qp_ctxp->isq_mutex);
 424                         (void) sprintf(errmsg, "cb already exists");
 425                         error = B_TRUE;
 426                         status = IBMF_CB_REGISTERED;
 427                         goto bail;
 428                 }
 429 
 430                 qp_ctxp->isq_recv_cb = async_msg_cb;
 431                 qp_ctxp->isq_recv_cb_arg = async_msg_cb_args;
 432 
 433                 mutex_exit(&qp_ctxp->isq_mutex);
 434         }
 435 
 436 bail:
 437         if (error) {
 438                 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
 439                     ibmf_setup_async_cb_err, IBMF_TNF_ERROR, "",
 440                     "ibmf_setup_async_cb(): %s\n", tnf_string, msg, errmsg);
 441         }
 442 
 443         IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_setup_async_cb_end,
 444             IBMF_TNF_TRACE, "", "ibmf_setup_async_cb() exit\n");
 445 
 446         return (status);
 447 }
 448 
 449 
 450 /* ARGSUSED */
 451 int
 452 ibmf_tear_down_async_cb(ibmf_handle_t ibmf_handle,
 453     ibmf_qp_handle_t ibmf_qp_handle, uint_t flags)
 454 {
 455         ibmf_client_t   *clientp;
 456         boolean_t       error = B_FALSE;
 457         int             status = IBMF_SUCCESS;
 458         char            errmsg[128];
 459 
 460         clientp = (ibmf_client_t *)ibmf_handle;
 461 
 462         IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_tear_down_async_cb_start,
 463             IBMF_TNF_TRACE, "", "ibmf_tear_down_async_cb() enter, "
 464             "ibmf_handlep = %p, ibmf_qp_handle = %p, flags = 0x%x\n",
 465             tnf_opaque, ibmf_handle, ibmf_handle,
 466             tnf_opaque, ibmf_qp_handle, ibmf_qp_handle, tnf_uint, flags, flags);
 467 
 468         /* check for null ibmf_handlep */
 469         if (ibmf_handle == NULL) {
 470                 (void) sprintf(errmsg,
 471                     "invalid argument, NULL pointer argument");
 472                 error = B_TRUE;
 473                 status = IBMF_INVALID_ARG;
 474                 goto bail;
 475         }
 476 
 477         /* validate ibmf_handle */
 478         if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
 479                 (void) sprintf(errmsg, "bad ibmf registration handle");
 480                 error = B_TRUE;
 481                 status = IBMF_BAD_HANDLE;
 482                 goto bail;
 483         }
 484 
 485         /* validate ibmf_qp_handle */
 486         if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
 487             IBMF_SUCCESS) {
 488                 (void) sprintf(errmsg, "bad qp handle");
 489                 error = B_TRUE;
 490                 status = IBMF_BAD_QP_HANDLE;
 491                 goto bail;
 492         }
 493 
 494         /* check signature */
 495         if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
 496                 (void) sprintf(errmsg, "bad signature");
 497                 error = B_TRUE;
 498                 status = IBMF_BAD_HANDLE;
 499                 goto bail;
 500         }
 501 
 502         ASSERT(clientp->ic_myci != NULL);
 503 
 504         /* remove the registered callback from the appropriate context */
 505         if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
 506 
 507                 mutex_enter(&clientp->ic_mutex);
 508 
 509                 /* check if callback has not been registered */
 510                 if (clientp->ic_recv_cb == NULL) {
 511                         mutex_exit(&clientp->ic_mutex);
 512                         (void) sprintf(errmsg, "no cb exists");
 513                         error = B_TRUE;
 514                         status = IBMF_CB_NOT_REGISTERED;
 515                         goto bail;
 516                 }
 517 
 518                 /*
 519                  * if an unsolicited MAD just arrived for this
 520                  * client, wait for it to be processed
 521                  */
 522                 while (clientp->ic_flags & IBMF_CLIENT_RECV_CB_ACTIVE) {
 523                         clientp->ic_flags |= IBMF_CLIENT_TEAR_DOWN_CB;
 524                         cv_wait(&clientp->ic_recv_cb_teardown_cv,
 525                             &clientp->ic_mutex);
 526                         clientp->ic_flags &= ~IBMF_CLIENT_TEAR_DOWN_CB;
 527                 }
 528 
 529                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(clientp->ic_recv_cb,
 530                      clientp->ic_recv_cb_arg))
 531 
 532                 /*
 533                  * if using the default QP handle, remove the callback from
 534                  * the client context
 535                  */
 536                 clientp->ic_recv_cb = NULL;
 537                 clientp->ic_recv_cb_arg = NULL;
 538 
 539                 ASSERT((clientp->ic_flags & IBMF_CLIENT_RECV_CB_ACTIVE) == 0);
 540 
 541                 mutex_exit(&clientp->ic_mutex);
 542         } else {
 543                 ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
 544 
 545                 mutex_enter(&qpp->isq_mutex);
 546 
 547                 /* check if callback has not been registered */
 548                 if (qpp->isq_recv_cb == NULL) {
 549                         mutex_exit(&qpp->isq_mutex);
 550                         (void) sprintf(errmsg, "no cb exists");
 551                         error = B_TRUE;
 552                         status = IBMF_CB_NOT_REGISTERED;
 553                         goto bail;
 554                 }
 555 
 556                 /*
 557                  * if an unsolicited MAD just arrived for this
 558                  * client on the alternate QP, wait for it to be processed
 559                  */
 560                 while (qpp->isq_flags & IBMF_CLIENT_RECV_CB_ACTIVE) {
 561                         qpp->isq_flags |= IBMF_CLIENT_TEAR_DOWN_CB;
 562                         cv_wait(&qpp->isq_recv_cb_teardown_cv,
 563                             &qpp->isq_mutex);
 564                         qpp->isq_flags &= ~IBMF_CLIENT_TEAR_DOWN_CB;
 565                 }
 566 
 567                 /*
 568                  * if using an alternate QP handle, remove the callback from
 569                  * the alternate QP context
 570                  */
 571                 qpp->isq_recv_cb = NULL;
 572                 qpp->isq_recv_cb_arg = NULL;
 573 
 574                 ASSERT((qpp->isq_flags & IBMF_CLIENT_RECV_CB_ACTIVE) == 0);
 575 
 576                 mutex_exit(&qpp->isq_mutex);
 577         }
 578 
 579 bail:
 580         if (error) {
 581                 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
 582                     ibmf_tear_down_async_cb_err, IBMF_TNF_ERROR, "",
 583                     "ibmf_tear_down_async_cb(): %s\n", tnf_string, msg, errmsg);
 584         }
 585 
 586         IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_tear_down_async_cb_end,
 587             IBMF_TNF_TRACE, "", "ibmf_tear_down_async_cb() exit\n");
 588 
 589         return (status);
 590 }
 591 
 592 
 593 int
 594 ibmf_alloc_msg(ibmf_handle_t ibmf_handle, int flag, ibmf_msg_t **ibmf_msgpp)
 595 {
 596         ibmf_msg_impl_t *ibmf_msg_impl;
 597         ibmf_client_t   *clientp;
 598         int             km_flags;
 599         boolean_t       error = B_FALSE;
 600         int             status = IBMF_SUCCESS;
 601         char            errmsg[128];
 602 
 603         clientp = (ibmf_client_t *)ibmf_handle;
 604 
 605         IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_msg_start,
 606             IBMF_TNF_TRACE, "", "ibmf_alloc_msg() enter, "
 607             "ibmf_handle = %p, flags = 0x%x\n",
 608             tnf_opaque, ibmf_handle, ibmf_handle, tnf_uint, flag, flag);
 609 
 610         /* check for null ibmf_handle and ibmf_msgpp */
 611         if ((ibmf_handle == NULL) || (ibmf_msgpp == NULL)) {
 612                 (void) sprintf(errmsg,
 613                     "invalid argument, NULL pointer argument");
 614                 error = B_TRUE;
 615                 status = IBMF_INVALID_ARG;
 616                 goto bail;
 617         }
 618 
 619         /* validate ibmf_handle */
 620         if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
 621                 (void) sprintf(errmsg, "bad ibmf registration handle");
 622                 error = B_TRUE;
 623                 status = IBMF_BAD_HANDLE;
 624                 goto bail;
 625         }
 626 
 627         /* check signature */
 628         if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
 629                 (void) sprintf(errmsg, "bad signature");
 630                 error = B_TRUE;
 631                 status = IBMF_BAD_HANDLE;
 632                 goto bail;
 633         }
 634 
 635         /* validate flag */
 636         if (flag != IBMF_ALLOC_SLEEP && flag != IBMF_ALLOC_NOSLEEP) {
 637                 (void) sprintf(errmsg, "invalid flags, flags = 0x%x", flag);
 638                 error = B_TRUE;
 639                 status = IBMF_BAD_FLAGS;
 640                 goto bail;
 641         }
 642 
 643         /* set flags for kmem allocaton */
 644         km_flags = (flag == IBMF_ALLOC_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
 645 
 646         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ibmf_msg_impl))
 647 
 648         /* call the internal function to allocate the IBMF message context */
 649         status = ibmf_i_alloc_msg(clientp, &ibmf_msg_impl, km_flags);
 650         if (status != IBMF_SUCCESS) {
 651                 mutex_enter(&clientp->ic_kstat_mutex);
 652                 IBMF_ADD32_KSTATS(clientp, msg_allocs_failed, 1);
 653                 mutex_exit(&clientp->ic_kstat_mutex);
 654                 (void) sprintf(errmsg, "message allocation failure");
 655                 error = B_TRUE;
 656                 goto bail;
 657         }
 658 
 659         /* increment counter and kstats for number of allocated messages */
 660         mutex_enter(&clientp->ic_mutex);
 661         clientp->ic_msgs_alloced++;
 662         mutex_exit(&clientp->ic_mutex);
 663         mutex_enter(&clientp->ic_kstat_mutex);
 664         IBMF_ADD32_KSTATS(clientp, msgs_alloced, 1);
 665         mutex_exit(&clientp->ic_kstat_mutex);
 666 
 667         /* initialize the msg */
 668         ibmf_msg_impl->im_client = clientp;
 669         cv_init(&ibmf_msg_impl->im_trans_cv, NULL, CV_DRIVER, NULL);
 670         mutex_init(&ibmf_msg_impl->im_mutex, NULL, MUTEX_DRIVER, NULL);
 671         *ibmf_msgpp = (ibmf_msg_t *)ibmf_msg_impl;
 672 
 673         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ibmf_msg_impl))
 674 
 675 bail:
 676         if (error) {
 677                 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
 678                     ibmf_alloc_msg_err, IBMF_TNF_ERROR, "",
 679                     "ibmf_alloc_msg(): %s\n", tnf_string, msg, errmsg);
 680         }
 681 
 682         IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_msg_end,
 683             IBMF_TNF_TRACE, "", "ibmf_alloc_msg() exit\n");
 684 
 685         return (status);
 686 }
 687 
 688 
 689 int
 690 ibmf_free_msg(ibmf_handle_t ibmf_handle, ibmf_msg_t **ibmf_msgpp)
 691 {
 692         ibmf_client_t   *clientp;
 693         ibmf_msg_impl_t *ibmf_msg_impl;
 694         boolean_t       error = B_FALSE;
 695         int             status = IBMF_SUCCESS;
 696         char            errmsg[128];
 697         timeout_id_t    msg_rp_set_id, msg_tr_set_id;
 698         timeout_id_t    msg_rp_unset_id, msg_tr_unset_id;
 699 
 700         IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_msg_start,
 701             IBMF_TNF_TRACE, "", "ibmf_free_msg() enter, " "ibmf_handle = %p\n",
 702             tnf_opaque, ibmf_handle, ibmf_handle);
 703 
 704         /* check for null ibmf_handle and ibmf_msgpp */
 705         if ((ibmf_handle == NULL) || (ibmf_msgpp == NULL)) {
 706                 (void) sprintf(errmsg,
 707                     "invalid argument, NULL pointer argument");
 708                 error = B_TRUE;
 709                 status = IBMF_INVALID_ARG;
 710                 goto bail;
 711         }
 712 
 713         /* validate ibmf_handle */
 714         if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
 715                 (void) sprintf(errmsg, "bad ibmf registration handle");
 716                 error = B_TRUE;
 717                 status = IBMF_BAD_HANDLE;
 718                 goto bail;
 719         }
 720 
 721         ibmf_msg_impl = (ibmf_msg_impl_t *)*ibmf_msgpp;
 722 
 723         /* check for null message pointer */
 724         if (ibmf_msg_impl == NULL) {
 725                 (void) sprintf(errmsg, "null message");
 726                 error = B_TRUE;
 727                 status = IBMF_FAILURE;
 728                 goto bail;
 729         }
 730 
 731         mutex_enter(&ibmf_msg_impl->im_mutex);
 732 
 733         /* check if message context flags indicate a busy message */
 734         if (ibmf_msg_impl->im_flags & IBMF_MSG_FLAGS_BUSY) {
 735                 mutex_exit(&ibmf_msg_impl->im_mutex);
 736                 (void) sprintf(errmsg, "message in use");
 737                 error = B_TRUE;
 738                 status = IBMF_BUSY;
 739                 goto bail;
 740         }
 741 
 742         ASSERT((ibmf_msg_impl->im_flags & IBMF_MSG_FLAGS_ON_LIST) == 0);
 743 
 744         /* Initialize the timer ID holders */
 745         msg_rp_set_id = msg_tr_set_id = 0;
 746         msg_rp_unset_id = msg_tr_unset_id = 0;
 747 
 748         /* Clear any timers that are still set */
 749 
 750         if (ibmf_msg_impl->im_rp_timeout_id != 0) {
 751                 msg_rp_set_id = ibmf_msg_impl->im_rp_timeout_id;
 752                 ibmf_msg_impl->im_rp_timeout_id = 0;
 753         }
 754 
 755         if (ibmf_msg_impl->im_tr_timeout_id != 0) {
 756                 msg_tr_set_id = ibmf_msg_impl->im_tr_timeout_id;
 757                 ibmf_msg_impl->im_tr_timeout_id = 0;
 758         }
 759 
 760         if (ibmf_msg_impl->im_rp_unset_timeout_id != 0) {
 761                 msg_rp_unset_id = ibmf_msg_impl->im_rp_unset_timeout_id;
 762                 ibmf_msg_impl->im_rp_unset_timeout_id = 0;
 763         }
 764 
 765         if (ibmf_msg_impl->im_tr_unset_timeout_id != 0) {
 766                 msg_tr_unset_id = ibmf_msg_impl->im_tr_unset_timeout_id;
 767                 ibmf_msg_impl->im_tr_unset_timeout_id = 0;
 768         }
 769 
 770         /* mark the message context flags to indicate a freed message */
 771         ibmf_msg_impl->im_flags |= IBMF_MSG_FLAGS_FREE;
 772 
 773         mutex_exit(&ibmf_msg_impl->im_mutex);
 774 
 775         /* cast pointer to client context */
 776         clientp = (ibmf_client_t *)ibmf_handle;
 777 
 778         /* check signature */
 779         if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
 780                 (void) sprintf(errmsg, "bad signature");
 781                 error = B_TRUE;
 782                 status = IBMF_BAD_HANDLE;
 783                 goto bail;
 784         }
 785 
 786         /* Clear the timers */
 787         if (msg_rp_unset_id != 0) {
 788                 (void) untimeout(msg_rp_unset_id);
 789         }
 790 
 791         if (msg_tr_unset_id != 0) {
 792                 (void) untimeout(msg_tr_unset_id);
 793         }
 794 
 795         if (msg_rp_set_id != 0) {
 796                 (void) untimeout(msg_rp_set_id);
 797         }
 798 
 799         if (msg_tr_set_id != 0) {
 800                 (void) untimeout(msg_tr_set_id);
 801         }
 802 
 803         /* destroy the condition variables */
 804         cv_destroy(&ibmf_msg_impl->im_trans_cv);
 805 
 806         /* decrement counter and kstats for number of allocated messages */
 807         mutex_enter(&clientp->ic_mutex);
 808         clientp->ic_msgs_alloced--;
 809         mutex_exit(&clientp->ic_mutex);
 810         mutex_enter(&clientp->ic_kstat_mutex);
 811         IBMF_SUB32_KSTATS(clientp, msgs_alloced, 1);
 812         mutex_exit(&clientp->ic_kstat_mutex);
 813 
 814         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ibmf_msg_impl,
 815             ibmf_msg_impl->im_msgbufs_recv,
 816             ibmf_msg_impl->im_msgbufs_send))
 817 
 818         /* call the internal function to free the message context */
 819         ibmf_i_free_msg(ibmf_msg_impl);
 820 
 821         *ibmf_msgpp = NULL;
 822 
 823 bail:
 824         if (error) {
 825                 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
 826                     ibmf_free_msg_err, IBMF_TNF_ERROR, "",
 827                     "ibmf_free_msg(): %s\n", tnf_string, msg, errmsg);
 828         }
 829 
 830         IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_msg_end,
 831             IBMF_TNF_TRACE, "", "ibmf_free_msg() exit\n");
 832 
 833         return (status);
 834 }
 835 
 836 
 837 /* ARGSUSED */
 838 int
 839 ibmf_msg_transport(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
 840     ibmf_msg_t *msgp, ibmf_retrans_t *retrans, ibmf_msg_cb_t msg_cb,
 841     void *msg_cb_args, uint_t flags)
 842 {
 843         ibmf_client_t   *clientp;
 844         ibmf_msg_impl_t *msgimplp;
 845         boolean_t       blocking, loopback, error = B_FALSE;
 846         int             status = IBMF_SUCCESS;
 847         sm_dr_mad_hdr_t *dr_hdr;
 848         char            errmsg[128];
 849 
 850         IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_msg_transport_start,
 851             IBMF_TNF_TRACE, "", "ibmf_msg_transport() enter, "
 852             "ibmf_handlep = %p, ibmf_qp_handle = %p, flags = 0x%x "
 853             "msgp = 0x%p, retrans = 0x%p\n",
 854             tnf_opaque, ibmf_handle, ibmf_handle,
 855             tnf_opaque, ibmf_qp_handle, ibmf_qp_handle, tnf_uint, flags, flags,
 856             tnf_opaque, msgp, msgp, tnf_opaque, retrans, retrans);
 857 
 858         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msgp,*msgimplp))
 859 
 860         /* check for null ibmf_handle and msgp */
 861         if ((ibmf_handle == NULL) || (msgp == NULL)) {
 862                 (void) sprintf(errmsg,
 863                     "invalid argument, NULL pointer argument");
 864                 error = B_TRUE;
 865                 status = IBMF_INVALID_ARG;
 866                 goto bail;
 867         }
 868 
 869         /* validate ibmf_handle */
 870         if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
 871                 (void) sprintf(errmsg, "bad ibmf registration handle");
 872                 error = B_TRUE;
 873                 status = IBMF_BAD_HANDLE;
 874                 goto bail;
 875         }
 876 
 877         /* validate ibmf_qp_handle */
 878         if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
 879             IBMF_SUCCESS) {
 880                 (void) sprintf(errmsg, "bad qp handle");
 881                 error = B_TRUE;
 882                 status = IBMF_BAD_QP_HANDLE;
 883                 goto bail;
 884         }
 885 
 886         clientp = (ibmf_client_t *)ibmf_handle;
 887 
 888         /* check signature */
 889         if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
 890                 (void) sprintf(errmsg, "bad signature");
 891                 error = B_TRUE;
 892                 status = IBMF_BAD_HANDLE;
 893                 goto bail;
 894         }
 895 
 896         /*
 897          * Check the validity of the pkey and qkey in the posted packet
 898          * For special QPs do the check for QP1 only
 899          * For the alternate qps, the pkey and qkey should match the
 900          * pkey and qkey maintained in the ibmf cached qp context
 901          */
 902         if ((ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) &&
 903             ((clientp->ic_client_info.client_class != SUBN_AGENT) &&
 904             (clientp->ic_client_info.client_class != SUBN_ADM_AGENT) &&
 905             (clientp->ic_client_info.client_class != SUBN_MANAGER))) {
 906 
 907                 if ((msgp->im_local_addr.ia_p_key != IBMF_P_KEY_DEF_FULL) &&
 908                     (msgp->im_local_addr.ia_p_key != IBMF_P_KEY_DEF_LIMITED)) {
 909                         (void) sprintf(errmsg,
 910                             "PKey in packet not default PKey");
 911                         error = B_TRUE;
 912                         status = IBMF_BAD_QP_HANDLE;
 913                         goto bail;
 914                 }
 915 
 916                 if (msgp->im_local_addr.ia_q_key != IBMF_MGMT_Q_KEY) {
 917                         (void) sprintf(errmsg, "QKey in packet not Mgt QKey");
 918                         error = B_TRUE;
 919                         status = IBMF_BAD_QP_HANDLE;
 920                         goto bail;
 921                 }
 922         } else if (ibmf_qp_handle != IBMF_QP_HANDLE_DEFAULT) {
 923                 ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
 924 
 925                 /* alternate QP context */
 926 
 927                 mutex_enter(&qpp->isq_mutex);
 928 
 929                 if (msgp->im_local_addr.ia_p_key != qpp->isq_pkey) {
 930                         mutex_exit(&qpp->isq_mutex);
 931                         (void) sprintf(errmsg, "PKey in packet does not match "
 932                             "PKey in the QP context");
 933                         error = B_TRUE;
 934                         status = IBMF_BAD_QP_HANDLE;
 935                         goto bail;
 936                 }
 937 
 938                 if (msgp->im_local_addr.ia_q_key != qpp->isq_qkey) {
 939                         mutex_exit(&qpp->isq_mutex);
 940                         (void) sprintf(errmsg, "QKey in packet does not match "
 941                             "QKey in the QP context");
 942                         error = B_TRUE;
 943                         status = IBMF_BAD_QP_HANDLE;
 944                         goto bail;
 945                 }
 946 
 947                 mutex_exit(&qpp->isq_mutex);
 948         }
 949 
 950         msgimplp = (ibmf_msg_impl_t *)msgp;
 951 
 952         ASSERT(msgimplp->im_client != NULL);
 953         ASSERT(msgimplp->im_client == clientp);
 954 
 955         msgimplp->im_transp_op_flags = flags;
 956 
 957         mutex_enter(&msgimplp->im_mutex);
 958 
 959         if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
 960                 if (msgimplp->im_msgbufs_send.im_bufs_mad_hdr == NULL) {
 961                         mutex_exit(&msgimplp->im_mutex);
 962                         (void) sprintf(errmsg, "Send buffer MAD header data "
 963                             "not provided for special QP");
 964                         error = B_TRUE;
 965                         status = IBMF_BAD_SIZE;
 966                         goto bail;
 967                 }
 968         } else {
 969                 ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
 970 
 971                 mutex_enter(&qpp->isq_mutex);
 972 
 973                 if (((qpp->isq_flags & IBMF_RAW_ONLY) == 0) &&
 974                     (msgimplp->im_msgbufs_send.im_bufs_mad_hdr == NULL)) {
 975                         mutex_exit(&qpp->isq_mutex);
 976                         mutex_exit(&msgimplp->im_mutex);
 977                         (void) sprintf(errmsg, "Send buffer MAD header data "
 978                             "not provided for alternate QP");
 979                         error = B_TRUE;
 980                         status = IBMF_BAD_SIZE;
 981                         goto bail;
 982                 }
 983                 mutex_exit(&qpp->isq_mutex);
 984         }
 985 
 986         /* check if client has freed the message by calling ibmf_free_msg() */
 987         if (msgimplp->im_flags & IBMF_MSG_FLAGS_FREE) {
 988                 mutex_exit(&msgimplp->im_mutex);
 989                 (void) sprintf(errmsg, "Message is being freed");
 990                 error = B_TRUE;
 991                 status = IBMF_BUSY;
 992                 goto bail;
 993         }
 994 
 995         /*
 996          * check if the message is already in use in an
 997          * ibmf_msg_transport() call
 998          */
 999         if (msgimplp->im_flags & IBMF_MSG_FLAGS_BUSY) {
1000                 mutex_exit(&msgimplp->im_mutex);
1001                 (void) sprintf(errmsg,
1002                     "Message is being processed by an other thread");
1003                 error = B_TRUE;
1004                 status = IBMF_BUSY;
1005                 goto bail;
1006         }
1007 
1008         msgimplp->im_flags = IBMF_MSG_FLAGS_BUSY;
1009 
1010         mutex_exit(&msgimplp->im_mutex);
1011 
1012         /* check for the Directed Route SMP loopback case */
1013         loopback = B_FALSE;
1014         dr_hdr = (sm_dr_mad_hdr_t *)msgimplp->im_msgbufs_send.im_bufs_mad_hdr;
1015         if ((dr_hdr->MgmtClass == MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE) &&
1016             (dr_hdr->HopCount == 0)) {
1017                 loopback = B_TRUE;
1018         }
1019 
1020         /* check for and perform DR loopback on tavor */
1021         status = ibmf_i_check_for_loopback(msgimplp, msg_cb, msg_cb_args,
1022             retrans, &loopback);
1023         if (status != IBMF_SUCCESS) {
1024                 (void) sprintf(errmsg, "dr_loopback_check failed");
1025                 error = B_TRUE;
1026                 mutex_enter(&msgimplp->im_mutex);
1027                 msgimplp->im_flags &= ~IBMF_MSG_FLAGS_BUSY;
1028                 mutex_exit(&msgimplp->im_mutex);
1029                 goto bail;
1030         }
1031         if (loopback == B_TRUE) {
1032                 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1033                     ibmf_msg_transport_end, IBMF_TNF_TRACE, "",
1034                     "ibmf_msg_transport() exit, dr_loopback ok\n");
1035                 return (IBMF_SUCCESS);
1036         }
1037 
1038         if (msg_cb == NULL) {
1039                 blocking = B_TRUE;
1040         } else {
1041                 blocking = B_FALSE;
1042         }
1043 
1044         /* initialize the message context */
1045         ibmf_i_init_msg(msgimplp, msg_cb, msg_cb_args, retrans, blocking);
1046 
1047         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msgp,*msgimplp))
1048 
1049         /* call the internal function to transport the message */
1050         status = ibmf_i_msg_transport(clientp, ibmf_qp_handle, msgimplp,
1051             blocking);
1052         if (status != IBMF_SUCCESS) {
1053                 (void) sprintf(errmsg, "message transport failed");
1054                 error = B_TRUE;
1055                 mutex_enter(&msgimplp->im_mutex);
1056                 msgimplp->im_flags &= ~IBMF_MSG_FLAGS_BUSY;
1057                 mutex_exit(&msgimplp->im_mutex);
1058                 goto bail;
1059         }
1060 
1061 bail:
1062         if (error) {
1063                 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1064                     ibmf_msg_transport_err, IBMF_TNF_ERROR, "",
1065                     "ibmf_msg_transport(): %s\n", tnf_string, msg, errmsg);
1066         }
1067 
1068         IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_msg_transport_end,
1069             IBMF_TNF_TRACE, "", "ibmf_msg_transport() exit\n");
1070 
1071         return (status);
1072 }
1073 
1074 
1075 /* ARGSUSED */
1076 int
1077 ibmf_alloc_qp(ibmf_handle_t ibmf_handle, ib_pkey_t p_key, ib_qkey_t q_key,
1078     uint_t flags, ibmf_qp_handle_t *ibmf_qp_handlep)
1079 {
1080         ibmf_client_t   *clientp = (ibmf_client_t *)ibmf_handle;
1081         uint_t          alloc_flags;
1082         ibmf_alt_qp_t   *qp_ctx;
1083         boolean_t       error = B_FALSE;
1084         int             status = IBMF_SUCCESS;
1085         char            errmsg[128];
1086 
1087         IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_qp_start,
1088             IBMF_TNF_TRACE, "", "ibmf_alloc_qp() enter, "
1089             "ibmf_handlep = %p, p_key = 0x%x, q_key = 0x%x\n",
1090             tnf_opaque, ibmf_handle, ibmf_handle,
1091             tnf_uint, pkey, p_key, tnf_uint, qkey, q_key);
1092 
1093         /* check for null ibmf_handle and ibmf_qp_handle */
1094         if ((ibmf_handle == NULL) || (ibmf_qp_handlep == NULL)) {
1095                 (void) sprintf(errmsg,
1096                     "invalid argument, NULL pointer argument");
1097                 error = B_TRUE;
1098                 status = IBMF_INVALID_ARG;
1099                 goto bail;
1100         }
1101 
1102         /* validate ibmf_handle */
1103         if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
1104                 (void) sprintf(errmsg, "bad ibmf registration handle");
1105                 error = B_TRUE;
1106                 status = IBMF_BAD_HANDLE;
1107                 goto bail;
1108         }
1109 
1110         /* check signature */
1111         if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
1112                 (void) sprintf(errmsg, "bad signature");
1113                 error = B_TRUE;
1114                 status = IBMF_BAD_HANDLE;
1115                 goto bail;
1116         }
1117 
1118         /* validate PKey */
1119         if (IBMF_INVALID_PKEY(p_key)) {
1120                 (void) sprintf(errmsg, "invalid value in p_key argument");
1121                 error = B_TRUE;
1122                 status = IBMF_INVALID_ARG;
1123                 goto bail;
1124         }
1125 
1126         if (((flags & IBMF_ALT_QP_MAD_NO_RMPP) == 0) &&
1127             ((flags & IBMF_ALT_QP_MAD_RMPP) == 0) &&
1128             ((flags & IBMF_ALT_QP_RAW_ONLY) == 0)) {
1129                 (void) sprintf(errmsg, "invalid flags combination");
1130                 error = B_TRUE;
1131                 status = IBMF_BAD_FLAGS;
1132                 goto bail;
1133         }
1134 
1135         alloc_flags = IBMF_ALLOC_SLEEP;
1136 
1137         /* call the internal function to allocate the alternate QP context */
1138         status = ibmf_i_alloc_qp(clientp, p_key, q_key, alloc_flags,
1139             ibmf_qp_handlep);
1140         if (status != IBMF_SUCCESS) {
1141                 mutex_enter(&clientp->ic_kstat_mutex);
1142                 IBMF_ADD32_KSTATS(clientp, alt_qp_allocs_failed, 1);
1143                 mutex_exit(&clientp->ic_kstat_mutex);
1144                 (void) sprintf(errmsg, "unable to allocate QP");
1145                 error = B_TRUE;
1146                 status = IBMF_NO_RESOURCES;
1147                 goto bail;
1148         }
1149 
1150         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp_ctx))
1151 
1152         qp_ctx = (ibmf_alt_qp_t *)*ibmf_qp_handlep;
1153 
1154         /* initialize the alternate qp context */
1155         if (flags & IBMF_ALT_QP_MAD_NO_RMPP)
1156                 qp_ctx->isq_flags |= IBMF_MAD_ONLY;
1157 
1158         if (flags & IBMF_ALT_QP_RAW_ONLY)
1159                 qp_ctx->isq_flags |= IBMF_RAW_ONLY;
1160 
1161         if (flags & IBMF_ALT_QP_MAD_RMPP)
1162                 qp_ctx->isq_supports_rmpp = B_TRUE;
1163         else
1164                 qp_ctx->isq_supports_rmpp = B_FALSE;
1165 
1166 bail:
1167         if (error) {
1168                 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1169                     ibmf_alloc_qp_err, IBMF_TNF_ERROR, "",
1170                     "ibmf_alloc_qp(): %s\n", tnf_string, msg, errmsg);
1171         }
1172 
1173         IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_qp_end,
1174             IBMF_TNF_TRACE, "", "ibmf_alloc_qp() exit\n");
1175 
1176 
1177         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*qp_ctx))
1178 
1179         return (status);
1180 }
1181 
1182 
1183 /* ARGSUSED */
1184 int
1185 ibmf_query_qp(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
1186     uint_t *qp_num, ib_pkey_t *p_key, ib_qkey_t *q_key, uint8_t *portnum,
1187     uint_t flags)
1188 {
1189         ibmf_client_t   *clientp = (ibmf_client_t *)ibmf_handle;
1190         ibmf_alt_qp_t *qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
1191         uint_t          query_flags;
1192         boolean_t       error = B_FALSE;
1193         int             status = IBMF_SUCCESS;
1194         char            errmsg[128];
1195 
1196         IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_query_qp_start,
1197             IBMF_TNF_TRACE, "", "ibmf_query_qp() enter, "
1198             "ibmf_handlep = %p, ibmf_qp_handle = %p\n",
1199             tnf_opaque, ibmf_handle, ibmf_handle,
1200             tnf_opaque, ibmf_qp_handle, ibmf_qp_handle);
1201 
1202         /* check for null args */
1203         if ((ibmf_handle == NULL) || (ibmf_qp_handle == NULL) ||
1204             (qp_num == NULL) || (p_key == NULL) || (q_key == NULL) ||
1205             (portnum == NULL)) {
1206                 (void) sprintf(errmsg,
1207                     "invalid argument, NULL pointer argument");
1208                 error = B_TRUE;
1209                 status = IBMF_INVALID_ARG;
1210                 goto bail;
1211         }
1212 
1213         /* validate ibmf_handle */
1214         if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
1215                 (void) sprintf(errmsg, "bad ibmf registration handle");
1216                 error = B_TRUE;
1217                 status = IBMF_BAD_HANDLE;
1218                 goto bail;
1219         }
1220 
1221         /* validate ibmf_qp_handle */
1222         if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
1223             IBMF_SUCCESS) {
1224                 (void) sprintf(errmsg, "bad qp handle");
1225                 error = B_TRUE;
1226                 status = IBMF_BAD_QP_HANDLE;
1227                 goto bail;
1228         }
1229 
1230         /* validate ibmf_qp_handle */
1231         if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1232                 (void) sprintf(errmsg, "bad qp handle (default)");
1233                 error = B_TRUE;
1234                 status = IBMF_BAD_QP_HANDLE;
1235                 goto bail;
1236         }
1237 
1238         /* check signature */
1239         if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
1240                 (void) sprintf(errmsg, "bad client signature");
1241                 error = B_TRUE;
1242                 status = IBMF_BAD_HANDLE;
1243                 goto bail;
1244         }
1245 
1246         /* validate client context handle */
1247         if (qp_ctx->isq_client_hdl != clientp) {
1248                 (void) sprintf(errmsg, "bad QP handle");
1249                 error = B_TRUE;
1250                 status = IBMF_BAD_QP_HANDLE;
1251                 goto bail;
1252         }
1253 
1254         query_flags = IBMF_ALLOC_NOSLEEP;
1255 
1256         /* call the internal function to query the alternate qp */
1257         status = ibmf_i_query_qp(ibmf_qp_handle, query_flags, qp_num, p_key,
1258             q_key, portnum);
1259         if (status != IBMF_SUCCESS) {
1260                 (void) sprintf(errmsg, "unable to query QP");
1261                 error = B_TRUE;
1262                 goto bail;
1263         }
1264 
1265 bail:
1266         if (error) {
1267                 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1268                     ibmf_query_qp_err, IBMF_TNF_ERROR, "",
1269                     "ibmf_query_qp(): %s\n", tnf_string, msg, errmsg);
1270         }
1271 
1272         IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_query_qp_end,
1273             IBMF_TNF_TRACE, "", "ibmf_query_qp() exit, qp = %d, "
1274             "pkey = 0x%x, qkey = 0x%x\n", tnf_uint, qp_num, *qp_num,
1275             tnf_uint, pkey, *p_key, tnf_uint, qkey, *q_key);
1276 
1277         return (status);
1278 }
1279 
1280 
1281 /* ARGSUSED */
1282 int
1283 ibmf_modify_qp(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
1284     ib_pkey_t p_key, ib_qkey_t q_key, uint_t flags)
1285 {
1286         ibmf_client_t   *clientp = (ibmf_client_t *)ibmf_handle;
1287         ibmf_alt_qp_t *qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
1288         uint_t          modify_flags;
1289         boolean_t       error = B_FALSE;
1290         int             status = IBMF_SUCCESS;
1291         char            errmsg[128];
1292 
1293         IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_modify_qp_start,
1294             IBMF_TNF_TRACE, "", "ibmf_modify_qp() enter, "
1295             "ibmf_handlep = %p, ibmf_qp_handle = %p, pkey = 0x%x, "
1296             "qkey = 0x%x\n", tnf_opaque, ibmf_handle, ibmf_handle,
1297             tnf_opaque, ibmf_qp_handle, ibmf_qp_handle,
1298             tnf_uint, p_key, p_key, tnf_uint, q_key, q_key);
1299 
1300         /* check for null args */
1301         if ((ibmf_handle == NULL) || (ibmf_qp_handle == NULL)) {
1302                 (void) sprintf(errmsg,
1303                     "invalid argument, NULL pointer argument");
1304                 error = B_TRUE;
1305                 status = IBMF_INVALID_ARG;
1306                 goto bail;
1307         }
1308 
1309         /* validate ibmf_handle */
1310         if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
1311                 (void) sprintf(errmsg, "bad ibmf registration handle");
1312                 error = B_TRUE;
1313                 status = IBMF_BAD_HANDLE;
1314                 goto bail;
1315         }
1316 
1317         /* validate ibmf_qp_handle */
1318         if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
1319             IBMF_SUCCESS) {
1320                 (void) sprintf(errmsg, "bad qp handle");
1321                 error = B_TRUE;
1322                 status = IBMF_BAD_QP_HANDLE;
1323                 goto bail;
1324         }
1325 
1326         /* validate ibmf_qp_handle */
1327         if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1328                 (void) sprintf(errmsg, "bad qp handle (default)");
1329                 error = B_TRUE;
1330                 status = IBMF_BAD_QP_HANDLE;
1331                 goto bail;
1332         }
1333 
1334         /* check signature */
1335         if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
1336                 (void) sprintf(errmsg, "bad client signature");
1337                 error = B_TRUE;
1338                 status = IBMF_BAD_HANDLE;
1339                 goto bail;
1340         }
1341 
1342         /* validate PKey */
1343         if (IBMF_INVALID_PKEY(p_key)) {
1344                 (void) sprintf(errmsg, "invalid value in p_key argument");
1345                 error = B_TRUE;
1346                 status = IBMF_INVALID_ARG;
1347                 goto bail;
1348         }
1349 
1350         if (qp_ctx->isq_client_hdl != clientp) {
1351                 (void) sprintf(errmsg, "bad QP handle");
1352                 error = B_TRUE;
1353                 status = IBMF_BAD_QP_HANDLE;
1354                 goto bail;
1355         }
1356 
1357         modify_flags = IBMF_ALLOC_SLEEP;
1358 
1359         /* call the internal function to modify the qp */
1360         status = ibmf_i_modify_qp(ibmf_qp_handle, p_key, q_key, modify_flags);
1361         if (status != IBMF_SUCCESS) {
1362                 (void) sprintf(errmsg, "unable to modify QP");
1363                 error = B_TRUE;
1364                 goto bail;
1365         }
1366 
1367 bail:
1368         if (error) {
1369                 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1370                     ibmf_modify_qp_err, IBMF_TNF_ERROR, "",
1371                     "ibmf_modify_qp(): %s\n", tnf_string, msg, errmsg);
1372         }
1373 
1374         IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_modify_qp_end,
1375             IBMF_TNF_TRACE, "", "ibmf_modify_qp() exit\n");
1376 
1377         return (status);
1378 }
1379 
1380 /* ARGSUSED */
1381 int
1382 ibmf_free_qp(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t *ibmf_qp_handle,
1383     uint_t flags)
1384 {
1385         ibmf_client_t   *clientp = (ibmf_client_t *)ibmf_handle;
1386         ibmf_alt_qp_t   *qp_ctx = (ibmf_alt_qp_t *)*ibmf_qp_handle;
1387         uint_t          modify_flags;
1388         boolean_t       error = B_FALSE;
1389         int             status = IBMF_SUCCESS;
1390         char            errmsg[128];
1391 
1392         IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_qp_start,
1393             IBMF_TNF_TRACE, "", "ibmf_free_qp() enter, "
1394             "ibmf_handlep = %p, ibmf_qp_handle = %p\n",
1395             tnf_opaque, ibmf_handle, ibmf_handle,
1396             tnf_opaque, ibmf_qp_handle, *ibmf_qp_handle);
1397 
1398         /* check for null args */
1399         if ((ibmf_handle == NULL) || (ibmf_qp_handle == NULL)) {
1400                 (void) sprintf(errmsg,
1401                     "invalid argument, NULL pointer argument");
1402                 error = B_TRUE;
1403                 status = IBMF_INVALID_ARG;
1404                 goto bail;
1405         }
1406 
1407         /* validate ibmf_handle */
1408         if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
1409                 (void) sprintf(errmsg, "bad ibmf registration handle");
1410                 error = B_TRUE;
1411                 status = IBMF_BAD_HANDLE;
1412                 goto bail;
1413         }
1414 
1415         /* validate ibmf_qp_handle */
1416         if (ibmf_i_is_qp_handle_valid(ibmf_handle, *ibmf_qp_handle) !=
1417             IBMF_SUCCESS) {
1418                 (void) sprintf(errmsg, "bad qp handle");
1419                 error = B_TRUE;
1420                 status = IBMF_BAD_QP_HANDLE;
1421                 goto bail;
1422         }
1423 
1424         /* validate ibmf_qp_handle */
1425         if (*ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1426                 (void) sprintf(errmsg, "bad qp handle (default)");
1427                 error = B_TRUE;
1428                 status = IBMF_BAD_QP_HANDLE;
1429                 goto bail;
1430         }
1431 
1432         /* check signature */
1433         if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
1434                 (void) sprintf(errmsg, "bad client signature");
1435                 error = B_TRUE;
1436                 status = IBMF_BAD_HANDLE;
1437                 goto bail;
1438         }
1439 
1440         /* validate client context handle */
1441         if (qp_ctx->isq_client_hdl != clientp) {
1442                 (void) sprintf(errmsg, "bad QP handle");
1443                 error = B_TRUE;
1444                 status = IBMF_BAD_QP_HANDLE;
1445                 goto bail;
1446         }
1447 
1448         mutex_enter(&qp_ctx->isq_mutex);
1449 
1450         if (qp_ctx->isq_recv_cb != NULL) {
1451                 mutex_exit(&qp_ctx->isq_mutex);
1452                 (void) sprintf(errmsg, "QP busy, callback active");
1453                 error = B_TRUE;
1454                 status = IBMF_BUSY;
1455                 goto bail;
1456         }
1457 
1458         mutex_exit(&qp_ctx->isq_mutex);
1459 
1460         modify_flags = IBMF_ALLOC_SLEEP;
1461 
1462         status = ibmf_i_free_qp(*ibmf_qp_handle, modify_flags);
1463         if (status != IBMF_SUCCESS) {
1464                 (void) sprintf(errmsg, "unable to free QP");
1465                 error = B_TRUE;
1466                 goto bail;
1467         }
1468 
1469         *ibmf_qp_handle = NULL;
1470 
1471 bail:
1472         if (error) {
1473                 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1474                     ibmf_free_qp_err, IBMF_TNF_ERROR, "",
1475                     "ibmf_free_qp(): %s\n", tnf_string, msg, errmsg);
1476         }
1477 
1478         IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_qp_end,
1479             IBMF_TNF_TRACE, "", "ibmf_free_qp() exit\n");
1480 
1481         return (status);
1482 }