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