|
Packit |
857059 |
/* BEGIN_ICS_COPYRIGHT4 ****************************************
|
|
Packit |
857059 |
|
|
Packit |
857059 |
Copyright (c) 2015, Intel Corporation
|
|
Packit |
857059 |
|
|
Packit |
857059 |
Redistribution and use in source and binary forms, with or without
|
|
Packit |
857059 |
modification, are permitted provided that the following conditions are met:
|
|
Packit |
857059 |
|
|
Packit |
857059 |
* Redistributions of source code must retain the above copyright notice,
|
|
Packit |
857059 |
this list of conditions and the following disclaimer.
|
|
Packit |
857059 |
* Redistributions in binary form must reproduce the above copyright
|
|
Packit |
857059 |
notice, this list of conditions and the following disclaimer in the
|
|
Packit |
857059 |
documentation and/or other materials provided with the distribution.
|
|
Packit |
857059 |
* Neither the name of Intel Corporation nor the names of its contributors
|
|
Packit |
857059 |
may be used to endorse or promote products derived from this software
|
|
Packit |
857059 |
without specific prior written permission.
|
|
Packit |
857059 |
|
|
Packit |
857059 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
Packit |
857059 |
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
857059 |
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
Packit |
857059 |
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
Packit |
857059 |
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
Packit |
857059 |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
Packit |
857059 |
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
Packit |
857059 |
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
Packit |
857059 |
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
Packit |
857059 |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
857059 |
|
|
Packit |
857059 |
** END_ICS_COPYRIGHT4 ****************************************/
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#include <datatypes.h>
|
|
Packit |
857059 |
#include <imemory.h>
|
|
Packit |
857059 |
#include <ilist.h>
|
|
Packit |
857059 |
#include <ievent.h>
|
|
Packit |
857059 |
#include <stl_sd.h>
|
|
Packit |
857059 |
#include <sdi.h>
|
|
Packit |
857059 |
#include <subscribe.h>
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
uint32 LastClientId;
|
|
Packit |
857059 |
CLIENT_CONTROL_PARAMETERS DefaultClientParameters;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
QUICK_LIST *pClientList = NULL;
|
|
Packit |
857059 |
SPIN_LOCK *pClientListLock = NULL;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// Initialize the default parameters that clients get
|
|
Packit |
857059 |
void
|
|
Packit |
857059 |
SetDefaultClientParameters(
|
|
Packit |
857059 |
void
|
|
Packit |
857059 |
)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
DefaultClientParameters.ControlParameters.RetryCount = g_SdParams.DefaultRetryCount;
|
|
Packit |
857059 |
DefaultClientParameters.ControlParameters.Timeout = g_SdParams.DefaultRetryInterval;
|
|
Packit |
857059 |
DefaultClientParameters.ClientDebugFlags = g_SdParams.DefaultDebugFlags;
|
|
Packit |
857059 |
DefaultClientParameters.OptionFlags = g_SdParams.DefaultOptionFlags;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
SpinLockAcquire(pClientListLock);
|
|
Packit |
857059 |
LastClientId = 0;
|
|
Packit |
857059 |
SpinLockRelease(pClientListLock);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
FSTATUS
|
|
Packit |
857059 |
iba_sd_register(
|
|
Packit |
857059 |
IN OUT CLIENT_HANDLE *ClientHandle,
|
|
Packit |
857059 |
IN PCLIENT_CONTROL_PARAMETERS pClientParameters OPTIONAL
|
|
Packit |
857059 |
)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
ClientListEntry *pClientEntry;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
//
|
|
Packit |
857059 |
// Note: If the caller is running at low priority, the input pointers for
|
|
Packit |
857059 |
// the client ID and the client parameters can be pageable. If the caller
|
|
Packit |
857059 |
// is running at a high priority, it is the caller's responsibility to
|
|
Packit |
857059 |
// make sure that the pointers point to non-pageable memory.
|
|
Packit |
857059 |
//
|
|
Packit |
857059 |
|
|
Packit |
857059 |
_DBG_ENTER_LVL(_DBG_LVL_FUNC_TRACE, iba_sd_register);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
pClientEntry = (ClientListEntry*)MemoryAllocate2AndClear(sizeof(ClientListEntry), IBA_MEM_FLAG_NONE,
|
|
Packit |
857059 |
SUBNET_DRIVER_TAG);
|
|
Packit |
857059 |
if (pClientEntry == NULL)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
_DBG_ERROR(
|
|
Packit |
857059 |
("Cannot allocate memory for new client entry\n"));
|
|
Packit |
857059 |
return(FINSUFFICIENT_MEMORY);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
pClientEntry->ListItem.pObject = (void *)pClientEntry;
|
|
Packit |
857059 |
if (pClientParameters == NULL)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
_DBG_INFO(("ClientParameters is NULL, Setting Driver Defaults\n"));
|
|
Packit |
857059 |
MemoryCopy(&pClientEntry->ClientParameters, &DefaultClientParameters,
|
|
Packit |
857059 |
sizeof(pClientEntry->ClientParameters));
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
MemoryCopy(&pClientEntry->ClientParameters, pClientParameters,
|
|
Packit |
857059 |
sizeof(pClientEntry->ClientParameters));
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
QListInit(&pClientEntry->ClientTraps);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
SpinLockAcquire(pClientListLock);
|
|
Packit |
857059 |
pClientEntry->ClientId = LastClientId++;
|
|
Packit |
857059 |
//
|
|
Packit |
857059 |
// Note: We are running at the priority level of the caller. If the caller
|
|
Packit |
857059 |
// is running at low priority, the memory containing input client parameters
|
|
Packit |
857059 |
// could be pageable and may not be touched at high priority with a spin
|
|
Packit |
857059 |
// lock held. We therefor copy parameters to (non-pageable) stack location
|
|
Packit |
857059 |
// before raising priority by getting a lock
|
|
Packit |
857059 |
//
|
|
Packit |
857059 |
|
|
Packit |
857059 |
QListInsertHead(pClientList, &pClientEntry->ListItem);
|
|
Packit |
857059 |
SpinLockRelease(pClientListLock);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
//
|
|
Packit |
857059 |
// Now we are back at the caller's priority, which could be low. In that
|
|
Packit |
857059 |
// case, it is now safe to touch the caller's potentially pageable memory.
|
|
Packit |
857059 |
//
|
|
Packit |
857059 |
//*pCid = Cid;
|
|
Packit |
857059 |
*ClientHandle = (CLIENT_HANDLE)pClientEntry;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
_DBG_LEAVE_LVL( _DBG_LVL_FUNC_TRACE );
|
|
Packit |
857059 |
return(FSUCCESS);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
FSTATUS
|
|
Packit |
857059 |
iba_sd_deregister(
|
|
Packit |
857059 |
IN CLIENT_HANDLE ClientHandle
|
|
Packit |
857059 |
)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return CommonSdDeregister(ClientHandle);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
FSTATUS
|
|
Packit |
857059 |
CommonSdDeregister(
|
|
Packit |
857059 |
IN CLIENT_HANDLE ClientHandle
|
|
Packit |
857059 |
)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
ClientListEntry *pClientEntry = (ClientListEntry *)ClientHandle;
|
|
Packit |
857059 |
FSTATUS Fstatus = FNOT_FOUND;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
_DBG_ENTER_LVL(_DBG_LVL_FUNC_TRACE, iba_sd_deregister);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
SpinLockAcquire(pClientListLock);
|
|
Packit |
857059 |
// &pClientEntry->ListItem does not dereference pClientEntry
|
|
Packit |
857059 |
if(QListIsItemInList(pClientList, &pClientEntry->ListItem) == TRUE)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
QListRemoveItem(pClientList, &pClientEntry->ListItem);
|
|
Packit |
857059 |
Fstatus = FSUCCESS;
|
|
Packit |
857059 |
_DBG_INFO(("Client Entry removal passed\n"));
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
Fstatus = FNOT_FOUND;
|
|
Packit |
857059 |
_DBG_INFO(("Client Entry removal failed\n"));
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
SpinLockRelease(pClientListLock);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// Clean up CompletionList and QueryList for this clienthandle
|
|
Packit |
857059 |
if(Fstatus == FSUCCESS)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
CancelClientQueries(ClientHandle);
|
|
Packit |
857059 |
UnsubscribeClient(pClientEntry);
|
|
Packit |
857059 |
MemoryDeallocate(pClientEntry);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
_DBG_LEAVE_LVL( _DBG_LVL_FUNC_TRACE );
|
|
Packit |
857059 |
return(Fstatus);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static boolean
|
|
Packit |
857059 |
CompareClientHandle(
|
|
Packit |
857059 |
IN LIST_ITEM* pListItem,
|
|
Packit |
857059 |
IN void* Context)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return (((PQueryDetails)QListObj(pListItem))->ClientHandle == (CLIENT_HANDLE)Context);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// cancel all queries in progress for client
|
|
Packit |
857059 |
// if we remove them from the pQueryList, any subsequent responses will
|
|
Packit |
857059 |
// be discarded, same as if the query had timed out
|
|
Packit |
857059 |
// if we cancel just before completions are reported, we could find some
|
|
Packit |
857059 |
// on the completion list for this client, so we clean them up too
|
|
Packit |
857059 |
//
|
|
Packit |
857059 |
// Note that child queries are never associated to a ClientHandle.
|
|
Packit |
857059 |
// Hence we will not be cancelling any child queries here.
|
|
Packit |
857059 |
// By cancelling the parent, the child will be discarded when it comes to
|
|
Packit |
857059 |
// the head of the pChildQueryList or when its response arrives.
|
|
Packit |
857059 |
void
|
|
Packit |
857059 |
CancelClientQueries(
|
|
Packit |
857059 |
IN CLIENT_HANDLE ClientHandle
|
|
Packit |
857059 |
)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
QueryDetails *pQueryElement;
|
|
Packit |
857059 |
boolean schedule = FALSE;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
_DBG_ENTER_LVL(_DBG_LVL_FUNC_TRACE, CancelClientQueries);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// first process the Query List
|
|
Packit |
857059 |
SpinLockAcquire(&pQueryList->m_Lock);
|
|
Packit |
857059 |
while (NULL != (pQueryElement = (QueryDetails*)QListFindFromHead(
|
|
Packit |
857059 |
&pQueryList->m_List,
|
|
Packit |
857059 |
CompareClientHandle, ClientHandle)))
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
QListRemoveItem(&pQueryList->m_List, &pQueryElement->QueryListItem);
|
|
Packit |
857059 |
DEBUG_ASSERT( pQueryElement->QState != QueryDestroy);
|
|
Packit |
857059 |
DEBUG_ASSERT( pQueryElement->pParentQuery == NULL); // not a child
|
|
Packit |
857059 |
pQueryElement->ClientHandle = NULL; // disassociate from client
|
|
Packit |
857059 |
if( pQueryElement->QState == ProcessingResponse
|
|
Packit |
857059 |
|| pQueryElement->ChildProcessingResponseCount)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
DEBUG_ASSERT(pQueryElement->QState == WaitingForChildToComplete
|
|
Packit |
857059 |
|| ! pQueryElement->ChildProcessingResponseCount);
|
|
Packit |
857059 |
// RecvHandler is still holding onto pQueryElement
|
|
Packit |
857059 |
// mark state so RecvHandler will destroy it, leave off list
|
|
Packit |
857059 |
pQueryElement->QState = QueryDestroy;
|
|
Packit |
857059 |
SpinLockRelease(&pQueryList->m_Lock);
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
// no one else is using this element, we can unlock and change it
|
|
Packit |
857059 |
SpinLockRelease(&pQueryList->m_Lock);
|
|
Packit |
857059 |
if( pQueryElement->QState == WaitingForResult
|
|
Packit |
857059 |
|| pQueryElement->QState == BusyRetryDelay)
|
|
Packit |
857059 |
AtomicDecrementVoid(&Outstanding);
|
|
Packit |
857059 |
// so we don't prempt here, defer destroy to premptable context
|
|
Packit |
857059 |
pQueryElement->QState = QueryDestroy;
|
|
Packit |
857059 |
LQListInsertHead(pCompletionList, &pQueryElement->QueryListItem);
|
|
Packit |
857059 |
schedule = TRUE;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
SpinLockAcquire(&pQueryList->m_Lock);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
SpinLockRelease(&pQueryList->m_Lock);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// now process the Completion List
|
|
Packit |
857059 |
SpinLockAcquire(&pCompletionList->m_Lock);
|
|
Packit |
857059 |
while (NULL != (pQueryElement = (QueryDetails*)QListFindFromHead(
|
|
Packit |
857059 |
&pCompletionList->m_List,
|
|
Packit |
857059 |
CompareClientHandle, ClientHandle)))
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
// any items in QueryDestroy state should no longer be associated to
|
|
Packit |
857059 |
// a client. so we can assert that we are not in QueryDestroy state
|
|
Packit |
857059 |
DEBUG_ASSERT(pQueryElement->QState == QueryComplete);
|
|
Packit |
857059 |
DEBUG_ASSERT( pQueryElement->pParentQuery == NULL); // not a child
|
|
Packit |
857059 |
pQueryElement->ClientHandle = NULL; // disassociate from client
|
|
Packit |
857059 |
// so we don't prempt here, defer destroy to premptable context
|
|
Packit |
857059 |
// can leave on list
|
|
Packit |
857059 |
pQueryElement->QState = QueryDestroy;
|
|
Packit |
857059 |
SpinLockRelease(&pCompletionList->m_Lock);
|
|
Packit |
857059 |
schedule = TRUE;
|
|
Packit |
857059 |
SpinLockAcquire(&pCompletionList->m_Lock);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
SpinLockRelease(&pCompletionList->m_Lock);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// completion processing will handle defered destroys
|
|
Packit |
857059 |
if (schedule)
|
|
Packit |
857059 |
ScheduleCompletionProcessing();
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
FSTATUS
|
|
Packit |
857059 |
iba_sd_get_client_control_parameters(
|
|
Packit |
857059 |
IN CLIENT_HANDLE ClientHandle,
|
|
Packit |
857059 |
IN OUT PCLIENT_CONTROL_PARAMETERS pClientControlParameters
|
|
Packit |
857059 |
)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
FSTATUS Fstatus = FNOT_FOUND;
|
|
Packit |
857059 |
CLIENT_CONTROL_PARAMETERS ClientParams;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
_DBG_ENTER_LVL(_DBG_LVL_FUNC_TRACE, iba_sd_get_client_control_parameters);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (pClientControlParameters == NULL) {
|
|
Packit |
857059 |
_DBG_INFO(("Invalid ClientControlParameters\n"));
|
|
Packit |
857059 |
_DBG_LEAVE_LVL( _DBG_LVL_FUNC_TRACE );
|
|
Packit |
857059 |
return(FINVALID_PARAMETER);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// Note: If the caller is running at low priority, the input memory for
|
|
Packit |
857059 |
// the client parameters can be pageable. If the caller is running at a
|
|
Packit |
857059 |
// high priority, it is the caller's responsibility to make sure that the
|
|
Packit |
857059 |
// memory is non-pageable.
|
|
Packit |
857059 |
Fstatus = ValidateClientHandle(ClientHandle, &ClientParams);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// Now we are back to the caller's priority level and can safely touch
|
|
Packit |
857059 |
// the memory to which the results have to be written.
|
|
Packit |
857059 |
if (Fstatus == FSUCCESS)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
MemoryCopy(pClientControlParameters, &ClientParams,
|
|
Packit |
857059 |
sizeof(ClientParams));
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
_DBG_LEAVE_LVL( _DBG_LVL_FUNC_TRACE );
|
|
Packit |
857059 |
return(Fstatus);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
FSTATUS
|
|
Packit |
857059 |
iba_sd_set_client_control_parameters(
|
|
Packit |
857059 |
IN CLIENT_HANDLE ClientHandle,
|
|
Packit |
857059 |
IN PCLIENT_CONTROL_PARAMETERS pClientControlParameters
|
|
Packit |
857059 |
)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
FSTATUS Fstatus = FNOT_FOUND;
|
|
Packit |
857059 |
CLIENT_CONTROL_PARAMETERS ClientParams;
|
|
Packit |
857059 |
LIST_ITEM *pListItem = &((ClientListEntry *)ClientHandle)->ListItem;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
_DBG_ENTER_LVL(_DBG_LVL_FUNC_TRACE, iba_sd_set_client_control_parameters);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (pClientControlParameters == NULL)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
_DBG_INFO(("Invalid ClientControlParameters\n"));
|
|
Packit |
857059 |
_DBG_LEAVE_LVL( _DBG_LVL_FUNC_TRACE );
|
|
Packit |
857059 |
return(FINVALID_PARAMETER);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
// Note: If the caller is running at low priority, the input memory for
|
|
Packit |
857059 |
// the client parameters can be pageable. If the caller is running at a
|
|
Packit |
857059 |
// high priority, it is the caller's responsibility to make sure that the
|
|
Packit |
857059 |
// memory is non-pageable.
|
|
Packit |
857059 |
//
|
|
Packit |
857059 |
// Note: We are running at caller's priority, which may be low. In that
|
|
Packit |
857059 |
// case, the caller could have supplied us a pointer to pageable memory that
|
|
Packit |
857059 |
// cannot be touched at high priority with the spin lock held. We therefore
|
|
Packit |
857059 |
// copy the parameters first to a local (non-pageable) stack location.
|
|
Packit |
857059 |
MemoryCopy(&ClientParams, pClientControlParameters,
|
|
Packit |
857059 |
sizeof(ClientParams));
|
|
Packit |
857059 |
|
|
Packit |
857059 |
SpinLockAcquire(pClientListLock);
|
|
Packit |
857059 |
if (QListIsItemInList(pClientList, pListItem))
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
ClientListEntry *pClientEntry = (ClientListEntry*)ClientHandle;
|
|
Packit |
857059 |
Fstatus = FSUCCESS;
|
|
Packit |
857059 |
MemoryCopy(&(pClientEntry->ClientParameters), &ClientParams,
|
|
Packit |
857059 |
sizeof(pClientEntry->ClientParameters));
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
SpinLockRelease(pClientListLock);
|
|
Packit |
857059 |
_DBG_LEAVE_LVL( _DBG_LVL_FUNC_TRACE );
|
|
Packit |
857059 |
return(Fstatus);
|
|
Packit |
857059 |
}
|