Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

706 lines
16 KiB

/*++
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.
Author:
Kevin Martin(KevinMa) 20-Dec-1993
Environment:
Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
Revision History:
--*/
#include <tok162sw.h>
NDIS_STATUS
TOK162ConstrainPacket(
IN PTOK162_ADAPTER Adapter,
IN PNDIS_PACKET Packet,
OUT PTOK162_SUPER_COMMAND_BLOCK CommandBlock
);
NDIS_STATUS
TOK162TransmitPacket(
IN PTOK162_ADAPTER Adapter,
PNDIS_PACKET FirstPacket
);
#if DBG
VOID
PrintTransmitEntry(
IN PTOK162_SUPER_COMMAND_BLOCK TransmitBlock
);
#endif
NDIS_STATUS
TOK162Send(
IN NDIS_HANDLE MiniportAdapterContext,
IN PNDIS_PACKET Packet,
IN UINT Flags
)
/*++
Routine Description:
The TOK162Send request instructs a Miniport to transmit a packet through
the adapter onto the medium.
Arguments:
MiniportAdapterContext - The context value returned by the Miniport when
the adapter was initialized. In reality, it is
a pointer to TOK162_ADAPTER.
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.
--*/
{
//
// Pointer to the adapter.
//
PTOK162_ADAPTER Adapter =
PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
//
// Status returned from TOK162TransmitPacket.
//
NDIS_STATUS Status;
//
// 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.
//
PTOK162_RESERVED Reserved = PTOK162_RESERVED_FROM_PACKET(Packet);
//
// The number of ndis buffers in the packet.
//
UINT NdisBufferCount;
//
// The number of physical buffers in the entire packet.
//
UINT PhysicalBufferCount;
//
// The total amount of data contained within the ndis packet.
//
UINT TotalVirtualLength;
//
// Log the fact that we are entering TOK162Send.
//
IF_LOG('s');
ASSERT(sizeof(TOK162_RESERVED) <= sizeof(Packet->MiniportReserved));
//
// If we are in the middle of a reset, return this fact
//
if (Adapter->ResetInProgress == TRUE) {
return(NDIS_STATUS_RESET_IN_PROGRESS);
}
//
// Determine if and how much adapter space would need to be allocated
// to meet hardware constraints.
//
NdisQueryPacket(
Packet,
&PhysicalBufferCount,
&NdisBufferCount,
NULL,
&TotalVirtualLength
);
//
// See if the packet exceeds TOK162_MAXIMUM_BLOCKS_PER_PACKET.
// Keep in mind that if the total virtual packet length is less than
// MINIMUM_TOKENRING_PACKET_SIZE then we'll have to chain on an
// additional buffer to pad the packet out to the minimum size.
//
if ((PhysicalBufferCount > Adapter->TransmitThreshold) ||
(TotalVirtualLength < MINIMUM_TOKENRING_PACKET_SIZE)) {
Reserved->NdisBuffersToMove = NdisBufferCount;
} else {
Reserved->NdisBuffersToMove = 0;
}
//
// See if we can send it now.
//
Status = TOK162TransmitPacket(Adapter, Packet);
//
// Log the fact that we are leaving TOK162Send
//
IF_LOG('S');
return Status;
}
NDIS_STATUS
TOK162TransmitPacket(
IN PTOK162_ADAPTER Adapter,
PNDIS_PACKET FirstPacket
)
/*++
Routine Description:
This routine attempts to take a packet through a stage of allocation.
Arguments:
Adapter - The adapter that the packets are coming through.
FirstPacket - Packet to be sent.
Return Value:
NDIS_STATUS_RESOURCES - if there are not enough resources
NDIS_STATUS_PENDING - if sending.
--*/
{
//
// Status
//
NDIS_STATUS Status;
//
// If we successfully acquire a command block, this
// is a pointer to it.
//
PTOK162_SUPER_COMMAND_BLOCK CommandBlock;
//
// Points to the reserved portion of the packet.
//
PTOK162_RESERVED Reserved = PTOK162_RESERVED_FROM_PACKET(FirstPacket);
//
// Pointer to the TOK162 data block descriptor being filled.
//
UNALIGNED PTOK162_DATA_BLOCK DataBlock;
//
// The total amount of data in the ndis packet.
//
UINT TotalDataLength;
//
// The number of ndis buffers in the packet.
//
UINT NdisBufferCount;
//
// Points to the current ndis buffer being walked.
//
PNDIS_BUFFER CurrentBuffer;
//
// Log the fact we are in TOK162TransmitPacket.
//
IF_LOG('t');
//
// See if there is a free transmit block
//
if (TOK162AcquireTransmitBlock(
Adapter,
&CommandBlock
)) {
// We have a command block.
// Initialize the general fields of the Command Block.
//
CommandBlock->OwningPacket = FirstPacket;
CommandBlock->NextCommand = NULL;
CommandBlock->Hardware.Status = 0;
CommandBlock->Hardware.NextPending = TOK162_NULL;
CommandBlock->Hardware.CommandCode = CMD_DMA_XMIT;
//
// Check to see if we need to constrain the packet
//
if (PTOK162_RESERVED_FROM_PACKET(
FirstPacket)->NdisBuffersToMove != 0) {
//
// Now we merge the packet into a buffer
//
Status = TOK162ConstrainPacket(Adapter,
FirstPacket,
CommandBlock
);
//
// Otherwise, we will use the map registers and send the packet out
// as is.
//
} else {
//
// Array to hold the physical segments
//
NDIS_PHYSICAL_ADDRESS_UNIT PhysicalSegmentArray[TOK162_MAX_SG];
//
// Number of physical segments in the buffer
//
UINT BufferPhysicalSegments;
//
// map register to use for this buffer
//
UINT CurMapRegister;
//
// Iteration variable
//
UINT i;
//
// Assume we will be successful
//
Status = NDIS_STATUS_SUCCESS;
//
// Get the first buffer as well as the number of ndis buffers in
// the packet.
//
NdisQueryPacket(
FirstPacket,
NULL,
&NdisBufferCount,
&CurrentBuffer,
&TotalDataLength
);
//
// Each packet is sent out complete and is not chained.
//
CommandBlock->Hardware.TransmitEntry.ForwardPointer = 0xFFFFFFFF;
//
// Let the card know this buffer is ready to send.
//
CommandBlock->Hardware.TransmitEntry.CSTAT =
TRANSMIT_CSTAT_REQUEST;
//
// We didn't have to constrain.
//
CommandBlock->UsedTOK162Buffer = FALSE;
//
// Store the frame size.
//
CommandBlock->Hardware.TransmitEntry.FrameSize =
BYTE_SWAP((USHORT)TotalDataLength);
//
// Get the first map register to use
//
CurMapRegister = CommandBlock->CommandBlockIndex *
Adapter->TransmitThreshold;
//
// Go through all of the buffers in the packet getting
// the actual physical buffers from each MDL.
//
DataBlock = (UNALIGNED PTOK162_DATA_BLOCK)
&(CommandBlock->Hardware.TransmitEntry.DataCount1);
while (CurrentBuffer != NULL) {
NdisMStartBufferPhysicalMapping(
Adapter->MiniportAdapterHandle,
CurrentBuffer,
CurMapRegister,
TRUE,
PhysicalSegmentArray,
&BufferPhysicalSegments
);
CurMapRegister++;
//
// Store segments into command block
//
for (i = 0; i < BufferPhysicalSegments ; i++) {
DataBlock->Size =
BYTE_SWAP((USHORT)PhysicalSegmentArray[i].Length + 0x8000);
DataBlock->IBMPhysicalAddress = BYTE_SWAP_ULONG(
NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress));
LOUD_DEBUG(DbgPrint("Address set is %08x\n",DataBlock->IBMPhysicalAddress);)
DataBlock++;
}
//
// Make sure the buffer, if cached, is updated in memory
//
NdisFlushBuffer(CurrentBuffer, TRUE);
//
// Get the next buffer
//
NdisGetNextBuffer(
CurrentBuffer,
&CurrentBuffer
);
}
//
// We'll be one past the last entry, so move back
//
DataBlock--;
//
// Strip off the high bit (already byte_swapped) to let the card
// know this is the last entry.
//
DataBlock->Size &= 0xFF7F;
}
if (Status == NDIS_STATUS_SUCCESS) {
//
// Indicate that we have one more transmit queued
//
Adapter->TransmitsQueued++;
//
// Display the send structure on the debugger
//
EXTRA_LOUD_DEBUG(PrintTransmitEntry(CommandBlock);)
//
// Submit the transmit block to be sent out
//
TOK162SubmitTransmitBlock(
Adapter,
CommandBlock
);
} else {
//
// Log the fact that we have an unsuccessful transmit setup
// and return the error code.
//
IF_LOG('U');
return(Status);
}
//
// No transmit block was available.
//
} else {
//
// Log the fact that we couldn't get a transmit block and return
// RESOURCES error.
//
IF_LOG('u');
return(NDIS_STATUS_RESOURCES);
}
//
// Log that we are leaving TOK162TransmitPacket
//
IF_LOG('T');
LOUD_DEBUG(DbgPrint("Transmit is now set to pending\n");)
//
// Indicate the send has pended.
//
return(NDIS_STATUS_PENDING);
}
NDIS_STATUS
TOK162ConstrainPacket(
IN PTOK162_ADAPTER Adapter,
IN PNDIS_PACKET Packet,
OUT PTOK162_SUPER_COMMAND_BLOCK CommandBlock
)
/*++
Routine Description:
Given a packet and if necessary attempt to acquire adapter
buffer resources so that the packet meets TOK162 hardware/MAC.BIN
contraints.
Arguments:
Adapter - The adapter the packet is coming through.
Packet - The packet whose buffers are to be constrained.
The packet reserved section is filled with information
detailing how the packet needs to be adjusted.
CommandBlock - Command block describing the packet to be sent.
Return Value:
Status - SUCCESS.
--*/
{
//
// Pointer to the reserved section of the packet to be contrained.
//
PTOK162_RESERVED Reserved = PTOK162_RESERVED_FROM_PACKET(Packet);
//
// Will point into the virtual address space addressed
// by the adapter buffer if one was successfully allocated.
//
PCHAR CurrentDestination;
//
// Will hold the total amount of data copied to the
// adapter buffer.
//
UINT TotalDataMoved = 0;
//
// Will point to the current source buffer.
//
PNDIS_BUFFER SourceBuffer;
//
// Points to the virtual address of the source buffers data.
//
PVOID SourceData;
//
// Will point to the number of bytes of data in the source
// buffer.
//
UINT SourceLength;
//
// The total amount of data contained within the ndis packet.
//
UINT TotalVirtualLength;
//
// Simple iteration variable.
//
INT i;
//
// Log that we entered TOK162ConstrainPacket
//
IF_LOG('v');
//
// Indicate that we are using this buffer
//
CommandBlock->UsedTOK162Buffer = TRUE;
//
// Get info on the data to be transmitted.
//
NdisQueryPacket(
Packet,
NULL,
NULL,
&SourceBuffer,
&TotalVirtualLength
);
NdisQueryBuffer(
SourceBuffer,
&SourceData,
&SourceLength
);
//
// There is no link to this transmit list, and
// this list is ready to send.
//
CommandBlock->Hardware.TransmitEntry.ForwardPointer = 0xFFFFFFFF;
CommandBlock->Hardware.TransmitEntry.CSTAT = TRANSMIT_CSTAT_REQUEST;
//
// Set frame size to total virtual length of the packet.
//
CommandBlock->Hardware.TransmitEntry.FrameSize =
BYTE_SWAP(TotalVirtualLength);
//
// Set data count to frame size
//
CommandBlock->Hardware.TransmitEntry.DataCount1 =
CommandBlock->Hardware.TransmitEntry.FrameSize;
//
// Set the address to the buffer associated with this transmit block
//
CommandBlock->Hardware.TransmitEntry.PhysicalAddress1=BYTE_SWAP_ULONG(
NdisGetPhysicalAddressLow(CommandBlock->TOK162BufferPhysicalAddress));
//
// Make sure count fields for the second and third entries are 0.
//
CommandBlock->Hardware.TransmitEntry.DataCount2 = 0x00000000;
CommandBlock->Hardware.TransmitEntry.DataCount3 = 0x00000000;
//
// Fill in the buffer with the data from the users buffers.
//
CurrentDestination = (PVOID)CommandBlock->TOK162BufferAddress;
for (
i = Reserved->NdisBuffersToMove;
i;
i--
) {
NdisMoveMemory(
CurrentDestination,
SourceData,
SourceLength
);
CurrentDestination = (PCHAR)CurrentDestination + SourceLength;
TotalDataMoved += SourceLength;
if (i > 1) {
NdisGetNextBuffer(
SourceBuffer,
&SourceBuffer
);
NdisQueryBuffer(
SourceBuffer,
&SourceData,
&SourceLength
);
}
}
//
// If the packet is less than the minimum TokenRing
// packet size, then clear the remaining part of
// the buffer up to the minimum packet size.
//
if (TotalVirtualLength < MINIMUM_TOKENRING_PACKET_SIZE) {
NdisZeroMemory(
CurrentDestination,
MINIMUM_TOKENRING_PACKET_SIZE - TotalVirtualLength
);
}
//
// Make sure the card and the system are in sync.
//
// The following was removed on 1/26/95 because it causes a hang
// on MIPs machines.
//
// NdisFlushBuffer(CommandBlock->FlushBuffer,TRUE);
//
// Log that we are leaving TOK162ConstrainPacket
//
IF_LOG('V');
return(NDIS_STATUS_SUCCESS);
}
#if DBG
VOID
PrintTransmitEntry(
IN PTOK162_SUPER_COMMAND_BLOCK TransmitBlock
)
/*++
Routine Description:
This routine displays a transmit list on the debug screen
Arguments:
CommandBlock - Pointer to the command block with the transmit list
Return Value:
None.
--*/
{
//
// Pointer to the transmit list portion of the transmit block.
//
TOK162_TRANSMIT_LIST Transmit = TransmitBlock->Hardware.TransmitEntry;
//
// Display all of the information about the send on the debugger.
//
DbgPrint("Forward Pointer = %08lx\n",Transmit.ForwardPointer);
DbgPrint("CSTAT = %x\n" ,Transmit.CSTAT);
DbgPrint("Frame Size = %04x\n" ,Transmit.FrameSize);
DbgPrint("DataCount1 = %04x\n" ,Transmit.DataCount1);
DbgPrint("DataAddress1 = %08lx\n",Transmit.PhysicalAddress1);
DbgPrint("DataCount2 = %04x\n" ,Transmit.DataCount2);
DbgPrint("DataAddress2 = %08lx\n",Transmit.PhysicalAddress2);
DbgPrint("DataCount3 = %04x\n" ,Transmit.DataCount3);
DbgPrint("DataAddress3 = %08lx\n",Transmit.PhysicalAddress3);
}
#endif