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_modify.c
34  *
35  * PURPOSE: Endpoint management
36  * Description: Interfaces in this file are completely described in
37  *		the DAPL 1.0 API, Chapter 6, section 5
38  *
39  * $Id: dapl_ep_modify.c,v 1.23 2003/07/11 18:42:17 hobie16 Exp $
40  */
41 
42 #include "dapl.h"
43 #include "dapl_cookie.h"
44 #include "dapl_ep_util.h"
45 #include "dapl_adapter_util.h"
46 
47 /*
48  * Internal prototypes
49  */
50 
51 static _INLINE_ DAT_RETURN
52 dapli_ep_modify_validate_parameters(
53 	IN DAT_EP_HANDLE ep_handle,
54 	IN DAT_EP_PARAM_MASK ep_param_mask,
55 	IN const DAT_EP_PARAM *ep_param,
56 	OUT DAPL_IA **ia_ptr,
57 	OUT DAPL_EP **ep_ptr,
58 	OUT DAT_EP_ATTR	*ep_attr_ptr);
59 
60 /*
61  * dapl_ep_modify
62  *
63  * DAPL Requirements Version xxx, 6.5.6
64  *
65  * Provide the consumer parameters, including attributes and status of
66  * the Endpoint.
67  *
68  * Input:
69  *	ep_handle
70  *	ep_args_mask
71  *
72  * Output:
73  *	ep_args
74  *
75  * Returns:
76  *	DAT_SUCCESS
77  *	DAT_INVALID_PARAMETER
78  *	DAT_INVALID_ATTRIBUTE
79  *	DAT_INVALID_STATE
80  */
81 DAT_RETURN
dapl_ep_modify(IN DAT_EP_HANDLE ep_handle,IN DAT_EP_PARAM_MASK ep_param_mask,IN const DAT_EP_PARAM * ep_param)82 dapl_ep_modify(
83 	IN DAT_EP_HANDLE ep_handle,
84 	IN DAT_EP_PARAM_MASK ep_param_mask,
85 	IN const DAT_EP_PARAM *ep_param)
86 {
87 	DAPL_IA	*ia;
88 	DAPL_EP	*ep1, *ep2;
89 	DAT_EP_ATTR ep_attr1, ep_attr2;
90 	DAPL_EP	new_ep, copy_of_old_ep;
91 	DAPL_EP	alloc_ep; /* Holder for resources.  */
92 	DAPL_PZ	*tmp_pz;
93 	DAPL_EVD *tmp_evd;
94 	DAT_RETURN dat_status;
95 
96 /* Flag indicating we've allocated a new one of these.  */
97 	DAT_BOOLEAN qp_allocated = DAT_FALSE;
98 	DAT_BOOLEAN rqst_cb_allocated = DAT_FALSE;
99 	DAT_BOOLEAN recv_cb_allocated = DAT_FALSE;
100 
101 /* Flag indicating we've used (assigned to QP) a new one of these.  */
102 	DAT_BOOLEAN qp_used = DAT_FALSE;
103 	DAT_BOOLEAN rqst_cb_used = DAT_FALSE;
104 	DAT_BOOLEAN recv_cb_used = DAT_FALSE;
105 
106 	dat_status = dapli_ep_modify_validate_parameters(ep_handle,
107 	    ep_param_mask, ep_param, &ia, &ep1, &ep_attr1);
108 	if (DAT_SUCCESS != dat_status) {
109 		goto bail;
110 	}
111 
112 	/*
113 	 * Setup the alloc_ep with the appropriate parameters (primarily
114 	 * for allocating the QP.
115 	 */
116 	alloc_ep = *ep1;
117 	alloc_ep.param.ep_attr = ep_attr1;
118 	if (ep_param_mask & DAT_EP_FIELD_PZ_HANDLE) {
119 		alloc_ep.param.pz_handle = ep_param->pz_handle;
120 	}
121 
122 	if (ep_param_mask & DAT_EP_FIELD_RECV_EVD_HANDLE) {
123 		alloc_ep.param.recv_evd_handle = ep_param->recv_evd_handle;
124 	}
125 
126 	if (ep_param_mask & DAT_EP_FIELD_REQUEST_EVD_HANDLE) {
127 		alloc_ep.param.request_evd_handle =
128 		    ep_param->request_evd_handle;
129 	}
130 
131 	if (ep_param_mask & DAT_EP_FIELD_CONNECT_EVD_HANDLE) {
132 		alloc_ep.param.connect_evd_handle =
133 		    ep_param->connect_evd_handle;
134 	}
135 
136 	/*
137 	 * Allocate everything that might be needed.
138 	 * We allocate separately, and into a different "holding"
139 	 * ep, since we a) want the copy of the old ep into the new ep to
140 	 * be atomic with the assignment back (under lock), b) want the
141 	 * assignment of the allocated materials to be after the copy of the
142 	 * old ep into the new ep, and c) don't want the allocation done
143 	 * under lock.
144 	 */
145 	dat_status = dapls_cb_create(
146 	    &alloc_ep.req_buffer, ep1, DAPL_COOKIE_QUEUE_EP,
147 	    ep_attr1.max_request_dtos);
148 	if (DAT_SUCCESS != dat_status) {
149 		goto bail;
150 	}
151 	rqst_cb_allocated = DAT_TRUE;
152 
153 	if (!ep1->srq_attached) {
154 		dat_status = dapls_cb_create(&alloc_ep.recv_buffer, ep1,
155 		    DAPL_COOKIE_QUEUE_EP, ep_attr1.max_recv_dtos);
156 		if (DAT_SUCCESS != dat_status) {
157 			goto bail;
158 		}
159 		recv_cb_allocated = DAT_TRUE;
160 	}
161 
162 	dat_status = dapls_ib_qp_alloc(ia, &alloc_ep, ep1);
163 	if (dat_status != DAT_SUCCESS) {
164 		goto bail;
165 	}
166 	qp_allocated = DAT_TRUE;
167 
168 	/*
169 	 * Now we atomically modify the EP, under lock
170 	 * There's a lot of work done here, but there should be no
171 	 * allocation or blocking.
172 	 */
173 	dapl_os_lock(&ep1->header.lock);
174 
175 	/*
176 	 * Revalidate parameters; make sure that races haven't
177 	 * changed anything important.
178 	 */
179 	dat_status = dapli_ep_modify_validate_parameters(ep_handle,
180 	    ep_param_mask, ep_param, &ia, &ep2, &ep_attr2);
181 	if (DAT_SUCCESS != dat_status) {
182 		dapl_os_unlock(&ep2->header.lock);
183 		goto bail;
184 	}
185 
186 	/*
187 	 * All of the following should be impossible, if validation
188 	 * occurred.  But they're important to the logic of this routine,
189 	 * so we check.
190 	 */
191 	dapl_os_assert(ep1 == ep2);
192 	dapl_os_assert(ep_attr2.max_recv_dtos == ep_attr1.max_recv_dtos);
193 	dapl_os_assert(ep_attr2.max_request_dtos == ep_attr1.max_request_dtos);
194 
195 	copy_of_old_ep = *ep2;
196 
197 	/*
198 	 * Setup new ep.
199 	 */
200 	new_ep = *ep2;
201 	new_ep.param.ep_attr = ep_attr2;
202 
203 	/*
204 	 * We can initialize the PZ and EVD handles from the alloc_ep because
205 	 * the only thing that could have changed since we setup the alloc_ep
206 	 * is stuff changed by dapl_cr_accept, and neither PZ nor EVD is in that
207 	 * list.
208 	 */
209 	new_ep.param.pz_handle = alloc_ep.param.pz_handle;
210 	new_ep.param.recv_evd_handle = alloc_ep.param.recv_evd_handle;
211 	new_ep.param.request_evd_handle = alloc_ep.param.request_evd_handle;
212 	new_ep.param.connect_evd_handle = alloc_ep.param.connect_evd_handle;
213 
214 	/* Deal with each of the allocation fields.  */
215 	if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS &&
216 	    (ep_param->ep_attr.max_recv_dtos !=
217 	    ep2->param.ep_attr.max_recv_dtos)) {
218 		new_ep.recv_buffer = alloc_ep.recv_buffer;
219 		recv_cb_used = DAT_TRUE;
220 	}
221 
222 	if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS &&
223 	    (ep_param->ep_attr.max_request_dtos !=
224 	    ep2->param.ep_attr.max_request_dtos)) {
225 		new_ep.req_buffer = alloc_ep.req_buffer;
226 		rqst_cb_used = DAT_TRUE;
227 	}
228 
229 	/*
230 	 * We need to change the QP only if there already was a QP
231 	 * (leave things the way you found them!) and one of the
232 	 * following has changed: send/recv EVD, send/recv reqs/IOV max.
233 	 */
234 	if (DAPL_QP_STATE_UNATTACHED != new_ep.qp_state && (ep_param_mask
235 	    & (DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_IOV |
236 	    DAT_EP_FIELD_EP_ATTR_MAX_RECV_IOV |
237 	    DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS |
238 	    DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS |
239 	    DAT_EP_FIELD_RECV_EVD_HANDLE |
240 	    DAT_EP_FIELD_REQUEST_EVD_HANDLE))) {
241 		/*
242 		 * We shouldn't be racing with connection establishment
243 		 * because the parameter validate routine should protect us,
244 		 * but it's an important enough point that we assert it.
245 		 */
246 		dapl_os_assert((ep2->param.ep_state !=
247 		    DAT_EP_STATE_PASSIVE_CONNECTION_PENDING) &&
248 		    (ep2->param.ep_state !=
249 		    DAT_EP_STATE_ACTIVE_CONNECTION_PENDING));
250 
251 		new_ep.qp_handle = alloc_ep.qp_handle;
252 		new_ep.qpn = alloc_ep.qpn;
253 		qp_used = DAT_TRUE;
254 	}
255 
256 	/*
257 	 * The actual assignment, including modifying QP parameters.
258 	 * Modifying QP parameters needs to come first, as if it fails
259 	 * we need to exit.
260 	 */
261 	if (DAPL_QP_STATE_UNATTACHED != new_ep.qp_state) {
262 		dat_status = dapls_ib_qp_modify(ia, ep2, &ep_attr2);
263 		if (dat_status != DAT_SUCCESS) {
264 			dapl_os_unlock(& ep2->header.lock);
265 			goto bail;
266 		}
267 	}
268 	*ep2 = new_ep;
269 
270 	dapl_os_unlock(&ep2->header.lock);
271 
272 	/*
273 	 * Modify reference counts, incrementing new ones
274 	 * and then decrementing old ones (so if they're the same
275 	 * the refcount never drops to zero).
276 	 */
277 	tmp_pz = (DAPL_PZ *) new_ep.param.pz_handle;
278 	if (NULL != tmp_pz) {
279 		dapl_os_atomic_inc(&tmp_pz->pz_ref_count);
280 	}
281 
282 	tmp_evd = (DAPL_EVD *) new_ep.param.recv_evd_handle;
283 	if (NULL != tmp_evd) {
284 		dapl_os_atomic_inc(&tmp_evd->evd_ref_count);
285 	}
286 
287 	tmp_evd = (DAPL_EVD *) new_ep.param.request_evd_handle;
288 	if (NULL != tmp_evd) {
289 		dapl_os_atomic_inc(&tmp_evd->evd_ref_count);
290 		}
291 
292 	tmp_evd = (DAPL_EVD *) new_ep.param.connect_evd_handle;
293 	if (NULL != tmp_evd) {
294 		dapl_os_atomic_inc(&tmp_evd->evd_ref_count);
295 	}
296 
297 	/* decreament the old reference counts */
298 	tmp_pz = (DAPL_PZ *) copy_of_old_ep.param.pz_handle;
299 	if (NULL != tmp_pz) {
300 		dapl_os_atomic_dec(&tmp_pz->pz_ref_count);
301 	}
302 
303 	tmp_evd = (DAPL_EVD *) copy_of_old_ep.param.recv_evd_handle;
304 	if (NULL != tmp_evd) {
305 		dapl_os_atomic_dec(&tmp_evd->evd_ref_count);
306 	}
307 
308 	tmp_evd = (DAPL_EVD *) copy_of_old_ep.param.request_evd_handle;
309 	if (NULL != tmp_evd) {
310 		dapl_os_atomic_dec(&tmp_evd->evd_ref_count);
311 	}
312 
313 	tmp_evd = (DAPL_EVD *) copy_of_old_ep.param.connect_evd_handle;
314 	if (NULL != tmp_evd) {
315 		dapl_os_atomic_dec(&tmp_evd->evd_ref_count);
316 	}
317 
318 bail:
319 	if (qp_allocated) {
320 		DAT_RETURN local_dat_status;
321 		if (dat_status != DAT_SUCCESS || !qp_used) {
322 			local_dat_status = dapls_ib_qp_free(ia, &alloc_ep);
323 		} else {
324 			local_dat_status = dapls_ib_qp_free(ia,
325 			    &copy_of_old_ep);
326 		}
327 		if (local_dat_status != DAT_SUCCESS) {
328 			dapl_dbg_log(DAPL_DBG_TYPE_WARN,
329 			    "ep_modify: Failed to free QP; status %x\n",
330 			    local_dat_status);
331 		}
332 	}
333 
334 	if (rqst_cb_allocated) {
335 		if (dat_status != DAT_SUCCESS || !rqst_cb_used) {
336 			dapls_cb_free(&alloc_ep.req_buffer);
337 		} else {
338 			dapls_cb_free(&copy_of_old_ep.req_buffer);
339 		}
340 	}
341 
342 	if (recv_cb_allocated) {
343 		if (dat_status != DAT_SUCCESS || !recv_cb_used) {
344 			dapls_cb_free(&alloc_ep.recv_buffer);
345 		} else {
346 			dapls_cb_free(&copy_of_old_ep.recv_buffer);
347 		}
348 	}
349 
350 	return (dat_status);
351 }
352 
353 
354 /*
355  * dapli_ep_modify_validate_parameters
356  *
357  * Validate parameters
358  *
359  * The space for the ep_attr_ptr parameter should be allocated by the
360  * consumer. Upon success, this parameter will contain the current ep
361  * attribute values with the requested modifications made.
362  *
363  */
364 
365 static DAT_RETURN
dapli_ep_modify_validate_parameters(IN DAT_EP_HANDLE ep_handle,IN DAT_EP_PARAM_MASK ep_param_mask,IN const DAT_EP_PARAM * ep_param,OUT DAPL_IA ** ia_ptr,OUT DAPL_EP ** ep_ptr,OUT DAT_EP_ATTR * ep_attr_ptr)366 dapli_ep_modify_validate_parameters(
367 	IN DAT_EP_HANDLE ep_handle,
368 	IN DAT_EP_PARAM_MASK ep_param_mask,
369 	IN const DAT_EP_PARAM *ep_param,
370 	OUT DAPL_IA **ia_ptr,
371 	OUT DAPL_EP **ep_ptr,
372 	OUT DAT_EP_ATTR	*ep_attr_ptr)
373 {
374 	DAPL_IA	*ia;
375 	DAPL_EP	*ep;
376 	DAT_EP_ATTR ep_attr;
377 	DAT_EP_ATTR ep_attr_limit;
378 	DAT_EP_ATTR ep_attr_request;
379 	DAT_RETURN dat_status;
380 
381 	*ia_ptr = NULL;
382 	*ep_ptr = NULL;
383 	dat_status = DAT_SUCCESS;
384 
385 	if (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP)) {
386 		dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
387 		    DAT_INVALID_HANDLE_EP);
388 		goto bail;
389 	}
390 
391 	ep = (DAPL_EP *) ep_handle;
392 	ia = ep->header.owner_ia;
393 
394 	/*
395 	 * Verify parameters valid in current EP state
396 	 */
397 	if (ep_param_mask & (DAT_EP_FIELD_IA_HANDLE |
398 	    DAT_EP_FIELD_EP_STATE |
399 	    DAT_EP_FIELD_LOCAL_IA_ADDRESS_PTR |
400 	    DAT_EP_FIELD_LOCAL_PORT_QUAL |
401 	    DAT_EP_FIELD_REMOTE_IA_ADDRESS_PTR |
402 	    DAT_EP_FIELD_REMOTE_PORT_QUAL |
403 	    DAT_EP_FIELD_SRQ_HANDLE |
404 	    DAT_EP_FIELD_EP_ATTR_SRQ_SOFT_HW)) {
405 		dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2);
406 		goto bail;
407 	}
408 
409 	/*
410 	 * Can only change the PZ handle if we are UNCONNECTED or
411 	 * TENTATIVE_CONNECTION_PENDING(psp PROVIDER allocated EP)
412 	 */
413 	if ((ep_param_mask & DAT_EP_FIELD_PZ_HANDLE) &&
414 	    (ep->param.ep_state != DAT_EP_STATE_UNCONNECTED &&
415 	    ep->param.ep_state !=
416 	    DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING)) {
417 		dat_status = DAT_ERROR(DAT_INVALID_STATE,
418 		    dapls_ep_state_subtype(ep));
419 		goto bail;
420 	}
421 
422 	if ((ep_param_mask & (DAT_EP_FIELD_RECV_EVD_HANDLE |
423 	    DAT_EP_FIELD_REQUEST_EVD_HANDLE |
424 	    DAT_EP_FIELD_CONNECT_EVD_HANDLE |
425 	    DAT_EP_FIELD_EP_ATTR_SERVICE_TYPE |
426 	    DAT_EP_FIELD_EP_ATTR_MAX_MESSAGE_SIZE |
427 	    DAT_EP_FIELD_EP_ATTR_MAX_RDMA_SIZE |
428 	    DAT_EP_FIELD_EP_ATTR_QOS |
429 	    DAT_EP_FIELD_EP_ATTR_REQUEST_COMPLETION_FLAGS |
430 	    DAT_EP_FIELD_EP_ATTR_RECV_COMPLETION_FLAGS |
431 	    DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS |
432 	    DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS |
433 	    DAT_EP_FIELD_EP_ATTR_MAX_RECV_IOV |
434 	    DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_IOV)) &&
435 	    (ep->param.ep_state != DAT_EP_STATE_UNCONNECTED &&
436 	    ep->param.ep_state != DAT_EP_STATE_RESERVED &&
437 	    ep->param.ep_state !=
438 	    DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING)) {
439 		dat_status = DAT_ERROR(DAT_INVALID_STATE,
440 		    dapls_ep_state_subtype(ep));
441 		goto bail;
442 	}
443 
444 	/*
445 	 * Validate handles being modified
446 	 */
447 	if (ep_param_mask & DAT_EP_FIELD_PZ_HANDLE) {
448 		if (ep_param->pz_handle != NULL &&
449 		    DAPL_BAD_HANDLE(ep_param->pz_handle, DAPL_MAGIC_PZ)) {
450 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
451 			    DAT_INVALID_ARG3);
452 			goto bail;
453 		}
454 	}
455 
456 	if (ep_param_mask & DAT_EP_FIELD_RECV_EVD_HANDLE) {
457 		if (ep_param->recv_evd_handle != NULL &&
458 		    (DAPL_BAD_HANDLE(ep_param->recv_evd_handle,
459 		    DAPL_MAGIC_EVD) ||
460 		    !((DAPL_EVD *)ep_param->recv_evd_handle)->evd_flags &
461 		    DAT_EVD_DTO_FLAG)) {
462 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
463 			    DAT_INVALID_ARG3);
464 			goto bail;
465 		}
466 	}
467 
468 	if (ep_param_mask & DAT_EP_FIELD_REQUEST_EVD_HANDLE) {
469 		if (ep_param->request_evd_handle != NULL &&
470 		    DAPL_BAD_HANDLE(ep_param->request_evd_handle,
471 		    DAPL_MAGIC_EVD)) {
472 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
473 			    DAT_INVALID_ARG3);
474 			goto bail;
475 		}
476 	}
477 
478 	if (ep_param_mask & DAT_EP_FIELD_CONNECT_EVD_HANDLE) {
479 		if (ep_param->connect_evd_handle != NULL &&
480 		    DAPL_BAD_HANDLE(ep_param->connect_evd_handle,
481 		    DAPL_MAGIC_EVD) &&
482 		    !(((DAPL_EVD *)ep_param->connect_evd_handle)->evd_flags &
483 		    DAT_EVD_CONNECTION_FLAG)) {
484 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
485 			    DAT_INVALID_ARG3);
486 			goto bail;
487 		}
488 	}
489 
490 	/*
491 	 * Validate the attributes against the HCA limits
492 	 */
493 	ep_attr = ep->param.ep_attr;
494 
495 	(void) dapl_os_memzero(&ep_attr_limit, sizeof (DAT_EP_ATTR));
496 	dat_status = dapls_ib_query_hca(ia->hca_ptr, NULL,
497 	    &ep_attr_limit, NULL, NULL);
498 	if (dat_status != DAT_SUCCESS) {
499 		goto bail;
500 	}
501 
502 	ep_attr_request = ep_param->ep_attr;
503 
504 	if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_SERVICE_TYPE) {
505 		if (ep_attr_request.service_type != DAT_SERVICE_TYPE_RC) {
506 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
507 			    DAT_INVALID_ARG3);
508 			goto bail;
509 		}
510 	}
511 
512 	if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_MESSAGE_SIZE) {
513 		if (ep_attr_request.max_mtu_size > ep_attr_limit.max_mtu_size) {
514 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
515 			    DAT_INVALID_ARG3);
516 			goto bail;
517 		} else {
518 			ep_attr.max_mtu_size = ep_attr_request.max_mtu_size;
519 		}
520 	}
521 
522 	/*
523 	 * Do nothing if the DAT_EP_FIELD_EP_ATTR_MAX_RDMA_SIZE flag is
524 	 * set. Each RDMA transport/provider may or may not have a limit
525 	 * on the size of an RDMA DTO. For InfiniBand, this parameter is
526 	 * validated in the implementation of the dapls_ib_qp_modify()
527 	 * function.
528 	 */
529 	/* LINTED: E_NOP_IF_STMT */
530 	if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_QOS) {
531 		/* Do nothing, not defined in the spec yet */
532 	}
533 
534 	if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_RECV_COMPLETION_FLAGS) {
535 		dat_status = dapl_ep_check_recv_completion_flags(
536 		    ep_attr_request.recv_completion_flags);
537 		if (dat_status != DAT_SUCCESS) {
538 			goto bail;
539 		} else {
540 			ep_attr.recv_completion_flags =
541 			    ep_attr_request.recv_completion_flags;
542 		}
543 	}
544 
545 	if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_REQUEST_COMPLETION_FLAGS) {
546 		dat_status = dapl_ep_check_request_completion_flags(
547 		    ep_attr_request.request_completion_flags);
548 		if (dat_status != DAT_SUCCESS) {
549 			goto bail;
550 		} else {
551 			ep_attr.request_completion_flags =
552 			    ep_attr_request.request_completion_flags;
553 		}
554 	}
555 
556 	if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS) {
557 		if ((ep->param.srq_handle != NULL) ||
558 		    (ep_attr_request.max_recv_dtos >
559 		    ep_attr_limit.max_recv_dtos) ||
560 		    (ep_param->recv_evd_handle  == DAT_HANDLE_NULL &&
561 		    (ep_attr_request.max_recv_dtos > 0))) {
562 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
563 			    DAT_INVALID_ARG3);
564 			goto bail;
565 		} else {
566 			ep_attr.max_recv_dtos = ep_attr_request.max_recv_dtos;
567 		}
568 	}
569 
570 	if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS) {
571 		if (ep_attr_request.max_request_dtos >
572 		    ep_attr_limit.max_request_dtos ||
573 		    (ep_param->request_evd_handle  == DAT_HANDLE_NULL &&
574 		    (ep_attr_request.max_request_dtos > 0))) {
575 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
576 			    DAT_INVALID_ARG3);
577 			goto bail;
578 		} else {
579 			ep_attr.max_request_dtos =
580 			    ep_attr_request.max_request_dtos;
581 		}
582 	}
583 
584 	if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RECV_IOV) {
585 		if ((ep->param.srq_handle != NULL) ||
586 		    (ep_attr_request.max_recv_iov >
587 		    ep_attr_limit.max_recv_iov)) {
588 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
589 			    DAT_INVALID_ARG3);
590 			goto bail;
591 		} else {
592 			ep_attr.max_recv_iov = ep_attr_request.max_recv_iov;
593 		}
594 	}
595 
596 	if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_IOV) {
597 		if (ep_attr_request.max_request_iov >
598 		    ep_attr_limit.max_request_iov) {
599 			dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
600 			    DAT_INVALID_ARG3);
601 			goto bail;
602 		} else {
603 			ep_attr.max_request_iov =
604 			    ep_attr_request.max_request_iov;
605 		}
606 	}
607 
608 	*ia_ptr = ia;
609 	*ep_ptr = ep;
610 	*ep_attr_ptr = ep_attr;
611 
612 bail:
613 	return (dat_status);
614 }
615