/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
*
* MODULE: dapl_cookie.c
*
* PURPOSE: Manage CQE cookie structures
*
* The DAPL spec requires that all a cookies passed to a posting operation
* be returned in the operation's corresponding completion.
*
* Implementing this feature is complicated by the user's ability to
* suppress event generation for specific operations. When these operations
* complete successfully, the provider does not have an easy way to
* deallocate resources devoted to storing context data for these operations.
*
* To support this feature, a pool of memory is allocated up front large
* enough to hold cookie data for the maximum number of operations possible
* on an endpoint.
*
* Two pieces of information are maintained to manage cookie allocation:
*
* head index : index of next unallocated cookie
* tail index : index of last unallocated cookie
*
* Each cookie store its index in this memory pool.
*
* When an event is received, the index stored in the event's cookie will be
* used to update the tail. This will implicitly deallocate all of the cookies
* "between" the old tail and the new tail.
*
* The implementation relies on the following assumptions:
*
* - there can be only 1 thread in dat_ep_post_send(), dat_ep_post_rdma_write(),
* dat_ep_post_rdma_read(), or dat_rmr_bind() at a time, therefore
* dapls_cb_get() does not need to be thread safe when manipulating
* request data structures.
*
* - there can be only 1 thread in dat_ep_post_recv(), therefore
* dapls_cb_get() does not need to be thread safe when manipulating
* receive data structures.
*
* - there can be only 1 thread generating completions for a given EP's request
* opeartions, therefore dapls_cb_put() does not need to be thread safe when
* manipulating request data structures.
*
* - there can be only 1 thread generating completions for a given EP's receive
* opeartions therefore dapls_cb_put() does not need to be thread safe when
* manipulating receive data structures.
*
* - completions are delivered in order
*
* $Id: dapl_cookie.c,v 1.13 2003/06/16 17:53:32 sjs2 Exp $
*/
#include "dapl_cookie.h"
#include "dapl_ring_buffer_util.h"
/*
*
* Function Prototypes
*
*/
DAT_RETURN
dapls_cb_get(
DAPL_COOKIE_BUFFER *buffer,
DAPL_COOKIE **cookie_ptr);
DAT_RETURN
dapls_cb_put(
DAPL_COOKIE_BUFFER *buffer,
DAPL_COOKIE *cookie);
/*
*
* Function Definitions
*
*/
/*
* dapls_cb_create
*
* Given a DAPL_COOKIE_BUFFER, allocate and initialize memory for
* the data structure.
*
* Input:
* buffer pointer to DAPL_COOKIE_BUFFER
* ep endpoint to associate with cookies
* size number of elements to allocate & manage
*
* Output:
* none
*
* Returns:
* DAT_SUCCESS
* DAT_INSUFFICIENT_RESOURCES
*
*/
DAT_RETURN
dapls_cb_create(
IN DAPL_COOKIE_BUFFER *buffer,
IN void *queue,
IN DAPL_COOKIE_QUEUE_TYPE type,
IN DAT_COUNT size)
{
DAT_COUNT i;
/*
* allocate one additional entry so that the tail
* can always point at an empty location
*/
size++;
/* round up to multiple of 2 */
i = 2;
while (size > i) {
i <<= 1;
}
size = i;
buffer->pool = dapl_os_alloc(size * sizeof (DAPL_COOKIE));
if (NULL != buffer->pool) {
buffer->pool_size = size;
buffer->head = 0;
buffer->tail = 0;
for (i = 0; i < size; i++) {
buffer->pool[i].index = i;
buffer->pool[i].queue_type = type;
if (type == DAPL_COOKIE_QUEUE_EP) {
buffer->pool[i].queue.ep = queue;
} else {
buffer->pool[i].queue.srq = queue;
}
}
return (DAT_SUCCESS);
} else {
return (DAT_INSUFFICIENT_RESOURCES);
}
}
/*
* dapls_cb_resize
*
* Given a DAPL_COOKIE_BUFFER, reallocate a larger buffer and initialize
* memory for the data structure from an old one
*
* Input:
* curr_buffer pointer to existing DAPL_COOKIE_BUFFER
* new_size new number of elements to allocate & manage,
* has to be > current buffer's size
* new_buffer pointer to the newly allocated cookie buffer
*
* Output:
* none
*
* Returns:
* DAT_SUCCESS
* DAT_INVALID_PARAMETER
* DAT_INSUFFICIENT_RESOURCES
*
*/
DAT_RETURN
dapls_cb_resize(
IN DAPL_COOKIE_BUFFER *curr_buffer,
IN DAT_COUNT new_size,
IN DAPL_COOKIE_BUFFER *new_buffer)
{
int index;
DAPL_ATOMIC head;
DAPL_ATOMIC tail;
DAT_RETURN dat_return;
if (new_size < curr_buffer->pool_size) {
return (DAT_ERROR(DAT_INVALID_PARAMETER, 0));
}
/*
* create a new cookie buffer, the queue type and queue ptr remain the
* same as the curr_buffer so use the values from there
*/
dat_return = dapls_cb_create(new_buffer,
curr_buffer->pool[0].queue.ptr, curr_buffer->pool[0].queue_type,
new_size);
if (dat_return != DAT_SUCCESS) {
return (dat_return);
}
/* copy all the free cookies to the new buffer */
head = curr_buffer->head;
tail = curr_buffer->tail;
index = 0;
while (head != tail) {
new_buffer->pool[index] = curr_buffer->pool[head];
head = (head + 1) % curr_buffer->pool_size;
index++;
}
new_buffer->head = 0;
new_buffer->tail = index;
return (DAT_SUCCESS);
}
/*
* dapls_cb_free
*
* Free the data structure
*
* Input:
* buffer pointer to DAPL_COOKIE_BUFFER
*
* Output:
* none
*
* Returns:
* none
*
*/
void
dapls_cb_free(
IN DAPL_COOKIE_BUFFER *buffer)
{
if (NULL != buffer->pool) {
dapl_os_free(buffer->pool, buffer->pool_size *
sizeof (DAPL_COOKIE));
}
}
/*
* dapls_cb_get
*
* Remove an entry from the buffer
*
* Input:
* buffer pointer to DAPL_COOKIE_BUFFER
*
* Output:
* cookie_ptr pointer to pointer to cookie
*
* Returns:
* DAT_SUCCESS
* DAT_INVALID_PARAMETER
* DAT_INSUFFICIENT_RESOURCES
*
*/
DAT_RETURN
dapls_cb_get(
IN DAPL_COOKIE_BUFFER *buffer,
OUT DAPL_COOKIE **cookie_ptr)
{
DAT_RETURN dat_status;
DAT_COUNT new_head;
dapl_os_assert(NULL != cookie_ptr);
new_head = (buffer->head + 1) % buffer->pool_size;
if (new_head == buffer->tail) {
dat_status = DAT_INSUFFICIENT_RESOURCES;
goto bail;
} else {
buffer->head = new_head;
*cookie_ptr = &buffer->pool[buffer->head];
dat_status = DAT_SUCCESS;
}
bail:
return (dat_status);
}
/*
* dapls_cb_put
*
* Add entry(s) to the buffer
*
* Input:
* buffer pointer to DAPL_COOKIE_BUFFER
* cookie pointer to cookie
*
* Output:
* entry entry removed from the ring buffer
*
* Returns:
* DAT_SUCCESS
* DAT_INSUFFICIENT_EMPTY
*
*/
DAT_RETURN
dapls_cb_put(
IN DAPL_COOKIE_BUFFER *buffer,
IN DAPL_COOKIE *cookie)
{
buffer->tail = cookie->index;
return (DAT_SUCCESS);
}
/*
* dapls_rmr_cookie_alloc
*
* Allocate an RMR Bind cookie
*
* Input:
* buffer pointer to DAPL_COOKIE_BUFFER
* rmr rmr to associate with the cookie
* user_cookie user's cookie data
*
* Output:
* cookie_ptr pointer to pointer to allocated cookie
*
* Returns:
* DAT_SUCCESS
* DAT_INSUFFICIENT_EMPTY
*
*/
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)
{
DAPL_COOKIE *cookie;
DAT_RETURN dat_status;
if (DAT_SUCCESS != dapls_cb_get(buffer, &cookie)) {
*cookie_ptr = NULL;
dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
DAT_RESOURCE_MEMORY);
goto bail;
}
dat_status = DAT_SUCCESS;
cookie->type = DAPL_COOKIE_TYPE_RMR;
cookie->val.rmr.rmr = rmr;
cookie->val.rmr.cookie = user_cookie;
*cookie_ptr = cookie;
bail:
return (dat_status);
}
/*
* dapls_dto_cookie_alloc
*
* Allocate a DTO cookie
*
* Input:
* buffer pointer to DAPL_COOKIE_BUFFER
* type DTO type
* user_cookie user's cookie data
*
* Output:
* cookie_ptr pointer to pointer to allocated cookie
*
* Returns:
* DAT_SUCCESS
* DAT_INSUFFICIENT_EMPTY
*
*/
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)
{
DAPL_COOKIE *cookie;
if (DAT_SUCCESS != dapls_cb_get(buffer, &cookie)) {
*cookie_ptr = NULL;
return (DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
DAT_RESOURCE_MEMORY));
}
cookie->type = DAPL_COOKIE_TYPE_DTO;
cookie->val.dto.type = type;
cookie->val.dto.cookie = user_cookie;
cookie->val.dto.size = 0;
*cookie_ptr = cookie;
return (DAT_SUCCESS);
}
void
dapls_cookie_dealloc(
IN DAPL_COOKIE_BUFFER *buffer,
IN DAPL_COOKIE *cookie)
{
buffer->tail = cookie->index;
}