root/usr/src/lib/udapl/udapl_tavor/common/dapl_ep_util.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
 */

/*
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 *
 * MODULE: dapl_ep_util.c
 *
 * PURPOSE: Manage EP Info structure
 *
 * $Id: dapl_ep_util.c,v 1.36 2003/08/04 16:50:27 sjs2 Exp $
 */

#include "dapl_ep_util.h"
#include "dapl_ring_buffer_util.h"
#include "dapl_cookie.h"
#include "dapl_adapter_util.h"
#include "dapl_evd_util.h"
#include "dapl_ia_util.h"

/*
 * Local definitions
 */
/*
 * Default number of I/O operations on an end point
 */
#define IB_IO_DEFAULT   16
/*
 * Default number of scatter/gather entries available to a single
 * post send/recv
 */
#define IB_IOV_DEFAULT  4

/*
 * Default number of RDMA operations in progress at a time
 */
#define IB_RDMA_DEFAULT 4

extern void dapli_ep_default_attrs(
    IN DAPL_EP                  *ep_ptr);


/*
 * dapl_ep_alloc
 *
 * alloc and initialize an EP INFO struct
 *
 * Input:
 *      IA INFO struct ptr
 *
 * Output:
 *      ep_ptr
 *
 * Returns:
 *      none
 *
 */
DAPL_EP *
dapl_ep_alloc(
        IN DAPL_IA              *ia_ptr,
        IN const DAT_EP_ATTR    *ep_attr,
        IN DAT_BOOLEAN          srq_attached)
{
        DAPL_EP *ep_ptr;

        /* Allocate EP */
        ep_ptr = (DAPL_EP *)dapl_os_alloc(sizeof (DAPL_EP));
        if (ep_ptr == NULL) {
                goto bail;
        }

        /* zero the structure */
        (void) dapl_os_memzero(ep_ptr, sizeof (DAPL_EP));

        /*
         * initialize the header
         */
        ep_ptr->header.provider         = ia_ptr->header.provider;
        ep_ptr->header.magic            = DAPL_MAGIC_EP;
        ep_ptr->header.handle_type      = DAT_HANDLE_TYPE_EP;
        ep_ptr->header.owner_ia                 = ia_ptr;
        ep_ptr->header.user_context.as_64       = 0;
        ep_ptr->header.user_context.as_ptr      = NULL;
        dapl_llist_init_entry(&ep_ptr->header.ia_list_entry);
        dapl_os_lock_init(&ep_ptr->header.lock);

        /*
         * Initialize the body
         */
        (void) dapl_os_memzero(&ep_ptr->param, sizeof (DAT_EP_PARAM));
        ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED;
        ep_ptr->param.local_ia_address_ptr =
            (DAT_IA_ADDRESS_PTR)&ia_ptr->hca_ptr->hca_address;

        /* Set the remote address pointer */
        ep_ptr->param.remote_ia_address_ptr =
            (DAT_IA_ADDRESS_PTR) &ep_ptr->remote_ia_address;

        /*
         * Set up default parameters if the user passed in a NULL
         */
        if (ep_attr == NULL) {
                dapli_ep_default_attrs(ep_ptr);
        } else {
                ep_ptr->param.ep_attr = *ep_attr;
        }

        /*
         * IBM OS API specific fields
         */
        ep_ptr->qp_handle       = IB_INVALID_HANDLE;
        ep_ptr->qpn             = 0;
        ep_ptr->qp_state        = DAPL_QP_STATE_UNATTACHED;
        ep_ptr->cm_handle       = IB_INVALID_HANDLE;

        ep_ptr->req_count = 0;
        ep_ptr->recv_count = 0;

        ep_ptr->srq_attached = srq_attached;

        if (DAT_SUCCESS != dapls_cb_create(&ep_ptr->req_buffer, ep_ptr,
            DAPL_COOKIE_QUEUE_EP, ep_ptr->param.ep_attr.max_request_dtos)) {
                dapl_ep_dealloc(ep_ptr);
                ep_ptr = NULL;
                goto bail;
        }

        if (!srq_attached) {
                if (DAT_SUCCESS != dapls_cb_create(&ep_ptr->recv_buffer, ep_ptr,
                    DAPL_COOKIE_QUEUE_EP,
                    ep_ptr->param.ep_attr.max_recv_dtos)) {
                        dapl_ep_dealloc(ep_ptr);
                        ep_ptr = NULL;
                        goto bail;
                }
        }

bail:
        return (ep_ptr);
}


