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/ibtl/impl/ibtl.h>
  26 #include <sys/ib/ibtl/impl/ibtl_cm.h>
  27 
  28 /*
  29  * ibtl_qp.c
  30  *      These routines implement (most of) the verbs related to
  31  *      Queue Pairs.
  32  */
  33 
  34 /* Globals. */
  35 static char ibtf_qp[] = "ibtl";
  36 
  37 /* This table indirectly initializes the ibt_cep_next_state[] table. */
  38 typedef struct ibt_cep_next_state_s {
  39         ibt_cep_state_t         next_state;
  40         ibt_cep_modify_flags_t  modify_flags;
  41 } ibt_cep_next_state_t;
  42 
  43 struct  {
  44         ibt_cep_state_t         current_state;
  45         ibt_cep_state_t         next_state;
  46         ibt_cep_modify_flags_t  modify_flags;
  47 } ibt_cep_next_state_inits[] = {
  48         { IBT_STATE_RESET, IBT_STATE_INIT, IBT_CEP_SET_RESET_INIT},
  49         { IBT_STATE_INIT, IBT_STATE_RTR, IBT_CEP_SET_INIT_RTR},
  50         { IBT_STATE_RTR, IBT_STATE_RTS, IBT_CEP_SET_RTR_RTS}
  51 };
  52 
  53 ibt_cep_next_state_t ibt_cep_next_state[IBT_STATE_NUM];
  54 
  55 /* The following data and functions can increase system stability. */
  56 
  57 int ibtl_qp_calls_curr;
  58 int ibtl_qp_calls_max = 128;    /* limit on # of simultaneous QP verb calls */
  59 kmutex_t ibtl_qp_mutex;
  60 kcondvar_t ibtl_qp_cv;
  61 
  62 void
  63 ibtl_qp_flow_control_enter(void)
  64 {
  65         mutex_enter(&ibtl_qp_mutex);
  66         while (ibtl_qp_calls_curr >= ibtl_qp_calls_max) {
  67                 cv_wait(&ibtl_qp_cv, &ibtl_qp_mutex);
  68         }
  69         ++ibtl_qp_calls_curr;
  70         mutex_exit(&ibtl_qp_mutex);
  71 }
  72 
  73 void
  74 ibtl_qp_flow_control_exit(void)
  75 {
  76         mutex_enter(&ibtl_qp_mutex);
  77         cv_signal(&ibtl_qp_cv);
  78         --ibtl_qp_calls_curr;
  79         mutex_exit(&ibtl_qp_mutex);
  80 }
  81 
  82 /*
  83  * Function:
  84  *      ibt_alloc_qp
  85  * Input:
  86  *      hca_hdl         HCA Handle.
  87  *      type            Specifies the type of QP to alloc in ibt_alloc_qp()
  88  *      qp_attrp        Specifies the ibt_qp_alloc_attr_t that are needed to
  89  *                      allocate a QP and transition it to the RTS state for
  90  *                      UDs and INIT state for all other QPs.
  91  * Output:
  92  *      queue_sizes_p   Returned sizes for SQ, RQ, SQ WR SGL elements & RQ
  93  *                      WR SGL elements.
  94  *      qpn_p           Returned QP Number of the allocated QP.
  95  *      ibt_qp_p        The ibt_qp_hdl_t of the allocated QP.
  96  * Returns:
  97  *      IBT_SUCCESS
  98  * Description:
  99  *      Allocate a QP with specified attributes.
 100  */
 101 ibt_status_t
 102 ibt_alloc_qp(ibt_hca_hdl_t hca_hdl, ibt_qp_type_t type,
 103     ibt_qp_alloc_attr_t *qp_attrp, ibt_chan_sizes_t *queue_sizes_p,
 104     ib_qpn_t *qpn_p, ibt_qp_hdl_t *ibt_qp_p)
 105 {
 106         ibt_status_t            retval;
 107         ibtl_channel_t          *chanp;
 108         ibt_tran_srv_t          qp_type;
 109 
 110         IBTF_DPRINTF_L3(ibtf_qp, "ibt_alloc_qp(%p, %d, %p, %p, %p, %p) ",
 111             hca_hdl, type, qp_attrp, queue_sizes_p, qpn_p, ibt_qp_p);
 112 
 113         switch (type) {
 114         case IBT_UD_RQP:
 115                 qp_type = IBT_UD_SRV;
 116                 break;
 117         case IBT_RC_RQP:
 118                 qp_type = IBT_RC_SRV;
 119                 break;
 120         case IBT_UC_RQP:
 121                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: Unreliable Connected "
 122                     "Transport Type is not supported.");
 123                 *ibt_qp_p = NULL;
 124                 return (IBT_NOT_SUPPORTED);
 125         case IBT_RD_RQP:
 126                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: Reliable Datagram "
 127                     "Transport Type is not supported.");
 128                 *ibt_qp_p = NULL;
 129                 return (IBT_NOT_SUPPORTED);
 130         default:
 131                 /* shouldn't happen ILLEGAL Type */
 132                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: Illegal Transport Type "
 133                     "%d", type);
 134                 *ibt_qp_p = NULL;
 135                 return (IBT_QP_SRV_TYPE_INVALID);
 136         }
 137 
 138         /* Get CI CQ handles */
 139         qp_attrp->qp_ibc_scq_hdl = (qp_attrp->qp_scq_hdl == NULL) ? NULL :
 140             qp_attrp->qp_scq_hdl->cq_ibc_cq_hdl;
 141         qp_attrp->qp_ibc_rcq_hdl = (qp_attrp->qp_rcq_hdl == NULL) ? NULL :
 142             qp_attrp->qp_rcq_hdl->cq_ibc_cq_hdl;
 143 
 144         /* Get CI SRQ handle */
 145         if ((qp_attrp->qp_alloc_flags & IBT_QP_USES_SRQ) &&
 146             (qp_attrp->qp_srq_hdl != NULL))
 147                 qp_attrp->qp_ibc_srq_hdl =
 148                     qp_attrp->qp_srq_hdl->srq_ibc_srq_hdl;
 149         else
 150                 qp_attrp->qp_ibc_srq_hdl = NULL;
 151 
 152         /* Allocate Channel structure */
 153         chanp = kmem_zalloc(sizeof (*chanp), KM_SLEEP);
 154 
 155         ibtl_qp_flow_control_enter();
 156         retval = (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_qp)(
 157             IBTL_HCA2CIHCA(hca_hdl), &chanp->ch_qp, type, qp_attrp,
 158             queue_sizes_p, qpn_p, &chanp->ch_qp.qp_ibc_qp_hdl);
 159         ibtl_qp_flow_control_exit();
 160         if (retval != IBT_SUCCESS) {
 161                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: "
 162                     "Failed to allocate QP: %d", retval);
 163                 kmem_free(chanp, sizeof (*chanp));
 164                 *ibt_qp_p = NULL;
 165                 return (retval);
 166         }
 167 
 168         /* Initialize the internal QP struct. */
 169         chanp->ch_qp.qp_type = qp_type;
 170         chanp->ch_qp.qp_hca = hca_hdl;
 171         chanp->ch_qp.qp_send_cq = qp_attrp->qp_scq_hdl;
 172         chanp->ch_qp.qp_recv_cq = qp_attrp->qp_rcq_hdl;
 173         chanp->ch_current_state = IBT_STATE_RESET;
 174         /*
 175          * The IBTA spec does not include the signal type or PD on a QP
 176          * query operation. In order to implement the "CLONE" feature
 177          * we need to cache these values.  Mostly used by TI client.
 178          */
 179         chanp->ch_qp.qp_flags = qp_attrp->qp_flags;
 180         chanp->ch_qp.qp_pd_hdl = qp_attrp->qp_pd_hdl;
 181         mutex_init(&chanp->ch_cm_mutex, NULL, MUTEX_DEFAULT, NULL);
 182         cv_init(&chanp->ch_cm_cv, NULL, CV_DEFAULT, NULL);
 183 
 184         atomic_inc_32(&hca_hdl->ha_qp_cnt);
 185 
 186         IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: SUCCESS: qp %p owned by '%s'",
 187             chanp, hca_hdl->ha_clnt_devp->clnt_name);
 188 
 189         *ibt_qp_p = chanp;
 190 
 191         return (retval);
 192 }
 193 
 194 
 195 /*
 196  * Function:
 197  *      ibt_initialize_qp
 198  * Input:
 199  *      ibt_qp          The previously allocated IBT QP Handle.
 200  *      modify_attrp    Specifies the QP Modify attributes that to transition
 201  *                      the QP to the RTS state for UDs (including special QPs)
 202  *                      and INIT state for all other QPs.
 203  * Output:
 204  *      none.
 205  * Returns:
 206  *      IBT_SUCCESS
 207  * Description:
 208  *      Transition the QP to the RTS state for UDs (including special QPs)
 209  *      and INIT state for all other QPs.
 210  */
 211 ibt_status_t
 212 ibt_initialize_qp(ibt_qp_hdl_t ibt_qp, ibt_qp_info_t *modify_attrp)
 213 {
 214         ibt_status_t            status;
 215         ibt_cep_state_t         state;
 216         ibc_hca_hdl_t           ibc_hca_hdl = IBTL_CHAN2CIHCA(ibt_qp);
 217         ibc_qp_hdl_t            ibc_qp_hdl = IBTL_CHAN2CIQP(ibt_qp);
 218         ibc_operations_t        *hca_ops_p = IBTL_CHAN2CIHCAOPS_P(ibt_qp);
 219         ibt_cep_modify_flags_t  modify_flags;
 220 
 221         IBTF_DPRINTF_L3(ibtf_qp, "ibt_initialize_qp(%p, %p)",
 222             ibt_qp, modify_attrp);
 223 
 224         /*
 225          * Validate the QP Type from the channel with QP Type from the
 226          * modify attribute struct.
 227          */
 228         if (ibt_qp->ch_qp.qp_type != modify_attrp->qp_trans) {
 229                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_initialize_qp: "
 230                     "QP Type mismatch: Chan QP Type<%d>, Modify QP Type<%d>",
 231                     ibt_qp->ch_qp.qp_type, modify_attrp->qp_trans);
 232                 return (IBT_QP_SRV_TYPE_INVALID);
 233         }
 234         if (ibt_qp->ch_current_state != IBT_STATE_RESET) {
 235                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_initialize_qp: "
 236                     "QP needs to be in RESET state: Chan QP State<%d>",
 237                     ibt_qp->ch_current_state);
 238                 return (IBT_CHAN_STATE_INVALID);
 239         }
 240 
 241         /*
 242          * Initialize the QP to the RTS state for UDs
 243          * and INIT state for all other QPs.
 244          */
 245         switch (modify_attrp->qp_trans) {
 246         case IBT_UD_SRV:
 247 
 248                 /*
 249                  * Bring the QP to the RTS state.
 250                  */
 251                 state = IBT_STATE_RESET;
 252                 ibtl_qp_flow_control_enter();
 253                 do {
 254                         modify_attrp->qp_current_state = state;
 255                         modify_flags = ibt_cep_next_state[state].modify_flags;
 256                         modify_attrp->qp_state = state =
 257                             ibt_cep_next_state[state].next_state;
 258 
 259                         IBTF_DPRINTF_L3(ibtf_qp, "ibt_initialize_qp: "
 260                             "modifying qp state to 0x%x", state);
 261                         status = (hca_ops_p->ibc_modify_qp)(ibc_hca_hdl,
 262                             ibc_qp_hdl, modify_flags, modify_attrp, NULL);
 263                 } while ((state != IBT_STATE_RTS) && (status == IBT_SUCCESS));
 264                 ibtl_qp_flow_control_exit();
 265 
 266                 if (status == IBT_SUCCESS) {
 267                         ibt_qp->ch_current_state = state;
 268                         ibt_qp->ch_transport.ud.ud_port_num =
 269                             modify_attrp->qp_transport.ud.ud_port;
 270                         ibt_qp->ch_transport.ud.ud_qkey =
 271                             modify_attrp->qp_transport.ud.ud_qkey;
 272                 }
 273                 break;
 274         case IBT_UC_SRV:
 275         case IBT_RD_SRV:
 276         case IBT_RC_SRV:
 277 
 278                 /*
 279                  * Bring the QP to the INIT state.
 280                  */
 281                 modify_attrp->qp_state = IBT_STATE_INIT;
 282 
 283                 ibtl_qp_flow_control_enter();
 284                 status = (hca_ops_p->ibc_modify_qp)(ibc_hca_hdl, ibc_qp_hdl,
 285                     IBT_CEP_SET_RESET_INIT, modify_attrp, NULL);
 286                 ibtl_qp_flow_control_exit();
 287                 if (status == IBT_SUCCESS)
 288                         ibt_qp->ch_current_state = IBT_STATE_INIT;
 289                 break;
 290         default:
 291                 /* shouldn't happen ILLEGAL Type */
 292                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_initialize_qp: Illegal Type %d",
 293                     modify_attrp->qp_trans);
 294                 return (IBT_QP_SRV_TYPE_INVALID);
 295         } /* End switch */
 296 
 297         return (status);
 298 }
 299 
 300 
 301 /*
 302  * Function:
 303  *      ibt_alloc_special_qp
 304  * Input:
 305  *      hca_hdl         HCA Handle.
 306  *      type            Specifies the type of Special QP to be allocated.
 307  *      qp_attrp        Specifies the ibt_qp_alloc_attr_t that are needed to
 308  *                      allocate a special QP.
 309  * Output:
 310  *      queue_sizes_p   Returned sizes for SQ, RQ, SQ WR SGL elements & RQ
 311  *                      WR SGL elements.
 312  *      qpn_p           Returned qpn of the allocated QP.
 313  *      ibt_qp_p        The ibt_qp_hdl_t of the allocated QP.
 314  * Returns:
 315  *      IBT_SUCCESS
 316  * Description:
 317  *      Allocate a special QP with specified attributes.
 318  */
 319 ibt_status_t
 320 ibt_alloc_special_qp(ibt_hca_hdl_t hca_hdl, uint8_t port, ibt_sqp_type_t type,
 321     ibt_qp_alloc_attr_t *qp_attrp, ibt_chan_sizes_t *queue_sizes_p,
 322     ibt_qp_hdl_t *ibt_qp_p)
 323 {
 324         ibt_qp_hdl_t    chanp;
 325         ibt_status_t    retval;
 326         ibt_tran_srv_t  sqp_type;
 327 
 328         IBTF_DPRINTF_L3(ibtf_qp, "ibt_alloc_special_qp(%p, %d, %x, %p, %p, %p)",
 329             hca_hdl, port, type, qp_attrp, queue_sizes_p, ibt_qp_p);
 330 
 331         switch (type) {
 332         case IBT_SMI_SQP:
 333         case IBT_GSI_SQP:
 334                 sqp_type = IBT_UD_SRV;
 335                 break;
 336 
 337         case IBT_RAWIP_SQP:
 338                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_special_qp: Raw IP "
 339                     "Transport Type is not supported.");
 340                 *ibt_qp_p = NULL;
 341                 return (IBT_NOT_SUPPORTED);
 342 
 343         case IBT_RAWETHER_SQP:
 344                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_special_qp: Raw Ethernet "
 345                     "Transport Type is not supported.");
 346                 *ibt_qp_p = NULL;
 347                 return (IBT_NOT_SUPPORTED);
 348 
 349         default:
 350                 /* Shouldn't happen */
 351                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_special_qp: "
 352                     "Illegal Type 0x%x", type);
 353                 *ibt_qp_p = NULL;
 354                 return (IBT_QP_SPECIAL_TYPE_INVALID);
 355         }
 356 
 357         /* convert the CQ handles for the CI */
 358         qp_attrp->qp_ibc_scq_hdl = qp_attrp->qp_scq_hdl->cq_ibc_cq_hdl;
 359         qp_attrp->qp_ibc_rcq_hdl = qp_attrp->qp_rcq_hdl->cq_ibc_cq_hdl;
 360 
 361         /* Allocate Channel structure */
 362         chanp = kmem_zalloc(sizeof (*chanp), KM_SLEEP);
 363 
 364         ibtl_qp_flow_control_enter();
 365         retval = (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_special_qp)(
 366             IBTL_HCA2CIHCA(hca_hdl), port, &chanp->ch_qp, type, qp_attrp,
 367             queue_sizes_p, &chanp->ch_qp.qp_ibc_qp_hdl);
 368         ibtl_qp_flow_control_exit();
 369         if (retval != IBT_SUCCESS) {
 370                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_special_qp: "
 371                     "Failed to allocate Special QP: %d", retval);
 372                 kmem_free(chanp, sizeof (*chanp));
 373                 *ibt_qp_p = NULL;
 374                 return (retval);
 375         }
 376 
 377         /* Initialize the internal QP struct. */
 378         chanp->ch_qp.qp_type = sqp_type;
 379         chanp->ch_qp.qp_hca = hca_hdl;
 380         chanp->ch_qp.qp_send_cq = qp_attrp->qp_scq_hdl;
 381         chanp->ch_qp.qp_recv_cq = qp_attrp->qp_rcq_hdl;
 382         chanp->ch_current_state = IBT_STATE_RESET;
 383         mutex_init(&chanp->ch_cm_mutex, NULL, MUTEX_DEFAULT, NULL);
 384         cv_init(&chanp->ch_cm_cv, NULL, CV_DEFAULT, NULL);
 385 
 386         /* Updating these variable, so that debugger shows correct values. */
 387         chanp->ch_qp.qp_flags = qp_attrp->qp_flags;
 388         chanp->ch_qp.qp_pd_hdl = qp_attrp->qp_pd_hdl;
 389 
 390         atomic_inc_32(&hca_hdl->ha_qp_cnt);
 391 
 392         *ibt_qp_p = chanp;
 393 
 394         return (retval);
 395 }
 396 
 397 
 398 /*
 399  * Function:
 400  *      ibt_flush_qp
 401  * Input:
 402  *      ibtl_qp         Handle for QP that needs to be flushed.
 403  * Output:
 404  *      none.
 405  * Returns:
 406  *      IBT_SUCCESS
 407  *      IBT_QP_HDL_INVALID
 408  * Description:
 409  *      Put the QP into error state to flush out work requests.
 410  */
 411 ibt_status_t
 412 ibt_flush_qp(ibt_qp_hdl_t ibt_qp)
 413 {
 414         ibt_qp_info_t           modify_attr;
 415         ibt_status_t            retval;
 416 
 417         IBTF_DPRINTF_L3(ibtf_qp, "ibt_flush_qp(%p)", ibt_qp);
 418 
 419         if (ibt_qp->ch_qp.qp_type == IBT_RC_SRV) {
 420                 mutex_enter(&ibtl_free_qp_mutex);
 421                 if ((ibt_qp->ch_transport.rc.rc_free_flags &
 422                     (IBTL_RC_QP_CONNECTED | IBTL_RC_QP_CLOSING)) ==
 423                     IBTL_RC_QP_CONNECTED) {
 424                         mutex_exit(&ibtl_free_qp_mutex);
 425                         IBTF_DPRINTF_L2(ibtf_qp, "ibt_flush_qp(%p): "
 426                             "called with a connected RC QP", ibt_qp);
 427                         return (IBT_CHAN_STATE_INVALID);
 428                 }
 429                 mutex_exit(&ibtl_free_qp_mutex);
 430         }
 431 
 432         bzero(&modify_attr, sizeof (ibt_qp_info_t));
 433 
 434         /*
 435          * Set the QP state to error to flush any uncompleted WRs.
 436          */
 437         modify_attr.qp_state = IBT_STATE_ERROR;
 438         modify_attr.qp_trans = ibt_qp->ch_qp.qp_type;
 439 
 440         retval = ibt_modify_qp(ibt_qp, IBT_CEP_SET_STATE, &modify_attr, NULL);
 441 
 442         if (retval != IBT_SUCCESS) {
 443                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_flush_qp: "
 444                     "failed on chan %p: %d", ibt_qp, retval);
 445         }
 446         return (retval);
 447 }
 448 
 449 
 450 /*
 451  * ibtl_cm_chan_is_opening()
 452  *
 453  *      Inform IBTL that the connection established process is in progress
 454  *      on this channel so that care need to be taken while free'ing when
 455  *      open is NOT yet complete.
 456  *
 457  *      chan    Channel Handle
 458  */
 459 void
 460 ibtl_cm_chan_is_opening(ibt_channel_hdl_t chan)
 461 {
 462         IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_chan_is_opening(%p)", chan);
 463         ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV);
 464         mutex_enter(&ibtl_free_qp_mutex);
 465         ASSERT(chan->ch_transport.rc.rc_free_flags == 0);
 466         chan->ch_transport.rc.rc_free_flags |= IBTL_RC_QP_CONNECTING;
 467         mutex_exit(&ibtl_free_qp_mutex);
 468 }
 469 
 470 /*
 471  * ibtl_cm_chan_open_is_aborted()
 472  *
 473  *      Inform IBTL that the connection established on this channel has
 474  *      aborted. So undo what was done in ibtl_cm_chan_is_opening().
 475  *
 476  *      chan    Channel Handle
 477  */
 478 void
 479 ibtl_cm_chan_open_is_aborted(ibt_channel_hdl_t chan)
 480 {
 481         IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_chan_open_is_aborted(%p)", chan);
 482         ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV);
 483         mutex_enter(&ibtl_free_qp_mutex);
 484         chan->ch_transport.rc.rc_free_flags &= ~IBTL_RC_QP_CONNECTING;
 485         mutex_exit(&ibtl_free_qp_mutex);
 486 }
 487 
 488 /*
 489  * ibtl_cm_chan_is_open()
 490  *
 491  *      Inform IBTL that the connection has been established on this
 492  *      channel so that a later call to ibtl_cm_chan_is_closed()
 493  *      will be required to free the QPN used by this channel.
 494  *
 495  *      chan    Channel Handle
 496  */
 497 void
 498 ibtl_cm_chan_is_open(ibt_channel_hdl_t chan)
 499 {
 500         IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_chan_is_open(%p)", chan);
 501         ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV);
 502         mutex_enter(&ibtl_free_qp_mutex);
 503         chan->ch_transport.rc.rc_free_flags &= ~IBTL_RC_QP_CONNECTING;
 504         chan->ch_transport.rc.rc_free_flags |= IBTL_RC_QP_CONNECTED;
 505         mutex_exit(&ibtl_free_qp_mutex);
 506 }
 507 
 508 /*
 509  * ibtl_cm_is_chan_closing()
 510  *
 511  *      Returns 1, if the connection that has been
 512  *      started for this channel has moved to TIMEWAIT
 513  *      If not, returns 0
 514  *
 515  *      chan    Channel Handle
 516  */
 517 int
 518 ibtl_cm_is_chan_closing(ibt_channel_hdl_t chan)
 519 {
 520         IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_is_chan_closing(%p)", chan);
 521         ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV);
 522         mutex_enter(&ibtl_free_qp_mutex);
 523         if (chan->ch_transport.rc.rc_free_flags & IBTL_RC_QP_CLOSING) {
 524                 mutex_exit(&ibtl_free_qp_mutex);
 525                 return (1);
 526         }
 527         mutex_exit(&ibtl_free_qp_mutex);
 528         return (0);
 529 }
 530 
 531 /*
 532  * ibtl_cm_is_chan_closed()
 533  *
 534  *      Returns 1, if the connection that has been
 535  *      started for this channel has completed TIMEWAIT
 536  *      If not, returns 0
 537  *
 538  *      chan    Channel Handle
 539  */
 540 int
 541 ibtl_cm_is_chan_closed(ibt_channel_hdl_t chan)
 542 {
 543         IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_is_chan_closed(%p)", chan);
 544         ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV);
 545         mutex_enter(&ibtl_free_qp_mutex);
 546         if (chan->ch_transport.rc.rc_free_flags & IBTL_RC_QP_CLOSED) {
 547                 mutex_exit(&ibtl_free_qp_mutex);
 548                 return (1);
 549         }
 550         mutex_exit(&ibtl_free_qp_mutex);
 551         return (0);
 552 }
 553 /*
 554  * ibtl_cm_chan_is_closing()
 555  *
 556  *      Inform IBTL that the TIMEWAIT delay for the connection has been
 557  *      started for this channel so that the QP can be freed.
 558  *
 559  *      chan    Channel Handle
 560  */
 561 void
 562 ibtl_cm_chan_is_closing(ibt_channel_hdl_t chan)
 563 {
 564         IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_chan_is_closing(%p)", chan);
 565         ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV);
 566         mutex_enter(&ibtl_free_qp_mutex);
 567         ASSERT(chan->ch_transport.rc.rc_free_flags == IBTL_RC_QP_CONNECTED);
 568         chan->ch_transport.rc.rc_free_flags |= IBTL_RC_QP_CLOSING;
 569         mutex_exit(&ibtl_free_qp_mutex);
 570 }
 571 /*
 572  * ibtl_cm_chan_is_closed()
 573  *
 574  *      Inform IBTL that the TIMEWAIT delay for the connection has been
 575  *      reached for this channel so that the QPN can be reused.
 576  *
 577  *      chan    Channel Handle
 578  */
 579 void
 580 ibtl_cm_chan_is_closed(ibt_channel_hdl_t chan)
 581 {
 582         ibt_status_t status;
 583         ibtl_hca_t *ibtl_hca = chan->ch_qp.qp_hca;
 584 
 585         IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_chan_is_closed(%p)", chan);
 586         ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV);
 587         mutex_enter(&ibtl_free_qp_mutex);
 588         ASSERT((chan->ch_transport.rc.rc_free_flags &
 589             (IBTL_RC_QP_CONNECTED | IBTL_RC_QP_CLOSING)) ==
 590             (IBTL_RC_QP_CONNECTED | IBTL_RC_QP_CLOSING));
 591 
 592         chan->ch_transport.rc.rc_free_flags &= ~IBTL_RC_QP_CONNECTED;
 593         chan->ch_transport.rc.rc_free_flags &= ~IBTL_RC_QP_CLOSING;
 594         chan->ch_transport.rc.rc_free_flags |= IBTL_RC_QP_CLOSED;
 595 
 596         ibtl_cm_set_chan_private(chan, NULL);
 597 
 598         if ((chan->ch_transport.rc.rc_free_flags & IBTL_RC_QP_FREED) == 0) {
 599                 mutex_exit(&ibtl_free_qp_mutex);
 600                 return;
 601         }
 602         mutex_exit(&ibtl_free_qp_mutex);
 603         ibtl_qp_flow_control_enter();
 604         if ((status = (IBTL_CHAN2CIHCAOPS_P(chan)->ibc_release_qpn)
 605             (IBTL_CHAN2CIHCA(chan), chan->ch_transport.rc.rc_qpn_hdl)) ==
 606             IBT_SUCCESS) {
 607                 /* effectively, this is kmem_free(chan); */
 608                 ibtl_free_qp_async_check(&chan->ch_qp);
 609 
 610                 /* decrement ha_qpn_cnt and check for close in progress */
 611                 ibtl_close_hca_check(ibtl_hca);
 612         } else
 613                 IBTF_DPRINTF_L2(ibtf_qp, "ibtl_cm_chan_is_closed: "
 614                     "ibc_release_qpn failed: status = %d\n", status);
 615         ibtl_qp_flow_control_exit();
 616 }
 617 
 618 /*
 619  * ibtl_cm_chan_is_reused()
 620  *
 621  *      Inform IBTL that the channel is going to be re-used
 622  *      chan    Channel Handle
 623  */
 624 void
 625 ibtl_cm_chan_is_reused(ibt_channel_hdl_t chan)
 626 {
 627         IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_chan_is_reused(%p)", chan);
 628         ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV);
 629         mutex_enter(&ibtl_free_qp_mutex);
 630         ASSERT(((chan->ch_transport.rc.rc_free_flags & IBTL_RC_QP_CONNECTED) !=
 631             IBTL_RC_QP_CONNECTED));
 632 
 633         /* channel is no longer in closed state, shall be re-used */
 634         chan->ch_transport.rc.rc_free_flags = 0;
 635 
 636         mutex_exit(&ibtl_free_qp_mutex);
 637 
 638 }
 639 
 640 /*
 641  * Function:    ibt_free_qp()
 642  *
 643  * Input:       ibt_qp          Handle for Channel(QP) that needs to be freed.
 644  *
 645  * Output:      NONE.
 646  *
 647  * Returns:     IBT_SUCCESS
 648  *              IBT_QP_STATE_INVALID
 649  *              IBT_QP_HDL_INVALID
 650  *
 651  * Description:
 652  *              Free a previously allocated QP.
 653  */
 654 ibt_status_t
 655 ibt_free_qp(ibt_qp_hdl_t ibt_qp)
 656 {
 657         ibt_status_t            status;
 658         ibtl_hca_t              *ibtl_hca = ibt_qp->ch_qp.qp_hca;
 659 
 660         IBTF_DPRINTF_L3(ibtf_qp, "ibt_free_qp(%p)", ibt_qp);
 661 
 662         if (ibt_qp->ch_qp.qp_type == IBT_RC_SRV) {
 663                 ibtl_qp_flow_control_enter();
 664                 mutex_enter(&ibtl_free_qp_mutex);
 665                 if (ibt_qp->ch_transport.rc.rc_free_flags &
 666                     IBTL_RC_QP_CONNECTING) {
 667                         IBTF_DPRINTF_L2(ibtf_qp, "ibt_free_qp: ERROR - "
 668                             "Channel establishment is still in PROGRESS.");
 669                         mutex_exit(&ibtl_free_qp_mutex);
 670                         ibtl_qp_flow_control_exit();
 671                         return (IBT_CHAN_STATE_INVALID);
 672                 }
 673                 if (ibt_qp->ch_transport.rc.rc_free_flags &
 674                     IBTL_RC_QP_CONNECTED) {
 675                         if ((ibt_qp->ch_transport.rc.rc_free_flags &
 676                             IBTL_RC_QP_CLOSING) == 0) {
 677                                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_free_qp: ERROR - "
 678                                     "need to call ibt_close_rc_channel");
 679                                 mutex_exit(&ibtl_free_qp_mutex);
 680                                 ibtl_qp_flow_control_exit();
 681                                 return (IBT_CHAN_STATE_INVALID);
 682                         }
 683                         ibt_qp->ch_transport.rc.rc_free_flags |=
 684                             IBTL_RC_QP_FREED;
 685                         status = (IBTL_CHAN2CIHCAOPS_P(ibt_qp)->ibc_free_qp)
 686                             (IBTL_CHAN2CIHCA(ibt_qp), IBTL_CHAN2CIQP(ibt_qp),
 687                             IBC_FREE_QP_ONLY,
 688                             &ibt_qp->ch_transport.rc.rc_qpn_hdl);
 689                         mutex_exit(&ibtl_free_qp_mutex);
 690                         ibtl_qp_flow_control_exit();
 691 
 692                         if (status == IBT_SUCCESS) {
 693                                 mutex_enter(&ibtl_clnt_list_mutex);
 694                                 ibtl_hca->ha_qpn_cnt++;
 695                                 mutex_exit(&ibtl_clnt_list_mutex);
 696                                 atomic_dec_32(&ibtl_hca->ha_qp_cnt);
 697                                 IBTF_DPRINTF_L3(ibtf_qp, "ibt_free_qp(%p) - "
 698                                     "SUCCESS", ibt_qp);
 699                         } else
 700                                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_free_qp: "
 701                                     "ibc_free_qp failed: status = %d", status);
 702                         return (status);
 703                 }
 704                 mutex_exit(&ibtl_free_qp_mutex);
 705         } else
 706                 ibtl_qp_flow_control_enter();
 707 
 708         status = (IBTL_CHAN2CIHCAOPS_P(ibt_qp)->ibc_free_qp)
 709             (IBTL_CHAN2CIHCA(ibt_qp), IBTL_CHAN2CIQP(ibt_qp),
 710             IBC_FREE_QP_AND_QPN, NULL);
 711         ibtl_qp_flow_control_exit();
 712 
 713         if (status == IBT_SUCCESS) {
 714                 /* effectively, this is kmem_free(ibt_qp); */
 715                 ibtl_free_qp_async_check(&ibt_qp->ch_qp);
 716 
 717                 atomic_dec_32(&ibtl_hca->ha_qp_cnt);
 718                 IBTF_DPRINTF_L3(ibtf_qp, "ibt_free_qp(%p) - SUCCESS", ibt_qp);
 719         } else {
 720                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_free_qp: "
 721                     "ibc_free_qp failed with error %d", status);
 722         }
 723 
 724         return (status);
 725 }
 726 
 727 
 728 /* helper function for ibt_query_qp */
 729 static void
 730 ibtl_fillin_sgid(ibt_cep_path_t *pathp, ibtl_hca_devinfo_t *hca_devp)
 731 {
 732         uint8_t port;
 733         uint32_t sgid_ix;
 734         ib_gid_t *sgidp;
 735 
 736         port = pathp->cep_hca_port_num;
 737         sgid_ix = pathp->cep_adds_vect.av_sgid_ix;
 738         if (port == 0 || port > hca_devp->hd_hca_attr->hca_nports ||
 739             sgid_ix >= IBTL_HDIP2SGIDTBLSZ(hca_devp)) {
 740                 pathp->cep_adds_vect.av_sgid.gid_prefix = 0;
 741                 pathp->cep_adds_vect.av_sgid.gid_guid = 0;
 742         } else {
 743                 mutex_enter(&ibtl_clnt_list_mutex);
 744                 sgidp = hca_devp->hd_portinfop[port-1].p_sgid_tbl;
 745                 pathp->cep_adds_vect.av_sgid = sgidp[sgid_ix];
 746                 mutex_exit(&ibtl_clnt_list_mutex);
 747         }
 748 }
 749 
 750 
 751 /*
 752  * Function:    ibt_query_qp
 753  *
 754  * Input:       ibt_qp                  - The IBT QP Handle.
 755  *
 756  * Output:      ibt_qp_query_attrp      - Points to a ibt_qp_query_attr_t
 757  *                                        that on return contains all the
 758  *                                        attributes of the specified qp.
 759  *
 760  * Returns:     IBT_SUCCESS
 761  *              IBT_QP_HDL_INVALID
 762  *
 763  * Description:
 764  *              Query QP attributes
 765  *
 766  */
 767 ibt_status_t
 768 ibt_query_qp(ibt_qp_hdl_t ibt_qp, ibt_qp_query_attr_t *qp_query_attrp)
 769 {
 770         ibt_status_t            retval;
 771         ibtl_hca_devinfo_t      *hca_devp;
 772         ibt_qp_info_t           *qp_infop;
 773 
 774         IBTF_DPRINTF_L3(ibtf_qp, "ibt_query_qp(%p, %p)",
 775             ibt_qp, qp_query_attrp);
 776 
 777         ibtl_qp_flow_control_enter();
 778         retval = (IBTL_CHAN2CIHCAOPS_P(ibt_qp)->ibc_query_qp(
 779             IBTL_CHAN2CIHCA(ibt_qp), IBTL_CHAN2CIQP(ibt_qp), qp_query_attrp));
 780         ibtl_qp_flow_control_exit();
 781         if (retval == IBT_SUCCESS) {
 782                 ibt_qp->ch_current_state = qp_query_attrp->qp_info.qp_state;
 783 
 784                 /* need to fill in sgid from port and sgid_ix for RC and UC */
 785                 hca_devp = ibt_qp->ch_qp.qp_hca->ha_hca_devp;
 786                 qp_infop = &qp_query_attrp->qp_info;
 787 
 788                 switch (qp_infop->qp_trans) {
 789                 case IBT_RC_SRV:
 790                         ibtl_fillin_sgid(&qp_infop->qp_transport.rc.rc_path,
 791                             hca_devp);
 792                         ibtl_fillin_sgid(&qp_infop->qp_transport.rc.rc_alt_path,
 793                             hca_devp);
 794                         break;
 795                 case IBT_UC_SRV:
 796                         ibtl_fillin_sgid(&qp_infop->qp_transport.uc.uc_path,
 797                             hca_devp);
 798                         ibtl_fillin_sgid(&qp_infop->qp_transport.uc.uc_alt_path,
 799                             hca_devp);
 800                         break;
 801                 }
 802         } else {
 803                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_query_qp: "
 804                     "failed on chan %p: %d", ibt_qp, retval);
 805         }
 806 
 807         return (retval);
 808 }
 809 
 810 
 811 /*
 812  * Function:
 813  *      ibt_modify_qp
 814  * Input:
 815  *      ibt_qp          The IBT QP Handle.
 816  *      flags           Specifies which attributes in ibt_qp_mod_attr_t
 817  *                      are to be modified.
 818  *      qp_attrp        Points to an ibt_qp_mod_attr_t struct that contains all
 819  *                      the attributes of the specified QP that a client is
 820  *                      allowed to modify after a QP has been allocated
 821  * Output:
 822  *      actual_sz       Returned actual queue sizes.
 823  * Returns:
 824  *      IBT_SUCCESS
 825  * Description:
 826  *      Modify the attributes of an existing QP.
 827  */
 828 ibt_status_t
 829 ibt_modify_qp(ibt_qp_hdl_t ibt_qp, ibt_cep_modify_flags_t flags,
 830     ibt_qp_info_t *modify_attrp, ibt_queue_sizes_t *actual_sz)
 831 {
 832         ibt_status_t            retval;
 833 
 834         IBTF_DPRINTF_L3(ibtf_qp, "ibt_modify_qp(%p, %d, %p, %p)",
 835             ibt_qp, flags, modify_attrp, actual_sz);
 836 
 837         ibtl_qp_flow_control_enter();
 838         retval = (IBTL_CHAN2CIHCAOPS_P(ibt_qp)->ibc_modify_qp)(
 839             IBTL_CHAN2CIHCA(ibt_qp), IBTL_CHAN2CIQP(ibt_qp), flags,
 840             modify_attrp, actual_sz);
 841         ibtl_qp_flow_control_exit();
 842         if (retval == IBT_SUCCESS) {
 843                 ibt_qp->ch_current_state = modify_attrp->qp_state;
 844                 if (ibt_qp->ch_qp.qp_type == IBT_UD_SRV) {
 845                         if (flags & (IBT_CEP_SET_PORT | IBT_CEP_SET_RESET_INIT))
 846                                 ibt_qp->ch_transport.ud.ud_port_num =
 847                                     modify_attrp->qp_transport.ud.ud_port;
 848                         if (flags & (IBT_CEP_SET_QKEY | IBT_CEP_SET_RESET_INIT))
 849                                 ibt_qp->ch_transport.ud.ud_qkey =
 850                                     modify_attrp->qp_transport.ud.ud_qkey;
 851                 }
 852         } else {
 853                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_modify_qp: failed on chan %p: %d",
 854                     ibt_qp, retval);
 855 
 856                 if (retval == IBT_CHAN_STATE_INVALID) {
 857                         /* That means our cache had invalid QP state value. */
 858                         ibt_qp_query_attr_t     qp_attr;
 859 
 860                         /* Query the channel (QP) */
 861                         if (ibt_query_qp(ibt_qp, &qp_attr) == IBT_SUCCESS)
 862                                 ibt_qp->ch_current_state =
 863                                     qp_attr.qp_info.qp_state;
 864                 }
 865         }
 866         return (retval);
 867 }
 868 
 869 
 870 /*
 871  * Function:
 872  *      ibt_migrate_path
 873  * Input:
 874  *      rc_chan         A previously allocated RC channel handle.
 875  * Output:
 876  *      none.
 877  * Returns:
 878  *      IBT_SUCCESS on Success else appropriate error.
 879  * Description:
 880  *      Force the CI to use the alternate path. The alternate path becomes
 881  *      the primary path. A new alternate path should be loaded and enabled.
 882  *      Assumes that the given channel is in RTS/SQD state
 883  */
 884 ibt_status_t
 885 ibt_migrate_path(ibt_channel_hdl_t rc_chan)
 886 {
 887         ibt_status_t            retval;
 888         ibt_qp_info_t           qp_info;
 889         ibt_qp_query_attr_t     qp_attr;
 890         ibt_cep_modify_flags_t  cep_flags;
 891         int                     retries = 1;
 892 
 893         IBTF_DPRINTF_L3(ibtf_qp, "ibt_migrate_path: channel %p", rc_chan);
 894 
 895         if (rc_chan->ch_qp.qp_type != IBT_RC_SRV) {
 896                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_migrate_path: "
 897                     "Invalid Channel type: Applicable only to RC Channel");
 898                 return (IBT_CHAN_SRV_TYPE_INVALID);
 899         }
 900 
 901         if (rc_chan->ch_current_state != IBT_STATE_RTS &&
 902             rc_chan->ch_current_state != IBT_STATE_SQD) {
 903                 if (ibt_query_qp(rc_chan, &qp_attr) == IBT_SUCCESS) {
 904                         /* ch_current_state is fixed by ibt_query_qp */
 905                         if (rc_chan->ch_current_state != IBT_STATE_RTS &&
 906                             rc_chan->ch_current_state != IBT_STATE_SQD)
 907                                 return (IBT_CHAN_STATE_INVALID);
 908                         retries = 0;
 909                 } else /* query_qp should never really fail */
 910                         return (IBT_CHAN_STATE_INVALID);
 911         }
 912 
 913 retry:
 914         /* Call modify_qp */
 915         cep_flags = IBT_CEP_SET_MIG | IBT_CEP_SET_STATE;
 916         qp_info.qp_state = rc_chan->ch_current_state;
 917         qp_info.qp_current_state = rc_chan->ch_current_state;
 918         qp_info.qp_trans = IBT_RC_SRV;
 919         qp_info.qp_transport.rc.rc_mig_state = IBT_STATE_MIGRATED;
 920         retval = ibt_modify_qp(rc_chan, cep_flags, &qp_info, NULL);
 921 
 922         if (retval != IBT_SUCCESS) {
 923                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_migrate_path:"
 924                     " ibt_modify_qp() returned = %d", retval);
 925                 if (rc_chan->ch_current_state != qp_info.qp_state &&
 926                     --retries >= 0) {
 927                         /*
 928                          * That means our cached 'state' was invalid.
 929                          * We know ibt_modify_qp() fixed it up, so it
 930                          * might be worth retrying.
 931                          */
 932                         if (rc_chan->ch_current_state != IBT_STATE_RTS &&
 933                             rc_chan->ch_current_state != IBT_STATE_SQD)
 934                                 return (IBT_CHAN_STATE_INVALID);
 935                         IBTF_DPRINTF_L2(ibtf_qp, "ibt_migrate_path:"
 936                             " retrying after 'state' fixed");
 937                         goto retry;
 938                 }
 939         }
 940         return (retval);
 941 }
 942 
 943 
 944 /*
 945  * Function:
 946  *      ibt_set_qp_private
 947  * Input:
 948  *      ibt_qp          The ibt_qp_hdl_t of the allocated QP.
 949  *      clnt_private    The client private data.
 950  * Output:
 951  *      none.
 952  * Returns:
 953  *      none.
 954  * Description:
 955  *      Set the client private data.
 956  */
 957 void
 958 ibt_set_qp_private(ibt_qp_hdl_t ibt_qp, void *clnt_private)
 959 {
 960         ibt_qp->ch_clnt_private = clnt_private;
 961 }
 962 
 963 
 964 /*
 965  * Function:
 966  *      ibt_get_qp_private
 967  * Input:
 968  *      ibt_qp          The ibt_qp_hdl_t of the allocated QP.
 969  * Output:
 970  *      none.
 971  * Returns:
 972  *      The client private data.
 973  * Description:
 974  *      Get the client private data.
 975  */
 976 void *
 977 ibt_get_qp_private(ibt_qp_hdl_t ibt_qp)
 978 {
 979         return (ibt_qp->ch_clnt_private);
 980 }
 981 
 982 
 983 /*
 984  * Function:
 985  *      ibt_qp_to_hca_guid
 986  * Input:
 987  *      ibt_qp          The ibt_qp_hdl_t of the allocated QP.
 988  * Output:
 989  *      none.
 990  * Returns:
 991  *      hca_guid        Returned HCA GUID on which the specified QP is
 992  *                      allocated. Valid if it is non-NULL on return.
 993  * Description:
 994  *      A helper function to retrieve HCA GUID for the specified QP.
 995  */
 996 ib_guid_t
 997 ibt_qp_to_hca_guid(ibt_qp_hdl_t ibt_qp)
 998 {
 999         IBTF_DPRINTF_L3(ibtf_qp, "ibt_qp_to_hca_guid(%p)", ibt_qp);
1000 
1001         return (IBTL_HCA2HCAGUID(IBTL_CHAN2HCA(ibt_qp)));
1002 }
1003 
1004 
1005 /*
1006  * Function:
1007  *      ibt_recover_ud_qp
1008  * Input:
1009  *      ibt_qp          An QP Handle which is in SQError state.
1010  * Output:
1011  *      none.
1012  * Returns:
1013  *      IBT_SUCCESS
1014  *      IBT_QP_SRV_TYPE_INVALID
1015  *      IBT_QP_STATE_INVALID.
1016  * Description:
1017  *      Recover an UD QP which has transitioned to SQ Error state. The
1018  *      ibt_recover_ud_qp() transitions the QP from SQ Error state to
1019  *      Ready-To-Send QP state.
1020  *
1021  *      If a work request posted to a UD QP's send queue completes with an
1022  *      error (see ibt_wc_status_t), the QP gets transitioned to SQ Error state.
1023  *      In order to reuse this QP, ibt_recover_ud_qp() can be used to recover
1024  *      the QP to a usable (Ready-to-Send) state.
1025  */
1026 ibt_status_t
1027 ibt_recover_ud_qp(ibt_qp_hdl_t ibt_qp)
1028 {
1029         IBTF_DPRINTF_L3(ibtf_qp, "ibt_recover_ud_qp(%p)", ibt_qp);
1030 
1031         return (ibt_recover_ud_channel(IBTL_QP2CHAN(ibt_qp)));
1032 }
1033 
1034 
1035 /*
1036  * Function:
1037  *      ibt_recycle_ud
1038  * Input:
1039  *      ud_chan         The IBT UD QP Handle.
1040  *      various attributes
1041  *
1042  * Output:
1043  *      none
1044  * Returns:
1045  *      IBT_SUCCESS
1046  *      IBT_CHAN_SRV_TYPE_INVALID
1047  *      IBT_CHAN_STATE_INVALID
1048  *
1049  * Description:
1050  *      Revert the UD QP back to a usable state.
1051  */
1052 ibt_status_t
1053 ibt_recycle_ud(ibt_channel_hdl_t ud_chan, uint8_t hca_port_num,
1054     uint16_t pkey_ix, ib_qkey_t qkey)
1055 {
1056         ibt_qp_query_attr_t     qp_attr;
1057         ibt_status_t            retval;
1058 
1059         IBTF_DPRINTF_L3(ibtf_qp, "ibt_recycle_ud(%p, %d, %x, %x): ",
1060             ud_chan, hca_port_num, pkey_ix, qkey);
1061 
1062         if (ud_chan->ch_qp.qp_type != IBT_UD_SRV) {
1063                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_recycle_ud: "
1064                     "chan %p is not a UD channel", ud_chan);
1065                 return (IBT_CHAN_SRV_TYPE_INVALID);
1066         }
1067 
1068         retval = ibt_query_qp(ud_chan, &qp_attr);
1069         if (retval != IBT_SUCCESS) {
1070                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_recycle_ud: "
1071                     "ibt_query_qp failed on chan %p: %d", ud_chan, retval);
1072                 return (retval);
1073         }
1074         if (qp_attr.qp_info.qp_state != IBT_STATE_ERROR) {
1075                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_recycle_ud: "
1076                     "chan %p is in state %d (not in ERROR state)",
1077                     ud_chan, qp_attr.qp_info.qp_state);
1078                 ud_chan->ch_current_state = qp_attr.qp_info.qp_state;
1079                 return (IBT_CHAN_STATE_INVALID);
1080         }
1081 
1082         /* transition the QP from ERROR to RESET */
1083         qp_attr.qp_info.qp_state = IBT_STATE_RESET;
1084         qp_attr.qp_info.qp_trans = ud_chan->ch_qp.qp_type;
1085         retval = ibt_modify_qp(ud_chan, IBT_CEP_SET_STATE, &qp_attr.qp_info,
1086             NULL);
1087         if (retval != IBT_SUCCESS) {
1088                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_recycle_ud: "
1089                     "ibt_modify_qp(ERROR=>RESET) failed on chan %p: %d",
1090                     ud_chan, retval);
1091                 return (retval);
1092         }
1093         ud_chan->ch_current_state = IBT_STATE_RESET;
1094 
1095         /* transition the QP back to RTS */
1096         qp_attr.qp_info.qp_transport.ud.ud_port = hca_port_num;
1097         qp_attr.qp_info.qp_transport.ud.ud_qkey = qkey;
1098         qp_attr.qp_info.qp_transport.ud.ud_pkey_ix = pkey_ix;
1099         retval = ibt_initialize_qp(ud_chan, &qp_attr.qp_info);
1100         if (retval != IBT_SUCCESS) {
1101                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_recycle_ud: "
1102                     "ibt_initialize_qp failed on chan %p: %d", ud_chan, retval);
1103                 /* the man page says the QP should be left in ERROR state */
1104                 (void) ibt_flush_qp(ud_chan);
1105         }
1106         return (retval);
1107 }
1108 
1109 /*
1110  * Function:
1111  *      ibt_pause_sendq
1112  * Input:
1113  *      chan            The IBT QP Handle.
1114  *      modify_flags    IBT_CEP_SET_NOTHING or IBT_CEP_SET_SQD_EVENT
1115  *
1116  * Output:
1117  *      none.
1118  * Returns:
1119  *      IBT_SUCCESS
1120  *      IBT_CHAN_HDL_INVALID
1121  *      IBT_CHAN_STATE_INVALID
1122  *      IBT_INVALID_PARAM
1123  *
1124  * Description:
1125  *      Place the send queue of the specified channel into the send queue
1126  *      drained (SQD) state.
1127  *
1128  */
1129 ibt_status_t
1130 ibt_pause_sendq(ibt_channel_hdl_t chan, ibt_cep_modify_flags_t modify_flags)
1131 {
1132         ibt_qp_info_t           modify_attr;
1133         ibt_status_t            retval;
1134 
1135         IBTF_DPRINTF_L3(ibtf_qp, "ibt_pause_sendq(%p, %x)", chan, modify_flags);
1136 
1137         modify_flags &= IBT_CEP_SET_SQD_EVENT;      /* ignore other bits */
1138         modify_flags |= IBT_CEP_SET_STATE;
1139 
1140         bzero(&modify_attr, sizeof (ibt_qp_info_t));
1141         /*
1142          * Set the QP state to SQD.
1143          */
1144         modify_attr.qp_state = IBT_STATE_SQD;
1145         modify_attr.qp_trans = chan->ch_qp.qp_type;
1146 
1147         retval = ibt_modify_qp(chan, modify_flags, &modify_attr, NULL);
1148 
1149         if (retval != IBT_SUCCESS) {
1150                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_pause_sendq: "
1151                     "failed on chan %p: %d", chan, retval);
1152         }
1153         return (retval);
1154 }
1155 
1156 
1157 /*
1158  * Function:
1159  *      ibt_unpause_sendq
1160  * Input:
1161  *      chan    The IBT Channel Handle.
1162  * Output:
1163  *      none.
1164  * Returns:
1165  *      IBT_SUCCESS
1166  *      IBT_CHAN_HDL_INVALID
1167  *      IBT_CHAN_STATE_INVALID
1168  * Description:
1169  *      Un-pauses the previously paused channel. This call will transition the
1170  *      QP from SQD to RTS state.
1171  */
1172 ibt_status_t
1173 ibt_unpause_sendq(ibt_channel_hdl_t chan)
1174 {
1175         ibt_qp_info_t           modify_attr;
1176         ibt_status_t            retval;
1177 
1178         IBTF_DPRINTF_L3(ibtf_qp, "ibt_unpause_sendq(%p)", chan);
1179 
1180         bzero(&modify_attr, sizeof (ibt_qp_info_t));
1181 
1182         /*
1183          * Set the QP state to RTS.
1184          */
1185         modify_attr.qp_current_state = IBT_STATE_SQD;
1186         modify_attr.qp_state = IBT_STATE_RTS;
1187         modify_attr.qp_trans = chan->ch_qp.qp_type;
1188 
1189         retval = ibt_modify_qp(chan, IBT_CEP_SET_STATE, &modify_attr, NULL);
1190         if (retval != IBT_SUCCESS) {
1191                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_unpause_sendq: "
1192                     "failed on chan %p: %d", chan, retval);
1193         }
1194         return (retval);
1195 }
1196 
1197 
1198 /*
1199  * Function:
1200  *      ibt_resize_queues
1201  * Input:
1202  *      chan            A previously allocated channel handle.
1203  *      flags           QP Flags
1204  *                              IBT_SEND_Q
1205  *                              IBT_RECV_Q
1206  *      request_sz      Requested new sizes.
1207  * Output:
1208  *      actual_sz       Returned actual sizes.
1209  * Returns:
1210  *      IBT_SUCCESS
1211  * Description:
1212  *      Resize the SendQ/RecvQ sizes of a channel. Can only be called on
1213  *      a previously opened channel.
1214  */
1215 ibt_status_t
1216 ibt_resize_queues(ibt_channel_hdl_t chan, ibt_qflags_t flags,
1217     ibt_queue_sizes_t *request_sz, ibt_queue_sizes_t *actual_sz)
1218 {
1219         ibt_cep_modify_flags_t  modify_flags = IBT_CEP_SET_STATE;
1220         ibt_qp_info_t           modify_attr;
1221         ibt_status_t            retval;
1222 
1223         IBTF_DPRINTF_L3(ibtf_qp, "ibt_resize_queues(%p, 0x%X, %p, %p)",
1224             chan, flags, request_sz, actual_sz);
1225 
1226         if ((flags & (IBT_SEND_Q | IBT_RECV_Q)) == 0)  {
1227                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_resize_queues: "
1228                     "Flags <0x%X> not set", flags);
1229                 return (IBT_INVALID_PARAM);
1230         }
1231 
1232         bzero(&modify_attr, sizeof (ibt_qp_info_t));
1233 
1234         modify_attr.qp_current_state = chan->ch_current_state;
1235         modify_attr.qp_trans = chan->ch_qp.qp_type;
1236         modify_attr.qp_state = chan->ch_current_state;
1237 
1238         if (flags & IBT_SEND_Q) {
1239                 modify_attr.qp_sq_sz = request_sz->qs_sq;
1240                 modify_flags |= IBT_CEP_SET_SQ_SIZE;
1241         }
1242 
1243         if (flags & IBT_RECV_Q) {
1244                 modify_attr.qp_rq_sz = request_sz->qs_rq;
1245                 modify_flags |= IBT_CEP_SET_RQ_SIZE;
1246         }
1247 
1248         retval = ibt_modify_qp(chan, modify_flags, &modify_attr, actual_sz);
1249         if (retval != IBT_SUCCESS) {
1250                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_resize_queues: "
1251                     "failed on QP %p: %d", chan, retval);
1252         }
1253 
1254         return (retval);
1255 }
1256 
1257 
1258 /*
1259  * Function:
1260  *      ibt_query_queues
1261  * Input:
1262  *      chan            A previously allocated channel handle.
1263  * Output:
1264  *      actual_sz       Returned actual sizes.
1265  * Returns:
1266  *      IBT_SUCCESS
1267  * Description:
1268  *      Query the SendQ/RecvQ sizes of a channel.
1269  */
1270 ibt_status_t
1271 ibt_query_queues(ibt_channel_hdl_t chan, ibt_queue_sizes_t *actual_sz)
1272 {
1273         ibt_status_t            retval;
1274         ibt_qp_query_attr_t     qp_query_attr;
1275 
1276         IBTF_DPRINTF_L3(ibtf_qp, "ibt_query_queues(%p)", chan);
1277 
1278         /* Perform Query QP and retrieve QP sizes. */
1279         retval = ibt_query_qp(chan, &qp_query_attr);
1280         if (retval != IBT_SUCCESS) {
1281                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_query_queues: "
1282                     "ibt_query_qp failed: qp %p: %d", chan, retval);
1283                 return (retval);
1284         }
1285 
1286         actual_sz->qs_sq = qp_query_attr.qp_info.qp_sq_sz;
1287         actual_sz->qs_rq = qp_query_attr.qp_info.qp_rq_sz;
1288         chan->ch_current_state = qp_query_attr.qp_info.qp_state;
1289 
1290         return (retval);
1291 }
1292 
1293 
1294 /*
1295  * Function:
1296  *      ibt_modify_rdma
1297  * Input:
1298  *      rc_chan         A previously allocated channel handle.
1299  *
1300  *      modify_flags    Bitwise "or" of any of the following:
1301  *                      IBT_CEP_SET_RDMA_R      Enable/Disable RDMA RD
1302  *                      IBT_CEP_SET_RDMA_W      Enable/Disable RDMA WR
1303  *                      IBT_CEP_SET_ATOMIC      Enable/Disable Atomics
1304  *
1305  *      flags           Channel End Point (CEP) Disable Flags (0 => enable).
1306  *                      IBT_CEP_NO_RDMA_RD      Disable incoming RDMA RD's
1307  *                      IBT_CEP_NO_RDMA_WR      Disable incoming RDMA WR's
1308  *                      IBT_CEP_NO_ATOMIC       Disable incoming Atomics.
1309  * Output:
1310  *      none.
1311  * Returns:
1312  *      IBT_SUCCESS
1313  *      IBT_QP_SRV_TYPE_INVALID
1314  *      IBT_CHAN_HDL_INVALID
1315  *      IBT_CHAN_ATOMICS_NOT_SUPPORTED
1316  *      IBT_CHAN_STATE_INVALID
1317  * Description:
1318  *      Enable/disable RDMA operations. To enable an operation clear the
1319  *      "disable" flag. Can call this function when the channel is in
1320  *      INIT, RTS or SQD states. If called in any other state
1321  *      IBT_CHAN_STATE_INVALID is returned. When the operation completes the
1322  *      channel state is left unchanged.
1323  */
1324 ibt_status_t
1325 ibt_modify_rdma(ibt_channel_hdl_t rc_chan,
1326     ibt_cep_modify_flags_t modify_flags, ibt_cep_flags_t flags)
1327 {
1328         ibt_status_t            retval;
1329         ibt_qp_info_t           modify_attr;
1330 
1331         IBTF_DPRINTF_L3(ibtf_qp, "ibt_modify_rdma(%p, 0x%x, 0x%x)",
1332             rc_chan, modify_flags, flags);
1333 
1334         if (rc_chan->ch_qp.qp_type != IBT_RC_SRV) {
1335                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_modify_rdma: "
1336                     "Invalid Channel type: 0x%X, Applicable only to RC Channel",
1337                     rc_chan->ch_qp.qp_type);
1338                 return (IBT_QP_SRV_TYPE_INVALID);
1339         }
1340 
1341         bzero(&modify_attr, sizeof (ibt_qp_info_t));
1342 
1343         /*
1344          * Can only call this function when the channel in INIT, RTS or SQD
1345          * states.
1346          */
1347         if ((rc_chan->ch_current_state != IBT_STATE_INIT) &&
1348             (rc_chan->ch_current_state != IBT_STATE_RTS) &&
1349             (rc_chan->ch_current_state != IBT_STATE_SQD)) {
1350                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_modify_rdma: Invalid Channel "
1351                     "state: 0x%X", rc_chan->ch_current_state);
1352                 return (IBT_CHAN_STATE_INVALID);
1353         }
1354 
1355         modify_attr.qp_state = modify_attr.qp_current_state =
1356             rc_chan->ch_current_state;
1357         modify_attr.qp_trans = rc_chan->ch_qp.qp_type;
1358         modify_attr.qp_flags = flags;
1359 
1360         modify_flags &= (IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
1361             IBT_CEP_SET_ATOMIC);
1362         modify_flags |= IBT_CEP_SET_STATE;
1363 
1364         retval = ibt_modify_qp(rc_chan, modify_flags, &modify_attr, NULL);
1365         if (retval != IBT_SUCCESS) {
1366                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_modify_rdma: "
1367                     "failed on chan %p: %d", rc_chan, retval);
1368         }
1369         return (retval);
1370 }
1371 
1372 
1373 /*
1374  * Function:
1375  *      ibt_set_rdma_resource
1376  * Input:
1377  *      chan            A previously allocated RC channel handle.
1378  *      modify_flags    Bitwise "or" of any of the following:
1379  *                      IBT_CEP_SET_RDMARA_OUT  Initiator depth (rdma_ra_out)
1380  *                      IBT_CEP_SET_RDMARA_IN   Responder Resources
1381  *                                              (rdma_ra_in)
1382  *      rdma_ra_out     Outgoing RDMA Reads/Atomics
1383  *      rdma_ra_in      Incoming RDMA Reads/Atomics
1384  * Output:
1385  *      none.
1386  * Returns:
1387  *      IBT_SUCCESS
1388  * Description:
1389  *      Change the number of resources to be used for incoming and outgoing
1390  *      RDMA reads & Atomics. Can only be called on a previously opened
1391  *      RC channel.  Can only be called on a paused channel, and this will
1392  *      un-pause that channel.
1393  */
1394 ibt_status_t
1395 ibt_set_rdma_resource(ibt_channel_hdl_t chan,
1396     ibt_cep_modify_flags_t modify_flags, uint8_t rdma_ra_out,
1397     uint8_t resp_rdma_ra_out)
1398 {
1399         ibt_qp_info_t           modify_attr;
1400         ibt_status_t            retval;
1401 
1402         IBTF_DPRINTF_L3(ibtf_qp, "ibt_set_rdma_resource(%p, 0x%x, %d, %d)",
1403             chan, modify_flags, rdma_ra_out, resp_rdma_ra_out);
1404 
1405         if (chan->ch_qp.qp_type != IBT_RC_SRV) {
1406                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_set_rdma_resource: "
1407                     "Invalid Channel type: 0x%X, Applicable only to RC Channel",
1408                     chan->ch_qp.qp_type);
1409                 return (IBT_CHAN_SRV_TYPE_INVALID);
1410         }
1411 
1412         bzero(&modify_attr, sizeof (ibt_qp_info_t));
1413 
1414         modify_attr.qp_trans = chan->ch_qp.qp_type;
1415         modify_attr.qp_state = IBT_STATE_SQD;
1416 
1417         modify_attr.qp_transport.rc.rc_rdma_ra_out = rdma_ra_out;
1418         modify_attr.qp_transport.rc.rc_rdma_ra_in = resp_rdma_ra_out;
1419         modify_flags &= (IBT_CEP_SET_RDMARA_OUT | IBT_CEP_SET_RDMARA_IN);
1420         modify_flags |= IBT_CEP_SET_STATE;
1421 
1422         retval = ibt_modify_qp(chan, modify_flags, &modify_attr, NULL);
1423         if (retval != IBT_SUCCESS) {
1424                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_set_rdma_resource: "
1425                     "failed on chan %p: %d", chan, retval);
1426         }
1427         return (retval);
1428 }
1429 
1430 
1431 /*
1432  * Function:
1433  *      ibt_change_port
1434  * Input:
1435  *      rc_chan         A previously allocated RC channel handle.
1436  *      port_num        New HCA port.
1437  * Output:
1438  *      none.
1439  * Returns:
1440  *      IBT_SUCCESS
1441  * Description:
1442  *      Change the primary physical port of a channel. (This is done only if
1443  *      HCA supports this capability).
1444  */
1445 ibt_status_t
1446 ibt_change_port(ibt_channel_hdl_t chan, uint8_t port_num)
1447 {
1448         ibt_cep_modify_flags_t  modify_flags;
1449         ibt_qp_info_t           modify_attr;
1450         ibt_status_t            retval;
1451 
1452         IBTF_DPRINTF_L3(ibtf_qp, "ibt_change_port(%p, %d)", chan, port_num);
1453 
1454         if (chan->ch_qp.qp_type != IBT_RC_SRV) {
1455                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_change_port: "
1456                     "Invalid Channel type: 0x%X, Applicable only to RC Channel",
1457                     chan->ch_qp.qp_type);
1458                 return (IBT_CHAN_SRV_TYPE_INVALID);
1459         }
1460         bzero(&modify_attr, sizeof (ibt_qp_info_t));
1461 
1462         modify_attr.qp_state = IBT_STATE_SQD;
1463         modify_attr.qp_trans = chan->ch_qp.qp_type;
1464         modify_attr.qp_transport.rc.rc_path.cep_hca_port_num = port_num;
1465 
1466         modify_flags = IBT_CEP_SET_STATE | IBT_CEP_SET_PORT;
1467 
1468         retval = ibt_modify_qp(chan, modify_flags, &modify_attr, NULL);
1469         if (retval != IBT_SUCCESS) {
1470                 IBTF_DPRINTF_L2(ibtf_qp, "ibt_change_port: "
1471                     "failed on chan %p: %d", chan, retval);
1472         }
1473         return (retval);
1474 }
1475 
1476 
1477 void
1478 ibtl_init_cep_states(void)
1479 {
1480         int     index;
1481         int     ibt_nstate_inits;
1482 
1483         IBTF_DPRINTF_L3(ibtf_qp, "ibtl_init_cep_states()");
1484 
1485         ibt_nstate_inits = sizeof (ibt_cep_next_state_inits) /
1486             sizeof (ibt_cep_next_state_inits[0]);
1487 
1488         /*
1489          * Initialize CEP next state table, using an indirect lookup table so
1490          * that this code isn't dependent on the ibt_cep_state_t enum values.
1491          */
1492         for (index = 0; index < ibt_nstate_inits; index++) {
1493                 ibt_cep_state_t state;
1494 
1495                 state = ibt_cep_next_state_inits[index].current_state;
1496 
1497                 ibt_cep_next_state[state].next_state =
1498                     ibt_cep_next_state_inits[index].next_state;
1499 
1500                 ibt_cep_next_state[state].modify_flags =
1501                     ibt_cep_next_state_inits[index].modify_flags;
1502         }
1503 }