diff options
Diffstat (limited to 'private/ntos/ndis/ibmtok')
-rw-r--r-- | private/ntos/ndis/ibmtok/ibmtok.c | 5906 | ||||
-rw-r--r-- | private/ntos/ndis/ibmtok/ibmtok.rc | 39 | ||||
-rw-r--r-- | private/ntos/ndis/ibmtok/interrup.c | 4855 | ||||
-rw-r--r-- | private/ntos/ndis/ibmtok/keywords.h | 54 | ||||
-rw-r--r-- | private/ntos/ndis/ibmtok/makefile | 6 | ||||
-rw-r--r-- | private/ntos/ndis/ibmtok/packet.c | 732 | ||||
-rw-r--r-- | private/ntos/ndis/ibmtok/send.c | 322 | ||||
-rw-r--r-- | private/ntos/ndis/ibmtok/sources | 48 | ||||
-rw-r--r-- | private/ntos/ndis/ibmtok/tokhrd.h | 667 | ||||
-rw-r--r-- | private/ntos/ndis/ibmtok/toksft.h | 1373 | ||||
-rw-r--r-- | private/ntos/ndis/ibmtok/transfer.c | 412 |
11 files changed, 14414 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; + +} diff --git a/private/ntos/ndis/ibmtok/ibmtok.rc b/private/ntos/ndis/ibmtok/ibmtok.rc new file mode 100644 index 000000000..ef5e6e0fb --- /dev/null +++ b/private/ntos/ndis/ibmtok/ibmtok.rc @@ -0,0 +1,39 @@ +#include <windows.h> +#include <ntverp.h> + +/*-----------------------------------------------*/ +/* the following lines are specific to this file */ +/*-----------------------------------------------*/ + +/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR + * and VER_INTERNALNAME_STR must be defined before including COMMON.VER + * The strings don't need a '\0', since common.ver has them. + */ +#define VER_FILETYPE VFT_DRV +/* possible values: VFT_UNKNOWN + VFT_APP + VFT_DLL + VFT_DRV + VFT_FONT + VFT_VXD + VFT_STATIC_LIB +*/ +#define VER_FILESUBTYPE VFT2_DRV_NETWORK +/* possible values VFT2_UNKNOWN + VFT2_DRV_PRINTER + VFT2_DRV_KEYBOARD + VFT2_DRV_LANGUAGE + VFT2_DRV_DISPLAY + VFT2_DRV_MOUSE + VFT2_DRV_NETWORK + VFT2_DRV_SYSTEM + VFT2_DRV_INSTALLABLE + VFT2_DRV_SOUND + VFT2_DRV_COMM +*/ +#define VER_FILEDESCRIPTION_STR "IBM Token Ring 4, 16, 16/4 and 16/4A network driver" +#define VER_INTERNALNAME_STR "IBMTOK.SYS" +#define VER_ORIGINALFILENAME_STR "IBMTOK.SYS" + +#include "common.ver" + diff --git a/private/ntos/ndis/ibmtok/interrup.c b/private/ntos/ndis/ibmtok/interrup.c new file mode 100644 index 000000000..eb406b02a --- /dev/null +++ b/private/ntos/ndis/ibmtok/interrup.c @@ -0,0 +1,4855 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + interrup.c + +Abstract: + + This is a part of the driver for the IBM IBMTOK + Token-ring controller. It contains the interrupt-handling routines. + 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: + + Adam Barr (adamba) 16-Jan-1991 + +Environment: + + Kernel Mode - Or whatever is the equivalent. + +Revision History: + + Sean Selitrennikoff - 10/91 + Fixed synchronization bugs. + + Sean Selitrennikoff - 10/15/91 + Converted to Ndis 3.0 + + Sean Selitrennikoff - 1/8/92 + Added error logging + + Brian E. Moore - 9/7/94 + Added PCMCIA support + +--*/ + +#pragma optimize("",off) + +#include <ndis.h> + + +#include <tfilter.h> +#include <tokhrd.h> +#include <toksft.h> + + +#if DEVL +#define STATIC +#else +#define STATIC static +#endif + +#if DBG +extern INT IbmtokDbg; +#endif + +// +// This section contains all the functions and definitions for +// doing logging of input and output to/from the card. +// + +#if LOG + +// +// Place in the circular buffer. +// +UCHAR IbmtokLogPlace; + +// +// Circular buffer for storing log information. +// +UCHAR IbmtokLog[256]; + +#endif + +VOID +SetResetVariables( + IN PIBMTOK_ADAPTER Adapter + ); + +STATIC +VOID +IbmtokHandleSrbSsb( + IN PIBMTOK_ADAPTER Adapter + ); + +STATIC +VOID +IbmtokHandleArbAsb( + IN PIBMTOK_ADAPTER Adapter + ); + + +STATIC +VOID +HandleResetStaging( + IN PIBMTOK_ADAPTER Adapter + ); + +STATIC +BOOLEAN +IbmtokSynchGetSrbSsbBits( + IN PVOID Context + ); + +STATIC +BOOLEAN +IbmtokSynchGetArbAsbBits( + IN PVOID Context + ); + +STATIC +VOID +PutPacketOnWaitingForAsb( + IN PIBMTOK_ADAPTER Adapter, + IN PNDIS_PACKET Packet + ); + +STATIC +PNDIS_PACKET +RemoveTransmitFromSrb( + IN PIBMTOK_ADAPTER Adapter, + OUT PBOOLEAN PacketRemoved + ); + +STATIC +VOID +SetupTransmitFrameSrb( + IN PIBMTOK_ADAPTER Adapter, + IN PNDIS_PACKET Packet + ); + +STATIC +VOID +SetupTransmitStatusAsb( + IN PIBMTOK_ADAPTER Adapter, + IN PNDIS_PACKET Packet + ); + +STATIC +VOID +GetAdapterStatisticsFromSrb( + PIBMTOK_ADAPTER Adapter + ); + +STATIC +VOID +GetAdapterErrorsFromSrb( + PIBMTOK_ADAPTER Adapter + ); + + +STATIC +NDIS_STATUS +StartPendQueueOp( + IN PIBMTOK_ADAPTER Adapter + ); + +STATIC +NDIS_STATUS +FinishSetOperation( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_PEND_DATA PendOp + ); + + +STATIC +BOOLEAN +FinishPendQueueOp( + IN PIBMTOK_ADAPTER Adapter, + IN BOOLEAN Successful + ); + +STATIC +NDIS_STATUS +SetAdapterFunctionalAddress( + IN PIBMTOK_ADAPTER Adapter + ); + +STATIC +VOID +SetupFunctionalSrb( + IN PIBMTOK_ADAPTER Adapter, + IN TR_FUNCTIONAL_ADDRESS FunctionalAddress + ); + +STATIC +NDIS_STATUS +SetAdapterGroupAddress( + IN PIBMTOK_ADAPTER Adapter + ); + +STATIC +VOID +SetupGroupSrb( + IN PIBMTOK_ADAPTER Adapter, + IN TR_FUNCTIONAL_ADDRESS FunctionalAddress + ); + +STATIC +VOID +SetupReceivedDataAsb( + IN PIBMTOK_ADAPTER Adapter, + IN SRAM_PTR ReceiveBuffer + ); + + +// +// These macros are used to set the SRPR correctly. +// +#define SET_SRB_SRPR(Adapter) \ + if (Adapter->SharedRamPaging) { \ + WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, Adapter->SrbSrprLow) \ + } + +#define SET_SSB_SRPR(Adapter) \ + if (Adapter->SharedRamPaging) { \ + WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, Adapter->SsbSrprLow) \ + } + +#define SET_ARB_SRPR(Adapter) \ + if (Adapter->SharedRamPaging) { \ + WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, Adapter->ArbSrprLow) \ + } + +#define SET_ASB_SRPR(Adapter) \ + if (Adapter->SharedRamPaging) { \ + WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, Adapter->AsbSrprLow) \ + } + + + +typedef struct _IBMTOK_SYNCH_CONTEXT { + + // + // Pointer to the ibmtok adapter for which interrupts are + // being synchronized. + // + PIBMTOK_ADAPTER Adapter; + + // + // Points to the variable on to which the relevant + // interrupt bits should be ORed. + // + PVOID Local; + +} IBMTOK_SYNCH_CONTEXT, * PIBMTOK_SYNCH_CONTEXT; + +// +// This macro is to synchronize execution with interrupts. It +// gets the stored value of the SRB/SSB bits and clears the +// old value. +// +#define GET_SRB_SSB_BITS(A,L) \ +{ \ + PIBMTOK_ADAPTER _A = A; \ + IBMTOK_SYNCH_CONTEXT _C; \ + _C.Adapter = _A; \ + _C.Local = (PVOID)(L); \ + NdisSynchronizeWithInterrupt( \ + &(_A->Interrupt), \ + (PVOID) IbmtokSynchGetSrbSsbBits, \ + &_C \ + ); \ +} + +// +// This macro is to synchronize execution with interrupts. It +// gets the stored value of the ARB/ASB bits and clears the +// old value. +// +#define GET_ARB_ASB_BITS(A,L) \ +{ \ + PIBMTOK_ADAPTER _A = A; \ + IBMTOK_SYNCH_CONTEXT _C; \ + _C.Adapter = _A; \ + _C.Local = (PVOID)(L); \ + NdisSynchronizeWithInterrupt( \ + &(_A->Interrupt), \ + (PVOID) IbmtokSynchGetArbAsbBits, \ + &_C \ + ); \ +} + + +//++ +// +// PNDIS_PACKET +// FindPacketGivenCorrelator( +// IN PIBMTOK_ADAPTER Adapter, +// IN UCHAR CommandCorrelator +// ) +// +// +// Routine Description: +// +// This looks a packet up on the command correlator array. +// +// This routine should be called with the spinlock held. +// +// Arguments: +// +// Adapter - The adapter that this packet is coming through. +// +// CommandCorrelator - The command correlator to search based on. +// +// Return Value: +// +// The packet if found, NULL otherwise. +// +//-- + +#define FindPacketGivenCorrelator(_Adapter, _CommandCorrelator) \ + ((_Adapter)->CorrelatorArray[_CommandCorrelator]) + + +STATIC +BOOLEAN +IbmtokSynchGetSrbSsbBits( + IN PVOID Context + ) + +/*++ + +Routine Description: + + This routine is used by the normal interrupt processing routine + to synchronize with interrupts from the card. It will or + the value of the stored SRB/SSB bits into the other passed address + in the context and clear the stored value. + +Arguments: + + Context - This is really a pointer to a record type peculiar + to this routine. The record contains a pointer to the adapter + and a pointer to an address in which to place the contents + of the ISRP. + +Return Value: + + Always returns true. + +--*/ + +{ + PIBMTOK_SYNCH_CONTEXT C = (PIBMTOK_SYNCH_CONTEXT)Context; + + *((PUCHAR)C->Local) = (C->Adapter->IsrpBits) & + (ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE); + + C->Adapter->IsrpBits = (C->Adapter->IsrpBits) & + (~(ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE)); + + return TRUE; +} + +ULONG PCMCIAStall = 0; + +STATIC +BOOLEAN +IbmtokSynchGetArbAsbBits( + IN PVOID Context + ) + +/*++ + +Routine Description: + + This routine is used by the normal interrupt processing routine + to synchronize with interrupts from the card. It will or + the value of the stored ARB/ASB bits into the other passed address + in the context and clear the stored value. + +Arguments: + + Context - This is really a pointer to a record type peculiar + to this routine. The record contains a pointer to the adapter + and a pointer to an address in which to place the contents + of the ISRP. +Return Value: + + Always returns true. + +--*/ + +{ + PIBMTOK_SYNCH_CONTEXT C = (PIBMTOK_SYNCH_CONTEXT)Context; + UCHAR Test,i; +IF_LOG('*'); + + if (C->Adapter->CardType == IBM_TOKEN_RING_PCMCIA) + { + NdisStallExecution(PCMCIAStall); + } + + *((PUCHAR)C->Local) = (C->Adapter->IsrpBits) & + (ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE); + + C->Adapter->IsrpBits = (C->Adapter->IsrpBits) & + (~(ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE)); + + return TRUE; +} + +extern +BOOLEAN +IbmtokSynchSetReset( + IN PVOID Context + ) + +/*++ + +Routine Description: + + This routine is called by the SET_INTERRUPT_RESET_FLAG macro. + It sets the ResetInterruptAllowed flag to TRUE. + +Arguments: + + Context - A pointer to the Adapter structure. + +Return Value: + + Always returns true. + +--*/ + +{ + PIBMTOK_ADAPTER Adapter = (PIBMTOK_ADAPTER)Context; + + Adapter->ResetInterruptAllowed = TRUE; + + return TRUE; +} + +extern +BOOLEAN +IbmtokSynchClearIsrpBits( + IN PVOID Context + ) + +/*++ + +Routine Description: + + This routine is called by the CLEAR_ISRP_BITS macro. + It clears the SRB/SSB and ARB/ASB bits. This is used + when a reset has started to prevent a previously + queued interrupt handler to come in and start + playing with an adapter that is being reset. + +Arguments: + + Context - A pointer to the Adapter structure. + +Return Value: + + Always returns true. + +--*/ + +{ + PIBMTOK_ADAPTER Adapter = (PIBMTOK_ADAPTER)Context; + + Adapter->IsrpBits = 0; + + return TRUE; +} + +extern +BOOLEAN +IbmtokISR( + IN PVOID Context + ) + +/*++ + +Routine Description: + + Interrupt service routine for the token-ring card. It's main job is + to get the value of ISR and record the changes in the + adapters own list of interrupt reasons. + +Arguments: + + Context - Really a pointer to the adapter. + +Return Value: + + Returns true if the card ISR is non-zero. + +--*/ + +{ + + // + // Holds the pointer to the adapter. + // + PIBMTOK_ADAPTER Adapter = Context; + + // + // Holds the value of the ISRP High + // + UCHAR IsrpHigh; + + READ_ADAPTER_REGISTER(Adapter, ISRP_HIGH, &IsrpHigh); + + if (!Adapter->BringUp) + { + Adapter->ContinuousIsrs++; + + if (Adapter->ContinuousIsrs == 0xFF) + { + // + // We seemed to be confused since the DPCs aren't getting in. + // Shutdown and exit. + // +#if DBG + if (IbmtokDbg) + DbgPrint("IBMTOK: Continuous ISRs received\n"); +#endif + + WRITE_ADAPTER_PORT(Adapter, RESET_LATCH, 0); + + return(FALSE); + } + } + + +#if DBG + if (IbmtokDbg) DbgPrint("ISRP High: %x\n", IsrpHigh); +#endif + + IF_LOG('i'); + + // + // Acknowledge all the interrupts we got in IsrpHigh. + // + WRITE_ADAPTER_REGISTER(Adapter, ISRP_HIGH_RESET, (UCHAR)(~IsrpHigh)); + + // + // If the adapter is not accepting requests, ignore everything + // but SRB_RESPONSE interrupts, saving any others until + // NotAcceptingRequests goes to FALSE (note that we have + // already turned off ALL bits in ISRP_HIGH). + // + if (Adapter->NotAcceptingRequests) + { + Adapter->IsrpDeferredBits |= (IsrpHigh & (~ISRP_HIGH_SRB_RESPONSE)); + + IsrpHigh &= ISRP_HIGH_SRB_RESPONSE; + } + else + { + // + // Put the deferred bits back on (after the first time + // through they will be 0). + // + IsrpHigh |= Adapter->IsrpDeferredBits; + + Adapter->IsrpDeferredBits = 0; + } + + // + // Now store the bits for the DPC. + // + Adapter->IsrpBits |= IsrpHigh; + + // + // If this is the reset interrupt, set the flag. + // + if (Adapter->ResetInterruptAllowed) + { + Adapter->ResetInterruptHasArrived = TRUE; + } + + if (Adapter->FirstInitialization) + { + USHORT WrbOffset; + PSRB_BRING_UP_RESULT BringUpSrb; + UCHAR Value1, Value2; + USHORT RegValue; + + READ_ADAPTER_REGISTER(Adapter, WRBR_LOW, &Value1); + READ_ADAPTER_REGISTER(Adapter, WRBR_HIGH, &Value2); + + WrbOffset = (((USHORT)Value1) << 8) + (USHORT)Value2; + + if (WrbOffset & 0x1) + { + // + // Mis-aligned WRB, fail to load + // + if (Adapter->UsingPcIoBus) + { + WRITE_ADAPTER_PORT(Adapter, INTERRUPT_RELEASE_ISA_ONLY, 1); + } + + return(FALSE); + } + + Adapter->InitialWrbOffset = WrbOffset; + + BringUpSrb = (PSRB_BRING_UP_RESULT)(Adapter->SharedRam + WrbOffset); + + NdisReadRegisterUshort(&(BringUpSrb->ReturnCode), &RegValue); + + if (RegValue == 0x0000) + { + Adapter->BringUp = TRUE; + } + + // + // If we are using the PC I/O Bus then we have to re-enable + // interrupts because the card is blocking all other interrupts + // + if (Adapter->UsingPcIoBus) + { + WRITE_ADAPTER_PORT(Adapter, INTERRUPT_RELEASE_ISA_ONLY, 1); + } + + IF_LOG('I'); + + // + // no DPC for the first init. + // + return(FALSE); + } + + // + // If we are using the PC I/O Bus then we have to re-enable + // interrupts because the card is blocking all other interrupts + // + if (Adapter->UsingPcIoBus) + { + WRITE_ADAPTER_PORT(Adapter, INTERRUPT_RELEASE_ISA_ONLY, 1); + } + + if (IsrpHigh == 0x0) + { + // + // This means that the interrupt was generated from the IsrpLow + // and needs to be cleared. + // + READ_ADAPTER_REGISTER(Adapter, ISRP_LOW, &IsrpHigh); + + // + // Mask off the bits we need. + // + IsrpHigh &= 0x1C; + + Adapter->IsrpLowBits = IsrpHigh; + + // + // Acknowledge all the interrupts we got in IsrpLow. + // + WRITE_ADAPTER_REGISTER(Adapter, ISRP_LOW_RESET, (UCHAR)(~IsrpHigh)); + } + + IF_LOG('I'); + + if (Adapter->IsrpBits != 0) + { + return TRUE; + } + else + { + return FALSE; + } +} + +extern +VOID +IbmtokDPC( + IN PVOID SystemSpecific1, + IN PVOID Context, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ) + +/*++ + +Routine Description: + + This DPC routine is queued by Ndis after interrupt service routine + has run. It's main job is to call the interrupt processing code. + +Arguments: + + SystemSpecific1 - Not used. + + Context - Really a pointer to the adapter. + + SystemArgument1(2) - Neither of these arguments used. + +Return Value: + + None. + +--*/ + +{ + PIBMTOK_ADAPTER Adapter = (PIBMTOK_ADAPTER)Context; + + NdisDprAcquireSpinLock(&Adapter->Lock); + + Adapter->ContinuousIsrs = 0; + + IF_LOG('d'); + + if (Adapter->IsrpLowBits) + { + Adapter->IsrpLowBits = 0; + } + + if ((Adapter->IsrpBits & (ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE)) && + (!Adapter->HandleArbRunning)) + { + IbmtokHandleArbAsb(Adapter); + + NdisDprAcquireSpinLock(&(Adapter->Lock)); + } + + if ((Adapter->IsrpBits & (ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE)) && + (!Adapter->HandleSrbRunning)) + { + IbmtokHandleSrbSsb(Adapter); + } + else + { + NdisDprReleaseSpinLock(&Adapter->Lock); + } + +#if DBG + NdisDprAcquireSpinLock(&Adapter->Lock); + IF_LOG('D'); + NdisDprReleaseSpinLock(&Adapter->Lock); +#endif +} + +extern +VOID +IbmtokHandleSrbSsb( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine is called by the DPC routine + and other routines within the driver that notice that + some deferred processing needs to be done. It's main + job is to call the interrupt processing code. + + NOTE: THIS ROUTINE IS CALLED WITH THE LOCK HELD!! AND RETURNS + WITH IT RELEASED!! + +Arguments: + + Adapter - A pointer to the adapter. + +Return Value: + + None. + +--*/ + +{ + UCHAR IsrpHigh; + UCHAR TmpUchar; + USHORT TmpUshort; + UCHAR Temp; + UINT Nibble3; + + IF_LOG('h'); + + Adapter->References++; + + if (Adapter->ResetInProgress) + { + if (Adapter->ResetInterruptHasArrived) + { + // + // This is the interrupt after a reset, + // continue things along. + // + HandleResetStaging(Adapter); + + IBMTOK_DO_DEFERRED(Adapter); + + return; + } + } + + // + // If ResetInProgress is TRUE but this is an old + // interrupt, proceed as usual (once the reset + // actually starts, GET_SRB_SSB_BITS will return + // nothing so no work will get done). + // + Adapter->HandleSrbRunning = TRUE; + + if (Adapter->CardType != IBM_TOKEN_RING_PCMCIA) + { + GET_SRB_SSB_BITS(Adapter, &IsrpHigh); + } + else + { + // + // 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, + Temp & ~(ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE)); + + // + // update arb_asb + // + IsrpHigh = (Adapter->IsrpBits) & (ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE); + Adapter->IsrpBits = (Adapter->IsrpBits) & (~(ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE)); + + // + // reenable interrupts on the card + // + WRITE_ADAPTER_REGISTER( + Adapter, + ISRP_LOW, + ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE); + } + + while (IsrpHigh & (ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE)) + { + IF_LOG((UCHAR)(Adapter->OpenInProgress)); + + if (Adapter->Unplugged && !Adapter->UnpluggedResetInProgress) + { + // + // Do, nothing. This is most likely a stale interrupt. We + // wait until we get a ring status interrupt telling us that + // the cable is plugged in. + // + break; + } + + if (IsrpHigh & ISRP_HIGH_SRB_RESPONSE) + { + if (Adapter->OpenInProgress) + { + // + // Handle the result of the DIR.OPEN.ADAPTER command. + // + PSRB_OPEN_RESPONSE OpenResponseSrb; + PIBMTOK_OPEN Open; + PLIST_ENTRY CurrentLink; + UCHAR ReturnCode; + + OpenResponseSrb = (PSRB_OPEN_RESPONSE) + (Adapter->SharedRam + Adapter->InitialWrbOffset); + + NdisReadRegisterUchar(&(OpenResponseSrb->ReturnCode), &ReturnCode); + +#if DBG + if (IbmtokDbg) + DbgPrint("IBMTOK: OPEN, Return code = %x, at %lx\n", + ReturnCode, + OpenResponseSrb); +#endif + +// + if (ReturnCode == 0x0) + { + NdisDprReleaseSpinLock(&(Adapter->Lock)); + + if (Adapter->SharedRamPaging) + { + NdisReadRegisterUshort(&(OpenResponseSrb->SrbPointer), &TmpUshort); + + TmpUshort = IBMSHORT_TO_USHORT(TmpUshort); + + Adapter->SrbAddress = SHARED_RAM_ADDRESS(Adapter, + SHARED_RAM_LOW_BITS(TmpUshort)); + Adapter->SrbSrprLow = (UCHAR)(TmpUshort >> 14); + + + NdisReadRegisterUshort(&(OpenResponseSrb->SsbPointer), &TmpUshort); + + TmpUshort = IBMSHORT_TO_USHORT(TmpUshort); + + Adapter->SsbAddress = SHARED_RAM_ADDRESS(Adapter, + SHARED_RAM_LOW_BITS(TmpUshort)); + Adapter->SsbSrprLow = (UCHAR)(TmpUshort >> 14); + + + NdisReadRegisterUshort(&(OpenResponseSrb->ArbPointer), &TmpUshort); + + TmpUshort = IBMSHORT_TO_USHORT(TmpUshort); + + Adapter->ArbAddress = SHARED_RAM_ADDRESS(Adapter, + SHARED_RAM_LOW_BITS(TmpUshort)); + Adapter->ArbSrprLow = (UCHAR)(TmpUshort >> 14); + + + NdisReadRegisterUshort(&(OpenResponseSrb->AsbPointer), &TmpUshort); + + TmpUshort = IBMSHORT_TO_USHORT(TmpUshort); + + Adapter->AsbAddress = SHARED_RAM_ADDRESS(Adapter, + SHARED_RAM_LOW_BITS(TmpUshort)); + Adapter->AsbSrprLow = (UCHAR)(TmpUshort >> 14); + } + else + { + NdisReadRegisterUshort(&(OpenResponseSrb->SrbPointer), &TmpUshort); + Adapter->SrbAddress = SRAM_PTR_TO_PVOID(Adapter, TmpUshort); + + NdisReadRegisterUshort(&(OpenResponseSrb->SsbPointer), &TmpUshort); + Adapter->SsbAddress = SRAM_PTR_TO_PVOID(Adapter, TmpUshort); + + NdisReadRegisterUshort(&(OpenResponseSrb->ArbPointer), &TmpUshort); + Adapter->ArbAddress = SRAM_PTR_TO_PVOID(Adapter, TmpUshort); + + NdisReadRegisterUshort(&(OpenResponseSrb->AsbPointer), &TmpUshort); + Adapter->AsbAddress = SRAM_PTR_TO_PVOID(Adapter, TmpUshort); + } + + if (((ULONG)Adapter->SrbAddress > + (ULONG)(Adapter->SharedRam + Adapter->MappedSharedRam)) || + ((ULONG)Adapter->SsbAddress > + (ULONG)(Adapter->SharedRam + Adapter->MappedSharedRam)) || + ((ULONG)Adapter->ArbAddress > + (ULONG)(Adapter->SharedRam + Adapter->MappedSharedRam)) || + ((ULONG)Adapter->AsbAddress > + (ULONG)(Adapter->SharedRam + Adapter->MappedSharedRam))) + { + // + // Something is definitely wrong. Fail! + // + goto OpenFailed; + } + +#if DBG + if (IbmtokDbg) + { + USHORT TmpUshort1; + USHORT TmpUshort2; + USHORT TmpUshort3; + USHORT TmpUshort4; + NdisReadRegisterUshort(&(OpenResponseSrb->SrbPointer), &TmpUshort1); + NdisReadRegisterUshort(&(OpenResponseSrb->SsbPointer), &TmpUshort2); + NdisReadRegisterUshort(&(OpenResponseSrb->ArbPointer), &TmpUshort3); + NdisReadRegisterUshort(&(OpenResponseSrb->AsbPointer), &TmpUshort4); + DbgPrint("IBMTOK: Offsets: SRB %x SSB %x ARB %x ASB %x\n", + IBMSHORT_TO_USHORT(TmpUshort1), + IBMSHORT_TO_USHORT(TmpUshort2), + IBMSHORT_TO_USHORT(TmpUshort3), + IBMSHORT_TO_USHORT(TmpUshort4)); + } +#endif + + // + // Now we have to start worrying about synchronization. + // + NdisDprAcquireSpinLock(&(Adapter->Lock)); + + Adapter->CurrentRingState = NdisRingStateOpened; + Adapter->OpenInProgress = FALSE; + Adapter->OpenErrorCode = 0; + Adapter->AdapterNotOpen = FALSE; + Adapter->NotAcceptingRequests = FALSE; + + // + // Complete all opens that pended during this operation. + // + CurrentLink = Adapter->OpenBindings.Flink; + + while (CurrentLink != &(Adapter->OpenBindings)) + { + Open = CONTAINING_RECORD(CurrentLink, IBMTOK_OPEN, OpenList); + if (Open->OpenPending) + { + Open->OpenPending = FALSE; + NdisDprReleaseSpinLock(&(Adapter->Lock)); + + NdisCompleteOpenAdapter( + Open->NdisBindingContext, + NDIS_STATUS_SUCCESS, + 0); + + NdisDprAcquireSpinLock(&(Adapter->Lock)); + } + + CurrentLink = CurrentLink->Flink; + } + + // + // Get any interrupts that have been deferred + // while NotAcceptingRequests was TRUE. + // + IbmtokForceAdapterInterrupt(Adapter); + } + else + { + // + // Open Failed! + // + // Here is where I check the return code from the Open and see if it + // indicates an incorrect ring speed. If it does, I change the ring speed + // and reissue the OpenAdapter. BEM + // + NdisReadRegisterUshort( + &(OpenResponseSrb->ErrorCode), + &(TmpUshort)); + + // + // If a catastrophic error and a frequency error and we want ring speed listen + // and the number of retries > 0, bail out. We have already tried a different + // speed + // + if ((ReturnCode == 0x07) && // catastrophic error + (TmpUshort == 0x2400) && // frequency error + Adapter->RingSpeedListen && // we want ring speed listen + (Adapter->RingSpeedRetries == 0)) // have not tried before + { +#if DBG + if (IbmtokDbg) + DbgPrint("IBMTOK: Incorrect Ring Speed, Changing.\n"); +#endif + // + // + // Change the ring speed + // + + if (Adapter->Running16Mbps == TRUE) + Adapter->Running16Mbps == FALSE; + else + Adapter->Running16Mbps == TRUE; + + Nibble3 = NIBBLE_3; + + if (Adapter->RingSpeed == 16) + { // swap speeds + Nibble3 |= RING_SPEED_4_MPS; + } + else + { + Nibble3 |= RING_SPEED_16_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; + } + + WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble3); + + // + // Now to reissue the Open Adapter SRB with the necessary changes. + // + // Reset these fields in the SRB for the Open Adapter. + // + OpenResponseSrb->ReturnCode = 0xFE; + OpenResponseSrb->ErrorCode = 0x0000; + + // DbgBreakPoint(); + // + // Tell the adapter to handle the change. + // + WRITE_ADAPTER_REGISTER( + Adapter, + ISRA_HIGH_SET, + ISRA_HIGH_COMMAND_IN_SRB); + + Adapter->RingSpeedRetries++; // first retry + + // end of check for incorrect ring speed + } + else + { +OpenFailed: +#if DBG + if (IbmtokDbg) + { + DbgPrint("IBMTOK: Open failed!\n"); + } +#endif + // + // Now we have to start worrying about synchronization. + // + Adapter->CurrentRingState = NdisRingStateOpenFailure; + Adapter->OpenInProgress = FALSE; + NdisReadRegisterUshort( + &(OpenResponseSrb->ErrorCode), + &(Adapter->OpenErrorCode)); + Adapter->OpenErrorCode = IBMSHORT_TO_USHORT(Adapter->OpenErrorCode); + Adapter->AdapterNotOpen = TRUE; + Adapter->NotAcceptingRequests = TRUE; + + // + // Fail all opens that pended during this operation. + // + CurrentLink = Adapter->OpenBindings.Flink; + + while (CurrentLink != &(Adapter->OpenBindings)) + { + Open = CONTAINING_RECORD( + CurrentLink, + IBMTOK_OPEN, + OpenList); + + if (Open->OpenPending) + { + Open->OpenPending = FALSE; + + NdisDprReleaseSpinLock(&(Adapter->Lock)); + + NdisCompleteOpenAdapter( + Open->NdisBindingContext, + NDIS_STATUS_OPEN_FAILED, + NDIS_STATUS_TOKEN_RING_OPEN_ERROR | + (NDIS_STATUS)(Adapter->OpenErrorCode)); + + NdisDprAcquireSpinLock(&(Adapter->Lock)); + + CurrentLink = CurrentLink->Flink; + + RemoveEntryList(&(Open->OpenList)); + + IBMTOK_FREE_PHYS(Open, sizeof(IBMTOK_OPEN)); + + Adapter->References--; + } + else + { + // + // Note: All opens are pending, otherwise the + // adapter would have already been open. + // + } + } + } + } + } + else + { +#if DBG + if (IbmtokDbg) + DbgPrint("IBMTOK: SRB Response\n"); +#endif + IF_LOG('>'); + + if (Adapter->TransmittingPacket != (PNDIS_PACKET)NULL) + { + BOOLEAN PacketRemoved; + + // + // Happens if the transmit failed. + // + (PVOID)RemoveTransmitFromSrb(Adapter, &PacketRemoved); + + // + // If the packet was successfully removed, then + // start the next command. + // + // This will release the spin lock. + // + if (PacketRemoved) + { + // + // SrbAvailable will still be FALSE here, + // as required. + // + SetupSrbCommand(Adapter); + } + } + else if (!Adapter->SrbAvailable) + { + PSRB_GENERIC GenericSrb = (PSRB_GENERIC)Adapter->SrbAddress; + UCHAR ReturnCode; + + // + // Another command in progress, complete it unless + // it was an INTERRUPT command. + // + NdisReadRegisterUchar(&(GenericSrb->ReturnCode), &ReturnCode); + + IF_LOG('N'); + + NdisReadRegisterUchar(&(GenericSrb->Command), &TmpUchar); + + if (TmpUchar != SRB_CMD_INTERRUPT) + { + if ((TmpUchar != SRB_CMD_READ_LOG) && + (TmpUchar != SRB_CMD_SET_FUNCTIONAL_ADDRESS) && + (TmpUchar != SRB_CMD_SET_GROUP_ADDRESS) && + (TmpUchar != SRB_CMD_DLC_STATISTICS)) + { + // + // We have an invalid response. Log an error an exit. + // + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER, + 3, + handleSrbSsb, + IBMTOK_ERRMSG_INVALID_CMD, + (ULONG)TmpUchar); + } + else + { + // + // This interrupt had to come from a pended op. + // + ASSERT(Adapter->PendData != NULL); + + if (Adapter->PendData->RequestType == NdisRequestGeneric1) + { + // + // If no request, it came as a result of the + // card overflowing a counter and then we + // submitted the correcting operation. + // + if (ReturnCode == 0x00) + { + if (Adapter->PendData->COMMAND.MAC.ReadLogPending) + { + // + // We are getting an SRB_CMD_READ_LOG from + // we sent as a result to a RING_STATUS_CHANGE. + // + GetAdapterErrorsFromSrb(Adapter); + } + else + { + // + // We are getting an SRB_CMD_DLC_STATISTICS from + // we sent as a result to a DLC_STATUS. + // + GetAdapterStatisticsFromSrb(Adapter); + } + } + + // + // Free up pend operation. + // + IBMTOK_FREE_PHYS(Adapter->PendData, sizeof(IBMTOK_PEND_DATA)); + + Adapter->PendData = NULL; + + // + // Fire off next command. + // + SetupSrbCommand(Adapter); + } + else + { + // + // This is the result of a pending op from Ndis. + // + if (FinishPendQueueOp( + Adapter, + (BOOLEAN)(ReturnCode == 0x00 ? TRUE : FALSE))) + { + + // + // Fire off next command. + // + SetupSrbCommand(Adapter); + } + } + } + } + else + { + SetupSrbCommand(Adapter); + } + } + else + { + // + // Nothing to do -- we get here when an SRB_FREE_REQUEST + // comes through after the ARB to transfer the data has + // already come through. + // + } + } + } + + if (IsrpHigh & ISRP_HIGH_SSB_RESPONSE) + { + // + // This has to be a transmit completing since + // that is the only operation we do that pends. + // + PSSB_TRANSMIT_COMPLETE ResponseSsb = + (PSSB_TRANSMIT_COMPLETE)Adapter->SsbAddress; + + NdisReadRegisterUchar(&(ResponseSsb->Command), &TmpUchar); + + if (TmpUchar == SRB_CMD_TRANSMIT_DIR_FRAME) + { + UCHAR CorrelatorInSrb; + NDIS_STATUS SendStatus; + UCHAR SrbReturnCode; + + // + // Initialize this to one less since the loop starts by + // incrementing it. + // + UCHAR CurrentCorrelator = (UCHAR) + ((Adapter->NextCorrelatorToComplete + + (MAX_COMMAND_CORRELATOR-1)) % + MAX_COMMAND_CORRELATOR); + + NdisReadRegisterUchar(&(ResponseSsb->CommandCorrelator), &CorrelatorInSrb); + + // + // Have to loop to complete since supposedly one + // of these can indicate multiple completing sends. + // + + // + // Figure out what the return code should be. + // + NdisReadRegisterUchar(&(ResponseSsb->ReturnCode), &SrbReturnCode); + + if (SrbReturnCode == 0x00) + { + SendStatus = NDIS_STATUS_SUCCESS; + } + else if (SrbReturnCode == 0x22) + { + // + // Check the frame status. + // + UCHAR FrameStatus; + UCHAR HighAc; + UCHAR LowAc; + + NdisReadRegisterUchar(&(ResponseSsb->ErrorFrameStatus), &FrameStatus); + HighAc = GET_FRAME_STATUS_HIGH_AC(FrameStatus); + LowAc = GET_FRAME_STATUS_LOW_AC(FrameStatus); + + if (HighAc != LowAc || + (HighAc != AC_NOT_RECOGNIZED)) + { + SendStatus = NDIS_STATUS_NOT_RECOGNIZED; + } + else + { + SendStatus = NDIS_STATUS_SUCCESS; + } + +#if DBG + if (IbmtokDbg) DbgPrint("IBMTOK: Send failed, code %x err %x\n", + SrbReturnCode, + FrameStatus); +#endif + + } + else + { + SendStatus = NDIS_STATUS_FAILURE; +#if DBG + if (IbmtokDbg) DbgPrint("IBMTOK: Send failed, code %x\n", + SrbReturnCode); +#endif + } + + NdisDprReleaseSpinLock(&(Adapter->Lock)); + + do + { + PNDIS_PACKET TransmitPacket; + PIBMTOK_RESERVED Reserved; + PIBMTOK_OPEN Open; + + CurrentCorrelator = (UCHAR)((CurrentCorrelator + 1) % + MAX_COMMAND_CORRELATOR); + + // + // Complete the transmit. + // + TransmitPacket = + FindPacketGivenCorrelator(Adapter, CurrentCorrelator); + + if (TransmitPacket == (PNDIS_PACKET)NULL) + { +#if DBG + if (IbmtokDbg) DbgPrint("IBMTOK: Missing %d to complete, %d to %d\n", + CurrentCorrelator, + Adapter->NextCorrelatorToComplete, + CorrelatorInSrb); +#endif + continue; + } + + RemovePacketFromCorrelatorArray(Adapter, TransmitPacket); + + Reserved = PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket); + + Open = + PIBMTOK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle); + + // + // If doing LOOPBACK, this should really be a check + // of ReadyToComplete etc. + // +#ifdef CHECK_DUP_SENDS + { + VOID IbmtokRemovePacketFromList(PIBMTOK_ADAPTER, PNDIS_PACKET); + IbmtokRemovePacketFromList(Adapter, TransmitPacket); + } +#endif + + if (SendStatus == NDIS_STATUS_SUCCESS) + { + Adapter->FramesTransmitted++; + } + else + { + Adapter->FrameTransmitErrors++; + } + + NdisCompleteSend( + Open->NdisBindingContext, + Reserved->Packet, + SendStatus); + + // + // Decrement the reference count for the open. + // +#if DBG + NdisDprAcquireSpinLock(&(Adapter->Lock)); + IF_LOG('C'); + NdisDprReleaseSpinLock(&(Adapter->Lock)); +#endif + NdisInterlockedAddUlong((PULONG)&Open->References, (UINT)-1, &Adapter->Lock); + + } while (CurrentCorrelator != CorrelatorInSrb); + + NdisDprAcquireSpinLock(&(Adapter->Lock)); + + Adapter->SendTimeout = FALSE; + + Adapter->NextCorrelatorToComplete = + (UCHAR)((CurrentCorrelator + 1) % MAX_COMMAND_CORRELATOR); + + // + // We know that SrbAvailable is FALSE... + // + IF_LOG('<'); + + SetupSrbCommand(Adapter); + } + else + { + // + // Nothing else should pend!! + // + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER, + 3, + handleSrbSsb, + IBMTOK_ERRMSG_INVALID_CMD, + (ULONG)TmpUchar); + +#if DBG + if (IbmtokDbg) DbgPrint("IBMTOK: Error! Got Cmd %x\n",TmpUchar); +#endif + } + + WRITE_ADAPTER_REGISTER( + Adapter, + ISRA_HIGH_SET, + ISRA_HIGH_SSB_FREE); + } + + if (Adapter->CardType != IBM_TOKEN_RING_PCMCIA) + { + GET_SRB_SSB_BITS(Adapter, &IsrpHigh); + } + else + { + // + // 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, + Temp & (~(ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE) ) ); + + // + // update arb_asb + // + IsrpHigh = (Adapter->IsrpBits) & (ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE); + Adapter->IsrpBits = (Adapter->IsrpBits) & (~(ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE)); + + // + // reenable interrupts on the card + // + WRITE_ADAPTER_REGISTER( + Adapter, + ISRP_LOW, + ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE); + } + } + + Adapter->HandleSrbRunning = FALSE; + + IF_LOG('H'); + + // + // This macro assumes it is called with the lock held, + // and releases it. + // + IBMTOK_DO_DEFERRED(Adapter); +} + +extern +VOID +IbmtokHandleArbAsb( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine is called by the DPC + and other routines within the driver that notice that + some deferred processing needs to be done. It's main + job is to call the interrupt processing code. + + NOTE: THIS ROUTINE IS CALLED WITH THE LOCK HELD!! AND RETURNS WITH + THE LOCK REALEASED!! + +Arguments: + + Adapter - A pointer to the adapter. + +Return Value: + + None. + +--*/ + +{ + UCHAR IsrpHigh; + + PARB_TRANSMIT_DATA_REQUEST TransmitDataArb; + + PARB_RECEIVED_DATA ReceivedDataArb; + + PNDIS_PACKET TransmitPacket; + + SRAM_PTR ReceiveBufferPointer; + + PRECEIVE_BUFFER ReceiveBuffer; + + UINT PacketLength, DummyBytesCopied; + + BOOLEAN FreedSrb; + + PIBMTOK_RESERVED Reserved; + + PUCHAR DhbAddress; + + UINT PacketSize, LookaheadSize; + + PUCHAR FrameData; + + ULONG HeaderLength; + + UCHAR TmpUchar; + + USHORT TmpUshort; + + PUCHAR LookaheadBuffer; + + UCHAR Temp; + + Adapter->References++; + + Adapter->HandleArbRunning = TRUE; + + IF_LOG('j'); + + if (Adapter->CardType != IBM_TOKEN_RING_PCMCIA) + { + GET_ARB_ASB_BITS(Adapter, &IsrpHigh); + } + else + { + // + // 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, + Temp & (~(ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE) ) ); + + // + // update arb_asb + // + IsrpHigh = (Adapter->IsrpBits) & (ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE); + Adapter->IsrpBits = (Adapter->IsrpBits) & (~(ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE)); + + // + // reenable interrupts on the card + // + WRITE_ADAPTER_REGISTER( + Adapter, + ISRP_LOW, + ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE); + } + + while (IsrpHigh & (ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE)) + { + if (IsrpHigh & ISRP_HIGH_ARB_COMMAND) + { + NdisReadRegisterUchar(&((PARB_GENERIC)Adapter->ArbAddress)->Command, &TmpUchar); + + switch (TmpUchar) + { + case ARB_CMD_DLC_STATUS: +#if DBG + if (IbmtokDbg) + { + NdisReadRegisterUshort( + &((PARB_DLC_STATUS)Adapter->ArbAddress)->Status, &TmpUshort); + DbgPrint("IBMTOK: DLC Status %x\n", + IBMSHORT_TO_USHORT(TmpUshort)); + } +#endif + + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_ARB_FREE); + + IF_LOG('#'); + + // + // If it is a counter overflow, we need to queue a + // DLC.STATISTICS command. + // + NdisReadRegisterUshort( + &((PARB_RING_STATUS_CHANGE)Adapter->ArbAddress)->NetworkStatus, + &TmpUshort); + + if (IBMSHORT_TO_USHORT(TmpUshort) & 0x0040 ) + { + // + // Build a pending operation. It will get run ASAP + // by ProcessSrbCommand. + // + PIBMTOK_PEND_DATA PendOp; + + if (IBMTOK_ALLOC_PHYS(&PendOp,sizeof(IBMTOK_PEND_DATA)) != + NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + handleSrbSsb, + IBMTOK_ERRMSG_ALLOC_MEM); + + break; + } + + PendOp->Next = NULL; + PendOp->RequestType = NdisRequestGeneric1; + PendOp->COMMAND.MAC.ReadLogPending = FALSE; + + if (Adapter->PendQueue == NULL) + { + Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp; + } + else + { + // + // Put this operation on the front, so it can + // correct the error quickly. + // + PendOp->Next = Adapter->PendQueue; + Adapter->PendQueue = PendOp; + } + + // + // It is now in the pend + // queue so we should start that up. + // + IbmtokProcessSrbRequests(Adapter); + } + + break; + + case ARB_CMD_RECEIVED_DATA: + +#if DBG + if (IbmtokDbg) + DbgPrint("IBMTOK: Received data\n"); +#endif + IF_LOG('r'); + + if (Adapter->Unplugged && !Adapter->UnpluggedResetInProgress) + { + // + // Do, nothing. This is most likely a stale interrupt. We + // wait until we get a ring status interrupt telling us that + // the cable is plugged in. + // + break; + } + + ReceivedDataArb = (PARB_RECEIVED_DATA)Adapter->ArbAddress; + + NdisReadRegisterUshort(&(ReceivedDataArb->ReceiveBuffer), &ReceiveBufferPointer); + + // + // Prepare for indication. + // + Adapter->IndicatedReceiveBuffer = ReceiveBufferPointer; + + ReceiveBuffer = (PRECEIVE_BUFFER) + ((PUCHAR)SRAM_PTR_TO_PVOID(Adapter, ReceiveBufferPointer) + 2); + + NdisReadRegisterUshort(&(ReceivedDataArb->FrameLength), &PacketSize); + + PacketSize = IBMSHORT_TO_USHORT(PacketSize); + + NdisReadRegisterUshort(&(ReceiveBuffer->BufferLength), &LookaheadSize); + + LookaheadSize = IBMSHORT_TO_USHORT(LookaheadSize); + + WRITE_ADAPTER_REGISTER( + Adapter, + ISRA_HIGH_SET, + ISRA_HIGH_ARB_FREE); + +#if DBG + if (IbmtokDbg) + DbgPrint("IBMTOK: indicate len %d, lookahead %d\n", PacketSize, LookaheadSize); +#endif + + // + // Calculate how big the header is for this + // packet. + // + FrameData = ReceiveBuffer->FrameData; + + NdisReadRegisterUchar(&FrameData[8], &TmpUchar); + + if (TmpUchar & 0x80) + { + // + // Source routing bit is on in source address. + // + NdisReadRegisterUchar(&FrameData[14], &TmpUchar); + HeaderLength = (TmpUchar & 0x1f) + 14; + } + else + { + HeaderLength = 14; + } + + Adapter->IndicatedHeaderLength = (USHORT)HeaderLength; + + Adapter->FramesReceived++; + + NdisDprReleaseSpinLock(&Adapter->Lock); + + // + // Call into the filter package to do the + // indication. + // + if (LookaheadSize < HeaderLength) + { + // + // Must at least have an address + // + if (LookaheadSize >= TR_LENGTH_OF_ADDRESS) + { + NdisCreateLookaheadBufferFromSharedMemory( + (PVOID)FrameData, + LookaheadSize, + &LookaheadBuffer); + + if (LookaheadBuffer != NULL) + { + // + // Runt Packet + // + TrFilterIndicateReceive( + Adapter->FilterDB, + (NDIS_HANDLE)ReceiveBuffer, // context + LookaheadBuffer, // header + LookaheadSize, // header length + NULL, // lookahead + 0, // lookahead length + 0); + + NdisDestroyLookaheadBufferFromSharedMemory(LookaheadBuffer); + } + } + } + else + { + NdisCreateLookaheadBufferFromSharedMemory( + (PVOID)FrameData, + LookaheadSize, + &LookaheadBuffer); + + if (LookaheadBuffer != NULL) + { + TrFilterIndicateReceive( + Adapter->FilterDB, + (NDIS_HANDLE)ReceiveBuffer, // context + LookaheadBuffer, // header + HeaderLength, // header length + LookaheadBuffer + HeaderLength, // lookahead + LookaheadSize - HeaderLength, // lookahead length + PacketSize - HeaderLength); + + NdisDestroyLookaheadBufferFromSharedMemory(LookaheadBuffer); + } + } + + TrFilterIndicateReceiveComplete( Adapter->FilterDB ); + + // + // Now worry about the ASB. + // + NdisDprAcquireSpinLock(&(Adapter->Lock)); + + // + // Set response in ASB, if possible, else queue the response + // + if (Adapter->AsbAvailable) + { + Adapter->AsbAvailable = FALSE; + + Adapter->UseNextAsbForReceive = FALSE; + + SetupReceivedDataAsb(Adapter, ReceiveBufferPointer); + WRITE_ADAPTER_REGISTER( + Adapter, + ISRA_HIGH_SET, + ISRA_HIGH_RESPONSE_IN_ASB); + + // + // LOOPBACK HERE!! + // + } + else + { +#if DBG + if (IbmtokDbg) DbgPrint("W_ASB R\n"); +#endif + if (Adapter->ReceiveWaitingForAsbEnd == (USHORT)(-1)) + { + Adapter->ReceiveWaitingForAsbList = ReceiveBufferPointer; + } + else + { + PVOID PEnd; + + PEnd = SRAM_PTR_TO_PVOID( + Adapter, + Adapter->ReceiveWaitingForAsbEnd); + + NdisWriteRegisterUshort(PEnd, ReceiveBufferPointer); + } + + Adapter->ReceiveWaitingForAsbEnd = ReceiveBufferPointer; + + if (!(Adapter->OutstandingAsbFreeRequest)) + { + Adapter->OutstandingAsbFreeRequest = TRUE; + + WRITE_ADAPTER_REGISTER( + Adapter, + ISRA_HIGH_SET, + ISRA_HIGH_ASB_FREE_REQUEST); + + IF_LOG('a'); + } + } + + break; + + case ARB_CMD_RING_STATUS_CHANGE: + { + USHORT RingStatus; + NDIS_STATUS NotifyStatus = 0; + + NdisReadRegisterUshort( + &((PARB_RING_STATUS_CHANGE)Adapter->ArbAddress)->NetworkStatus, + &RingStatus); + + RingStatus = IBMSHORT_TO_USHORT(RingStatus); +#if DBG + if (IbmtokDbg) + DbgPrint("IBMTOK: Ring Status %x\n", RingStatus); +#endif + + WRITE_ADAPTER_REGISTER( + Adapter, + ISRA_HIGH_SET, + ISRA_HIGH_ARB_FREE); + + // + // If it is a counter overflow, we need to queue a + // DIR.READ.LOG command. + // + if (RingStatus & 0x0080) + { + // + // Build a pending operation. It will get run ASAP + // by ProcessSrbCommand. + // + PIBMTOK_PEND_DATA PendOp; + + if (IBMTOK_ALLOC_PHYS(&PendOp,sizeof(IBMTOK_PEND_DATA)) != + NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + handleSrbSsb, + IBMTOK_ERRMSG_ALLOC_MEM); + + break; + } + + PendOp->Next = NULL; + PendOp->RequestType = NdisRequestGeneric1; + PendOp->COMMAND.MAC.ReadLogPending = TRUE; + + if (Adapter->PendQueue == NULL) + { + Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp; + + } + else + { + // + // Put this operation on the front, so it can + // correct the error quickly. + // + PendOp->Next = Adapter->PendQueue; + Adapter->PendQueue = PendOp; + } + + // + // It is now in the pend + // queue so we should start that up. + // Returns with lock released + // + IbmtokProcessSrbRequests(Adapter); + } + + if (RingStatus & 0x0020) + { + // + // Ring Recovery + // + NotifyStatus |= NDIS_RING_RING_RECOVERY; + } + + if (RingStatus & 0x0040) + { + // + // Single Station + // + NotifyStatus |= NDIS_RING_SINGLE_STATION; + } + + if (RingStatus & 0x0080) + { + // + // Counter Overflow + // + NotifyStatus |= NDIS_RING_COUNTER_OVERFLOW; + } + + if (RingStatus & 0x0100) + { + // + // Remove received + // + NotifyStatus |= NDIS_RING_REMOVE_RECEIVED; + } + + if (RingStatus & 0x0400) + { + // + // Auto-removal + // + NotifyStatus |= NDIS_RING_AUTO_REMOVAL_ERROR; + } + + if (RingStatus & 0x0800) + { + // + // Lobe wire fault + // + NotifyStatus |= NDIS_RING_LOBE_WIRE_FAULT; + } + + if (RingStatus & 0x1000) + { + // + // Transmit Beacon + // + NotifyStatus |= NDIS_RING_TRANSMIT_BEACON; + } + + if (RingStatus & 0x2000) + { + // + // Soft error + // + NotifyStatus |= NDIS_RING_SOFT_ERROR; + } + + if (RingStatus & 0x4000) + { + // + // Hard error + // + NotifyStatus |= NDIS_RING_HARD_ERROR; + } + + if (RingStatus & 0x8000) + { + // + // Signal loss + // + NotifyStatus |= NDIS_RING_SIGNAL_LOSS; + } + + if (NotifyStatus != 0) + { + PLIST_ENTRY CurrentLink; + PIBMTOK_OPEN TempOpen; + + // + // Indicate Status to all opens + // + CurrentLink = Adapter->OpenBindings.Flink; + + while (CurrentLink != &(Adapter->OpenBindings)){ + + TempOpen = CONTAINING_RECORD( + CurrentLink, + IBMTOK_OPEN, + OpenList); + + TempOpen->References++; + + NdisDprReleaseSpinLock(&Adapter->Lock); + + NdisIndicateStatus( + TempOpen->NdisBindingContext, + NDIS_STATUS_RING_STATUS, + (PVOID)&NotifyStatus, + sizeof(NotifyStatus)); + + NdisIndicateStatusComplete(TempOpen->NdisBindingContext); + + NdisDprAcquireSpinLock(&Adapter->Lock); + + CurrentLink = CurrentLink->Flink; + + TempOpen->References--; + } + + Adapter->LastNotifyStatus = NotifyStatus; + } + + // + // Handle a cable being unplugged + // + if ((RingStatus & 0x5000) == 0x5000) + { + // receive and transmit beacon + + // + // Ok, the cable has been unplugged. We now abort all + // outstanding sends, etc. + // + + Adapter->Unplugged = TRUE; + + IbmtokAbortPending(Adapter, NDIS_STATUS_DEVICE_FAILED); + + if ((RingStatus & 0x800) == 0x800) + { + Adapter->LobeWireFaultIndicated = TRUE; + } + } + else if ((RingStatus & 0x0020) && + !(RingStatus & 0x4000) && + (Adapter->Unplugged) && + (!Adapter->UnpluggedResetInProgress)) + { + // + // Reset the adapter to remove all stale information + // + Adapter->UnpluggedResetInProgress = TRUE; + + IbmtokSetupForReset(Adapter, NULL); + + IbmtokHandleDeferred(Adapter); + } + } + + break; + + case ARB_CMD_TRANSMIT_DATA_REQUEST: +#if DBG + if (IbmtokDbg) DbgPrint("IBMTOK: Transmit data\n"); +#endif + if (Adapter->Unplugged && !Adapter->UnpluggedResetInProgress) + { + // + // Do, nothing. This is most likely a stale interrupt. We + // wait until we get a ring status interrupt telling us that + // the cable is plugged in. + // + break; + } + + TransmitDataArb = + (PARB_TRANSMIT_DATA_REQUEST)Adapter->ArbAddress; + + // + // First see if we have to assign the command correlator. + // + NdisReadRegisterUchar(&(TransmitDataArb->CommandCorrelator), &TmpUchar); + + TransmitPacket = FindPacketGivenCorrelator(Adapter, TmpUchar); + + if (TransmitPacket == NULL) + { + BOOLEAN PacketRemoved; + + // + // Have to take the correlator out of the SRB + // ourselves. This means that the SRB must still + // be occupied by the request for this transmit. + // + ASSERT(!Adapter->SrbAvailable); + + FreedSrb = FALSE; + + // + // This call will remove the packet from the SRB. + // + TransmitPacket = + RemoveTransmitFromSrb(Adapter, &PacketRemoved); + + // + // This will be NULL if there was an error in + // the transmit command, but in that case why + // are we getting this ARB request?? Just exit. + // The WakeUpDpc will reset the card if it is hosed. + // + if ((TransmitPacket == (PNDIS_PACKET)NULL) || !PacketRemoved) + { + break; + } + } + else + { + FreedSrb = FALSE; + + Reserved = + PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket); + } + + NdisDprReleaseSpinLock(&(Adapter->Lock)); + + // + // Fill in the AC and FC bytes. + // + NdisReadRegisterUshort(&(TransmitDataArb->DhbPointer), &TmpUshort); + + DhbAddress = (PUCHAR)SRAM_PTR_TO_PVOID(Adapter,TmpUshort); + + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_ARB_FREE); + + + // + // Now copy the data down from TransmitPacket. + // + NdisQueryPacket( + TransmitPacket, + NULL, + NULL, + NULL, + &PacketLength); + + IbmtokCopyFromPacketToBuffer( + TransmitPacket, + 0, + PacketLength, + (PCHAR)DhbAddress, + &DummyBytesCopied); + + + // + // Now worry about the ASB. + // + NdisDprAcquireSpinLock(&(Adapter->Lock)); + + IF_LOG('c'); + + // + // Set response in ASB, if available, else queue response + // + if (Adapter->AsbAvailable) + { + Adapter->AsbAvailable = FALSE; + + Adapter->UseNextAsbForReceive = TRUE; + + SetupTransmitStatusAsb(Adapter, TransmitPacket); + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_RESPONSE_IN_ASB); + + // + // LOOPBACK HERE!! + // + } + else + { +#if DBG + if (IbmtokDbg) DbgPrint("W_ASB T\n"); +#endif + + PutPacketOnWaitingForAsb(Adapter, TransmitPacket); + + if (!(Adapter->OutstandingAsbFreeRequest)) + { + Adapter->OutstandingAsbFreeRequest = TRUE; + + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_ASB_FREE_REQUEST); + + IF_LOG('a'); + } + + // + // FINAL RETURNCODE CHECK HERE! + // + } + + // + // If we freed up the SRB, queue the next command + // if there is one. + // Returns with lock released + // + if (FreedSrb) + { + IbmtokProcessSrbRequests(Adapter); + } + + break; + + default: + + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_ARB_FREE); + break; + + } + } + + if (IsrpHigh & ISRP_HIGH_ASB_FREE) + { + BOOLEAN ReceiveNeedsAsb = FALSE; + BOOLEAN TransmitNeedsAsb = FALSE; + + // + // Check whether we have stuff to do. + // + IF_LOG('A'); + + if (Adapter->Unplugged && !Adapter->UnpluggedResetInProgress) + { + // + // Do, nothing. This is most likely a stale interrupt. We + // wait until we get a ring status interrupt telling us that + // the cable is plugged in. + // + break; + } + + ASSERT(Adapter->AsbAvailable == FALSE); + + ASSERT(Adapter->OutstandingAsbFreeRequest == TRUE); + + if (Adapter->ReceiveWaitingForAsbList != (USHORT)-1) + { + ReceiveNeedsAsb = TRUE; + } + + if (Adapter->FirstWaitingForAsb != NULL) + { + TransmitNeedsAsb = TRUE; + } + + if (ReceiveNeedsAsb && (!TransmitNeedsAsb || Adapter->UseNextAsbForReceive)) + { + + SRAM_PTR ReceiveBufferPointer; + PVOID PFront; + +#if DBG + if (IbmtokDbg) DbgPrint("ASB R\n"); +#endif + IF_LOG('R'); + + // + // Save ReceiveWaitingForAsb so we can release + // the spinlock. + // + ReceiveBufferPointer = Adapter->ReceiveWaitingForAsbList; + + if (Adapter->ReceiveWaitingForAsbList == Adapter->ReceiveWaitingForAsbEnd) + { + Adapter->ReceiveWaitingForAsbList = (USHORT)-1; + + Adapter->ReceiveWaitingForAsbEnd = (USHORT)-1; + } + else + { + PFront = SRAM_PTR_TO_PVOID(Adapter,ReceiveBufferPointer); + + NdisReadRegisterUshort( + ((PUSHORT)PFront), + &(Adapter->ReceiveWaitingForAsbList)); + } + + Adapter->AsbAvailable = FALSE; + + Adapter->UseNextAsbForReceive = FALSE; + + // + // Fill in the ASB and submit it. + // + SetupReceivedDataAsb(Adapter, ReceiveBufferPointer); + + if (TransmitNeedsAsb) + { + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_RESPONSE_IN_ASB | ISRA_HIGH_ASB_FREE_REQUEST); + } + else + { + Adapter->OutstandingAsbFreeRequest = FALSE; + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_RESPONSE_IN_ASB); + } + } + else if (TransmitNeedsAsb) + { + PNDIS_PACKET AsbPacket = Adapter->FirstWaitingForAsb; + PIBMTOK_RESERVED Reserved = PIBMTOK_RESERVED_FROM_PACKET(AsbPacket); + +#if DBG + if (IbmtokDbg) DbgPrint("ASB T\n"); +#endif + IF_LOG('T'); + + // + // Take the packet off of WaitingForAsb; + // + Adapter->FirstWaitingForAsb = Reserved->Next; + + Adapter->AsbAvailable = FALSE; + + Adapter->UseNextAsbForReceive = TRUE; + + // + // Now fill in the ASB and fire it off. + // + SetupTransmitStatusAsb(Adapter, AsbPacket); + + if (ReceiveNeedsAsb || (Adapter->FirstWaitingForAsb != NULL)) + { + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_RESPONSE_IN_ASB | ISRA_HIGH_ASB_FREE_REQUEST); + } + else + { + Adapter->OutstandingAsbFreeRequest = FALSE; + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_RESPONSE_IN_ASB); + } + + // + // LOOPBACK HERE!! + // + } + else + { + +#if DBG + if (IbmtokDbg) DbgPrint("ASB -\n"); +#endif + + Adapter->AsbAvailable = TRUE; + } + } + + if (Adapter->CardType != IBM_TOKEN_RING_PCMCIA) + { + GET_ARB_ASB_BITS(Adapter, &IsrpHigh); + } + else + { + // + // 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, + Temp & (~(ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE) ) ); + + // + // update arb_asb + // + IsrpHigh = (Adapter->IsrpBits) & (ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE); + Adapter->IsrpBits = (Adapter->IsrpBits) & (~(ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE)); + + // + // reenable interrupts on the card + // + WRITE_ADAPTER_REGISTER(Adapter, ISRP_LOW, + ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE); + } + } + + Adapter->HandleArbRunning = FALSE; + + IF_LOG('J'); + + // + // This macro assumes it is called with the lock held, + // and releases it. + // + IBMTOK_DO_DEFERRED(Adapter); +} + +STATIC +VOID +CleanupResetFailure( + IN PIBMTOK_ADAPTER Adapter, + PNDIS_STATUS IndicateStatus, + IN ULONG FailureCode, + IN ULONG ResetStage + ) + +/*++ + +Routine Description: + + Clean up if a reset fails partway through. Called + from HandleResetStaging. + + Called with the lock held and returns with it held. + +Arguments: + + Adapter - The adapter that the reset is for. + + IndicateStatus - Status to indicate to the protocols, or NULL. + + FailureCode - A code to include in the error log. + + ResetStage - The stage of the reset where the failure occured. + +Return Value: + + None. + +--*/ + +{ + + PLIST_ENTRY CurrentLink; + PIBMTOK_OPEN TempOpen; + + if (!Adapter->UnpluggedResetInProgress) + { + // + // signal failure.... + // + Adapter->CurrentRingState = NdisRingStateRingFailure; + + // + // Indicate Status to all opens + // + CurrentLink = Adapter->OpenBindings.Flink; + + while (CurrentLink != &(Adapter->OpenBindings)) + { + TempOpen = CONTAINING_RECORD(CurrentLink, IBMTOK_OPEN, OpenList); + + TempOpen->References++; + + NdisReleaseSpinLock(&Adapter->Lock); + + if (IndicateStatus) + { + NdisIndicateStatus(TempOpen->NdisBindingContext, + NDIS_STATUS_CLOSED, + IndicateStatus, + sizeof(NDIS_STATUS)); + } + else + { + NdisIndicateStatus(TempOpen->NdisBindingContext, + NDIS_STATUS_CLOSED, + NULL, + 0); + } + + NdisIndicateStatusComplete(TempOpen->NdisBindingContext); + + NdisAcquireSpinLock(&Adapter->Lock); + + CurrentLink = CurrentLink->Flink; + + TempOpen->References--; + } + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 4, + handleResetStaging, + IBMTOK_ERRMSG_BRINGUP_FAILURE, + FailureCode, + ResetStage); + } + else + { + // + // Set this to false, we will try again later. + // + Adapter->LobeWireFaultIndicated = TRUE; + Adapter->UnpluggedResetInProgress = FALSE; + } + + // + // Set Abort + // + Adapter->CurrentResetStage = 4; + + SetResetVariables(Adapter); + + Adapter->OpenInProgress = FALSE; + Adapter->NotAcceptingRequests = TRUE; + + Adapter->ResetInProgress = FALSE; + Adapter->ResetInterruptAllowed = FALSE; + Adapter->ResetInterruptHasArrived = FALSE; + + if (Adapter->ResettingOpen != NULL) + { + PIBMTOK_OPEN Open = Adapter->ResettingOpen; + + // + // Decrement the reference count that was incremented + // in SetupForReset. + // + Open->References--; + + NdisReleaseSpinLock(&Adapter->Lock); + + NdisCompleteReset(Open->NdisBindingContext, NDIS_STATUS_FAILURE); + + NdisAcquireSpinLock(&Adapter->Lock); + } +} + +STATIC +VOID +HandleResetStaging( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + Handles the next stage of the transmit interrupt, + knowing that an SRB interrupt just came through. + + Called with the lock held and returns with it held. + +Arguments: + + Adapter - The adapter that the reset is for. + +Return Value: + + None. + +--*/ + +{ + USHORT TmpUshort; + UCHAR TmpUchar; + + switch (Adapter->CurrentResetStage) + { + case 1: + { + // + // The adapter just finished being reset. + // + USHORT WrbOffset; + PSRB_BRING_UP_RESULT BringUpSrb; + PSRB_OPEN_ADAPTER OpenSrb; + UCHAR Value1, Value2; + +#if DBG +if (IbmtokDbg) DbgPrint("IBMTOK: RESET done\n"); +#endif + + READ_ADAPTER_REGISTER(Adapter, WRBR_LOW, &Value1); + READ_ADAPTER_REGISTER(Adapter, WRBR_HIGH, &Value2); + + WrbOffset = (USHORT)(((USHORT)Value1) << 8) + (USHORT)Value2; + + Adapter->InitialWrbOffset = WrbOffset; + + BringUpSrb = (PSRB_BRING_UP_RESULT)(Adapter->SharedRam + WrbOffset); + + NdisReadRegisterUshort(&(BringUpSrb->ReturnCode), &TmpUshort); + + if (TmpUshort != 0x0000) + { + CleanupResetFailure (Adapter, NULL, TmpUshort, 1); + break; + } + + // + // Now set up the open SRB request. + // + OpenSrb = (PSRB_OPEN_ADAPTER) + (Adapter->SharedRam + Adapter->InitialWrbOffset); + + IBMTOK_ZERO_MAPPED_MEMORY(OpenSrb, sizeof(SRB_OPEN_ADAPTER)); + + NdisWriteRegisterUchar(&(OpenSrb->Command), SRB_CMD_OPEN_ADAPTER); + NdisWriteRegisterUshort(&(OpenSrb->OpenOptions), + (USHORT)(OPEN_CONTENDER | + (Adapter->EarlyTokenRelease ? + 0 : + OPEN_MODIFIED_TOKEN_RELEASE))); + + NdisMoveToMappedMemory((PCHAR)OpenSrb->NodeAddress, + Adapter->NetworkAddress, + TR_LENGTH_OF_ADDRESS); + + WRITE_IBMSHORT(OpenSrb->ReceiveBufferNum, + Adapter->NumberOfReceiveBuffers); + WRITE_IBMSHORT(OpenSrb->ReceiveBufferLen, + Adapter->ReceiveBufferLength); + + WRITE_IBMSHORT(OpenSrb->TransmitBufferLen, + Adapter->TransmitBufferLength); + + NdisWriteRegisterUchar(&(OpenSrb->TransmitBufferNum), + (UCHAR)Adapter->NumberOfTransmitBuffers); + + Adapter->CurrentResetStage = 2; + + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_COMMAND_IN_SRB | ISRA_HIGH_SRB_FREE_REQUEST); + + IF_LOG('1'); + + break; + } + + case 2: + { + // + // Handle the result of the DIR.OPEN.ADAPTER command. + // + PSRB_OPEN_RESPONSE OpenResponseSrb; + +#if DBG +if (IbmtokDbg) DbgPrint("IBMTOK: OPEN done\n"); +#endif + + OpenResponseSrb = (PSRB_OPEN_RESPONSE) + (Adapter->SharedRam + Adapter->InitialWrbOffset); + + NdisReadRegisterUchar(&(OpenResponseSrb->ReturnCode), &TmpUchar); + + if (TmpUchar != 0) + { + NDIS_STATUS IndicateStatus; + + NdisReadRegisterUshort(&(OpenResponseSrb->ErrorCode), + &(Adapter->OpenErrorCode)); + Adapter->OpenErrorCode = IBMSHORT_TO_USHORT(Adapter->OpenErrorCode); + IndicateStatus = + NDIS_STATUS_TOKEN_RING_OPEN_ERROR | + (NDIS_STATUS)(Adapter->OpenErrorCode); + + CleanupResetFailure (Adapter, &IndicateStatus, Adapter->OpenErrorCode, 2); + break; + } + + IF_LOG('2'); + +#if DBG + NdisReadRegisterUchar(&(OpenResponseSrb->ReturnCode),&TmpUchar); + if (IbmtokDbg) DbgPrint("IBMTOK: RESET OPEN, Return code = %x, at %lx\n", + TmpUchar, + OpenResponseSrb); +#endif + + NdisReadRegisterUshort(&(OpenResponseSrb->SrbPointer), &TmpUshort); + Adapter->SrbAddress = SRAM_PTR_TO_PVOID(Adapter,TmpUshort); + + NdisReadRegisterUshort(&(OpenResponseSrb->SsbPointer), &TmpUshort); + Adapter->SsbAddress = SRAM_PTR_TO_PVOID(Adapter,TmpUshort); + + NdisReadRegisterUshort(&(OpenResponseSrb->ArbPointer), &TmpUshort); + Adapter->ArbAddress = SRAM_PTR_TO_PVOID(Adapter,TmpUshort); + + NdisReadRegisterUshort(&(OpenResponseSrb->AsbPointer), &TmpUshort); + Adapter->AsbAddress = SRAM_PTR_TO_PVOID(Adapter,TmpUshort); + +#if DBG +if (IbmtokDbg) +{ + USHORT TmpUshort1; + USHORT TmpUshort2; + USHORT TmpUshort3; + USHORT TmpUshort4; + NdisReadRegisterUshort(&(OpenResponseSrb->SrbPointer), &TmpUshort1); + NdisReadRegisterUshort(&(OpenResponseSrb->SsbPointer), &TmpUshort2); + NdisReadRegisterUshort(&(OpenResponseSrb->ArbPointer), &TmpUshort3); + NdisReadRegisterUshort(&(OpenResponseSrb->AsbPointer), &TmpUshort4); + DbgPrint("IBMTOK: Offsets: SRB %x SSB %x ARB %x ASB %x\n", + IBMSHORT_TO_USHORT(TmpUshort1), + IBMSHORT_TO_USHORT(TmpUshort2), + IBMSHORT_TO_USHORT(TmpUshort3), + IBMSHORT_TO_USHORT(TmpUshort4)); +} +#endif + + // + // Now queue a SET.FUNCT.ADDRESS command if needed. + // + Adapter->CurrentCardFunctional = (TR_FUNCTIONAL_ADDRESS)0; + + if (SetAdapterFunctionalAddress(Adapter) == NDIS_STATUS_SUCCESS) + { + // + // This means that the command did not have to be + // queued, so we are done with this step. + // + if (SetAdapterGroupAddress(Adapter) == NDIS_STATUS_SUCCESS) + { + // + // This one did not pend either, we are done. + // + IbmtokFinishAdapterReset(Adapter); + } + else + { + Adapter->CurrentResetStage = 4; + + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_COMMAND_IN_SRB | ISRA_HIGH_SRB_FREE_REQUEST); + } + } + else + { + Adapter->CurrentResetStage = 3; + + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_COMMAND_IN_SRB | ISRA_HIGH_SRB_FREE_REQUEST); + } + + break; + } + + case 3: + { + // + // The SET.FUNCT.ADDRESS command finished. + // + PSRB_GENERIC GenericSrb = (PSRB_GENERIC)Adapter->SrbAddress; + UCHAR ReturnCode; + + NdisReadRegisterUchar(&(GenericSrb->ReturnCode), &ReturnCode); + + IF_LOG('3'); + +#if DBG +if (IbmtokDbg) DbgPrint("IBMTOK: SET FUNCT done\n"); +#endif + if (ReturnCode == 0x00) + { + if (SetAdapterGroupAddress(Adapter) == NDIS_STATUS_SUCCESS) + { + // + // This one did not pend, the dishes are done. + // + IbmtokFinishAdapterReset(Adapter); + } + else + { + Adapter->CurrentResetStage = 4; + + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_COMMAND_IN_SRB | ISRA_HIGH_SRB_FREE_REQUEST); + } + } + else if (ReturnCode != 0xfe) + { + CleanupResetFailure (Adapter, NULL, (ULONG)ReturnCode, 3); + } + + break; + } + + case 4: + { + // + // The SET.GROUP.ADDRESS command finished. + // + PSRB_GENERIC GenericSrb = (PSRB_GENERIC)Adapter->SrbAddress; + UCHAR ReturnCode; + + NdisReadRegisterUchar(&(GenericSrb->ReturnCode), &ReturnCode); + + IF_LOG('4'); + +#if DBG +if (IbmtokDbg) DbgPrint("IBMTOK: SET GROUP done\n"); +#endif + if (ReturnCode == 0x00) + { + IbmtokFinishAdapterReset(Adapter); + } + else if (ReturnCode != 0xfe) + { + CleanupResetFailure (Adapter, NULL, (ULONG)ReturnCode, 4); + } + + break; + } + } +} + +STATIC +PNDIS_PACKET +RemoveTransmitFromSrb( + IN PIBMTOK_ADAPTER Adapter, + OUT PBOOLEAN PacketRemoved + ) + +/*++ + +Routine Description: + + Cleans a transmit out of the SRB if one was there. + + NOTE : Should be called with the spinlock held!!! + +Arguments: + + Adapter - The adapter that this packet is coming through. + + PacketRemoved - TRUE if the packet was removed from the SRB. + +Return Value: + + The packet removed. + +--*/ + +{ + PNDIS_PACKET TransmitPacket; + PIBMTOK_RESERVED Reserved; + UCHAR TmpUchar; + PSRB_TRANSMIT_DIR_FRAME TransmitSrb = + (PSRB_TRANSMIT_DIR_FRAME)Adapter->SrbAddress; + + + NdisReadRegisterUchar(&(TransmitSrb->ReturnCode), &TmpUchar); + + if (TmpUchar == 0xfe) + { + // + // The TRANSMIT command was just put in the SRB, and + // the adapter has not yet had time to process it. + // We return now before setting SrbAvailable to TRUE, + // so the command is left to be processed. + // + // NOTE: If this happens on a call from inside the + // ARB_TRANSMIT_DATA interrupt handler, we will fail + // on an assertion when we return NULL. + // + *PacketRemoved = FALSE; + + return (PNDIS_PACKET)NULL; + } + + // + // if there was a packet in there, put it in + // the correlator array. + // + TransmitPacket = Adapter->TransmittingPacket; + + Adapter->TransmittingPacket = (PNDIS_PACKET)NULL; + + if (TransmitPacket == NULL) + { + *PacketRemoved = FALSE; + + return(NULL); + } + + // + // This will be TRUE whatever happens next. + // + *PacketRemoved = TRUE; + + Reserved = PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket); + + // + // Check that the return code is OK. + // + if (TmpUchar != 0xff) + { + PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle); + // + // Fail the transmit. + // + + // + // If doing LOOPBACK, this should really be a check + // of ReadyToComplete etc. + // +#if DBG +if (IbmtokDbg) { + UCHAR TmpUchar1, TmpUchar2; + NdisReadRegisterUchar(&TransmitSrb->ReturnCode, &TmpUchar1); + NdisReadRegisterUchar(&TransmitSrb->Command, &TmpUchar2); + DbgPrint("IBMTOK: Transmit failed in SRB: %x for %x\n", TmpUchar1, TmpUchar2); +} +#endif + +#ifdef CHECK_DUP_SENDS + { + VOID IbmtokRemovePacketFromList(PIBMTOK_ADAPTER, PNDIS_PACKET); + IbmtokRemovePacketFromList(Adapter, TransmitPacket); + } +#endif + + Adapter->FrameTransmitErrors++; + + NdisReleaseSpinLock(&(Adapter->Lock)); + + NdisCompleteSend(Open->NdisBindingContext, Reserved->Packet, NDIS_STATUS_FAILURE); + + NdisAcquireSpinLock(&(Adapter->Lock)); + + Adapter->SendTimeout = FALSE; + + // + // Decrement the reference count for the open. + // + Open->References--; + + // + // This will cause an assertion failure if we were + // called from the ARB_TRANSMIT_DATA handler. + // + return (PNDIS_PACKET)NULL; + } + + // + // Put the packet in the correlator array. + // + Reserved->CorrelatorAssigned = TRUE; + NdisReadRegisterUchar(&(TransmitSrb->CommandCorrelator), &(Reserved->CommandCorrelator)); + + PutPacketInCorrelatorArray(Adapter, TransmitPacket); + + return TransmitPacket; +} + +VOID +SetupSrbCommand( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + Fills in the SRB with the next request. It first checks + if there is a pended request outstanding, then + handles any queued transmits. + + Called with the spinlock held. + + NOTE: Should be called with Adapter->SrbAvailable == FALSE. + +Arguments: + + Adapter - The Adapter to process interrupts for. + +Return Value: + + None. + +--*/ + +{ + if (Adapter->PendQueue != NULL) + { + // + // This will copy the appropriate info out of the + // pend queue. + // + if (StartPendQueueOp(Adapter) == NDIS_STATUS_PENDING) + { + // + // Indicate the SRB command. + // + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_COMMAND_IN_SRB); + + return; + } + } + + // + // If we reach here, the pend queue was empty or + // else StartPendQueueOp drained the entire queue + // without an operation needing the SRB. + // + if (Adapter->FirstTransmit != NULL) + { + // + // Remove the packet from the queue. + // + PNDIS_PACKET TransmitPacket = Adapter->FirstTransmit; + + PIBMTOK_RESERVED Reserved = + PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket); + + Adapter->FirstTransmit = Reserved->Next; + + Adapter->TransmittingPacket = TransmitPacket; + + // + // set up the send - this sets the packet equal + // to Adapter->TransmittingPacket; + // + SetupTransmitFrameSrb(Adapter, TransmitPacket); + + // + // Indicate the SRB command. + // + + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_COMMAND_IN_SRB); + } + else + { + Adapter->SrbAvailable = TRUE; + } +} + +extern +VOID +IbmtokForceAdapterInterrupt( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This forces an adapter interrupt by queueing an + INTERRUPT SRB. + + This is called with the spinlock held, and also + Adapter->SrbAvailable must be TRUE. + +Arguments: + + Adapter - The Adapter to force the interrupt on. + +Return Value: + + None. + +--*/ + +{ + + PSRB_INTERRUPT InterruptSrb = + (PSRB_INTERRUPT)Adapter->SrbAddress; + + ASSERT(Adapter->SrbAvailable); + + Adapter->SrbAvailable = FALSE; + + NdisWriteRegisterUchar(&(InterruptSrb->Command), SRB_CMD_INTERRUPT); + NdisWriteRegisterUchar(&(InterruptSrb->ReturnCode), 0xfe); + + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_COMMAND_IN_SRB); + + IF_LOG('O'); + +} + +STATIC +VOID +SetupTransmitFrameSrb( + IN PIBMTOK_ADAPTER Adapter, + IN PNDIS_PACKET Packet + ) + +/*++ + +Routine Description: + + This routine sets up the SRB for a TRANSMIT.DIR.FRAME. + +Arguments: + + Adapter - The adapter that this packet is coming through. + + Packet - The packet that is being sent. + +Return Value: + + None. + +--*/ + +{ + PSRB_TRANSMIT_DIR_FRAME TransmitSrb = + (PSRB_TRANSMIT_DIR_FRAME)Adapter->SrbAddress; + + UNREFERENCED_PARAMETER(Packet); + + NdisWriteRegisterUchar(&(TransmitSrb->Command), SRB_CMD_TRANSMIT_DIR_FRAME); + NdisWriteRegisterUchar(&(TransmitSrb->CommandCorrelator), 0x00); + NdisWriteRegisterUchar(&(TransmitSrb->ReturnCode), 0xfe); // will change to 0xff or error + NdisWriteRegisterUshort(&(TransmitSrb->StationId), USHORT_TO_IBMSHORT(0x00)); + + IF_LOG('x'); +} + +STATIC +VOID +SetupTransmitStatusAsb( + IN PIBMTOK_ADAPTER Adapter, + IN PNDIS_PACKET Packet + ) + +/*++ + +Routine Description: + + This routine sets up the ASB for a response from + a TRANSMIT.DATA.REQUEST. + +Arguments: + + Adapter - The adapter that this packet is coming through. + + Packet - The packet that has been copied down. + +Return Value: + + None. + +--*/ + +{ + + PASB_TRANSMIT_DATA_STATUS TransmitDataAsb; + UINT PacketLength; + PIBMTOK_RESERVED Reserved = PIBMTOK_RESERVED_FROM_PACKET(Packet); + + NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength); + + TransmitDataAsb = (PASB_TRANSMIT_DATA_STATUS) + Adapter->AsbAddress; + + NdisWriteRegisterUchar(&(TransmitDataAsb->Command), SRB_CMD_TRANSMIT_DIR_FRAME); + NdisWriteRegisterUchar(&(TransmitDataAsb->CommandCorrelator), + Reserved->CommandCorrelator); + NdisWriteRegisterUchar(&(TransmitDataAsb->ReturnCode), 0x00); + NdisWriteRegisterUshort(&(TransmitDataAsb->FrameLength), + USHORT_TO_IBMSHORT(PacketLength)); + + IF_LOG('X'); + +} + +STATIC +VOID +SetupAdapterStatisticsSrb( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine sets up the SRB for a DLC.STATISTICS. + +Arguments: + + Adapter - A pointer to the adapter. + +Return Value: + + None. + +--*/ +{ + PSRB_DLC_STATS StatsSrb = (PSRB_DLC_STATS)(Adapter->SrbAddress); + + NdisWriteRegisterUchar(&(StatsSrb->Command), SRB_CMD_DLC_STATISTICS); + NdisWriteRegisterUshort(&(StatsSrb->StationId), USHORT_TO_IBMSHORT(0x00)); + NdisWriteRegisterUchar((PUCHAR)(&(StatsSrb->ReturnCode)), 0x80); // Resets counters + +} + +STATIC +VOID +GetAdapterStatisticsFromSrb( + PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine reads the statistics after a DLC.STATISTICS has completed + and stores the results in the adapter structure. + +Arguments: + + Adapter - A pointer to the adapter. + +Return Value: + + None. + +--*/ + +{ + PSRB_DLC_STATS StatsSrb = (PSRB_DLC_STATS)(Adapter->SrbAddress); + PDLC_COUNTERS Counters; + USHORT TmpUshort; + UCHAR TmpUchar; + + NdisReadRegisterUshort(&StatsSrb->CountersOffset, &TmpUshort); + Counters = (PDLC_COUNTERS) (((PUCHAR)(Adapter->SrbAddress)) + + IBMSHORT_TO_USHORT(TmpUshort)); + + NdisReadRegisterUshort(&Counters->TransmitCount, &TmpUshort); + Adapter->FramesTransmitted += IBMSHORT_TO_USHORT(TmpUshort); + NdisReadRegisterUshort(&Counters->ReceiveCount, &TmpUshort); + Adapter->FramesReceived += IBMSHORT_TO_USHORT(TmpUshort); + NdisReadRegisterUchar(&Counters->TransmitErrors, &TmpUchar); + Adapter->FrameTransmitErrors += TmpUchar; + NdisReadRegisterUchar(&Counters->ReceiveErrors, &TmpUchar); + Adapter->FrameReceiveErrors += TmpUchar; + +} + +STATIC +VOID +GetAdapterErrorsFromSrb( + PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine reads the statistics after a DIR.READ.LOG has completed + and stores the results in the adapter structure. + +Arguments: + + Adapter - A pointer to the adapter. + +Return Value: + + None. + +--*/ + +{ + PSRB_READ_LOG ReadLogSrb = (PSRB_READ_LOG)(Adapter->SrbAddress); + ULONG TmpUchar; + + NdisReadRegisterUchar(&ReadLogSrb->LineErrors, &TmpUchar); + Adapter->LineErrors += TmpUchar; + NdisReadRegisterUchar(&ReadLogSrb->InternalErrors, &TmpUchar); + Adapter->InternalErrors += TmpUchar; + NdisReadRegisterUchar(&ReadLogSrb->BurstErrors, &TmpUchar); + Adapter->BurstErrors += TmpUchar; + NdisReadRegisterUchar(&ReadLogSrb->AcErrors, &TmpUchar); + Adapter->AcErrors += TmpUchar; + NdisReadRegisterUchar(&ReadLogSrb->AbortDelimeters, &TmpUchar); + Adapter->AbortDelimeters += TmpUchar; + NdisReadRegisterUchar(&ReadLogSrb->LostFrames, &TmpUchar); + Adapter->LostFrames += TmpUchar; + NdisReadRegisterUchar(&ReadLogSrb->ReceiveCongestionCount, &TmpUchar); + Adapter->ReceiveCongestionCount += TmpUchar; + NdisReadRegisterUchar(&ReadLogSrb->FrameCopiedErrors, &TmpUchar); + Adapter->FrameCopiedErrors += TmpUchar; + NdisReadRegisterUchar(&ReadLogSrb->FrequencyErrors, &TmpUchar); + Adapter->FrequencyErrors += TmpUchar; + NdisReadRegisterUchar(&ReadLogSrb->TokenErrors, &TmpUchar); + Adapter->TokenErrors += TmpUchar; +} + +STATIC +VOID +SetupAdapterErrorsSrb( + PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine sets up the SRB for a DIR.READ.LOG command. + +Arguments: + + Adapter - A pointer to the adapter. + +Return Value: + + None. + +--*/ +{ + PSRB_READ_LOG ReadLogSrb = (PSRB_READ_LOG)(Adapter->SrbAddress); + + NdisWriteRegisterUchar(&(ReadLogSrb->Command), SRB_CMD_READ_LOG); +} + +STATIC +NDIS_STATUS +StartPendQueueOp( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine goes through the pending queue until it + is empty or it finds a request that requires an SRB + command and hence pends. + + NOTE: This routine is called with the lock held and + returns with it held. + +Arguments: + + Adapter - The adapter that the queue should be checked for. + +Return Value: + + NDIS_STATUS_SUCCESS - If the queue was drained completely. + NDIS_STATUS_PENDING - If a request required the SRB. + +--*/ + +{ + // + // Holds the operation on the head of the queue + // (we know it is not empty). + // + PIBMTOK_PEND_DATA PendOp; + + // + // Holds status temporarily. + // + NDIS_STATUS RequestStatus; + + while (Adapter->PendQueue != NULL) + { + // + // First take the head operation off the queue. + // + PendOp = Adapter->PendQueue; + + Adapter->PendQueue = Adapter->PendQueue->Next; + + if (Adapter->PendQueue == NULL) + { + // + // We have just emptied the list. + // + Adapter->EndOfPendQueue = NULL; + } + + if (PendOp->RequestType == NdisRequestGeneric1) + { + // + // The pended operation is a result of the card having + // a counter overflow, and now we need to send the command. + // + if (PendOp->COMMAND.MAC.ReadLogPending) + { + // + // A DIR.READ.LOG command is needed. + // + SetupAdapterErrorsSrb(Adapter); + } + else + { + // + // A DLC.STATISTICS command is needed. + // + SetupAdapterStatisticsSrb(Adapter); + } + + // + // Issue adapter command. + // + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_COMMAND_IN_SRB); + + RequestStatus = NDIS_STATUS_PENDING; + } + else + { + switch (PendOp->RequestType) + { + case NdisRequestSetInformation: + + // + // It's a set filter or set address command. + // + if ((PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp))->DATA.SET_INFORMATION.Oid == + OID_GEN_CURRENT_PACKET_FILTER) + { + // + // It's a set filter command. + // + Adapter->OldPacketFilter = Adapter->CurrentPacketFilter; + + Adapter->CurrentPacketFilter = + PendOp->COMMAND.NDIS.SET_FILTER.NewFilterValue; + + RequestStatus = SetAdapterFunctionalAddress(Adapter); + } + else + { + // + // It's a set address command. + // +#if DBG + if (IbmtokDbg) + { + DbgPrint("IBMTOK: Starting Command\n"); + } +#endif + + if ((PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp))->DATA.SET_INFORMATION.Oid == + OID_802_5_CURRENT_FUNCTIONAL) + { + Adapter->CurrentFunctionalAddress = + PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue; + + RequestStatus = SetAdapterFunctionalAddress(Adapter); + } + else + { + Adapter->CurrentGroupAddress = + PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue; + + RequestStatus = SetAdapterGroupAddress(Adapter); + } + } + + break; + + case NdisRequestClose: + + // + // It's a set filter command. + // + Adapter->OldPacketFilter = Adapter->CurrentPacketFilter; + + Adapter->CurrentPacketFilter = + PendOp->COMMAND.NDIS.CLOSE.NewFilterValue; + + RequestStatus = SetAdapterFunctionalAddress(Adapter); + + break; + + case NdisRequestGeneric2: + + // + // It's a set address command. + // + Adapter->CurrentFunctionalAddress = + PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue; + + + RequestStatus = SetAdapterFunctionalAddress(Adapter); + + break; + + + case NdisRequestGeneric3: + + // + // It's a set address command. + // + Adapter->CurrentGroupAddress = + PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue; + + + RequestStatus = SetAdapterGroupAddress(Adapter); + + break; + + + case NdisRequestQueryStatistics: + + // + // We know it's a request for statistics. + // + RequestStatus = NDIS_STATUS_PENDING; + + SetupAdapterErrorsSrb(Adapter); + + PendOp->COMMAND.NDIS.STATISTICS.ReadLogPending = TRUE; + + // + // Issue adapter command. + // + WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, + ISRA_HIGH_COMMAND_IN_SRB); + + break; + + default: + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 3, + IBMTOK_ERRMSG_BAD_OP, + 1, + PendOp->RequestType); + } + } + + if (RequestStatus == NDIS_STATUS_PENDING) + { + // + // Set this up for when the request completes. + // + Adapter->PendData = PendOp; + + return NDIS_STATUS_PENDING; + } + else if (RequestStatus == NDIS_STATUS_SUCCESS) + { + PIBMTOK_OPEN TmpOpen; + + switch (PendOp->RequestType) + { + case NdisRequestSetInformation: + + // + // Complete the request. + // + TmpOpen = PendOp->COMMAND.NDIS.SET_FILTER.Open; + + NdisReleaseSpinLock(&(Adapter->Lock)); + + NdisCompleteRequest( + PendOp->COMMAND.NDIS.SET_FILTER.Open->NdisBindingContext, + PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp), + NDIS_STATUS_SUCCESS); + + NdisAcquireSpinLock(&(Adapter->Lock)); + + Adapter->RequestTimeout = FALSE; + + TmpOpen->References--; + + break; + + case NdisRequestClose: + + PendOp->COMMAND.NDIS.CLOSE.Open->References--; + break; + + case NdisRequestGeneric2: + case NdisRequestGeneric3: + + PendOp->COMMAND.NDIS.SET_ADDRESS.Open->References--; + break; + + case NdisRequestQueryStatistics: + + NdisReleaseSpinLock(&(Adapter->Lock)); + + NdisCompleteQueryStatistics( + Adapter->NdisMacHandle, + PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp), + NDIS_STATUS_SUCCESS); + + NdisAcquireSpinLock(&(Adapter->Lock)); + + Adapter->RequestTimeout = FALSE; + + Adapter->References--; + + break; + + default: + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 3, + startPendQueueOp, + IBMTOK_ERRMSG_BAD_OP, + PendOp->RequestType); + } + } + else + { + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 3, + startPendQueueOp, + IBMTOK_ERRMSG_INVALID_STATUS, + RequestStatus); + } + } + + // + // We drained the entire queue without pending. + // + return NDIS_STATUS_SUCCESS; +} + +STATIC +BOOLEAN +FinishPendQueueOp( + IN PIBMTOK_ADAPTER Adapter, + IN BOOLEAN Successful + ) + +/*++ + +Routine Description: + + This routine is called when an SRB command completes. + It calles CompleteRequest if needed and does any other + cleanup required. + + NOTE: This routine is called with the lock held and + returns with it held. + + NOTE: This routine assumes that the pended operation to + be completed was specifically requested by the protocol + and, thus, that PendData->Request != NULL. + +Arguments: + + Adapter - The adapter that the queue should be checked for. + + Successful - Was the SRB command completed successfully. + +Return Value: + + TRUE if the operation was completed, FALSE if another command + was submitted to the card to complete the operation. + +--*/ + +{ + PIBMTOK_PEND_DATA PendOp = Adapter->PendData; + + ASSERT(PendOp != NULL); + + switch (PendOp->RequestType) + { + case NdisRequestQueryStatistics: + // + // It was a request for global statistics. + // + if (Successful) + { + NDIS_STATUS StatusToReturn; + + // + // Grab the data + // + GetAdapterErrorsFromSrb(Adapter); + + // + // Fill in NdisRequest InformationBuffer + // + StatusToReturn = IbmtokFillInGlobalData( + Adapter, + PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp)); + + // + // Complete statistics call + // + Adapter->PendData = NULL; + + NdisReleaseSpinLock(&(Adapter->Lock)); + + NdisCompleteQueryStatistics( + Adapter->NdisMacHandle, + PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp), + StatusToReturn); + + NdisAcquireSpinLock(&(Adapter->Lock)); + + Adapter->RequestTimeout = FALSE; + + Adapter->References--; + } + else + { + // + // Complete statistics call + // + Adapter->PendData = NULL; + + NdisReleaseSpinLock(&(Adapter->Lock)); + + NdisCompleteQueryStatistics( + Adapter->NdisMacHandle, + PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp), + NDIS_STATUS_FAILURE); + + NdisAcquireSpinLock(&(Adapter->Lock)); + + Adapter->RequestTimeout = FALSE; + + Adapter->References--; + } + + break; + + case NdisRequestSetInformation: + + + // + // It was a request for address change. + // +#if DBG + if (IbmtokDbg) + { + if (Successful) + { + DbgPrint("IBMTOK: SUCCESS\n\n"); + } + else + { + DbgPrint("IBMTOK: FAILURE\n\n"); + } + } +#endif + + if (Successful) + { + PIBMTOK_OPEN TmpOpen; + + // + // complete the operation. + // + if (PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(Adapter->PendData)->DATA.SET_INFORMATION.Oid == + OID_802_5_CURRENT_GROUP) + { + // + // Store new group address + // + Adapter->CurrentCardGroup = Adapter->CurrentGroupAddress; + } + + Adapter->PendData = NULL; + + TmpOpen = PendOp->COMMAND.NDIS.SET_FILTER.Open; + + NdisReleaseSpinLock(&(Adapter->Lock)); + + NdisCompleteRequest( + PendOp->COMMAND.NDIS.SET_FILTER.Open->NdisBindingContext, + PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp), + NDIS_STATUS_SUCCESS); + + NdisAcquireSpinLock(&(Adapter->Lock)); + + Adapter->RequestTimeout = FALSE; + + TmpOpen->References--; + } + else + { + // + // complete the operation. + // + PIBMTOK_OPEN TmpOpen; + + Adapter->PendData = NULL; + + TmpOpen = PendOp->COMMAND.NDIS.SET_FILTER.Open; + + NdisReleaseSpinLock(&(Adapter->Lock)); + + NdisCompleteRequest( + PendOp->COMMAND.NDIS.SET_FILTER.Open->NdisBindingContext, + PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp), + NDIS_STATUS_FAILURE); + + NdisAcquireSpinLock(&(Adapter->Lock)); + + Adapter->RequestTimeout = FALSE; + + TmpOpen->References--; + } + + break; + + case NdisRequestClose: + case NdisRequestGeneric2: + case NdisRequestGeneric3: + + PendOp->COMMAND.NDIS.CLOSE.Open->References--; + + break; + } + + // + // Now finish up unsuccessful operations based on the type. + // + // NOTE: If we ever have cleanup for successful operations, + // we probably have to copy that code into the + // 'RequestStatus == NDIS_STATUS_SUCCESS' section + // in the function above. + // + if (!Successful) + { + switch (PendOp->RequestType) + { + case NdisRequestSetInformation: + + // + // We know it was a set filter or set address. + // + if ((PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp))->DATA.SET_INFORMATION.Oid == + OID_GEN_CURRENT_PACKET_FILTER) + { + // + // It was a set filter. + // + Adapter->CurrentPacketFilter = Adapter->OldPacketFilter; + + Adapter->CurrentCardFunctional = (TR_FUNCTIONAL_ADDRESS)0; + } + else + { + // + // It was a set address. + // + Adapter->CurrentFunctionalAddress = (TR_FUNCTIONAL_ADDRESS)0; + } + + break; + + case NdisRequestQueryStatistics: + + break; + + case NdisRequestClose: + case NdisRequestGeneric2: + case NdisRequestGeneric3: + + break; + + default: + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 3, + finishPendQueueOp, + IBMTOK_ERRMSG_BAD_OP, + PendOp->RequestType); + + break; + } + } + + return(TRUE); +} + +STATIC +NDIS_STATUS +SetAdapterFunctionalAddress( + IN PIBMTOK_ADAPTER Adapter + ) + + +/*++ + +Routine Description: + + This routine checks the functional address on the adapter + against what it should be given the current packet filter + and functional address specified, and queues an update + if necessary. + + NOTE: This routine assumes that it is called with the lock + acquired. + +Arguments: + + Adapter - The adapter to check. + +Return Value: + + NDIS_STATUS_SUCCESS - If no change is necessary. + NDIS_STATUS_PENDING - If the change was queued. + + +--*/ +{ + // + // The new value we compute for the functional address that + // should be on the card. + // + TR_FUNCTIONAL_ADDRESS NewCardFunctional; + + // + // Holds the value to be returned. + // + NDIS_STATUS StatusOfSet; + + // + // Used if ALL_MULTICAST is selected. + // + ULONG AllFunctionalAddress = 0x7fffffff; + + // + // First calculate what the new functional address + // should be. + // + +#if DBG + if (IbmtokDbg) + { + DbgPrint("IBMTOK: Current packet filter : 0x%x\n", Adapter->CurrentPacketFilter); + } +#endif + + if (Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) + { + // + // We have to set all the bits in the address. + // + NewCardFunctional = AllFunctionalAddress; + } + else if (Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_FUNCTIONAL) + { + NewCardFunctional = Adapter->CurrentFunctionalAddress; + } + else + { + NewCardFunctional = (TR_FUNCTIONAL_ADDRESS)0; + } + +#if DBG + if (IbmtokDbg) + { + DbgPrint("IBMTOK: NewFunc is 0x%x\n", NewCardFunctional); + } +#endif + + // + // Now queue it up if needed. + // + if (NewCardFunctional == Adapter->CurrentCardFunctional) + { +#if DBG + if (IbmtokDbg) + { + DbgPrint("IBMTOK: SUCCESS\n\n"); + } +#endif + StatusOfSet = NDIS_STATUS_SUCCESS; + } + else + { + SetupFunctionalSrb(Adapter, NewCardFunctional); + Adapter->CurrentCardFunctional = NewCardFunctional; + + StatusOfSet = NDIS_STATUS_PENDING; + } + + return StatusOfSet; +} + +STATIC +VOID +SetupFunctionalSrb( + IN PIBMTOK_ADAPTER Adapter, + IN TR_FUNCTIONAL_ADDRESS FunctionalAddress + ) + +/*++ + +Routine Description: + + This routine sets up the SRB for a DIR.SET.FUNCT.Address. + +Arguments: + + Adapter - The adapter that this packet is coming through. + + FunctionalAddress - The address to set up. + +Return Value: + + None. + +--*/ + +{ + // + // Used to set up the SRB request. + // + PSRB_SET_FUNCT_ADDRESS FunctSrb = + (PSRB_SET_FUNCT_ADDRESS)Adapter->SrbAddress; + + // + // Used to hold the functional address temporarily. + // + UCHAR TempAddress[4]; + + // + // Used to copy down the functional address. + // + UINT i; + + NdisWriteRegisterUchar(&(FunctSrb->Command), SRB_CMD_SET_FUNCTIONAL_ADDRESS); + NdisWriteRegisterUchar(&(FunctSrb->ReturnCode), 0xfe); + + // + // Have to worry about setting the functional address + // since it is not aligned correctly. + // + IBMTOK_STORE_ULONG(TempAddress, FunctionalAddress); + + for (i = 0; i < 4; i++) + { + NdisWriteRegisterUchar(&(FunctSrb->FunctionalAddress[i]), TempAddress[i]); + } +} + +STATIC +NDIS_STATUS +SetAdapterGroupAddress( + IN PIBMTOK_ADAPTER Adapter + ) + + +/*++ + +Routine Description: + + This routine takes the value in Adapter->CurrentGroupAddress and + puts it out to the card. + + NOTE: This routine assumes that it is called with the lock + acquired. + +Arguments: + + Adapter - The adapter to check. + +Return Value: + + NDIS_STATUS_PENDING - If the change was queued. + + +--*/ +{ + // + // Holds the value to be returned. + // + SetupGroupSrb(Adapter, Adapter->CurrentGroupAddress); + + return NDIS_STATUS_PENDING; +} + +STATIC +VOID +SetupGroupSrb( + IN PIBMTOK_ADAPTER Adapter, + IN TR_FUNCTIONAL_ADDRESS GroupAddress + ) + +/*++ + +Routine Description: + + This routine sets up the SRB for a DIR.SET.GROUP.ADDRESS. + +Arguments: + + Adapter - The adapter that this packet is coming through. + + GroupAddress - The address to set up. + +Return Value: + + None. + +--*/ + +{ + // + // Used to set up the SRB request. + // + PSRB_SET_GROUP_ADDRESS GroupSrb = (PSRB_SET_GROUP_ADDRESS)Adapter->SrbAddress; + + // + // Used to hold the group address temporarily. + // + UCHAR TempAddress[4]; + + // + // Used to copy down the group address. + // + UINT i; + + + NdisWriteRegisterUchar(&(GroupSrb->Command), SRB_CMD_SET_GROUP_ADDRESS); + NdisWriteRegisterUchar(&(GroupSrb->ReturnCode), 0xfe); + + // + // Have to worry about setting the group address + // since it is not aligned correctly. + // + IBMTOK_STORE_ULONG(TempAddress, GroupAddress); + + for (i = 0; i < 4; i++) + { + NdisWriteRegisterUchar(&(GroupSrb->GroupAddress[i]), TempAddress[i]); + } +} + +STATIC +VOID +SetupReceivedDataAsb( + IN PIBMTOK_ADAPTER Adapter, + IN SRAM_PTR ReceiveBuffer + ) + +/*++ + +Routine Description: + + This routine sets up the ASB for a response from + a RECEIVED.DATA ARB. + +Arguments: + + Adapter - The adapter that this packet is coming through. + + ReceiveBuffer - The first receive buffer in the frame. + +Return Value: + + None. + +--*/ + +{ + PASB_RECEIVED_DATA_STATUS ReceivedDataAsb; + + ReceivedDataAsb = (PASB_RECEIVED_DATA_STATUS) + Adapter->AsbAddress; + + NdisWriteRegisterUchar(&(ReceivedDataAsb->Command), ARB_CMD_RECEIVED_DATA); + NdisWriteRegisterUchar(&(ReceivedDataAsb->ReturnCode), 0x00); + NdisWriteRegisterUshort(&(ReceivedDataAsb->StationId), 0x0000); + NdisWriteRegisterUshort(&(ReceivedDataAsb->ReceiveBuffer), ReceiveBuffer); +} + +STATIC +VOID +PutPacketOnWaitingForAsb( + IN PIBMTOK_ADAPTER Adapter, + IN PNDIS_PACKET Packet + ) + +/*++ + +Routine Description: + + This queues a packet on the Waiting To Copy queue. + It is called and returns with the spinlock held. + +Arguments: + + Adapter - The adapter that this packet is coming through. + + Packet - The packet that is to be transmitted. + +Return Value: + + None. + +--*/ + +{ + // + // Points to the MAC reserved portion of this packet. This + // interpretation of the reserved section is only valid during + // the allocation phase of the packet. + // + PIBMTOK_RESERVED Reserved = PIBMTOK_RESERVED_FROM_PACKET(Packet); + + + ASSERT(sizeof(IBMTOK_RESERVED) <= sizeof(Packet->MacReserved)); + + if (Adapter->FirstWaitingForAsb == NULL) + { + Adapter->FirstWaitingForAsb = Packet; + } + else + { + PIBMTOK_RESERVED_FROM_PACKET(Adapter->FirstWaitingForAsb)->Next = Packet; + } + + Adapter->LastWaitingForAsb = Packet; + + Reserved->Next = NULL; +} +extern +VOID +IbmtokHandleDeferred( + IN PIBMTOK_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine handles any pending resets and closes. + It is called during interrupt processing and also at + the end of every routine if needed. + + NOTE: This routine is called with the spinlock held + and returns with it held. + +Arguments: + + Adapter - The adapter to check deferred processing on. + +Return Value: + + None. + +--*/ + +{ + PIBMTOK_OPEN Open; + + // + // Note that the following code depends on the fact that + // code above left the spinlock held. + // + + // + // We will only come in here if the adapter's reference + // count is zero, so if a reset is in progress then we + // can start the reset. + // + + // + // Make sure we don't start it twice!! + // + Adapter->References++; + + if (Adapter->ResetInProgress && Adapter->CurrentResetStage == 0) + { + Adapter->CurrentResetStage = 1; + + NdisReleaseSpinLock(&(Adapter->Lock)); + + IbmtokStartAdapterReset(Adapter); + + NdisAcquireSpinLock(&(Adapter->Lock)); + } + + if (!Adapter->ResetInProgress && !IsListEmpty(&(Adapter->CloseDuringResetList))) + { + // + // Status of the Filter delete call. + // + NDIS_STATUS Status; + + Open = CONTAINING_RECORD( + Adapter->CloseDuringResetList.Flink, + IBMTOK_OPEN, + OpenList); + + Open->References++; +#if DBG + if (IbmtokDbg) DbgPrint("IBMTOK: Calling TrDelete\n"); +#endif + + Status = TrDeleteFilterOpenAdapter( + Adapter->FilterDB, + Open->NdisFilterHandle, + NULL); + +#if DBG + if (IbmtokDbg) DbgPrint("IBMTOK: TrDelete returned\n"); +#endif + + // + // 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 (Status == 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) + { + // + // We are the only reference to the open. Remove + // it from the list and delete the memory. + // + RemoveEntryList(&Open->OpenList); + + // + // Complete the close here. + // + if (Adapter->LookAhead == Open->LookAhead) + { + IbmtokAdjustMaxLookAhead(Adapter); + } + + NdisReleaseSpinLock(&Adapter->Lock); + + NdisCompleteCloseAdapter( + Open->NdisBindingContext, + NDIS_STATUS_SUCCESS); + + IBMTOK_FREE_PHYS(Open,sizeof(IBMTOK_OPEN)); + + NdisAcquireSpinLock(&Adapter->Lock); + } + else + { + // + // Remove the open from the 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 (Status == NDIS_STATUS_PENDING) + { + // + // If it pended, there may be + // operations queued. + // Returns with lock released + // + 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 + { + // + // We should not get RESET_IN_PROGRESS or any other types. + // + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 3, + handleDeferred, + IBMTOK_ERRMSG_INVALID_STATUS, + Status); + } + } + + // + // If there are any opens on the closing list and their + // reference counts are zero then complete the close and + // delete them from the list. + // + // + if (!IsListEmpty(&(Adapter->CloseList))){ + + Open = CONTAINING_RECORD( + Adapter->CloseList.Flink, + IBMTOK_OPEN, + OpenList); + + if (!Open->References) + { + if (Adapter->LookAhead == Open->LookAhead) + { + IbmtokAdjustMaxLookAhead(Adapter); + } + + NdisReleaseSpinLock(&(Adapter->Lock)); + + NdisCompleteCloseAdapter( + Open->NdisBindingContext, + NDIS_STATUS_SUCCESS); + + NdisAcquireSpinLock(&(Adapter->Lock)); + RemoveEntryList(&(Open->OpenList)); + IBMTOK_FREE_PHYS(Open, sizeof(IBMTOK_OPEN)); + } + } + + Adapter->References--; +} + +extern +VOID +IbmtokAbortPending( + IN PIBMTOK_ADAPTER Adapter, + IN NDIS_STATUS AbortStatus + ) + +/*++ + +Routine Description: + + This routine aborts any pending requests, and calls + IbmtokAbortSends to abort any pending sends. + + NOTE: This routine is called with the spinlock held + and returns with it held. + +Arguments: + + Adapter - The adapter to abort. + + AbortStatus - The status to complete requests with. + +Return Value: + + None. + +--*/ + +{ + PIBMTOK_OPEN Open; + PIBMTOK_PEND_DATA PendOp; + + while (Adapter->PendQueue) + { + // + // Holds the operation on the head of the queue + // + PendOp = Adapter->PendQueue; + + Adapter->PendQueue = Adapter->PendQueue->Next; + + if (Adapter->PendQueue == NULL) + { + // + // We have just emptied the list. + // + Adapter->EndOfPendQueue = NULL; + } + + switch (PendOp->RequestType) + { + case NdisRequestSetInformation: + + // + // Complete the request. + // + Open = PendOp->COMMAND.NDIS.SET_FILTER.Open; + + NdisDprReleaseSpinLock(&(Adapter->Lock)); + + NdisCompleteRequest( + Open->NdisBindingContext, + PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp), + AbortStatus); + + NdisDprAcquireSpinLock(&(Adapter->Lock)); + + Adapter->RequestTimeout = FALSE; + + Open->References--; + + break; + + case NdisRequestClose: + + PendOp->COMMAND.NDIS.CLOSE.Open->References--; + break; + + case NdisRequestGeneric1: + + // + // Submitted by the driver + // + IBMTOK_FREE_PHYS(PendOp, sizeof(IBMTOK_PEND_DATA)); + Adapter->PendData = NULL; + break; + + case NdisRequestGeneric2: + case NdisRequestGeneric3: + + // + // Changes in address and filters due to a close + // + PendOp->COMMAND.NDIS.SET_ADDRESS.Open->References--; + break; + + + case NdisRequestQueryStatistics: + + NdisDprReleaseSpinLock(&(Adapter->Lock)); + + NdisCompleteQueryStatistics( + Adapter->NdisMacHandle, + PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp), + AbortStatus); + + NdisDprAcquireSpinLock(&(Adapter->Lock)); + + Adapter->RequestTimeout = FALSE; + + Adapter->References--; + + break; + } + } + + IbmtokAbortSends (Adapter, AbortStatus); +} + +extern +VOID +IbmtokAbortSends( + IN PIBMTOK_ADAPTER Adapter, + IN NDIS_STATUS AbortStatus + ) + +/*++ + +Routine Description: + + This routine aborts any pending sends. + + NOTE: This routine is called with the spinlock held + and returns with it held. + +Arguments: + + Adapter - The adapter to abort. + + AbortStatus - The status to complete requests with. + +Return Value: + + None. + +--*/ + +{ + PIBMTOK_OPEN Open; + PNDIS_PACKET TransmitPacket; + PIBMTOK_RESERVED Reserved; + UINT i; + + // + // First the packet in the SRB. + // + if (Adapter->TransmittingPacket != NULL) + { + TransmitPacket = Adapter->TransmittingPacket; + Adapter->TransmittingPacket = NULL; + + Reserved = PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket); + Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle); + + NdisDprReleaseSpinLock(&Adapter->Lock); + + NdisCompleteSend(Open->NdisBindingContext, TransmitPacket, AbortStatus); + + NdisDprAcquireSpinLock(&Adapter->Lock); + Open->References--; + } + + // + // Then any that are queued up waiting to be given to the card. + // + while (Adapter->FirstTransmit) + { + TransmitPacket = Adapter->FirstTransmit; + + Reserved = PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket); + Adapter->FirstTransmit = Reserved->Next; + + Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle); + + NdisDprReleaseSpinLock(&Adapter->Lock); + + NdisCompleteSend( + Open->NdisBindingContext, + TransmitPacket, + AbortStatus); + + NdisDprAcquireSpinLock(&Adapter->Lock); + Open->References--; + } + + // + // Finally, the Correlator array (this will include any + // packets on WaitingForAsb). + // + + for (i = 0; i < MAX_COMMAND_CORRELATOR; i++) + { + TransmitPacket = Adapter->CorrelatorArray[i]; + + if (TransmitPacket != NULL) + { + RemovePacketFromCorrelatorArray (Adapter, TransmitPacket); + + Reserved = PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket); + Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle); + + NdisDprReleaseSpinLock(&Adapter->Lock); + + NdisCompleteSend( + Open->NdisBindingContext, + Reserved->Packet, + AbortStatus); + + NdisDprAcquireSpinLock(&Adapter->Lock); + Open->References--; + } + } + + Adapter->FirstWaitingForAsb = NULL; +} + +VOID +IbmtokWakeUpDpc( + IN PVOID SystemSpecific1, + IN PVOID Context, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ) + +/*++ + +Routine Description: + + This DPC routine is queued every 2 seconds to check on the + queues. If an interrupt was not received + in the last two seconds and there should have been one, + then we abort all operations. + +Arguments: + + Context - Really a pointer to the adapter. + +Return Value: + + None. + +--*/ +{ + PIBMTOK_ADAPTER Adapter = (PIBMTOK_ADAPTER)Context; + + UNREFERENCED_PARAMETER(SystemSpecific1); + UNREFERENCED_PARAMETER(SystemSpecific2); + UNREFERENCED_PARAMETER(SystemSpecific3); + + NdisDprAcquireSpinLock(&Adapter->Lock); + + if ((Adapter->SendTimeout && + ((Adapter->TransmittingPacket != NULL) || + (Adapter->FirstTransmit != NULL))) || + (Adapter->RequestTimeout && (Adapter->PendQueue != NULL))) + { + // + // We had a pending operation the last time we ran, + // and it has not been completed...we need to complete + // it now. + Adapter->NotAcceptingRequests = TRUE; + + Adapter->SendTimeout = FALSE; + Adapter->RequestTimeout = FALSE; + + // + // Complete any pending requests or sends. + // + IbmtokAbortPending(Adapter, STATUS_REQUEST_ABORTED); + + Adapter->WakeUpErrorCount++; + IbmtokSetupForReset(Adapter, NULL); + + IbmtokHandleDeferred(Adapter); + } + else + { + if ((Adapter->TransmittingPacket != NULL) || + (Adapter->FirstTransmit != NULL)) + { + Adapter->SendTimeout = TRUE; + } + + if (Adapter->PendQueue != NULL) + { + Adapter->RequestTimeout = TRUE; + } + } + + // + // If we've been unplugged, and there is not a reset in + // progress, try one. + // + if ((Adapter->LobeWireFaultIndicated) && + (!Adapter->UnpluggedResetInProgress)) + { + Adapter->UnpluggedResetInProgress = TRUE; + + IbmtokSetupForReset(Adapter, NULL); + + IbmtokHandleDeferred(Adapter); + } + + NdisDprReleaseSpinLock(&Adapter->Lock); + + // + // Fire off another Dpc to execute after 30 seconds + // + NdisSetTimer(&Adapter->WakeUpTimer, 30000); +} + diff --git a/private/ntos/ndis/ibmtok/keywords.h b/private/ntos/ndis/ibmtok/keywords.h new file mode 100644 index 000000000..0e3217834 --- /dev/null +++ b/private/ntos/ndis/ibmtok/keywords.h @@ -0,0 +1,54 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + keywords.h + +Abstract: + + Contains all Ndis2 and Ndis3 mac-specific keywords. + +Author: + + Bob Noradki + +Environment: + + This driver is expected to work in DOS, OS2 and NT at the equivalent + of kernal mode. + + Architecturally, there is an assumption in this driver that we are + on a little endian machine. + +Notes: + + optional-notes + +Revision History: + + + +--*/ +#ifndef NDIS2 +#define NDIS2 0 +#endif + +#if NDIS2 + +#define SLOTNUMBER NDIS_STRING_CONST("SLOTNUMBER") +#define MAXPACKETSIZE NDIS_STRING_CONST("MAXPACKETSIZE") +#define IOADDRESS NDIS_STRING_CONST("IOBASE") +#define NETWORK_ADDRESS NDIS_STRING_CONST("NETADDRESS") +#define TOKEN_RELEASE NDIS_STRING_CONST("EARLYTOKENRELEASE") + +#else // NDIS3 + +#define SLOTNUMBER NDIS_STRING_CONST("SlotNumber") +#define MAXPACKETSIZE NDIS_STRING_CONST("MaximumPacketSize") +#define IOADDRESS NDIS_STRING_CONST("IoBaseAddress") +#define NETWORK_ADDRESS NDIS_STRING_CONST("NetworkAddress") +#define TOKEN_RELEASE NDIS_STRING_CONST("EarlyTokenRelease") + +#endif diff --git a/private/ntos/ndis/ibmtok/makefile b/private/ntos/ndis/ibmtok/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/ndis/ibmtok/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/ndis/ibmtok/packet.c b/private/ntos/ndis/ibmtok/packet.c new file mode 100644 index 000000000..dcff44c34 --- /dev/null +++ b/private/ntos/ndis/ibmtok/packet.c @@ -0,0 +1,732 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + transfer.c + +Abstract: + + This module contains code to copy from ndis packets to ndis packets, + and also to copy from ndis packets to a buffer. + +Author: + + Anthony V. Ercolano (Tonye) 12-Sept-1990 + +Environment: + + Works in kernel mode, but is not important that it does. + +Revision History: + + +--*/ + +#include <ndis.h> + +#include <tfilter.h> +#include <tokhrd.h> +#include <toksft.h> + + +extern +VOID +IbmtokCopyFromPacketToBuffer( + IN PNDIS_PACKET Packet, + IN UINT Offset, + IN UINT BytesToCopy, + OUT PCHAR Buffer, + OUT PUINT BytesCopied + ) + +/*++ + +Routine Description: + + Copy from an ndis packet into a buffer. + +Arguments: + + Packet - The packet to copy from. + + Offset - The offset from which to start the copy. + + BytesToCopy - The number of bytes to copy from the packet. + + Buffer - The destination of the copy. + + BytesCopied - The number of bytes actually copied. Can be less then + BytesToCopy if the packet is shorter than BytesToCopy. + +Return Value: + + None + +--*/ + +{ + + // + // Holds the number of ndis buffers comprising the packet. + // + UINT NdisBufferCount; + + // + // Points to the buffer from which we are extracting data. + // + PNDIS_BUFFER CurrentBuffer; + + // + // Holds the virtual address of the current buffer. + // + PVOID VirtualAddress; + + // + // Holds the length of the current buffer of the packet. + // + UINT CurrentLength; + + // + // Keep a local variable of BytesCopied so we aren't referencing + // through a pointer. + // + UINT LocalBytesCopied = 0; + + // + // Take care of boundary condition of zero length copy. + // + + *BytesCopied = 0; + if (!BytesToCopy) return; + + // + // Get the first buffer. + // + + NdisQueryPacket(Packet, + NULL, + &NdisBufferCount, + &CurrentBuffer, + NULL + ); + + // + // Could have a null packet. + // + + if (!NdisBufferCount) return; + + NdisQueryBuffer(CurrentBuffer, &VirtualAddress, &CurrentLength); + + while (LocalBytesCopied < BytesToCopy) { + + if (!CurrentLength) { + + NdisGetNextBuffer( + CurrentBuffer, + &CurrentBuffer + ); + + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested. + // + + if (CurrentBuffer == NULL) break; + + NdisQueryBuffer(CurrentBuffer, &VirtualAddress, &CurrentLength); + continue; + + } + + // + // Try to get us up to the point to start the copy. + // + + if (Offset) { + + if (Offset > CurrentLength) { + + // + // What we want isn't in this buffer. + // + + Offset -= CurrentLength; + CurrentLength = 0; + continue; + + } else { + + VirtualAddress = (PCHAR)VirtualAddress + Offset; + CurrentLength -= Offset; + Offset = 0; + + } + + } + + // + // Copy the data. + // + + + { + + // + // Holds the amount of data to move. + // + UINT AmountToMove; + + AmountToMove = + ((CurrentLength <= (BytesToCopy - LocalBytesCopied))? + (CurrentLength):(BytesToCopy - LocalBytesCopied)); + + IBMTOK_MOVE_TO_MAPPED_MEMORY( + Buffer, + VirtualAddress, + AmountToMove + ); + + Buffer = (PCHAR)Buffer + AmountToMove; + VirtualAddress = (PCHAR)VirtualAddress + AmountToMove; + + LocalBytesCopied += AmountToMove; + CurrentLength -= AmountToMove; + + } + + } + + *BytesCopied = LocalBytesCopied; + +} + +extern +VOID +IbmtokCopyFromBufferToPacket( + IN PCHAR Buffer, + IN UINT BytesToCopy, + IN PNDIS_PACKET Packet, + IN UINT Offset, + OUT PUINT BytesCopied + ) + +/*++ + +Routine Description: + + Copy from a buffer into an ndis packet. + +Arguments: + + Buffer - The packet to copy from. + + Offset - The offset from which to start the copy. + + BytesToCopy - The number of bytes to copy from the buffer. + + Packet - The destination of the copy. + + BytesCopied - The number of bytes actually copied. Will be less + than BytesToCopy if the packet is not large enough. + +Return Value: + + None + +--*/ + +{ + // + // Holds the count of the number of ndis buffers comprising the + // destination packet. + // + UINT DestinationBufferCount; + + // + // Points to the buffer into which we are putting data. + // + PNDIS_BUFFER DestinationCurrentBuffer; + + // + // Points to the location in Buffer from which we are extracting data. + // + PUCHAR SourceCurrentAddress; + + // + // Holds the virtual address of the current destination buffer. + // + PVOID DestinationVirtualAddress; + + // + // Holds the length of the current destination buffer. + // + UINT DestinationCurrentLength; + + // + // Keep a local variable of BytesCopied so we aren't referencing + // through a pointer. + // + UINT LocalBytesCopied = 0; + + + // + // Take care of boundary condition of zero length copy. + // + + *BytesCopied = 0; + if (!BytesToCopy) return; + + // + // Get the first buffer of the destination. + // + + NdisQueryPacket( + Packet, + NULL, + &DestinationBufferCount, + &DestinationCurrentBuffer, + NULL + ); + + // + // Could have a null packet. + // + + if (!DestinationBufferCount) return; + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + // + // Set up the source address. + // + + SourceCurrentAddress = Buffer; + + + while (LocalBytesCopied < BytesToCopy) { + + // + // Check to see whether we've exhausted the current destination + // buffer. If so, move onto the next one. + // + + if (!DestinationCurrentLength) { + + NdisGetNextBuffer( + DestinationCurrentBuffer, + &DestinationCurrentBuffer + ); + + if (DestinationCurrentBuffer == NULL) { + + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested.) + // + + break; + + } + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + continue; + + } + + // + // Try to get us up to the point to start the copy. + // + + if (Offset) { + + if (Offset > DestinationCurrentLength) { + + // + // What we want isn't in this buffer. + // + + Offset -= DestinationCurrentLength; + DestinationCurrentLength = 0; + continue; + + } else { + + DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress + + Offset; + DestinationCurrentLength -= Offset; + Offset = 0; + + } + + } + + + // + // Copy the data. + // + + { + + // + // Holds the amount of data to move. + // + UINT AmountToMove; + + // + // Holds the amount desired remaining. + // + UINT Remaining = BytesToCopy - LocalBytesCopied; + + + AmountToMove = DestinationCurrentLength; + + AmountToMove = ((Remaining < AmountToMove)? + (Remaining):(AmountToMove)); + + IBMTOK_MOVE_FROM_MAPPED_MEMORY( + DestinationVirtualAddress, + SourceCurrentAddress, + AmountToMove + ); + + SourceCurrentAddress += AmountToMove; + LocalBytesCopied += AmountToMove; + DestinationCurrentLength -= AmountToMove; + + } + + } + + *BytesCopied = LocalBytesCopied; + + +} + +extern +VOID +IbmtokCopyFromPacketToPacket( + IN PNDIS_PACKET Destination, + IN UINT DestinationOffset, + IN UINT BytesToCopy, + IN PNDIS_PACKET Source, + IN UINT SourceOffset, + OUT PUINT BytesCopied + ) + +/*++ + +Routine Description: + + Copy from an ndis packet to an ndis packet. + +Arguments: + + Destination - The packet should be copied in to. + + DestinationOffset - The offset from the beginning of the packet + into which the data should start being placed. + + BytesToCopy - The number of bytes to copy from the source packet. + + Source - The ndis packet from which to copy data. + + SourceOffset - The offset from the start of the packet from which + to start copying data. + + BytesCopied - The number of bytes actually copied from the source + packet. This can be less than BytesToCopy if the source or destination + packet is too short. + +Return Value: + + None + +--*/ + +{ + + // + // Holds the count of the number of ndis buffers comprising the + // destination packet. + // + UINT DestinationBufferCount; + + // + // Holds the count of the number of ndis buffers comprising the + // source packet. + // + UINT SourceBufferCount; + + // + // Points to the buffer into which we are putting data. + // + PNDIS_BUFFER DestinationCurrentBuffer; + + // + // Points to the buffer from which we are extracting data. + // + PNDIS_BUFFER SourceCurrentBuffer; + + // + // Holds the virtual address of the current destination buffer. + // + PVOID DestinationVirtualAddress; + + // + // Holds the virtual address of the current source buffer. + // + PVOID SourceVirtualAddress; + + // + // Holds the length of the current destination buffer. + // + UINT DestinationCurrentLength; + + // + // Holds the length of the current source buffer. + // + UINT SourceCurrentLength; + + // + // Keep a local variable of BytesCopied so we aren't referencing + // through a pointer. + // + UINT LocalBytesCopied = 0; + + // + // Take care of boundary condition of zero length copy. + // + + *BytesCopied = 0; + if (!BytesToCopy) return; + + // + // Get the first buffer of the destination. + // + + NdisQueryPacket( + Destination, + NULL, + &DestinationBufferCount, + &DestinationCurrentBuffer, + NULL + ); + + // + // Could have a null packet. + // + + if (!DestinationBufferCount) return; + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + // + // Get the first buffer of the source. + // + + NdisQueryPacket( + Source, + NULL, + &SourceBufferCount, + &SourceCurrentBuffer, + NULL + ); + + // + // Could have a null packet. + // + + if (!SourceBufferCount) return; + + NdisQueryBuffer( + SourceCurrentBuffer, + &SourceVirtualAddress, + &SourceCurrentLength + ); + + while (LocalBytesCopied < BytesToCopy) { + + // + // Check to see whether we've exhausted the current destination + // buffer. If so, move onto the next one. + // + + if (!DestinationCurrentLength) { + + NdisGetNextBuffer( + DestinationCurrentBuffer, + &DestinationCurrentBuffer + ); + + if (DestinationCurrentBuffer == NULL) { + + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested.) + // + + break; + + } + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + continue; + + } + + + // + // Check to see whether we've exhausted the current source + // buffer. If so, move onto the next one. + // + + if (!SourceCurrentLength) { + + NdisGetNextBuffer( + SourceCurrentBuffer, + &SourceCurrentBuffer + ); + + if (SourceCurrentBuffer == NULL) { + + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested.) + // + + break; + + } + + NdisQueryBuffer( + SourceCurrentBuffer, + &SourceVirtualAddress, + &SourceCurrentLength + ); + continue; + + } + + // + // Try to get us up to the point to start the copy. + // + + if (DestinationOffset) { + + if (DestinationOffset > DestinationCurrentLength) { + + // + // What we want isn't in this buffer. + // + + DestinationOffset -= DestinationCurrentLength; + DestinationCurrentLength = 0; + continue; + + } else { + + DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress + + DestinationOffset; + DestinationCurrentLength -= DestinationOffset; + DestinationOffset = 0; + + } + + } + + // + // Try to get us up to the point to start the copy. + // + + if (SourceOffset) { + + if (SourceOffset > SourceCurrentLength) { + + // + // What we want isn't in this buffer. + // + + SourceOffset -= SourceCurrentLength; + SourceCurrentLength = 0; + continue; + + } else { + + SourceVirtualAddress = (PCHAR)SourceVirtualAddress + + SourceOffset; + SourceCurrentLength -= SourceOffset; + SourceOffset = 0; + + } + + } + + // + // Copy the data. + // + + { + + // + // Holds the amount of data to move. + // + UINT AmountToMove; + + // + // Holds the amount desired remaining. + // + UINT Remaining = BytesToCopy - LocalBytesCopied; + + AmountToMove = + ((SourceCurrentLength <= DestinationCurrentLength)? + (SourceCurrentLength):(DestinationCurrentLength)); + + AmountToMove = ((Remaining < AmountToMove)? + (Remaining):(AmountToMove)); + + IBMTOK_MOVE_MEMORY( + DestinationVirtualAddress, + SourceVirtualAddress, + AmountToMove + ); + + DestinationVirtualAddress = + (PCHAR)DestinationVirtualAddress + AmountToMove; + SourceVirtualAddress = + (PCHAR)SourceVirtualAddress + AmountToMove; + + LocalBytesCopied += AmountToMove; + SourceCurrentLength -= AmountToMove; + DestinationCurrentLength -= AmountToMove; + + } + + } + + *BytesCopied = LocalBytesCopied; + +} diff --git a/private/ntos/ndis/ibmtok/send.c b/private/ntos/ndis/ibmtok/send.c new file mode 100644 index 000000000..a6cbddfb0 --- /dev/null +++ b/private/ntos/ndis/ibmtok/send.c @@ -0,0 +1,322 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + send.c + +Abstract: + + This file contains the code for putting a packet through the + staged allocation for transmission. + + This is a process of + + 1) Calculating the what would need to be done to the + packet so that the packet can be transmitted on the hardware. + + 2) Potentially allocating adapter buffers and copying user data + to those buffers so that the packet data is transmitted under + the hardware constraints. + + 3) Allocating enough hardware ring entries so that the packet + can be transmitted. + + 4) Relinquish thos ring entries to the hardware. + + The overall structure and most of the code is taken from + the Lance driver by Tony Ercolano. + +Author: + + Anthony V. Ercolano (Tonye) 12-Sept-1990 + Adam Barr (adamba) 16-Nov-1990 + +Environment: + + Kernel Mode - Or whatever is the equivalent. + +Revision History: + + +--*/ + +#include <ndis.h> + +#include <tfilter.h> +#include <tokhrd.h> +#include <toksft.h> + + +#if DEVL +#define STATIC +#else +#define STATIC static +#endif + +#if DBG +extern INT IbmtokDbg; + +extern UCHAR Packets[5][64]; +extern UCHAR NextPacket; +#endif + + + +#ifdef CHECK_DUP_SENDS + +// +// CHECK_DUP_SENDS enables checking ownership of packets, to +// make sure we are not given the same packet twice, or +// complete the same packet twice. +// + +#define PACKET_LIST_SIZE 50 + +PNDIS_PACKET IbmtokPacketList[PACKET_LIST_SIZE]; +IbmtokPacketListSize = 0; +IbmtokPacketsAdded = 0; +IbmtokPacketsRemoved = 0; + +VOID +IbmtokAddPacketToList( + PIBMTOK_ADAPTER Adapter, + PNDIS_PACKET NewPacket + ) +{ + INT i; + +++IbmtokPacketsAdded; + + for (i=0; i<IbmtokPacketListSize; i++) { + + if (IbmtokPacketList[i] == NewPacket) { + + DbgPrint("IBMTOK: dup send of %lx\n", NewPacket); + + } + + } + + IbmtokPacketList[IbmtokPacketListSize] = NewPacket; + ++IbmtokPacketListSize; + +} + +VOID +IbmtokRemovePacketFromList( + PIBMTOK_ADAPTER Adapter, + PNDIS_PACKET OldPacket + ) +{ + INT i; + +++IbmtokPacketsRemoved; + + for (i=0; i<IbmtokPacketListSize; i++) { + + if (IbmtokPacketList[i] == OldPacket) { + + break; + + } + + } + + if (i == IbmtokPacketListSize) { + + DbgPrint("IBMTOK: bad remove of %lx\n", OldPacket); + + } else { + + --IbmtokPacketListSize; + IbmtokPacketList[i] = IbmtokPacketList[IbmtokPacketListSize]; + + } + +} +#endif // CHECK_DUP_SENDS + + +extern +NDIS_STATUS +IbmtokSend( + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_PACKET Packet + ) + +/*++ + +Routine Description: + + The IbmtokSend request instructs a MAC to transmit a packet through + the adapter onto the medium. + +Arguments: + + MacBindingHandle - The context value returned by the MAC when the + adapter was opened. In reality, it is a pointer to IBMTOK_OPEN. + + Packet - A pointer to a descriptor for the packet that is to be + transmitted. + +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; + + // + // Pointer to the adapter. + // + PIBMTOK_ADAPTER Adapter; + + ULONG PacketLength; + + Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle); + + NdisQueryPacket( + Packet, + NULL, + NULL, + NULL, + &PacketLength + ); + + // + // Check that the packet will go on the wire. Note: I do not + // check that we have enough receive space to receive a packet + // of this size -- it is up to a protocol to work this out. + // + + if ((PacketLength < 14) || + (PacketLength > Adapter->MaxTransmittablePacket)) { + + return(NDIS_STATUS_INVALID_PACKET); + + } + + NdisAcquireSpinLock(&Adapter->Lock); + + Adapter->References++; + + if (Adapter->Unplugged) { + + StatusToReturn = NDIS_STATUS_DEVICE_FAILED; + + } else if (!Adapter->NotAcceptingRequests) { + + PIBMTOK_OPEN Open; + PIBMTOK_RESERVED Reserved = PIBMTOK_RESERVED_FROM_PACKET(Packet); + + Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + + if (!Open->BindingShuttingDown) { + + // + // We do not have to increment the open count. Since we hold + // the lock for the entire function we cannot have the open + // removed out from under us. + // + + // + // NOTE NOTE NOTE !!!!!! + // + // There is an assumption in the code that no pointer + // (which are really handles) to an ndis packet will have + // its low bit set. (Always have even byte alignment.) + // + + ASSERT(!((UINT)Packet & 1)); + + // + // ALL packets go on the wire (loopback is done + // by the card). + // +#ifdef CHECK_DUP_SENDS + IbmtokAddPacketToList(Adapter, Packet); +#endif + + Reserved->MacBindingHandle = MacBindingHandle; + Reserved->Packet = Packet; + + if (Adapter->FirstTransmit == NULL) { + + Adapter->FirstTransmit = Packet; + + } else { + + PIBMTOK_RESERVED_FROM_PACKET(Adapter->LastTransmit)->Next = Packet; + + } + + Adapter->LastTransmit = Packet; + + Reserved->Next = NULL; + + // + // Increment the reference on the open since it + // will be leaving this packet around on the transmit + // queues. + // + + Open->References++; + + // + // This will send the transmit SRB command + // if the SRB is available. + // + + IbmtokProcessSrbRequests( + Adapter + ); + + } 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, + 2 + ); + + } + + } + + + // + // This macro assumes it is called with the lock held, + // and releases it. + // + + IBMTOK_DO_DEFERRED(Adapter); + return StatusToReturn; +} + diff --git a/private/ntos/ndis/ibmtok/sources b/private/ntos/ndis/ibmtok/sources new file mode 100644 index 000000000..1ee4f3023 --- /dev/null +++ b/private/ntos/ndis/ibmtok/sources @@ -0,0 +1,48 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=ndis2 + +TARGETNAME=ibmtok +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=DRIVER + +C_DEFINES=$(C_DEFINES) + +TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib + +INCLUDES=..\inc;..\..\inc + +SOURCES=ibmtok.c \ + interrup.c \ + send.c \ + packet.c \ + transfer.c \ + ibmtok.rc + +RELATIVE_DEPTH=..\.. + +MSC_WARNING_LEVEL=/W3 /WX + diff --git a/private/ntos/ndis/ibmtok/tokhrd.h b/private/ntos/ndis/ibmtok/tokhrd.h new file mode 100644 index 000000000..ab0721177 --- /dev/null +++ b/private/ntos/ndis/ibmtok/tokhrd.h @@ -0,0 +1,667 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + tokhrd.h + +Abstract: + + The hardware-related definitions for the IBMTOK drivers. + + +Author: + + Anthony V. Ercolano (tonye) creation-date 19-Jun-1990 + Adam Barr (adamba) 18-Feb-1991 + +Environment: + + Architecturally, there is an assumption in this driver that we are + on a little endian machine. + +Notes: + + optional-notes + +Revision History: + + Sean Selitrennikoff - 9/??/91 + Added/Changed definitions to allow for Microchannel cards too. + + +--*/ + +#ifndef _IBMTOKHARDWARE_ +#define _IBMTOKHARDWARE_ + +// +// Types of adapters this driver can work with +// +#define IBM_TOKEN_RING_PCMCIA 1 + +// +// Initialization Status Flag Bit Settings +// + +#define RINGSPEEDLISTEN 0x40 + +// +// Token-Ring Controller Configuration Register control bits +// Used by IBM_TOKEN_RING_16_4_CREDIT_CARD_ADAPTER +// +// #define DEFAULT_MMIO 0xD4000 +// #define DEFAULT_RAM 0xD6 +#define DEFAULT_MMIO 0xC2000 +#define DEFAULT_RAM 0xD0 + +#define SHARED_RAM_64K 0xC +#define SHARED_RAM_32K 0x8 +#define SHARED_RAM_16K 0x4 +#define SHARED_RAM_8K 0x0 + +#define RING_SPEED_16_MPS 0x2 +#define RING_SPEED_4_MPS 0x0 + +#define PRIMARY 0x0 +#define ALTERNATE 0x1 + +#define DEFAULT_NIBBLE_2 0x6 + +#define NIBBLE_0 0x00 +#define NIBBLE_1 0x10 +#define NIBBLE_2 0x20 +#define NIBBLE_3 0x30 +#define RELEASE_TR_CONTROLLER 0x40 + + +// +// IBM Token Ring Adapter IDs +// + +#define IBMTOK1_ADAPTER_ID 0xE000 +#define IBMTOK2_ADAPTER_ID 0xE001 + +// +// Start of I/O ports based on which adapter it is. +// + +#define PRIMARY_ADAPTER_OFFSET 0xa20 +#define ALTERNATE_ADAPTER_OFFSET 0xa24 + +// +// Offsets from above of the actual ports used. +// + +#define SWITCH_READ_1 0x000 +#define RESET_LATCH 0x001 +#define SWITCH_READ_2 0x002 +#define RESET_RELEASE 0x002 +#define INTERRUPT_RELEASE_ISA_ONLY 0x003 + + +// +// Registers in the MMIO. These are in the Attachment +// Control Area, which starts at offset 0x1e00 of the ACA. +// + +#define RRR_LOW 0x1e00 +#define RRR_HIGH 0x1e01 +#define WRBR_LOW 0x1e02 +#define WRBR_HIGH 0x1e03 +#define ISRP_LOW 0x1e08 +#define ISRP_LOW_RESET 0x1e28 +#define ISRP_LOW_SET 0x1e48 +#define ISRP_HIGH 0x1e09 +#define ISRP_HIGH_RESET 0x1e29 +#define ISRA_LOW 0x1e0a +#define ISRA_HIGH 0x1e0b +#define ISRA_HIGH_SET 0x1e4b +#define TCR_LOW 0x1e0c +#define TCR_HIGH 0x1e0d +#define TVR_LOW 0x1e0e +#define TVR_HIGH 0x1e0f +#define SRPR_LOW 0x1e18 +#define SRPR_HIGH 0x1e19 + + +// +// These are registers in the AIP (aka the ID PROM), +// which starts at offset 0x1f00 of the ACA. +// + +#define CHANNEL_IDENTIFIER 0x1f30 +#define TOTAL_ADAPTER_RAM 0x1fa6 +#define SHARED_RAM_PAGING 0x1fa8 +#define MAX_4_MBPS_DHB 0x1faa +#define MAX_16_MBPS_DHB 0x1fac + + +// +// Bits in the ISRA Low (even) register. +// + +#define ISRA_LOW_TIMER_INTERRUPT 0x40 +#define ISRA_LOW_INTERRUPT_MASK 0x01 + +// +// Bits in the ISRA High (odd) register. +// + +#define ISRA_HIGH_COMMAND_IN_SRB 0x20 +#define ISRA_HIGH_RESPONSE_IN_ASB 0x10 +#define ISRA_HIGH_SRB_FREE_REQUEST 0x08 +#define ISRA_HIGH_ASB_FREE_REQUEST 0x04 +#define ISRA_HIGH_ARB_FREE 0x02 +#define ISRA_HIGH_SSB_FREE 0x01 + +// +// Bits in the ISRP Low (even) register. +// + +#define ISRP_LOW_NO_CHANNEL_CHECK 0x80 +#define ISRP_LOW_INTERRUPT_ENABLE 0x40 + +// +// Bits in the ISRP High (odd) register. +// + +#define ISRP_HIGH_ADAPTER_CHECK 0x40 +#define ISRP_HIGH_SRB_RESPONSE 0x20 +#define ISRP_HIGH_ASB_FREE 0x10 +#define ISRP_HIGH_ARB_COMMAND 0x08 +#define ISRP_HIGH_SSB_RESPONSE 0x04 + +// +// Bits in the TCR Low (even) register. +// + +#define TCR_LOW_INTERRUPT_MASK 0x80 +#define TCR_LOW_RELOAD_TIMER 0x40 +#define TCR_LOW_COUNTER_ENABLE 0x20 + + +#define WRITE_ADAPTER_REGISTER(a, r, v) \ + NdisWriteRegisterUchar((PUCHAR)((a)->MmioRegion + (r)), (UCHAR)(v)) + +#define READ_ADAPTER_REGISTER(a, r, v) \ + NdisReadRegisterUchar((PUCHAR)(a)->MmioRegion + (r), (PUCHAR)(v)) + + +#define WRITE_ADAPTER_PORT(a, p, v) \ + NdisWritePortUchar((a)->NdisAdapterHandle, (ULONG)((a)->IbmtokPortAddress + (p)), (UCHAR)(v)) + +#define READ_ADAPTER_PORT(a, p, v) \ + NdisReadPortUchar((a)->NdisAdapterHandle, (ULONG)(a)->IbmtokPortAddress + (p), (PUCHAR)(v)) + + + +// +// An IBMSHORT is a short that is in IBM byte ordering, +// with the high and low bytes reversed. +// + +typedef USHORT IBMSHORT; + + +// +// NOTE: These are dangerous because s appears twice in them. +// + +#define READ_IBMSHORT(s) (USHORT)((((PUCHAR)&s)[0] << 8) + ((PUCHAR)&s)[1]) +#define WRITE_IBMSHORT(s, val) {\ + USHORT _tmp; \ + _tmp = (USHORT)((((val) >> 8) & 0xff) | (((val) & 0xff) << 8)); \ + NdisWriteRegisterUshort((PUSHORT)&s, _tmp); \ +} +#define USHORT_TO_IBMSHORT(val) (IBMSHORT)((((val) >> 8) & 0xff) | \ + (((val) & 0xff) << 8)) +#define IBMSHORT_TO_USHORT(val) (USHORT)((((val) >> 8) & 0xff) | \ + (((val) & 0xff) << 8)) + + +// +// An SRAM_PTR is a pointer into the Shared RAM on the adapter. +// It uses the IBM byte ordering. +// + +typedef IBMSHORT SRAM_PTR; + +#define NULL_SRAM_PTR ((SRAM_PTR)0x0000) + +#define SRAM_PTR_TO_PVOID(a, p) \ + ((PVOID)((a)->SharedRam + IBMSHORT_TO_USHORT(p))) + +#define SHARED_RAM_ADDRESS(a, p) \ + ((PVOID)((a)->SharedRam + ((ULONG)(p)))) + + +// +// Macros to deal with the frame status field. +// + +#define GET_FRAME_STATUS_HIGH_AC(Fs) ((UCHAR)(((Fs) & 0xc0) >> 6)) +#define GET_FRAME_STATUS_LOW_AC(Fs) ((UCHAR)(((Fs) & 0x0c) >> 2)) + +#define AC_NOT_RECOGNIZED 0x00 +#define AC_INVALID 0x01 +#define AC_NOT_COPIED 0x10 +#define AC_COPIED 0x11 + + +// +// Some adapters have to have the upper section of the +// Shared RAM zeroed out after initialization. +// + +#define SHARED_RAM_ZERO_OFFSET ((PVOID)0xfe00) +#define SHARED_RAM_ZERO_LENGTH 0x0200 + + +// +// The highest command correlator used by the adapter +// transmit logic. +// + +#define MAX_COMMAND_CORRELATOR 128 + + +// +// This macro is used to set up the SRPR depending on +// the given address (should only be called if it is +// known that the adapter supports Shared RAM Paging!!). +// + +#define SETUP_SRPR(Adapter, Address) \ + WRITE_ADAPTER_REGISTER((Adapter), SRPR_LOW, ((ULONG)(Address) >> 14)) + + +// +// This macro retrieves the part of an address that +// is used once SETUP_SRPR has been called. +// + +#define SHARED_RAM_LOW_BITS(Address) \ + ((ULONG)(Address) & 0x3fff) + + +// +// This macro determines if an address will fit on a +// single Shared RAM page. It makes sure that the beginning +// and end of the sequence have the same high two bits. +// + +#define SINGLE_SHARED_RAM_PAGE(Address, Length) \ + (((ULONG)(Address) & 0xc000) == (((ULONG)(Address)+(Length)-1) & 0xc000)) + + + +// +// Various structures which are read after the adapter +// is reset. +// + +typedef struct _ADAPTER_ADDRESS { + UCHAR NodeAddress[6]; + UCHAR GroupAddress[4]; + UCHAR FunctionalAddress[4]; +} ADAPTER_ADDRESS, * PADAPTER_ADDRESS; + + +typedef struct _ADAPTER_PARAMETERS { + UCHAR PhysicalAddress[4]; + UCHAR NaunNodeAddress[6]; + UCHAR NaunPhysicalAddress[4]; + UCHAR LastPoolAddress[6]; + UCHAR Reserved1[2]; + IBMSHORT TransmitAccessPriority; + IBMSHORT SourceClassAuthorization; + IBMSHORT LastAttentionCode; + UCHAR LastSourceAddress[6]; + IBMSHORT LastBeaconType; + IBMSHORT LastMajorVector; + IBMSHORT RingStatus; + IBMSHORT SoftErrorTimer; + IBMSHORT FrontEndError; + IBMSHORT LocalRingNumber; + IBMSHORT MonitorErrorCode; + IBMSHORT BeaconTransmitType; + IBMSHORT BeaconReceiveType; + IBMSHORT FrameCorrelator; + UCHAR BeaconNaun[6]; + UCHAR Reserved2[4]; + UCHAR BeaconPhysicalAddress[4]; +} ADAPTER_PARAMETERS, * PADAPTER_PARAMETERS; + + +typedef struct _SRB_BRING_UP_RESULT { + UCHAR Command; + UCHAR InitStatus; + UCHAR Reserved1[4]; + IBMSHORT ReturnCode; + SRAM_PTR EncodedAddressPointer; + SRAM_PTR LevelAddressPointer; + SRAM_PTR AdapterAddressPointer; // points to ADAPTER_ADDRESS + SRAM_PTR ParameterAddressPointer; // points to ADAPTER_PARAMETERS + SRAM_PTR MacBufferPointer; +} SRB_BRING_UP_RESULT, * PSRB_BRING_UP_RESULT; + + + + +// +// Structure of the System Request Block as defined +// for various commands. +// + +typedef struct _SRB_GENERIC { + UCHAR Command; + UCHAR Reserved1[1]; + UCHAR ReturnCode; +} SRB_GENERIC, * PSRB_GENERIC; + + +// +// Values for the SRB Command field. +// + +#define SRB_CMD_CLOSE_ADAPTER 0x04 +#define SRB_CMD_INTERRUPT 0x00 +#define SRB_CMD_MODIFY_OPEN_PARMS 0x01 +#define SRB_CMD_OPEN_ADAPTER 0x03 +#define SRB_CMD_CLOSE_ADAPTER 0x04 +#define SRB_CMD_READ_LOG 0x08 +#define SRB_CMD_RESTORE_OPEN_PARMS 0x02 +#define SRB_CMD_SET_FUNCTIONAL_ADDRESS 0x07 +#define SRB_CMD_SET_GROUP_ADDRESS 0x06 +#define SRB_CMD_TRANSMIT_DIR_FRAME 0x0a +#define SRB_CMD_DLC_STATISTICS 0x1e + + +typedef struct _SRB_OPEN_ADAPTER { + UCHAR Command; + UCHAR Reserved1[7]; + IBMSHORT OpenOptions; + UCHAR NodeAddress[6]; + UCHAR GroupAddress[4]; + UCHAR FunctionalAddress[4]; + IBMSHORT ReceiveBufferNum; + IBMSHORT ReceiveBufferLen; + IBMSHORT TransmitBufferLen; + UCHAR TransmitBufferNum; + UCHAR Reserved2[1]; + UCHAR DlcValues[10]; + UCHAR ProductId[18]; +} SRB_OPEN_ADAPTER, * PSRB_OPEN_ADAPTER; + + +typedef struct _SRB_CLOSE_ADAPTER { + UCHAR Command; + UCHAR Reserved1; + UCHAR ReturnCode; +} SRB_CLOSE_ADAPTER, * PSRB_CLOSE_ADAPTER; + + +// +// Bit values for the OpenOptions field (these are +// reversed to be in IBMSHORT format). +// + +#define OPEN_LOOPBACK 0x0080 +#define OPEN_DISABLE_HARD_ERROR 0x0040 +#define OPEN_DISABLE_SOFT_ERROR 0x0020 +#define OPEN_PASS_ADAPTER_MAC 0x0010 +#define OPEN_PASS_ATTENTION_MAC 0x0008 +#define OPEN_CONTENDER 0x0001 +#define OPEN_PASS_BEACON_MAC 0x8000 +#define OPEN_MODIFIED_TOKEN_RELEASE 0x1000 +#define OPEN_REMOTE_PROGRAM_LOAD 0x2000 + + +typedef struct _SRB_OPEN_RESPONSE { + UCHAR Command; + UCHAR Reserved1[1]; + UCHAR ReturnCode; + UCHAR Reserved2[3]; + IBMSHORT ErrorCode; + SRAM_PTR AsbPointer; + SRAM_PTR SrbPointer; + SRAM_PTR ArbPointer; + SRAM_PTR SsbPointer; +} SRB_OPEN_RESPONSE, * PSRB_OPEN_RESPONSE; + + +typedef struct _SRB_TRANSMIT_DIR_FRAME { + UCHAR Command; + UCHAR CommandCorrelator; + UCHAR ReturnCode; + UCHAR Reserved1[1]; + IBMSHORT StationId; +} SRB_TRANSMIT_DIR_FRAME, * PSRB_TRANSMIT_DIR_FRAME; + + +typedef struct _SRB_SET_FUNCT_ADDRESS { + UCHAR Command; + UCHAR Reserved1[1]; + UCHAR ReturnCode; + UCHAR Reserved2[3]; + // + // Making this a TR_FUNCTIONAL_ADDRESS would cause + // the compiler to insert two bytes for alignment. + // + UCHAR FunctionalAddress[4]; +} SRB_SET_FUNCT_ADDRESS, * PSRB_SET_FUNCT_ADDRESS; + + +typedef struct _SRB_SET_GROUP_ADDRESS { + UCHAR Command; + UCHAR Reserved1[1]; + UCHAR ReturnCode; + UCHAR Reserved2[3]; + // + // Making this a TR_FUNCTIONAL_ADDRESS would cause + // the compiler to insert two bytes for alignment. + // + UCHAR GroupAddress[4]; +} SRB_SET_GROUP_ADDRESS, * PSRB_SET_GROUP_ADDRESS; + + +typedef struct _SRB_INTERRUPT { + UCHAR Command; + UCHAR Reserved1[1]; + UCHAR ReturnCode; +} SRB_INTERRUPT, * PSRB_INTERRUPT; + + +typedef struct _SRB_READ_LOG { + UCHAR Command; + UCHAR Reserved1[1]; + UCHAR ReturnCode; + UCHAR Reserved2[3]; + UCHAR LineErrors; + UCHAR InternalErrors; + UCHAR BurstErrors; + UCHAR AcErrors; + UCHAR AbortDelimeters; + UCHAR Reserved3[1]; + UCHAR LostFrames; + UCHAR ReceiveCongestionCount; + UCHAR FrameCopiedErrors; + UCHAR FrequencyErrors; + UCHAR TokenErrors; + UCHAR Reserved4[3]; +} SRB_READ_LOG, * PSRB_READ_LOG; + + +typedef struct _SRB_DLC_STATS{ + UCHAR Command; + UCHAR Reserved1; + UCHAR ReturnCode; + UCHAR Reserved2; + IBMSHORT StationId; + IBMSHORT CountersOffset; + IBMSHORT HeaderAddr; + UCHAR ResetOption; +}SRB_DLC_STATS, *PSRB_DLC_STATS; + + +typedef struct _DLC_COUNTERS{ + IBMSHORT TransmitCount; + IBMSHORT ReceiveCount; + UCHAR TransmitErrors; + UCHAR ReceiveErrors; + IBMSHORT T1Expires; + UCHAR ReceivedCommand; + UCHAR SentCommand; + UCHAR PrimaryState; + UCHAR SecondaryState; + UCHAR SendState; + UCHAR ReceiveState; + UCHAR LastReceivedNr; +}DLC_COUNTERS, *PDLC_COUNTERS; + + + + +// +// Structure of the Adapter Request Block as defined +// for various commands. +// + +typedef struct _ARB_GENERIC { + UCHAR Command; +} ARB_GENERIC, * PARB_GENERIC; + + +// +// Values for the ARB Command field. +// + +#define ARB_CMD_DLC_STATUS 0x83 +#define ARB_CMD_RECEIVED_DATA 0x81 +#define ARB_CMD_RING_STATUS_CHANGE 0x84 +#define ARB_CMD_TRANSMIT_DATA_REQUEST 0x82 + + +typedef struct _ARB_RING_STATUS_CHANGE { + UCHAR Command; + UCHAR Reserved1[5]; + IBMSHORT NetworkStatus; +} ARB_RING_STATUS_CHANGE, * PARB_RING_STATUS_CHANGE; + + +typedef struct _ARB_DLC_STATUS { + UCHAR Command; + UCHAR Reserved1[3]; + IBMSHORT StationId; + IBMSHORT Status; + UCHAR FrmrData[5]; + UCHAR AccessPriority; + UCHAR RemoteAddress[6]; + UCHAR RemoteRsapValue; +} ARB_DLC_STATUS, * PARB_DLC_STATUS; + + +typedef struct _ARB_TRANSMIT_DATA_REQUEST { + UCHAR Command; + UCHAR CommandCorrelator; + UCHAR Reserved1[2]; + IBMSHORT StationId; + SRAM_PTR DhbPointer; +} ARB_TRANSMIT_DATA_REQUEST, * PARB_TRANSMIT_DATA_REQUEST; + + +typedef struct _ARB_RECEIVED_DATA { + UCHAR Command; + UCHAR Reserved1[3]; + IBMSHORT StationId; + SRAM_PTR ReceiveBuffer; // points to a RECEIVE_BUFFER + UCHAR LanHeaderLength; + UCHAR DlcHeaderLength; + IBMSHORT FrameLength; + UCHAR MessageType; +} ARB_RECEIVED_DATA, * PARB_RECEIVED_DATA; + + +typedef struct _RECEIVE_BUFFER { + // + // Leave out the first two reserved bytes. + // + SRAM_PTR NextBuffer; + UCHAR Reserved2[1]; + UCHAR ReceiveFs; + IBMSHORT BufferLength; + UCHAR FrameData[1]; +} RECEIVE_BUFFER, * PRECEIVE_BUFFER; + + + + +// +// Structure of the Adapter Status Block as defined +// for various commands. +// + +typedef struct _ASB_GENERIC { + UCHAR Command; + UCHAR Reserved1[1]; + UCHAR ReturnCode; +} ASB_GENERIC, * PASB_GENERIC; + + +// +// The ASB Command field takes the same values as the +// ARB Command field. +// + +typedef struct _ASB_TRANSMIT_DATA_STATUS { + UCHAR Command; + UCHAR CommandCorrelator; + UCHAR ReturnCode; + UCHAR Reserved1[1]; + IBMSHORT StationId; + IBMSHORT FrameLength; + UCHAR Reserved2[2]; +} ASB_TRANSMIT_DATA_STATUS, * PASB_TRANSMIT_DATA_STATUS; + + +typedef struct _ASB_RECEIVED_DATA_STATUS { + UCHAR Command; + UCHAR Reserved1[1]; + UCHAR ReturnCode; + UCHAR Reserved2[1]; + IBMSHORT StationId; + SRAM_PTR ReceiveBuffer; +} ASB_RECEIVED_DATA_STATUS, * PASB_RECEIVED_DATA_STATUS; + + + + +// +// Structure of the System Status Block as defined +// for various commands. +// + +typedef struct _SSB_GENERIC { + UCHAR Command; +} SSB_GENERIC, * PSSB_GENERIC; + + +// +// The SSB Command field takes the same values as the +// SRB Command field. +// + +typedef struct _SSB_TRANSMIT_COMPLETE { + UCHAR Command; + UCHAR CommandCorrelator; + UCHAR ReturnCode; + UCHAR Reserved1[1]; + IBMSHORT StationId; + UCHAR ErrorFrameStatus; +} SSB_TRANSMIT_COMPLETE, * PSSB_TRANSMIT_COMPLETE; + + + +#endif // _IBMTOKHARDWARE_ diff --git a/private/ntos/ndis/ibmtok/toksft.h b/private/ntos/ndis/ibmtok/toksft.h new file mode 100644 index 000000000..5f120c1d9 --- /dev/null +++ b/private/ntos/ndis/ibmtok/toksft.h @@ -0,0 +1,1373 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + toksft.h + +Abstract: + + The main header for a IBMTOK NDIS driver. + + The overall structure is taken from the Lance driver + by Tony Ercolano. + +Author: + + Anthony V. Ercolano (tonye) creation-date 19-Jun-1990 + Adam Barr (adamba) 20-Nov-1990 + +Environment: + + Architecturally, there is an assumption in this driver that we are + on a little endian machine. + +Notes: + + optional-notes + +Revision History: + + +--*/ + +#ifndef _IBMTOKSFT_ +#define _IBMTOKSFT_ + + +#define IBMTOK_NDIS_MAJOR_VERSION 3 +#define IBMTOK_NDIS_MINOR_VERSION 0 + +#if DBG +#define LOG 1 +#else +#define LOG 0 +#endif + +#if LOG + +// +// Place in the circular buffer. +// +extern UCHAR IbmtokLogPlace; + +// +// Circular buffer for storing log information. +// +extern UCHAR IbmtokLog[]; + +#define IF_LOG(A) {IbmtokLog[IbmtokLogPlace] = (A); \ + IbmtokLog[(IbmtokLogPlace+3) % 255] = '.'; \ + IbmtokLogPlace = (IbmtokLogPlace+1) % 255; } + +#else + +#define IF_LOG(A) + +#endif + +extern const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax; + +#define IBMTOK_ALLOC_PHYS(pp,s) NdisAllocateMemory((PVOID *)(pp),(s),0,HighestAcceptableMax) +#define IBMTOK_FREE_PHYS(p,s) NdisFreeMemory((PVOID)(p),(s),0) +#define IBMTOK_MOVE_MEMORY(Destination,Source,Length) NdisMoveMemory((PVOID)(Destination),(PVOID)(Source),Length) +#define IBMTOK_ZERO_MEMORY(Destination,Length) NdisZeroMemory((PVOID)(Destination),Length) +#define IBMTOK_MOVE_TO_MAPPED_MEMORY(Destination,Source,Length) NdisMoveToMappedMemory((PVOID)(Destination),(PVOID)(Source),Length) +#define IBMTOK_MOVE_FROM_MAPPED_MEMORY(Destination,Source,Length) NdisMoveFromMappedMemory((PVOID)(Destination),(PVOID)(Source),Length) +#define IBMTOK_ZERO_MAPPED_MEMORY(Destination,Length) NdisZeroMappedMemory((PVOID)(Destination),Length) +#define IBMTOK_STORE_ULONG(Destination,Source)\ +{\ + PUCHAR _D = (PUCHAR)(Destination);\ + ULONG _S = (ULONG)(Source);\ + _D[0] = (UCHAR)(_S >> 24);\ + _D[1] = (UCHAR)(_S >> 16);\ + _D[2] = (UCHAR)(_S >> 8);\ + _D[3] = (UCHAR)(_S);\ +} + + +typedef struct _IBMTOK_MAC { + + // + // The handle returned by NdisInitializeWrapper. + // + + NDIS_HANDLE NdisWrapperHandle; + + // + // The handle returned by NdisRegisterMac. + // + + NDIS_HANDLE NdisMacHandle; + +} IBMTOK_MAC, *PIBMTOK_MAC; + + + +// +// This record type is inserted into the MacReserved portion +// of the packet header when the packet is going through the +// staged allocation of buffer space prior to the actual send. +// +typedef struct _IBMTOK_RESERVED { + + // + // Points to the next packet in the chain of queued packets + // waiting for the SRB or the ASB. + // + // The packet will start out on the Transmit queue, + // then move to TransmittingPacket when its transmit is + // in the SRB. When the correlator is assigned it is placed + // in CorrelatorArray (where the Next field is not used), + // and at that time may also be in WaitingForAsb if it + // needs the ASB to acknowledge the copying down of the + // transmit data. Packets are completed out of the + // CorrelatorArray. + // + // + PNDIS_PACKET Next; + + // + // This field holds the binding handle of the open binding + // that submitted this packet for send. + // + NDIS_HANDLE MacBindingHandle; + + // + // This field holds the pointer to the packet so that when + // the send finnaly completes it can be used to indicate to + // the protocol. + // + PNDIS_PACKET Packet; + + // + // TRUE if a command correlator has been assigned for this + // packet. + // + BOOLEAN CorrelatorAssigned; + + // + // The value of the adapter-assigned command correlator. + // + UCHAR CommandCorrelator; + +} IBMTOK_RESERVED,*PIBMTOK_RESERVED; + + +// +// This macro will return a pointer to the reserved portion +// of a packet given a pointer to a packet. +// +#define PIBMTOK_RESERVED_FROM_PACKET(Packet) \ + ((PIBMTOK_RESERVED)((PVOID)((Packet)->MacReserved))) + + + +// +// This structure is inserted into the MacReserved section of the +// NDIS_REQUEST for operations that must pend. Note: the sizeof +// this structure must be less than or equal to 16 bytes. +// +// The flags are broken down as follows.... +// +// Type == IBMTOK_PEND_MAC for requests submitted by the MAC to clear card errors. +// ReadLogPending == TRUE if the MAC submitted a DIR.READ.LOG command. +// ReadLogPending == FALSE if the MAC submitted DLC.STATISTICS. +// +// Type == IBMTOK_PEND_NDIS_CLOSE for request submitted thru Ndis. +// Open, the open that submitted the Ndis request. +// +// Type == IBMTOK_PEND_NDIS_SET_FILTER for request submitted thru Ndis. +// Open, the open that submitted the Ndis request. +// +// Type == IBMTOK_PEND_NDIS_STATISTICS for request submitted thru Ndis. +// ReadLogPending, Boolean if the DIR.READ.LOG command was submitted. +// +// +// +typedef struct _IBMTOK_PEND_DATA{ + + // + // Points to the next request in the chain of queued packets + // waiting for the SRB. + // + // The request will start out on the PendQueue, + // then move to front of the queue when its operation is + // in the SRB. + // + // + struct _IBMTOK_PEND_DATA * Next; + + + union _COMMAND{ + + struct _MAC{ + + // + // Whether the statistics command was a + // DIR.READ.LOG or DLC.STATISTICS + // + + UINT ReadLogPending; + + }MAC; + + union _NDIS{ + + struct _CLOSE{ + + // + // This field holds the open instance which submitted the + // request. + // + + struct _IBMTOK_OPEN *Open; + + // + // This field holds the new filter value. + // + + UINT NewFilterValue; + + + }CLOSE; + + + struct _SET_FILTER{ + + // + // The first two fields of SET_FILTER and SET_ADDRESS need + // to align so that the processing in FinishSetOperation + // is easier. + // + + + // + // This field holds the open instance which submitted the + // request. + // + + struct _IBMTOK_OPEN *Open; + + // + // This field holds the new filter value. + // + + UINT NewFilterValue; + + }SET_FILTER; + + + struct _SET_ADDRESS{ + + // + // The first two fields of SET_FILTER and SET_ADDRESS need + // to align so that the processing in FinishSetOperation + // is easier. + // + + + // + // This field holds the open instance which submitted the + // request. + // + + struct _IBMTOK_OPEN *Open; + + // + // This field holds the new address value. + // + + TR_FUNCTIONAL_ADDRESS NewAddressValue; + + }SET_ADDRESS; + + + struct _STATISTICS{ + + // + // Pointer into NdisRequest at the New filter value. + // + + BOOLEAN ReadLogPending; + + + }STATISTICS; + + }NDIS; + + }COMMAND; + + // + // Buffer to fill in Reserved section so that the next field overlaps + // with the RequestType in the NdisRequest. + // + + ULONG Buffer; + + + NDIS_REQUEST_TYPE RequestType; + + +}IBMTOK_PEND_DATA, *PIBMTOK_PEND_DATA; + +// +// This macro will return a pointer to the reserved area of +// a PNDIS_REQUEST. +// +#define PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(Request) \ + ((PIBMTOK_PEND_DATA)((PVOID)((Request)->MacReserved))) + +// +// This macros returns the enclosing NdisRequest. +// +#define PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp)\ + ((PNDIS_REQUEST)((PVOID)(PendOp))) + +// +// Define Maximum number of bytes a protocol can read during a +// receive data indication. +// +#define IBMTOK_MAX_LOOKAHEAD 240 + + +typedef struct _IBMTOK_ADAPTER { + + // + // Holds the interrupt object for this adapter. + // + NDIS_INTERRUPT Interrupt; + + // + // Flag to tell if the ISR removed the interrupt. + // + UCHAR ContinuousIsrs; + + PVOID WakeUpDpc; + NDIS_TIMER WakeUpTimer; + BOOLEAN SendTimeout; + BOOLEAN RequestTimeout; + UCHAR WakeUpErrorCount; + + // + // Defines whether the adapter is an ISA or PCMCIA adapter. + // + UINT CardType; + + // + // Boolean to turn on/off early token release + // + BOOLEAN EarlyTokenRelease; + + // + // Flag to indicate that the card initialized. + // + BOOLEAN BringUp; + + // + // Spinlock for the interrupt. + // + NDIS_SPIN_LOCK InterruptLock; + + // + // The interrupt level as read from the card. + // + UINT InterruptLevel; + + // + // Is the adapter running at 16 Mbps (versus 4 Mbps). + // + BOOLEAN Running16Mbps; + + // + // Is the adapter using the PC I/O Bus (versus MicroChannel). + // + BOOLEAN UsingPcIoBus; + + // + // Does the upper 512 bytes of the shared RAM have to + // be zeroed after initialization. + // + BOOLEAN UpperSharedRamZero; + + // + // Are we using Shared RAM paging. + // + BOOLEAN SharedRamPaging; + + // + // The size of the RAM on the adapter. + // + ULONG TotalSharedRam; + + // + // The amount of Shared RAM to be mapped in. + // + ULONG MappedSharedRam; + + // + // The maximum size of a DHB at 4 Mbps. + // + USHORT Max4MbpsDhb; + + // + // The maximum size of a DHB at 16 Mbps. + // + USHORT Max16MbpsDhb; + + // + // Value of the RRR Low register (address of Shared Ram). + // + UCHAR RrrLowValue; + +// The following fields are accessed by the ISR and must be aligned to the +// minimum granularity of the architecture on which it runs + +#if defined(_ALPHA_) + + union { + UQUAD _ForceQuadwordAlignment; + struct { + +#endif // defined(_ALPHA_) + + // + // These variables are used to hold bits stored in the ISR + // and read in the DPC. + // + UCHAR IsrpBits; + + // + // These hold ISR bits whose processing is delayed because + // the adapter is not accepting requests. + // + UCHAR IsrpDeferredBits; + + // + // Any Error conditions found in the IsrpLow register + // + UCHAR IsrpLowBits; + +#if defined(_ALPHA_) + + }; + }; + +#endif // defined(_ALPHA_) + +// End of ISR access fields + + // + // This boolean is used as a gate to ensure that only one thread + // of execution is actually processing SRB interrupts + // + BOOLEAN HandleSrbRunning; + + // + // This boolean is used as a gate to ensure that only one thread + // of execution is actually processing SRB interrupts + // + BOOLEAN HandleArbRunning; + + // + // The network address in use. + // + CHAR NetworkAddress[TR_LENGTH_OF_ADDRESS]; + + // + // The network address from the hardware. + // + CHAR PermanentNetworkAddress[TR_LENGTH_OF_ADDRESS]; + + // + // Pointer to the beginning of the IBMTOK ports. + // + ULONG IbmtokPortAddress; + + // + // Keeps a reference count on the current number of uses of + // this adapter block. Uses is defined to be the number of + // routines currently within the "external" interface. + // + UINT References; + + // + // List head for all open bindings for this adapter. + // + LIST_ENTRY OpenBindings; + + // + // List head for all opens that had outstanding references + // when an attempt was made to close them. + // + LIST_ENTRY CloseList; + + // + // List head for all opens that were attempted to be closed + // during a reset. + LIST_ENTRY CloseDuringResetList; + + // + // Spinlock to protect fields in this structure.. + // + NDIS_SPIN_LOCK Lock; + + // + // Handle given by NDIS when the MAC registered itself. + // + NDIS_HANDLE NdisMacHandle; + + // + // Handle given by NDIS when the adapter was registered. + // + NDIS_HANDLE NdisAdapterHandle; + + // + // Pointer to the filter database for the MAC. + // + PTR_FILTER FilterDB; + + // + // Holds queued Pending operations. + // + PIBMTOK_PEND_DATA PendQueue; + + // + // Last pending operation on queue. + // + PIBMTOK_PEND_DATA EndOfPendQueue; + + // + // Pointer to the pended operation that is currently executing. + // + PIBMTOK_PEND_DATA PendData; + + // + // The current packet filter. + // + UINT CurrentPacketFilter; + + // + // The old packet filter (in case of failure to set to a new filter). + // + UINT OldPacketFilter; + + // + // The current functional address requested. + // + TR_FUNCTIONAL_ADDRESS CurrentFunctionalAddress; + + // + // The functional address on the card (may differ + // from CurrentFunctionalAddress if ALL_MULTICAST + // is selected). + // + TR_FUNCTIONAL_ADDRESS CurrentCardFunctional; + + // + // The current group address requested. + // + TR_FUNCTIONAL_ADDRESS CurrentGroupAddress; + + // + // The group address on the card + // + TR_FUNCTIONAL_ADDRESS CurrentCardGroup; + + // + // The address that the MMIO is mapped to. + // + PUCHAR MmioRegion; + + // + // The address that the Shared RAM is mapped to. + // + PUCHAR SharedRam; + + // + // Initial offset of WRB in Shared RAM (contains location + // of bring-up SRB). + // + USHORT InitialWrbOffset; + + // + // Addresses of the Shared RAM structures. + // + PVOID SrbAddress; + PVOID SsbAddress; + PVOID ArbAddress; + PVOID AsbAddress; + + // + // For Shared RAM Paging mode, the SRPR Low value needed + // to talk to each of the Shared RAM structures. + // + UCHAR SrbSrprLow; + UCHAR SsbSrprLow; + UCHAR ArbSrprLow; + UCHAR AsbSrprLow; + + // + // Is the SRB available. + // + BOOLEAN SrbAvailable; + + // + // Is the ASB available. + // + BOOLEAN AsbAvailable; + + // + // The next correlator number which we think we should + // be completing the send for. + // + UCHAR NextCorrelatorToComplete; + + // + // Points to the packet being transmitted if TransmitInSrb + // is TRUE. + // + PNDIS_PACKET TransmittingPacket; + + // + // The receive buffer that is waiting for the ASB. + // + SRAM_PTR ReceiveWaitingForAsbList; + + // + // A SRAM_PTR to the last receive buffer waiting for + // the ASB to indicate completion. + // + SRAM_PTR ReceiveWaitingForAsbEnd; + + + // + // The receive buffer that the transfer data should + // begin at (used during receive indications). + // + SRAM_PTR IndicatedReceiveBuffer; + + // + // Length of the header for this received indication. + // + USHORT IndicatedHeaderLength; + + // + // Should the ASB be used for a receive next. + // + BOOLEAN UseNextAsbForReceive; + + // + // The number of transmit buffers. + // + USHORT NumberOfTransmitBuffers; + + // + // The size of the transmit buffers. + // + USHORT TransmitBufferLength; + + // + // The size of the maximum packet transmittable. + // + UINT MaxTransmittablePacket; + + // + // The number of receive buffers. + // + USHORT NumberOfReceiveBuffers; + + // + // The size of the receive buffers. + // + USHORT ReceiveBufferLength; + + // + // Pointers to the first and last packets at a particular stage + // of allocation. All packets in transmit are linked + // via there next field. + // + // Can only be accessed when the adapter lock + // is held. + // + PNDIS_PACKET FirstTransmit; + PNDIS_PACKET LastTransmit; + + PNDIS_PACKET FirstWaitingForAsb; + PNDIS_PACKET LastWaitingForAsb; + + // + // Holds counter return by DLC.STATISTICS command. + // + + UINT FramesTransmitted; + UINT FramesReceived; + UINT FrameTransmitErrors; + UINT FrameReceiveErrors; + + + // + // Holds counter returned by the DIR.READ.LOG command. + // + UINT LineErrors; + UINT InternalErrors; + UINT BurstErrors; + UINT AcErrors; + UINT AbortDelimeters; + UINT LostFrames; + UINT ReceiveCongestionCount; + UINT FrameCopiedErrors; + UINT FrequencyErrors; + UINT TokenErrors; + + // + // Holds number of different types of RING.STATUS.CHANGE + // indications. + // + UINT SignalLoss; + UINT HardError; + UINT SoftError; + UINT TransmitBeacon; + UINT LobeWireFault; + UINT AutoRemovalError; + UINT RemoveReceived; + UINT CounterOverflow; + UINT SingleStation; + UINT RingRecovery; + + // + // Last ring status indicated to protocols. + // + NDIS_STATUS LastNotifyStatus; + + // + // Current state of the ring. + // + NDIS_802_5_RING_STATE CurrentRingState; + + // + // Flag that when enabled lets routines know that a reset + // is in progress. + // + BOOLEAN ResetInProgress; + + // + // The progress of the reset. + // + UINT CurrentResetStage; + + // + // LookAhead information + // + + ULONG LookAhead; + + // + // TRUE when the ISR is expecting the next interrupt to + // be the one following adapter reset. + // + BOOLEAN ResetInterruptAllowed; + + // + // TRUE when ISR gets the reset interrupt. + // + BOOLEAN ResetInterruptHasArrived; + + // + // Pointer to the binding that initiated the reset. This + // will be null if the reset is initiated by the MAC itself. + // + struct _IBMTOK_OPEN *ResettingOpen; + + // + // Will be true the first time that the hardware is initialized + // by the driver initialization. + // + BOOLEAN FirstInitialization; + + // + // Will be true if the adapter is not yet opened. + // + BOOLEAN AdapterNotOpen; + + // + // Will be true if the driver is being opened. + // + BOOLEAN OpenInProgress; + + // + // TRUE if ResetInProgress or OpenInProgress is TRUE. + // + BOOLEAN NotAcceptingRequests; + + // + // Last Error Code. + // + USHORT OpenErrorCode; + + // + // TRUE if we get a ring status indicating the cable is unplugged. + // + BOOLEAN Unplugged; + + // + // TRUE if we are doing a reset after the cable was unplugged + // to try to reenter the ring. + // + BOOLEAN UnpluggedResetInProgress; + + // + // TRUE if we have gotten a lobe wire fault indication, + // meaning the adapter is closed. + // + BOOLEAN LobeWireFaultIndicated; + + // + // TRUE if there exists an outstanding ASB_FREE_REQUEST + // + BOOLEAN OutstandingAsbFreeRequest; + + // + // The command correlator array (put this at the end since + // it is so big). + // + PNDIS_PACKET CorrelatorArray[MAX_COMMAND_CORRELATOR]; + + // + // IBM_TOKEN_RING_16_4_CREDIT_CARD_ADAPTER specific + // keywords + // + UINT RingSpeed; + ULONG Ram; + UINT RamSize; + ULONG MmioAddress; + BOOLEAN InvalidValue; + BOOLEAN RingSpeedListen; + ULONG RingSpeedRetries; + +} IBMTOK_ADAPTER,*PIBMTOK_ADAPTER; + + +// +// Given a MacBindingHandle this macro returns a pointer to the +// IBMTOK_ADAPTER. +// +#define PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(Handle) \ + (((PIBMTOK_OPEN)((PVOID)(Handle)))->OwningIbmtok) + + +// +// Given a MacContextHandle return the PIBMTOK_ADAPTER +// it represents. +// +#define PIBMTOK_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \ + ((PIBMTOK_ADAPTER)((PVOID)(Handle))) + + +// +// Given a pointer to a IBMTOK_ADAPTER return the +// proper MacContextHandle. +// +#define CONTEXT_HANDLE_FROM_PIBMTOK_ADAPTER(Ptr) \ + ((NDIS_HANDLE)((PVOID)(Ptr))) + + +// +// One of these structures is created on each MacOpenAdapter. +// +typedef struct _IBMTOK_OPEN { + + // + // Linking structure for all of the open bindings of a particular + // adapter. + // + LIST_ENTRY OpenList; + + // + // The Adapter that requested this open binding. + // + PIBMTOK_ADAPTER OwningIbmtok; + + // + // Handle of this adapter in the filter database. + // + NDIS_HANDLE NdisFilterHandle; + + // + // Given by NDIS when the adapter was opened. + // + NDIS_HANDLE NdisBindingContext; + + // + // Counter of all the different reasons that a open binding + // couldn't be closed. This would be incremented each time + // for: + // + // While a particular interface routine is accessing this open + // + // During an indication. + // + // When the open causes a reset. + // + // A packet currently being sent. + // + // (Basically the above two mean any time the open has left + // some processing around to be accomplished later.) + // + // This field should only be accessed when the adapter lock is held. + // + UINT References; + + // + // Minimum Number of bytes for a lookahead. + // + UINT LookAhead; + + // + // A flag indicating that the open has pended. + // + BOOLEAN OpenPending; + + // + // A flag indicating that this binding is in the process of closing. + // + BOOLEAN BindingShuttingDown; + + + // + // A bogus NdisRequest to queue operations during a close. + // + NDIS_REQUEST CloseRequestChangeFilter; + NDIS_REQUEST CloseRequestChangeAddress; + NDIS_REQUEST CloseRequestChangeGroupAddress; + +} IBMTOK_OPEN,*PIBMTOK_OPEN; + + +// +// procedures which do error logging +// + +typedef enum _IBMTOK_PROC_ID{ + registerAdapter, + openAdapter, + hardwareDetails, + handleResetStaging, + handleSrbSsb, + startPendQueueOp, + finishPendQueueOp, + handleDeferred, + ibmtokDpc +}IBMTOK_PROC_ID; + +// +// Error log values +// + +#define IBMTOK_ERRMSG_NOT_FOUND (ULONG)0x01 +#define IBMTOK_ERRMSG_CREATE_DB (ULONG)0x02 +#define IBMTOK_ERRMSG_INIT_INTERRUPT (ULONG)0x03 +#define IBMTOK_ERRMSG_OPEN_DB (ULONG)0x04 +#define IBMTOK_ERRMSG_ALLOC_MEM (ULONG)0x05 +#define IBMTOK_ERRMSG_UNSUPPORTED_RAM (ULONG)0x06 +#define IBMTOK_ERRMSG_BRINGUP_FAILURE (ULONG)0x07 +#define IBMTOK_ERRMSG_INVALID_CMD (ULONG)0x08 +#define IBMTOK_ERRMSG_BAD_OP (ULONG)0x09 +#define IBMTOK_ERRMSG_INVALID_STATUS (ULONG)0x0A +#define IBMTOK_ERRMSG_INVALID_STATE (ULONG)0x0B +#define IBMTOK_ERRMSG_ISRP_LOW_ERROR (ULONG)0x0C + +// +// This macro returns a pointer to a PIBMTOK_OPEN given a MacBindingHandle. +// +#define PIBMTOK_OPEN_FROM_BINDING_HANDLE(Handle) \ + ((PIBMTOK_OPEN)((PVOID)Handle)) + + +// +// This macro returns a NDIS_HANDLE from a PIBMTOK_OPEN +// +#define BINDING_HANDLE_FROM_PIBMTOK_OPEN(Open) \ + ((NDIS_HANDLE)((PVOID)Open)) + + +// +// This macro will act a "epilogue" to every routine in the +// *interface*. It will check whether there any requests needed +// to defer there processing. It will also decrement the reference +// count on the adapter. If the reference count is zero and there +// is deferred work to do it will insert the interrupt processing +// routine in the DPC queue. +// +// Note that we don't need to include checking for blocked receives +// since blocked receives imply that there will eventually be an +// interrupt. +// +// NOTE: This macro assumes that it is called with the lock acquired. +// +#define IBMTOK_DO_DEFERRED(Adapter) \ +{ \ + PIBMTOK_ADAPTER _A = (Adapter); \ + _A->References--; \ + if ((!_A->References) && \ + (_A->ResetInProgress || \ + (!IsListEmpty(&_A->CloseList)))) { \ + IbmtokHandleDeferred(_A); \ + NdisReleaseSpinLock(&_A->Lock); \ + } else { \ + NdisReleaseSpinLock(&_A->Lock); \ + } \ +} + + +//++ +// +// VOID +// SET_INTERRUPT_RESET_FLAG( +// IN PIBMTOK_ADAPTER Adapter, +// ) +// +// +// Routine Description: +// +// This routine uses NdisSynchronizeWithInterrupt to call the +// IbmtokSynchSetReset, which sets the ResetInterruptAllowed +// flag in the adapter structure. This is set after the +// adapter is reset to allow the interrupt indicating the +// end of the reset to come through (since all others +// should be blocked during the reset). +// +// Arguments: +// +// Adapter - The adapter to set the flag for. +// +// Return Value: +// +// None. +// +//-- + +#define SET_INTERRUPT_RESET_FLAG(A) \ +{ \ + PIBMTOK_ADAPTER _A = A; \ + NdisSynchronizeWithInterrupt( \ + &_A->Interrupt, \ + (PVOID) IbmtokSynchSetReset, \ + (PVOID)_A \ + ); \ +} + + +// +// This macro is to clear the SRB/SSB and ARB/ASB bits +// used by the interrupt handlers. +// + +#define CLEAR_ISRP_BITS(A) \ +{ \ + PIBMTOK_ADAPTER _A = A; \ + NdisSynchronizeWithInterrupt( \ + &_A->Interrupt, \ + (PVOID) IbmtokSynchClearIsrpBits, \ + (PVOID)_A \ + ); \ +} + + + +// +// VOID +// IbmtokProcessSrbRequests( +// IN PIBMTOK_ADAPTER Adapter +// ) +// /*++ +// +// Routine Description: +// +// Check if the SRB is available, if so queue the next +// request on it. Preferably, it is called when it is known +// that there is something on the queue. +// +// NOTE: THIS IS CALLED WITH THE LOCK HELD!!! +// +// NOTE: THIS MUST BE CALLED WITH Adapter->SrbAvailable == TRUE !!!!! +// +// Arguments: +// +// Adapter - The Adapter to process interrupts for. +// +// Return Value: +// +// None. +// +// --*/ +// + +#define IbmtokProcessSrbRequests(_Adapter) \ +{ \ + if (_Adapter->SrbAvailable) { \ + (_Adapter)->SrbAvailable = FALSE;\ + SetupSrbCommand(_Adapter); \ + } \ +} + + +// VOID +// PutPacketInCorrelatorArray( +// IN PIBMTOK_ADAPTER Adapter, +// IN PNDIS_PACKET Packet +// ) +// +// /*++ +// +// Routine Description: +// +// This inserts a packet in the correlator array, based +// on the value of its command correlator. +// +// Arguments: +// +// Adapter - The adapter that this packet is coming through. +// +// Packet - The packet that is to be inserted. +// +// Return Value: +// +// None. +// +// --*/ +// +#define PutPacketInCorrelatorArray( _Adapter, _Packet) \ +{ \ + PIBMTOK_RESERVED _Reserved = PIBMTOK_RESERVED_FROM_PACKET(_Packet); \ + ASSERT(_Reserved->CorrelatorAssigned); \ + ASSERT((_Adapter)->CorrelatorArray[_Reserved->CommandCorrelator] == (PNDIS_PACKET)NULL); \ + (_Adapter)->CorrelatorArray[_Reserved->CommandCorrelator] = (_Packet); \ +} + + + +// STATIC +// VOID +// RemovePacketFromCorrelatorArray( +// IN PIBMTOK_ADAPTER Adapter, +// IN PNDIS_PACKET Packet +// ) +// +// /*++ +// +// Routine Description: +// +// This deletes a packet in the correlator array, based +// on the value of its command correlator. +// +// Arguments: +// +// Adapter - The adapter that this packet is coming through. +// +// Packet - The packet that is to be removed. +// +// Return Value: +// +// None. +// +// --*/ +// +#define RemovePacketFromCorrelatorArray(_Adapter, _Packet) \ +{ \ + PIBMTOK_RESERVED _Reserved = PIBMTOK_RESERVED_FROM_PACKET(_Packet); \ + ASSERT(_Reserved->CorrelatorAssigned); \ + _Reserved->CorrelatorAssigned = FALSE; \ + (_Adapter)->CorrelatorArray[_Reserved->CommandCorrelator] = (PNDIS_PACKET)NULL; \ +} + + + + + +// +// We define the external interfaces to the ibmtok driver. +// These routines are only external to permit separate +// compilation. Given a truely fast compiler they could +// all reside in a single file and be static. +// + + +extern +VOID +IbmtokAdjustMaxLookAhead( + IN PIBMTOK_ADAPTER Adapter + ); + + +extern +VOID +IbmtokDPC( + IN PVOID SystemSpecific1, + IN PVOID Context, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ); + +extern +VOID +SetupSrbCommand( + IN PIBMTOK_ADAPTER Adapter + ); + +extern +VOID +IbmtokWakeUpDpc( + IN PVOID SystemSpecific1, + IN PVOID Context, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ); + +extern +BOOLEAN +IbmtokISR( + IN PVOID Context + ); + +extern +VOID +IbmtokHandleDeferred( + IN PIBMTOK_ADAPTER Adapter + ); + +extern +NDIS_STATUS +IbmtokSetPacketFilter( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open, + IN PNDIS_REQUEST NdisRequest, + IN UINT PacketFilter + ); + +extern +NDIS_STATUS +IbmtokChangeFunctionalAddress( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open, + IN PNDIS_REQUEST NdisRequest, + IN PUCHAR Address + ); + +extern +NDIS_STATUS +IbmtokFillInGlobalData( + IN PIBMTOK_ADAPTER Adapter, + IN PNDIS_REQUEST NdisRequest + ); + + +extern +VOID +IbmtokForceAdapterInterrupt( + IN PIBMTOK_ADAPTER Adapter + ); + +extern +VOID +IbmtokSetupForReset( + IN PIBMTOK_ADAPTER Adapter, + IN PIBMTOK_OPEN Open + ); + +extern +VOID +IbmtokStartAdapterReset( + IN PIBMTOK_ADAPTER Adapter + ); + +extern +VOID +IbmtokFinishAdapterReset( + IN PIBMTOK_ADAPTER Adapter + ); + +extern +BOOLEAN +IbmtokSynchSetReset( + IN PVOID Context + ); + +extern +VOID +IbmtokAbortPending( + IN PIBMTOK_ADAPTER Adapter, + IN NDIS_STATUS AbortStatus + ); + +extern +VOID +IbmtokAbortSends( + IN PIBMTOK_ADAPTER Adapter, + IN NDIS_STATUS AbortStatus + ); + +extern +BOOLEAN +IbmtokSynchClearIsrpBits( + IN PVOID Context + ); + +extern +NDIS_STATUS +IbmtokTransferData( + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE MacReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer, + OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred + ); + +extern +NDIS_STATUS +IbmtokSend( + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_PACKET Packet + ); + +extern +VOID +IbmtokCopyFromPacketToBuffer( + IN PNDIS_PACKET Packet, + IN UINT Offset, + IN UINT BytesToCopy, + OUT PCHAR Buffer, + OUT PUINT BytesCopied + ); + +extern +VOID +IbmtokCopyFromBufferToPacket( + IN PCHAR Buffer, + IN UINT BytesToCopy, + IN PNDIS_PACKET Packet, + IN UINT Offset, + OUT PUINT BytesCopied + ); + +extern +VOID +IbmtokCopyFromPacketToPacket( + IN PNDIS_PACKET Destination, + IN UINT DestinationOffset, + IN UINT BytesToCopy, + IN PNDIS_PACKET Source, + IN UINT SourceOffset, + OUT PUINT BytesCopied + ); + +extern +VOID +IbmtokShutdown( + IN PVOID ShutdownContext + ); + +#endif // _IBMTOKSFT_ + diff --git a/private/ntos/ndis/ibmtok/transfer.c b/private/ntos/ndis/ibmtok/transfer.c new file mode 100644 index 000000000..8ae9da411 --- /dev/null +++ b/private/ntos/ndis/ibmtok/transfer.c @@ -0,0 +1,412 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + transfer.c + +Abstract: + + This file contains the code to implement the MacTransferData + API for the ndis 3.0 interface. + +Author: + + Anthony V. Ercolano (Tonye) 12-Sept-1990 + Adam Barr (adamba) 15-Mar-1991 + +Environment: + + Kernel Mode - Or whatever is the equivalent. + +Revision History: + + +--*/ + +#include <ndis.h> + +#include <tfilter.h> +#include <tokhrd.h> +#include <toksft.h> + + +extern +NDIS_STATUS +IbmtokTransferData( + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE MacReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer, + OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred + ) + +/*++ + +Routine Description: + + A protocol calls the IbmtokTransferData request (indirectly via + NdisTransferData) from within its Receive event handler + to instruct the MAC to copy the contents of the received packet + a specified packet buffer. + +Arguments: + + MacBindingHandle - The context value returned by the MAC when the + adapter was opened. In reality this is a pointer to IBMTOK. + + MacReceiveContext - The context value passed by the MAC on its call + to NdisIndicateReceive. The MAC can use this value to determine + which packet, on which adapter, is being received. + + ByteOffset - An unsigned integer specifying the offset within the + received packet at which the copy is to begin. If the entire packet + is to be copied, ByteOffset must be zero. + + BytesToTransfer - An unsigned integer specifying the number of bytes + to copy. It is legal to transfer zero bytes; this has no effect. If + the sum of ByteOffset and BytesToTransfer is greater than the size + of the received packet, then the remainder of the packet (starting from + ByteOffset) is transferred, and the trailing portion of the receive + buffer is not modified. + + Packet - A pointer to a descriptor for the packet storage into which + the MAC is to copy the received packet. + + BytesTransfered - A pointer to an unsigned integer. The MAC writes + the actual number of bytes transferred into this location. This value + is not valid if the return status is STATUS_PENDING. + +Return Value: + + The function value is the status of the operation. + + +--*/ + +{ + + PIBMTOK_ADAPTER Adapter; + + NDIS_STATUS StatusToReturn; + + Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle); + + NdisAcquireSpinLock(&Adapter->Lock); + Adapter->References++; + + if (!Adapter->NotAcceptingRequests) { + + PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + + if (!Open->BindingShuttingDown) { + + // + // The code in this section is quite similar to the + // code in CopyFromPacketToPacket. It could easily go + // into its own routine, except that it is not likely + // to be used in any other implementation. + // + SRAM_PTR SourceReceiveBuffer = + Adapter->IndicatedReceiveBuffer; + + // + // Holds the count of the number of ndis buffers comprising + // the destination packet. + // + UINT DestinationBufferCount; + + // + // Points to the buffer into which we are putting data. + // + PNDIS_BUFFER DestinationCurrentBuffer; + + // + // Holds the virtual address of the current destination + // buffer. + // + PVOID DestinationVirtualAddress; + + // + // Holds the virtual address of the current source buffer. + // + PRECEIVE_BUFFER SourceBufferAddress; + + // + // Holds the address of the data in the current source buffer. + // + PVOID SourceVirtualAddress; + + // + // Holds the length of the current destination buffer. + // + UINT DestinationCurrentLength; + + // + // Holds the length of the current source buffer. + // + UINT SourceCurrentLength; + + // + // Keep a local variable of BytesTransferred so we aren't + // referencing through a pointer. + // + UINT LocalBytesTransferred = 0; + + USHORT PortValue; + + Open->References++; + + NdisReleaseSpinLock(&Adapter->Lock); + + *BytesTransferred = 0; + + ASSERT(sizeof(UINT) >= 2); + ASSERT(sizeof(UINT) == sizeof(NDIS_HANDLE)); + + // + // Get the first buffer of the destination. + // + + NdisQueryPacket( + Packet, + NULL, + &DestinationBufferCount, + &DestinationCurrentBuffer, + NULL + ); + + // + // Could have a null packet. + // + + if (DestinationBufferCount != 0) { + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + // + // Get the information for the first buffer of the source. + // + + SourceBufferAddress = (PRECEIVE_BUFFER) + ((PUCHAR)SRAM_PTR_TO_PVOID(Adapter, + SourceReceiveBuffer) + 2); + + // + // Adjust the address and length to account for the + // header for this frame. + // + + SourceVirtualAddress = + SourceBufferAddress->FrameData + + Adapter->IndicatedHeaderLength; + + NdisReadRegisterUshort(&SourceBufferAddress->BufferLength, + &PortValue + ); + + SourceCurrentLength = IBMSHORT_TO_USHORT(PortValue) - + Adapter->IndicatedHeaderLength; + + + + // + // Take care of boundary condition of zero length copy. + // + + while (LocalBytesTransferred < BytesToTransfer) { + + // + // Check to see whether we've exhausted the current + // destination buffer. If so, move onto the next one. + // + + if (!DestinationCurrentLength) { + + NdisGetNextBuffer( + DestinationCurrentBuffer, + &DestinationCurrentBuffer + ); + + if (!DestinationCurrentBuffer) { + + // + // We've reached the end of the packet. We + // return with what we've done so far. (Which + // must be shorter than requested.) + // + + break; + + } + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + continue; + + } + + + // + // Check to see whether we've exhausted the current + // source buffer. If so, move onto the next one. + // + + if (!SourceCurrentLength) { + + NdisReadRegisterUshort( + &SourceBufferAddress->NextBuffer, + &SourceReceiveBuffer + ); + + if (SourceReceiveBuffer == NULL_SRAM_PTR) { + + // + // We've reached the end of the frame. We + // return with what we've done so far. (Which + // must be shorter than requested.) + // + + break; + + } + + SourceBufferAddress = (PRECEIVE_BUFFER) + SRAM_PTR_TO_PVOID(Adapter, SourceReceiveBuffer); + + SourceVirtualAddress = + (PVOID)SourceBufferAddress->FrameData; + + NdisReadRegisterUshort( + &SourceBufferAddress->BufferLength, + &SourceCurrentLength + ); + + SourceCurrentLength = IBMSHORT_TO_USHORT( + SourceCurrentLength + ); + + continue; + + } + + // + // Try to get us up to the point to start the copy. + // + + if (ByteOffset) { + + if (ByteOffset > SourceCurrentLength) { + + // + // What we want isn't in this buffer. + // + + ByteOffset -= SourceCurrentLength; + SourceCurrentLength = 0; + continue; + + } else { + + SourceVirtualAddress = + (PCHAR)SourceVirtualAddress + ByteOffset; + SourceCurrentLength -= ByteOffset; + ByteOffset = 0; + + } + + } + + // + // Copy the data. + // + + { + + // + // Holds the amount of data to move. + // + UINT AmountToMove; + + // + // Holds the amount desired remaining. + // + UINT Remaining = BytesToTransfer + - LocalBytesTransferred; + + AmountToMove = + ((SourceCurrentLength <= DestinationCurrentLength)? + (SourceCurrentLength):(DestinationCurrentLength)); + + AmountToMove = ((Remaining < AmountToMove)? + (Remaining):(AmountToMove)); + + IBMTOK_MOVE_FROM_MAPPED_MEMORY( + DestinationVirtualAddress, + SourceVirtualAddress, + AmountToMove + ); + + DestinationVirtualAddress = + (PCHAR)DestinationVirtualAddress + AmountToMove; + SourceVirtualAddress = + (PCHAR)SourceVirtualAddress + AmountToMove; + + LocalBytesTransferred += AmountToMove; + SourceCurrentLength -= AmountToMove; + DestinationCurrentLength -= AmountToMove; + + } + + } + + *BytesTransferred = LocalBytesTransferred; + + } + + NdisAcquireSpinLock(&Adapter->Lock); + Open->References--; + StatusToReturn = NDIS_STATUS_SUCCESS; + + } else { + + StatusToReturn = NDIS_STATUS_REQUEST_ABORTED; + + } + + } else { + + if (Adapter->ResetInProgress) { + + StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS; + + } else if (Adapter->OpenInProgress) { + + StatusToReturn = NDIS_STATUS_FAILURE; + + } else { + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + IBMTOK_ERRMSG_INVALID_STATE, + 1 + ); + + } + + } + + IBMTOK_DO_DEFERRED(Adapter); + return StatusToReturn; +} |