/*
 * dapl_ep_dealloc
 *
 * Free the passed in EP structure.
 *
 * Input:
 *      entry point pointer
 *
 * Output:
 *      none
 *
 * Returns:
 *      none
 *
 */
void
dapl_ep_dealloc(
        IN DAPL_EP              *ep_ptr)
{
        dapl_os_assert(ep_ptr->header.magic == DAPL_MAGIC_EP ||
            ep_ptr->header.magic == DAPL_MAGIC_EP_EXIT);

        /* reset magic to prevent reuse */
        ep_ptr->header.magic = DAPL_MAGIC_INVALID;

        dapls_cb_free(&ep_ptr->req_buffer);
        dapls_cb_free(&ep_ptr->recv_buffer);

        dapl_os_free(ep_ptr, sizeof (DAPL_EP));
}


/*
 * dapl_ep_default_attrs
 *
 * Set default values in the parameter fields
 *
 * Input:
 *      entry point pointer
 *
 * Output:
 *      none
 *
 * Returns:
 *      none
 *
 */
void
dapli_ep_default_attrs(
        IN DAPL_EP              *ep_ptr)
{
        DAT_EP_ATTR             *ep_attr;

        ep_attr = &ep_ptr->param.ep_attr;
        /* Set up defaults */
        (void) dapl_os_memzero(ep_attr, sizeof (DAT_EP_ATTR));

        /*
         * mtu and rdma sizes fixed in IB as per IBTA 1.1, 9.4.3, 9.4.4,
         * 9.7.7.
         */
        ep_attr->max_mtu_size   = 0x80000000;
        ep_attr->max_rdma_size  = 0x80000000;

        ep_attr->qos            = DAT_QOS_BEST_EFFORT;
        ep_attr->service_type   = DAT_SERVICE_TYPE_RC;
        ep_attr->max_recv_dtos  = IB_IO_DEFAULT;
        ep_attr->max_request_dtos       = IB_IO_DEFAULT;
        ep_attr->max_recv_iov           = IB_IOV_DEFAULT;
        ep_attr->max_request_iov        = IB_IOV_DEFAULT;
        ep_attr->max_rdma_read_in       = IB_RDMA_DEFAULT;
        ep_attr->max_rdma_read_out      = IB_RDMA_DEFAULT;

        ep_attr->request_completion_flags = DAT_COMPLETION_EVD_THRESHOLD_FLAG;
        ep_attr->recv_completion_flags    = DAT_COMPLETION_EVD_THRESHOLD_FLAG;
        /*
         * Unspecified defaults:
         *    - ep_privileges: No RDMA capabilities
         *    - num_transport_specific_params: none
         *    - transport_specific_params: none
         *    - num_provider_specific_params: 0
         *    - provider_specific_params: 0
         */
}


DAT_RETURN
dapl_ep_check_recv_completion_flags(
        DAT_COMPLETION_FLAGS    flags)
{

        /*
         * InfiniBand will not allow unsignaled/suppressed RECV completions,
         * see the 1.0.1 spec section 10.7.3.1, 10.8.6
         */

        if ((flags & DAT_COMPLETION_UNSIGNALLED_FLAG) ||
            (flags & DAT_COMPLETION_SUPPRESS_FLAG)) {
                return (DAT_INVALID_PARAMETER);
        }

        return (DAT_SUCCESS);
}

/* ARGSUSED */
DAT_RETURN
dapl_ep_check_request_completion_flags(
        DAT_COMPLETION_FLAGS    flags)
{
        return (DAT_SUCCESS);
}

DAT_RETURN
dapl_ep_check_qos(
        DAT_QOS qos)
{
        if (qos & ~(DAT_QOS_BEST_EFFORT | DAT_QOS_HIGH_THROUGHPUT |
            DAT_QOS_LOW_LATENCY | DAT_QOS_ECONOMY | DAT_QOS_PREMIUM)) {
                return (DAT_INVALID_PARAMETER);
        }
        return (DAT_SUCCESS);
}

