1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
24  */
25 
26 /*
27  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 /*
32  *
33  * MODULE: dapl_ep_util.c
34  *
35  * PURPOSE: Manage EP Info structure
36  *
37  * $Id: dapl_ep_util.c,v 1.36 2003/08/04 16:50:27 sjs2 Exp $
38  */
39 
40 #include "dapl_ep_util.h"
41 #include "dapl_ring_buffer_util.h"
42 #include "dapl_cookie.h"
43 #include "dapl_adapter_util.h"
44 #include "dapl_evd_util.h"
45 #include "dapl_ia_util.h"
46 
47 /*
48  * Local definitions
49  */
50 /*
51  * Default number of I/O operations on an end point
52  */
53 #define	IB_IO_DEFAULT	16
54 /*
55  * Default number of scatter/gather entries available to a single
56  * post send/recv
57  */
58 #define	IB_IOV_DEFAULT	4
59 
60 /*
61  * Default number of RDMA operations in progress at a time
62  */
63 #define	IB_RDMA_DEFAULT	4
64 
65 extern void dapli_ep_default_attrs(
66     IN DAPL_EP			*ep_ptr);
67 
68 
69 /*
70  * dapl_ep_alloc
71  *
72  * alloc and initialize an EP INFO struct
73  *
74  * Input:
75  * 	IA INFO struct ptr
76  *
77  * Output:
78  * 	ep_ptr
79  *
80  * Returns:
81  * 	none
82  *
83  */
84 DAPL_EP *
dapl_ep_alloc(IN DAPL_IA * ia_ptr,IN const DAT_EP_ATTR * ep_attr,IN DAT_BOOLEAN srq_attached)85 dapl_ep_alloc(
86 	IN DAPL_IA		*ia_ptr,
87 	IN const DAT_EP_ATTR	*ep_attr,
88 	IN DAT_BOOLEAN		srq_attached)
89 {
90 	DAPL_EP	*ep_ptr;
91 
92 	/* Allocate EP */
93 	ep_ptr = (DAPL_EP *)dapl_os_alloc(sizeof (DAPL_EP));
94 	if (ep_ptr == NULL) {
95 		goto bail;
96 	}
97 
98 	/* zero the structure */
99 	(void) dapl_os_memzero(ep_ptr, sizeof (DAPL_EP));
100 
101 	/*
102 	 * initialize the header
103 	 */
104 	ep_ptr->header.provider		= ia_ptr->header.provider;
105 	ep_ptr->header.magic		= DAPL_MAGIC_EP;
106 	ep_ptr->header.handle_type	= DAT_HANDLE_TYPE_EP;
107 	ep_ptr->header.owner_ia			= ia_ptr;
108 	ep_ptr->header.user_context.as_64	= 0;
109 	ep_ptr->header.user_context.as_ptr	= NULL;
110 	dapl_llist_init_entry(&ep_ptr->header.ia_list_entry);
111 	dapl_os_lock_init(&ep_ptr->header.lock);
112 
113 	/*
114 	 * Initialize the body
115 	 */
116 	(void) dapl_os_memzero(&ep_ptr->param, sizeof (DAT_EP_PARAM));
117 	ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED;
118 	ep_ptr->param.local_ia_address_ptr =
119 	    (DAT_IA_ADDRESS_PTR)&ia_ptr->hca_ptr->hca_address;
120 
121 	/* Set the remote address pointer */
122 	ep_ptr->param.remote_ia_address_ptr =
123 	    (DAT_IA_ADDRESS_PTR) &ep_ptr->remote_ia_address;
124 
125 	/*
126 	 * Set up default parameters if the user passed in a NULL
127 	 */
128 	if (ep_attr == NULL) {
129 		dapli_ep_default_attrs(ep_ptr);
130 	} else {
131 		ep_ptr->param.ep_attr = *ep_attr;
132 	}
133 
134 	/*
135 	 * IBM OS API specific fields
136 	 */
137 	ep_ptr->qp_handle	= IB_INVALID_HANDLE;
138 	ep_ptr->qpn		= 0;
139 	ep_ptr->qp_state	= DAPL_QP_STATE_UNATTACHED;
140 	ep_ptr->cm_handle	= IB_INVALID_HANDLE;
141 
142 	ep_ptr->req_count = 0;
143 	ep_ptr->recv_count = 0;
144 
145 	ep_ptr->srq_attached = srq_attached;
146 
147 	if (DAT_SUCCESS != dapls_cb_create(&ep_ptr->req_buffer, ep_ptr,
148 	    DAPL_COOKIE_QUEUE_EP, ep_ptr->param.ep_attr.max_request_dtos)) {
149 		dapl_ep_dealloc(ep_ptr);
150 		ep_ptr = NULL;
151 		goto bail;
152 	}
153 
154 	if (!srq_attached) {
155 		if (DAT_SUCCESS != dapls_cb_create(&ep_ptr->recv_buffer, ep_ptr,
156 		    DAPL_COOKIE_QUEUE_EP,
157 		    ep_ptr->param.ep_attr.max_recv_dtos)) {
158 			dapl_ep_dealloc(ep_ptr);
159 			ep_ptr = NULL;
160 			goto bail;
161 		}
162 	}
163 
164 bail:
165 	return (ep_ptr);
166 }
167 
168 
169 /*
170  * dapl_ep_dealloc
171  *
172  * Free the passed in EP structure.
173  *
174  * Input:
175  * 	entry point pointer
176  *
177  * Output:
178  * 	none
179  *
180  * Returns:
181  * 	none
182  *
183  */
184 void
dapl_ep_dealloc(IN DAPL_EP * ep_ptr)185 dapl_ep_dealloc(
186 	IN DAPL_EP		*ep_ptr)
187 {
188 	dapl_os_assert(ep_ptr->header.magic == DAPL_MAGIC_EP ||
189 	    ep_ptr->header.magic == DAPL_MAGIC_EP_EXIT);
190 
191 	/* reset magic to prevent reuse */
192 	ep_ptr->header.magic = DAPL_MAGIC_INVALID;
193 
194 	dapls_cb_free(&ep_ptr->req_buffer);
195 	dapls_cb_free(&ep_ptr->recv_buffer);
196 
197 	dapl_os_free(ep_ptr, sizeof (DAPL_EP));
198 }
199 
200 
201 /*
202  * dapl_ep_default_attrs
203  *
204  * Set default values in the parameter fields
205  *
206  * Input:
207  * 	entry point pointer
208  *
209  * Output:
210  * 	none
211  *
212  * Returns:
213  * 	none
214  *
215  */
216 void
dapli_ep_default_attrs(IN DAPL_EP * ep_ptr)217 dapli_ep_default_attrs(
218 	IN DAPL_EP		*ep_ptr)
219 {
220 	DAT_EP_ATTR		*ep_attr;
221 
222 	ep_attr = &ep_ptr->param.ep_attr;
223 	/* Set up defaults */
224 	(void) dapl_os_memzero(ep_attr, sizeof (DAT_EP_ATTR));
225 
226 	/*
227 	 * mtu and rdma sizes fixed in IB as per IBTA 1.1, 9.4.3, 9.4.4,
228 	 * 9.7.7.
229 	 */
230 	ep_attr->max_mtu_size	= 0x80000000;
231 	ep_attr->max_rdma_size	= 0x80000000;
232 
233 	ep_attr->qos		= DAT_QOS_BEST_EFFORT;
234 	ep_attr->service_type	= DAT_SERVICE_TYPE_RC;
235 	ep_attr->max_recv_dtos	= IB_IO_DEFAULT;
236 	ep_attr->max_request_dtos	= IB_IO_DEFAULT;
237 	ep_attr->max_recv_iov		= IB_IOV_DEFAULT;
238 	ep_attr->max_request_iov	= IB_IOV_DEFAULT;
239 	ep_attr->max_rdma_read_in	= IB_RDMA_DEFAULT;
240 	ep_attr->max_rdma_read_out	= IB_RDMA_DEFAULT;
241 
242 	ep_attr->request_completion_flags = DAT_COMPLETION_EVD_THRESHOLD_FLAG;
243 	ep_attr->recv_completion_flags    = DAT_COMPLETION_EVD_THRESHOLD_FLAG;
244 	/*
245 	 * Unspecified defaults:
246 	 *    - ep_privileges: No RDMA capabilities
247 	 *    - num_transport_specific_params: none
248 	 *    - transport_specific_params: none
249 	 *    - num_provider_specific_params: 0
250 	 *    - provider_specific_params: 0
251 	 */
252 }
253 
254 
255 DAT_RETURN
dapl_ep_check_recv_completion_flags(DAT_COMPLETION_FLAGS flags)256 dapl_ep_check_recv_completion_flags(
257 	DAT_COMPLETION_FLAGS	flags)
258 {
259 
260 	/*
261 	 * InfiniBand will not allow unsignaled/suppressed RECV completions,
262 	 * see the 1.0.1 spec section 10.7.3.1, 10.8.6
263 	 */
264 
265 	if ((flags & DAT_COMPLETION_UNSIGNALLED_FLAG) ||
266 	    (flags & DAT_COMPLETION_SUPPRESS_FLAG)) {
267 		return (DAT_INVALID_PARAMETER);
268 	}
269 
270 	return (DAT_SUCCESS);
271 }
272 
273 /* ARGSUSED */
274 DAT_RETURN
dapl_ep_check_request_completion_flags(DAT_COMPLETION_FLAGS flags)275 dapl_ep_check_request_completion_flags(
276 	DAT_COMPLETION_FLAGS	flags)
277 {
278 	return (DAT_SUCCESS);
279 }
280 
281 DAT_RETURN
dapl_ep_check_qos(DAT_QOS qos)282 dapl_ep_check_qos(
283 	DAT_QOS	qos)
284 {
285 	if (qos & ~(DAT_QOS_BEST_EFFORT | DAT_QOS_HIGH_THROUGHPUT |
286 	    DAT_QOS_LOW_LATENCY | DAT_QOS_ECONOMY | DAT_QOS_PREMIUM)) {
287 		return (DAT_INVALID_PARAMETER);
288 	}
289 	return (DAT_SUCCESS);
290 }
291 
292 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)293 dapl_ep_post_send_req(
294     IN	DAT_EP_HANDLE		ep_handle,
295     IN	DAT_COUNT		num_segments,
296     IN	DAT_LMR_TRIPLET		*local_iov,
297     IN	DAT_DTO_COOKIE		user_cookie,
298     IN	const DAT_RMR_TRIPLET	*remote_iov,
299     IN	DAT_COMPLETION_FLAGS	completion_flags,
300     IN  DAPL_DTO_TYPE 		dto_type,
301     IN  ib_send_op_type_t	op_type)
302 {
303 	DAPL_EP 		*ep;
304 	DAPL_COOKIE		*cookie;
305 	DAT_RETURN		dat_status;
306 
307 	if (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP)) {
308 		dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
309 		    DAT_INVALID_HANDLE_EP);
310 		goto bail;
311 	}
312 
313 	ep = (DAPL_EP *)ep_handle;
314 
315 	/*
316 	 * Synchronization ok since this buffer is only used for send
317 	 * requests, which aren't allowed to race with each other.
318 	 */
319 	dat_status = dapls_dto_cookie_alloc(&ep->req_buffer,
320 	    dto_type,
321 	    user_cookie,
322 	    &cookie);
323 	if (dat_status != DAT_SUCCESS) {
324 		goto bail;
325 	}
326 
327 	/*
328 	 * Invoke provider specific routine to post DTO
329 	 */
330 	if (num_segments != 1 ||
331 	    completion_flags != DAT_COMPLETION_DEFAULT_FLAG)
332 		dat_status = dapls_ib_post_send(ep,
333 		    op_type,
334 		    cookie,
335 		    num_segments,
336 		    local_iov,
337 		    remote_iov,
338 		    completion_flags);
339 	else
340 		dat_status = dapls_ib_post_send_one(ep,
341 		    op_type,
342 		    cookie,
343 		    local_iov,
344 		    remote_iov);
345 
346 	if (dat_status != DAT_SUCCESS) {
347 		dapls_cookie_dealloc(&ep->req_buffer, cookie);
348 	} else {
349 		dapl_os_atomic_inc(&ep->req_count);
350 	}
351 
352 bail:
353 	return (dat_status);
354 }
355 
356 
357 /*
358  * dapli_ep_timeout
359  *
360  * If this routine is invoked before a connection occurs, generate an
361  * event
362  */
363 void
dapls_ep_timeout(unsigned long arg)364 dapls_ep_timeout(
365 	unsigned long			arg)
366 {
367 	DAPL_EP		*ep_ptr;
368 
369 	dapl_dbg_log(DAPL_DBG_TYPE_CM, "--> dapls_ep_timeout! ep %lx\n", arg);
370 
371 	ep_ptr = (DAPL_EP *)arg;
372 
373 	/* reset the EP state */
374 	ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;
375 
376 	(void) dapls_evd_post_connection_event(
377 	    (DAPL_EVD *)ep_ptr->param.connect_evd_handle,
378 	    DAT_CONNECTION_EVENT_TIMED_OUT,
379 	    (DAT_HANDLE) ep_ptr,
380 	    0,
381 	    0);
382 }
383 
384 
385 /*
386  * dapls_ep_state_subtype
387  *
388  * Return the INVALID_STATE connection subtype associated with an
389  * INVALID_STATE on an EP. Strictly for error reporting.
390  */
391 DAT_RETURN_SUBTYPE
dapls_ep_state_subtype(IN DAPL_EP * ep_ptr)392 dapls_ep_state_subtype(
393     IN  DAPL_EP			*ep_ptr)
394 {
395 	DAT_RETURN_SUBTYPE	dat_status;
396 
397 	switch (ep_ptr->param.ep_state) {
398 	case DAT_EP_STATE_RESERVED:
399 	{
400 		dat_status = DAT_INVALID_STATE_EP_RESERVED;
401 		break;
402 	}
403 	case DAT_EP_STATE_PASSIVE_CONNECTION_PENDING:
404 	{
405 		dat_status = DAT_INVALID_STATE_EP_PASSCONNPENDING;
406 		break;
407 	}
408 	case DAT_EP_STATE_ACTIVE_CONNECTION_PENDING:
409 	{
410 		dat_status = DAT_INVALID_STATE_EP_ACTCONNPENDING;
411 		break;
412 	}
413 	case DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING:
414 	{
415 		dat_status = DAT_INVALID_STATE_EP_TENTCONNPENDING;
416 		break;
417 	}
418 	case DAT_EP_STATE_CONNECTED:
419 	{
420 		dat_status = DAT_INVALID_STATE_EP_CONNECTED;
421 		break;
422 	}
423 	case DAT_EP_STATE_DISCONNECT_PENDING:
424 	{
425 		dat_status = DAT_INVALID_STATE_EP_DISCPENDING;
426 		break;
427 	}
428 	case DAT_EP_STATE_DISCONNECTED:
429 	{
430 		dat_status = DAT_INVALID_STATE_EP_DISCONNECTED;
431 		break;
432 	}
433 	case DAT_EP_STATE_COMPLETION_PENDING:
434 	{
435 		dat_status = DAT_INVALID_STATE_EP_COMPLPENDING;
436 		break;
437 	}
438 	default:
439 	{
440 		dat_status = 0;
441 		break;
442 	}
443 	}
444 
445 	return (dat_status);
446 }
447 
448 
449 /*
450  * dapl_ep_create_common
451  *
452  * Common code used by dapl_ep_create and dapl_ep_create_srq
453  *
454  * Input:
455  *	ia_handle
456  *	pz_handle
457  *	recv_evd_handle (recv DTOs)
458  *	request_evd_handle (xmit DTOs)
459  *	connect_evd_handle
460  *	srq_handle
461  *	ep_attrs
462  *
463  * Output:
464  *	ep_handle
465  *
466  * Returns:
467  *	DAT_SUCCESS
468  *	DAT_INSUFFICIENT_RESOURCES
469  *	DAT_INVALID_PARAMETER
470  *	DAT_INVALID_ATTRIBUTE
471  *	DAT_MODEL_NOT_SUPPORTED
472  */
473 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)474 dapl_ep_create_common(
475 	IN	DAT_IA_HANDLE		ia_handle,
476 	IN	DAT_PZ_HANDLE		pz_handle,
477 	IN	DAT_EVD_HANDLE		recv_evd_handle,
478 	IN	DAT_EVD_HANDLE		request_evd_handle,
479 	IN	DAT_EVD_HANDLE		connect_evd_handle,
480 	IN	DAT_SRQ_HANDLE		srq_handle,
481 	IN	const DAT_EP_ATTR	*ep_attr_arg,
482 	OUT	DAT_EP_HANDLE		*ep_handle)
483 {
484 	DAPL_IA			*ia_ptr;
485 	DAPL_EP			*ep_ptr;
486 	DAT_EP_ATTR		ep_attr_limit;
487 	DAPL_EVD		*evd_ptr;
488 	DAT_RETURN		dat_status;
489 	DAT_BOOLEAN		srq_attached;
490 	DAT_EP_ATTR		*ep_attr, epa;
491 
492 	if (ep_attr_arg) {
493 		epa = *ep_attr_arg;
494 		ep_attr = &epa;
495 	} else
496 		ep_attr = NULL;
497 
498 	ia_ptr = (DAPL_IA *)ia_handle;
499 	dat_status = DAT_SUCCESS;
500 	/*
501 	 * Verify parameters
502 	 */
503 	if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) {
504 		dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
505 		    DAT_INVALID_HANDLE_IA);
506 		goto bail;
507 	}
508 
509 	/*
510 	 * Verify non-required parameters.
511 	 * N.B. Assumption: any parameter that can be
512 	 * modified by dat_ep_modify() is not strictly
513 	 * required when the EP is created
514 	 */
515 	if (pz_handle != NULL &&
516 	    DAPL_BAD_HANDLE(pz_handle, DAPL_MAGIC_PZ)) {
517 		dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
518 		    DAT_INVALID_HANDLE_PZ);
519 		goto bail;
520 	}
521 
522 	/* If connect handle is !NULL verify handle is good  */
523 	if (connect_evd_handle != DAT_HANDLE_NULL &&
524 	    (DAPL_BAD_HANDLE(connect_evd_handle, DAPL_MAGIC_EVD) ||
525 	    !(((DAPL_EVD *)connect_evd_handle)->evd_flags &
526 	    DAT_EVD_CONNECTION_FLAG))) {
527 		dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
528 		    DAT_INVALID_HANDLE_EVD_CONN);
529 		goto bail;
530 	}
531 	/* If recv_evd is !NULL, verify handle is good and flags are valid */
532 	if ((recv_evd_handle != DAT_HANDLE_NULL) &&
533 	    (DAPL_BAD_HANDLE(recv_evd_handle, DAPL_MAGIC_EVD) ||
534 	    !(((DAPL_EVD *)recv_evd_handle)->evd_flags & DAT_EVD_DTO_FLAG))) {
535 		dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
536 		    DAT_INVALID_HANDLE_EVD_RECV);
537 		goto bail;
538 	}
539 
540 	/* If req_evd is !NULL, verify handle is good and flags are valid */
541 	if ((request_evd_handle != DAT_HANDLE_NULL) &&
542 	    (DAPL_BAD_HANDLE(request_evd_handle, DAPL_MAGIC_EVD) ||
543 	    !(((DAPL_EVD *)request_evd_handle)->evd_flags &
544 	    DAT_EVD_DTO_FLAG))) {
545 		dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
546 		    DAT_INVALID_HANDLE_EVD_REQUEST);
547 		goto bail;
548 	}
549 
550 	srq_attached = DAT_FALSE;
551 
552 	/* if srq_handle is not null validate it */
553 	if (srq_handle != DAT_HANDLE_NULL) {
554 		if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) {
555 			dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
556 			    DAT_INVALID_HANDLE_SRQ);
557 			goto bail;
558 		} else if (pz_handle !=
559 		    ((DAPL_SRQ *)srq_handle)->param.pz_handle) {
560 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
561 			    DAT_INVALID_ARG2);
562 			goto bail;
563 		}
564 		srq_attached = DAT_TRUE;
565 	}
566 
567 	if (ep_handle == NULL) {
568 		dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
569 		    (srq_attached ? DAT_INVALID_ARG8 : DAT_INVALID_ARG7));
570 		goto bail;
571 	}
572 
573 	/* For EPs with SRQ ep_attr is required */
574 	if ((srq_attached && (ep_attr == NULL)) || (uintptr_t)ep_attr & 3) {
575 		dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
576 		    (srq_attached ? DAT_INVALID_ARG7 : DAT_INVALID_ARG6));
577 		goto bail;
578 	}
579 
580 	/*
581 	 * Qualify EP Attributes are legal and make sense.  Note that if one
582 	 * or both of the DTO handles are NULL, then the corresponding
583 	 * max_*_dtos must 0 as the user will not be able to post dto ops on
584 	 * the respective queue.
585 	 */
586 	if (ep_attr != NULL) {
587 		if (ep_attr->service_type != DAT_SERVICE_TYPE_RC ||
588 		    (request_evd_handle == DAT_HANDLE_NULL &&
589 		    ep_attr->max_request_dtos != 0) ||
590 		    (request_evd_handle != DAT_HANDLE_NULL &&
591 		    ep_attr->max_request_dtos == 0) ||
592 		    ep_attr->max_request_iov == 0 ||
593 		    (DAT_SUCCESS != dapl_ep_check_qos(ep_attr->qos)) ||
594 		    (DAT_SUCCESS != dapl_ep_check_recv_completion_flags(
595 		    ep_attr->recv_completion_flags))) {
596 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
597 			    (srq_attached ? DAT_INVALID_ARG7 :
598 			    DAT_INVALID_ARG6));
599 			goto bail;
600 		}
601 
602 		if (srq_attached) {
603 			if ((ep_attr->max_recv_dtos != DAT_HW_DEFAULT) ||
604 			    (ep_attr->srq_soft_hw != DAT_HW_DEFAULT)) {
605 				dat_status = DAT_ERROR(DAT_MODEL_NOT_SUPPORTED,
606 				    0);
607 				goto bail;
608 			}
609 		} else {
610 			/* These checks are needed only for EPs without SRQ */
611 			if ((recv_evd_handle == DAT_HANDLE_NULL &&
612 			    ep_attr->max_recv_dtos != 0) ||
613 			    (recv_evd_handle != DAT_HANDLE_NULL &&
614 			    ep_attr->max_recv_dtos == 0) ||
615 			    ep_attr->max_recv_iov == 0) {
616 				dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
617 				    DAT_INVALID_ARG6);
618 				goto bail;
619 			}
620 		}
621 	}
622 
623 	/* Verify the attributes against the transport */
624 	if (ep_attr != NULL) {
625 		(void) dapl_os_memzero(&ep_attr_limit, sizeof (DAT_EP_ATTR));
626 		dat_status = dapls_ib_query_hca(ia_ptr->hca_ptr,
627 		    NULL, &ep_attr_limit, NULL, NULL);
628 		if (dat_status != DAT_SUCCESS) {
629 			goto bail;
630 		}
631 		if (ep_attr->max_mtu_size > ep_attr_limit.max_mtu_size ||
632 		    ep_attr->max_rdma_size > ep_attr_limit.max_rdma_size ||
633 		    (ep_attr->max_request_dtos >
634 		    ep_attr_limit.max_request_dtos) ||
635 		    ep_attr->max_request_iov > ep_attr_limit.max_request_iov) {
636 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
637 			    (srq_attached ? DAT_INVALID_ARG7 :
638 			    DAT_INVALID_ARG6));
639 			goto bail;
640 		}
641 		/* if inlining enabled, recompute max_request_iov */
642 		if (ia_ptr->hca_ptr->max_inline_send)
643 			ep_attr->max_request_iov = dapls_ib_max_request_iov(
644 			    ep_attr->max_request_iov,
645 			    ep_attr->max_request_dtos,
646 			    ep_attr_limit.max_request_iov,
647 			    ia_ptr->hca_ptr->max_inline_send);
648 
649 		/* Only EPs without SRQ need the following check */
650 		if ((!srq_attached) &&
651 		    (ep_attr->max_recv_dtos > ep_attr_limit.max_recv_dtos) ||
652 		    (ep_attr->max_recv_iov > ep_attr_limit.max_recv_iov)) {
653 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
654 			    DAT_INVALID_ARG6);
655 			goto bail;
656 		}
657 
658 
659 	}
660 	/*
661 	 * Verify the completion flags for the EVD and the EP
662 	 */
663 
664 	evd_ptr = (DAPL_EVD *)recv_evd_handle;
665 	if (evd_ptr->completion_type == DAPL_EVD_STATE_INIT) {
666 		if (ep_attr != NULL &&
667 		    (ep_attr->recv_completion_flags ==
668 		    DAT_COMPLETION_DEFAULT_FLAG)) {
669 			evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD;
670 		} else {
671 			/*
672 			 * Currently we support only thresholds -
673 			 * eventually it'll depend on
674 			 * ep_attr->recv_completion_flags;
675 			 */
676 			evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD;
677 		}
678 	}
679 	evd_ptr = (DAPL_EVD *)request_evd_handle;
680 	if (evd_ptr->completion_type == DAPL_EVD_STATE_INIT) {
681 		if (ep_attr != NULL &&
682 		    (ep_attr->recv_completion_flags ==
683 		    DAT_COMPLETION_DEFAULT_FLAG)) {
684 			evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD;
685 		} else {
686 			/*
687 			 * Currently we support only thresholds -
688 			 * eventually it'll depend on
689 			 * ep_attr->recv_completion_flags;
690 			 */
691 			evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD;
692 		}
693 	}
694 
695 	/* Allocate EP */
696 	ep_ptr = dapl_ep_alloc(ia_ptr, ep_attr, srq_attached);
697 	if (ep_ptr == NULL) {
698 		dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
699 		    DAT_RESOURCE_MEMORY);
700 		goto bail;
701 	}
702 
703 	/*
704 	 * Fill in the EP
705 	 */
706 	ep_ptr->param.ia_handle		= ia_handle;
707 	ep_ptr->param.pz_handle		= pz_handle;
708 	ep_ptr->param.recv_evd_handle	= recv_evd_handle;
709 	ep_ptr->param.request_evd_handle = request_evd_handle;
710 	ep_ptr->param.connect_evd_handle = connect_evd_handle;
711 	ep_ptr->param.srq_handle	= srq_handle;
712 
713 	ep_ptr->srq_attached = srq_attached;
714 
715 	/*
716 	 * Make sure we handle the NULL DTO EVDs
717 	 */
718 	if (recv_evd_handle == DAT_HANDLE_NULL && ep_attr == NULL) {
719 		ep_ptr->param.ep_attr.max_recv_dtos = 0;
720 	}
721 
722 	if (request_evd_handle == DAT_HANDLE_NULL && ep_attr == NULL) {
723 		ep_ptr->param.ep_attr.max_request_dtos = 0;
724 	}
725 
726 	/*
727 	 * If the user has specified a PZ handle we allocate a QP for
728 	 * this EP; else we defer until it is assigned via ep_modify().
729 	 * As much as possible we try to keep QP creation out of the
730 	 * connect path to avoid resource errors in strange places.
731 	 */
732 	if (pz_handle != DAT_HANDLE_NULL) {
733 		/* Take a reference on the PZ handle */
734 		dapl_os_atomic_inc(&((DAPL_PZ *)pz_handle)->pz_ref_count);
735 
736 		/*
737 		 * Get a QP from the IB provider
738 		 */
739 		dat_status = dapls_ib_qp_alloc(ia_ptr, ep_ptr, ep_ptr);
740 
741 		if (dat_status != DAT_SUCCESS) {
742 			dapl_os_atomic_dec(&((DAPL_PZ *)pz_handle)->
743 			    pz_ref_count);
744 			dapl_ep_dealloc(ep_ptr);
745 			goto bail;
746 		}
747 	} else {
748 		ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED;
749 	}
750 
751 	/*
752 	 * Update ref counts. See the spec where the endpoint marks
753 	 * a data object as 'in use'
754 	 *   pz_handle: dat_pz_free, uDAPL Document, 6.6.1.2
755 	 *   evd_handles:
756 	 *
757 	 * N.B. This should really be done by a util routine.
758 	 */
759 	dapl_os_atomic_inc(&((DAPL_EVD *)connect_evd_handle)->evd_ref_count);
760 	/* Optional handles */
761 	if (recv_evd_handle != NULL) {
762 		dapl_os_atomic_inc(&((DAPL_EVD *)recv_evd_handle)->
763 		    evd_ref_count);
764 	}
765 	if (request_evd_handle != NULL) {
766 		dapl_os_atomic_inc(&((DAPL_EVD *)request_evd_handle)->
767 		    evd_ref_count);
768 	}
769 	if (srq_handle != NULL) {
770 		dapl_os_atomic_inc(&((DAPL_SRQ *)srq_handle)->srq_ref_count);
771 	}
772 
773 	/* Link it onto the IA */
774 	dapl_ia_link_ep(ia_ptr, ep_ptr);
775 
776 	*ep_handle = ep_ptr;
777 
778 bail:
779 	return (dat_status);
780 }
781 
782 /*
783  * Local variables:
784  *  c-indent-level: 4
785  *  c-basic-offset: 4
786  *  tab-width: 8
787  * End:
788  */
789