dapl/cma: fix referencing freed address
authorshefty <shefty@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Fri, 29 Jan 2010 05:05:03 +0000 (05:05 +0000)
committershefty <shefty@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Fri, 29 Jan 2010 05:05:03 +0000 (05:05 +0000)
From: Sean Hefty <sean.hefty@intel.com>

DAPL uses a pointer to reference the local and remote addresses
of an endpoint.  It expects that those addresses are located
in memory that is always accessible.  Typically, for the local
address, the pointer references the address stored with the DAPL
HCA device.  However, for the cma provider, it changes this pointer
to reference the address stored with the rdma_cm_id.

This causes a problem when that endpoint is connected on the
passive side of a connection.  When connect requests are given
to DAPL, a new rdma_cm_id is associated with the request.  The
DAPL code replaces the current rdma_cm_id associated with a
user's endpoint with the new rdma_cm_id.  The old rdma_cm_id is
then deleted.  But the endpoint's local address pointer still
references the address stored with the old rdma_cm_id.  The
result is that any reference to the address will access freed
memory.

Fix this by keeping the local address pointer always pointing
to the address associated with the DAPL HCA device.  This is about
the best that can be done given the DAPL interface design.

Signed-off-by: Sean Hefty <sean.hefty@intel.com>
git-svn-id: svn://openib.tc.cornell.edu/gen1/trunk@2687 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

ulp/dapl2/dapl/openib_common/qp.c

