Logo Search packages:      
Sourcecode: dapl version File versions  Download package

dapl_ib_qp.c

/*
 * This Software is licensed under one of the following licenses:
 *
 * 1) under the terms of the "Common Public License 1.0" a copy of which is
 *    available from the Open Source Initiative, see
 *    http://www.opensource.org/licenses/cpl.php.
 *
 * 2) under the terms of the "The BSD License" a copy of which is
 *    available from the Open Source Initiative, see
 *    http://www.opensource.org/licenses/bsd-license.php.
 *
 * 3) under the terms of the "GNU General Public License (GPL) Version 2" a
 *    copy of which is available from the Open Source Initiative, see
 *    http://www.opensource.org/licenses/gpl-license.php.
 *
 * Licensee has the right to choose one of the above licenses.
 *
 * Redistributions of source code must retain the above copyright
 * notice and one of the license notices.
 *
 * Redistributions in binary form must reproduce both the above copyright
 * notice, one of the license notices in the documentation
 * and/or other materials provided with the distribution.
 */

/**********************************************************************
 *
 * MODULE: dapl_ib_qp.c
 *
 * PURPOSE: QP routines for access to ofa rdma verbs 
 *
 * $Id: $
 **********************************************************************/

#include "dapl.h"
#include "dapl_adapter_util.h"

/*
 * dapl_ib_qp_alloc
 *
 * Alloc a QP
 *
 * Input:
 *    *ep_ptr           pointer to EP INFO
 *    ib_hca_handle     provider HCA handle
 *    ib_pd_handle      provider protection domain handle
 *    cq_recv           provider recv CQ handle
 *    cq_send           provider send CQ handle
 *
 * Output:
 *    none
 *
 * Returns:
 *    DAT_SUCCESS
 *    DAT_INSUFFICIENT_RESOURCES
 *    DAT_INTERNAL_ERROR
 *
 */
