dapl_cookie.c revision 9517:b4839b0aa7a4
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 2005 Sun Microsystems, Inc.  All rights reserved.
28 * Use is subject to license terms.
29 */
30
31/*
32 *
33 * MODULE: dapl_cookie.c
34 *
35 * PURPOSE: Manage CQE cookie structures
36 *
37 * The DAPL spec requires that all a cookies passed to a posting operation
38 * be returned in the operation's corresponding completion.
39 *
40 * Implementing this feature is complicated by the user's ability to
41 * suppress event generation for specific operations. When these operations
42 * complete successfully, the provider does not have an easy way to
43 * deallocate resources devoted to storing context data for these operations.
44 *
45 * To support this feature, a pool of memory is allocated up front large
46 * enough to hold cookie data for the maximum number of operations possible
47 * on an endpoint.
48 *
49 * Two pieces of information are maintained to manage cookie allocation:
50 *
51 * head index : index of next unallocated cookie
52 * tail index : index of last unallocated cookie
53 *
54 * Each cookie store its index in this memory pool.
55 *
56 * When an event is received, the index stored in the event's cookie will be
57 * used to update the tail. This will implicitly deallocate all of the cookies
58 * "between" the old tail and the new tail.
59 *
60 * The implementation relies on the following assumptions:
61 *
62 * - there can be only 1 thread in dat_ep_post_send(), dat_ep_post_rdma_write(),
63 *   dat_ep_post_rdma_read(), or dat_rmr_bind() at a time, therefore
64 *   dapls_cb_get() does not need to be thread safe when manipulating
65 *   request data structures.
66 *
67 * - there can be only 1 thread in dat_ep_post_recv(), therefore
68 *   dapls_cb_get() does not need to be thread safe when manipulating
69 *   receive data structures.
70 *
71 * - there can be only 1 thread generating completions for a given EP's request
72 *   opeartions, therefore dapls_cb_put() does not need to be thread safe when
73 *   manipulating request data structures.
74 *
75 * - there can be only 1 thread generating completions for a given EP's receive
76 *   opeartions therefore dapls_cb_put() does not need to be thread safe when
77 *   manipulating receive data structures.
78 *
79 * - completions are delivered in order
80 *
81 * $Id: dapl_cookie.c,v 1.13 2003/06/16 17:53:32 sjs2 Exp $
82 */
83
84#include "dapl_cookie.h"
85#include "dapl_ring_buffer_util.h"
86
87/*
88 *
89 * Function Prototypes
90 *
91 */
92
93DAT_RETURN
94dapls_cb_get(
95	DAPL_COOKIE_BUFFER		*buffer,
96	DAPL_COOKIE 		**cookie_ptr);
97
98DAT_RETURN
99dapls_cb_put(
100	DAPL_COOKIE_BUFFER		*buffer,
101	DAPL_COOKIE 		*cookie);
102
103
104/*
105 *
106 * Function Definitions
107 *
108 */
109
110/*
111 * dapls_cb_create
112 *
113 * Given a DAPL_COOKIE_BUFFER, allocate and initialize memory for
114 * the data structure.
115 *
116 * Input:
117 *	buffer		pointer to DAPL_COOKIE_BUFFER
118 *	ep		endpoint to associate with cookies
119 *	size		number of elements to allocate & manage
120 *
121 * Output:
122 *	none
123 *
124 * Returns:
125 *	DAT_SUCCESS
126 *	DAT_INSUFFICIENT_RESOURCES
127 *
128 */
129DAT_RETURN
130dapls_cb_create(
131	IN	DAPL_COOKIE_BUFFER	*buffer,
132	IN	void			*queue,
133	IN	DAPL_COOKIE_QUEUE_TYPE	type,
134	IN	DAT_COUNT		size)
135
136{
137	DAT_COUNT 			i;
138
139	/*
140	 * allocate one additional entry so that the tail
141	 * can always point at an empty location
142	 */
143	size++;
144	/* round up to multiple of 2 */
145	i = 2;
146	while (size > i) {
147	    i <<= 1;
148	}
149	size = i;
150
151	buffer->pool = dapl_os_alloc(size * sizeof (DAPL_COOKIE));
152	if (NULL != buffer->pool) {
153		buffer->pool_size = size;
154		buffer->head = 0;
155		buffer->tail = 0;
156
157		for (i = 0; i < size; i++) {
158			buffer->pool[i].index = i;
159			buffer->pool[i].queue_type = type;
160			if (type == DAPL_COOKIE_QUEUE_EP) {
161				buffer->pool[i].queue.ep = queue;
162			} else {
163				buffer->pool[i].queue.srq = queue;
164			}
165		}
166
167		return (DAT_SUCCESS);
168	} else {
169		return (DAT_INSUFFICIENT_RESOURCES);
170	}
171}
172
173/*
174 * dapls_cb_resize
175 *
176 * Given a DAPL_COOKIE_BUFFER, reallocate a larger buffer and initialize
177 * memory for the data structure from an old one
178 *
179 * Input:
180 *	curr_buffer     pointer to existing DAPL_COOKIE_BUFFER
181 *	new_size	new number of elements to allocate & manage,
182 *			has to be > current buffer's size
183 *	new_buffer	pointer to the newly allocated cookie buffer
184 *
185 * Output:
186 *	none
187 *
188 * Returns:
189 *	DAT_SUCCESS
190 *	DAT_INVALID_PARAMETER
191 *	DAT_INSUFFICIENT_RESOURCES
192 *
193 */
194DAT_RETURN
195dapls_cb_resize(
196	IN	DAPL_COOKIE_BUFFER	*curr_buffer,
197	IN	DAT_COUNT		new_size,
198	IN	DAPL_COOKIE_BUFFER	*new_buffer)
199{
200	int		index;
201	DAPL_ATOMIC	head;
202	DAPL_ATOMIC	tail;
203
204	DAT_RETURN	dat_return;
205
206	if (new_size < curr_buffer->pool_size) {
207		return (DAT_ERROR(DAT_INVALID_PARAMETER, 0));
208	}
209
210	/*
211	 * create a new cookie buffer, the queue type and queue ptr remain the
212	 * same as the curr_buffer so use the values from there
213	 */
214	dat_return = dapls_cb_create(new_buffer,
215	    curr_buffer->pool[0].queue.ptr, curr_buffer->pool[0].queue_type,
216	    new_size);
217
218	if (dat_return != DAT_SUCCESS) {
219		return (dat_return);
220	}
221
222	/* copy all the free cookies to the new buffer */
223	head = curr_buffer->head;
224	tail = curr_buffer->tail;
225	index = 0;
226	while (head != tail) {
227		new_buffer->pool[index] = curr_buffer->pool[head];
228		head = (head + 1) % curr_buffer->pool_size;
229		index++;
230	}
231	new_buffer->head = 0;
232	new_buffer->tail = index;
233
234	return (DAT_SUCCESS);
235}
236
237/*
238 * dapls_cb_free
239 *
240 * Free the data structure
241 *
242 * Input:
243 *	buffer		pointer to DAPL_COOKIE_BUFFER
244 *
245 * Output:
246 *	none
247 *
248 * Returns:
249 *	none
250 *
251 */
252void
253dapls_cb_free(
254	IN  DAPL_COOKIE_BUFFER	*buffer)
255{
256	if (NULL != buffer->pool) {
257		dapl_os_free(buffer->pool, buffer->pool_size *
258		    sizeof (DAPL_COOKIE));
259	}
260}
261
262
263/*
264 * dapls_cb_get
265 *
266 * Remove an entry from the buffer
267 *
268 * Input:
269 *	buffer		pointer to DAPL_COOKIE_BUFFER
270 *
271 * Output:
272 *      cookie_ptr 	pointer to pointer to cookie
273 *
274 * Returns:
275 *	DAT_SUCCESS
276 * 	DAT_INVALID_PARAMETER
277 *	DAT_INSUFFICIENT_RESOURCES
278 *
279 */
280DAT_RETURN
281dapls_cb_get(
282	IN  DAPL_COOKIE_BUFFER	*buffer,
283	OUT DAPL_COOKIE 		**cookie_ptr)
284{
285	DAT_RETURN	dat_status;
286	DAT_COUNT	new_head;
287
288	dapl_os_assert(NULL != cookie_ptr);
289
290	new_head = (buffer->head + 1) % buffer->pool_size;
291
292	if (new_head == buffer->tail) {
293		dat_status = DAT_INSUFFICIENT_RESOURCES;
294		goto bail;
295	} else {
296		buffer->head = new_head;
297		*cookie_ptr = &buffer->pool[buffer->head];
298		dat_status = DAT_SUCCESS;
299	}
300
301bail:
302	return (dat_status);
303}
304
305/*
306 * dapls_cb_put
307 *
308 * Add entry(s) to the buffer
309 *
310 * Input:
311 *	buffer		pointer to DAPL_COOKIE_BUFFER
312 *      cookie 		pointer to cookie
313 *
314 * Output:
315 *	entry		entry removed from the ring buffer
316 *
317 * Returns:
318 *	DAT_SUCCESS
319 *	DAT_INSUFFICIENT_EMPTY
320 *
321 */
322DAT_RETURN
323dapls_cb_put(
324	IN  DAPL_COOKIE_BUFFER	*buffer,
325	IN  DAPL_COOKIE 	*cookie)
326{
327	buffer->tail = cookie->index;
328
329	return (DAT_SUCCESS);
330}
331
332/*
333 * dapls_rmr_cookie_alloc
334 *
335 * Allocate an RMR Bind cookie
336 *
337 * Input:
338 *	buffer		pointer to DAPL_COOKIE_BUFFER
339 *      rmr 		rmr to associate with the cookie
340 *      user_cookie     user's cookie data
341 *
342 * Output:
343 *	cookie_ptr	pointer to pointer to allocated cookie
344 *
345 * Returns:
346 *	DAT_SUCCESS
347 *	DAT_INSUFFICIENT_EMPTY
348 *
349 */
350DAT_RETURN
351dapls_rmr_cookie_alloc(
352	IN DAPL_COOKIE_BUFFER	*buffer,
353	IN DAPL_RMR		*rmr,
354	IN DAT_RMR_COOKIE	user_cookie,
355	OUT DAPL_COOKIE 	**cookie_ptr)
356{
357	DAPL_COOKIE 		*cookie;
358	DAT_RETURN		dat_status;
359
360	if (DAT_SUCCESS != dapls_cb_get(buffer, &cookie)) {
361		*cookie_ptr = NULL;
362		dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
363		    DAT_RESOURCE_MEMORY);
364		goto bail;
365	}
366
367	dat_status = DAT_SUCCESS;
368	cookie->type = DAPL_COOKIE_TYPE_RMR;
369	cookie->val.rmr.rmr = rmr;
370	cookie->val.rmr.cookie = user_cookie;
371	*cookie_ptr =  cookie;
372
373bail:
374	return (dat_status);
375}
376
377
378/*
379 * dapls_dto_cookie_alloc
380 *
381 * Allocate a DTO cookie
382 *
383 * Input:
384 *	buffer		pointer to DAPL_COOKIE_BUFFER
385 * 	type 		DTO type
386 *      user_cookie     user's cookie data
387 *
388 * Output:
389 *	cookie_ptr	pointer to pointer to allocated cookie
390 *
391 * Returns:
392 *	DAT_SUCCESS
393 *	DAT_INSUFFICIENT_EMPTY
394 *
395 */
396DAT_RETURN
397dapls_dto_cookie_alloc(
398	IN DAPL_COOKIE_BUFFER	*buffer,
399	IN DAPL_DTO_TYPE	type,
400	IN DAT_DTO_COOKIE	user_cookie,
401	OUT DAPL_COOKIE		**cookie_ptr)
402{
403	DAPL_COOKIE 		*cookie;
404
405	if (DAT_SUCCESS != dapls_cb_get(buffer, &cookie)) {
406		*cookie_ptr = NULL;
407		return (DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
408		    DAT_RESOURCE_MEMORY));
409	}
410	cookie->type = DAPL_COOKIE_TYPE_DTO;
411	cookie->val.dto.type = type;
412	cookie->val.dto.cookie = user_cookie;
413	cookie->val.dto.size = 0;
414
415	*cookie_ptr = cookie;
416	return (DAT_SUCCESS);
417}
418
419void
420dapls_cookie_dealloc(
421	IN  DAPL_COOKIE_BUFFER	*buffer,
422	IN 	DAPL_COOKIE	*cookie)
423{
424	buffer->tail = cookie->index;
425}
426