DAT_RETURN
dapl_ep_post_send_req(
    IN  DAT_EP_HANDLE           ep_handle,
    IN  DAT_COUNT               num_segments,
    IN  DAT_LMR_TRIPLET         *local_iov,
    IN  DAT_DTO_COOKIE          user_cookie,
    IN  const DAT_RMR_TRIPLET   *remote_iov,
    IN  DAT_COMPLETION_FLAGS    completion_flags,
    IN  DAPL_DTO_TYPE           dto_type,
    IN  ib_send_op_type_t       op_type)
{
        DAPL_EP                 *ep;
        DAPL_COOKIE             *cookie;
        DAT_RETURN              dat_status;

        if (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP)) {
                dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
                    DAT_INVALID_HANDLE_EP);
                goto bail;
        }

        ep = (DAPL_EP *)ep_handle;

        /*
         * Synchronization ok since this buffer is only used for send
         * requests, which aren't allowed to race with each other.
         */
        dat_status = dapls_dto_cookie_alloc(&ep->req_buffer,
            dto_type,
            user_cookie,
            &cookie);
        if (dat_status != DAT_SUCCESS) {
                goto bail;
        }

        /*
         * Invoke provider specific routine to post DTO
         */
        if (num_segments != 1 ||
            completion_flags != DAT_COMPLETION_DEFAULT_FLAG)
                dat_status = dapls_ib_post_send(ep,
                    op_type,
                    cookie,
                    num_segments,
                    local_iov,
                    remote_iov,
                    completion_flags);
        else
                dat_status = dapls_ib_post_send_one(ep,
                    op_type,
                    cookie,
                    local_iov,
                    remote_iov);

        if (dat_status != DAT_SUCCESS) {
                dapls_cookie_dealloc(&ep->req_buffer, cookie);
        } else {
                dapl_os_atomic_inc(&ep->req_count);
        }

bail:
        return (dat_status);
}


/*
 * dapli_ep_timeout
 *
 * If this routine is invoked before a connection occurs, generate an
 * event
 */
void
dapls_ep_timeout(
        unsigned long                   arg)
{
        DAPL_EP         *ep_ptr;

        dapl_dbg_log(DAPL_DBG_TYPE_CM, "--> dapls_ep_timeout! ep %lx\n", arg);

        ep_ptr = (DAPL_EP *)arg;

        /* reset the EP state */
        ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;

        (void) dapls_evd_post_connection_event(
            (DAPL_EVD *)ep_ptr->param.connect_evd_handle,
            DAT_CONNECTION_EVENT_TIMED_OUT,
            (DAT_HANDLE) ep_ptr,
            0,
            0);
}


/*
 * dapls_ep_state_subtype
 *
 * Return the INVALID_STATE connection subtype associated with an
 * INVALID_STATE on an EP. Strictly for error reporting.
 */
DAT_RETURN_SUBTYPE
dapls_ep_state_subtype(
    IN  DAPL_EP                 *ep_ptr)
{
        DAT_RETURN_SUBTYPE      dat_status;

        switch (ep_ptr->param.ep_state) {
        case DAT_EP_STATE_RESERVED:
        {
                dat_status = DAT_INVALID_STATE_EP_RESERVED;
                break;
        }
        case DAT_EP_STATE_PASSIVE_CONNECTION_PENDING:
        {
                dat_status = DAT_INVALID_STATE_EP_PASSCONNPENDING;
                break;
        }
        case DAT_EP_STATE_ACTIVE_CONNECTION_PENDING:
        {
                dat_status = DAT_INVALID_STATE_EP_ACTCONNPENDING;
                break;
        }
        case DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING:
        {
                dat_status = DAT_INVALID_STATE_EP_TENTCONNPENDING;
                break;
        }
        case DAT_EP_STATE_CONNECTED:
        {
                dat_status = DAT_INVALID_STATE_EP_CONNECTED;
                break;
        }
        case DAT_EP_STATE_DISCONNECT_PENDING:
        {
                dat_status = DAT_INVALID_STATE_EP_DISCPENDING;
                break;
        }
        case DAT_EP_STATE_DISCONNECTED:
        {
                dat_status = DAT_INVALID_STATE_EP_DISCONNECTED;
                break;
        }
        case DAT_EP_STATE_COMPLETION_PENDING:
        {
                dat_status = DAT_INVALID_STATE_EP_COMPLPENDING;
                break;
        }
        default:
        {
                dat_status = 0;
                break;
        }
        }

        return (dat_status);
}


