Blame IbAccess/Common/Ibt/Sma/ibnotify.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
#include "ibnotify.h"
Packit 857059
Packit 857059
//
Packit 857059
// Globals
Packit 857059
//
Packit 857059
IBT_NOTIFY_GROUP	NotifyGroup;
Packit 857059
Packit 857059
Packit 857059
//
Packit 857059
// Initialize the Notify Group
Packit 857059
//
Packit 857059
//INPUT:
Packit 857059
// 	Callback - when a new User is added to the Notify group, this routine
Packit 857059
//		is called to distribute initial events to User
Packit 857059
void
Packit 857059
IbtInitNotifyGroup (
Packit 857059
   IN	IB_ROOT_CALLBACK		Callback
Packit 857059
   )
Packit 857059
{
Packit 857059
	_DBG_ENTER_LVL( _DBG_LVL_IBT_API, IbtInitNotifyGroup );
Packit 857059
Packit 857059
	ASSERT(! NotifyGroup.Initialized);
Packit 857059
Packit 857059
	MapInitState( &NotifyGroup.Lists );
Packit 857059
	SpinLockInitState( &NotifyGroup.Lock );
Packit 857059
Packit 857059
	if (MapInit( &NotifyGroup.Lists ) != FSUCCESS)
Packit 857059
	{
Packit 857059
		_DBG_ERROR (("Failed to Initialize Notification Map\n"));
Packit 857059
		goto done;
Packit 857059
	}
Packit 857059
	if (SpinLockInit( &NotifyGroup.Lock ) == FALSE)
Packit 857059
	{
Packit 857059
		_DBG_ERROR (("Failed to Initialize Notification lock\n"));
Packit 857059
		goto faillock;
Packit 857059
	}
Packit 857059
Packit 857059
	// Add root callback for new users
Packit 857059
	ASSERT ( Callback );
Packit 857059
	NotifyGroup.RootCallback = Callback;
Packit 857059
Packit 857059
	NotifyGroup.Initialized = TRUE;
Packit 857059
Packit 857059
done:
Packit 857059
	_DBG_LEAVE_LVL(_DBG_LVL_IBT_API);
Packit 857059
	return;
Packit 857059
Packit 857059
faillock:
Packit 857059
	MapDestroy ( &NotifyGroup.Lists );
Packit 857059
	goto done;
Packit 857059
}
Packit 857059
Packit 857059
Packit 857059
//
Packit 857059
// Cleanup for shutdown
Packit 857059
void
Packit 857059
IbtDestroyNotifyGroup ( void )
Packit 857059
{
Packit 857059
	QUICK_LIST				*pList;
Packit 857059
Packit 857059
	_DBG_ENTER_LVL( _DBG_LVL_IBT_API, IbtDestroyNotifyGroup );
Packit 857059
Packit 857059
	if (! NotifyGroup.Initialized)
Packit 857059
		goto done;
Packit 857059
Packit 857059
	// Empty list contents
Packit 857059
	SpinLockAcquire( &NotifyGroup.Lock );
Packit 857059
Packit 857059
	while (NULL != (pList = (QUICK_LIST*)MapRemoveHead(&NotifyGroup.Lists)))
Packit 857059
	{
Packit 857059
		LIST_ITEM				*pListItem;
Packit 857059
Packit 857059
		while (NULL != (pListItem = QListRemoveHead(pList)))
Packit 857059
		{
Packit 857059
			IBT_NOTIFY_USER_BLOCK	*pUser = (IBT_NOTIFY_USER_BLOCK *)pListItem;
Packit 857059
			MemoryDeallocate( pUser );
Packit 857059
		}	
Packit 857059
		QListDestroy(pList);
Packit 857059
		MemoryDeallocate(pList);
Packit 857059
	}
Packit 857059
	NotifyGroup.Initialized = FALSE;
Packit 857059
Packit 857059
	SpinLockRelease( &NotifyGroup.Lock );
Packit 857059
Packit 857059
	MapDestroy( &NotifyGroup.Lists );
Packit 857059
	SpinLockDestroy( &NotifyGroup.Lock );
Packit 857059
Packit 857059
done:
Packit 857059
	_DBG_LEAVE_LVL(_DBG_LVL_IBT_API);
Packit 857059
}
Packit 857059
Packit 857059
// Notify all users in pList of pRec event
Packit 857059
void
Packit 857059
IbtNotifyList(
Packit 857059
	QUICK_LIST				*pList,
Packit 857059
	IB_NOTIFY_RECORD		*pRec
Packit 857059
	 )
