windows-nt/Source/XPSP1/NT/net/1394/nic/sys/bcm.c
2020-09-26 16:20:57 +08:00

2797 lines
78 KiB
C

//
// Copyright (c) 1998-1999, Microsoft Corporation, all rights reserved
//
// bcm.c
//
// IEEE1394 mini-port/call-manager driver
//
// Bradcast Channel Manager
//
// 07/05/99 ADube - Created - Declaration for miniport routines
//
#include <precomp.h>
#pragma hdrstop
//
// Local Prototypes
//
VOID
nicUpdateLocalHostNodeAddress (
IN PADAPTERCB
);
//
// Local functions
//
VOID
nicBCMReset (
IN PADAPTERCB pAdapter
)
/*++
Routine Description:
Resets the Bus with the force root flag.
Only if there are remote nodes present on the bus
Arguments:
pAdapter
Return Value:
--*/
{
BOOLEAN NoRemoteNodes = FALSE;
TRACE( TL_T, TM_Bcm, ( "==> nicBCMReset " ) );
ADAPTER_ACQUIRE_LOCK (pAdapter);
NoRemoteNodes = IsListEmpty (&pAdapter->PDOList);
ADAPTER_RELEASE_LOCK (pAdapter);
//
// Do not reset the bus if there are no remote nodes present
//
if (NoRemoteNodes == TRUE)
{
return;
}
//
//Reset the bus
//
TRACE( TL_I, TM_Bcm, ( " RESETTING WITH FORCE ROOT") );
nicBusReset( pAdapter , BUS_RESET_FLAGS_FORCE_ROOT);
TRACE( TL_T, TM_Bcm, ( "<== nicBCMReset " ) );
}
VOID
nicBCRAccessedCallback (
IN PNOTIFICATION_INFO pNotificationInfo
)
// Function Description:
// This is the callback function invoked whenever another node
// tries to access the local host's BCR
// The value of the BCR is set elsewhere. So this function simply returns
//
// Arguments
// Adapter - this is passed to the workitem
//
//
// Return Value:
// Failure if allocation of workitem failed
//
{
UNALIGNED NETWORK_CHANNELSR* pBCR = NULL;
PADAPTERCB pAdapter = (PADAPTERCB) pNotificationInfo->Context;
PBROADCAST_CHANNEL_DATA pBCRData = &pAdapter->BCRData;
TRACE( TL_T, TM_Bcm, ( "==> nicBCRAccessedCallback NotificationInfo %x", pNotificationInfo) );
TRACE( TL_V, TM_Bcm, ( " pMdl %x", pNotificationInfo->Mdl) );
TRACE( TL_V, TM_Bcm, ( " SourceID %x", ((PASYNC_PACKET)pNotificationInfo->RequestPacket)->AP_Source_ID) );
pBCR = (NETWORK_CHANNELSR*) NIC_GET_SYSTEM_ADDRESS_FOR_MDL(pNotificationInfo->Mdl);
ASSERT (pNotificationInfo->Mdl == pAdapter->BCRData.AddressRangeContext.pMdl);
switch (pNotificationInfo->fulNotificationOptions)
{
case NOTIFY_FLAGS_AFTER_READ:
{
TRACE( TL_V, TM_Bcm, ( " LocalHost's BCR is READ") );
if ( pBCRData->Flags & BCR_ChannelAllocated)
{
TRACE( TL_V, TM_Bcm, ( " BCR_ChannelAllocated Flag Set ") );
}
else
{
TRACE( TL_V, TM_Bcm, ( " BCR_ChannelAllocated Flag Not Set ") );
}
ASSERT ( pAdapter->BCRData.LocalHostBCRBigEndian & BCR_IMPLEMENTED_BIG_ENDIAN);
TRACE( TL_V, TM_Bcm, ( " pBCR %x", pBCR) );
TRACE( TL_I, TM_Bcm, ( " BCR Accessed %x", *pBCR) );
break;
}
case NOTIFY_FLAGS_AFTER_LOCK:
{
TRACE( TL_V, TM_Bcm, ( " LocalHost's BCR is being Locked to") );
//
// knowingly fall into AsyncWrite
//
}
case NOTIFY_FLAGS_AFTER_WRITE:
{
ULONG LocalHostBCRLittleEndian;
TRACE( TL_V, TM_Bcm, ( " LocalHost's BCR is being Written to") );
//
// Update local data structures.
//
LocalHostBCRLittleEndian = SWAPBYTES_ULONG (pAdapter->BCRData.LocalHostBCRBigEndian);
pBCR = (NETWORK_CHANNELSR*)(&LocalHostBCRLittleEndian);
TRACE( TL_V, TM_Bcm, ( " pBCR %x", pBCR) );
TRACE( TL_V, TM_Bcm, ( " BCR %x", *pBCR) );
if ( BCR_IS_VALID (pBCR) == TRUE)
{
ADAPTER_ACQUIRE_LOCK(pAdapter);
pAdapter->BCRData.IRM_BCR.NC_One =1;
pAdapter->BCRData.IRM_BCR.NC_Valid =1;
pAdapter->BCRData.IRM_BCR.NC_Channel = pBCR->NC_Channel;
BCR_SET_FLAG (pAdapter,BCR_LocalHostBCRUpdated);
ADAPTER_RELEASE_LOCK(pAdapter);
nicSetEventMakeCall(pAdapter);
TRACE( TL_I, TM_Bcm, ( " IRM_BCR Accessed %x", pAdapter->BCRData.IRM_BCR) );
}
break;
}
default :
{
ASSERT (0);
break;
}
}
TRACE( TL_T, TM_Bcm, ( "<== nicBCRAccessedCallback NotificationInfo %x", pNotificationInfo) );
}
VOID
nicBCMAddRemoteNode (
IN PADAPTERCB pAdapter,
IN BOOLEAN fIsOnlyRemoteNode
)
/*++
Routine Description:
This is the BCM algorithm - It finds out if the local host is the IRM and goes into the appropriate code path.
Due to network conditions, this can quietly fail if all other remedies fail
Arguments:
pAdapter - Adapter
Generation - Generation associated with this iteration of the algorithm
Return Value:
None -
--*/
{
BOOLEAN fDoBcm = FALSE;
ULONG Generation = 0;
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
TRACE( TL_T, TM_Bcm, ( "==>nicBCMAddRemoteNode pAdapter %x, fIsOnlyRemoteNode %x ", pAdapter, fIsOnlyRemoteNode ) );
NdisStatus = nicGetGenerationCount (pAdapter, &Generation);
//
// Do not schedule the BCM, if the have a valid BCR for the current generation
//
if (NdisStatus == NDIS_STATUS_SUCCESS &&
(BCR_IS_VALID (&pAdapter->BCRData.IRM_BCR) == TRUE) &&
Generation == pAdapter->Generation )
{
fDoBcm = FALSE;
}
else
{
fDoBcm = TRUE;
}
#ifdef INTEROP
//
// The Samsung driver wants us to write to its BCR if it is not the IRM
//
fDoBcm = TRUE;
#endif // !INTEROP
TRACE( TL_T, TM_Bcm, ( " nicBCMAddRemoteNode fDoBCM%x ", fDoBcm) );
//
// Set An Event so a waiting BCM thread (in FindIrmAmongRemoteNodes) can
// be schduled to run
//
ADAPTER_ACQUIRE_LOCK (pAdapter);
BCR_CLEAR_FLAG (pAdapter, BCR_LastNodeRemoved);
if (fDoBcm == TRUE)
{
//
// if the BCM is already in progress, mark it as dirty
//
BCR_SET_FLAG (pAdapter, BCR_NewNodeArrived);
pAdapter->BCRData.BCRWaitForNewRemoteNode.EventCode = Nic1394EventCode_NewNodeArrived;
NdisSetEvent( &pAdapter->BCRData.BCRWaitForNewRemoteNode.NdisEvent);
}
ADAPTER_RELEASE_LOCK (pAdapter);
if (fDoBcm == TRUE)
{
TRACE( TL_A, TM_Bcm , ("Add RemoteNode- scheduling the BCM" ) );
nicScheduleBCMWorkItem(pAdapter);
}
//
// now do the media connectivity stuff
//
if (fIsOnlyRemoteNode == TRUE)
{
//
// WE have media connectivity
//
pAdapter->MediaConnectStatus = NdisMediaStateConnected;
nicMIndicateStatus( pAdapter, NDIS_STATUS_MEDIA_CONNECT, NULL, 0);
}
TRACE( TL_T, TM_Bcm, ( "<== nicBCMAddRemoteNode ") );
}
VOID
nicBCMAlgorithm(
PADAPTERCB pAdapter,
ULONG BcmGeneration
)
/*++
Routine Description:
Execute the BCM algorithm.
Finds out if the current host Is IRM
If YES then inform remote nodes and exit
if NO then find the remote node and read its BCR.
Reasons for abort - New Node Arrival or Invalid Generation caused by a BusReset
If no remote nodes are present and this node is the IRM it will allocate the b channel and exit
Arguments:
pAdapter - paDapter
BCMGeneration - Generation at which the BCM was started
Return Value:
--*/
{
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
PREMOTE_NODE pRemoteNode= NULL;
PREMOTE_NODE pIRMRemoteNode = NULL;
PTOPOLOGY_MAP pTopologyMap = NULL;
ULONG Length = DEFAULT_TOPOLOGY_MAP_LENGTH;
PVOID pTopologyBuffer = NULL;
NODE_ADDRESS LocalNodeAddress;
BOOLEAN fIsLocalHostIrm = FALSE;
ULONG TopologyGeneration = 0;
PVOID pOldTopologyMap = NULL;
STORE_CURRENT_IRQL;
ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
TRACE( TL_T, TM_Bcm, ( "==>nicBCMAlgorithm pAdapter %x, BcmGen %x", pAdapter, BcmGeneration ) );
do
{
ASSERT (BCR_TEST_FLAG (pAdapter, BCR_BCMInProgress) == TRUE);
//
// find out if the local host is the IRM and update the generation count as well
//
NdisStatus = nicIsLocalHostTheIrm ( pAdapter,
&fIsLocalHostIrm,
&pTopologyMap,
&LocalNodeAddress);
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
TRACE( TL_A, TM_Bcm, ( " nicBCMAlgorithm: nicIsLocalHostTheIrm FAILED ") );
break;
}
//
// Update the adapter structure
//
TopologyGeneration = pTopologyMap->TOP_Generation;
if (TopologyGeneration != BcmGeneration)
{
TRACE( TL_A, TM_Bcm, ( " TopologyGeneration %x, BcmGeneration %x", TopologyGeneration, BcmGeneration) );
break;
}
ADAPTER_ACQUIRE_LOCK (pAdapter);
ASSERT (pAdapter->Generation == pTopologyMap->TOP_Generation);
pAdapter->BCRData.LocalNodeAddress = LocalNodeAddress;
pOldTopologyMap = pAdapter->BCRData.pTopologyMap;
pAdapter->BCRData.pTopologyMap = pTopologyMap;
pAdapter->BCRData.LocalNodeNumber = LocalNodeAddress.NA_Node_Number;
pAdapter->NodeAddress = LocalNodeAddress;
//
// Temporary
//
pAdapter->Generation = pTopologyMap->TOP_Generation;
BcmGeneration = pTopologyMap->TOP_Generation;
ADAPTER_RELEASE_LOCK (pAdapter);
//
// Free the Old Topology Map
//
if (pOldTopologyMap != NULL)
{
FREE_NONPAGED(pOldTopologyMap);
}
//
// Now Start the BCM algorithm
//
if (fIsLocalHostIrm == TRUE)
{
pAdapter->BCRData.Flags |= BCR_LocalHostIsIRM;
ASSERT (pTopologyMap->TOP_Node_Count-1 == LocalNodeAddress.NA_Node_Number);
TRACE( TL_V, TM_Bcm, ( " LOCAL HOST IS IRM ") );
NdisStatus = nicLocalHostIsIrm (pAdapter);
}
else
{
TRACE( TL_V, TM_Bcm, ( " LOCAL HOST IS NOT IRM ") );
NdisStatus = nicLocalHostIsNotIrm( pAdapter,
BcmGeneration );
}
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
TRACE( TL_V, TM_Bcm, ( " nicBCMAlogrithm: nicLocalHostIsNotIrm or nicLocalHostIsIrm FAILED") );
break;
}
//
// Marks the end of the BCM algorithm . Do the clean up work.
// Check for the last node going away. , Release any pending make calls
// and set up the Gasp Header
//
nicMakeGaspHeader (pAdapter, &pAdapter->GaspHeader);
nicBCMCheckLastNodeRemoved(pAdapter);
nicSetEventMakeCall (pAdapter);
} while (FALSE);
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
NIC1394_LOG_PKT(pAdapter,
NIC1394_LOGFLAGS_BCM_FAILED,
pAdapter->Generation,
fIsLocalHostIrm ,
&NdisStatus,
sizeof (NDIS_STATUS));
BCR_SET_FLAG (pAdapter, BCR_BCMFailed);
}
TRACE( TL_T, TM_Bcm, ( "<==nicBCMAlgorithm %x ", NdisStatus ) );
MATCH_IRQL;
}
VOID
nicBCMAlgorithmWorkItem(
PNDIS_WORK_ITEM pWorkItem,
PVOID pContext
)
/*++
Routine Description:
The function kicks of the BCM algorithm.
Restarts the BCM if a reset occurred during the BCM algorithm.
Arguments:
Adapter - localhost
Return Value:
--*/
{
PADAPTERCB pAdapter = (PADAPTERCB)pContext;
ULONG BcmGeneration = pAdapter->Generation;
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
ULONG Generation;
BOOLEAN fRestartBCM = FALSE;
BOOLEAN fFreeBCR = FALSE;
BOOLEAN fFlagSetByThisThread = FALSE;
STORE_CURRENT_IRQL;
TRACE( TL_T, TM_Bcm, ( "==>nicBCMAlgorithmWorkItem pAdapter %x, Generation %x", pAdapter, BcmGeneration ) );
//
// Ensure that only one thread gets into the BCM algorithm and
// all other threads are returned immediately
//
ADAPTER_ACQUIRE_LOCK (pAdapter);
//
// If the BCR is being freed, then don't touch it
//
if (BCR_TEST_FLAGS (pAdapter, (BCR_Freed |BCR_BCRNeedsToBeFreed ) )== TRUE)
{
// Do Nothing, this thread will simply exit
//
}
else
{
//
// The BCR is active,
// If there is no other thread running the BCM algorithm, then this thread should set
// the BCMInProgress flag
//
if (BCR_TEST_FLAG (pAdapter, BCR_BCMInProgress ) == FALSE )
{
BCR_SET_FLAG (pAdapter, BCR_BCMInProgress );
fFlagSetByThisThread = TRUE;
}
}
ADAPTER_RELEASE_LOCK (pAdapter);
do
{
//
// First check to see if we have a valid reason to stop
//
if (fFlagSetByThisThread == FALSE)
{
break;
}
ADAPTER_ACQUIRE_LOCK (pAdapter);
//
// If there are no remote nodes then mark the BCR as so
//
if (IsListEmpty (&pAdapter->PDOList) == TRUE )
{
TRACE (TL_V, TM_Bcm, ("No Nodes present" ) );
BCR_SET_FLAG (pAdapter, BCR_NoNodesPresent);
}
else
{
BCR_CLEAR_FLAG (pAdapter, BCR_NoNodesPresent);
}
//
// Clear the two flags which cause us to restart the BCM
//
ADAPTER_CLEAR_FLAG (pAdapter, fADAPTER_InvalidGenerationCount) ;
BCR_CLEAR_FLAG (pAdapter, BCR_NewNodeArrived );
ADAPTER_RELEASE_LOCK (pAdapter);
do
{
NdisStatus = nicGetGenerationCount (pAdapter, &Generation) ;
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
TRACE( TL_T, TM_Bcm, ( " nicGetGenerationCount , Generation %x", pAdapter, BcmGeneration ) );
break;
}
//
// If the BCM is freed then exit
//
if ((BCR_TEST_FLAGS (pAdapter, BCR_Freed | BCR_BCRNeedsToBeFreed )== TRUE) )
{
break;
}
//
// Update the generation count
//
BcmGeneration = Generation;
pAdapter->Generation = Generation;
//
// Update the remote nodes table
//
nicUpdateRemoteNodeTable (pAdapter);
nicUpdateLocalHostNodeAddress (pAdapter);
if ( ADAPTER_TEST_FLAG (pAdapter, fADAPTER_InvalidGenerationCount) == TRUE)
{
//
// The local host has been reset since the start of the loop. Break
// out and restart
//
break;
}
//
// Now start the BCM
//
if (BCR_TEST_FLAG (pAdapter, BCR_LocalHostBCRUpdated ) == FALSE)
{
//
// We need to go and do the BCM because our registers have not been updated
//
nicBCMAlgorithm(pAdapter, BcmGeneration);
}
else
{
//
// Our BCR was written to
//
ULONG LocalHostBCRLittleEndian ;
NETWORK_CHANNELSR* pBCR;
ASSERT (BCR_TEST_FLAG (pAdapter, BCR_LocalHostBCRUpdated ) == TRUE);
//
// Update the IRM_BCR so we have a record of the new BCM
//
ADAPTER_ACQUIRE_LOCK (pAdapter);
NdisZeroMemory (&pAdapter->BCRData.IRM_BCR, sizeof (NETWORK_CHANNELSR) );
LocalHostBCRLittleEndian = SWAPBYTES_ULONG (pAdapter->BCRData.LocalHostBCRBigEndian);
ASSERT ((LocalHostBCRLittleEndian & BCR_VALID_LITTLE_ENDIAN) == BCR_VALID_LITTLE_ENDIAN);
pBCR = (NETWORK_CHANNELSR*)(&LocalHostBCRLittleEndian);
pAdapter->BCRData.IRM_BCR.NC_Channel = pBCR->NC_Channel ; // bits 0-5
pAdapter->BCRData.IRM_BCR.NC_Valid = pBCR->NC_Valid ; // bit 30
pAdapter->BCRData.IRM_BCR.NC_One = pBCR->NC_One ;
ADAPTER_RELEASE_LOCK (pAdapter);
}
} while (FALSE);
//
// Check to see if another Bus Reset has come in.
// if so we need to restart the BCM
//
ADAPTER_ACQUIRE_LOCK (pAdapter);
BCR_CLEAR_FLAG (pAdapter, BCR_BCMInProgress);
//
// if the generation is bad the BCR is not being freed initialzed then restart the BCM
//
TRACE( TL_V, TM_Bcm, ( "pAdapter Flags %x, BCM flags %x, BCM %x", pAdapter->ulFlags, pAdapter->BCRData.Flags, pAdapter->BCRData.IRM_BCR) );
//
// If the BCR is getting freed , set the flag and break, then we cannot loop back, we must exit
//
if (BCR_TEST_FLAGS (pAdapter, (BCR_Freed |BCR_BCRNeedsToBeFreed ) )== TRUE)
{
//
// As the BCM is about to be freed, this run of the BCM should terminate
// and free the BCR
//
fRestartBCM = FALSE;
fFreeBCR = TRUE;
ADAPTER_RELEASE_LOCK (pAdapter);
break;
}
//
// We need to do the bcm again, if a reset has occurred or a new node has arrived
//
if ((ADAPTER_TEST_FLAG (pAdapter, fADAPTER_InvalidGenerationCount) == TRUE) ||
(BCR_TEST_FLAG (pAdapter, BCR_NewNodeArrived)== TRUE) )
{
//
// Invalidate the BCR and restart
//
pAdapter->BCRData.IRM_BCR.NC_Valid = 0;
//
// We are going to try again. Update the flags
//
BCR_CLEAR_FLAG (pAdapter, BCR_BCMFailed | BCR_LocalHostBCRUpdated | BCR_LocalHostIsIRM | BCR_NewNodeArrived );
//
// As this thread is going ot retry thr BCM, it must block all new entrants again
//
BCR_SET_FLAG (pAdapter, BCR_BCMInProgress);
fRestartBCM = TRUE;
TRACE( TL_V, TM_Bcm, ( "Restart BCM TRUE ") );
}
else
{
//
// We do not retart the BCM has completed
//
TRACE( TL_V, TM_Bcm, ( "Restart BCM FALSE") );
fRestartBCM = FALSE;
}
ADAPTER_RELEASE_LOCK (pAdapter);
if ((fRestartBCM == TRUE) &&
(BCR_TEST_FLAGS (pAdapter, BCR_ChannelAllocated) == TRUE))
{
TRACE (TL_V, TM_Bcm, ("Free Channel %x", pAdapter->BCRData.LocallyAllocatedChannel ));
nicFreeChannel (pAdapter, pAdapter->BCRData.LocallyAllocatedChannel );
}
//
// fSimply Exit is also false, and will allow this thread to execute again
//
}while (fRestartBCM == TRUE) ;
if (fFlagSetByThisThread == TRUE)
{
if ( BCR_TEST_FLAG (pAdapter, BCR_BCRNeedsToBeFreed) == FALSE)
{
//
// If we are not freeing the BCR, then the adapter is still valid.
// Update the local Host Node Address, so that we have the latest information
// from the bus.
//
nicUpdateLocalHostNodeAddress (pAdapter);
nicUpdateRemoteNodeTable (pAdapter);
}
}
//
// Does the BCR need to be freed by this thread. Only threads that have been
// given a chance to execute the bcm, should be able to free the BCR
//
if (fFreeBCR == TRUE)
{
nicFreeBroadcastChannelRegister (pAdapter);
}
//
// Dereference the adapter . reference was added for the work item
//
nicDereferenceAdapter (pAdapter, "nicBCMAlgorithmWorkItem ");
FREE_NONPAGED (pWorkItem);
TRACE( TL_T, TM_Bcm, ( "<==nicBCMAlgorithmWorkItem fRestartBCM %x", fRestartBCM) );
MATCH_IRQL;
}
VOID
nicBCMAbort (
IN PADAPTERCB pAdapter,
IN PREMOTE_NODE pRemoteNode
)
// Function Description:
// This function is called when the BCM aborts. It should release the allocated channel
//
// Arguments
// pAdapter - Current local Host
//
// Return Value:
//
{
BOOLEAN fNeedToFreeChannel = FALSE;
PBROADCAST_CHANNEL_DATA pBCRData = &pAdapter->BCRData;
TRACE( TL_T, TM_Bcm, ( "==>nicBCMAbort pAdapter %x", pAdapter) );
ADAPTER_ACQUIRE_LOCK (pAdapter);
if ( BCR_TEST_FLAG (pAdapter, BCR_InformingRemoteNodes) == TRUE)
{
fNeedToFreeChannel = TRUE;
BCR_CLEAR_FLAG (pAdapter, BCR_ChannelAllocated);
BCR_CLEAR_FLAG (pAdapter, BCR_InformingRemoteNodes);
}
else
{
fNeedToFreeChannel = FALSE;
}
ADAPTER_RELEASE_LOCK (pAdapter);
if (fNeedToFreeChannel == TRUE)
{
nicFreeChannel ( pAdapter,
pBCRData->LocallyAllocatedChannel);
}
pBCRData->LocallyAllocatedChannel = INVALID_CHANNEL;
TRACE( TL_T, TM_Bcm, ( "<==nicBCMAbort " ) );
}
VOID
nicBCMCheckLastNodeRemoved(
IN PADAPTERCB pAdapter
)
// Function Description:
// Called from the BCMAlgorithm code path
// Check to see if the last node has gone away during the algorithm.
// If it has then turn off the valid bit.
//
// Arguments
// pADpater - Local host
//
// Return Value:
//
{
TRACE( TL_T, TM_Bcm, ( "==> nicBCMCheckLastNodeRemoved pAdapter %x", pAdapter ) );
TRACE( TL_T, TM_Bcm, ( "<== nicBCMCheckLastNodeRemoved " ) );
}
NDIS_STATUS
nicFindIrmAmongRemoteNodes (
IN PADAPTERCB pAdapter,
IN ULONG BCMGeneration,
OUT PPREMOTE_NODE ppIrmRemoteNode
)
// Function Description:
// This function goes through all the remote nodes
// and attempts to get their address to verify which one is
// the IRM
//
//
// Arguments
// pADpater - Local host
// BCMGeneration - the Gerneration at which the BCMStarted
// ppIrmRemoteNode - output value - IRM
//
// Return Value:
// Success - if an IRM is found
//
{
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
PLIST_ENTRY pPdoListEntry = NULL;
PREMOTE_NODE pRemoteNode = NULL;
PREMOTE_NODE pIrmRemoteNode = NULL;
NODE_ADDRESS RemoteNodeAddress;
ULONG HighestNode;
ULONG Generation;
ULONG NumRetry =0;
PNIC1394_EVENT pBCRWaitForNewRemoteNode = &pAdapter->BCRData.BCRWaitForNewRemoteNode;
ULONG BackOffWait = ONE_MINUTE>>4;
TRACE( TL_T, TM_Bcm, ( "==>nicFindIrmAmongRemoteNodes pAdapter %x, ppIrmRemoteNode %x",
pAdapter, ppIrmRemoteNode) );
ASSERT (pAdapter->BCRData.pTopologyMap != NULL);
HighestNode = pAdapter->BCRData.pTopologyMap->TOP_Node_Count-1;
//
// Set up a loop, so that we continue until we succeed, timeout, or have a good reason to break
// One of two things will cause the break:
// 1. the bus has been reset - break out
// 2. Irm has been found
//
do
{
pBCRWaitForNewRemoteNode->EventCode = Nic1394EventCode_InvalidEventCode;
NdisResetEvent (&pBCRWaitForNewRemoteNode->NdisEvent);
//
// First see if we already have this remote node in our table
//
ADAPTER_ACQUIRE_LOCK (pAdapter);
if (pAdapter->NodeTable.RemoteNode[HighestNode] != NULL)
{
//
// we found the IRM. Lets break out.
//
*ppIrmRemoteNode = pAdapter->NodeTable.RemoteNode[HighestNode] ;
//
// Reference the IRM. This will be dereferenced after the BCM is finished. (ie) at the end of nicLocalHostisNotIrm
//
nicReferenceRemoteNode (*ppIrmRemoteNode, "nicFindIrmAmongRemoteNodes");
ADAPTER_RELEASE_LOCK (pAdapter);
NdisStatus = NDIS_STATUS_SUCCESS;
//
// Break out if the IRM is found
//
break;
}
else
{
//
// If the IRM is not in adapter's data structures, the thread needs to wait for it to arrive
//
BOOLEAN bWaitSuccessful;
ADAPTER_RELEASE_LOCK (pAdapter);
//
// Sleep and try again
//
TRACE( TL_V, TM_Bcm, ( " About to Wait 15 sec. for Remote Node") );
bWaitSuccessful = NdisWaitEvent (&pBCRWaitForNewRemoteNode->NdisEvent, BackOffWait );
TRACE( TL_V, TM_Bcm, ( " pBCRWaitForNewRemoteNode signalled Event Code = %x, bWaitSuccessful %x",
pBCRWaitForNewRemoteNode->EventCode, bWaitSuccessful) );
BackOffWait = BackOffWait << 1;
if (bWaitSuccessful == TRUE)
{
//
// Check for invalid conditions
//
if (pBCRWaitForNewRemoteNode->EventCode == nic1394EventCode_BusReset ||
pBCRWaitForNewRemoteNode->EventCode == nic1394EventCode_FreedAddressRange)
{
TRACE( TL_V, TM_Bcm, ( " Bus Has been reset,or addresss range freed aborting BCM") );
//
// Break out if the Bus Has been reset
//
break;
}
TRACE( TL_V, TM_Bcm, ( " New Node has arrived check its node address") );
ASSERT (pBCRWaitForNewRemoteNode->EventCode == Nic1394EventCode_NewNodeArrived);
//
// Hit the while (TRUE) condition loop back and verify if the new node is the IRM
//
}
else
{
//
// Wait has timed out
//
if (ADAPTER_TEST_FLAG (pAdapter, fADAPTER_InvalidGenerationCount) == TRUE)
{
//
// If the generation is invalid then break out and abort the BCM
//
NdisStatus = NIC1394_STATUS_INVALID_GENERATION;
break;
}
NumRetry ++;
if (NumRetry == 5 )// aribtrary constant
{
break;
}
}
}
} while (TRUE);
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
//
// Log this failuire
//
NIC1394_LOG_PKT(pAdapter,
NIC1394_LOGFLAGS_BCM_IRM_NOT_FOUND,
pAdapter->Generation,
HighestNode,
&pAdapter->NodeTable,
5 * sizeof (PVOID)); // arbitrarily number - copies 5 entries
}
TRACE( TL_T, TM_Bcm, ( "<==nicFindIrmAmongRemoteNodes Status %x pIrm %x", NdisStatus, *ppIrmRemoteNode ) );
return NdisStatus;
}
VOID
nicFreeBroadcastChannelRegister(
IN PADAPTERCB pAdapter
)
// Function Description:
// Free the boradcast channed reigster. Only called
// from the Init failure or halt code path
//
// Arguments
// pAdapter
//
// Return Value:
//
// None
//
{
ADDRESS_RANGE_CONTEXT BCRAddressRange;
TIMESTAMP_ENTRY ("==>Free BCR");
TRACE( TL_T, TM_Bcm, ( "==> nicFreeBroadcastChannelRegister pAdapter %x", pAdapter ) );
do
{
ADAPTER_ACQUIRE_LOCK (pAdapter);
BCR_SET_FLAG (pAdapter, BCR_BCRNeedsToBeFreed);
//
// If a Make Call is pending, then set the Event so that the make call can complete.
//
if (BCR_TEST_FLAG (pAdapter,BCR_MakeCallPending)== TRUE)
{
pAdapter->BCRData.MakeCallWaitEvent.EventCode = nic1394EventCode_FreedAddressRange;
NdisSetEvent (&pAdapter->BCRData.MakeCallWaitEvent.NdisEvent);
}
//
// If the BCM is in progress, let the BCM thread free the BCR instead
//
if (BCR_TEST_FLAG (pAdapter, BCR_BCMInProgress) == TRUE)
{
ADAPTER_RELEASE_LOCK (pAdapter);
//
// Wake up any pending threads - This wakes up an existing BCM thread that could
// be waiting for a new remote node
//
pAdapter->BCRData.BCRWaitForNewRemoteNode.EventCode = nic1394EventCode_FreedAddressRange;
NdisSetEvent (&pAdapter->BCRData.BCRWaitForNewRemoteNode.NdisEvent);
TRACE( TL_N, TM_Bcm, ( " nicFreeBroadcastChannelRegister BCM in progress or already freed, breaking out", pAdapter ) );
break;
}
//
// if the BCR is already freed, then simply exit. The event that the caller will wait
// on BCRData.BCRFreeAddressRange.NdisEvent has already been set
//
if (BCR_TEST_FLAG (pAdapter, BCR_Freed) == TRUE)
{
ADAPTER_RELEASE_LOCK (pAdapter);
break;
}
//
// sanity check
//
ASSERT (BCR_TEST_FLAG (pAdapter, BCR_BCRNeedsToBeFreed) == TRUE);
//
// Now update the flags
//
BCR_CLEAR_FLAG (pAdapter, BCR_Initialized | BCR_ChannelAllocated | BCR_BCRNeedsToBeFreed);
//
// clear all the BCR Valid bits
//
pAdapter->BCRData.IRM_BCR.NC_Valid = 0;
pAdapter->BCRData.LocalHostBCRBigEndian = BCR_IMPLEMENTED_LITTLE_ENDIAN; //0x80000000
if (pAdapter->BCRData.pRemoteBCRMdl != NULL)
{
nicFreeMdl (pAdapter->BCRData.pRemoteBCRMdl);
pAdapter->BCRData.pRemoteBCRMdl = NULL;
}
//
// Temporary copy of the Address Range Context
//
BCRAddressRange = pAdapter->BCRData.AddressRangeContext;
//
// Zero out the Address Range Structure. This zeroes out AddressRangeContext.Mdl as well.
// This is ok as BCRData.pLocalBCRMdl will be freed below and they both
// point to the same mdl.
//
NdisZeroMemory (
&pAdapter->BCRData.AddressRangeContext,
sizeof (pAdapter->BCRData.AddressRangeContext));
//
// Clear out the VC. if any
//
if (pAdapter->BCRData.pBroadcastChanneVc != NULL)
{
nicDereferenceCall ((PVCCB) pAdapter->BCRData.pBroadcastChanneVc, "nicFreeBroadcastChannelRegister ");
pAdapter->BCRData.pBroadcastChanneVc = NULL;
}
ADAPTER_RELEASE_LOCK (pAdapter);
//
// Free Address Range
//
if (BCRAddressRange.hAddressRange != NULL)
{
nicFreeAddressRange (pAdapter,
BCRAddressRange.AddressesReturned,
&BCRAddressRange.AddressRange,
&BCRAddressRange.hAddressRange );
}
ADAPTER_ACQUIRE_LOCK (pAdapter);
if (pAdapter->BCRData.pLocalBCRMdl != NULL)
{
nicFreeMdl (pAdapter->BCRData.pLocalBCRMdl);
pAdapter->BCRData.pLocalBCRMdl = NULL;
}
//
// Free the Adapter's BCRData. TopologyMap as that is locally allocated
//
if (pAdapter->BCRData.pTopologyMap)
{
FREE_NONPAGED (pAdapter->BCRData.pTopologyMap);
pAdapter->BCRData.pTopologyMap = NULL;
}
//
// Clear the flags to force the BCR to be reintitalized
//
BCR_CLEAR_ALL_FLAGS(pAdapter);
BCR_SET_FLAG (pAdapter, BCR_Freed);
ADAPTER_RELEASE_LOCK (pAdapter);
//
// Set the Event and let the halt go through
//
pAdapter->BCRData.BCRFreeAddressRange.EventCode = nic1394EventCode_FreedAddressRange;
NdisSetEvent (&pAdapter->BCRData.BCRFreeAddressRange.NdisEvent);
TRACE( TL_N, TM_Bcm, ( " nicFreeBroadcastChannelRegister BCM freed", pAdapter ) );
} while (FALSE);
TRACE( TL_T, TM_Bcm, ( "<== nicFreeBroadcastChannelRegister pAdapter %x", pAdapter ) );
TIMESTAMP_EXIT ("<==Free BCR");
}
NDIS_STATUS
nicInformAllRemoteNodesOfBCM (
IN PADAPTERCB pAdapter
)
// Function Description:
// This function will simply walk through the remote node list and write
// to the BCR of all the remote nodes
//
// Arguments
// pAdapter - Current local Host
// Channel - Channel used for broadcast
//
// Return Value:
//
//
{
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
PREMOTE_NODE pRemoteNode = NULL;
PLIST_ENTRY pPdoListEntry = NULL;
IO_ADDRESS Destination;
ULONG IrmGeneration ;
PMDL pBCRMdl;
BOOLEAN fLockAcquired = FALSE;
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
BOOLEAN fReferencedCurrentRemoteNode = FALSE;
TRACE( TL_T, TM_Bcm, ( "==> nicInformAllRemoteNodesOfBCM pAdapter %x, Channel %x OldGeneration %x",
pAdapter, pAdapter->BCRData.LocalHostBCRBigEndian, pAdapter->BCRData.IrmGeneration ) );
//
// Set up the constants that will be used
//
Destination.IA_Destination_Offset.Off_Low = INITIAL_REGISTER_SPACE_LO | NETWORK_CHANNELS_LOCATION;
Destination.IA_Destination_Offset.Off_High = INITIAL_REGISTER_SPACE_HI;
if ( (pAdapter->BCRData.LocalHostBCRBigEndian & BCR_VALID_BIG_ENDIAN) != BCR_VALID_BIG_ENDIAN)
{
//
// Do not write an invalid bcr to remote nodes
//
ASSERT ((ADAPTER_TEST_FLAG (pAdapter, fADAPTER_InvalidGenerationCount) == TRUE) ||
(BCR_TEST_FLAGS (pAdapter, BCR_Freed | BCR_BCRNeedsToBeFreed )== TRUE) );
return NIC1394_STATUS_INVALID_GENERATION;
}
pBCRMdl = pAdapter->BCRData.pLocalBCRMdl;
//
// Acquire the lock and walk the list of remote nodes
//
ADAPTER_ACQUIRE_LOCK (pAdapter);
fLockAcquired = TRUE;
IrmGeneration = pAdapter->BCRData.IrmGeneration;
pPdoListEntry = pAdapter->PDOList.Flink ;
//
// Now start the actual informing the remote nodes- asyncwrite algorithm
//
//
// Since the loop can be broken in the middle of the while loop. the code
// keeps track of lock acquire/release state
//
while (pPdoListEntry != &pAdapter->PDOList )
{
pRemoteNode = CONTAINING_RECORD (pPdoListEntry,
REMOTE_NODE,
linkPdo);
nicReferenceRemoteNode (pRemoteNode, "nicInformAllRemoteNodesOfBCM ");
fReferencedCurrentRemoteNode = TRUE;
ADAPTER_RELEASE_LOCK (pAdapter);
fLockAcquired = FALSE;
//
// First check if we are still in the same generation
//
if (pAdapter->Generation != IrmGeneration)
{
NdisStatus = NIC1394_STATUS_INVALID_GENERATION;
TRACE( TL_T, TM_Bcm, ( " nicInformAllRemoteNodesOfBCM Generation Incorrect New Gen %x, Old Gen ",
pAdapter->Generation , IrmGeneration));
break;
}
TRACE( TL_V, TM_Bcm, ( " BCR %x, Mdl %x, IrmGeneration %x" ,
pAdapter->BCRData.LocalHostBCRBigEndian, pBCRMdl, IrmGeneration ) );
NdisStatus = nicAsyncWrite_Synch( pRemoteNode,
Destination, // Address to write to
sizeof(NETWORK_CHANNELSR), // Bytes to write
sizeof(NETWORK_CHANNELSR), // Block size of write
0 , //fulFlags, // Flags pertinent to write
pBCRMdl, // Destination buffer
IrmGeneration , // Generation as known by driver
&NtStatus);
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
//
// Break out if the generation has changed or there are no more nodes left
//
if (NtStatus == STATUS_INVALID_GENERATION ||
BCR_TEST_FLAG (pAdapter, BCR_LastNodeRemoved) )
{
TRACE( TL_V, TM_Bcm, ( " nicAsyncWrite_Synch FAILED Status %x. Aborting ", NtStatus) );
nicBCMAbort (pAdapter, pRemoteNode);
break;
}
}
ADAPTER_ACQUIRE_LOCK (pAdapter);
fLockAcquired = TRUE;
//
// If the irps succeed and then the deref happens , else it happens below
//
nicDereferenceRemoteNode (pRemoteNode , "nicInformAllRemoteNodesOfBCM " );
fReferencedCurrentRemoteNode = FALSE;
pPdoListEntry = ListNext (pPdoListEntry);
} // end of while loop while (pPdoListEntry != &pAdapter->PDOList )
//
// Clear the Informing remote nodes flag and release the lock
//
if (fLockAcquired == FALSE)
{
ADAPTER_ACQUIRE_LOCK (pAdapter);
}
BCR_CLEAR_FLAG (pAdapter, BCR_InformingRemoteNodes);
ADAPTER_RELEASE_LOCK (pAdapter);
//
// Dereference the ref made in the beginning of the function
//
if (fReferencedCurrentRemoteNode == TRUE)
{
nicDereferenceRemoteNode (pRemoteNode , "nicInformAllRemoteNodesOfBCM " );
}
TRACE( TL_T, TM_Bcm, ( "<== nicInformAllRemoteNodesOfBCM (always returns success) Status %x", NdisStatus ) );
NdisStatus = NDIS_STATUS_SUCCESS; // No failure
return NdisStatus;
}
NDIS_STATUS
nicInitializeBroadcastChannelRegister (
PADAPTERCB pAdapter
)
// Function Description:
// This function allocates address range for the BCR with its own MDL and data.
// Allocates an MDL for the time when we try to read other node's BCR
// Initializes the IRM_BCR
//
// Return Value:
// Success - if the IRP succeeds
//
//
//
{
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
PULONG pBCRBuffer = NULL;
PMDL pBCRMdl = NULL;
ADDRESS_OFFSET Required1394Offset;
ULONG AddressesReturned;
ADDRESS_RANGE BCRAddressRange;
HANDLE hAddressRange;
ULONG LocalNodeNumber;
PMDL pRemoteBCRMdl = NULL;
TRACE( TL_T, TM_Bcm, ( "==>nicInitializeBroadcastChannelRegister Adapter %x" , pAdapter ) );
do
{
BCR_CLEAR_ALL_FLAGS(pAdapter);
//
//Initialize the Local Host's BCR
//
pAdapter->BCRData.LocalHostBCRBigEndian = BCR_IMPLEMENTED_BIG_ENDIAN;
//
// Get an MDL that describes this buffer
//
if (pAdapter->BCRData.pLocalBCRMdl == NULL)
{
NdisStatus = nicGetMdl (sizeof(NETWORK_CHANNELSR),
&pAdapter->BCRData.LocalHostBCRBigEndian,
&pBCRMdl ) ;
if (pBCRMdl == NULL)
{
TRACE( TL_A, TM_Bcm, ( " nicInitializeBroadcastChannelRegister IoAllocateMdl FAILED" ) );
NdisStatus = NDIS_STATUS_RESOURCES;
break;
}
}
else
{
//
// We already have an MDL
//
pBCRMdl = pAdapter->BCRData.pLocalBCRMdl;
}
//
// Allocate an Address Range at the BCR offset and use the MDL as its descriptor
//
TRACE( TL_V, TM_Bcm, ( " LocalHostBCR Mdl %x", pBCRMdl ) );
Required1394Offset.Off_Low = INITIAL_REGISTER_SPACE_LO | NETWORK_CHANNELS_LOCATION;
Required1394Offset.Off_High = INITIAL_REGISTER_SPACE_HI ;
pAdapter->BCRData.AddressRangeContext.pMdl = pBCRMdl ;
//
// There is no reference for this address range. The last outgoing Remote Node will simply Free it.
//
NdisStatus = nicAllocateAddressRange_Synch ( pAdapter,
pBCRMdl,
0, // Little Endian
sizeof (ULONG), // length
0, // maxsegmentsize
ACCESS_FLAGS_TYPE_READ | ACCESS_FLAGS_TYPE_WRITE | ACCESS_FLAGS_TYPE_LOCK | ACCESS_FLAGS_TYPE_BROADCAST,
NOTIFY_FLAGS_AFTER_READ | NOTIFY_FLAGS_AFTER_WRITE | NOTIFY_FLAGS_AFTER_LOCK ,
nicBCRAccessedCallback,
(PVOID)pAdapter,
Required1394Offset,
NULL,
NULL,
&AddressesReturned,
&BCRAddressRange,
&hAddressRange
);
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
TRACE( TL_A, TM_Bcm, ( " nicInitializeBroadcastChannelRegister nicAllocateAddressRange_Synch FAILED" ) );
ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
break;
}
TRACE( TL_V, TM_Bcm, ( " nicInitializeBroadcastChannelRegister nicAllocateAddressRange_Synch Succeeded" ) );
TRACE( TL_V, TM_Bcm, ( " &BCR Address Range %x, AddressesReturned %x, hAddressRange %x",
&BCRAddressRange, AddressesReturned, hAddressRange) );
NdisStatus = nicGetMdl (sizeof(NETWORK_CHANNELSR),
&pAdapter->BCRData.RemoteBCRMdlData,
&pRemoteBCRMdl);
if (NdisStatus != NDIS_STATUS_SUCCESS || pBCRMdl == NULL)
{
TRACE( TL_V, TM_Bcm, ( " nicInitializeBroadcastChannelRegister : nicGetMdl FAILED " ) );
ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
break;
}
ADAPTER_ACQUIRE_LOCK (pAdapter);
pAdapter->BCRData.AddressRangeContext.AddressRange = BCRAddressRange;
pAdapter->BCRData.AddressRangeContext.AddressesReturned = AddressesReturned;
pAdapter->BCRData.AddressRangeContext.hAddressRange = hAddressRange;
pAdapter->BCRData.pLocalBCRMdl = pBCRMdl; // points to the same MDL as pAdapter->BCRData.AddressRangeContext.pMdl
pAdapter->BCRData.pRemoteBCRMdl = pRemoteBCRMdl;
pAdapter->BCRData.IRM_BCR.NC_One = 1;
pAdapter->BCRData.MakeCallWaitEvent.EventCode = Nic1394EventCode_InvalidEventCode;
NdisResetEvent (&pAdapter->BCRData.MakeCallWaitEvent.NdisEvent);
BCR_SET_FLAG (pAdapter, BCR_Initialized);
ADAPTER_RELEASE_LOCK (pAdapter);
} while (FALSE);
TRACE( TL_T, TM_Bcm, ( "<==nicInitializeBroadcastChannelRegister %x", NdisStatus ) );
return NdisStatus;
}
NDIS_STATUS
nicIsLocalHostTheIrm(
IN PADAPTERCB pAdapter,
OUT PBOOLEAN pfIsLocalHostIrm,
OUT PPTOPOLOGY_MAP ppTopologyMap,
OUT PNODE_ADDRESS pLocalHostAddress
)
// Function Description:
// This function figures out if the Local Host is the IRM.
// If a remote node is specified, it will use that Node, otherwise
// it will pick one from the adapter
// It gets the 1394 address, and the topologyMap. It then figures out
// if the local host's node address makes it the IRM
//
// Arguments
//
// pAdapter - Local Host,
// pfIsLocalHostIrm, - TRUE if Local Host Is IRM, False - otherwise
// ppTopologyMap, - TopologyMap used to determine if this is the IRM
// pLocalHostAddress - LocalHost Address discovered by querying the local host
//
//
// Return Value:
//
//
//
//
{
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
PVOID pTopologyBuffer = NULL;
PREMOTE_NODE pRemoteNode = NULL;
NODE_ADDRESS LocalNodeAddress;
PTOPOLOGY_MAP pTopologyMap = NULL;
PTOPOLOGY_MAP pOldTopologyMap = NULL;
ULONG Length = DEFAULT_TOPOLOGY_MAP_LENGTH;
TRACE( TL_T, TM_Bcm, ( "==>nicIsLocalHostTheIrm ") );
ASSERT (pfIsLocalHostIrm != NULL);
ASSERT (ppTopologyMap!=NULL);
ASSERT (pLocalHostAddress != NULL);
do
{
//
// get the address of the local node/
//
NdisStatus = nicGet1394AddressFromDeviceObject( pAdapter->pNdisDeviceObject,
&LocalNodeAddress,
USE_LOCAL_NODE );
if (NDIS_STATUS_SUCCESS != NdisStatus)
{
BREAK( TM_Bcm, ( "GetAddrFrom DevObj (Local) FAILED" ) );
}
TRACE ( TL_I, TM_Bcm, ( " NODE_ADDRESS Node Address %x, Number %x",LocalNodeAddress, LocalNodeAddress.NA_Node_Number ) );
ASSERT (LocalNodeAddress.NA_Bus_Number == 0x3ff);
//
// Now we get the TopologyMap to find out if LocalHostIsIrm. We could fail the 1st Irp because our buffer is not
// big enough, hence the do .. while loop
//
do
{
pTopologyBuffer = ALLOC_NONPAGED (Length , MTAG_DEFAULT);
if (pTopologyBuffer ==NULL)
{
NdisStatus = NDIS_STATUS_RESOURCES;
break;
}
NdisStatus = nicGetLocalHostCSRTopologyMap (pAdapter,
&Length,
pTopologyBuffer );
if (NdisStatus == NDIS_STATUS_INVALID_LENGTH)
{
FREE_NONPAGED(pTopologyBuffer);
}
} while (NdisStatus == NDIS_STATUS_INVALID_LENGTH);
TRACE ( TL_V, TM_Bcm, ( " TopologyBuffer %x",pTopologyBuffer) );
pTopologyMap = (PTOPOLOGY_MAP)pTopologyBuffer;
TRACE( TL_I, TM_Bcm, ( " Top node count = %x ", pTopologyMap->TOP_Node_Count) );
} while (FALSE);
if (NdisStatus == NDIS_STATUS_SUCCESS)
{
//
// Now update all the output parameters. The Top_Node_count can be zero.
//
if ( LocalNodeAddress.NA_Node_Number == (pTopologyMap->TOP_Node_Count -1 ) ||
pTopologyMap->TOP_Node_Count == 0)
{
*pfIsLocalHostIrm = TRUE;
BCR_SET_FLAG (pAdapter, BCR_LocalHostIsIRM);
}
else
{
*pfIsLocalHostIrm = FALSE;
}
//
// If there is a topology map in the pointer, then it means that the topology map from
// the previous query. Free it first.
//
if ( *ppTopologyMap != NULL)
{
FREE_NONPAGED(*ppTopologyMap);
}
*ppTopologyMap = pTopologyMap;
*pLocalHostAddress = LocalNodeAddress;
}
TRACE( TL_T, TM_Bcm, ( "<==nicIsLocalHostTheIrm %x NdisStatus %x",*pfIsLocalHostIrm , NdisStatus ) );
return NdisStatus;
}
NDIS_STATUS
nicLocalHostIsIrm(
IN PADAPTERCB pAdapter
)
// Function Description:
//
//
//
//
// Arguments
// pAdapter - Local adapter object
// pRemoteNode - Node to be used for submitting IRPs to the Busdriver
//
//
// Return Value:
//
//
//
//
{
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
ULONG Channel = BROADCAST_CHANNEL;
ULONG TimeOut = 5;
ULONG LocalHostBCRLittleEndian;
ULONG WaitBackOff = ONE_SEC;
TRACE( TL_T, TM_Bcm, ( "==>nicLocalHostIsIrm Adapter %x ", pAdapter) );
//
// Allocate BCM channel = 31
//
Channel = BROADCAST_CHANNEL;
do
{
//
// If the channel is already allocated. Do not try and reallocate it.
//
if (BCR_TEST_FLAG(pAdapter,BCR_ChannelAllocated) == TRUE)
{
ASSERT (pAdapter->BCRData.IRM_BCR.NC_Channel == Channel);
NdisStatus = NDIS_STATUS_SUCCESS;
break;
}
//
// Retry a 5 times to allocate the channel
//
while (NdisStatus != NDIS_STATUS_SUCCESS && TimeOut-- != 0 )
{
NdisStatus = nicAllocateChannel (pAdapter,
Channel,
NULL);
if (NdisStatus != NDIS_STATUS_SUCCESS )
{
TRACE( TL_V, TM_Bcm, ( " nicNodeIsIRMAlgorithm: nicallocateChannel Failed. Sleep and try again") );
if (BCR_TEST_FLAG (pAdapter, BCR_BCRNeedsToBeFreed |BCR_NewNodeArrived) == TRUE ||
ADAPTER_TEST_FLAG (pAdapter,fADAPTER_InvalidGenerationCount) == TRUE)
{
break;
}
//
// Sleep for 1 Sec and try again.
//
NdisMSleep (WaitBackOff);
WaitBackOff = WaitBackOff << 1;
//
// Someother node has alredy asked for the BroadcastChannel .Force it out.
// Eventually will need to allocate a new channel.
//
}
}
} while (FALSE);
if (NdisStatus == NDIS_STATUS_SUCCESS)
{
//
// Update our BCR and inform all the remote Nodes
//
TRACE( TL_V, TM_Bcm, ( " nicLocalHostIsIrm: nicallocateChannel succeeded %x", Channel) );
ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
ASSERT (Channel == BROADCAST_CHANNEL);
ADAPTER_ACQUIRE_LOCK (pAdapter);
//
// Update State - if no reset has occurred
//
if (ADAPTER_TEST_FLAG (pAdapter, fADAPTER_InvalidGenerationCount) == FALSE)
{
BCR_SET_FLAG (pAdapter, BCR_ChannelAllocated);
BCR_SET_FLAG (pAdapter, BCR_InformingRemoteNodes);
pAdapter->BCRData.IrmGeneration = pAdapter->Generation;
pAdapter->BCRData.LocalHostBCRBigEndian = 0;
NdisZeroMemory (&pAdapter->BCRData.IRM_BCR, sizeof (NETWORK_CHANNELSR) );
//
// Update the BCR
//
pAdapter->BCRData.IRM_BCR.NC_Channel = Channel; // bits 0-5
pAdapter->BCRData.IRM_BCR.NC_Valid = 1; // bit 30
pAdapter->BCRData.IRM_BCR.NC_One = 1; // bit 31
pAdapter->BCRData.LocallyAllocatedChannel = Channel;
}
else
{
TRACE( TL_V, TM_Bcm, ( " nicLocalHostIsIrm: Reset after nicallocateChannel succeeded %x", Channel) );
pAdapter->BCRData.IRM_BCR.NC_Valid = 0; // bit 30
}
TRACE( TL_V, TM_Bcm, ( " nicLocalHostIsIrm: IRM_BCR Updated to %x ",pAdapter->BCRData.IRM_BCR) );
//
// Now convert LocalHost BCR so it can be read over the network
//
pAdapter->BCRData.LocalHostBCRBigEndian = SWAPBYTES_ULONG (*(PULONG)(&pAdapter->BCRData.IRM_BCR));
TRACE( TL_V, TM_Bcm, ( " nicLocalHostIsIrm: LocalHost BCR Updated to %x ",pAdapter->BCRData.LocalHostBCRBigEndian ) );
ADAPTER_RELEASE_LOCK (pAdapter);
if ((pAdapter->BCRData.LocalHostBCRBigEndian & BCR_VALID_BIG_ENDIAN) == (BCR_VALID_BIG_ENDIAN))
{
//
// Tell all the other nodes about the BCM and the channel.
// This will abort the process if a reset happenned just prior
// to the channel allocation.
//
nicInformAllRemoteNodesOfBCM (pAdapter);
}
}
else
{
TRACE( TL_A, TM_Bcm, ( " nicLocalHostIsIrm - Failed RESET THE BUS") );
NIC1394_LOG_PKT(pAdapter,
NIC1394_LOGFLAGS_BCM_IS_IRM_TIMEOUT,
pAdapter->Generation,
0,
&NdisStatus,
sizeof (NDIS_STATUS));
//
// If the generation is invalid or we need to bail out of the BCM for some reason,
// then simply exit. Otherwise reset the bus
//
if (! (BCR_TEST_FLAG (pAdapter, BCR_BCRNeedsToBeFreed |BCR_NewNodeArrived) == TRUE ||
ADAPTER_TEST_FLAG (pAdapter,fADAPTER_InvalidGenerationCount) == TRUE) )
{
nicBCMReset(pAdapter);
}
}
TRACE( TL_T, TM_Bcm, ( "<==nicLocalHostIsIrm%x ",NdisStatus ) );
return NdisStatus;
}
NDIS_STATUS
nicLocalHostIsNotIrm (
IN PADAPTERCB pAdapter,
IN ULONG BCMGeneration
)
// Function Description:
// This function goes through all the remote nodes
// and attempts to read their broadcast channels register
// If the Read itself fails - means the IRM does not implement the BCR - we issue a reset
// If the generation is wrong - means the bus has been reset and we need to abort
// If the read succeeds, but BCR's MSB is not set - we issue a reset
//
// If the read succeeds and valid bit is not set, we retry for 5 min. waiting for the Valid bit
// This involves i) attempt to read the (IRM) remote Node's BCR
// If Read does not find a BCR,
// Sleep
// Check to see if RemoteNode Has written to Our BCR
// If RemoteNode has NOT written to our BCR, then go back to i)
//
//
// This function can be optimized into a do while loop. However for
// the sake of simplicity and blindly following the BCM algorithm, it is
// spread out.
//
// Arguments
//
//
//
// Return Value:
//
//
//
//
{
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
PLIST_ENTRY pPdoListEntry = NULL;
PREMOTE_NODE pIrmRemoteNode = NULL;
PMDL pRemoteBCRMdl = NULL;
ULONG Generation, BCMChannel ;
BOOLEAN fRemoteNodeBCRIsValid = FALSE;
BOOLEAN fNeedToReset = FALSE;
BOOLEAN fDidTheBusReset = FALSE;
BOOLEAN fExit= FALSE;
ULONG TimeOut;
ULONG LocalHostBCRLittleEndian , RemoteNodeBCRLittleEndian;
NETWORK_CHANNELSR* pBCR = NULL;
BOOLEAN fLocalHostBCRIsValid = FALSE;
ULONG BackOffWait = ONE_SEC;
TRACE( TL_T, TM_Bcm, ( "==>nicLocalHostIsNotIrm " ) );
ASSERT (pAdapter->BCRData.pTopologyMap != NULL);
do
{
//
// First do the wait - BCM algorithm requires this
//
pBCR = (NETWORK_CHANNELSR*)(&LocalHostBCRLittleEndian) ;
NdisStatus = nicLocalNotIrmMandatoryWait (pAdapter,
BCMGeneration,
pBCR);
if (NdisStatus == NDIS_STATUS_SUCCESS)
{
fLocalHostBCRIsValid = TRUE;
TRACE( TL_V, TM_Bcm, ( " BCR written to during Mandatory Wait ") );
break;
}
else
{
fLocalHostBCRIsValid = FALSE;
}
//
// Initialize variables again and move on
//
pBCR = NULL;
LocalHostBCRLittleEndian = 0;
//
// Our BCR has not been updated. Lets go and find the IRM's BCR. we will loop until we
// i)either find the IRM, ii)timeout and then reset, or iii)find a new generation and abort
//
//
NdisStatus = nicFindIrmAmongRemoteNodes (pAdapter, BCMGeneration, &pIrmRemoteNode);
if (NdisStatus != NDIS_STATUS_SUCCESS )
{
//
// If there is NO IRM , it means we have not been notified of its addition.
//
TRACE( TL_V, TM_Bcm, ( " nicLocalHostIsNotIrm : nicFindIrmAmongRemoteNodes FAILED " ) );
//
// One of two things can have caused this:
// 1. the bus has been reset - break out
// 2. we have not been notified of a new node - continue on
//
if (NdisStatus == NIC1394_STATUS_INVALID_GENERATION)
{
TRACE( TL_V, TM_Bcm, ( " Invalid Generation, the bus has been reset ") );
NdisStatus = NtStatusToNdisStatus(NIC1394_STATUS_INVALID_GENERATION);
break;
}
//
// We have not been able to find the IRM and have timed out.
// If the BCR is not freed, then abort and Reset
//
if (BCR_TEST_FLAGS (pAdapter, (BCR_Freed | BCR_BCRNeedsToBeFreed) == FALSE))
{
TRACE( TL_I, TM_Bcm, ( " nicLocalHostIsNotIrm - Could Not Find IRM RESETTING ") );
fNeedToReset = TRUE;
}
break;
}
ASSERT (pIrmRemoteNode != NULL)
//
// We will now wait for the BCM to come up and initialize its BCR.
// We will attempt to read it 5 times
//
pRemoteBCRMdl = pAdapter->BCRData.pRemoteBCRMdl;
pAdapter->BCRData.RemoteBCRMdlData = 0;
TimeOut = 5; // arbitrary
while (TimeOut-- != 0 )
{
NdisStatus = nicReadIrmBcr ( pIrmRemoteNode,
pRemoteBCRMdl,
BCMGeneration,
&fDidTheBusReset);
//
// First check to see if no reset has happenned while we were reading the BCR
//
if ( fDidTheBusReset == TRUE ||
(ADAPTER_TEST_FLAG (pAdapter, fADAPTER_InvalidGenerationCount) == TRUE))
{
//
// A reset has gone through under us.
// We need to abort this round of the BCM process
//
TRACE( TL_V, TM_Bcm, ( " nicLocalHostIsNotIrm : nicReadIrmBcr FAILED Invalid generation ") );
NdisStatus = NDIS_STATUS_FAILURE;
break;
}
//
// Now check for Success and see if the BCR is implemented by the IRM
//
if (NdisStatus == NDIS_STATUS_SUCCESS )
{
TRACE( TL_V, TM_Bcm, ( " BCR is %x ", pAdapter->BCRData.RemoteBCRMdlData ) );
//
// At this point we have a guarantee that nicReadIrmBcr succeeded. If the IRM does not implement the BCR
// at all, there is no point in retrying, reset the bus and become the IRM
//
RemoteNodeBCRLittleEndian = SWAPBYTES_ULONG (pAdapter->BCRData.RemoteBCRMdlData);
pBCR = (NETWORK_CHANNELSR*)(&RemoteNodeBCRLittleEndian );
if ( IS_A_BCR (pBCR) == FALSE && NdisStatus == NDIS_STATUS_SUCCESS)
{
fNeedToReset = TRUE;
TRACE( TL_I, TM_Bcm, ( " nicLocalHostIsNotIrm : IRM does not implement the BCR %x RESETTING",RemoteNodeBCRLittleEndian ) );
break;
}
//
// The remote node implements the BCR, so now lets see if it has set up the broadcast channel by looking
// at the valid bit.
//
if (BCR_IS_VALID (pBCR) ==TRUE)
{
//
// We've succeeded and have received a Broadcast Channel. Update data structures and exit.
//
ULONG BCMChannel;
fRemoteNodeBCRIsValid = TRUE;
BCMChannel = pBCR->NC_Channel;
TRACE( TL_V, TM_Bcm, ( " BCM Channel %x ", BCMChannel ) );
break;
}
//
// At this point we know that the IRM implements the BCR but has not set its valid bit yet.
// Lets sleep and give it som more time
//
pBCR = NULL;
RemoteNodeBCRLittleEndian = 0;
}
//
// Check to see if the Remote Node PDO is valid
//
if (REMOTE_NODE_TEST_FLAG(pIrmRemoteNode, PDO_Removed) )
{
fNeedToReset = TRUE;
fExit = TRUE;
}
//
// Remote Node's BCR is not up yet
// We need to sleep and retry to read the IRM's BCR in the hope that it will have allocated the
// broadcast channel by the time we read the register again.
//
NdisMSleep (BackOffWait);
BackOffWait = BackOffWait << 1;
ADAPTER_ACQUIRE_LOCK (pAdapter);
if (BCR_TEST_FLAG (pAdapter, BCR_BCRNeedsToBeFreed) == FALSE )
{
LocalHostBCRLittleEndian = SWAPBYTES_ULONG (pAdapter->BCRData.LocalHostBCRBigEndian);
}
else
{
fExit = TRUE;
}
ADAPTER_RELEASE_LOCK (pAdapter);
//
// Address range has been freed, exit
//
if (fExit == TRUE)
{
break;
}
pBCR = (NETWORK_CHANNELSR*)(&LocalHostBCRLittleEndian);
//
// Check if the BCR is valid and that no reset has come through the in the Interim.
// The reset would have cleared the BCR_localHostBCRUpdated field
//
if ( BCR_IS_VALID (pBCR) == TRUE &&
( BCR_TEST_FLAGS (pAdapter, BCR_LocalHostBCRUpdated ) == TRUE))
{
//
// We've succeeded. Update data structures and exit.
// The actual IRM BCR will have been updated in the BCRAccessed thread
// so we simply exit
//
NdisStatus = NDIS_STATUS_SUCCESS;
BCMChannel = pBCR->NC_Channel;
TRACE( TL_V, TM_Bcm, ( " BCM Channel %x ", BCMChannel ) );
fLocalHostBCRIsValid = TRUE;
fRemoteNodeBCRIsValid = FALSE;
break;
}
if (TimeOut == 0)
{
//
// We've waited, retried 5 times. The IRM has not implemented the BCM
// We need to wrest control by resetting the bus
//
// This happens when the remote node is still booting up.
//
TRACE( TL_I, TM_Bcm, ( " nicLocalHostIsNotIrm - TIMEOUT RESETTING") );
fNeedToReset = TRUE;
}
LocalHostBCRLittleEndian = 0;
pBCR = NULL;
} //while (Timeout-- != 0 )
//
// Last case: The IRM does not implement the BCR (Broadcast Channel Register). We need to wrest control
// by issuing a Bus Reset.
} while (FALSE);
//
// Now do the clean up work and updating of data structures that needs to be done at the end of the BCM
// algorithm
//
nicLocalHostIsNotIrmPost (pAdapter,
pIrmRemoteNode,
fNeedToReset,
fRemoteNodeBCRIsValid ,
fLocalHostBCRIsValid ,
fDidTheBusReset,
pBCR );
//
// If the IRM was successfuly found, then it was referenced as well. We dereference it now
// Ref was made in FindIRmAmongstRemoteNode
//
if (pIrmRemoteNode != NULL)
{
nicDereferenceRemoteNode (pIrmRemoteNode, "nicLocalHostIsNotIrm ");
}
TRACE( TL_T, TM_Bcm, ( "<==nicLocalHostIsNotIrm Status %x", NdisStatus ) );
return NdisStatus;
}
VOID
nicLocalHostIsNotIrmPost (
PADAPTERCB pAdapter,
PREMOTE_NODE pIrmRemoteNode,
BOOLEAN fNeedToReset,
BOOLEAN fRemoteNodeBCRIsValid ,
BOOLEAN fLocalHostBCRIsValid ,
BOOLEAN fDidTheBusReset,
NETWORK_CHANNELSR* pBCR
)
/*++
Routine Description:
This routine does the post processing after the Local Host Is Not Irm has completed.
It i)resets the bus if necessary, ii) Updates the BCR if pBCR has a valid Value
The Boolean Variables passed in indicate the state of the BCM algorithm
Arguments:
pAdapter - pAdapter in question,
pIrmRemoteNode - RemoteNode that is the IRM,
fNeedToReset - Does the bus need to be reset,
fRemoteNodeBCRIsValid - Is the RemoteNodeBCR Valid ,
fLocalHostBCRIsValid - LocalHost BCR Valid,
fDidTheBusReset - Did the bus reset during this iteration of the BCM algorithm,
pBCR - the BCR that was passed in
Return Value:
--*/
{
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
TRACE( TL_T, TM_Bcm, ( "==> nicLocalHostIsNotIrmPost pAdapter %x, pIrm %x, fNeedToReset%x, fRemoteNodeBCRIsValid %x, fLocalHostBCRIsValid %x, fDidTheBusReset,%x, pBCR %x",
pAdapter, pIrmRemoteNode, fNeedToReset, fRemoteNodeBCRIsValid , fLocalHostBCRIsValid, fDidTheBusReset, pBCR) );
do
{
if (fRemoteNodeBCRIsValid == TRUE || fLocalHostBCRIsValid == TRUE)
{
//
// The BCM algorithm has succeeded. We need to update our internal record of
// the IRM's BCR. In both ocde (local and Remote) the pBCR points to the BCR in little
// endian
//
ASSERT (fNeedToReset == FALSE);
//
// One final check
//
ASSERT (pBCR!= NULL);
ASSERT (pBCR->NC_Valid == 1);
ADAPTER_ACQUIRE_LOCK (pAdapter);
pAdapter->BCRData.IRM_BCR.NC_One = 1;
pAdapter->BCRData.IRM_BCR.NC_Valid = 1;
pAdapter->BCRData.IRM_BCR.NC_Channel = pBCR->NC_Channel;
ASSERT ( BCR_IS_VALID (&pAdapter->BCRData.IRM_BCR) == TRUE);
TRACE( TL_V, TM_Bcm, ( " Updated IRM_BCM with %x ",pAdapter->BCRData.IRM_BCR ) );
ADAPTER_RELEASE_LOCK (pAdapter);
ASSERT (fDidTheBusReset == FALSE);
ASSERT (fNeedToReset == FALSE);
break;
}
if ( fNeedToReset )
{
//
// If our BCR's are invalid and the IRM has gone away
// OR if there has been a timeout, we should reset the
// bus to force a new BCM
//
BOOLEAN NoRemoteNodes = IsListEmpty(&pAdapter->PDOList) ;
//
// Reset only if there are remote nodes present
//
if (NoRemoteNodes == FALSE)
{
TRACE( TL_V, TM_Bcm, ("fNeedToReset %x, RemoteNode %p\n",fNeedToReset,pIrmRemoteNode));
nicBCMReset( pAdapter);
}
ASSERT (fRemoteNodeBCRIsValid == FALSE);
ASSERT (fDidTheBusReset == FALSE);
break;
}
} while (FALSE);
TRACE( TL_T, TM_Bcm, ( "<== nicLocalHostIsNotIrmPost ") );
}
NDIS_STATUS
nicLocalNotIrmMandatoryWait (
IN PADAPTERCB pAdapter,
IN ULONG BCMGeneration,
OUT NETWORK_CHANNELSR* pBCR
)
// Function Description:
// This function implements the mandatory portion
// of the local host is not Irm protion of the BCM algorithm
//
// Sleeps and expects that a IRM will have written to its BCR
// by the time it wakes up
//
// Arguments
// pAdapter
//
//
// Return Value:
//
//
{
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
ULONG HighestNode = pAdapter->BCRData.pTopologyMap->TOP_Node_Count-1;
ULONG LocalNodeNumber = pAdapter->BCRData.LocalNodeNumber;
ULONG TimeOut = 0;
ULONG Generation;
ULONG LocalHostBCRLittleEndian = 0;
ASSERT (pBCR != NULL);
TRACE( TL_T, TM_Bcm, ( "==> nicLocalNotIrmMandatoryWait pAdapter %x, HighNode %x, LocalNode %x, BCMGeneration %x",
pAdapter, HighestNode, LocalNodeNumber, BCMGeneration) );
//
// BCM algorithm states that node must wait 15ms * IRM_ID - candidate_ID
//
TimeOut = HighestNode - LocalNodeNumber;
do
{
if (TimeOut > 64)
{
ASSERT (TimeOut <= 64);
NdisStatus = NDIS_STATUS_FAILURE;
break;
}
//
// Store the generation as a reference point. The moment the bus is reset, the gen count
// will increment and we will need to bail out of this round of the BCM process
//
if (BCMGeneration != pAdapter->Generation)
{
TRACE( TL_V, TM_Bcm, ( " nicLocalHostIsNotIrm : Generations do not match " ) );
NdisStatus = NIC1394_STATUS_INVALID_GENERATION;
break;
}
//
// Sleep for 15ms * IRM_ID - CandidateNodeID
//
NdisMSleep (TimeOut * 15000);
//
// First let's read our own BCR and see if someone has written a valid BCR to it.
//
ADAPTER_ACQUIRE_LOCK (pAdapter);
LocalHostBCRLittleEndian = pAdapter->BCRData.LocalHostBCRBigEndian;
ADAPTER_RELEASE_LOCK (pAdapter);
//
// Copy it over to what pBCR points to
//
LocalHostBCRLittleEndian = SWAPBYTES_ULONG (LocalHostBCRLittleEndian );
*pBCR = (*(NETWORK_CHANNELSR*)&LocalHostBCRLittleEndian );
if ( BCR_IS_VALID(pBCR)==TRUE)
{
//
// We've succeeded. Update data structures and exit. Nothing for us
// to do as the other thread updates everything
//
ULONG BCMChannel = -1;
NdisStatus = NDIS_STATUS_SUCCESS;
BCMChannel = pBCR->NC_Channel;
TRACE( TL_V, TM_Bcm, ( " BCM Channel %x ", BCMChannel ) );
TRACE( TL_V, TM_Bcm, ( " BCR Is valid on LocalHost BCR", pAdapter->BCRData.LocalHostBCRBigEndian) );
NdisStatus = NDIS_STATUS_SUCCESS;
ASSERT (BCMChannel == 31);
break;
}
else
{
NdisStatus = NDIS_STATUS_FAILURE;
}
} while (FALSE);
TRACE( TL_T, TM_Bcm, ( "<== nicLocalNotIrmMandatoryWait Status %x , pBCR %x", NdisStatus, pBCR) );
return NdisStatus;
}
NDIS_STATUS
nicReadIrmBcr (
PREMOTE_NODE pIrmRemoteNode,
IN PMDL pBCRMdl,
IN ULONG GivenGeneration,
OUT PBOOLEAN pfDidTheBusReset
)
// Function Description:
// Purpose is to do an async read on the IRM's BCR and see if it is set.
// Arguments
// pIrmRemoteNode - The remote node (IRM)
// pBCRMdl The MDL that will contain the remote node's BCR. Needs to preinitialized
// Return Value:
// Success - If Irp succeeded. Appropriate Error code otherwise
// If the Generation is incorrect. the call will be failed
//
//
{
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
IO_ADDRESS Destination;
PNETWORK_CHANNELS pBCR = NULL;
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
TRACE( TL_T, TM_Bcm, ( "==>nicReadIrmBcr pIrm %x, pMdl %x, GivenGeneration %x",
pIrmRemoteNode, pBCRMdl, GivenGeneration) );
ASSERT (pBCRMdl != NULL);
ASSERT (pIrmRemoteNode != NULL);
pBCR = NIC_GET_SYSTEM_ADDRESS_FOR_MDL(pBCRMdl);
Destination.IA_Destination_Offset.Off_Low = INITIAL_REGISTER_SPACE_LO | NETWORK_CHANNELS_LOCATION;
Destination.IA_Destination_Offset.Off_High = INITIAL_REGISTER_SPACE_HI;
do
{
if (pBCR == NULL)
{
break;
}
pBCR->NC_Valid = 0;
if (pIrmRemoteNode->pAdapter->Generation != GivenGeneration)
{
TRACE( TL_A, TM_Bcm, ( "nicReadIrmBcr : Generation Mismatch orig %x, curr %x", GivenGeneration , pIrmRemoteNode->pAdapter->Generation) );
NdisStatus = NDIS_STATUS_DEST_OUT_OF_ORDER;
*pfDidTheBusReset = TRUE;
break;
}
if (REMOTE_NODE_TEST_FLAG (pIrmRemoteNode, PDO_Removed))
{
NdisStatus = NDIS_STATUS_DEST_OUT_OF_ORDER;
break;
}
//
// We have a correct generation count
//
*pfDidTheBusReset = FALSE;
NdisStatus = nicAsyncRead_Synch( pIrmRemoteNode,
Destination,
sizeof(NETWORK_CHANNELSR), // Number of bytes to Read
sizeof (NETWORK_CHANNELSR), // Block Size
0, // fulFlags,
pBCRMdl ,
GivenGeneration,
&NtStatus);
} while (FALSE);
if (NtStatus == STATUS_INVALID_GENERATION )
{
*pfDidTheBusReset = TRUE;
}
TRACE( TL_I, TM_Bcm, ( " nicReadIrmBcr pBCRMdl %x, BCR %x ", pBCRMdl, *pBCR ) );
TRACE( TL_T, TM_Bcm, ( "<==nicReadIrmBcr Status %x, fDidTheBusReset %x", NdisStatus ,*pfDidTheBusReset ) );
return NdisStatus;
}
NDIS_STATUS
nicScheduleBCMWorkItem(
PADAPTERCB pAdapter
)
/*++
Routine Description:
This function queues a workitem to kick of the BCM algorithm.
If there is already a BCM in progress, (look at BCM_WorkItem flag)
it simply returns.
It is the responsiblity of the caller to mark the invocation of BCMAlgorithm as
dirty, thereby forcing it to restart the BCM (by setting the InvalidGeneration of the
new Node Arrived Flags)
Arguments:
pAdapter - Adapter
Return Value:
--*/
{
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
PNDIS_WORK_ITEM pBCMWorkItem;
BOOLEAN fBCMWorkItemInProgress = FALSE;
TRACE( TL_T, TM_Bcm, ( "==>nicScheduleBCMWorkItem pAdapter %x", pAdapter ) );
do
{
if (BCR_TEST_FLAG(pAdapter, BCR_Initialized)== FALSE)
{
NdisStatus = NDIS_STATUS_FAILURE;
break;
}
pBCMWorkItem = ALLOC_NONPAGED (sizeof(NDIS_WORK_ITEM), MTAG_WORKITEM);
if (pBCMWorkItem == NULL )
{
TRACE( TL_A, TM_Cm, ( "Local Alloc failed for WorkItem" ) );
NdisStatus = NDIS_STATUS_RESOURCES;
break;
}
else
{
//
// From here on, this function cannot fail.
//
NdisStatus = NDIS_STATUS_SUCCESS;
}
//
// reference the adapter as it is going to passed to a workiter.
// decremented in the workitem
//
nicReferenceAdapter(pAdapter, "nicScheduleBCMWorkItem ");
NdisInitializeWorkItem ( pBCMWorkItem,
(NDIS_PROC) nicBCMAlgorithmWorkItem,
(PVOID) pAdapter);
TRACE( TL_V, TM_Cm, ( "Scheduling BCM WorkItem" ) );
NdisScheduleWorkItem (pBCMWorkItem);
} while (FALSE);
TRACE( TL_T, TM_Bcm, ( "<==nicScheduleBCMWorkItem %x ", NdisStatus ) );
return NdisStatus;
}
VOID
nicSetEventMakeCall (
IN PADAPTERCB pAdapter
)
// Function Description:
// The Sets the event that a Broadcast channel Make Call might be waiting for
//
// Arguments
// Adapter - this is passed to the workitem
//
//
// Return Value:
// Failure if allocation of workitem failed
//
{
TRACE( TL_T, TM_Bcm, ( "==> nicSetEventMakeCall pAdapter %x", pAdapter) );
//
// now inform a waiting channel Vc to move on. If the BCR is not active.
// it will continue waiting till the next round
//
if (BCR_IS_VALID(&(pAdapter->BCRData.IRM_BCR))==TRUE)
{
ADAPTER_ACQUIRE_LOCK (pAdapter);
if (BCR_TEST_FLAG (pAdapter, BCR_MakeCallPending) == TRUE)
{
TRACE( TL_V, TM_Bcm, ( " We found a waiting call ") );
NdisSetEvent (&pAdapter->BCRData.MakeCallWaitEvent.NdisEvent);
}
else
{
TRACE( TL_V, TM_Bcm, ( " No Call Waiting") );
}
ADAPTER_RELEASE_LOCK (pAdapter);
}
TRACE( TL_T, TM_Bcm, ( "<==nicSetEventMakeCall ") );
}
VOID
nicUpdateLocalHostNodeAddress (
IN PADAPTERCB pAdapter
)
/*++
Routine Description:
This function queries the Bus driver for the Local Node Address of
the Adapter
If the Node Address has changed, it updates the GaspHeader
Arguments:
pAdapter - Adapter
Return Value:
--*/
{
NODE_ADDRESS LocalNodeAddress, OldNodeAddress;
NDIS_STATUS NdisStatus;
OldNodeAddress = pAdapter->NodeAddress;
NdisStatus = nicGet1394AddressFromDeviceObject( pAdapter->pNdisDeviceObject,
&LocalNodeAddress,
USE_LOCAL_NODE );
if (NdisStatus == NDIS_STATUS_SUCCESS)
{
pAdapter->NodeAddress = LocalNodeAddress;
// If the Node Address has changed , then update the GaspHeader
//
if (FALSE == NdisEqualMemory (&LocalNodeAddress,&OldNodeAddress, sizeof(NODE_ADDRESS) ) )
{
nicMakeGaspHeader (pAdapter, &pAdapter->GaspHeader);
}
}
}