DAT_RETURN
dapls_ib_qp_alloc(IN DAPL_IA * ia_ptr,
              IN DAPL_EP * ep_ptr, IN DAPL_EP * ep_ctx_ptr)
{
      DAT_EP_ATTR *attr;
      DAPL_EVD *rcv_evd, *req_evd;
      ib_cq_handle_t rcv_cq, req_cq;
      ib_pd_handle_t ib_pd_handle;
      struct ibv_qp_init_attr qp_create;

      dapl_dbg_log(DAPL_DBG_TYPE_EP,
                 " qp_alloc: ia_ptr %p ep_ptr %p ep_ctx_ptr %p\n",
                 ia_ptr, ep_ptr, ep_ctx_ptr);

      attr = &ep_ptr->param.ep_attr;
      ib_pd_handle = ((DAPL_PZ *) ep_ptr->param.pz_handle)->pd_handle;
      rcv_evd = (DAPL_EVD *) ep_ptr->param.recv_evd_handle;
      req_evd = (DAPL_EVD *) ep_ptr->param.request_evd_handle;

      /* 
       * DAT allows usage model of EP's with no EVD's but IB does not. 
       * Create a CQ with zero entries under the covers to support and 
       * catch any invalid posting. 
       */
      if (rcv_evd != DAT_HANDLE_NULL)
            rcv_cq = rcv_evd->ib_cq_handle;
      else if (!ia_ptr->hca_ptr->ib_trans.ib_cq_empty)
            rcv_cq = ia_ptr->hca_ptr->ib_trans.ib_cq_empty;
      else {
            struct ibv_comp_channel *channel =
                ia_ptr->hca_ptr->ib_trans.ib_cq;
#ifdef CQ_WAIT_OBJECT
            if (rcv_evd->cq_wait_obj_handle)
                  channel = rcv_evd->cq_wait_obj_handle;
#endif
            /* Call IB verbs to create CQ */
            rcv_cq = ibv_create_cq(ia_ptr->hca_ptr->ib_hca_handle,
                               0, NULL, channel, 0);

            if (rcv_cq == IB_INVALID_HANDLE)
                  return (dapl_convert_errno(ENOMEM, "create_cq"));

            ia_ptr->hca_ptr->ib_trans.ib_cq_empty = rcv_cq;
      }
      if (req_evd != DAT_HANDLE_NULL)
            req_cq = req_evd->ib_cq_handle;
      else
            req_cq = ia_ptr->hca_ptr->ib_trans.ib_cq_empty;

      /* Setup attributes and create qp */
      dapl_os_memzero((void *)&qp_create, sizeof(qp_create));
      qp_create.send_cq = req_cq;
      qp_create.cap.max_send_wr = attr->max_request_dtos;
      qp_create.cap.max_send_sge = attr->max_request_iov;
      qp_create.cap.max_inline_data =
          ia_ptr->hca_ptr->ib_trans.max_inline_send;
      qp_create.qp_type = IBV_QPT_RC;

#ifdef DAT_EXTENSIONS
      if (attr->service_type == DAT_IB_SERVICE_TYPE_UD) {
            qp_create.qp_type = IBV_QPT_UD;
            if (attr->max_message_size >
                (128 << ia_ptr->hca_ptr->ib_trans.mtu)) {
                  return (DAT_INVALID_PARAMETER | DAT_INVALID_ARG6);
            }
      }
#endif
      qp_create.qp_context = (void *)ep_ptr;

      /* ibv assumes rcv_cq is never NULL, set to req_cq */
      if (rcv_cq == NULL) {
            qp_create.recv_cq = req_cq;
            qp_create.cap.max_recv_wr = 0;
            qp_create.cap.max_recv_sge = 0;
      } else {
            qp_create.recv_cq = rcv_cq;
            qp_create.cap.max_recv_wr = attr->max_recv_dtos;
            qp_create.cap.max_recv_sge = attr->max_recv_iov;
      }

      ep_ptr->qp_handle = ibv_create_qp(ib_pd_handle, &qp_create);
      if (!ep_ptr->qp_handle)
            return (dapl_convert_errno(ENOMEM, "create_qp"));

      dapl_dbg_log(DAPL_DBG_TYPE_EP,
                 " qp_alloc: qpn %p sq %d,%d rq %d,%d\n",
                 ep_ptr->qp_handle->qp_num,
                 qp_create.cap.max_send_wr, qp_create.cap.max_send_sge,
                 qp_create.cap.max_recv_wr, qp_create.cap.max_recv_sge);

      /* Setup QP attributes for INIT state on the way out */
      if (dapls_modify_qp_state(ep_ptr->qp_handle,
                          IBV_QPS_INIT, NULL) != DAT_SUCCESS) {
            ibv_destroy_qp(ep_ptr->qp_handle);
            ep_ptr->qp_handle = IB_INVALID_HANDLE;
            return DAT_INTERNAL_ERROR;
      }

      return DAT_SUCCESS;
}

/*
 * dapl_ib_qp_free
 *
 * Free a QP
 *
 * Input:
 *    ia_handle   IA handle
 *    *ep_ptr           pointer to EP INFO
 *
 * Output:
 *    none
 *
 * Returns:
 *    DAT_SUCCESS
 *  dapl_convert_errno
 *
 */
DAT_RETURN dapls_ib_qp_free(IN DAPL_IA * ia_ptr, IN DAPL_EP * ep_ptr)
{
      dapl_dbg_log(DAPL_DBG_TYPE_EP, " qp_free:  ep_ptr %p qp %p\n",
                 ep_ptr, ep_ptr->qp_handle);

      if (ep_ptr->qp_handle != IB_INVALID_HANDLE) {
            /* force error state to flush queue, then destroy */
            dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_ERR, NULL);

            if (ibv_destroy_qp(ep_ptr->qp_handle))
                  return (dapl_convert_errno(errno, "destroy_qp"));

            ep_ptr->qp_handle = IB_INVALID_HANDLE;
      }

      return DAT_SUCCESS;
}

