diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/ndis/ibmtok/ibmtok.c | 5906 |
1 files changed, 5906 insertions, 0 deletions
diff --git a/private/ntos/ndis/ibmtok/ibmtok.c b/private/ntos/ndis/ibmtok/ibmtok.c new file mode 100644 index 000000000..30e4da708 --- /dev/null +++ b/private/ntos/ndis/ibmtok/ibmtok.c @@ -0,0 +1,5906 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + ibmtok.c + +Abstract: + + This is the main file for the IBM Token-Ring 16/4 Adapter. + This driver conforms to the NDIS 3.0 interface. + + The overall structure and much of the code is taken from + the Lance NDIS driver by Tony Ercolano. + +Author: + + Anthony V. Ercolano (Tonye) 20-Jul-1990 + Adam Barr (adamba) 15-Feb-1990 + +Environment: + + Kernel Mode - Or whatever is the equivalent. + +Revision History: + + Sean Selitrennikoff -- 9/15/91: + Added code to handle Microchannel with PC I/O bus handling. + Fixed bugs. + Sean Selitrennikoff -- 10/15/91: + Converted to Ndis 3.0 spec. + George Joy -- 12/1/91 + Changed for compilation under DOS as well as NT + Sean Selitrennikoff -- 1/8/92: + Added error logging + Brian E. Moore -- 8/8/95 + Added AutoRingSpeed Support for the PCMCIA token-ring III card. + + Sanjay Deshpande -- 11/22/95 + PCMCIA MMIO and RAM is read from registry always .... no default values +--*/ + + +#include <ndis.h> + + +#include <tfilter.h> +#include <tokhrd.h> +#include <toksft.h> + +#include "keywords.h" + +// +// This constant is used for places where NdisAllocateMemory +// needs to be called and the HighestAcceptableAddress does +// not matter. +// + +const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = + NDIS_PHYSICAL_ADDRESS_CONST(-1,-1); + + +// +// If you add to this, make sure to add the +// a case in IbmtokFillInGlobalData() and in +// IbmtokQueryGlobalStatistics() +// +static const UINT IbmtokGlobalSupportedOids[] = { + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_LOOKAHEAD, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_MAC_OPTIONS, + OID_GEN_PROTOCOL_OPTIONS, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_RECEIVE_BUFFER_SPACE, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_CURRENT_LOOKAHEAD, + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, + OID_802_5_PERMANENT_ADDRESS, + OID_802_5_CURRENT_ADDRESS, + OID_802_5_CURRENT_FUNCTIONAL, + OID_802_5_CURRENT_GROUP, + OID_802_5_LAST_OPEN_STATUS, + OID_802_5_CURRENT_RING_STATUS, + OID_802_5_CURRENT_RING_STATE, + OID_802_5_LINE_ERRORS, + OID_802_5_LOST_FRAMES + }; + +// +// If you add to this, make sure to add the +// a case in IbmtokQueryGlobalStatistics() and in +// IbmtokQueryProtocolInformation() +// +static const UINT IbmtokProtocolSupportedOids[] = { + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_LOOKAHEAD, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_MAC_OPTIONS, + OID_GEN_PROTOCOL_OPTIONS, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_RECEIVE_BUFFER_SPACE, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_CURRENT_LOOKAHEAD, + OID_802_5_PERMANENT_ADDRESS, + OID_802_5_CURRENT_ADDRESS, + OID_802_5_CURRENT_FUNCTIONAL, + OID_802_5_CURRENT_GROUP + }; + + +// +// On a development build, don't define functions as static +// so we can set breakpoints on them. +// + + +#if DEVL +#define STATIC +#else +#define STATIC static +#endif + + +#if DBG +INT IbmtokDbg = 0; +#define LOG 1 +#else +#define LOG 0 +#endif + + +// +// Get from configuration file. +// + +#define MAX_MULTICAST_ADDRESS ((UINT)16) +#define MAX_ADAPTERS ((UINT)4) + + +// +// This macro determines if the directed address +// filtering in the CAM is actually necessary given +// the current filter. +// +#define CAM_DIRECTED_SIGNIFICANT(_Filter) \ + ((((_Filter) & NDIS_PACKET_TYPE_DIRECTED) && \ + (!((_Filter) & NDIS_PACKET_TYPE_PROMISCUOUS))) ? 1 : 0) + + +// +// This macro determines if the multicast filtering in +// the CAM are actually necessary given the current filter. +// +#define CAM_MULTICAST_SIGNIFICANT(_Filter) \ + ((((_Filter) & NDIS_PACKET_TYPE_MULTICAST) && \ + (!((_Filter) & (NDIS_PACKET_TYPE_ALL_MULTICAST | \ + NDIS_PACKET_TYPE_PROMISCUOUS)))) ? 1 : 0) + + +STATIC +NDIS_STATUS +IbmtokOpenAdapter( + OUT PNDIS_STATUS OpenErrorStatus, + OUT NDIS_HANDLE *MacBindingHandle, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE NdisBindingContext, + IN NDIS_HANDLE MacAdapterContext, + IN UINT OpenOptions, + IN PSTRING AddressingInformation OPTIONAL + ); + +STATIC +NDIS_STATUS +IbmtokCloseAdapter( + IN NDIS_HANDLE MacBindingHandle + ); + + +STATIC +NDIS_STATUS +IbmtokRequest( + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest + ); + +STATIC +NDIS_STATUS +IbmtokQueryInformation( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open, + IN PNDIS_REQUEST NdisRequest + ); + + +STATIC +NDIS_STATUS +IbmtokSetInformation( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open, + IN PNDIS_REQUEST NdisRequest + ); + +STATIC +NDIS_STATUS +IbmtokQueryGlobalStatistics( + IN NDIS_HANDLE MacAdapterContext, + IN PNDIS_REQUEST NdisRequest + ); + +NDIS_STATUS +IbmtokAddAdapter( + IN NDIS_HANDLE MacMacContext, + IN NDIS_HANDLE ConfigurationHandle, + IN PNDIS_STRING AdaptName + ); + +VOID +IbmtokRemoveAdapter( + IN PVOID MacAdapterContext + ); + +STATIC +NDIS_STATUS +IbmtokSetPacketFilter( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open, + IN PNDIS_REQUEST NdisRequest, + IN UINT PacketFilter + ); + +STATIC +NDIS_STATUS +IbmtokSetGroupAddress( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open, + IN PNDIS_REQUEST NdisRequest, + IN PUCHAR Address + ); + +STATIC +NDIS_STATUS +IbmtokChangeFunctionalAddress( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open, + IN PNDIS_REQUEST NdisRequest, + IN PUCHAR Address + ); + +STATIC +NDIS_STATUS +IbmtokReset( + IN NDIS_HANDLE MacBindingHandle + ); + +STATIC +NDIS_STATUS +IbmtokTest( + IN NDIS_HANDLE MacBindingHandle + ); + +STATIC +NDIS_STATUS +IbmtokChangeFilter( + IN UINT OldFilterClasses, + IN UINT NewFilterClasses, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +STATIC +NDIS_STATUS +IbmtokChangeAddress( + IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress, + IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +STATIC +NDIS_STATUS +IbmtokChangeGroupAddress( + IN TR_FUNCTIONAL_ADDRESS OldGroupAddress, + IN TR_FUNCTIONAL_ADDRESS NewGroupAddress, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +STATIC +BOOLEAN +IbmtokHardwareDetails( + IN PIBMTOK_ADAPTER Adapter + ); + +STATIC +NDIS_STATUS +IbmtokRegisterAdapter( + IN PIBMTOK_ADAPTER Adapter, + IN NDIS_HANDLE ConfigurationHandle, + IN PNDIS_STRING DeviceName, + IN BOOLEAN McaCard, + IN BOOLEAN ConfigError + ); + +STATIC +VOID +SetInitializeVariables( + IN PIBMTOK_ADAPTER Adapter + ); + +VOID +SetResetVariables( + IN PIBMTOK_ADAPTER Adapter + ); + +extern +VOID +IbmtokStartAdapterReset( + IN PIBMTOK_ADAPTER Adapter + ); + +STATIC +VOID +IbmtokCloseAction( + IN NDIS_HANDLE MacBindingHandle + ); + +STATIC +VOID +IbmtokSetupRegistersAndInit( + IN PIBMTOK_ADAPTER Adapter + ); + +STATIC +NDIS_STATUS +IbmtokInitialInit( + IN PIBMTOK_ADAPTER Adapter + ); + +VOID +IbmtokUnload( + IN NDIS_HANDLE MacMacContext + ); + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +#pragma NDIS_INIT_FUNCTION(DriverEntry) + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + This is the primary initialization routine for the ibmtok driver. + It is simply responsible for the intializing the wrapper and registering + the MAC. It then calls a system and architecture specific routine that + will initialize and register each adapter. + +Arguments: + + DriverObject - Pointer to driver object created by the system. + +Return Value: + + The status of the operation. + +--*/ + +{ + + + // + // Receives the status of the NdisRegisterMac operation. + // + NDIS_STATUS InitStatus; + PIBMTOK_MAC IbmtokMac; + NDIS_HANDLE NdisWrapperHandle; + char Tmp[sizeof(NDIS_MAC_CHARACTERISTICS)]; + PNDIS_MAC_CHARACTERISTICS IbmtokChar = (PNDIS_MAC_CHARACTERISTICS)(PVOID)Tmp; + NDIS_STRING MacName = NDIS_STRING_CONST("IbmTok"); + +#if NDIS_WIN + UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + 2 * sizeof (USHORT)]; +#endif + +#if NDIS_WIN + ((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=0; + ((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=2; + *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 0)=IBMTOK1_ADAPTER_ID; + *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 1)=IBMTOK2_ADAPTER_ID; + (PVOID) DriverObject = (PVOID) pIds; +#endif + + // + // Initialize the wrapper. + // + + NdisInitializeWrapper( + &NdisWrapperHandle, + DriverObject, + RegistryPath, + NULL + ); + + // + // Now allocate memory for our global structure. + // + + InitStatus = IBMTOK_ALLOC_PHYS(&IbmtokMac, sizeof(IBMTOK_MAC)); + + if (InitStatus != NDIS_STATUS_SUCCESS) { + + return NDIS_STATUS_RESOURCES; + + } + + IbmtokMac->NdisWrapperHandle = NdisWrapperHandle; + + // + // Initialize the MAC characteristics for the call to + // NdisRegisterMac. + // + + + IbmtokChar->MajorNdisVersion = IBMTOK_NDIS_MAJOR_VERSION; + IbmtokChar->MinorNdisVersion = IBMTOK_NDIS_MINOR_VERSION; + IbmtokChar->OpenAdapterHandler = (OPEN_ADAPTER_HANDLER) IbmtokOpenAdapter; + IbmtokChar->CloseAdapterHandler = (CLOSE_ADAPTER_HANDLER) IbmtokCloseAdapter; + IbmtokChar->RequestHandler = IbmtokRequest; + IbmtokChar->SendHandler = IbmtokSend; + IbmtokChar->TransferDataHandler = IbmtokTransferData; + IbmtokChar->ResetHandler = IbmtokReset; + IbmtokChar->UnloadMacHandler = IbmtokUnload; + IbmtokChar->QueryGlobalStatisticsHandler = IbmtokQueryGlobalStatistics; + IbmtokChar->AddAdapterHandler = IbmtokAddAdapter; + IbmtokChar->RemoveAdapterHandler = IbmtokRemoveAdapter; + + IbmtokChar->Name = MacName; + + NdisRegisterMac( + &InitStatus, + &IbmtokMac->NdisMacHandle, + NdisWrapperHandle, + (PVOID)IbmtokMac, + IbmtokChar, + sizeof(*IbmtokChar) + ); + + if (InitStatus != NDIS_STATUS_SUCCESS) { + + NdisTerminateWrapper(NdisWrapperHandle, NULL); + + return NDIS_STATUS_FAILURE; + + } + + return NDIS_STATUS_SUCCESS; + +} + + + +#pragma NDIS_INIT_FUNCTION(IbmtokRegisterAdapter) + +STATIC +NDIS_STATUS +IbmtokRegisterAdapter( + IN PIBMTOK_ADAPTER Adapter, + IN NDIS_HANDLE ConfigurationHandle, + IN PNDIS_STRING DeviceName, + IN BOOLEAN McaCard, + IN BOOLEAN ConfigError + ) + +/*++ + +Routine Description: + + This routine (and its interface) are not portable. They are + defined by the OS, the architecture, and the particular IBMTOK + implementation. + + This routine is responsible for the allocation of the datastructures + for the driver as well as any hardware specific details necessary + to talk with the device. + +Arguments: + + Adapter - Pointer to the adapter block. + + ConfigurationHandle - Handle passed to MacAddAdapter, to be passed to + NdisRegisterAdapter. + + DeviceName - Name of this adapter. + + McaCard - This is an MCA bus. + + ConfigError - TRUE if a configuration error was found earlier. + +Return Value: + + Returns NDIS_STATUS_SUCCESS if everything goes ok, else + if anything occurred that prevents the initialization + of the adapter it returns an appropriate NDIS error. + +--*/ + +{ + + NDIS_STATUS Status; + + // + // Holds information needed when registering the adapter. + // + + NDIS_ADAPTER_INFORMATION AdapterInformation; + + // We put in this assertion to make sure that ushort are 2 bytes. + // if they aren't then the initialization block definition needs + // to be changed. + // + // Also all of the logic that deals with status registers assumes + // that control registers are only 2 bytes. + // + + ASSERT(sizeof(USHORT) == 2); + + // + // Get the interrupt number and MMIO address. + // + + // + // Set the adapter state. + // + + SetInitializeVariables(Adapter); + + SetResetVariables(Adapter); + + // + // Set up the AdapterInformation structure; zero it + // first in case it is extended later. + // + + IBMTOK_ZERO_MEMORY (&AdapterInformation, sizeof(NDIS_ADAPTER_INFORMATION)); + AdapterInformation.AdapterType = (McaCard ? NdisInterfaceMca : NdisInterfaceIsa); + AdapterInformation.NumberOfPortDescriptors = 1; + AdapterInformation.PortDescriptors[0].InitialPort = Adapter->IbmtokPortAddress; + AdapterInformation.PortDescriptors[0].NumberOfPorts = 4; + + // + // Register the adapter with Ndis. + // + + Status = NdisRegisterAdapter( + &Adapter->NdisAdapterHandle, + Adapter->NdisMacHandle, + Adapter, + ConfigurationHandle, + DeviceName, + &AdapterInformation + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + return(Status); + + } + + if (ConfigError) { + + // + // Error and quit + // + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, + 0 + ); + + NdisDeregisterAdapter(Adapter->NdisAdapterHandle); + + return(NDIS_STATUS_FAILURE); + + } + + + + if (!IbmtokHardwareDetails(Adapter)) { + + NdisDeregisterAdapter(Adapter->NdisAdapterHandle); + return NDIS_STATUS_ADAPTER_NOT_FOUND; + + } + + + // + // Reset the card to put it in a valid state. + // + + if (Adapter->SharedRamPaging) { + + WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, 0xc0); + + } + + // + // OK, do the reset as detailed in the Tech Ref... + // + + WRITE_ADAPTER_PORT(Adapter, RESET_LATCH, 0); + + NdisStallExecution(50000); + + WRITE_ADAPTER_PORT(Adapter, RESET_RELEASE, 0); + + // + // Initialize the interrupt. + // + + NdisAllocateSpinLock(&Adapter->InterruptLock); + + NdisInitializeInterrupt( + &Status, + &Adapter->Interrupt, + Adapter->NdisAdapterHandle, + IbmtokISR, + Adapter, + IbmtokDPC, + Adapter->InterruptLevel, + Adapter->InterruptLevel, + FALSE, + (Adapter->UsingPcIoBus)?NdisInterruptLatched: + NdisInterruptLevelSensitive + ); + + if (Status == NDIS_STATUS_SUCCESS){ + + // + // Set up the Adapter variables. (We have to do the + // initial init to get the network address before we + // create the filter DB.) + // + if (IbmtokInitialInit(Adapter) != NDIS_STATUS_SUCCESS) { + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_ADAPTER_NOT_FOUND, + 2, + registerAdapter, + IBMTOK_ERRMSG_NOT_FOUND + ); + + NdisRemoveInterrupt(&Adapter->Interrupt); + + NdisDeregisterAdapter(Adapter->NdisAdapterHandle); + NdisFreeSpinLock(&(Adapter->Lock)); + return NDIS_STATUS_ADAPTER_NOT_FOUND; + + } else { + + if (!TrCreateFilter( + IbmtokChangeAddress, + IbmtokChangeGroupAddress, + IbmtokChangeFilter, + IbmtokCloseAction, + Adapter->NetworkAddress, + &Adapter->Lock, + &Adapter->FilterDB + )) { + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + registerAdapter, + IBMTOK_ERRMSG_CREATE_DB + ); + + NdisRemoveInterrupt(&Adapter->Interrupt); + NdisDeregisterAdapter(Adapter->NdisAdapterHandle); + NdisFreeSpinLock(&(Adapter->Lock)); + return NDIS_STATUS_RESOURCES; + + } else { + + // + // Initialize the wake up timer to catch interrupts that + // don't complete. It fires continuously + // every thirty seconds, and we check if there are any + // uncompleted operations from the previous two-second + // period. + // + + Adapter->WakeUpDpc = (PVOID)IbmtokWakeUpDpc; + + NdisInitializeTimer(&Adapter->WakeUpTimer, + (PVOID)(Adapter->WakeUpDpc), + Adapter ); + + NdisSetTimer( + &Adapter->WakeUpTimer, + 30000 + ); + + NdisRegisterAdapterShutdownHandler( + Adapter->NdisAdapterHandle, + (PVOID)Adapter, + IbmtokShutdown + ); + + return(NDIS_STATUS_SUCCESS); + + } + + } + + } else { + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_INTERRUPT_CONNECT, + 2, + registerAdapter, + IBMTOK_ERRMSG_INIT_INTERRUPT + ); + + NdisDeregisterAdapter(Adapter->NdisAdapterHandle); + NdisFreeSpinLock(&(Adapter->Lock)); + return(Status); + } + +} + + +#pragma NDIS_INIT_FUNCTION(SetInitializeVariables) + +STATIC +VOID +SetInitializeVariables( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine initializes all the variables in the Adapter + structure that should only be set during adapter initialization + (i.e. not during a reset). + +Arguments: + + Adapter - The adapter for the hardware. + +Return Value: + + None. + +--*/ + +{ + InitializeListHead(&Adapter->OpenBindings); + InitializeListHead(&Adapter->CloseList); + InitializeListHead(&Adapter->CloseDuringResetList); + + NdisAllocateSpinLock(&Adapter->Lock); + + // + // If this is not true, then uncomment below + // + + ASSERT(FALSE == (BOOLEAN)0); + + // Adapter->HandleSrbRunning = FALSE; + // Adapter->HandleArbRunning = FALSE; + + // Adapter->OpenInProgress = FALSE; + + Adapter->AdapterNotOpen = TRUE; + Adapter->NotAcceptingRequests = TRUE; + + // Adapter->ResetInProgress = FALSE; + // Adapter->ResettingOpen = NULL; + // Adapter->ResetInterruptAllowed = FALSE; + // Adapter->ResetInterruptHasArrived = FALSE; + + // Adapter->BringUp = FALSE; + + // + // Note: These assume that the SAP info will not + // take up more than 218 bytes. This is ok, for now, since + // we open the card with 0 SAPs allowed. + // + + Adapter->ReceiveBufferLength = 256; + Adapter->NumberOfTransmitBuffers = 1; + + // + // Note: The following fields are set in the interrupt handler after + // the card tells us if the ring is 16 or 4 Mbps. + // + // + // TransmitBufferLength + // NumberOfReceiveBuffers + // MaximumTransmittablePacket + // + + // Adapter->IsrpDeferredBits = 0; + + Adapter->FirstInitialization = TRUE; + + // Adapter->OutstandingAsbFreeRequest = FALSE; +} + + +VOID +SetResetVariables( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine initializes all the variables in the Adapter + structure that are set both during an initialization and + after a reset. + +Arguments: + + Adapter - The adapter for the hardware. + +Return Value: + + None. + +--*/ + +{ + Adapter->FirstTransmit = NULL; + Adapter->LastTransmit = NULL; + Adapter->FirstWaitingForAsb = NULL; + Adapter->LastWaitingForAsb = NULL; + Adapter->TransmittingPacket = NULL; + + IBMTOK_ZERO_MEMORY(Adapter->CorrelatorArray, + sizeof(PNDIS_PACKET) * MAX_COMMAND_CORRELATOR); + + Adapter->PendQueue = NULL; + Adapter->EndOfPendQueue = NULL; + + Adapter->SrbAvailable = TRUE; + Adapter->AsbAvailable = TRUE; + + Adapter->IsrpBits = 0; + Adapter->IsrpLowBits = 0; + + Adapter->NextCorrelatorToComplete = 0; + Adapter->ReceiveWaitingForAsbList = (USHORT)-1; + Adapter->ReceiveWaitingForAsbEnd = (USHORT)-1; + Adapter->UseNextAsbForReceive = TRUE; +} + +#pragma NDIS_INIT_FUNCTION(IbmtokInitialInit) + +NDIS_STATUS +IbmtokInitialInit( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine sets up the initial init of the driver. + +Arguments: + + Adapter - The adapter for the hardware. + +Return Value: + + None. + +--*/ + +{ + USHORT RegValue; + UINT Time = 50; // Number of 100 milliseconds to delay while waiting + // for the card to initialize. + + + + IbmtokSetupRegistersAndInit(Adapter); + + // + // Delay execution for 5 seconds to give the ring + // time to initialize. + // + + while((!Adapter->BringUp) && (Time != 0)){ + + NdisStallExecution(100000); + + Time--; + + } + + if (!Adapter->BringUp){ + + return(NDIS_STATUS_ADAPTER_NOT_FOUND); + + } else { + + // + // Do remaining initialization. + // + + USHORT WrbOffset; + PSRB_BRING_UP_RESULT BringUpSrb; + PUCHAR EncodedAddress; + UCHAR Value1, Value2; + + READ_ADAPTER_REGISTER(Adapter, WRBR_LOW, &Value1); + READ_ADAPTER_REGISTER(Adapter, WRBR_HIGH, &Value2); + + WrbOffset = (((USHORT)Value1) << 8) + (USHORT)Value2; + + Adapter->InitialWrbOffset = WrbOffset; + +#if DBG + if (IbmtokDbg) { + + DbgPrint("IBMTOK: Initial Offset = 0x%x\n", WrbOffset); + + } +#endif + + BringUpSrb = (PSRB_BRING_UP_RESULT) + (Adapter->SharedRam + WrbOffset); + + NdisReadRegisterUshort(&(BringUpSrb->ReturnCode), &RegValue); + + if (RegValue != 0x0000) { + + if (RegValue == 0x30){ + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, + 0x32, + handleSrbSsb, + IBMTOK_ERRMSG_BRINGUP_FAILURE + ); + + + return(NDIS_STATUS_ADAPTER_NOT_FOUND); + + } else { + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 3, + handleSrbSsb, + IBMTOK_ERRMSG_BRINGUP_FAILURE, + (ULONG)RegValue + ); + + return(NDIS_STATUS_ADAPTER_NOT_FOUND); + + + } + + } else { + + Adapter->FirstInitialization = FALSE; + Adapter->BringUp = TRUE; + + } + + NdisReadRegisterUchar(&(BringUpSrb->InitStatus), &RegValue); + +// The following routine assumes that the AutoRingSpeed keyword is set in +// the registry. If the adapter doesn't support RingSpeedListen, turn off flag. + + + if (!(RegValue & RINGSPEEDLISTEN)) { + + Adapter->RingSpeedListen = FALSE; + +#if DBG + if (IbmtokDbg) DbgPrint("IBMTOK: Adapter doesn't support Ring Speed Listen.\n"); +#endif + + } + + if (RegValue & 0x01) { + +#if DBG + if (IbmtokDbg) DbgPrint("IBMTOK: 16 Mbps\n"); +#endif + + Adapter->Running16Mbps = TRUE; + + } else { + + Adapter->Running16Mbps = FALSE; + + } + + // + // ZZZ: This code assumes that there is no shared ram paging and + // that the MappedSharedRam is all that is available. + // + + +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: shared RAM size is %x (%d)\n", Adapter->MappedSharedRam, Adapter->MappedSharedRam ); +#endif + if (Adapter->MappedSharedRam > 0x2000){ + + ULONG RamAvailable; + UCHAR NumTransmitBuffers = (UCHAR)Adapter->NumberOfTransmitBuffers; + + // + // 2096 is the amount of shared ram that is current sucked + // up by the areas found on page 7-27 of the Tech. Ref. + // + // + + RamAvailable = Adapter->MappedSharedRam; + + if (Adapter->MappedSharedRam == 0x10000){ + + // + // Subtract an extra 8K to account for when we map + // MMIO space to the top 8K of RAM. + // + + RamAvailable = RamAvailable - 2096 - 0x2000; + + } else { + + RamAvailable = RamAvailable - 1584; + + } +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: RAM available is %x (%d)\n", RamAvailable, RamAvailable ); +#endif + + // + // The card has more than 8K of ram, so adjust + // transmit buffer size to abuse this. + // + + if (Adapter->Running16Mbps) { + + // + // Use the maximum allowed + // + + Adapter->TransmitBufferLength = Adapter->Max16MbpsDhb; +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: 16 MB ring. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength ); +#endif + + } else { + + // + // Use the maximum allowed + // + Adapter->TransmitBufferLength = Adapter->Max4MbpsDhb; +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: 4 MB ring. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength ); +#endif + + } + + // + // First we subtract off buffer space for receiving the + // maximum sized packet that can be on the wire. This is + // the *minimum* number of receive buffers and may be + // modified below if the transmit space does not take up + // the rest. + // + +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: Receive buffer length is %x (%d)\n", Adapter->ReceiveBufferLength, Adapter->ReceiveBufferLength ); +#endif + if (RamAvailable < Adapter->TransmitBufferLength) { + + // + // There is not enough buffer space for even a single maximum + // sized frame. So, just divide the buffer space into two + // equally sized areas -- receive and transmit. + // + + Adapter->NumberOfReceiveBuffers = (USHORT)((RamAvailable / 2) / + Adapter->ReceiveBufferLength) + + 1; +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: RAM too small. # receive buffers is %x (%d)\n", Adapter->NumberOfReceiveBuffers, Adapter->NumberOfReceiveBuffers ); +#endif + + } else { + + Adapter->NumberOfReceiveBuffers = (USHORT)(Adapter->TransmitBufferLength / + Adapter->ReceiveBufferLength) + 1; +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: RAM large enough. # receive buffers is %x (%d)\n", Adapter->NumberOfReceiveBuffers, Adapter->NumberOfReceiveBuffers ); +#endif + + } + + RamAvailable = RamAvailable - + (Adapter->NumberOfReceiveBuffers * Adapter->ReceiveBufferLength); +#if DBG + if (IbmtokDbg) { + DbgPrint( "IBMTOK: RAM available for transmit is %x (%d)\n", RamAvailable, RamAvailable ); + DbgPrint( "IBMTOK: # transmit buffers is %x (%d)\n", NumTransmitBuffers, NumTransmitBuffers ); + } +#endif + + if (Adapter->TransmitBufferLength > (RamAvailable / NumTransmitBuffers)) { + + if ((RamAvailable / NumTransmitBuffers) < 0x1000) { + + Adapter->TransmitBufferLength = 0x800; + + } else if ((RamAvailable / NumTransmitBuffers) < 0x2000) { + + Adapter->TransmitBufferLength = 0x1000; + + } else if ((RamAvailable / NumTransmitBuffers) < 0x4000) { + + Adapter->TransmitBufferLength = 0x2000; + + } else { + + Adapter->TransmitBufferLength = 0x4000; + + } + +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: RAM too small. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength ); +#endif + } + + + // + // If computed value is greater than the value that the + // registry allows, then use the registry value. + // + +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: Original max transmit length is %x (%d)\n", Adapter->MaxTransmittablePacket, Adapter->MaxTransmittablePacket ); +#endif + if (Adapter->TransmitBufferLength > Adapter->MaxTransmittablePacket) { + + Adapter->TransmitBufferLength = Adapter->MaxTransmittablePacket; +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: Max too small. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength ); +#endif + + } + + Adapter->MaxTransmittablePacket = Adapter->TransmitBufferLength - 6; +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: New max transmit length is %x (%d)\n", Adapter->MaxTransmittablePacket, Adapter->MaxTransmittablePacket ); +#endif + + // + // Remove space taken up by transmit buffers. + // + + RamAvailable = RamAvailable - ((ULONG)NumTransmitBuffers * + (ULONG)Adapter->TransmitBufferLength); + + // + // Add in any left over space for receive buffers. + // + + Adapter->NumberOfReceiveBuffers += (USHORT)(RamAvailable / + Adapter->ReceiveBufferLength); +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: New # receive buffers is %x (%d)\n", Adapter->NumberOfReceiveBuffers, Adapter->NumberOfReceiveBuffers ); +#endif + + } else { + + Adapter->TransmitBufferLength = 0x800; + Adapter->NumberOfTransmitBuffers = 1; +#if DBG + if (IbmtokDbg) { + DbgPrint( "IBMTOK: Only 8K shared RAM. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength ); + DbgPrint( "IBMTOK: Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength ); + } +#endif + + // + // There is only 8K of buffer space, which is not enough space for + // receiving and transmitting packets on even a 4Mbit ring. So, + // use some reasonable values for transmit and receive space. + // + + // If computed value is greater than the value that the + // registry allows, then use the registry value. + // + +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: Original max transmit length is %x (%d)\n", Adapter->MaxTransmittablePacket, Adapter->MaxTransmittablePacket ); +#endif + if (Adapter->TransmitBufferLength > Adapter->MaxTransmittablePacket) { + + Adapter->TransmitBufferLength = Adapter->MaxTransmittablePacket; +#if DBG + if (IbmtokDbg) DbgPrint( "IBMTOK: Max too small. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength ); +#endif + + } + + Adapter->MaxTransmittablePacket = Adapter->TransmitBufferLength - 6; + + Adapter->NumberOfReceiveBuffers = 15; +#if DBG + if (IbmtokDbg) { + DbgPrint( "IBMTOK: New max transmit length is %x (%d)\n", Adapter->MaxTransmittablePacket, Adapter->MaxTransmittablePacket ); + DbgPrint( "IBMTOK: # receive buffers is %x (%d)\n", Adapter->NumberOfReceiveBuffers, Adapter->NumberOfReceiveBuffers ); + } +#endif + + } + +#if DBG + if (IbmtokDbg) { + DbgPrint("IBMTOK: Space: 0x%x, # Rcv: 0x%x, TransmitSize: 0x%x\n", + Adapter->RrrLowValue, + Adapter->NumberOfReceiveBuffers, + Adapter->MaxTransmittablePacket + ); + } +#endif + + NdisReadRegisterUshort(&(BringUpSrb->EncodedAddressPointer), &RegValue); + + EncodedAddress = (PUCHAR) + SRAM_PTR_TO_PVOID(Adapter,RegValue); + + IBMTOK_MOVE_FROM_MAPPED_MEMORY(Adapter->PermanentNetworkAddress, EncodedAddress, + TR_LENGTH_OF_ADDRESS); + + + if ((Adapter->NetworkAddress[0] == 0x00) && + (Adapter->NetworkAddress[1] == 0x00) && + (Adapter->NetworkAddress[2] == 0x00) && + (Adapter->NetworkAddress[3] == 0x00) && + (Adapter->NetworkAddress[4] == 0x00) && + (Adapter->NetworkAddress[5] == 0x00)) { + + + IBMTOK_MOVE_FROM_MAPPED_MEMORY(Adapter->NetworkAddress, EncodedAddress, + TR_LENGTH_OF_ADDRESS); + } + + // + // If required, we have to zero the upper section + // of the Shared RAM now. + // + // + // THIS DOESN'T WORK! It hangs the system while + // zeroing the first address. (One gets an infinite number of + // hardware interrupts w/o any reason) + // + +#if 0 + if (Adapter->UpperSharedRamZero) { + + PUCHAR ZeroPointer; + UINT i; + PUCHAR OldSharedRam; + NDIS_PHYSICAL_ADDRESS PhysicalAddress; + +#if DBG + if (IbmtokDbg) DbgPrint("IBMTOK: Zeroing Memory\n"); +#endif + + + if (Adapter->MappedSharedRam < 0x10000) { + + // + // This portion of memory is not currently mapped, so do it. + // + + OldSharedRam = Adapter->SharedRam; + + NdisSetPhysicalAddressHigh(PhysicalAddress, 0); + NdisSetPhysicalAddressLow(PhysicalAddress, (Adapter->RrrLowValue << 12) + (0x10000 - 512)); + + NdisMapIoSpace( + &Status, + &(Adapter->SharedRam), + Adapter->NdisAdapterHandle, + PhysicalAddress, + 512); + + if (Status != NDIS_STATUS_SUCCESS) { + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_RESOURCE_CONFLICT, + 0 + ); + + return(Status); + + } + + } + + if (Adapter->SharedRamPaging){ + + SETUP_SRPR(Adapter, SHARED_RAM_ZERO_OFFSET); + +#if DBG + if (IbmtokDbg) DbgPrint("IBMTOK: Shared RAM paging enabled\n"); +#endif + + ZeroPointer = + SHARED_RAM_ADDRESS(Adapter, + SHARED_RAM_LOW_BITS(SHARED_RAM_ZERO_OFFSET)); + + } else { + + if (Adapter->MappedSharedRam < 0x10000) { + + // + // No offset for this portion, since we just mapped it. + // + // + + ZeroPointer = SHARED_RAM_ADDRESS(Adapter, 0); + + } else { + + ZeroPointer = + SHARED_RAM_ADDRESS(Adapter, SHARED_RAM_ZERO_OFFSET); + + } + + } + + for (i=0; i<SHARED_RAM_ZERO_LENGTH; i++) { + + NdisWriteRegisterUchar(&(ZeroPointer[i]), 0x00); + + } + + if (Adapter->MappedSharedRam < 0x10000) { + + // + // Unmap it + // + + NdisUnmapIoSpace(Adapter->NdisAdapterHandle, + Adapter->SharedRam, + 512); + + Adapter->SharedRam = OldSharedRam; + + } + + } +#endif + + + // + // Now set the timer to the maximum...we still need it + // as a card heartbeat. + // + + WRITE_ADAPTER_REGISTER(Adapter, TVR_HIGH, 0xff); + + return NDIS_STATUS_SUCCESS; + + } + +} + + +#pragma NDIS_PAGABLE_FUNCTION(IbmtokOpenAdapter) + +STATIC +NDIS_STATUS +IbmtokOpenAdapter( + OUT PNDIS_STATUS OpenErrorStatus, + OUT NDIS_HANDLE *MacBindingHandle, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE NdisBindingContext, + IN NDIS_HANDLE MacAdapterContext, + IN UINT OpenOptions, + IN PSTRING AddressingInformation OPTIONAL + ) + +/*++ + +Routine Description: + + OpenErrorStatus - Returns more information about the error status. In + this card it is not used, since this code returns either success or + pending, no failure is possible. + + This routine is used to create an open instance of an adapter, in effect + creating a binding between an upper-level module and the MAC module over + the adapter. + +Arguments: + + OpenErrorStatus - Returns more information about the error status. In + this card it is not used, since this code returns either success or + pending, no failure is possible. + + MacBindingHandle - A pointer to a location in which the MAC stores + a context value that it uses to represent this binding. + + + SelectedMediumIndex - An index into the MediumArray of the medium + typedef that the MAC wishes to viewed as. + + MediumArray - An array of medium types which the protocol supports. + + MediumArraySize - The number of elements in MediumArray. + + NdisBindingContext - A value to be recorded by the MAC and passed as + context whenever an indication is delivered by the MAC for this binding. + + MacAdapterContext - The value associated with the adapter that is being + opened when the MAC registered the adapter with NdisRegisterAdapter. + + IN UINT OpenOptions, + + AddressingInformation - An optional pointer to a variable length string + containing hardware-specific information that can be used to program the + device. (This is not used by this MAC.) + +Return Value: + + The function value is the status of the operation. If the MAC does not + complete this request synchronously, the value would be + NDIS_STATUS_PENDING. + + +--*/ + +{ + + // + // The IBMTOK_ADAPTER that this open binding should belong too. + // + PIBMTOK_ADAPTER Adapter; + + // + // Holds the status that should be returned to the caller. + // + NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS; + + // + // Pointer to the space allocated for the binding. + // + PIBMTOK_OPEN NewOpen; + + // + // Generic loop variable + // + UINT i; + + + UNREFERENCED_PARAMETER(AddressingInformation); + + *OpenErrorStatus = (NDIS_STATUS)0; + + // + // Search for the medium type (token ring) + // + + for(i=0; i < MediumArraySize; i++){ + + if (MediumArray[i] == NdisMedium802_5){ + + break; + + } + + } + + if (i == MediumArraySize){ + + return(NDIS_STATUS_UNSUPPORTED_MEDIA); + + } + + *SelectedMediumIndex = i; + + Adapter = PIBMTOK_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext); + + NdisInterlockedAddUlong((PULONG)&Adapter->References, 1, &Adapter->Lock); + + // + // Allocate the space for the open binding. Fill in the fields. + // + + if (IBMTOK_ALLOC_PHYS(&NewOpen, sizeof(IBMTOK_OPEN)) == + NDIS_STATUS_SUCCESS){ + + *MacBindingHandle = BINDING_HANDLE_FROM_PIBMTOK_OPEN(NewOpen); + InitializeListHead(&NewOpen->OpenList); + NewOpen->NdisBindingContext = NdisBindingContext; + NewOpen->References = 0; + NewOpen->BindingShuttingDown = FALSE; + NewOpen->OwningIbmtok = Adapter; + NewOpen->OpenPending = FALSE; + + NdisAcquireSpinLock(&Adapter->Lock); + if (!TrNoteFilterOpenAdapter( + NewOpen->OwningIbmtok->FilterDB, + NewOpen, + NdisBindingContext, + &NewOpen->NdisFilterHandle + )) { + + NdisReleaseSpinLock(&Adapter->Lock); + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + openAdapter, + IBMTOK_ERRMSG_OPEN_DB + ); + + IBMTOK_FREE_PHYS(NewOpen, sizeof(IBMTOK_OPEN)); + + StatusToReturn = NDIS_STATUS_FAILURE; + NdisAcquireSpinLock(&Adapter->Lock); + + } else { + + // + // Everything has been filled in. Synchronize access to the + // adapter block and link the new open adapter in and increment + // the opens reference count to account for the fact that the + // filter routines have a "reference" to the open. + // + + NewOpen->LookAhead = IBMTOK_MAX_LOOKAHEAD; + + Adapter->LookAhead = IBMTOK_MAX_LOOKAHEAD; + + InsertTailList(&Adapter->OpenBindings,&NewOpen->OpenList); + NewOpen->References++; + + // + // Now see if the adapter is currently open. + // + + if (Adapter->AdapterNotOpen) { + + // + // The adapter is not open, so this has to pend. + // + NewOpen->OpenPending = TRUE; + + StatusToReturn = NDIS_STATUS_PENDING; + + if (!Adapter->OpenInProgress) { + + // + // Fill in the SRB for the open if this is the first + // one for the card. + // + + PSRB_OPEN_ADAPTER OpenSrb; + + IF_LOG('o'); + + Adapter->OpenInProgress = TRUE; + Adapter->CurrentRingState = NdisRingStateOpening; + + NdisReleaseSpinLock(&Adapter->Lock); + + OpenSrb = (PSRB_OPEN_ADAPTER) + (Adapter->SharedRam + Adapter->InitialWrbOffset); + + IBMTOK_ZERO_MAPPED_MEMORY(OpenSrb, sizeof(SRB_OPEN_ADAPTER)); + + NdisWriteRegisterUchar( + (PUCHAR)&OpenSrb->Command, + SRB_CMD_OPEN_ADAPTER); + + NdisWriteRegisterUshort( + (PUSHORT)&OpenSrb->OpenOptions, + (USHORT)(OPEN_CONTENDER | + (Adapter->RingSpeedListen ? + OPEN_REMOTE_PROGRAM_LOAD : + 0)) + ); + + for (i=0; i < TR_LENGTH_OF_ADDRESS; i++) { + NdisWriteRegisterUchar((PCHAR)&OpenSrb->NodeAddress[i], + Adapter->NetworkAddress[i] + ); + } + + WRITE_IBMSHORT(OpenSrb->ReceiveBufferNum, + Adapter->NumberOfReceiveBuffers); + WRITE_IBMSHORT(OpenSrb->ReceiveBufferLen, + Adapter->ReceiveBufferLength); + + WRITE_IBMSHORT(OpenSrb->TransmitBufferLen, + Adapter->TransmitBufferLength); + NdisWriteRegisterUchar( + (PUCHAR)&OpenSrb->TransmitBufferNum, + (UCHAR)Adapter->NumberOfTransmitBuffers); + + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_COMMAND_IN_SRB); + + NdisAcquireSpinLock(&Adapter->Lock); + + } + + } + + } + + } else { + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + openAdapter, + IBMTOK_ERRMSG_ALLOC_MEM + ); + + return(NDIS_STATUS_RESOURCES); + + } + + + + + // + // This macro assumes it is called with the lock held, + // and releases it. + // + + IBMTOK_DO_DEFERRED(Adapter); + return StatusToReturn; +} + + +VOID +IbmtokAdjustMaxLookAhead( + IN PIBMTOK_ADAPTER Adapter + ) +/*++ + +Routine Description: + + This routine finds the open with the maximum lookahead value and + stores that in the adapter block. + +Arguments: + + Adapter - A pointer to the adapter block. + +Returns: + + None. + +--*/ +{ + ULONG CurrentMax = 0; + PLIST_ENTRY CurrentLink; + PIBMTOK_OPEN TempOpen; + + CurrentLink = Adapter->OpenBindings.Flink; + + while (CurrentLink != &(Adapter->OpenBindings)){ + + TempOpen = CONTAINING_RECORD( + CurrentLink, + IBMTOK_OPEN, + OpenList + ); + + if (TempOpen->LookAhead > CurrentMax) { + + CurrentMax = TempOpen->LookAhead; + + } + + CurrentLink = CurrentLink->Flink; + + } + + if (CurrentMax == 0) { + + CurrentMax = IBMTOK_MAX_LOOKAHEAD; + + } + + Adapter->LookAhead = CurrentMax; + +} + +STATIC +NDIS_STATUS +IbmtokCloseAdapter( + IN NDIS_HANDLE MacBindingHandle + ) + +/*++ + +Routine Description: + + This routine causes the MAC to close an open handle (binding). + +Arguments: + + MacBindingHandle - The context value returned by the MAC when the + adapter was opened. In reality it is a PIBMTOK_OPEN. + +Return Value: + + The function value is the status of the operation. + + +--*/ + +{ + + PIBMTOK_ADAPTER Adapter; + PIBMTOK_OPEN Open; + + NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS; + + Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle); + Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + + // + // Hold the lock while we update the reference counts for the + // adapter and the open. + // + + NdisAcquireSpinLock(&Adapter->Lock); + Adapter->References++; + + if (!Open->BindingShuttingDown) { + + Open->References++; + + StatusToReturn = TrDeleteFilterOpenAdapter( + Adapter->FilterDB, + Open->NdisFilterHandle, + NULL + ); + + // + // If the status is successful that merely implies that + // we were able to delete the reference to the open binding + // from the filtering code. If we have a successful status + // at this point we still need to check whether the reference + // count to determine whether we can close. + // + // + // The delete filter routine can return a "special" status + // that indicates that there is a current NdisIndicateReceive + // on this binding. + // + + + if (StatusToReturn == NDIS_STATUS_SUCCESS) + { + // + // Check whether the reference count is two. If + // it is then we can get rid of the memory for + // this open. + // + // A count of two indicates one for this routine + // and one for the filter which we *know* we can + // get rid of. + // + + if (Open->References == 2) { + + RemoveEntryList(&Open->OpenList); + + // + // We are the only reference to the open. Remove + // it from the open list and delete the memory. + // + + RemoveEntryList(&Open->OpenList); + + if (Open->LookAhead == Adapter->LookAhead) { + + IbmtokAdjustMaxLookAhead(Adapter); + + } + + IBMTOK_FREE_PHYS(Open,sizeof(IBMTOK_OPEN)); + + } else { + + Open->BindingShuttingDown = TRUE; + + // + // Remove the open from the open list and put it on + // the closing list. + // + + RemoveEntryList(&Open->OpenList); + InsertTailList(&Adapter->CloseList,&Open->OpenList); + + // + // Account for this routines reference to the open + // as well as reference because of the filtering. + // + + Open->References -= 2; + + // + // Change the status to indicate that we will + // be closing this later. + // + + StatusToReturn = NDIS_STATUS_PENDING; + + } + + } + else if (StatusToReturn == NDIS_STATUS_PENDING) + { + // + // If it pended, there may be + // operations queued. + // + if (Adapter->CardType == IBM_TOKEN_RING_PCMCIA) + { + // + // Check if the card is still in the machine + // + ULONG AdapterId; + ULONG PcIoBusId = 0x5049434f; + UINT j; + UCHAR TmpUchar; + + AdapterId = 0; + + for (j = 0; j < 16; j += 2) + { + READ_ADAPTER_REGISTER( + Adapter, + CHANNEL_IDENTIFIER + (16 + j), + &TmpUchar + ); + + AdapterId = (AdapterId << 4) + (TmpUchar & 0x0f); + } + + if (AdapterId != PcIoBusId) + { + Adapter->InvalidValue = TRUE; +#if DBG + if (IbmtokDbg) + DbgPrint("IBMTOK: Card was removed or undocked\n"); +#endif + } + else + { + Adapter->InvalidValue = FALSE; + } + } + + if (Adapter->InvalidValue) + { + IbmtokAbortPending (Adapter, STATUS_SUCCESS); + } + else + { + IbmtokProcessSrbRequests(Adapter); + } + + // + // Now start closing down this open. + // + + Open->BindingShuttingDown = TRUE; + + // + // Remove the open from the open list and put it on + // the closing list. + // + + RemoveEntryList(&Open->OpenList); + InsertTailList(&Adapter->CloseList,&Open->OpenList); + + // + // Account for this routines reference to the open + // as well as reference because of the filtering. + // + + Open->References -= 2; + + } else if (StatusToReturn == NDIS_STATUS_CLOSING_INDICATING) { + + // + // When we have this status it indicates that the filtering + // code was currently doing an NdisIndicateReceive. It + // would not be wise to delete the memory for the open at + // this point. The filtering code will call our close action + // routine upon return from NdisIndicateReceive and that + // action routine will decrement the reference count for + // the open. + // + + Open->BindingShuttingDown = TRUE; + + // + // This status is private to the filtering routine. Just + // tell the caller the the close is pending. + // + + StatusToReturn = NDIS_STATUS_PENDING; + + // + // Remove the open from the open list and put it on + // the closing list. + // + + RemoveEntryList(&Open->OpenList); + InsertTailList(&Adapter->CloseList,&Open->OpenList); + + // + // Account for this routines reference to the open. + // + + Open->References--; + + } else if (StatusToReturn == NDIS_STATUS_RESET_IN_PROGRESS) { + + Open->BindingShuttingDown = TRUE; + + // + // Remove the open from the open list and put it on + // the closing list. + // + + RemoveEntryList(&Open->OpenList); + InsertTailList(&Adapter->CloseDuringResetList,&Open->OpenList); + + + // + // Account for this routines reference to the open. + // + + Open->References--; + + StatusToReturn = NDIS_STATUS_PENDING; + + } else { + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + IBMTOK_ERRMSG_INVALID_STATUS, + 1 + ); + + } + + } else { + + StatusToReturn = NDIS_STATUS_CLOSING; + + } + + + // + // This macro assumes it is called with the lock held, + // and releases it. + // + + IBMTOK_DO_DEFERRED(Adapter); + return StatusToReturn; + +} + +STATIC +NDIS_STATUS +IbmtokRequest( + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest + ) + +/*++ + +Routine Description: + + The IbmtokRequest allows a protocol to query and set information + about the MAC. + +Arguments: + + MacBindingHandle - The context value returned by the MAC when the + adapter was opened. In reality, it is a pointer to IBMTOK_OPEN. + + NdisRequest - A structure which contains the request type (Set or + Query), an array of operations to perform, and an array for holding + the results of the operations. + +Return Value: + + The function value is the status of the operation. + +--*/ + +{ + NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS; + + PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle); + PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + + NdisAcquireSpinLock(&(Adapter->Lock)); + + Adapter->References++; + + // + // Process request + // + + if (NdisRequest->RequestType == NdisRequestQueryInformation) { + + StatusToReturn = IbmtokQueryInformation(Adapter, Open, NdisRequest); + + } else if (NdisRequest->RequestType == NdisRequestSetInformation) { + + + // + // Make sure Adapter is in a valid state. + // + + if (Adapter->Unplugged) { + + StatusToReturn = NDIS_STATUS_DEVICE_FAILED; + + } else if (!Adapter->NotAcceptingRequests) { + + // + // Make sure the open instance is valid + // + + if (!Open->BindingShuttingDown) { + + StatusToReturn = IbmtokSetInformation(Adapter,Open,NdisRequest); + + } else { + + StatusToReturn = NDIS_STATUS_CLOSING; + + } + + } else { + + if (Adapter->ResetInProgress) { + + StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS; + + } else if (Adapter->AdapterNotOpen) { + + StatusToReturn = NDIS_STATUS_FAILURE; + + } else { + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + IBMTOK_ERRMSG_INVALID_STATE, + 3 + ); + + } + } + } else { + + StatusToReturn = NDIS_STATUS_NOT_RECOGNIZED; + + } + + IBMTOK_DO_DEFERRED(Adapter); + + return(StatusToReturn); + +} + +STATIC +NDIS_STATUS +IbmtokQueryProtocolInformation( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open, + IN NDIS_OID Oid, + IN BOOLEAN GlobalMode, + IN PVOID InfoBuffer, + IN UINT BytesLeft, + OUT PUINT BytesNeeded, + OUT PUINT BytesWritten +) + +/*++ + +Routine Description: + + The IbmtokQueryProtocolInformation process a Query request for + NDIS_OIDs that are specific to a binding about the MAC. Note that + some of the OIDs that are specific to bindings are also queryable + on a global basis. Rather than recreate this code to handle the + global queries, I use a flag to indicate if this is a query for the + global data or the binding specific data. + +Arguments: + + Adapter - a pointer to the adapter. + + Open - a pointer to the open instance. + + Oid - the NDIS_OID to process. + + GlobalMode - Some of the binding specific information is also used + when querying global statistics. This is a flag to specify whether + to return the global value, or the binding specific value. + + InfoBuffer - a pointer into the NdisRequest->InformationBuffer + into which store the result of the query. + + BytesLeft - the number of bytes left in the InformationBuffer. + + BytesNeeded - If there is not enough room in the information buffer + then this will contain the number of bytes needed to complete the + request. + + BytesWritten - a pointer to the number of bytes written into the + InformationBuffer. + +Return Value: + + The function value is the status of the operation. + +--*/ + +{ + NDIS_MEDIUM Medium = NdisMedium802_5; + ULONG GenericULong; + USHORT GenericUShort; + UCHAR GenericArray[6]; + + NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS; + + // + // Common variables for pointing to result of query + // + + PVOID MoveSource = (PVOID)(&GenericULong); + ULONG MoveBytes = sizeof(GenericULong); + + NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady; + + // + // General Algorithm: + // + // Switch(Request) + // Get requested information + // Store results in a common variable. + // Copy result in common variable to result buffer. + // + + // + // Switch on request type + // + + switch (Oid) { + + case OID_GEN_MAC_OPTIONS: + + GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | + NDIS_MAC_OPTION_RECEIVE_SERIALIZED + ); + + break; + + case OID_GEN_SUPPORTED_LIST: + + if (!GlobalMode){ + MoveSource = (PVOID)(IbmtokProtocolSupportedOids); + MoveBytes = sizeof(IbmtokProtocolSupportedOids); + } else { + MoveSource = (PVOID)(IbmtokGlobalSupportedOids); + MoveBytes = sizeof(IbmtokGlobalSupportedOids); + } + break; + + case OID_GEN_HARDWARE_STATUS: + + + if (Adapter->ResetInProgress){ + + HardwareStatus = NdisHardwareStatusReset; + + } else if ((Adapter->FirstInitialization) || + (Adapter->OpenInProgress)){ + + HardwareStatus = NdisHardwareStatusInitializing; + + } else if (Adapter->NotAcceptingRequests){ + + HardwareStatus = NdisHardwareStatusNotReady; + + } else + HardwareStatus = NdisHardwareStatusReady; + + + MoveSource = (PVOID)(&HardwareStatus); + MoveBytes = sizeof(NDIS_HARDWARE_STATUS); + + break; + + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + + MoveSource = (PVOID) (&Medium); + MoveBytes = sizeof(NDIS_MEDIUM); + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + + GenericULong = IBMTOK_MAX_LOOKAHEAD; + + break; + + + case OID_GEN_MAXIMUM_FRAME_SIZE: + case OID_GEN_MAXIMUM_TOTAL_SIZE: + + GenericULong = (ULONG)(Adapter->MaxTransmittablePacket); + + if (Oid == OID_GEN_MAXIMUM_FRAME_SIZE) { + + // + // For the receive frame size, we subtract the minimum + // header size from the number. + // + + GenericULong -= 14; + } + + break; + + + case OID_GEN_LINK_SPEED: + + GenericULong = (ULONG)(Adapter->Running16Mbps? 160000 : 40000); + + break; + + + case OID_GEN_TRANSMIT_BUFFER_SPACE: + + GenericULong = (ULONG)(Adapter->NumberOfTransmitBuffers * + Adapter->TransmitBufferLength); + + break; + + case OID_GEN_RECEIVE_BUFFER_SPACE: + + GenericULong = (ULONG)(Adapter->NumberOfReceiveBuffers * + Adapter->ReceiveBufferLength); + + break; + + case OID_GEN_TRANSMIT_BLOCK_SIZE: + + GenericULong = (ULONG)(Adapter->TransmitBufferLength); + + break; + + case OID_GEN_RECEIVE_BLOCK_SIZE: + + GenericULong = (ULONG)(Adapter->ReceiveBufferLength); + + break; + + case OID_GEN_VENDOR_ID: + + NdisMoveMemory( + (PVOID)&GenericULong, + Adapter->PermanentNetworkAddress, + 3 + ); + GenericULong &= 0xFFFFFF00; + + if (Adapter->UsingPcIoBus) { + + GenericULong |= 0x01; + + } + + MoveSource = (PVOID)(&GenericULong); + MoveBytes = sizeof(GenericULong); + break; + + case OID_GEN_VENDOR_DESCRIPTION: + + if (Adapter->UsingPcIoBus){ + MoveSource = (PVOID)"Ibm Token Ring Network Card for PC I/O bus."; + MoveBytes = 44; + } else { + MoveSource = (PVOID)"Ibm Token Ring Network Card for MCA bus."; + MoveBytes = 41; + } + break; + + case OID_GEN_DRIVER_VERSION: + + GenericUShort = (USHORT)((IBMTOK_NDIS_MAJOR_VERSION << 8) | IBMTOK_NDIS_MINOR_VERSION); + + MoveSource = (PVOID)(&GenericUShort); + MoveBytes = sizeof(GenericUShort); + break; + + + case OID_GEN_CURRENT_PACKET_FILTER: + + if (GlobalMode) { + + GenericULong = (ULONG)(Adapter->CurrentPacketFilter); + + } else { + + GenericULong = (ULONG)(TR_QUERY_PACKET_FILTER( + Adapter->FilterDB, + Open->NdisFilterHandle)); + + } + + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + + if (!GlobalMode){ + + GenericULong = Open->LookAhead; + + } else { + + PLIST_ENTRY CurrentLink; + PIBMTOK_OPEN TempOpen; + + CurrentLink = Adapter->OpenBindings.Flink; + + GenericULong = 0; + + while (CurrentLink != &(Adapter->OpenBindings)){ + + TempOpen = CONTAINING_RECORD( + CurrentLink, + IBMTOK_OPEN, + OpenList + ); + + if (TempOpen->LookAhead > GenericULong) { + + GenericULong = TempOpen->LookAhead; + + if (GenericULong == IBMTOK_MAX_LOOKAHEAD) { + + break; + + } + } + + CurrentLink = CurrentLink->Flink; + + } + + } + + break; + + case OID_802_5_PERMANENT_ADDRESS: + + TR_COPY_NETWORK_ADDRESS((PCHAR)GenericArray, + Adapter->PermanentNetworkAddress); + + MoveSource = (PVOID)(GenericArray); + MoveBytes = sizeof(Adapter->PermanentNetworkAddress); + + break; + + case OID_802_5_CURRENT_ADDRESS: + + TR_COPY_NETWORK_ADDRESS((PCHAR)GenericArray, + Adapter->NetworkAddress); + + MoveSource = (PVOID)(GenericArray); + MoveBytes = sizeof(Adapter->NetworkAddress); + + break; + + case OID_802_5_CURRENT_FUNCTIONAL: + + if (!GlobalMode){ + + GenericULong = TR_QUERY_FILTER_BINDING_ADDRESS( + Adapter->FilterDB, + Open->NdisFilterHandle); + + } else { + + GenericULong = Adapter->CurrentCardFunctional & 0xffffffff; + + } + + // + // Now we need to reverse the crazy thing. + // + + GenericULong = (ULONG)( + ((GenericULong >> 24) & 0xFF) | + ((GenericULong >> 8) & 0xFF00) | + ((GenericULong << 8) & 0xFF0000) | + ((GenericULong << 24) & 0xFF000000) + ); + + break; + + case OID_802_5_CURRENT_GROUP: + + GenericULong = Adapter->CurrentCardGroup & 0xffffffff; + + // + // Now we need to reverse the crazy thing. + // + + GenericULong = (ULONG)( + ((GenericULong >> 24) & 0xFF) | + ((GenericULong >> 8) & 0xFF00) | + ((GenericULong << 8) & 0xFF0000) | + ((GenericULong << 24) & 0xFF000000) + ); + + break; + + default: + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + if (StatusToReturn == NDIS_STATUS_SUCCESS){ + + if (MoveBytes > BytesLeft){ + + // + // Not enough room in InformationBuffer. Punt + // + + *BytesNeeded = MoveBytes; + + StatusToReturn = NDIS_STATUS_INVALID_LENGTH; + + } else { + + // + // Store result. + // + + IBMTOK_MOVE_MEMORY(InfoBuffer, MoveSource, MoveBytes); + + (*BytesWritten) += MoveBytes; + + } + } + + return(StatusToReturn); +} + +STATIC +NDIS_STATUS +IbmtokQueryInformation( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open, + IN PNDIS_REQUEST NdisRequest + ) +/*++ + +Routine Description: + + The IbmtokQueryInformation is used by IbmtokRequest to query information + about the MAC. + +Arguments: + + Adapter - A pointer to the adapter. + + Open - A pointer to a particular open instance. + + NdisRequest - A structure which contains the request type (Query), + an array of operations to perform, and an array for holding + the results of the operations. + +Return Value: + + The function value is the status of the operation. + +--*/ + +{ + + UINT BytesWritten = 0; + UINT BytesNeeded = 0; + UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength; + PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer); + + NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS; + + + StatusToReturn = IbmtokQueryProtocolInformation( + Adapter, + Open, + NdisRequest->DATA.QUERY_INFORMATION.Oid, + FALSE, + InfoBuffer, + BytesLeft, + &BytesNeeded, + &BytesWritten + ); + + NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten; + + NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded; + + return(StatusToReturn); +} + +STATIC +NDIS_STATUS +IbmtokSetInformation( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open, + IN PNDIS_REQUEST NdisRequest + ) +/*++ + +Routine Description: + + The IbmtokSetInformation is used by IbmtokRequest to set information + about the MAC. + +Arguments: + + Adapter - A pointer to the adapter. + + Open - A pointer to an open instance. + + NdisRequest - A structure which contains the request type (Set), + an array of operations to perform, and an array for holding + the results of the operations. + +Return Value: + + The function value is the status of the operation. + +--*/ + +{ + + // + // General Algorithm: + // + // Verify length + // Switch(Request) + // Process Request + // + + UINT BytesNeeded = 0; + UINT BytesLeft = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength; + PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer); + + // + // Variables for the request + // + + NDIS_OID Oid; + UINT OidLength; + + // + // Variables for holding the new values to be used. + // + + ULONG LookAhead; + ULONG Filter; + + NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS; + + + // + // Get Oid and Length of request + // + + Oid = NdisRequest->DATA.SET_INFORMATION.Oid; + + OidLength = BytesLeft; + + // + // Verify length + // + + if (OidLength != 4){ + + StatusToReturn = NDIS_STATUS_INVALID_LENGTH; + + NdisRequest->DATA.SET_INFORMATION.BytesRead = 0; + NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + + return(StatusToReturn); + } + + switch (Oid) { + + case OID_802_5_CURRENT_FUNCTIONAL: + + StatusToReturn = IbmtokChangeFunctionalAddress( + Adapter, + Open, + NdisRequest, + InfoBuffer + ); + + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + + IBMTOK_MOVE_MEMORY(&Filter, InfoBuffer, 4); + + StatusToReturn = IbmtokSetPacketFilter(Adapter, + Open, + NdisRequest, + Filter); + + break; + + case OID_802_5_CURRENT_GROUP: + + StatusToReturn = IbmtokSetGroupAddress( + Adapter, + Open, + NdisRequest, + InfoBuffer + ); + + break; + + + case OID_GEN_PROTOCOL_OPTIONS: + + StatusToReturn = NDIS_STATUS_SUCCESS; + + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + + IBMTOK_MOVE_MEMORY(&LookAhead, InfoBuffer, 4); + + if (LookAhead <= IBMTOK_MAX_LOOKAHEAD) { + + if (LookAhead > Adapter->LookAhead) { + + Open->LookAhead = LookAhead; + + Adapter->LookAhead = LookAhead; + + } else { + + if ((Open->LookAhead == Adapter->LookAhead) && + (LookAhead < Open->LookAhead)) { + + Open->LookAhead = LookAhead; + + IbmtokAdjustMaxLookAhead(Adapter); + + } else { + + Open->LookAhead = LookAhead; + + } + + } + + } else { + + StatusToReturn = NDIS_STATUS_INVALID_LENGTH; + + } + + break; + + default: + + StatusToReturn = NDIS_STATUS_INVALID_OID; + + NdisRequest->DATA.SET_INFORMATION.BytesRead = 0; + NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + + break; + } + + if (StatusToReturn == NDIS_STATUS_SUCCESS){ + + NdisRequest->DATA.SET_INFORMATION.BytesRead = OidLength; + NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + + } + + + + return(StatusToReturn); +} + +STATIC +NDIS_STATUS +IbmtokSetPacketFilter( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open, + IN PNDIS_REQUEST NdisRequest, + IN UINT PacketFilter + ) + +/*++ + +Routine Description: + + This routine processes the stages necessary to implement changing + the packets that a protocol receives from the MAC. + +Arguments: + + Adapter - A pointer to the Adapter. + + Open - A pointer to the open instance. + + NdisRequest - A pointer to the request submitting the set command. + + PacketFilter - A bit mask that contains flags that correspond to specific + classes of received packets. If a particular bit is set in the mask, + then packet reception for that class of packet is enabled. If the + bit is clear, then packets that fall into that class are not received + by the client. A single exception to this rule is that if the promiscuous + bit is set, then the client receives all packets on the network, regardless + of the state of the other flags. + +Return Value: + + The function value is the status of the operation. + +--*/ + +{ + + // + // Keeps track of the *MAC's* status. The status will only be + // reset if the filter change action routine is called. + // + NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS; + + // + // Verify bits + // + + if (PacketFilter & (NDIS_PACKET_TYPE_SOURCE_ROUTING | + NDIS_PACKET_TYPE_MULTICAST | + NDIS_PACKET_TYPE_PROMISCUOUS | + NDIS_PACKET_TYPE_ALL_MULTICAST | + NDIS_PACKET_TYPE_SMT | + NDIS_PACKET_TYPE_MAC_FRAME + )) { + + return(NDIS_STATUS_NOT_SUPPORTED); + + } + + // + // Increment the open while it is going through the filtering + // routines. + // + + Open->References++; + + StatusOfFilterChange = TrFilterAdjust( + Adapter->FilterDB, + Open->NdisFilterHandle, + NdisRequest, + PacketFilter, + TRUE + ); + Open->References--; + + if (StatusOfFilterChange == NDIS_STATUS_PENDING) { + + // + // If it pended, it will be in the pend + // queue so we should start that up. + // + + IbmtokProcessSrbRequests(Adapter); + + } + + return StatusOfFilterChange; +} + +STATIC +NDIS_STATUS +IbmtokChangeFunctionalAddress( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open, + IN PNDIS_REQUEST NdisRequest, + IN PUCHAR Address + ) + +/*++ + +Routine Description: + + This routine processes the stages necessary to implement changing + the packets that a protocol receives from the MAC. + + + Note: The spin lock must be held before entering this routine. + +Arguments: + + Adapter - A pointer to the Adapter. + + Open - A pointer to the open instance. + + NdisRequest - A pointer to the request submitting the set command. + + Address - The new functional address. + +Return Value: + + The function value is the status of the operation. + +--*/ + +{ + + // + // Keeps track of the *MAC's* status. The status will only be + // reset if the address change action routine is called. + // + NDIS_STATUS StatusOfChange = NDIS_STATUS_SUCCESS; + + // + // Increment the open while it is going through the filtering + // routines. + // + + Open->References++; + + StatusOfChange = TrChangeFunctionalAddress( + Open->OwningIbmtok->FilterDB, + Open->NdisFilterHandle, + NdisRequest, + Address, + TRUE + ); + + Open->References--; + + if (StatusOfChange == NDIS_STATUS_PENDING) { + + // + // If it pended, it will be in the pend + // queue so we should start that up. + // + + IbmtokProcessSrbRequests(Adapter); + + } + + return StatusOfChange; +} + +STATIC +NDIS_STATUS +IbmtokSetGroupAddress( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open, + IN PNDIS_REQUEST NdisRequest, + IN PUCHAR Address + ) + +/*++ + +Routine Description: + + This routine processes the stages necessary to implement changing + the packets that a protocol receives from the MAC. + + + Note: The spin lock must be held before entering this routine. + +Arguments: + + Adapter - A pointer to the Adapter. + + Open - A pointer to the open instance. + + NdisRequest - A pointer to the request submitting the set command. + + Address - The new group address. + +Return Value: + + The function value is the status of the operation. + +--*/ + +{ + + // + // Keeps track of the *MAC's* status. The status will only be + // reset if the address change action routine is called. + // + NDIS_STATUS StatusOfChange = NDIS_STATUS_SUCCESS; + + // + // Increment the open while it is going through the filtering + // routines. + // + + Open->References++; + + StatusOfChange = TrChangeGroupAddress( + Open->OwningIbmtok->FilterDB, + Open->NdisFilterHandle, + NdisRequest, + Address, + TRUE + ); + + Open->References--; + + if (StatusOfChange == NDIS_STATUS_PENDING) { + + // + // If it pended, it will be in the pend + // queue so we should start that up. + // + + IbmtokProcessSrbRequests(Adapter); + + } + + return StatusOfChange; +} + +NDIS_STATUS +IbmtokFillInGlobalData( + IN PIBMTOK_ADAPTER Adapter, + IN PNDIS_REQUEST NdisRequest + ) + +/*++ + +Routine Description: + + This routine completes a GlobalStatistics request. It is critical that + if information is needed from the Adapter->* fields, they have been + updated before this routine is called. + +Arguments: + + Adapter - A pointer to the Adapter. + + NdisRequest - A structure which contains the request type (Global + Query), an array of operations to perform, and an array for holding + the results of the operations. + +Return Value: + + The function value is the status of the operation. + +--*/ +{ + // + // General Algorithm: + // + // Switch(Request) + // Get requested information + // Store results in a common variable. + // default: + // Try protocol query information + // If that fails, fail query. + // + // Copy result in common variable to result buffer. + // Finish processing + + UINT BytesWritten = 0; + UINT BytesNeeded = 0; + UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength; + PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer); + + NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS; + + // + // This variable holds result of query + // + + ULONG GenericULong; + ULONG MoveBytes = sizeof(ULONG) * 2 + sizeof(NDIS_OID); + + + StatusToReturn = IbmtokQueryProtocolInformation( + Adapter, + NULL, + NdisRequest->DATA.QUERY_INFORMATION.Oid, + TRUE, + InfoBuffer, + BytesLeft, + &BytesNeeded, + &BytesWritten + ); + + + if (StatusToReturn == NDIS_STATUS_NOT_SUPPORTED){ + + StatusToReturn = NDIS_STATUS_SUCCESS; + + // + // Switch on request type + // + + switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) { + + case OID_GEN_XMIT_OK: + + GenericULong = (ULONG)(Adapter->FramesTransmitted); + + break; + + case OID_GEN_RCV_OK: + + GenericULong = (ULONG)(Adapter->FramesReceived); + + break; + + case OID_GEN_XMIT_ERROR: + + GenericULong = (ULONG)(Adapter->FrameTransmitErrors); + + break; + + case OID_GEN_RCV_ERROR: + + GenericULong = (ULONG)(Adapter->FrameReceiveErrors); + + break; + + case OID_GEN_RCV_NO_BUFFER: + + GenericULong = (ULONG)(Adapter->ReceiveCongestionCount); + + break; + + case OID_802_5_LINE_ERRORS: + + GenericULong = (ULONG)(Adapter->LineErrors); + + break; + + case OID_802_5_LOST_FRAMES: + + GenericULong = (ULONG)(Adapter->LostFrames); + + break; + + case OID_802_5_LAST_OPEN_STATUS: + + GenericULong = (ULONG)(NDIS_STATUS_TOKEN_RING_OPEN_ERROR | + (NDIS_STATUS)(Adapter->OpenErrorCode)); + + break; + + case OID_802_5_CURRENT_RING_STATUS: + + GenericULong = (ULONG)(Adapter->LastNotifyStatus); + + break; + + case OID_802_5_CURRENT_RING_STATE: + + GenericULong = (ULONG)(Adapter->CurrentRingState); + + break; + + default: + + StatusToReturn = NDIS_STATUS_INVALID_OID; + + break; + + } + + if (StatusToReturn == NDIS_STATUS_SUCCESS){ + + // + // Check to make sure there is enough room in the + // buffer to store the result. + // + + if (BytesLeft >= sizeof(ULONG)) { + + // + // Store the result. + // + + IBMTOK_MOVE_MEMORY( + (PVOID)InfoBuffer, + (PVOID)(&GenericULong), + sizeof(ULONG) + ); + + BytesWritten += sizeof(ULONG); + + } else { + + BytesNeeded = sizeof(ULONG) - BytesLeft; + + StatusToReturn = NDIS_STATUS_INVALID_LENGTH; + + } + + } + + } + + NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten; + + NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded; + + return(StatusToReturn); +} + +STATIC +NDIS_STATUS +IbmtokQueryGlobalStatistics( + IN NDIS_HANDLE MacAdapterContext, + IN PNDIS_REQUEST NdisRequest + ) + +/*++ + +Routine Description: + + The IbmtokQueryGlobalStatistics is used by the protocol to query + global information about the MAC. + +Arguments: + + MacAdapterContext - The value associated with the adapter that is being + opened when the MAC registered the adapter with NdisRegisterAdapter. + + NdisRequest - A structure which contains the request type (Query), + an array of operations to perform, and an array for holding + the results of the operations. + +Return Value: + + The function value is the status of the operation. + +--*/ + +{ + + // + // General Algorithm: + // + // + // Check if a request is going to pend... + // If so, pend the entire operation. + // + // Else + // Fill in the request block. + // + // + + PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext); + + NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS; + + // + // Check if a request is valid and going to pend... + // If so, pend the entire operation. + // + + NdisInterlockedAddUlong((PULONG)&Adapter->References, 1 ,&(Adapter->Lock)); + + // + // Switch on request type + // + + switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) { + case OID_GEN_SUPPORTED_LIST: + case OID_GEN_HARDWARE_STATUS: + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + case OID_GEN_MAXIMUM_LOOKAHEAD: + case OID_GEN_MAXIMUM_FRAME_SIZE: + case OID_GEN_MAXIMUM_TOTAL_SIZE: + case OID_GEN_MAC_OPTIONS: + case OID_GEN_LINK_SPEED: + case OID_GEN_TRANSMIT_BUFFER_SPACE: + case OID_GEN_RECEIVE_BUFFER_SPACE: + case OID_GEN_TRANSMIT_BLOCK_SIZE: + case OID_GEN_RECEIVE_BLOCK_SIZE: + case OID_GEN_VENDOR_ID: + case OID_GEN_VENDOR_DESCRIPTION: + case OID_GEN_DRIVER_VERSION: + case OID_GEN_CURRENT_PACKET_FILTER: + case OID_GEN_CURRENT_LOOKAHEAD: + case OID_802_5_CURRENT_GROUP: + case OID_802_5_LAST_OPEN_STATUS: + case OID_802_5_CURRENT_RING_STATUS: + case OID_802_5_CURRENT_RING_STATE: + case OID_802_5_PERMANENT_ADDRESS: + case OID_802_5_CURRENT_ADDRESS: + case OID_802_5_CURRENT_FUNCTIONAL: + break; + + case OID_GEN_XMIT_OK: + case OID_GEN_RCV_OK: + case OID_GEN_XMIT_ERROR: + case OID_GEN_RCV_ERROR: + case OID_GEN_RCV_NO_BUFFER: + case OID_802_5_LINE_ERRORS: + case OID_802_5_LOST_FRAMES: + + StatusToReturn = NDIS_STATUS_PENDING; + + break; + + default: + + StatusToReturn = NDIS_STATUS_INVALID_OID; + + break; + } + + if (StatusToReturn == NDIS_STATUS_PENDING) { + + // + // Build a pending operation + // + + PIBMTOK_PEND_DATA PendOp = PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest); + + PendOp->Next = NULL; + PendOp->COMMAND.NDIS.STATISTICS.ReadLogPending = FALSE; + + NdisAcquireSpinLock(&Adapter->Lock); + + if (Adapter->PendQueue == NULL){ + + Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp; + + } else { + + Adapter->EndOfPendQueue->Next = PendOp; + + } + + + // + // It is now in the pend + // queue so we should start that up. + // + + IbmtokProcessSrbRequests(Adapter); + + NdisReleaseSpinLock(&Adapter->Lock); + + // + // Defer subtracting from Adapter->Reference until the + // request completes (see IbmtokFinishPendQueueOp()). + // + + return(StatusToReturn); + + } + + if (StatusToReturn == NDIS_STATUS_SUCCESS){ + + StatusToReturn = IbmtokFillInGlobalData(Adapter, NdisRequest); + + } + + NdisAcquireSpinLock(&Adapter->Lock); + + IBMTOK_DO_DEFERRED(Adapter); + + return(StatusToReturn); +} + +STATIC +NDIS_STATUS +IbmtokReset( + IN NDIS_HANDLE MacBindingHandle + ) + +/*++ + +Routine Description: + + The IbmtokReset request instructs the MAC to issue a hardware reset + to the network adapter. The MAC also resets its software state. See + the description of NdisReset for a detailed description of this request. + +Arguments: + + MacBindingHandle - The context value returned by the MAC when the + adapter was opened. In reality, it is a pointer to IBMTOK_OPEN. + +Return Value: + + The function value is the status of the operation. + + +--*/ + +{ + + // + // Holds the status that should be returned to the caller. + // + NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING; + + PIBMTOK_ADAPTER Adapter = + PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle); + + PIBMTOK_OPEN Open; + + // + // Hold the locks while we update the reference counts on the + // adapter and the open. + // + + NdisAcquireSpinLock(&Adapter->Lock); + Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + + Adapter->References++; + + if (Adapter->ResetInProgress) { + + StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS; + + } else if (Adapter->AdapterNotOpen) { + + StatusToReturn = NDIS_STATUS_FAILURE; + + } else { + + if (!Open->BindingShuttingDown) { + + Open->References++; + IbmtokSetupForReset( + Adapter, + PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle) + ); + Open->References--; + + } else { + + StatusToReturn = NDIS_STATUS_CLOSING; + + } + + } + + // + // This macro assumes it is called with the lock held, + // and releases it. + // + + IBMTOK_DO_DEFERRED(Adapter); + return StatusToReturn; + +} + +STATIC +NDIS_STATUS +IbmtokChangeFilter( + IN UINT OldFilterClasses, + IN UINT NewFilterClasses, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + Action routine that will get called when a particular filter + class is first used or last cleared. + + NOTE: This routine assumes that it is called with the lock + acquired. + +Arguments: + + OldFilterClasses - The values of the class filter before it + was changed. + + NewFilterClasses - The current value of the class filter + + MacBindingHandle - The context value returned by the MAC when the + adapter was opened. In reality, it is a pointer to IBMTOK_OPEN. + + Set - If true the change resulted from a set, otherwise the + change resulted from a open closing. + +Return Value: + + None. + +--*/ + +{ + + + PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle); + + // + // The open that made this request. + // + PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + + // + // Holds the change that should be returned to the filtering package. + // + NDIS_STATUS StatusOfChange; + + if (NdisRequest == NULL) { + + NdisRequest = &(Open->CloseRequestChangeFilter); + + NdisRequest->RequestType = NdisRequestClose; + + + } + + + if (Adapter->ResetInProgress) { + + StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS; + + } else { + + // + // The whole purpose of this routine is to determine whether + // the filtering changes need to result in the hardware being + // reset. + // + + ASSERT(OldFilterClasses != NewFilterClasses); + +#if DBG + if (IbmtokDbg) DbgPrint("IBMTOK: Change filter\n"); +#endif + + if (NewFilterClasses & + (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_SOURCE_ROUTING)) { + + // + // The adapter cannot support promiscuous mode, or + // source routing which implies promiscuous. + // + + StatusOfChange = NDIS_STATUS_FAILURE; + + } else { + + // + // Queue this request. + // + + PIBMTOK_PEND_DATA PendOp = PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest); + + // + // Store open block. + // + + PendOp->COMMAND.NDIS.SET_FILTER.Open = Open; + + // + // Hold new Filter value + // + + if (PendOp->RequestType == NdisRequestClose){ + + PendOp->COMMAND.NDIS.CLOSE.NewFilterValue = NewFilterClasses; + + } else { + + PendOp->COMMAND.NDIS.SET_FILTER.NewFilterValue = NewFilterClasses; + + } + + + // + // Insert into queue. + // + + PendOp->Next = NULL; + + if (Adapter->PendQueue == NULL) { + + Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp; + + } else { + + Adapter->EndOfPendQueue->Next = PendOp; + + } + + Open->References++; + + StatusOfChange = NDIS_STATUS_PENDING; + + + } + + } + + return StatusOfChange; + +} + +STATIC +NDIS_STATUS +IbmtokChangeAddress( + IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress, + IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ) + + +/*++ + +Routine Description: + + Action routine that will get called when an address is added to + the filter that wasn't referenced by any other open binding. + + NOTE: This routine assumes that it is called with the lock + acquired. + +Arguments: + + OldFunctionalAddress - The previous functional address. + + NewFunctionalAddress - The new functional address. + + MacBindingHandle - The context value returned by the MAC when the + adapter was opened. In reality, it is a pointer to IBMTOK_OPEN. + + NdisRequest - A pointer to the Request that submitted the set command. + + Set - If true the change resulted from a set, otherwise the + change resulted from a open closing. + +Return Value: + + None. + + +--*/ + +{ + + PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle); + + // + // Holds the status that should be returned to the filtering package. + // + NDIS_STATUS StatusOfChange; + + // + // The open that made this request. + // + PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + +#if DBG + if (IbmtokDbg) { + DbgPrint("IBMTOK: Queueing:\n"); + DbgPrint(" Req : 0x%x\n", NdisRequest); + DbgPrint(" Old : 0x%x\n", OldFunctionalAddress); + DbgPrint(" New : 0x%x\n", NewFunctionalAddress); + } +#endif + + // Check to see if the device is already resetting. If it is + // then reject this change. + // + + if (NdisRequest == NULL) { + + NdisRequest = &(Open->CloseRequestChangeAddress); + + NdisRequest->RequestType = NdisRequestGeneric2; // Close, set address + + } + + + if (Adapter->ResetInProgress) { + +#if DBG + if (IbmtokDbg) { + DbgPrint("IBMTOK: ResetInProgress\n\n"); + } +#endif + + StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS; + + } else { + + // + // Queue this request. + // + + PIBMTOK_PEND_DATA PendOp = PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest); + + + // + // Store open block. + // + + PendOp->COMMAND.NDIS.SET_ADDRESS.Open = Open; + + // + // Hold new Address value + // + + PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue = NewFunctionalAddress; + + + // + // Insert into queue. + // + + PendOp->Next = NULL; + + if (Adapter->PendQueue == NULL) { + + Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp; + + } else { + + Adapter->EndOfPendQueue->Next = PendOp; + + } + + Open->References++; + + StatusOfChange = NDIS_STATUS_PENDING; + + } + + return StatusOfChange; + +} + +STATIC +NDIS_STATUS +IbmtokChangeGroupAddress( + IN TR_FUNCTIONAL_ADDRESS OldGroupAddress, + IN TR_FUNCTIONAL_ADDRESS NewGroupAddress, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + Action routine that will get called when a group address is to + be changed. + + NOTE: This routine assumes that it is called with the lock + acquired. + +Arguments: + + OldGroupAddress - The previous group address. + + NewGroupAddress - The new group address. + + MacBindingHandle - The context value returned by the MAC when the + adapter was opened. In reality, it is a pointer to IBMTOK_OPEN. + + NdisRequest - A pointer to the Request that submitted the set command. + + Set - If true the change resulted from a set, otherwise the + change resulted from a open closing. + +Return Value: + + None. + + +--*/ + +{ + + PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle); + + // + // Holds the status that should be returned to the filtering package. + // + NDIS_STATUS StatusOfChange; + + // + // The open that made this request. + // + PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + + + if (NdisRequest == NULL) { + + NdisRequest = &(Open->CloseRequestChangeGroupAddress); + + NdisRequest->RequestType = NdisRequestGeneric3; // Close, set group address + + } + + + // + // Check to see if the device is already resetting. If it is + // then reject this change. + // + + if (Adapter->ResetInProgress) { + + StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS; + + } else { + + // + // Queue this request. + // + + PIBMTOK_PEND_DATA PendOp = PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest); + + + // + // Store open block. + // + + PendOp->COMMAND.NDIS.SET_ADDRESS.Open = Open; + + // + // Hold new Address value + // + + PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue = NewGroupAddress; + + + // + // Insert into queue. + // + + PendOp->Next = NULL; + + if (Adapter->PendQueue == NULL) { + + Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp; + + } else { + + Adapter->EndOfPendQueue->Next = PendOp; + + } + + Open->References++; + + StatusOfChange = NDIS_STATUS_PENDING; + + } + + return StatusOfChange; + +} + +STATIC +VOID +IbmtokCloseAction( + IN NDIS_HANDLE MacBindingHandle + ) + +/*++ + +Routine Description: + + Action routine that will get called when a particular binding + was closed while it was indicating through NdisIndicateReceive + + All this routine needs to do is to decrement the reference count + of the binding. + + NOTE: This routine assumes that it is called with the lock acquired. + +Arguments: + + MacBindingHandle - The context value returned by the MAC when the + adapter was opened. In reality, it is a pointer to IBMTOK_OPEN. + +Return Value: + + None. + + +--*/ + +{ + + PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->References--; + +} + +extern +VOID +IbmtokStartAdapterReset( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This is the first phase of resetting the adapter hardware. + + It makes the following assumptions: + + 1) That the hardware has been stopped. + + 2) That it can not be preempted. + + 3) That no other adapter activity can occur. + + When this routine is finished all of the adapter information + will be as if the driver was just initialized. + +Arguments: + + Adapter - The adapter whose hardware is to be reset. + +Return Value: + + None. + +--*/ +{ + + // + // Disable these so no pending interrupts + // will fire. + // + CLEAR_ISRP_BITS(Adapter); + + // + // OK, do the reset as detailed in the Tech Ref... + // + + WRITE_ADAPTER_PORT(Adapter, RESET_LATCH, 0); + + NdisStallExecution(50000); + + WRITE_ADAPTER_PORT(Adapter, RESET_RELEASE, 0); + + // + // Have to write this now to enable Shared RAM paging. + // + if (Adapter->SharedRamPaging) { + + WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, 0xc0); + + } + + + if (Adapter->CardType == IBM_TOKEN_RING_PCMCIA) + { + UINT Nibble0; + UINT Nibble1; + UINT Nibble2; + UINT Nibble3; + ULONG MmioAddress; + + // + // Configure the card to match registry + // Use the Default MMIO value here (this never changes from system to system) + // + MmioAddress = Adapter->MmioAddress; + + // + // Nibble 0 - ROM address + // + Nibble0 = NIBBLE_0 | ((UINT)(MmioAddress >> 16 ) & 0x0F); + + // + // Nibble 1 - ROM address, INT 0 + // + Nibble1 = NIBBLE_1 | ((UINT)(MmioAddress >> 12) & 0x0F); + + // + // Nibble 2 - INT1, F ROS, SRAM, S RST + // + Nibble2 = NIBBLE_2 | DEFAULT_NIBBLE_2; + + // + // Nibble 3 - Ring Speed, RAM size, Prim/Alt + // + Nibble3 = NIBBLE_3; + + if (Adapter->RingSpeed == 16) + { + Nibble3 |= RING_SPEED_16_MPS; + } + else + { + Nibble3 |= RING_SPEED_4_MPS; + } + + switch (Adapter->RamSize) + { + case 0x10000: + Nibble3 |= SHARED_RAM_64K; + break; + + case 0x8000: + Nibble3 |= SHARED_RAM_32K; + break; + + case 0x4000: + Nibble3 |= SHARED_RAM_16K; + break; + + case 0x2000: + Nibble3 |= SHARED_RAM_8K; + break; + } + + // if ( Adapter->IbmtokPortAddress == PRIMARY_ADAPTER_OFFSET) + // { + // Nibble3 |= PRIMARY; + // } + // else + // { + // Nibble3 |= ALTERNATE; + // } + + // + // Write everything to the Token-Ring Controller Configuration Register + // + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_2, Nibble0); + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble0); + + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_2, Nibble1); + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble1); + + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_2, Nibble2); + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble2); + + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_2, Nibble3); + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble3); + + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_2, RELEASE_TR_CONTROLLER); + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, RELEASE_TR_CONTROLLER); + + WRITE_ADAPTER_REGISTER(Adapter, RRR_LOW, Adapter->RrrLowValue); + } + else if (Adapter->UsingPcIoBus) + { + // + // If this is a PC I/O Bus.... + // Set up the shared RAM to be right after the MMIO. + // + WRITE_ADAPTER_REGISTER(Adapter, RRR_LOW, Adapter->RrrLowValue); + } + + + // + // Allow the reset complete interrupt to be + // serviced correctly. + // + if (Adapter->CardType != IBM_TOKEN_RING_PCMCIA) + { + SET_INTERRUPT_RESET_FLAG(Adapter); + } + else + { + UCHAR Temp; + + // + // disable interrupts on the card, + // since we don't trust ndissyncint to work + // + READ_ADAPTER_REGISTER(Adapter, ISRP_LOW, &Temp); + + WRITE_ADAPTER_REGISTER( + Adapter, + ISRP_LOW, + (UCHAR)(Temp & (~(ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE))) + ); + + // + // Set the reset flag + // + Adapter->ResetInterruptAllowed = TRUE; + + // + // reenable interrupts on the card + // + WRITE_ADAPTER_REGISTER( + Adapter, + ISRP_LOW, + ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE + ); + } + + // + // Enable card interrupts to get the reset interrupt. + // + + WRITE_ADAPTER_REGISTER(Adapter, ISRP_LOW, + ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE); + + + // + // The remaining processing is done in the + // interrupt handler. + // + + + + // + // OK, now abort pending requests before we nuke + // everything. + // + + NdisDprAcquireSpinLock (&Adapter->Lock); + + IbmtokAbortSends (Adapter, NDIS_STATUS_REQUEST_ABORTED); + + NdisDprReleaseSpinLock (&Adapter->Lock); + +} + +extern +VOID +IbmtokFinishAdapterReset( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + Called by HandleResetStaging when the last piece + of the adapter reset is complete and normal + operation can resume. + + Called with the lock held and returns with it held. + +Arguments: + + Adapter - The adapter that the reset is for. + +Return Value: + + None. + +--*/ + +{ + PLIST_ENTRY CurrentLink; + PIBMTOK_OPEN TempOpen; + + + SetResetVariables(Adapter); + + if (Adapter->UnpluggedResetInProgress) { + Adapter->UnpluggedResetInProgress = FALSE; + Adapter->Unplugged = FALSE; + Adapter->LobeWireFaultIndicated = FALSE; + } + + Adapter->ResetInProgress = FALSE; + Adapter->ResetInterruptAllowed = FALSE; + Adapter->ResetInterruptHasArrived = FALSE; + Adapter->NotAcceptingRequests = FALSE; + + // + // Get any interrupts that have been deferred + // while NotAcceptingRequests was TRUE. + // + IbmtokForceAdapterInterrupt(Adapter); + + if (Adapter->ResettingOpen != NULL) { + + PIBMTOK_OPEN ResettingOpen = Adapter->ResettingOpen; + + // + // Indicate reset complete to everybody + // + + CurrentLink = Adapter->OpenBindings.Flink; + + while (CurrentLink != &(Adapter->OpenBindings)){ + + TempOpen = CONTAINING_RECORD( + CurrentLink, + IBMTOK_OPEN, + OpenList + ); + + NdisReleaseSpinLock(&Adapter->Lock); + + NdisIndicateStatus(TempOpen->NdisBindingContext, + NDIS_STATUS_RESET_END, + NULL, + 0 + ); + + NdisIndicateStatusComplete(TempOpen->NdisBindingContext); + + NdisAcquireSpinLock(&Adapter->Lock); + + CurrentLink = CurrentLink->Flink; + + } + + // + // Decrement the reference count that was incremented + // in SetupForReset. + // + ResettingOpen->References--; + + NdisReleaseSpinLock(&Adapter->Lock); + + NdisCompleteReset( + ResettingOpen->NdisBindingContext, + NDIS_STATUS_SUCCESS + ); + + NdisAcquireSpinLock(&Adapter->Lock); + + } + +} + +#pragma NDIS_INIT_FUNCTION(IbmtokSetupRegistersAndInit) + +STATIC +VOID +IbmtokSetupRegistersAndInit( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + It is this routines responsibility to make sure that the + initialization block is filled and the chip is initialized + *but not* started. + + NOTE: This routine assumes that it is called with the lock + acquired OR that only a single thread of execution is working + with this particular adapter. + +Arguments: + + Adapter - The adapter whose hardware is to be initialized. + +Return Value: + + None. + +--*/ +{ + + // + // Enable card interrupts to get the reset interrupt. + // + + WRITE_ADAPTER_REGISTER(Adapter, ISRP_LOW, + ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE); + + // + // Set the timer to 10 milliseconds...this seems to + // be necessary for proper operation (according to + // ChandanC). + // + + WRITE_ADAPTER_REGISTER(Adapter, TVR_HIGH, 0x01); + + + // + // Start the timer and set it to reload, but not to + // interrupt us (TCR_LOW_INTERRUPT_MASK is off). This + // will still cause bit 4 in the ISRP Low to go on, + // but it won't cause an interrupt. + // + +#if 0 + WRITE_ADAPTER_REGISTER(Adapter, TCR_LOW, +// TCR_LOW_INTERRUPT_MASK | + TCR_LOW_RELOAD_TIMER | TCR_LOW_COUNTER_ENABLE); +#endif + WRITE_ADAPTER_REGISTER(Adapter, TCR_LOW, 0); + + + + // + // If this is a PC I/O Bus... + // Set up the shared RAM to be right after the MMIO. + // + + if (Adapter->UsingPcIoBus) + { + WRITE_ADAPTER_REGISTER(Adapter, RRR_LOW, Adapter->RrrLowValue); + } + else if (Adapter->CardType == IBM_TOKEN_RING_PCMCIA) + { + WRITE_ADAPTER_REGISTER(Adapter, RRR_LOW, (UCHAR)(Adapter->Ram >> 12)); + } + + + // + // The remaining initialization processing is done in + // the interrupt handler. + // + +} + + +STATIC +VOID +IbmtokSetupForReset( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open + ) + +/*++ + +Routine Description: + + This routine is used to fill in the who and why a reset is + being set up as well as setting the appropriate fields in the + adapter. + + NOTE: This routine must be called with the lock acquired. + +Arguments: + + Adapter - The adapter whose hardware is to be initialized. + + Open - A (possibly NULL) pointer to an sonic open structure. + The reason it could be null is if the adapter is initiating the + reset on its own. + +Return Value: + + None. + +--*/ +{ + // + // Notify of reset start + // + + PLIST_ENTRY CurrentLink; + PIBMTOK_OPEN TempOpen; + + if (Open != NULL) { + + CurrentLink = Adapter->OpenBindings.Flink; + + while (CurrentLink != &(Adapter->OpenBindings)){ + + TempOpen = CONTAINING_RECORD( + CurrentLink, + IBMTOK_OPEN, + OpenList + ); + + NdisReleaseSpinLock(&Adapter->Lock); + + NdisIndicateStatus(TempOpen->NdisBindingContext, + NDIS_STATUS_RESET_START, + NULL, + 0 + ); + + NdisAcquireSpinLock(&Adapter->Lock); + + CurrentLink = CurrentLink->Flink; + + } + } + + + Adapter->ResetInProgress = TRUE; + Adapter->NotAcceptingRequests = TRUE; + + Adapter->ResettingOpen = Open; + + // + // This will go to 1 when StartAdapterReset is called. + // + Adapter->CurrentResetStage = 0; + + // + // If there is a valid open we should up the reference count + // so that the open can't be deleted before we indicate that + // their request is finished. + // + + if (Open != NULL) { + + Open->References++; + + } + +} + + +#pragma NDIS_INIT_FUNCTION(IbmtokAddAdapter) + +NDIS_STATUS +IbmtokAddAdapter( + IN NDIS_HANDLE MacMacContext, + IN NDIS_HANDLE ConfigurationHandle, + IN PNDIS_STRING AdapterName + ) + +/*++ + +Routine Description: + + This routine is used to initialize each adapter card/chip. + +Arguments: + + see NDIS 3.0 spec... + +Return Value: + + + NDIS_STATUS_SUCCESS - Adapter was successfully added. + NDIS_STATUS_FAILURE - Adapter was not added, also MAC deregistered. + +--*/ + +{ + PIBMTOK_ADAPTER Adapter; + + NDIS_HANDLE ConfigHandle; + PNDIS_CONFIGURATION_PARAMETER ReturnedValue; + NDIS_STRING CardTypeStr = NDIS_STRING_CONST("CardType"); + NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType"); + NDIS_STRING IOAddressStr = IOADDRESS; + NDIS_STRING NetworkAddressStr = NETWORK_ADDRESS; + NDIS_STRING PacketSizeStr = MAXPACKETSIZE; + NDIS_STRING TokenReleaseStr = TOKEN_RELEASE; + + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + + BOOLEAN PrimaryAdapter = TRUE; + BOOLEAN ConfigError = FALSE; + BOOLEAN McaCard = FALSE; + + UINT SlotNumber; + NDIS_MCA_POS_DATA McaData; + + PVOID NetAddress; + ULONG Length; + + // + // Allocate the Adapter block. + // + + if (IBMTOK_ALLOC_PHYS(&Adapter, sizeof(IBMTOK_ADAPTER)) != + NDIS_STATUS_SUCCESS + ) + { + return(NDIS_STATUS_RESOURCES); + } + + IBMTOK_ZERO_MEMORY(Adapter, sizeof(IBMTOK_ADAPTER)); + + Adapter->MaxTransmittablePacket = 17960; + Adapter->CurrentRingState = NdisRingStateClosed; + + Adapter->NdisMacHandle = ((PIBMTOK_MAC)MacMacContext)->NdisMacHandle; + + NdisOpenConfiguration( + &Status, + &ConfigHandle, + ConfigurationHandle + ); + if (Status != NDIS_STATUS_SUCCESS) + { + IBMTOK_FREE_PHYS(Adapter, sizeof(IBMTOK_ADAPTER)); + + return(NDIS_STATUS_FAILURE); + } + + // + // Determine the type of the card; + // IBM_TOKEN_RING_ISA, IBM_TOKEN_RING_PCMCIA. + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &CardTypeStr, + NdisParameterInteger + ); + if (NDIS_STATUS_SUCCESS == Status) + Adapter->CardType = (UINT)ReturnedValue->ParameterData.IntegerData; + + // + // Read Bus Type + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &BusTypeStr, + NdisParameterHexInteger + ); + if (NDIS_STATUS_SUCCESS == Status) + { + if (ReturnedValue->ParameterData.IntegerData == + (ULONG)NdisInterfaceMca) + { + McaCard = TRUE; + } + } + + // + // Get I/O Address + // + + if (McaCard) + { + // + // Get I/O Address from Mca Pos info. + // + NdisReadMcaPosInformation( + &Status, + ConfigurationHandle, + &SlotNumber, + &McaData + ); + if (Status != NDIS_STATUS_SUCCESS) + { + ConfigError = TRUE; + goto RegisterAdapter; + } + + // + // Now interperet the data + // + switch (McaData.PosData2 & 0x1) + { + case 0x00: + Adapter->IbmtokPortAddress = PRIMARY_ADAPTER_OFFSET; + break; + + case 0x01: + Adapter->IbmtokPortAddress = ALTERNATE_ADAPTER_OFFSET; + break; + + } + } + else if (IBM_TOKEN_RING_PCMCIA == Adapter->CardType) + { + // + // Read I/O Address. + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &IOAddressStr, + NdisParameterHexInteger + ); + if (NDIS_STATUS_SUCCESS == Status) + { + Adapter->IbmtokPortAddress = + (ULONG)ReturnedValue->ParameterData.IntegerData; + } + } + else + { + // + // Read I/O Address + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &IOAddressStr, + NdisParameterInteger + ); + if (NDIS_STATUS_SUCCESS == Status) + { + PrimaryAdapter = + (ReturnedValue->ParameterData.IntegerData == 1) ? TRUE : FALSE; + } + + if (PrimaryAdapter) + { + Adapter->IbmtokPortAddress = PRIMARY_ADAPTER_OFFSET; + } + else + { + Adapter->IbmtokPortAddress = ALTERNATE_ADAPTER_OFFSET; + } + } + + // if IBM_TOKEN_RING_16_4_CREDIT_CARD_ADAPTER, read in bunch of stuff + // like mmio, ringspeed, interrupt, ramsize, so we can set the card to match + // + if (IBM_TOKEN_RING_PCMCIA == Adapter->CardType) + { + // The following strings were changed to match the correct Registry entries + + // NDIS_STRING AttributeAddressStr1 = NDIS_STRING_CONST("PCCARDAttributeMemoryAddress"); + // NDIS_STRING AttributeAddressStr2 = NDIS_STRING_CONST("PCCARDAttributeMemoryAddress_1"); + // NDIS_STRING AttributeSizeStr1 = NDIS_STRING_CONST("PCCARDAttributeMemorySize"); + // NDIS_STRING AttributeSizeStr2 = NDIS_STRING_CONST("PCCARDAttributeMemorySize_1"); + + NDIS_STRING AttributeAddressStr1 = NDIS_STRING_CONST("MemoryMappedBaseAddress"); + NDIS_STRING AttributeAddressStr2 = NDIS_STRING_CONST("MemoryMappedBaseAddress_1"); + NDIS_STRING AttributeSizeStr1 = NDIS_STRING_CONST("MemoryMappedSize"); + NDIS_STRING AttributeSizeStr2 = NDIS_STRING_CONST("MemoryMappedSize_1"); + NDIS_STRING RingSpeedStr = NDIS_STRING_CONST("RingSpeed"); + NDIS_STRING InterruptNumberStr = NDIS_STRING_CONST("InterruptNumber"); + NDIS_STRING AutoRingSpeedStr = NDIS_STRING_CONST("AutoRingSpeed"); + ULONG BaseAddress; + ULONG Size; + + // + // Get the memory mapped I/O attribute window. + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &AttributeAddressStr1, + NdisParameterInteger + ); + if (NDIS_STATUS_SUCCESS == Status) + { + // + // Save the memory mapped io base address. + // + BaseAddress = (ULONG)ReturnedValue->ParameterData.IntegerData; + } + else + { + // + // BAD BAD BAD + // + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, + 1, + 0x11111111 + ); + + ConfigError = TRUE; + goto RegisterAdapter; + } + + // + // Get the size of the memory mapped I/O attribute window. + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &AttributeSizeStr1, + NdisParameterInteger + ); + + // + // Save the size of the memory mapped io space. + // + Size = (ULONG)ReturnedValue->ParameterData.IntegerData; + + if ((Status != NDIS_STATUS_SUCCESS) || (Size != 0x2000)) + { + // + // BAD BAD BAD + // + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, + 1, + 0x22222222 + ); + + ConfigError = TRUE; + goto RegisterAdapter; + } + + // + // Save the memory mapped address in the adapter block. + // + Adapter->MmioAddress = BaseAddress; + + // + // Get the shared ram attribute window. + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &AttributeAddressStr2, + NdisParameterInteger + ); + if (NDIS_STATUS_SUCCESS == Status) + { + BaseAddress = (ULONG)ReturnedValue->ParameterData.IntegerData; + } + else + { + // + // BAD BAD BAD + // + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, + 1, + 0x33333333 + ); + + ConfigError = TRUE; + goto RegisterAdapter; + } + + // + // Get the size of the shared ram attribute window. + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &AttributeSizeStr2, + NdisParameterInteger + ); + + Size = (ULONG)ReturnedValue->ParameterData.IntegerData; + + if ((Status != NDIS_STATUS_SUCCESS) || + ((Size != 0x2000) && (Size != 0x4000) && + (Size != 0x8000) && (Size != 0x10000)) + ) + { + // + // BAD BAD BAD + // + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, + 1, + 0x44444444 + ); + + ConfigError = TRUE; + goto RegisterAdapter; + } + + Adapter->RamSize = Size; + Adapter->Ram = BaseAddress; + + // + // Find out ring speed + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &RingSpeedStr, + NdisParameterInteger + ); + if (NDIS_STATUS_SUCCESS == Status) + Adapter->RingSpeed = ReturnedValue->ParameterData.IntegerData; + + // + // Determine if Ring Speed Listen is desired BEM PCMCIA card + // + + + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &AutoRingSpeedStr, + NdisParameterInteger + ); + + if (Status == NDIS_STATUS_SUCCESS) { + + Adapter->RingSpeedListen = (BOOLEAN) ReturnedValue->ParameterData.IntegerData; + + } + + // + // Get the interrupt level. + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &InterruptNumberStr, + NdisParameterInteger + ); + if (NDIS_STATUS_SUCCESS == Status) + Adapter->InterruptLevel = ReturnedValue->ParameterData.IntegerData; + +#if DBG + if (IbmtokDbg) + { + DbgPrint("MMIO = %x\n", Adapter->MmioAddress); + DbgPrint("RAM = %x\n",Adapter->Ram); + DbgPrint("RAMSIZE = %x\n", Adapter->RamSize); + DbgPrint("RINGSPEED = %d\n", Adapter->RingSpeed); + DbgPrint("IO Base = %x\n", Adapter->IbmtokPortAddress); + DbgPrint("INT = %x\n", Adapter->InterruptLevel); + } +#endif + } + + // + // Read PacketSize + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &PacketSizeStr, + NdisParameterInteger + ); + if (Status == NDIS_STATUS_SUCCESS) + { + Adapter->MaxTransmittablePacket = + ReturnedValue->ParameterData.IntegerData; + } + + // + // Read net address + // + NdisReadNetworkAddress( + &Status, + &NetAddress, + &Length, + ConfigHandle + ); + if (Status == NDIS_STATUS_SUCCESS) + { + if (Length == TR_LENGTH_OF_ADDRESS) + { + TR_COPY_NETWORK_ADDRESS( + Adapter->NetworkAddress, + NetAddress + ); + } + else if (Length != 0) + { + ConfigError = TRUE; + goto RegisterAdapter; + } + } + + // + // Read token release + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &TokenReleaseStr, + NdisParameterInteger + ); + + Adapter->EarlyTokenRelease = TRUE; + + if (Status == NDIS_STATUS_SUCCESS) + { + if (ReturnedValue->ParameterData.IntegerData == 0) + { + Adapter->EarlyTokenRelease = FALSE; + } + } + +RegisterAdapter: + + NdisCloseConfiguration(ConfigHandle); + + Status = IbmtokRegisterAdapter( + Adapter, + ConfigurationHandle, + AdapterName, + McaCard, + ConfigError + ); + if (Status != NDIS_STATUS_SUCCESS) + { + IBMTOK_FREE_PHYS(Adapter, sizeof(IBMTOK_ADAPTER)); + } + + return(Status); +} + + + +VOID +IbmtokRemoveAdapter( + IN PVOID MacAdapterContext + ) + + +/*++ + +Routine Description: + + This routine is called when an adapter is to be removed. + +Arguments: + + MacAdapterContext - Pointer to global list of adapter blocks. + +Return Value: + + None + +--*/ + +{ + PIBMTOK_ADAPTER Adapter; + BOOLEAN Canceled; + + Adapter = PIBMTOK_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext); + + // + // There are no opens left, so remove ourselves. + // + + NdisDeregisterAdapterShutdownHandler(Adapter->NdisAdapterHandle); + + NdisCancelTimer(&Adapter->WakeUpTimer, &Canceled); + + if ( !Canceled ) { + + NdisStallExecution(500000); + } + + NdisRemoveInterrupt(&(Adapter->Interrupt)); + + NdisUnmapIoSpace(Adapter->NdisAdapterHandle, + Adapter->SharedRam, + (Adapter->MappedSharedRam == 0x10000) ? + 0x8000 : + Adapter->MappedSharedRam + ); + + TrDeleteFilter(Adapter->FilterDB); + + NdisFreeSpinLock(&Adapter->Lock); + + NdisDeregisterAdapter(Adapter->NdisAdapterHandle); + + IBMTOK_FREE_PHYS(Adapter, sizeof(IBMTOK_ADAPTER)); + + return; + +} + + +VOID +IbmtokShutdown( + IN PVOID ShutdownContext + ) + +/*++ + +Routine Description: + + Turns off the card during a powerdown of the system. + +Arguments: + + ShutdownContext - Really a pointer to the adapter structure. + +Return Value: + + None. + +--*/ + +{ + PIBMTOK_ADAPTER Adapter = (PIBMTOK_ADAPTER)(ShutdownContext); + + // + // Set the flag + // + + Adapter->NotAcceptingRequests = TRUE; + + // + // Shutdown the card gracefully if we can, else submit a reset to remove it. + // + + if ((Adapter->SrbAvailable) && (Adapter->SrbAddress != 0)) { + + PSRB_CLOSE_ADAPTER CloseSrb = (PSRB_CLOSE_ADAPTER)Adapter->SrbAddress; + + // + // Mask off all interrupts + // + WRITE_ADAPTER_REGISTER(Adapter, ISRP_LOW, ISRP_LOW_NO_CHANNEL_CHECK); + + // + // Fill in the SRB for the close. + // + + IBMTOK_ZERO_MAPPED_MEMORY(CloseSrb, sizeof(SRB_CLOSE_ADAPTER)); + + NdisWriteRegisterUchar((PUCHAR)&CloseSrb->Command, SRB_CMD_CLOSE_ADAPTER); + + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, ISRA_HIGH_COMMAND_IN_SRB); + + } else { + + // + // Set the reset latch and leave it. This should turn the card + // off and it will be removed from the ring, but is not as graceful + // as actually removing ourselves as above. + // + + WRITE_ADAPTER_PORT(Adapter, RESET_LATCH, 0); + + } +} + + +VOID +IbmtokUnload( + IN NDIS_HANDLE MacMacContext + ) + +/*++ + +Routine Description: + + IbmtokUnload is called when the MAC is to unload itself. + +Arguments: + + MacMacContext - nothing. + +Return Value: + + None. + +--*/ + +{ + NDIS_STATUS InitStatus; + + UNREFERENCED_PARAMETER(MacMacContext); + + NdisDeregisterMac( + &InitStatus, + ((PIBMTOK_MAC)MacMacContext)->NdisMacHandle + ); + + NdisTerminateWrapper( + ((PIBMTOK_MAC)MacMacContext)->NdisWrapperHandle, + NULL + ); + + return; +} + +#pragma NDIS_INIT_FUNCTION(IbmtokHardwareDetails) + +STATIC +BOOLEAN +IbmtokHardwareDetails( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine gets the MMIO address and interrupt level. + It also maps the MMIO and Shared RAM. + +Arguments: + + Adapter - Where to store the network address. + +Return Value: + + TRUE if successful. + +--*/ + +{ + + NDIS_STATUS Status; + + // + // Holds the value read from the SWITCH_READ_1 port. + // + UCHAR SwitchRead1; + + // + // Holds the value read from the SWITCH_READ_2 port in + // the Microchannel Bus. + // + UCHAR SwitchRead2; + + // + // Holds the physical address of the MMIO region. + // + ULONG MmioAddress; + + NDIS_PHYSICAL_ADDRESS PhysicalAddress; + + // + // The interrupt level; + // + UINT InterruptLevel; + + // + // The RRR bits indicating the Shared RAM size: + // 0 = 8K, 1 = 16K, 2 = 32K, 3 = 64K. + // + UCHAR SharedRamBits; + + // + // The actual size of Shared RAM from RRR bits 2,3 in + // the PC I/O Bus adapter. + // + UINT RrrSharedRamSize; + + // + // Common variable for storing total Shared RAM Size. + // + UINT SharedRamSize; + + // + // The actual address of Shared RAM from the SWITCH_READ_2 + // port in the Microchannel adapter. + // + UINT McaSharedRam; + + // + // The boundary needed for the Shared RAM mapping. + // + UCHAR BoundaryNeeded; + + // + // The value read from the Shared RAM paging byte of + // the AIP. + // + UCHAR AipSharedRamPaging; + + UCHAR RegValue; + + if (IBM_TOKEN_RING_PCMCIA == Adapter->CardType) + { + UINT Nibble0; + UINT Nibble1; + UINT Nibble2; + UINT Nibble3; + + // + // Configure the card to match registry + // Use the Default MMIO value here + // (this never changes from system to system) + // + MmioAddress = Adapter->MmioAddress; + + // + // Nibble 0 - ROM address + // + Nibble0 = NIBBLE_0 | ( ( UINT )( MmioAddress >> 16 ) & 0x0F ); + + // + // Nibble 1 - ROM address, INT 0 + // + Nibble1 = NIBBLE_1 | ( ( UINT )( MmioAddress >> 12) & 0x0F ); + + // + // Nibble 2 - INT1, F ROS, SRAM, S RST + // + Nibble2 = NIBBLE_2 | DEFAULT_NIBBLE_2; + + // + // Nibble 3 - Ring Speed, RAM size, Prim/Alt + // + Nibble3 = NIBBLE_3; + + if (Adapter->RingSpeed == 16) + { + Nibble3 |= RING_SPEED_16_MPS; + } + else + { + Nibble3 |= RING_SPEED_4_MPS; + } + + switch (Adapter->RamSize) + { + case 0x10000: + Nibble3 |= SHARED_RAM_64K; + break; + + case 0x8000: + Nibble3 |= SHARED_RAM_32K; + break; + + case 0x4000: + Nibble3 |= SHARED_RAM_16K; + break; + + case 0x2000: + Nibble3 |= SHARED_RAM_8K; + break; + } + + if ( Adapter->IbmtokPortAddress == PRIMARY_ADAPTER_OFFSET) + { + Nibble3 |= PRIMARY; + } + else + { + Nibble3 |= ALTERNATE; + } + +#if DBG + if (IbmtokDbg) + { + DbgPrint("Nibble0 = %x\n",Nibble0); + DbgPrint("Nibble1 = %x\n",Nibble1); + DbgPrint("Nibble2 = %x\n",Nibble2); + DbgPrint("Nibble3 = %x\n",Nibble3); + } +#endif + // + // Write everything to the Token-Ring + // Controller Configuration Register + // + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble0); + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble1); + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble2); + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble3); + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, RELEASE_TR_CONTROLLER); + + // + // Use the MMIO provided by ConfigMgr here + // + MmioAddress = Adapter->MmioAddress; + + NdisSetPhysicalAddressHigh(PhysicalAddress, 0); + NdisSetPhysicalAddressLow(PhysicalAddress, MmioAddress); + + NdisMapIoSpace( + &Status, + (PVOID *)&(Adapter->MmioRegion), + Adapter->NdisAdapterHandle, + PhysicalAddress, + 0x2000 + ); + + if (Status != NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_RESOURCE_CONFLICT, + 0 + ); + + return(FALSE); + } + + { + // + // Will hold the Adapter ID as read from the card. + // + ULONG AdapterId[3]; + + // + // What AdapterId should contain for a PC I/O bus card. + // + static ULONG PcIoBusId[3] = { 0x5049434f, 0x36313130, 0x39393020 }; + + // + // What AdapterId should contain for a Micro Channel card. + // + static ULONG MicroChannelId[3] = { 0x4d415253, 0x36335834, 0x35313820 }; + + // + // Loop counters. + // + UINT i, j; + + UCHAR TmpUchar; + + for (i = 0; i < 3; i++) + { + AdapterId[i] = 0; + + for (j = 0; j < 16; j += 2) + { + ULONG Port; + + Port = CHANNEL_IDENTIFIER + (i * 16) + j; + READ_ADAPTER_REGISTER( + Adapter, + Port, + &TmpUchar + ); + + AdapterId[i] = (AdapterId[i] << 4) + (TmpUchar & 0x0f); + } + } + + if ((AdapterId[0] == PcIoBusId[0]) && + (AdapterId[1] == PcIoBusId[1]) && + (AdapterId[2] == PcIoBusId[2]) + ) + { + Adapter->UsingPcIoBus = TRUE; + } + else + { + // + // Unknown channel type. + // + NdisUnmapIoSpace( + Adapter->NdisAdapterHandle, + Adapter->MmioRegion, + 0x2000 + ); + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS, + 0 + ); + + return(FALSE); + } + } + + NdisSetPhysicalAddressHigh(PhysicalAddress, 0); + NdisSetPhysicalAddressLow(PhysicalAddress, Adapter->Ram); + + NdisMapIoSpace( + &Status, + (PVOID *)&(Adapter->SharedRam), + Adapter->NdisAdapterHandle, + PhysicalAddress, + Adapter->RamSize + ); + + if (Status != NDIS_STATUS_SUCCESS) + { + NdisUnmapIoSpace( + Adapter->NdisAdapterHandle, + Adapter->MmioRegion, + 0x2000 + ); + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_RESOURCE_CONFLICT, + 0 + ); + + return(FALSE); + } + + Adapter->SharedRamPaging = FALSE; + Adapter->MappedSharedRam = Adapter->RamSize; + Adapter->RrrLowValue = (UCHAR)(Adapter->Ram >> 12); + WRITE_ADAPTER_REGISTER(Adapter, RRR_LOW, Adapter->RrrLowValue); + + +#if DBG + if (IbmtokDbg) + { + DbgPrint ("mmio in hw = %x\n",Adapter->MmioAddress); + DbgPrint ("mmio in adapter = %x\n",Adapter->MmioRegion); + DbgPrint ("Adapter->SharedRam = %x\n",Adapter->SharedRam); + DbgPrint ("Adapter->Ram = %x\n",Adapter->Ram); + DbgPrint ("DEFAULT_RAM = %x\n",DEFAULT_RAM); + { + UCHAR Fred; + READ_ADAPTER_REGISTER(Adapter, RRR_LOW, &Fred); + DbgPrint("RRR_LOW = %x\n",Fred); + READ_ADAPTER_REGISTER(Adapter, RRR_HIGH, &Fred); + DbgPrint("RRR_HIGH = %x\n",Fred); + } + } +#endif + } + else + { + // + // SwitchRead1 contains the interrupt code in the low 2 bits, + // and bits 18 through 13 of the MMIO address in the high + // 6 bits. + // + + READ_ADAPTER_PORT(Adapter, SWITCH_READ_1, &SwitchRead1); + + // + // SwitchRead2 contains Bit 19 of the MMIO address in the + // low bit. It is always 1 for PC I/O Bus and possibly 0 + // for the Microchannel bus + // + + READ_ADAPTER_PORT(Adapter, SWITCH_READ_2, &SwitchRead2); + + // + // To compute MmioAddress, we mask off the low 2 bits of + // SwitchRead1, shift it out by 11 (so that the high 6 bits + // are moved to the right place), and add in the 19th bit value. + // + + MmioAddress = ((SwitchRead1 & 0xfc) << 11) | ((SwitchRead2 & 1) << 19); + + NdisSetPhysicalAddressHigh(PhysicalAddress, 0); + NdisSetPhysicalAddressLow(PhysicalAddress, MmioAddress); + + NdisMapIoSpace( + &Status, + (PVOID *)&(Adapter->MmioRegion), + Adapter->NdisAdapterHandle, + PhysicalAddress, + 0x2000); + + if (Status != NDIS_STATUS_SUCCESS) { + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_RESOURCE_CONFLICT, + 0 + ); + + return(FALSE); + + } + + + // + // Now we have mapped the MMIO, look at the AIP. First + // determine the channel identifier. + // + + { + // + // Will hold the Adapter ID as read from the card. + // + ULONG AdapterId[3]; + + // + // What AdapterId should contain for a PC I/O bus card. + // + static ULONG PcIoBusId[3] = { 0x5049434f, 0x36313130, 0x39393020 }; + + // + // What AdapterId should contain for a Micro Channel card. + // + static ULONG MicroChannelId[3] = { 0x4d415253, 0x36335834, 0x35313820 }; + + // + // Loop counters. + // + UINT i, j; + + UCHAR TmpUchar; + + // + // Read in AdapterId. + // + // Turns out that the bytes which identify the card are stored + // in a very odd manner. There are 48 bytes on the card. The + // even numbered bytes contain 4 bits of the card signature. + // + + for (i=0; i<3; i++) { + + AdapterId[i] = 0; + + for (j=0; j<16; j+=2) { + + READ_ADAPTER_REGISTER(Adapter, + CHANNEL_IDENTIFIER + (i*16 + j), + &TmpUchar + ); + + AdapterId[i] = (AdapterId[i] << 4) + (TmpUchar & 0x0F); + + + } + + } + + if ((AdapterId[0] == PcIoBusId[0]) && + (AdapterId[1] == PcIoBusId[1]) && + (AdapterId[2] == PcIoBusId[2])) { + + Adapter->UsingPcIoBus = TRUE; + + } else if ((AdapterId[0] == MicroChannelId[0]) && + (AdapterId[1] == MicroChannelId[1]) && + (AdapterId[2] == MicroChannelId[2])) { + + Adapter->UsingPcIoBus = FALSE; + + } else { + + // + // Unknown channel type. + // + + + NdisUnmapIoSpace(Adapter->NdisAdapterHandle, + Adapter->MmioRegion, + 0x2000); + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS, + 0 + ); + + return FALSE; + + } + + } + + // + // We can read the network address from the AIP but we won't, + // we read it from the bring-up SRB instead. + // + + // + // Read the RRR High to get the Shared RAM size (we are + // only interested in bits 2 and 3). + // + + READ_ADAPTER_REGISTER(Adapter, RRR_HIGH, &SharedRamBits); + + SharedRamBits = ((SharedRamBits & 0x0c) >> 2); + + if (Adapter->UsingPcIoBus) { + + // + // Here we have to tell the Adapter where Shared RAM is + // going to be. To do this we first find the lowest + // address it could be at, and then advance the address + // such that it falls on a correct page boudary. + // + + + // + // To get value to put in RRR Low, which indicates where + // the Shared RAM is mapped, we first compute the lowest + // possible value, which is right after the MMIO region. + // We take the high six bits of SwitchRead and shift + // them right one (so bits 18-13 of the address are in + // bits 6-1), then we turn on bit 7 to indicate that bit + // 19 of the address is on, and leave bit 0 zero since + // it must be. + // + + Adapter->RrrLowValue = (UCHAR) + ((((SwitchRead1 & 0xfc) >> 1) | 0x80) + 0x02); + + // + // We now have to move up to a memory boundary + // based on the value of SharedRamBits; 0 (8K) = 16K boundary, + // 1 (16K) = 16K boundary, 2 (32K) = 32K boundary, and + // 3 (64K) = 64K Boundary. Remember that the way the + // address bits are shifted over in RrrLowValue, bit 1 + // is really bit 13 of the final address (turning it on + // adds 8K), bit 2 if bit 14, etc. We compute Boundary + // Needed in this frame of reference. + // + + switch (SharedRamBits) { + + case 0: + case 1: + + // + // 8K or 16K needs a 16K boundary. + // + + RrrSharedRamSize = (SharedRamBits == 0) ? 0x2000 : 0x4000; + BoundaryNeeded = 0x04; + break; + + case 2: + + // + // 32K needs a 32K boundary. + // + + RrrSharedRamSize = 0x8000; + BoundaryNeeded = 0x08; + break; + + case 3: + + // + // 64K needs a 64K boundary. + // + + RrrSharedRamSize = 0x10000; + BoundaryNeeded = 0x10; + break; + + } + + + // + // If RrrLowValue is not on the proper boundary, move it + // forward until it is. + // + + if (Adapter->RrrLowValue & (BoundaryNeeded-1)) { + + Adapter->RrrLowValue = (UCHAR) + ((Adapter->RrrLowValue & ~(BoundaryNeeded-1)) + BoundaryNeeded); + + } + + Adapter->MappedSharedRam = SharedRamSize = RrrSharedRamSize; + + NdisSetPhysicalAddressHigh(PhysicalAddress, 0); + NdisSetPhysicalAddressLow(PhysicalAddress, Adapter->RrrLowValue << 12); + + NdisMapIoSpace(&Status, + (PVOID *)&(Adapter->SharedRam), + Adapter->NdisAdapterHandle, + PhysicalAddress, + RrrSharedRamSize + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + NdisUnmapIoSpace(Adapter->NdisAdapterHandle, + Adapter->MmioRegion, + 0x2000); + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_RESOURCE_CONFLICT, + 0 + ); + + return(FALSE); + + } + + } else { + + // + // Using Microchannel + // + // No need to set Adapter->RrrLowValue since it is not + // used in the Microchannel adapter. + // + + switch (SharedRamBits){ + case 0: + SharedRamSize = 0x2000; + break; + case 1: + SharedRamSize = 0x4000; + break; + case 2: + SharedRamSize = 0x8000; + break; + case 3: + SharedRamSize = 0x10000; + break; + } + + McaSharedRam = ((SwitchRead2 & 0xfe) << 12); + + NdisSetPhysicalAddressHigh(PhysicalAddress, 0); + NdisSetPhysicalAddressLow(PhysicalAddress, McaSharedRam); + + NdisMapIoSpace(&Status, + (PVOID *)&(Adapter->SharedRam), + Adapter->NdisAdapterHandle, + PhysicalAddress, + SharedRamSize); + + if (Status != NDIS_STATUS_SUCCESS) { + + NdisUnmapIoSpace(Adapter->NdisAdapterHandle, + Adapter->MmioRegion, + 0x2000); + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_RESOURCE_CONFLICT, + 0 + ); + + return(FALSE); + + } + + Adapter->MappedSharedRam = SharedRamSize; + + } + + + + // + // Get the interrupt level...note that a switch being + // "off" shows up as a 1, "on" is 0. + // + + switch (SwitchRead1 & 0x03) { + + case 0: InterruptLevel = 2; break; + case 1: InterruptLevel = 3; break; + case 2: InterruptLevel = (Adapter->UsingPcIoBus)?6:10; break; + case 3: InterruptLevel = (Adapter->UsingPcIoBus)?7:11; break; + + } + + Adapter->InterruptLevel = InterruptLevel; + + // + // Now determine how much memory the adapter has, and + // whether to use Shared RAM paging. + // + + Adapter->UpperSharedRamZero = FALSE; + + READ_ADAPTER_REGISTER(Adapter, TOTAL_ADAPTER_RAM, &RegValue); + + RegValue &= 0x0F; + + switch (RegValue) { + + // + // These values are described on page 7-26 of the + // Technical Reference. + // + + case 0xf: + + Adapter->TotalSharedRam = SharedRamSize; + break; + + case 0xe: + + Adapter->TotalSharedRam = 0x2000; + break; + + case 0xd: + + Adapter->TotalSharedRam = 0x4000; + break; + + case 0xc: + + Adapter->TotalSharedRam = 0x8000; + break; + + case 0xb: + + Adapter->TotalSharedRam = 0x10000; + + Adapter->UpperSharedRamZero = TRUE; + break; + + case 0xa: + + Adapter->TotalSharedRam = 0x10000; + break; + + default: + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, + 3, + hardwareDetails, + IBMTOK_ERRMSG_UNSUPPORTED_RAM, + (ULONG)RegValue + ); + + NdisUnmapIoSpace(Adapter->NdisAdapterHandle, + Adapter->MmioRegion, + 0x2000); + + if (Adapter->UsingPcIoBus) { + NdisUnmapIoSpace( + Adapter->NdisAdapterHandle, + Adapter->SharedRam, + SharedRamSize); + } else { + NdisUnmapIoSpace( + Adapter->NdisAdapterHandle, + Adapter->SharedRam, + SharedRamSize); + } + + return FALSE; + + } + + // + // Only allow Shared RAM paging if we have 16K selected + // on SharedRamSize, 64K of total adapter memory, and it is allowed + // as specified on p. 7-26 of the Technical Reference. + // + + READ_ADAPTER_REGISTER(Adapter, SHARED_RAM_PAGING, &AipSharedRamPaging); +#if 0 + if (SharedRamSize == 0x4000 && + Adapter->TotalSharedRam == 0x10000 && + (AipSharedRamPaging == 0xe || AipSharedRamPaging == 0xc)) { + + Adapter->SharedRamPaging = TRUE; + + } else { + + Adapter->SharedRamPaging = FALSE; + + } +#else + Adapter->SharedRamPaging = FALSE; +#endif + } + + + // + // Read in the maximum sizes allowed for DHBs based on + // the speed of the adapter (which we don't know yet). + // + + READ_ADAPTER_REGISTER(Adapter, MAX_4_MBPS_DHB, &RegValue); + + RegValue &= 0x0F; + + switch (RegValue) { + + case 0xf: + default: + + Adapter->Max4MbpsDhb = 2048; + break; + + case 0xe: + + Adapter->Max4MbpsDhb = 4096; + break; + + case 0xd: + + Adapter->Max4MbpsDhb = 4464; + break; + + } + + READ_ADAPTER_REGISTER(Adapter, MAX_16_MBPS_DHB, &RegValue); + + RegValue &= 0x0F; + + switch (RegValue) { + + case 0xf: + default: + + Adapter->Max16MbpsDhb = 2048; + break; + + case 0xe: + + Adapter->Max16MbpsDhb = 4096; + break; + + case 0xd: + + Adapter->Max16MbpsDhb = 8192; + break; + + case 0xc: + + Adapter->Max16MbpsDhb = 16384; + break; + + case 0xb: + + Adapter->Max16MbpsDhb = 17960; + break; + + } + + + return TRUE; + +} |