index 143098e..c2b5c69 100644 (file)
-/*
- * 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.
- */
-#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;
-#ifdef _OPENIB_CMA_
-       dp_ib_cm_handle_t conn;
-#endif
-       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;
-
-               channel = ibv_create_comp_channel(ia_ptr->hca_ptr->ib_hca_handle);
-               if (!channel)
-                       return (dapl_convert_errno(ENOMEM, "create_cq"));
-                 
-               /* 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) {
-                       ibv_destroy_comp_channel(channel);
-                       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;
-
-       /* 
-        * IMPLEMENTATION NOTE:
-        * uDAPL allows consumers to post buffers on the EP after creation
-        * and before a connect request (outbound and inbound). This forces
-        * a binding to a device during the hca_open call and requires the
-        * consumer to predetermine which device to listen on or connect from.
-        * This restriction eliminates any option of listening or connecting 
-        * over multiple devices. uDAPL should add API's to resolve addresses 
-        * and bind to the device at the approriate time (before connect 
-        * and after CR arrives). Discovery should happen at connection time 
-        * based on addressing and not on static configuration during open.
-        */
-
-#ifdef _OPENIB_CMA_
-       /* Allocate CM and initialize lock */
-       if ((conn = dapls_ib_cm_create(ep_ptr)) == NULL)
-               return (dapl_convert_errno(ENOMEM, "create_cq"));
-
-       /* open identifies the local device; per DAT specification */
-       if (rdma_bind_addr(conn->cm_id,
-                          (struct sockaddr *)&ia_ptr->hca_ptr->hca_address))
-               return (dapl_convert_errno(EAFNOSUPPORT, "create_cq"));
-#endif
-       /* 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;
-       qp_create.qp_context = (void *)ep_ptr;
-
-#ifdef DAT_EXTENSIONS 
-       if (attr->service_type == DAT_IB_SERVICE_TYPE_UD) {
-#ifdef _OPENIB_CMA_
-               return (DAT_NOT_IMPLEMENTED);
-#endif
-               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
-       
-       /* 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;
-       }
-
-#ifdef _OPENIB_CMA_
-       if (rdma_create_qp(conn->cm_id, ib_pd_handle, &qp_create)) {
-               dapls_ib_cm_free(conn, ep_ptr);
-               return (dapl_convert_errno(errno, "create_qp"));
-       }
-       ep_ptr->qp_handle = conn->cm_id->qp;
-       ep_ptr->cm_handle = conn;
-       ep_ptr->qp_state = IBV_QPS_INIT;
-               
-       /* setup up ep->param to reference the bound local address and port */
-       ep_ptr->param.local_ia_address_ptr = 
-               &conn->cm_id->route.addr.src_addr;
-       ep_ptr->param.local_port_qual = rdma_get_src_port(conn->cm_id);
-#else
-       ep_ptr->qp_handle = ibv_create_qp(ib_pd_handle, &qp_create);
-       if (!ep_ptr->qp_handle)
-               return (dapl_convert_errno(ENOMEM, "create_qp"));
-               
-       /* Setup QP attributes for INIT state on the way out */
-       if (dapls_modify_qp_state(ep_ptr->qp_handle,
-                                 IBV_QPS_INIT, 0, 0, 0) != DAT_SUCCESS) {
-               ibv_destroy_qp(ep_ptr->qp_handle);
-               ep_ptr->qp_handle = IB_INVALID_HANDLE;
-               return DAT_INTERNAL_ERROR;
-       }
-#endif
-       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);
-
-       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->cm_handle != NULL) {
-               dapls_ib_cm_free(ep_ptr->cm_handle, ep_ptr);
-       }
-       
-       if (ep_ptr->qp_handle != NULL) {
-               /* force error state to flush queue, then destroy */
-               dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_ERR, 0,0,0);
-
-               if (ibv_destroy_qp(ep_ptr->qp_handle))
-                       return (dapl_convert_errno(errno, "destroy_qp"));
-
-               ep_ptr->qp_handle = NULL;
-       }
-
-#ifdef DAT_EXTENSIONS
-       /* UD endpoints can have many CR associations and will not
-        * set ep->cm_handle. Call provider with cm_ptr null to incidate
-        * UD type multi CR's for this EP. It will parse internal list
-        * and cleanup all associations.
-        */
-       if (ep_ptr->param.ep_attr.service_type == DAT_IB_SERVICE_TYPE_UD) 
-               dapls_ib_cm_free(NULL, ep_ptr);
-#endif
-
-       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, 0, 0, 0));
-       }
-
-       /*
-        * 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) || defined(_OPENIB_CMA_)
-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,0,0);
-               dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_INIT,0,0,0);
-       }
-}
-#endif                         // _WIN32 || _WIN64
-
-/* 
- * Generic QP modify for init, reset, error, RTS, RTR
- * For UD, create_ah on RTR, qkey on INIT
- * CM msg provides QP attributes, info in network order
- */
-DAT_RETURN
-dapls_modify_qp_state(IN ib_qp_handle_t                qp_handle,
-                     IN ib_qp_state_t          qp_state, 
-                     IN uint32_t               qpn,
-                     IN uint16_t               lid,
-                     IN ib_gid_handle_t        gid)
-{
-       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;
-       int ret;
-
-       dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));
-       qp_attr.qp_state = qp_state;
-       
-       switch (qp_state) {
-       case IBV_QPS_RTR:
-               dapl_dbg_log(DAPL_DBG_TYPE_EP,
-                               " QPS_RTR: type %d qpn 0x%x lid 0x%x"
-                               " port %d ep %p qp_state %d \n",
-                               qp_handle->qp_type, 
-                               ntohl(qpn), ntohs(lid), 
-                               ia_ptr->hca_ptr->port_num,
-                               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 = ntohl(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 = ntohs(lid);
-               if (ia_ptr->hca_ptr->ib_trans.global) {
-                       qp_attr.ah_attr.is_global = 1;
-                       qp_attr.ah_attr.grh.dgid.global.subnet_prefix = 
-                               ntohll(gid->global.subnet_prefix);
-                       qp_attr.ah_attr.grh.dgid.global.interface_id = 
-                               ntohll(gid->global.interface_id);
-                       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;
-
-               /* UD: already in RTR, RTS state */
-               if (qp_handle->qp_type == IBV_QPT_UD) {
-                       mask = IBV_QP_STATE;
-                       if (ep_ptr->qp_state == IBV_QPS_RTR ||
-                               ep_ptr->qp_state == IBV_QPS_RTS)
-                               return DAT_SUCCESS;
-               }
-               break;
-       case IBV_QPS_RTS:
-               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);
-
-               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;
-               }
-               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;
-               }
-
-               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 = DAT_UD_QKEY;
-               }
-
-               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"));
-       }
-}
-
-/* Modify UD type QP from init, rtr, rts, info network order */
-DAT_RETURN 
-dapls_modify_qp_ud(IN DAPL_HCA *hca, IN ib_qp_handle_t qp)
-{
-       struct ibv_qp_attr qp_attr;
-
-       /* modify QP, setup and prepost buffers */
-       dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));
-       qp_attr.qp_state = IBV_QPS_INIT;
-        qp_attr.pkey_index = 0;
-        qp_attr.port_num = hca->port_num;
-        qp_attr.qkey = DAT_UD_QKEY;
-       if (ibv_modify_qp(qp, &qp_attr, 
-                         IBV_QP_STATE          |
-                         IBV_QP_PKEY_INDEX     |
-                          IBV_QP_PORT          |
-                          IBV_QP_QKEY)) {
-               dapl_log(DAPL_DBG_TYPE_ERR,
-                       " modify_ud_qp INIT: ERR %s\n", strerror(errno));
-               return (dapl_convert_errno(errno, "modify_qp"));
-       }
-       dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));
-       qp_attr.qp_state = IBV_QPS_RTR;
-       if (ibv_modify_qp(qp, &qp_attr,IBV_QP_STATE)) {
-               dapl_log(DAPL_DBG_TYPE_ERR, 
-                       " modify_ud_qp RTR: ERR %s\n", strerror(errno));
-               return (dapl_convert_errno(errno, "modify_qp"));
-       }
-       dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));
-       qp_attr.qp_state = IBV_QPS_RTS;
-       qp_attr.sq_psn = 1;
-       if (ibv_modify_qp(qp, &qp_attr, 
-                         IBV_QP_STATE | IBV_QP_SQ_PSN)) {
-               dapl_log(DAPL_DBG_TYPE_ERR,
-                       " modify_ud_qp RTS: ERR %s\n", strerror(errno));
-               return (dapl_convert_errno(errno, "modify_qp"));
-       }
-       return DAT_SUCCESS;
-}
-
-/* Create address handle for remote QP, info in network order */
-ib_ah_handle_t 
-dapls_create_ah(IN DAPL_HCA            *hca,
-               IN ib_pd_handle_t       pd,
-               IN ib_qp_handle_t       qp,
-               IN uint16_t             lid,
-               IN ib_gid_handle_t      gid)
-{
-       struct ibv_qp_attr qp_attr;
-       ib_ah_handle_t  ah;
-
-       if (qp->qp_type != IBV_QPT_UD)
-               return NULL;
-
-       dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));
-       qp_attr.qp_state = IBV_QP_STATE;
-
-       /* address handle. RC and UD */
-       qp_attr.ah_attr.dlid = ntohs(lid);
-       if (gid != NULL) {
-               dapl_log(DAPL_DBG_TYPE_CM, "dapl_create_ah: with GID\n");
-               qp_attr.ah_attr.is_global = 1;
-               qp_attr.ah_attr.grh.dgid.global.subnet_prefix = 
-                               ntohll(gid->global.subnet_prefix);
-               qp_attr.ah_attr.grh.dgid.global.interface_id = 
-                               ntohll(gid->global.interface_id);
-               qp_attr.ah_attr.grh.hop_limit = hca->ib_trans.hop_limit;
-               qp_attr.ah_attr.grh.traffic_class = hca->ib_trans.tclass;
-       }
-       qp_attr.ah_attr.sl = 0;
-       qp_attr.ah_attr.src_path_bits = 0;
-       qp_attr.ah_attr.port_num = hca->port_num;
-
-       dapl_log(DAPL_DBG_TYPE_CM, 
-                       " dapls_create_ah: port %x lid %x pd %p ctx %p handle 0x%x\n", 
-                       hca->port_num,qp_attr.ah_attr.dlid, pd, pd->context, pd->handle);
-
-       /* UD: create AH for remote side */
-       ah = ibv_create_ah(pd, &qp_attr.ah_attr);
-       if (!ah) {
-               dapl_log(DAPL_DBG_TYPE_ERR,
-                       " create_ah: ERR %s\n", strerror(errno));
-               return NULL;
-       }
-
-       dapl_log(DAPL_DBG_TYPE_CM, 
-                       " dapls_create_ah: AH %p for lid %x\n", 
-                       ah, qp_attr.ah_attr.dlid);
-
-       return ah;
-}
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 8
- * End:
- */
+/*\r
+ * This Software is licensed under one of the following licenses:\r
+ *\r
+ * 1) under the terms of the "Common Public License 1.0" a copy of which is\r
+ *    available from the Open Source Initiative, see\r
+ *    http://www.opensource.org/licenses/cpl.php.\r
+ *\r
+ * 2) under the terms of the "The BSD License" a copy of which is\r
+ *    available from the Open Source Initiative, see\r
+ *    http://www.opensource.org/licenses/bsd-license.php.\r
+ *\r
+ * 3) under the terms of the "GNU General Public License (GPL) Version 2" a\r
+ *    copy of which is available from the Open Source Initiative, see\r
+ *    http://www.opensource.org/licenses/gpl-license.php.\r
+ *\r
+ * Licensee has the right to choose one of the above licenses.\r
+ *\r
+ * Redistributions of source code must retain the above copyright\r
+ * notice and one of the license notices.\r
+ *\r
+ * Redistributions in binary form must reproduce both the above copyright\r
+ * notice, one of the license notices in the documentation\r
+ * and/or other materials provided with the distribution.\r
+ */\r
+#include "dapl.h"\r
+#include "dapl_adapter_util.h"\r
+\r
+/*\r
+ * dapl_ib_qp_alloc\r
+ *\r
+ * Alloc a QP\r
+ *\r
+ * Input:\r
+ *     *ep_ptr         pointer to EP INFO\r
+ *     ib_hca_handle   provider HCA handle\r
+ *     ib_pd_handle    provider protection domain handle\r
+ *     cq_recv         provider recv CQ handle\r
+ *     cq_send         provider send CQ handle\r
+ *\r
+ * Output:\r
+ *     none\r
+ *\r
+ * Returns:\r
+ *     DAT_SUCCESS\r
+ *     DAT_INSUFFICIENT_RESOURCES\r
+ *     DAT_INTERNAL_ERROR\r
+ *\r
+ */\r
+DAT_RETURN\r
+dapls_ib_qp_alloc(IN DAPL_IA * ia_ptr,\r
+                 IN DAPL_EP * ep_ptr, IN DAPL_EP * ep_ctx_ptr)\r
+{\r
+       DAT_EP_ATTR *attr;\r
+       DAPL_EVD *rcv_evd, *req_evd;\r
+       ib_cq_handle_t rcv_cq, req_cq;\r
+       ib_pd_handle_t ib_pd_handle;\r
+       struct ibv_qp_init_attr qp_create;\r
+#ifdef _OPENIB_CMA_\r
+       dp_ib_cm_handle_t conn;\r
+#endif\r
+       dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
+                    " qp_alloc: ia_ptr %p ep_ptr %p ep_ctx_ptr %p\n",\r
+                    ia_ptr, ep_ptr, ep_ctx_ptr);\r
+\r
+       attr = &ep_ptr->param.ep_attr;\r
+       ib_pd_handle = ((DAPL_PZ *) ep_ptr->param.pz_handle)->pd_handle;\r
+       rcv_evd = (DAPL_EVD *) ep_ptr->param.recv_evd_handle;\r
+       req_evd = (DAPL_EVD *) ep_ptr->param.request_evd_handle;\r
+\r
+       /* \r
+        * DAT allows usage model of EP's with no EVD's but IB does not. \r
+        * Create a CQ with zero entries under the covers to support and \r
+        * catch any invalid posting. \r
+        */\r
+       if (rcv_evd != DAT_HANDLE_NULL)\r
+               rcv_cq = rcv_evd->ib_cq_handle;\r
+       else if (!ia_ptr->hca_ptr->ib_trans.ib_cq_empty)\r
+               rcv_cq = ia_ptr->hca_ptr->ib_trans.ib_cq_empty;\r
+       else {\r
+               struct ibv_comp_channel *channel;\r
+\r
+               channel = ibv_create_comp_channel(ia_ptr->hca_ptr->ib_hca_handle);\r
+               if (!channel)\r
+                       return (dapl_convert_errno(ENOMEM, "create_cq"));\r
+                 \r
+               /* Call IB verbs to create CQ */\r
+               rcv_cq = ibv_create_cq(ia_ptr->hca_ptr->ib_hca_handle,\r
+                                      0, NULL, channel, 0);\r
+\r
+               if (rcv_cq == IB_INVALID_HANDLE) {\r
+                       ibv_destroy_comp_channel(channel);\r
+                       return (dapl_convert_errno(ENOMEM, "create_cq"));\r
+               }\r
+\r
+               ia_ptr->hca_ptr->ib_trans.ib_cq_empty = rcv_cq;\r
+       }\r
+       if (req_evd != DAT_HANDLE_NULL)\r
+               req_cq = req_evd->ib_cq_handle;\r
+       else\r
+               req_cq = ia_ptr->hca_ptr->ib_trans.ib_cq_empty;\r
+\r
+       /* \r
+        * IMPLEMENTATION NOTE:\r
+        * uDAPL allows consumers to post buffers on the EP after creation\r
+        * and before a connect request (outbound and inbound). This forces\r
+        * a binding to a device during the hca_open call and requires the\r
+        * consumer to predetermine which device to listen on or connect from.\r
+        * This restriction eliminates any option of listening or connecting \r
+        * over multiple devices. uDAPL should add API's to resolve addresses \r
+        * and bind to the device at the approriate time (before connect \r
+        * and after CR arrives). Discovery should happen at connection time \r
+        * based on addressing and not on static configuration during open.\r
+        */\r
+\r
+#ifdef _OPENIB_CMA_\r
+       /* Allocate CM and initialize lock */\r
+       if ((conn = dapls_ib_cm_create(ep_ptr)) == NULL)\r
+               return (dapl_convert_errno(ENOMEM, "create_cq"));\r
+\r
+       /* open identifies the local device; per DAT specification */\r
+       if (rdma_bind_addr(conn->cm_id,\r
+                          (struct sockaddr *)&ia_ptr->hca_ptr->hca_address))\r
+               return (dapl_convert_errno(EAFNOSUPPORT, "create_cq"));\r
+#endif\r
+       /* Setup attributes and create qp */\r
+       dapl_os_memzero((void *)&qp_create, sizeof(qp_create));\r
+       qp_create.send_cq = req_cq;\r
+       qp_create.cap.max_send_wr = attr->max_request_dtos;\r
+       qp_create.cap.max_send_sge = attr->max_request_iov;\r
+       qp_create.cap.max_inline_data =\r
+           ia_ptr->hca_ptr->ib_trans.max_inline_send;\r
+       qp_create.qp_type = IBV_QPT_RC;\r
+       qp_create.qp_context = (void *)ep_ptr;\r
+\r
+#ifdef DAT_EXTENSIONS \r
+       if (attr->service_type == DAT_IB_SERVICE_TYPE_UD) {\r
+#ifdef _OPENIB_CMA_\r
+               return (DAT_NOT_IMPLEMENTED);\r
+#endif\r
+               qp_create.qp_type = IBV_QPT_UD;\r
+               if (attr->max_message_size >\r
+                   (128 << ia_ptr->hca_ptr->ib_trans.mtu)) {\r
+                       return (DAT_INVALID_PARAMETER | DAT_INVALID_ARG6);\r
+               }\r
+       }\r
+#endif\r
+       \r
+       /* ibv assumes rcv_cq is never NULL, set to req_cq */\r
+       if (rcv_cq == NULL) {\r
+               qp_create.recv_cq = req_cq;\r
+               qp_create.cap.max_recv_wr = 0;\r
+               qp_create.cap.max_recv_sge = 0;\r
+       } else {\r
+               qp_create.recv_cq = rcv_cq;\r
+               qp_create.cap.max_recv_wr = attr->max_recv_dtos;\r
+               qp_create.cap.max_recv_sge = attr->max_recv_iov;\r
+       }\r
+\r
+#ifdef _OPENIB_CMA_\r
+       if (rdma_create_qp(conn->cm_id, ib_pd_handle, &qp_create)) {\r
+               dapls_ib_cm_free(conn, ep_ptr);\r
+               return (dapl_convert_errno(errno, "create_qp"));\r
+       }\r
+       ep_ptr->qp_handle = conn->cm_id->qp;\r
+       ep_ptr->cm_handle = conn;\r
+       ep_ptr->qp_state = IBV_QPS_INIT;\r
+\r
+       ep_ptr->param.local_port_qual = rdma_get_src_port(conn->cm_id);\r
+#else\r
+       ep_ptr->qp_handle = ibv_create_qp(ib_pd_handle, &qp_create);\r
+       if (!ep_ptr->qp_handle)\r
+               return (dapl_convert_errno(ENOMEM, "create_qp"));\r
+               \r
+       /* Setup QP attributes for INIT state on the way out */\r
+       if (dapls_modify_qp_state(ep_ptr->qp_handle,\r
+                                 IBV_QPS_INIT, 0, 0, 0) != DAT_SUCCESS) {\r
+               ibv_destroy_qp(ep_ptr->qp_handle);\r
+               ep_ptr->qp_handle = IB_INVALID_HANDLE;\r
+               return DAT_INTERNAL_ERROR;\r
+       }\r
+#endif\r
+       dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
+                    " qp_alloc: qpn %p sq %d,%d rq %d,%d\n",\r
+                    ep_ptr->qp_handle->qp_num,\r
+                    qp_create.cap.max_send_wr, qp_create.cap.max_send_sge,\r
+                    qp_create.cap.max_recv_wr, qp_create.cap.max_recv_sge);\r
+\r
+       return DAT_SUCCESS;\r
+}\r
+\r
+/*\r
+ * dapl_ib_qp_free\r
+ *\r
+ * Free a QP\r
+ *\r
+ * Input:\r
+ *     ia_handle       IA handle\r
+ *     *ep_ptr         pointer to EP INFO\r
+ *\r
+ * Output:\r
+ *     none\r
+ *\r
+ * Returns:\r
+ *     DAT_SUCCESS\r
+ *  dapl_convert_errno\r
+ *\r
+ */\r
+DAT_RETURN dapls_ib_qp_free(IN DAPL_IA * ia_ptr, IN DAPL_EP * ep_ptr)\r
+{\r
+       dapl_dbg_log(DAPL_DBG_TYPE_EP, " qp_free:  ep_ptr %p qp %p\n",\r
+                    ep_ptr, ep_ptr->qp_handle);\r
+\r
+       if (ep_ptr->cm_handle != NULL) {\r
+               dapls_ib_cm_free(ep_ptr->cm_handle, ep_ptr);\r
+       }\r
+       \r
+       if (ep_ptr->qp_handle != NULL) {\r
+               /* force error state to flush queue, then destroy */\r
+               dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_ERR, 0,0,0);\r
+\r
+               if (ibv_destroy_qp(ep_ptr->qp_handle))\r
+                       return (dapl_convert_errno(errno, "destroy_qp"));\r
+\r
+               ep_ptr->qp_handle = NULL;\r
+       }\r
+\r
+#ifdef DAT_EXTENSIONS\r
+       /* UD endpoints can have many CR associations and will not\r
+        * set ep->cm_handle. Call provider with cm_ptr null to incidate\r
+        * UD type multi CR's for this EP. It will parse internal list\r
+        * and cleanup all associations.\r
+        */\r
+       if (ep_ptr->param.ep_attr.service_type == DAT_IB_SERVICE_TYPE_UD) \r
+               dapls_ib_cm_free(NULL, ep_ptr);\r
+#endif\r
+\r
+       return DAT_SUCCESS;\r
+}\r
+\r
+/*\r
+ * dapl_ib_qp_modify\r
+ *\r
+ * Set the QP to the parameters specified in an EP_PARAM\r
+ *\r
+ * The EP_PARAM structure that is provided has been\r
+ * sanitized such that only non-zero values are valid.\r
+ *\r
+ * Input:\r
+ *     ib_hca_handle           HCA handle\r
+ *     qp_handle               QP handle\r
+ *     ep_attr                 Sanitized EP Params\r
+ *\r
+ * Output:\r
+ *     none\r
+ *\r
+ * Returns:\r
+ *     DAT_SUCCESS\r
+ *     DAT_INSUFFICIENT_RESOURCES\r
+ *     DAT_INVALID_PARAMETER\r
+ *\r
+ */\r
+DAT_RETURN\r
+dapls_ib_qp_modify(IN DAPL_IA * ia_ptr,\r
+                  IN DAPL_EP * ep_ptr, IN DAT_EP_ATTR * attr)\r
+{\r
+       struct ibv_qp_attr qp_attr;\r
+\r
+       if (ep_ptr->qp_handle == IB_INVALID_HANDLE)\r
+               return DAT_INVALID_PARAMETER;\r
+\r
+       /* \r
+        * EP state, qp_handle state should be an indication\r
+        * of current state but the only way to be sure is with\r
+        * a user mode ibv_query_qp call which is NOT available \r
+        */\r
+\r
+       /* move to error state if necessary */\r
+       if ((ep_ptr->qp_state == IB_QP_STATE_ERROR) &&\r
+           (ep_ptr->qp_handle->state != IBV_QPS_ERR)) {\r
+               return (dapls_modify_qp_state(ep_ptr->qp_handle, \r
+                                             IBV_QPS_ERR, 0, 0, 0));\r
+       }\r
+\r
+       /*\r
+        * Check if we have the right qp_state to modify attributes\r
+        */\r
+       if ((ep_ptr->qp_handle->state != IBV_QPS_RTR) &&\r
+           (ep_ptr->qp_handle->state != IBV_QPS_RTS))\r
+               return DAT_INVALID_STATE;\r
+\r
+       /* Adjust to current EP attributes */\r
+       dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));\r
+       qp_attr.cap.max_send_wr = attr->max_request_dtos;\r
+       qp_attr.cap.max_recv_wr = attr->max_recv_dtos;\r
+       qp_attr.cap.max_send_sge = attr->max_request_iov;\r
+       qp_attr.cap.max_recv_sge = attr->max_recv_iov;\r
+\r
+       dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
+                    "modify_qp: qp %p sq %d,%d, rq %d,%d\n",\r
+                    ep_ptr->qp_handle,\r
+                    qp_attr.cap.max_send_wr, qp_attr.cap.max_send_sge,\r
+                    qp_attr.cap.max_recv_wr, qp_attr.cap.max_recv_sge);\r
+\r
+       if (ibv_modify_qp(ep_ptr->qp_handle, &qp_attr, IBV_QP_CAP)) {\r
+               dapl_dbg_log(DAPL_DBG_TYPE_ERR,\r
+                            "modify_qp: modify ep %p qp %p failed\n",\r
+                            ep_ptr, ep_ptr->qp_handle);\r
+               return (dapl_convert_errno(errno, "modify_qp_state"));\r
+       }\r
+\r
+       return DAT_SUCCESS;\r
+}\r
+\r
+/*\r
+ * dapls_ib_reinit_ep\r
+ *\r
+ * Move the QP to INIT state again.\r
+ *\r
+ * Input:\r
+ *     ep_ptr          DAPL_EP\r
+ *\r
+ * Output:\r
+ *     none\r
+ *\r
+ * Returns:\r
+ *     void\r
+ *\r
+ */\r
+#if defined(_WIN32) || defined(_WIN64) || defined(_OPENIB_CMA_)\r
+void dapls_ib_reinit_ep(IN DAPL_EP * ep_ptr)\r
+{\r
+       /* work around bug in low level driver - 3/24/09 */\r
+       /* RTS -> RESET -> INIT -> ERROR QP transition crashes system */\r
+       if (ep_ptr->qp_handle != IB_INVALID_HANDLE) {\r
+               dapls_ib_qp_free(ep_ptr->header.owner_ia, ep_ptr);\r
+               dapls_ib_qp_alloc(ep_ptr->header.owner_ia, ep_ptr, ep_ptr);\r
+       }\r
+}\r
+#else                          // _WIN32 || _WIN64\r
+void dapls_ib_reinit_ep(IN DAPL_EP * ep_ptr)\r
+{\r
+       if (ep_ptr->qp_handle != IB_INVALID_HANDLE &&\r
+           ep_ptr->qp_handle->qp_type != IBV_QPT_UD) {\r
+               /* move to RESET state and then to INIT */\r
+               dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_RESET,0,0,0);\r
+               dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_INIT,0,0,0);\r
+       }\r
+}\r
+#endif                         // _WIN32 || _WIN64\r
+\r
+/* \r
+ * Generic QP modify for init, reset, error, RTS, RTR\r
+ * For UD, create_ah on RTR, qkey on INIT\r
+ * CM msg provides QP attributes, info in network order\r
+ */\r
+DAT_RETURN\r
+dapls_modify_qp_state(IN ib_qp_handle_t                qp_handle,\r
+                     IN ib_qp_state_t          qp_state, \r
+                     IN uint32_t               qpn,\r
+                     IN uint16_t               lid,\r
+                     IN ib_gid_handle_t        gid)\r
+{\r
+       struct ibv_qp_attr qp_attr;\r
+       enum ibv_qp_attr_mask mask = IBV_QP_STATE;\r
+       DAPL_EP *ep_ptr = (DAPL_EP *) qp_handle->qp_context;\r
+       DAPL_IA *ia_ptr = ep_ptr->header.owner_ia;\r
+       int ret;\r
+\r
+       dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));\r
+       qp_attr.qp_state = qp_state;\r
+       \r
+       switch (qp_state) {\r
+       case IBV_QPS_RTR:\r
+               dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
+                               " QPS_RTR: type %d qpn 0x%x lid 0x%x"\r
+                               " port %d ep %p qp_state %d \n",\r
+                               qp_handle->qp_type, \r
+                               ntohl(qpn), ntohs(lid), \r
+                               ia_ptr->hca_ptr->port_num,\r
+                               ep_ptr, ep_ptr->qp_state);\r
+\r
+               mask |= IBV_QP_AV |\r
+                       IBV_QP_PATH_MTU |\r
+                       IBV_QP_DEST_QPN |\r
+                       IBV_QP_RQ_PSN |\r
+                       IBV_QP_MAX_DEST_RD_ATOMIC | IBV_QP_MIN_RNR_TIMER;\r
+\r
+               qp_attr.dest_qp_num = ntohl(qpn);\r
+               qp_attr.rq_psn = 1;\r
+               qp_attr.path_mtu = ia_ptr->hca_ptr->ib_trans.mtu;\r
+               qp_attr.max_dest_rd_atomic =\r
+                       ep_ptr->param.ep_attr.max_rdma_read_out;\r
+               qp_attr.min_rnr_timer =\r
+                       ia_ptr->hca_ptr->ib_trans.rnr_timer;\r
+\r
+               /* address handle. RC and UD */\r
+               qp_attr.ah_attr.dlid = ntohs(lid);\r
+               if (ia_ptr->hca_ptr->ib_trans.global) {\r
+                       qp_attr.ah_attr.is_global = 1;\r
+                       qp_attr.ah_attr.grh.dgid.global.subnet_prefix = \r
+                               ntohll(gid->global.subnet_prefix);\r
+                       qp_attr.ah_attr.grh.dgid.global.interface_id = \r
+                               ntohll(gid->global.interface_id);\r
+                       qp_attr.ah_attr.grh.hop_limit =\r
+                               ia_ptr->hca_ptr->ib_trans.hop_limit;\r
+                       qp_attr.ah_attr.grh.traffic_class =\r
+                               ia_ptr->hca_ptr->ib_trans.tclass;\r
+               }\r
+               qp_attr.ah_attr.sl = 0;\r
+               qp_attr.ah_attr.src_path_bits = 0;\r
+               qp_attr.ah_attr.port_num = ia_ptr->hca_ptr->port_num;\r
+\r
+               /* UD: already in RTR, RTS state */\r
+               if (qp_handle->qp_type == IBV_QPT_UD) {\r
+                       mask = IBV_QP_STATE;\r
+                       if (ep_ptr->qp_state == IBV_QPS_RTR ||\r
+                               ep_ptr->qp_state == IBV_QPS_RTS)\r
+                               return DAT_SUCCESS;\r
+               }\r
+               break;\r
+       case IBV_QPS_RTS:\r
+               if (qp_handle->qp_type == IBV_QPT_RC) {\r
+                       mask |= IBV_QP_SQ_PSN |\r
+                               IBV_QP_TIMEOUT |\r
+                               IBV_QP_RETRY_CNT |\r
+                               IBV_QP_RNR_RETRY | IBV_QP_MAX_QP_RD_ATOMIC;\r
+                       qp_attr.timeout =\r
+                               ia_ptr->hca_ptr->ib_trans.ack_timer;\r
+                       qp_attr.retry_cnt =\r
+                               ia_ptr->hca_ptr->ib_trans.ack_retry;\r
+                       qp_attr.rnr_retry =\r
+                               ia_ptr->hca_ptr->ib_trans.rnr_retry;\r
+                       qp_attr.max_rd_atomic =\r
+                               ep_ptr->param.ep_attr.max_rdma_read_out;\r
+               }\r
+               /* RC and UD */\r
+               qp_attr.qp_state = IBV_QPS_RTS;\r
+               qp_attr.sq_psn = 1;\r
+\r
+               dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
+                               " QPS_RTS: psn %x rd_atomic %d ack %d "\r
+                               " retry %d rnr_retry %d ep %p qp_state %d\n",\r
+                               qp_attr.sq_psn, qp_attr.max_rd_atomic,\r
+                               qp_attr.timeout, qp_attr.retry_cnt,\r
+                               qp_attr.rnr_retry, ep_ptr,\r
+                               ep_ptr->qp_state);\r
+\r
+               if (qp_handle->qp_type == IBV_QPT_UD) {\r
+                       /* already RTS, multi remote AH's on QP */\r
+                       if (ep_ptr->qp_state == IBV_QPS_RTS)\r
+                               return DAT_SUCCESS;\r
+                       else\r
+                               mask = IBV_QP_STATE | IBV_QP_SQ_PSN;\r
+               }\r
+               break;\r
+       case IBV_QPS_INIT:\r
+               mask |= IBV_QP_PKEY_INDEX | IBV_QP_PORT;\r
+               if (qp_handle->qp_type == IBV_QPT_RC) {\r
+                       mask |= IBV_QP_ACCESS_FLAGS;\r
+                       qp_attr.qp_access_flags =\r
+                               IBV_ACCESS_LOCAL_WRITE |\r
+                               IBV_ACCESS_REMOTE_WRITE |\r
+                               IBV_ACCESS_REMOTE_READ |\r
+                               IBV_ACCESS_REMOTE_ATOMIC |\r
+                               IBV_ACCESS_MW_BIND;\r
+               }\r
+\r
+               if (qp_handle->qp_type == IBV_QPT_UD) {\r
+                       /* already INIT, multi remote AH's on QP */\r
+                       if (ep_ptr->qp_state == IBV_QPS_INIT)\r
+                               return DAT_SUCCESS;\r
+                       mask |= IBV_QP_QKEY;\r
+                       qp_attr.qkey = DAT_UD_QKEY;\r
+               }\r
+\r
+               qp_attr.pkey_index = 0;\r
+               qp_attr.port_num = ia_ptr->hca_ptr->port_num;\r
+\r
+               dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
+                               " QPS_INIT: pi %x port %x acc %x qkey 0x%x\n",\r
+                               qp_attr.pkey_index, qp_attr.port_num,\r
+                               qp_attr.qp_access_flags, qp_attr.qkey);\r
+               break;\r
+       default:\r
+               break;\r
+       }\r
+\r
+       ret = ibv_modify_qp(qp_handle, &qp_attr, mask);\r
+       if (ret == 0) {\r
+               ep_ptr->qp_state = qp_state;\r
+               return DAT_SUCCESS;\r
+       } else {\r
+               return (dapl_convert_errno(errno, "modify_qp_state"));\r
+       }\r
+}\r
+\r
+/* Modify UD type QP from init, rtr, rts, info network order */\r
+DAT_RETURN \r
+dapls_modify_qp_ud(IN DAPL_HCA *hca, IN ib_qp_handle_t qp)\r
+{\r
+       struct ibv_qp_attr qp_attr;\r
+\r
+       /* modify QP, setup and prepost buffers */\r
+       dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));\r
+       qp_attr.qp_state = IBV_QPS_INIT;\r
+        qp_attr.pkey_index = 0;\r
+        qp_attr.port_num = hca->port_num;\r
+        qp_attr.qkey = DAT_UD_QKEY;\r
+       if (ibv_modify_qp(qp, &qp_attr, \r
+                         IBV_QP_STATE          |\r
+                         IBV_QP_PKEY_INDEX     |\r
+                          IBV_QP_PORT          |\r
+                          IBV_QP_QKEY)) {\r
+               dapl_log(DAPL_DBG_TYPE_ERR,\r
+                       " modify_ud_qp INIT: ERR %s\n", strerror(errno));\r
+               return (dapl_convert_errno(errno, "modify_qp"));\r
+       }\r
+       dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));\r
+       qp_attr.qp_state = IBV_QPS_RTR;\r
+       if (ibv_modify_qp(qp, &qp_attr,IBV_QP_STATE)) {\r
+               dapl_log(DAPL_DBG_TYPE_ERR, \r
+                       " modify_ud_qp RTR: ERR %s\n", strerror(errno));\r
+               return (dapl_convert_errno(errno, "modify_qp"));\r
+       }\r
+       dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));\r
+       qp_attr.qp_state = IBV_QPS_RTS;\r
+       qp_attr.sq_psn = 1;\r
+       if (ibv_modify_qp(qp, &qp_attr, \r
+                         IBV_QP_STATE | IBV_QP_SQ_PSN)) {\r
+               dapl_log(DAPL_DBG_TYPE_ERR,\r
+                       " modify_ud_qp RTS: ERR %s\n", strerror(errno));\r
+               return (dapl_convert_errno(errno, "modify_qp"));\r
+       }\r
+       return DAT_SUCCESS;\r
+}\r
+\r
+/* Create address handle for remote QP, info in network order */\r
+ib_ah_handle_t \r
+dapls_create_ah(IN DAPL_HCA            *hca,\r
+               IN ib_pd_handle_t       pd,\r
+               IN ib_qp_handle_t       qp,\r
+               IN uint16_t             lid,\r
+               IN ib_gid_handle_t      gid)\r
+{\r
+       struct ibv_qp_attr qp_attr;\r
+       ib_ah_handle_t  ah;\r
+\r
+       if (qp->qp_type != IBV_QPT_UD)\r
+               return NULL;\r
+\r
+       dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));\r
+       qp_attr.qp_state = IBV_QP_STATE;\r
+\r
+       /* address handle. RC and UD */\r
+       qp_attr.ah_attr.dlid = ntohs(lid);\r
+       if (gid != NULL) {\r
+               dapl_log(DAPL_DBG_TYPE_CM, "dapl_create_ah: with GID\n");\r
+               qp_attr.ah_attr.is_global = 1;\r
+               qp_attr.ah_attr.grh.dgid.global.subnet_prefix = \r
+                               ntohll(gid->global.subnet_prefix);\r
+               qp_attr.ah_attr.grh.dgid.global.interface_id = \r
+                               ntohll(gid->global.interface_id);\r
+               qp_attr.ah_attr.grh.hop_limit = hca->ib_trans.hop_limit;\r
+               qp_attr.ah_attr.grh.traffic_class = hca->ib_trans.tclass;\r
+       }\r
+       qp_attr.ah_attr.sl = 0;\r
+       qp_attr.ah_attr.src_path_bits = 0;\r
+       qp_attr.ah_attr.port_num = hca->port_num;\r
+\r
+       dapl_log(DAPL_DBG_TYPE_CM, \r
+                       " dapls_create_ah: port %x lid %x pd %p ctx %p handle 0x%x\n", \r
+                       hca->port_num,qp_attr.ah_attr.dlid, pd, pd->context, pd->handle);\r
+\r
+       /* UD: create AH for remote side */\r
+       ah = ibv_create_ah(pd, &qp_attr.ah_attr);\r
+       if (!ah) {\r
+               dapl_log(DAPL_DBG_TYPE_ERR,\r
+                       " create_ah: ERR %s\n", strerror(errno));\r
+               return NULL;\r
+       }\r
+\r
+       dapl_log(DAPL_DBG_TYPE_CM, \r
+                       " dapls_create_ah: AH %p for lid %x\n", \r
+                       ah, qp_attr.ah_attr.dlid);\r
+\r
+       return ah;\r
+}\r
+\r
+/*\r
+ * Local variables:\r
+ *  c-indent-level: 4\r
+ *  c-basic-offset: 4\r
+ *  tab-width: 8\r
+ * End:\r
+ */\r