/*
 * dapl_ib_qp_modify
 *
 * Set the QP to the parameters specified in an EP_PARAM
 *
 * The EP_PARAM structure that is provided has been
 * sanitized such that only non-zero values are valid.
 *
 * Input:
 *    ib_hca_handle           HCA handle
 *    qp_handle         QP handle
 *    ep_attr                   Sanitized EP Params
 *
 * Output:
 *    none
 *
 * Returns:
 *    DAT_SUCCESS
 *    DAT_INSUFFICIENT_RESOURCES
 *    DAT_INVALID_PARAMETER
 *
 */
DAT_RETURN
dapls_ib_qp_modify(IN DAPL_IA * ia_ptr,
               IN DAPL_EP * ep_ptr, IN DAT_EP_ATTR * attr)
{
      struct ibv_qp_attr qp_attr;

      if (ep_ptr->qp_handle == IB_INVALID_HANDLE)
            return DAT_INVALID_PARAMETER;

      /* 
       * EP state, qp_handle state should be an indication
       * of current state but the only way to be sure is with
       * a user mode ibv_query_qp call which is NOT available 
       */

      /* move to error state if necessary */
      if ((ep_ptr->qp_state == IB_QP_STATE_ERROR) &&
          (ep_ptr->qp_handle->state != IBV_QPS_ERR)) {
            return (dapls_modify_qp_state(ep_ptr->qp_handle,
                                    IBV_QPS_ERR, NULL));
      }

      /*
       * Check if we have the right qp_state to modify attributes
       */
      if ((ep_ptr->qp_handle->state != IBV_QPS_RTR) &&
          (ep_ptr->qp_handle->state != IBV_QPS_RTS))
            return DAT_INVALID_STATE;

      /* Adjust to current EP attributes */
      dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));
      qp_attr.cap.max_send_wr = attr->max_request_dtos;
      qp_attr.cap.max_recv_wr = attr->max_recv_dtos;
      qp_attr.cap.max_send_sge = attr->max_request_iov;
      qp_attr.cap.max_recv_sge = attr->max_recv_iov;

      dapl_dbg_log(DAPL_DBG_TYPE_EP,
                 "modify_qp: qp %p sq %d,%d, rq %d,%d\n",
                 ep_ptr->qp_handle,
                 qp_attr.cap.max_send_wr, qp_attr.cap.max_send_sge,
                 qp_attr.cap.max_recv_wr, qp_attr.cap.max_recv_sge);

      if (ibv_modify_qp(ep_ptr->qp_handle, &qp_attr, IBV_QP_CAP)) {
            dapl_dbg_log(DAPL_DBG_TYPE_ERR,
                       "modify_qp: modify ep %p qp %p failed\n",
                       ep_ptr, ep_ptr->qp_handle);
            return (dapl_convert_errno(errno, "modify_qp_state"));
      }

      return DAT_SUCCESS;
}

/*
 * dapls_ib_reinit_ep
 *
 * Move the QP to INIT state again.
 *
 * Input:
 *    ep_ptr            DAPL_EP
 *
 * Output:
 *    none
 *
 * Returns:
 *    void
 *
 */
#if defined(_WIN32) || defined(_WIN64)
void dapls_ib_reinit_ep(IN DAPL_EP * ep_ptr)
{
      /* work around bug in low level driver - 3/24/09 */
      /* RTS -> RESET -> INIT -> ERROR QP transition crashes system */
      if (ep_ptr->qp_handle != IB_INVALID_HANDLE) {
            dapls_ib_qp_free(ep_ptr->header.owner_ia, ep_ptr);
            dapls_ib_qp_alloc(ep_ptr->header.owner_ia, ep_ptr, ep_ptr);
      }
}
#else                   // _WIN32 || _WIN64
void dapls_ib_reinit_ep(IN DAPL_EP * ep_ptr)
{
      if (ep_ptr->qp_handle != IB_INVALID_HANDLE &&
          ep_ptr->qp_handle->qp_type != IBV_QPT_UD) {
            /* move to RESET state and then to INIT */
            dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_RESET, 0);
            dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_INIT, 0);
      }
}
#endif                        // _WIN32 || _WIN64

