Blame IbAccess/Common/SubnetDriver/client.c

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
}