OpenSolaris_b135/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:
 */