/* 
 * Generic QP modify for init, reset, error, RTS, RTR
 * For UD, create_ah on RTR, qkey on INIT
 */
DAT_RETURN
dapls_modify_qp_state(IN ib_qp_handle_t qp_handle,
                  IN ib_qp_state_t qp_state, IN struct ib_cm_handle *cm_ptr)
{
      struct ibv_qp_attr qp_attr;
      enum ibv_qp_attr_mask mask = IBV_QP_STATE;
      DAPL_EP *ep_ptr = (DAPL_EP *) qp_handle->qp_context;
      DAPL_IA *ia_ptr = ep_ptr->header.owner_ia;
      ib_qp_cm_t *qp_cm = &cm_ptr->dst;
      int ret;

      dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));
      qp_attr.qp_state = qp_state;
      switch (qp_state) {
            /* additional attributes with RTR and RTS */
      case IBV_QPS_RTR:
            {
                  dapl_dbg_log(DAPL_DBG_TYPE_EP,
                             " QPS_RTR: type %d state %d qpn %x lid %x"
                             " port %x ep %p qp_state %d\n",
                             qp_handle->qp_type, qp_handle->qp_type,
                             qp_cm->qpn, qp_cm->lid, qp_cm->port,
                             ep_ptr, ep_ptr->qp_state);

                  mask |= IBV_QP_AV |
                      IBV_QP_PATH_MTU |
                      IBV_QP_DEST_QPN |
                      IBV_QP_RQ_PSN |
                      IBV_QP_MAX_DEST_RD_ATOMIC | IBV_QP_MIN_RNR_TIMER;

                  qp_attr.dest_qp_num = qp_cm->qpn;
                  qp_attr.rq_psn = 1;
                  qp_attr.path_mtu = ia_ptr->hca_ptr->ib_trans.mtu;
                  qp_attr.max_dest_rd_atomic =
                      ep_ptr->param.ep_attr.max_rdma_read_out;
                  qp_attr.min_rnr_timer =
                      ia_ptr->hca_ptr->ib_trans.rnr_timer;

                  /* address handle. RC and UD */
                  qp_attr.ah_attr.dlid = qp_cm->lid;
                  if (ia_ptr->hca_ptr->ib_trans.global) {
                        qp_attr.ah_attr.is_global = 1;
                        qp_attr.ah_attr.grh.dgid = qp_cm->gid;
                        qp_attr.ah_attr.grh.hop_limit =
                            ia_ptr->hca_ptr->ib_trans.hop_limit;
                        qp_attr.ah_attr.grh.traffic_class =
                            ia_ptr->hca_ptr->ib_trans.tclass;
                  }
                  qp_attr.ah_attr.sl = 0;
                  qp_attr.ah_attr.src_path_bits = 0;
                  qp_attr.ah_attr.port_num = ia_ptr->hca_ptr->port_num;
#ifdef DAT_EXTENSIONS
                  /* UD: create AH for remote side */
                  if (qp_handle->qp_type == IBV_QPT_UD) {
                        ib_pd_handle_t pz;
                        pz = ((DAPL_PZ *)
                              ep_ptr->param.pz_handle)->pd_handle;
                        mask = IBV_QP_STATE;
                        cm_ptr->ah = ibv_create_ah(pz,
                                             &qp_attr.ah_attr);
                        if (!cm_ptr->ah)
                              return (dapl_convert_errno(errno,
                                                   "ibv_ah"));

                        /* already RTR, multi remote AH's on QP */
                        if (ep_ptr->qp_state == IBV_QPS_RTR ||
                            ep_ptr->qp_state == IBV_QPS_RTS)
                              return DAT_SUCCESS;
                  }
#endif
                  break;
            }
      case IBV_QPS_RTS:
            {
                  /* RC only */
                  if (qp_handle->qp_type == IBV_QPT_RC) {
                        mask |= IBV_QP_SQ_PSN |
                            IBV_QP_TIMEOUT |
                            IBV_QP_RETRY_CNT |
                            IBV_QP_RNR_RETRY | IBV_QP_MAX_QP_RD_ATOMIC;
                        qp_attr.timeout =
                            ia_ptr->hca_ptr->ib_trans.ack_timer;
                        qp_attr.retry_cnt =
                            ia_ptr->hca_ptr->ib_trans.ack_retry;
                        qp_attr.rnr_retry =
                            ia_ptr->hca_ptr->ib_trans.rnr_retry;
                        qp_attr.max_rd_atomic =
                            ep_ptr->param.ep_attr.max_rdma_read_out;
                  }
                  /* RC and UD */
                  qp_attr.qp_state = IBV_QPS_RTS;
                  qp_attr.sq_psn = 1;

                  dapl_dbg_log(DAPL_DBG_TYPE_EP,
                             " QPS_RTS: psn %x rd_atomic %d ack %d "
                             " retry %d rnr_retry %d ep %p qp_state %d\n",
                             qp_attr.sq_psn, qp_attr.max_rd_atomic,
                             qp_attr.timeout, qp_attr.retry_cnt,
                             qp_attr.rnr_retry, ep_ptr,
                             ep_ptr->qp_state);
#ifdef DAT_EXTENSIONS
                  if (qp_handle->qp_type == IBV_QPT_UD) {
                        /* already RTS, multi remote AH's on QP */
                        if (ep_ptr->qp_state == IBV_QPS_RTS)
                              return DAT_SUCCESS;
                        else
                              mask = IBV_QP_STATE | IBV_QP_SQ_PSN;
                  }
#endif
                  break;
            }
      case IBV_QPS_INIT:
            {
                  mask |= IBV_QP_PKEY_INDEX | IBV_QP_PORT;
                  if (qp_handle->qp_type == IBV_QPT_RC) {
                        mask |= IBV_QP_ACCESS_FLAGS;
                        qp_attr.qp_access_flags =
                            IBV_ACCESS_LOCAL_WRITE |
                            IBV_ACCESS_REMOTE_WRITE |
                            IBV_ACCESS_REMOTE_READ |
                            IBV_ACCESS_REMOTE_ATOMIC |
                            IBV_ACCESS_MW_BIND;
                  }
#ifdef DAT_EXTENSIONS
                  if (qp_handle->qp_type == IBV_QPT_UD) {
                        /* already INIT, multi remote AH's on QP */
                        if (ep_ptr->qp_state == IBV_QPS_INIT)
                              return DAT_SUCCESS;
                        mask |= IBV_QP_QKEY;
                        qp_attr.qkey = SCM_UD_QKEY;
                  }
#endif
                  qp_attr.pkey_index = 0;
                  qp_attr.port_num = ia_ptr->hca_ptr->port_num;

                  dapl_dbg_log(DAPL_DBG_TYPE_EP,
                             " QPS_INIT: pi %x port %x acc %x qkey 0x%x\n",
                             qp_attr.pkey_index, qp_attr.port_num,
                             qp_attr.qp_access_flags, qp_attr.qkey);
                  break;
            }
      default:
            break;

      }

      ret = ibv_modify_qp(qp_handle, &qp_attr, mask);
      if (ret == 0) {
            ep_ptr->qp_state = qp_state;
            return DAT_SUCCESS;
      } else {
            return (dapl_convert_errno(errno, "modify_qp_state"));
      }
}

/*
 * Local variables:
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 8
 * End:
 */

Generated by  Doxygen 1.6.0   Back to index