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 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  *
29  * MODULE: dapl_srq.c
30  *
31  * PURPOSE: Shared Receive Queue
32  * Description: Interfaces in this file are completely described in
33  *		the DAPL 1.2 API, Chapter 6, section 5
34  *
35  */
36 
37 #include "dapl.h"
38 #include "dapl_adapter_util.h"
39 #include "dapl_ia_util.h"
40 #include "dapl_srq_util.h"
41 #include "dapl_cookie.h"
42 
43 /*
44  * dapl_srq_create
45  *
46  * uDAPL: User Direct Access Program Library Version 1.2, 6.5.1
47  *
48  * creates an instance of a Shared Receive Queue (SRQ) that is provided
49  * to the Consumer as srq_handle.
50  *
51  * Input:
52  * 	ia_handle
53  * 	pz_handle
54  * 	srq_attr
55  *
56  * Output:
57  * 	srq_handle
58  *
59  * Returns:
60  * 	DAT_SUCCESS
61  * 	DAT_INSUFFICIENT_RESOURCES
62  * 	DAT_INVALID_HANDLE
63  * 	DAT_INVALID_PARAMETER
64  * 	DAT_MODEL_NOT_SUPPORTED
65  */
66 
67 DAT_RETURN
dapl_srq_create(IN DAT_IA_HANDLE ia_handle,IN DAT_PZ_HANDLE pz_handle,IN DAT_SRQ_ATTR * srq_attr,OUT DAT_SRQ_HANDLE * srq_handle)68 dapl_srq_create(
69 	IN	DAT_IA_HANDLE ia_handle,
70 	IN	DAT_PZ_HANDLE pz_handle,
71 	IN	DAT_SRQ_ATTR *srq_attr,
72 	OUT	DAT_SRQ_HANDLE *srq_handle)
73 {
74 	DAPL_IA		*ia_ptr;
75 	DAPL_SRQ	*srq_ptr;
76 	DAT_SRQ_ATTR	srq_attr_limit;
77 	DAT_RETURN	dat_status;
78 
79 	ia_ptr = (DAPL_IA *)ia_handle;
80 	dat_status = DAT_SUCCESS;
81 	/*
82 	 * Verify parameters
83 	 */
84 	if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) {
85 		dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
86 		    DAT_INVALID_HANDLE_IA);
87 		goto bail;
88 	}
89 
90 	if ((pz_handle == NULL) || DAPL_BAD_HANDLE(pz_handle, DAPL_MAGIC_PZ)) {
91 		dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
92 		    DAT_INVALID_HANDLE_PZ);
93 		goto bail;
94 	}
95 
96 	if ((srq_attr == NULL) || ((uintptr_t)srq_attr & 3)) {
97 		dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);
98 		goto bail;
99 	}
100 
101 	if (srq_handle == NULL) {
102 		dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4);
103 		goto bail;
104 	}
105 
106 	if (srq_attr->max_recv_dtos == 0 || srq_attr->max_recv_iov == 0 ||
107 	    srq_attr->low_watermark != DAT_SRQ_LW_DEFAULT) {
108 		dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);
109 		goto bail;
110 	}
111 
112 	/* Verify the attributes against the transport */
113 	(void) dapl_os_memzero(&srq_attr_limit, sizeof (DAT_SRQ_ATTR));
114 	dat_status = dapls_ib_query_hca(ia_ptr->hca_ptr, NULL, NULL, NULL,
115 	    &srq_attr_limit);
116 	if (dat_status != DAT_SUCCESS) {
117 			goto bail;
118 	}
119 	if (srq_attr->max_recv_dtos > srq_attr_limit.max_recv_dtos ||
120 	    srq_attr->max_recv_iov > srq_attr_limit.max_recv_iov) {
121 		dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);
122 		goto bail;
123 	}
124 
125 	/* Allocate SRQ */
126 	srq_ptr = dapl_srq_alloc(ia_ptr, srq_attr);
127 	if (srq_ptr == NULL) {
128 		dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
129 		    DAT_RESOURCE_MEMORY);
130 		goto bail;
131 	}
132 
133 	/* Take a reference on the PZ handle */
134 	dapl_os_atomic_inc(&((DAPL_PZ *)pz_handle)->pz_ref_count);
135 
136 	/*
137 	 * Fill in the SRQ
138 	 */
139 	srq_ptr->param.ia_handle	= ia_handle;
140 	srq_ptr->param.srq_state	= DAT_SRQ_STATE_OPERATIONAL;
141 	srq_ptr->param.pz_handle	= pz_handle;
142 	srq_ptr->param.max_recv_dtos	= srq_attr->max_recv_dtos;
143 	srq_ptr->param.max_recv_iov	= srq_attr->max_recv_iov;
144 	srq_ptr->param.low_watermark	= DAT_SRQ_LW_DEFAULT;
145 
146 	srq_ptr->param.available_dto_count	= DAT_VALUE_UNKNOWN;
147 	srq_ptr->param.outstanding_dto_count	= 0;
148 
149 	dat_status = dapls_ib_srq_alloc(ia_ptr, srq_ptr);
150 	if (dat_status != DAT_SUCCESS) {
151 		dapl_os_atomic_dec(&((DAPL_PZ *)pz_handle)->pz_ref_count);
152 		dapl_srq_dealloc(srq_ptr);
153 		goto bail;
154 	}
155 	/* Link it onto the IA */
156 	dapl_ia_link_srq(ia_ptr, srq_ptr);
157 
158 	*srq_handle = srq_ptr;
159 bail:
160 	return (dat_status);
161 }
162 
163 /*
164  * dapl_srq_free
165  *
166  * uDAPL: User Direct Access Program Library Version 1.2, 6.5.5
167  *
168  * destroys an instance of the SRQ. The SRQ cannot be destroyed if it is
169  * in use by an EP.
170  *
171  * Input:
172  * 	srq_handle
173  *
174  * Output:
175  * 	none
176  *
177  * Returns:
178  * 	DAT_SUCCESS
179  * 	DAT_INVALID_HANDLE
180  * 	DAT_INVALID_STATE
181  */
182 
183 DAT_RETURN
dapl_srq_free(IN DAT_SRQ_HANDLE srq_handle)184 dapl_srq_free(
185 	IN	DAT_SRQ_HANDLE srq_handle)
186 {
187 	DAPL_SRQ	*srq_ptr;
188 	DAPL_IA		*ia_ptr;
189 	DAT_SRQ_PARAM	*param;
190 	DAT_RETURN	dat_status = DAT_SUCCESS;
191 
192 	if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) {
193 		dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
194 		    DAT_INVALID_HANDLE_SRQ);
195 		goto bail;
196 	}
197 
198 	srq_ptr = (DAPL_SRQ *)srq_handle;
199 	param = &srq_ptr->param;
200 	if (0 != srq_ptr->srq_ref_count) {
201 		dapl_dbg_log(DAPL_DBG_TYPE_EP,
202 		    "dapl_srq_free: Free SRQ: %p, refcnt %d\n",
203 		    srq_ptr, srq_ptr->srq_ref_count);
204 		dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
205 		    DAT_INVALID_STATE_SRQ_IN_USE);
206 		goto bail;
207 	}
208 
209 	ia_ptr = srq_ptr->header.owner_ia;
210 	param->srq_state = DAT_SRQ_STATE_ERROR;
211 
212 	dapls_ib_srq_free(ia_ptr, srq_ptr);
213 
214 	/* Remove link from the IA */
215 	dapl_ia_unlink_srq(ia_ptr, srq_ptr);
216 
217 	dapl_os_assert(param->pz_handle != NULL);
218 	dapl_os_atomic_dec(&((DAPL_PZ *)param->pz_handle)->pz_ref_count);
219 	param->pz_handle = NULL;
220 
221 	dapl_srq_dealloc(srq_ptr);
222 
223 bail:
224 	return (dat_status);
225 }
226 
227 /*
228  * dapl_srq_post_recv
229  *
230  * uDAPL: User Direct Access Program Library Version 1.2, 6.5.8
231  *
232  * posts the receive buffer that can be used for the incoming message into
233  * the local_iov by any connected EP that uses SRQ.
234  *
235  * Input:
236  * 	srq_handle
237  * 	num_segments
238  * 	local_iov
239  *	user_cookie
240  *
241  * Output:
242  * 	none
243  *
244  * Returns:
245  * 	DAT_SUCCESS
246  * 	DAT_INVALID_HANDLE
247  * 	DAT_INSUFFICIENT_RESOURCES
248  * 	DAT_INVALID_PARAMETER
249  * 	DAT_PROTECTION_VIOLATION
250  * 	DAT_PRIVILEGES_VIOLATION
251  */
252 
253 DAT_RETURN
dapl_srq_post_recv(IN DAT_SRQ_HANDLE srq_handle,IN DAT_COUNT num_segments,IN DAT_LMR_TRIPLET * local_iov,IN DAT_DTO_COOKIE user_cookie)254 dapl_srq_post_recv(
255 	IN	DAT_SRQ_HANDLE srq_handle,
256 	IN	DAT_COUNT num_segments,
257 	IN	DAT_LMR_TRIPLET *local_iov,
258 	IN	DAT_DTO_COOKIE user_cookie)
259 {
260 	DAPL_SRQ 		*srq_ptr;
261 	DAPL_COOKIE		*cookie;
262 	DAT_RETURN		dat_status;
263 
264 	dapl_dbg_log(DAPL_DBG_TYPE_API,
265 	    "dapl_srq_post_recv (%p, %d, %p, %P)\n",
266 	    srq_handle,
267 	    num_segments,
268 	    local_iov,
269 	    user_cookie.as_64);
270 
271 	if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) {
272 		dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
273 		    DAT_INVALID_HANDLE_SRQ);
274 		goto bail;
275 	}
276 
277 	srq_ptr = (DAPL_SRQ *) srq_handle;
278 
279 	/*
280 	 * Synchronization ok since this buffer is only used for receive
281 	 * requests, which aren't allowed to race with each other.
282 	 */
283 	dat_status = dapls_dto_cookie_alloc(&srq_ptr->recv_buffer,
284 	    DAPL_DTO_TYPE_RECV,
285 	    user_cookie,
286 	    &cookie);
287 	if (DAT_SUCCESS != dat_status) {
288 		goto bail;
289 	}
290 
291 	/*
292 	 * Invoke provider specific routine to post DTO
293 	 */
294 	dat_status = dapls_ib_post_srq(srq_ptr, cookie, num_segments,
295 	    local_iov);
296 
297 	if (dat_status != DAT_SUCCESS) {
298 		dapls_cookie_dealloc(&srq_ptr->recv_buffer, cookie);
299 	} else {
300 		dapl_os_atomic_inc(&srq_ptr->recv_count);
301 	}
302 
303 bail:
304 	dapl_dbg_log(DAPL_DBG_TYPE_RTN,
305 	    "dapl_srq_post_recv () returns 0x%x\n", dat_status);
306 
307 	return (dat_status);
308 }
309 
310 
311 /*
312  * dapl_srq_query
313  *
314  * uDAPL: User Direct Access Program Library Version 1.2, 6.5.6
315  *
316  * provides to the Consumer SRQ parameters. The Consumer passes in a pointer
317  * to the Consumer-allocated structures for SRQ parameters that the Provider
318  * fills.
319  *
320  * Input:
321  * 	srq_handle
322  * 	srq_param_mask
323  *
324  * Output:
325  * 	srq_param
326  *
327  * Returns:
328  * 	DAT_SUCCESS
329  * 	DAT_INVALID_HANDLE
330  * 	DAT_INVALID_PARAMETER
331  */
332 
333 DAT_RETURN
dapl_srq_query(IN DAT_SRQ_HANDLE srq_handle,IN DAT_SRQ_PARAM_MASK srq_param_mask,OUT DAT_SRQ_PARAM * srq_param)334 dapl_srq_query(
335 	IN	DAT_SRQ_HANDLE srq_handle,
336 	IN	DAT_SRQ_PARAM_MASK srq_param_mask,
337 	OUT	DAT_SRQ_PARAM *srq_param)
338 {
339 	DAPL_SRQ	    *srq_ptr;
340 	DAT_RETURN	    dat_status;
341 
342 	dat_status = DAT_SUCCESS;
343 
344 	if (srq_param_mask & ~DAT_SRQ_FIELD_ALL) {
345 		dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2);
346 		goto bail;
347 	}
348 
349 	if (NULL == srq_param) {
350 		dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);
351 		goto bail;
352 	}
353 
354 
355 	if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) {
356 		dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0);
357 		goto bail;
358 	}
359 
360 	srq_ptr = (DAPL_SRQ *)srq_handle;
361 	/* Do a struct copy */
362 	*srq_param = srq_ptr->param;
363 	/* update the outstanding dto count */
364 	srq_param->outstanding_dto_count  = srq_ptr->recv_count;
365 
366 bail:
367 	return (dat_status);
368 }
369 
370 /*
371  * dapl_srq_set_lw
372  *
373  * uDAPL: User Direct Access Program Library Version 1.2, 6.5.4
374  *
375  * sets the low watermark value for SRQ and arms SRQ for generating an
376  * asynchronous event for low watermark. An asynchronous event will be
377  * generated when the number of buffers on SRQ is below the low watermark
378  * for the first time. This may happen during this call or when an
379  * associated EP takes a buffer from the SRQ.
380  *
381  * Input:
382  * 	srq_handle
383  * 	low_watermark
384  *
385  * Output:
386  * 	none
387  *
388  * Returns:
389  * 	DAT_SUCCESS
390  * 	DAT_INVALID_HANDLE
391  * 	DAT_INVALID_PARAMETER
392  * 	DAT_MODEL_NOT_SUPPORTED
393  */
394 
395 /* ARGSUSED */
396 DAT_RETURN
dapl_srq_set_lw(IN DAT_SRQ_HANDLE srq_handle,IN DAT_COUNT low_watermark)397 dapl_srq_set_lw(
398 	IN	DAT_SRQ_HANDLE srq_handle,
399 	IN	DAT_COUNT low_watermark)
400 {
401 	return (DAT_MODEL_NOT_SUPPORTED);
402 }
403 
404 /*
405  * dapl_srq_resize
406  *
407  * uDAPL: User Direct Access Program Library Version 1.2, 6.5.7
408  *
409  * modifies the size of the queue of SRQ. Resizing of SRQ shall not cause
410  * any incoming messages on any of the EPs that use the SRQ to be lost.
411  *
412  * Input:
413  * 	srq_handle
414  * 	srq_max_recv_dto
415  *
416  * Output:
417  * 	none
418  *
419  * Returns:
420  * 	DAT_SUCCESS
421  * 	DAT_INVALID_HANDLE
422  * 	DAT_INVALID_PARAMETER
423  * 	DAT_INSUFFICIENT_RESOURCES
424  * 	DAT_INVALID_STATE
425  */
426 
427 /* ARGSUSED */
428 DAT_RETURN
dapl_srq_resize(IN DAT_SRQ_HANDLE srq_handle,IN DAT_COUNT srq_max_recv_dtos)429 dapl_srq_resize(
430 	IN	DAT_SRQ_HANDLE srq_handle,
431 	IN	DAT_COUNT srq_max_recv_dtos)
432 {
433 	DAPL_SRQ		*srq_ptr;
434 	DAT_SRQ_ATTR		srq_attr_limit;
435 	DAPL_COOKIE_BUFFER	new_cb;
436 	DAT_RETURN		dat_status;
437 
438 
439 	srq_ptr = (DAPL_SRQ *)srq_handle;
440 	dat_status = DAT_SUCCESS;
441 
442 	if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) {
443 		return (DAT_ERROR(DAT_INVALID_HANDLE, DAT_HANDLE_TYPE_SRQ));
444 	}
445 
446 	/* can't shrink below the number of outstanding recvs */
447 	if (srq_max_recv_dtos < srq_ptr->recv_count) {
448 		return (DAT_ERROR(DAT_INVALID_STATE, 0));
449 	}
450 
451 	/*
452 	 * shrinking SRQs is not supported on tavor return success without
453 	 * any modification.
454 	 */
455 	if (srq_max_recv_dtos <= srq_ptr->param.max_recv_dtos) {
456 		return (DAT_SUCCESS);
457 	}
458 
459 	/* Verify the attributes against the transport */
460 	(void) dapl_os_memzero(&srq_attr_limit, sizeof (DAT_SRQ_ATTR));
461 	dat_status = dapls_ib_query_hca(srq_ptr->header.owner_ia->hca_ptr,
462 	    NULL, NULL, NULL, &srq_attr_limit);
463 	if (dat_status != DAT_SUCCESS) {
464 		return (dat_status);
465 	}
466 
467 	if (srq_max_recv_dtos > srq_attr_limit.max_recv_dtos) {
468 		dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2);
469 		return (dat_status);
470 	}
471 
472 	dat_status = dapls_cb_resize(&srq_ptr->recv_buffer, srq_max_recv_dtos,
473 	    &new_cb);
474 	if (dat_status != DAT_SUCCESS) {
475 		return (dat_status);
476 	}
477 
478 	dat_status = dapls_ib_srq_resize(srq_ptr, srq_max_recv_dtos);
479 	if (dat_status != DAT_SUCCESS) {
480 		goto bail;
481 	}
482 
483 	dapls_cb_free(&srq_ptr->recv_buffer);
484 	srq_ptr->recv_buffer = new_cb; /* struct copy */
485 	srq_ptr->param.max_recv_dtos = srq_max_recv_dtos;
486 
487 	return (DAT_SUCCESS);
488 bail:
489 	dapls_cb_free(&new_cb);
490 
491 	return (dat_status);
492 }
493