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 
93 DAT_RETURN
94 dapls_cb_get(
95 	DAPL_COOKIE_BUFFER		*buffer,
96 	DAPL_COOKIE 		**cookie_ptr);
97 
98 DAT_RETURN
99 dapls_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  */
129 DAT_RETURN
dapls_cb_create(IN DAPL_COOKIE_BUFFER * buffer,IN void * queue,IN DAPL_COOKIE_QUEUE_TYPE type,IN DAT_COUNT size)130 dapls_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  */
194 DAT_RETURN
dapls_cb_resize(IN DAPL_COOKIE_BUFFER * curr_buffer,IN DAT_COUNT new_size,IN DAPL_COOKIE_BUFFER * new_buffer)195 dapls_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  */
252 void
dapls_cb_free(IN DAPL_COOKIE_BUFFER * buffer)253 dapls_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  */
280 DAT_RETURN
dapls_cb_get(IN DAPL_COOKIE_BUFFER * buffer,OUT DAPL_COOKIE ** cookie_ptr)281 dapls_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 
301 bail:
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  */
322 DAT_RETURN
dapls_cb_put(IN DAPL_COOKIE_BUFFER * buffer,IN DAPL_COOKIE * cookie)323 dapls_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  */
350 DAT_RETURN
dapls_rmr_cookie_alloc(IN DAPL_COOKIE_BUFFER * buffer,IN DAPL_RMR * rmr,IN DAT_RMR_COOKIE user_cookie,OUT DAPL_COOKIE ** cookie_ptr)351 dapls_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 
373 bail:
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  */
396 DAT_RETURN
dapls_dto_cookie_alloc(IN DAPL_COOKIE_BUFFER * buffer,IN DAPL_DTO_TYPE type,IN DAT_DTO_COOKIE user_cookie,OUT DAPL_COOKIE ** cookie_ptr)397 dapls_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 
419 void
dapls_cookie_dealloc(IN DAPL_COOKIE_BUFFER * buffer,IN DAPL_COOKIE * cookie)420 dapls_cookie_dealloc(
421 	IN  DAPL_COOKIE_BUFFER	*buffer,
422 	IN 	DAPL_COOKIE	*cookie)
423 {
424 	buffer->tail = cookie->index;
425 }
426