/*
 * dapl_ep_create_common
 *
 * Common code used by dapl_ep_create and dapl_ep_create_srq
 *
 * Input:
 *      ia_handle
 *      pz_handle
 *      recv_evd_handle (recv DTOs)
 *      request_evd_handle (xmit DTOs)
 *      connect_evd_handle
 *      srq_handle
 *      ep_attrs
 *
 * Output:
 *      ep_handle
 *
 * Returns:
 *      DAT_SUCCESS
 *      DAT_INSUFFICIENT_RESOURCES
 *      DAT_INVALID_PARAMETER
 *      DAT_INVALID_ATTRIBUTE
 *      DAT_MODEL_NOT_SUPPORTED
 */
DAT_RETURN
dapl_ep_create_common(
        IN      DAT_IA_HANDLE           ia_handle,
        IN      DAT_PZ_HANDLE           pz_handle,
        IN      DAT_EVD_HANDLE          recv_evd_handle,
        IN      DAT_EVD_HANDLE          request_evd_handle,
        IN      DAT_EVD_HANDLE          connect_evd_handle,
        IN      DAT_SRQ_HANDLE          srq_handle,
        IN      const DAT_EP_ATTR       *ep_attr_arg,
        OUT     DAT_EP_HANDLE           *ep_handle)
{
        DAPL_IA                 *ia_ptr;
        DAPL_EP                 *ep_ptr;
        DAT_EP_ATTR             ep_attr_limit;
        DAPL_EVD                *evd_ptr;
        DAT_RETURN              dat_status;
        DAT_BOOLEAN             srq_attached;
        DAT_EP_ATTR             *ep_attr, epa;

        if (ep_attr_arg) {
                epa = *ep_attr_arg;
                ep_attr = &epa;
        } else
                ep_attr = NULL;

        ia_ptr = (DAPL_IA *)ia_handle;
        dat_status = DAT_SUCCESS;
        /*
         * Verify parameters
         */
        if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) {
                dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
                    DAT_INVALID_HANDLE_IA);
                goto bail;
        }

        /*
         * Verify non-required parameters.
         * N.B. Assumption: any parameter that can be
         * modified by dat_ep_modify() is not strictly
         * required when the EP is created
         */
        if (pz_handle != NULL &&
            DAPL_BAD_HANDLE(pz_handle, DAPL_MAGIC_PZ)) {
                dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
                    DAT_INVALID_HANDLE_PZ);
                goto bail;
        }

        /* If connect handle is !NULL verify handle is good  */
        if (connect_evd_handle != DAT_HANDLE_NULL &&
            (DAPL_BAD_HANDLE(connect_evd_handle, DAPL_MAGIC_EVD) ||
            !(((DAPL_EVD *)connect_evd_handle)->evd_flags &
            DAT_EVD_CONNECTION_FLAG))) {
                dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
                    DAT_INVALID_HANDLE_EVD_CONN);
                goto bail;
        }
        /* If recv_evd is !NULL, verify handle is good and flags are valid */
        if ((recv_evd_handle != DAT_HANDLE_NULL) &&
            (DAPL_BAD_HANDLE(recv_evd_handle, DAPL_MAGIC_EVD) ||
            !(((DAPL_EVD *)recv_evd_handle)->evd_flags & DAT_EVD_DTO_FLAG))) {
                dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
                    DAT_INVALID_HANDLE_EVD_RECV);
                goto bail;
        }

        /* If req_evd is !NULL, verify handle is good and flags are valid */
        if ((request_evd_handle != DAT_HANDLE_NULL) &&
            (DAPL_BAD_HANDLE(request_evd_handle, DAPL_MAGIC_EVD) ||
            !(((DAPL_EVD *)request_evd_handle)->evd_flags &
            DAT_EVD_DTO_FLAG))) {
                dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
                    DAT_INVALID_HANDLE_EVD_REQUEST);
                goto bail;
        }

        srq_attached = DAT_FALSE;

        /* if srq_handle is not null validate it */
        if (srq_handle != DAT_HANDLE_NULL) {
                if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) {
                        dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
                            DAT_INVALID_HANDLE_SRQ);
                        goto bail;
                } else if (pz_handle !=
                    ((DAPL_SRQ *)srq_handle)->param.pz_handle) {
                        dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
                            DAT_INVALID_ARG2);
                        goto bail;
                }
                srq_attached = DAT_TRUE;
        }

        if (ep_handle == NULL) {
                dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
                    (srq_attached ? DAT_INVALID_ARG8 : DAT_INVALID_ARG7));
                goto bail;
        }

        /* For EPs with SRQ ep_attr is required */
        if ((srq_attached && (ep_attr == NULL)) || (uintptr_t)ep_attr & 3) {
                dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
                    (srq_attached ? DAT_INVALID_ARG7 : DAT_INVALID_ARG6));
                goto bail;
        }

        /*
         * Qualify EP Attributes are legal and make sense.  Note that if one
         * or both of the DTO handles are NULL, then the corresponding
         * max_*_dtos must 0 as the user will not be able to post dto ops on
         * the respective queue.
         */
        if (ep_attr != NULL) {
                if (ep_attr->service_type != DAT_SERVICE_TYPE_RC ||
                    (request_evd_handle == DAT_HANDLE_NULL &&
                    ep_attr->max_request_dtos != 0) ||
                    (request_evd_handle != DAT_HANDLE_NULL &&
                    ep_attr->max_request_dtos == 0) ||
                    ep_attr->max_request_iov == 0 ||
                    (DAT_SUCCESS != dapl_ep_check_qos(ep_attr->qos)) ||
                    (DAT_SUCCESS != dapl_ep_check_recv_completion_flags(
                    ep_attr->recv_completion_flags))) {
                        dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
                            (srq_attached ? DAT_INVALID_ARG7 :
                            DAT_INVALID_ARG6));
                        goto bail;
                }

                if (srq_attached) {
                        if ((ep_attr->max_recv_dtos != DAT_HW_DEFAULT) ||
                            (ep_attr->srq_soft_hw != DAT_HW_DEFAULT)) {
                                dat_status = DAT_ERROR(DAT_MODEL_NOT_SUPPORTED,
                                    0);
                                goto bail;
                        }
                } else {
                        /* These checks are needed only for EPs without SRQ */
                        if ((recv_evd_handle == DAT_HANDLE_NULL &&
                            ep_attr->max_recv_dtos != 0) ||
                            (recv_evd_handle != DAT_HANDLE_NULL &&
                            ep_attr->max_recv_dtos == 0) ||
                            ep_attr->max_recv_iov == 0) {
                                dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
                                    DAT_INVALID_ARG6);
                                goto bail;
                        }
                }
        }

        /* Verify the attributes against the transport */
        if (ep_attr != NULL) {
                (void) dapl_os_memzero(&ep_attr_limit, sizeof (DAT_EP_ATTR));
                dat_status = dapls_ib_query_hca(ia_ptr->hca_ptr,
                    NULL, &ep_attr_limit, NULL, NULL);
                if (dat_status != DAT_SUCCESS) {
                        goto bail;
                }
                if (ep_attr->max_mtu_size > ep_attr_limit.max_mtu_size ||
                    ep_attr->max_rdma_size > ep_attr_limit.max_rdma_size ||
                    (ep_attr->max_request_dtos >
                    ep_attr_limit.max_request_dtos) ||
                    ep_attr->max_request_iov > ep_attr_limit.max_request_iov) {
                        dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
                            (srq_attached ? DAT_INVALID_ARG7 :
                            DAT_INVALID_ARG6));
                        goto bail;
                }
                /* if inlining enabled, recompute max_request_iov */
                if (ia_ptr->hca_ptr->max_inline_send)
                        ep_attr->max_request_iov = dapls_ib_max_request_iov(
                            ep_attr->max_request_iov,
                            ep_attr->max_request_dtos,
                            ep_attr_limit.max_request_iov,
                            ia_ptr->hca_ptr->max_inline_send);

                /* Only EPs without SRQ need the following check */
                if ((!srq_attached) &&
                    (ep_attr->max_recv_dtos > ep_attr_limit.max_recv_dtos) ||
                    (ep_attr->max_recv_iov > ep_attr_limit.max_recv_iov)) {
                        dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
                            DAT_INVALID_ARG6);
                        goto bail;
                }


        }
        /*
         * Verify the completion flags for the EVD and the EP
         */

        evd_ptr = (DAPL_EVD *)recv_evd_handle;
        if (evd_ptr->completion_type == DAPL_EVD_STATE_INIT) {
                if (ep_attr != NULL &&
                    (ep_attr->recv_completion_flags ==
                    DAT_COMPLETION_DEFAULT_FLAG)) {
                        evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD;
                } else {
                        /*
                         * Currently we support only thresholds -
                         * eventually it'll depend on
                         * ep_attr->recv_completion_flags;
                         */
                        evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD;
                }
        }
        evd_ptr = (DAPL_EVD *)request_evd_handle;
        if (evd_ptr->completion_type == DAPL_EVD_STATE_INIT) {
                if (ep_attr != NULL &&
                    (ep_attr->recv_completion_flags ==
                    DAT_COMPLETION_DEFAULT_FLAG)) {
                        evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD;
                } else {
                        /*
                         * Currently we support only thresholds -
                         * eventually it'll depend on
                         * ep_attr->recv_completion_flags;
                         */
                        evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD;
                }
        }

        /* Allocate EP */
        ep_ptr = dapl_ep_alloc(ia_ptr, ep_attr, srq_attached);
        if (ep_ptr == NULL) {
                dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
                    DAT_RESOURCE_MEMORY);
                goto bail;
        }

        /*
         * Fill in the EP
         */
        ep_ptr->param.ia_handle         = ia_handle;
        ep_ptr->param.pz_handle         = pz_handle;
        ep_ptr->param.recv_evd_handle   = recv_evd_handle;
        ep_ptr->param.request_evd_handle = request_evd_handle;
        ep_ptr->param.connect_evd_handle = connect_evd_handle;
        ep_ptr->param.srq_handle        = srq_handle;

        ep_ptr->srq_attached = srq_attached;

        /*
         * Make sure we handle the NULL DTO EVDs
         */
        if (recv_evd_handle == DAT_HANDLE_NULL && ep_attr == NULL) {
                ep_ptr->param.ep_attr.max_recv_dtos = 0;
        }

        if (request_evd_handle == DAT_HANDLE_NULL && ep_attr == NULL) {
                ep_ptr->param.ep_attr.max_request_dtos = 0;
        }

        /*
         * If the user has specified a PZ handle we allocate a QP for
         * this EP; else we defer until it is assigned via ep_modify().
         * As much as possible we try to keep QP creation out of the
         * connect path to avoid resource errors in strange places.
         */
        if (pz_handle != DAT_HANDLE_NULL) {
                /* Take a reference on the PZ handle */
                dapl_os_atomic_inc(&((DAPL_PZ *)pz_handle)->pz_ref_count);

                /*
                 * Get a QP from the IB provider
                 */
                dat_status = dapls_ib_qp_alloc(ia_ptr, ep_ptr, ep_ptr);

                if (dat_status != DAT_SUCCESS) {
                        dapl_os_atomic_dec(&((DAPL_PZ *)pz_handle)->
                            pz_ref_count);
                        dapl_ep_dealloc(ep_ptr);
                        goto bail;
                }
        } else {
                ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED;
        }

        /*
         * Update ref counts. See the spec where the endpoint marks
         * a data object as 'in use'
         *   pz_handle: dat_pz_free, uDAPL Document, 6.6.1.2
         *   evd_handles:
         *
         * N.B. This should really be done by a util routine.
         */
        dapl_os_atomic_inc(&((DAPL_EVD *)connect_evd_handle)->evd_ref_count);
        /* Optional handles */
        if (recv_evd_handle != NULL) {
                dapl_os_atomic_inc(&((DAPL_EVD *)recv_evd_handle)->
                    evd_ref_count);
        }
        if (request_evd_handle != NULL) {
                dapl_os_atomic_inc(&((DAPL_EVD *)request_evd_handle)->
                    evd_ref_count);
        }
        if (srq_handle != NULL) {
                dapl_os_atomic_inc(&((DAPL_SRQ *)srq_handle)->srq_ref_count);
        }

        /* Link it onto the IA */
        dapl_ia_link_ep(ia_ptr, ep_ptr);

        *ep_handle = ep_ptr;

bail:
        return (dat_status);
}

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