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 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 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 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 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 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 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 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 420 dapls_cookie_dealloc( 421 IN DAPL_COOKIE_BUFFER *buffer, 422 IN DAPL_COOKIE *cookie) 423 { 424 buffer->tail = cookie->index; 425 } 426