Packit 857059
{
Packit 857059
	LIST_ITEM				*pListFirst;
Packit 857059
	IBT_NOTIFY_USER_BLOCK	*pUser;
Packit 857059
Packit 857059
	pListFirst = QListHead( pList );
Packit 857059
			
Packit 857059
	while (pListFirst)
Packit 857059
	{
Packit 857059
		// If event has been subscribed by user, notify
Packit 857059
		if ( pRec->EventType & ((IBT_NOTIFY_USER_BLOCK *)pListFirst)->EventMask)
Packit 857059
		{
Packit 857059
			pUser = (IBT_NOTIFY_USER_BLOCK *)pListFirst;
Packit 857059
			pRec->Context = pUser->Context;
Packit 857059
			if (pUser->Locking == IB_NOTIFY_ASYNC)
Packit 857059
			{
Packit 857059
				pUser->RefCount++;
Packit 857059
				SpinLockRelease( &NotifyGroup.Lock );
Packit 857059
				( pUser->Callback )( *pRec );
Packit 857059
				SpinLockAcquire( &NotifyGroup.Lock );
Packit 857059
				pListFirst = QListNext( pList, pListFirst );
Packit 857059
				if (--(pUser->RefCount) == 0)
Packit 857059
				{
Packit 857059
					QListRemoveItem ( pList, &pUser->ListItem );
Packit 857059
					MemoryDeallocate( pUser );
Packit 857059
				}
Packit 857059
				continue;
Packit 857059
			} else {
Packit 857059
				ASSERT(pUser->RefCount);
Packit 857059
				( pUser->Callback )( *pRec );
Packit 857059
			}
Packit 857059
		}
Packit 857059
		pListFirst = QListNext( pList, pListFirst );
Packit 857059
	}
Packit 857059
}
Packit 857059
Packit 857059
// Notify all registered clients of an event against the given Guid
Packit 857059
void
Packit 857059
IbtNotifyGroup (
Packit 857059
	IN	EUI64				Guid,			// Port/Node GUID
Packit 857059
	IN	IB_NOTIFY_TYPE		EventType		// Type of event being reported
Packit 857059
	)
