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