Packit 857059
{
Packit 857059
	IB_NOTIFY_RECORD		Rec;
Packit 857059
	QUICK_LIST*				pList;
Packit 857059
Packit 857059
	_DBG_ENTER_LVL( _DBG_LVL_IBT_API, IbtNotifyGroup );
Packit 857059
Packit 857059
	_DBG_PRINT( _DBG_LVL_IBT_API,(
Packit 857059
				"NotifyGroup\n"
Packit 857059
				"\tEventType...:%"PRIxN"\n"
Packit 857059
				"\tGUID........:x%016"PRIx64"\n",
Packit 857059
				EventType, 
Packit 857059
				Guid ));
Packit 857059
Packit 857059
	if (! NotifyGroup.Initialized)
Packit 857059
		goto done;
Packit 857059
Packit 857059
	// Fill in common record info
Packit 857059
	Rec.Guid = Guid;
Packit 857059
	Rec.EventType = EventType;
Packit 857059
Packit 857059
	SpinLockAcquire( &NotifyGroup.Lock );
Packit 857059
		
Packit 857059
	// iterate on List in Map for Guid, then map for Guid==0
Packit 857059
	pList = (QUICK_LIST*)MapGet(&NotifyGroup.Lists, Guid);
Packit 857059
	if (pList != NULL)
Packit 857059
	{
Packit 857059
		IbtNotifyList(pList, &Rec;;
Packit 857059
	}
Packit 857059
Packit 857059
	pList = (QUICK_LIST*)MapGet(&NotifyGroup.Lists, 0);
Packit 857059
	if (pList != NULL)
Packit 857059
	{
Packit 857059
		IbtNotifyList(pList, &Rec;;
Packit 857059
	}
Packit 857059
Packit 857059
	SpinLockRelease( &NotifyGroup.Lock );
Packit 857059
Packit 857059
done:
Packit 857059
	_DBG_LEAVE_LVL(_DBG_LVL_IBT_API);
Packit 857059
}
Packit 857059
Packit 857059
// Send a notification to a single registered notify client
Packit 857059
// used as part of RootCallback to send initial events to a newly
Packit 857059
// registered client
Packit 857059
// returns FALSE if client has deregistered itself in callback
Packit 857059
boolean
Packit 857059
IbtNotifyUserEvent (
Packit 857059
	IN	void				*UserContext,
Packit 857059
	IN	EUI64				Guid,			// Port/Node GUID
Packit 857059
	IN	IB_NOTIFY_TYPE		EventType		// Type of event being reported
Packit 857059
	)
Packit 857059
{
Packit 857059
	IB_NOTIFY_RECORD		Rec;
Packit 857059
	IBT_NOTIFY_USER_BLOCK	*pUser = (IBT_NOTIFY_USER_BLOCK*)UserContext;
Packit 857059
Packit 857059
	_DBG_ENTER_LVL( _DBG_LVL_IBT_API, IbtNotifyUserEvent );
Packit 857059
Packit 857059
	_DBG_PRINT( _DBG_LVL_IBT_API,(
Packit 857059
			"NotifyGroup\n"
Packit 857059
			"\tEventType...:%"PRIxN"\n"
Packit 857059
			"\tGUID........:x%016"PRIx64"\n",
Packit 857059
			EventType, 
Packit 857059
			Guid ));
Packit 857059
Packit 857059
	if (! NotifyGroup.Initialized)
Packit 857059
	{
Packit 857059
		pUser = NULL;	// no more notifications needed
Packit 857059
		goto done;
Packit 857059
	}
Packit 857059
Packit 857059
	// Fill in common record info
Packit 857059
	Rec.Guid = Guid;
Packit 857059
	Rec.EventType = EventType;
Packit 857059
Packit 857059
	SpinLockAcquire( &NotifyGroup.Lock );
Packit 857059
Packit 857059
	// If event has been subscribed by user, notify
Packit 857059
	if ( ( EventType & pUser->EventMask )
Packit 857059
		&& (pUser->Guid == 0 || pUser->Guid == Guid))
Packit 857059
	{
Packit 857059
		Rec.Context = pUser->Context;
Packit 857059
		if (pUser->Locking == IB_NOTIFY_ASYNC)
Packit 857059
		{
Packit 857059
			pUser->RefCount++;
Packit 857059
			SpinLockRelease( &NotifyGroup.Lock );
Packit 857059
			( pUser->Callback )( Rec );
Packit 857059
			SpinLockAcquire( &NotifyGroup.Lock );
Packit 857059
			if (--(pUser->RefCount) == 0)
Packit 857059
			{
Packit 857059
				QUICK_LIST*				pList;
Packit 857059
Packit 857059
				pList = (QUICK_LIST*)MapGet(&NotifyGroup.Lists, pUser->Guid);
Packit 857059
				if (pList != NULL)
Packit 857059
					QListRemoveItem ( pList, &pUser->ListItem );
Packit 857059
				MemoryDeallocate( pUser );
Packit 857059
				pUser = NULL;
Packit 857059
			}
Packit 857059
		} else {
Packit 857059
			ASSERT(pUser->RefCount);
Packit 857059
			( pUser->Callback )( Rec );
Packit 857059
		}
Packit 857059
	} 
Packit 857059
Packit 857059
	SpinLockRelease( &NotifyGroup.Lock );
Packit 857059
Packit 857059
done:
Packit 857059
	_DBG_LEAVE_LVL(_DBG_LVL_IBT_API);
Packit 857059
	return (pUser != NULL);
Packit 857059
}
Packit 857059
Packit 857059
Packit 857059
Packit 857059
//
Packit 857059
// iba_register_notify
Packit 857059
//
Packit 857059
//	The caller uses this API to register for notifications of IB type events
Packit 857059
//
Packit 857059
//
Packit 857059
// INPUTS:
Packit 857059
//
Packit 857059
//	Callback		-Callback routine to be registered for notifications
Packit 857059
//
Packit 857059
//	Context			-User specified context to return in callbacks
Packit 857059
//	
Packit 857059
//	EventMask		-Mask to subscribe to event types
Packit 857059
//
Packit 857059
//	Locking			-locking model for callback
Packit 857059
//
Packit 857059
//
Packit 857059
//
Packit 857059
// OUTPUTS:
Packit 857059
//
Packit 857059
//	NotifyHandle	-Notification handle on successful registration
Packit 857059
//
Packit 857059
//
Packit 857059
// RETURNS:
Packit 857059
//
Packit 857059
//	FSUCCESS
Packit 857059
//	FINSUFFICIENT_MEMORY
Packit 857059
//
Packit 857059
//
Packit 857059
FSTATUS
Packit 857059
iba_register_notify (
Packit 857059
	IN	IB_NOTIFY_CALLBACK	Callback,
Packit 857059
	IN	void				*Context,
Packit 857059
	IN	IB_NOTIFY_TYPE		EventMask,
Packit 857059
	IN	IB_NOTIFY_LOCKING	Locking,
Packit 857059
	OUT	IB_HANDLE			*NotifyHandle
Packit 857059
	)
Packit 857059
{
Packit 857059
	FSTATUS					status	= FSUCCESS;
Packit 857059
	
Packit 857059
	_DBG_ENTER_LVL( _DBG_LVL_IBT_API, iba_register_notify );
Packit 857059
	status = iba_register_guid_notify(0, Callback, Context, EventMask, Locking, NotifyHandle);
Packit 857059
	_DBG_LEAVE_LVL(_DBG_LVL_IBT_API);
Packit 857059
	return status;
Packit 857059
}
Packit 857059
Packit 857059
Packit 857059
//
Packit 857059
// iba_register_guid_notify
Packit 857059
//
Packit 857059
//	The caller uses this API to register for notifications of IB type events
Packit 857059
//
Packit 857059
//
Packit 857059
// INPUTS:
Packit 857059
//
Packit 857059
//	Guid			-Guid user is interested in
Packit 857059
//
Packit 857059
//	Callback		-Callback routine to be registered for notifications
Packit 857059
//
Packit 857059
//	Context			-User specified context to return in callbacks
Packit 857059
//	
Packit 857059
//	EventMask		-Mask to subscribe to event types
Packit 857059
//
Packit 857059
//	Locking			-locking model for callback
Packit 857059
//
Packit 857059
//
Packit 857059
//
Packit 857059
// OUTPUTS:
Packit 857059
//
Packit 857059
//	NotifyHandle	-Notification handle on successful registration
Packit 857059
//
Packit 857059
//
Packit 857059
// RETURNS:
Packit 857059
//
Packit 857059
//	FSUCCESS
Packit 857059
//	FINSUFFICIENT_MEMORY
Packit 857059
//
Packit 857059
//
Packit 857059
FSTATUS
Packit 857059
iba_register_guid_notify (
Packit 857059
	IN  EUI64				Guid,
Packit 857059
	IN	IB_NOTIFY_CALLBACK	Callback,
Packit 857059
	IN	void				*Context,
Packit 857059
	IN	IB_NOTIFY_TYPE		EventMask,
Packit 857059
	IN	IB_NOTIFY_LOCKING	Locking,
Packit 857059
	OUT	IB_HANDLE			*NotifyHandle
Packit 857059
	)
Packit 857059
{
Packit 857059
	FSTATUS					status	= FSUCCESS;
Packit 857059
	IBT_NOTIFY_USER_BLOCK	*pUser;
Packit 857059
	QUICK_LIST *pList;
Packit 857059
	
Packit 857059
	_DBG_ENTER_LVL( _DBG_LVL_IBT_API, iba_register_notify );
Packit 857059
Packit 857059
	if (! NotifyGroup.Initialized)
Packit 857059
	{
Packit 857059
		status = FINVALID_STATE;
Packit 857059
		goto done;
Packit 857059
	}
Packit 857059
Packit 857059
	// Allocate memory to hold user registration
Packit 857059
	pUser = (IBT_NOTIFY_USER_BLOCK*)MemoryAllocateAndClear(
Packit 857059
										sizeof(IBT_NOTIFY_USER_BLOCK), FALSE,
Packit 857059
										IBT_NOTIFY_TAG );
Packit 857059
	if ( !pUser )
Packit 857059
	{
Packit 857059
		status = FINSUFFICIENT_MEMORY;
Packit 857059
		_DBG_ERROR(("%s\n", _DBG_PTR(FSTATUS_MSG(status))));
Packit 857059
		goto done;
Packit 857059
	}
Packit 857059
Packit 857059
	// Fill in user details
Packit 857059
	pUser->Guid = Guid;	// all Guids
Packit 857059
	pUser->Callback = Callback;
Packit 857059
	pUser->Context = Context;
Packit 857059
	pUser->RefCount = 1;
Packit 857059
	pUser->EventMask = EventMask;
Packit 857059
	pUser->Locking = Locking;
Packit 857059
Packit 857059
	// Save user list in group
Packit 857059
	SpinLockAcquire( &NotifyGroup.Lock );
Packit 857059
	pList = (QUICK_LIST*)MapGet(&NotifyGroup.Lists, Guid);
Packit 857059
	if (pList == NULL)
Packit 857059
	{
Packit 857059
		pList = (QUICK_LIST*)MemoryAllocateAndClear( sizeof(QUICK_LIST), FALSE,
Packit 857059
										IBT_NOTIFY_TAG );
Packit 857059
		QListInitState(pList);
Packit 857059
		if (! QListInit(pList))
Packit 857059
		{
Packit 857059
			status = FINSUFFICIENT_RESOURCES;
Packit 857059
			goto faillist;
Packit 857059
		}
Packit 857059
		status = MapInsert(&NotifyGroup.Lists, Guid, pList);
Packit 857059
		if (status != FSUCCESS)
Packit 857059
		{
Packit 857059
			goto failmap;
Packit 857059
		}
Packit 857059
	}
Packit 857059
	QListInsertHead( pList, &pUser->ListItem );
Packit 857059
	SpinLockRelease( &NotifyGroup.Lock );
Packit 857059
Packit 857059
	*NotifyHandle = pUser;
Packit 857059
Packit 857059
	_DBG_PRINT(_DBG_LVL_IBT_API,("Created entry x%p\n", _DBG_PTR(pUser)));
Packit 857059
Packit 857059
	if (EventMask & IB_NOTIFY_ON_REGISTER)
Packit 857059
	{
Packit 857059
		// Notify Root to pass user initial events
Packit 857059
		ASSERT (( NotifyGroup.RootCallback ));
Packit 857059
		( NotifyGroup.RootCallback )( pUser );
Packit 857059
	}
Packit 857059
Packit 857059
done:
Packit 857059
	_DBG_LEAVE_LVL(_DBG_LVL_IBT_API);
Packit 857059
	return status;
Packit 857059
Packit 857059
failmap:
Packit 857059
	QListDestroy(pList);
Packit 857059
faillist:
Packit 857059
	MemoryDeallocate(pList);
Packit 857059
	goto done;
Packit 857059
}
Packit 857059
Packit 857059
Packit 857059
Packit 857059
//
Packit 857059
// iba_deregister_notify 
Packit 857059
//
Packit 857059
//	The caller uses this API to Deregister previously registered notifications
Packit 857059
//
Packit 857059
//
Packit 857059
// INPUTS:
Packit 857059
//
Packit 857059
//	NotifyHandle		-Handle returned on successful registration
Packit 857059
//
Packit 857059
//
Packit 857059
//
Packit 857059
// OUTPUTS:
Packit 857059
//
Packit 857059
//
Packit 857059
//
Packit 857059
// RETURNS:
Packit 857059
//
Packit 857059
//	FSUCCESS
Packit 857059
//	FINVALID_PARAMETER
Packit 857059
//	FINSUFFICIENT_MEMORY
Packit 857059
//
Packit 857059
//
Packit 857059
FSTATUS
Packit 857059
iba_deregister_notify (
Packit 857059
	IN 	IB_HANDLE			NotifyHandle
Packit 857059
	)
Packit 857059
{
Packit 857059
	FSTATUS					status	= FSUCCESS;
Packit 857059
	IBT_NOTIFY_USER_BLOCK	*pUser	= (IBT_NOTIFY_USER_BLOCK*)NotifyHandle;
Packit 857059
	QUICK_LIST				*pList;
Packit 857059
Packit 857059
Packit 857059
	_DBG_ENTER_LVL( _DBG_LVL_IBT_API, iba_deregister_notify );
Packit 857059
Packit 857059
	if (! NotifyGroup.Initialized)
Packit 857059
	{
Packit 857059
		// could have never registered if we didn't initialize
Packit 857059
		status = FINVALID_PARAMETER;
Packit 857059
		goto done;
Packit 857059
	}
Packit 857059
	SpinLockAcquire( &NotifyGroup.Lock );
Packit 857059
	pList = (QUICK_LIST*)MapGet(&NotifyGroup.Lists, pUser->Guid);
Packit 857059
	ASSERT(pList);
Packit 857059
	if ( !QListIsItemInList( pList, &pUser->ListItem ) )
Packit 857059
	{
Packit 857059
		status = FINVALID_PARAMETER;
Packit 857059
		_DBG_ERROR(("Could not deregister. Notification is not in List!!!\n"));
Packit 857059
		goto done;
Packit 857059
	}
Packit 857059
	if (pUser->Locking == IB_NOTIFY_ASYNC)
Packit 857059
	{
Packit 857059
		if (--(pUser->RefCount) != 0)
Packit 857059
		{
Packit 857059
			// in use in callback
Packit 857059
			goto done;
Packit 857059
		}
Packit 857059
	} else {
Packit 857059
		ASSERT(pUser->RefCount == 1);
Packit 857059
	}
Packit 857059
Packit 857059
	QListRemoveItem ( pList, &pUser->ListItem );
Packit 857059
	MemoryDeallocate( pUser );
Packit 857059
Packit 857059
done:
Packit 857059
	SpinLockRelease( &NotifyGroup.Lock );
Packit 857059
Packit 857059
	_DBG_LEAVE_LVL(_DBG_LVL_IBT_API);
Packit 857059
	return status;
Packit 857059
}