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.
3178 lines
94 KiB
3178 lines
94 KiB
//
|
|
// Copyright (c) 1998-1999, Microsoft Corporation, all rights reserved
|
|
//
|
|
// send.c
|
|
//
|
|
// IEEE1394 mini-port/call-manager driver
|
|
//
|
|
// Mini-port Send routines
|
|
//
|
|
// 12/28/1998 ADube Created,
|
|
//
|
|
|
|
//
|
|
// A Send follows this simple algorithm:
|
|
// Copy incoming data to local buffers
|
|
// Create an Mdl for the local copy
|
|
// Store the IRB and VC in the ndispacket
|
|
// Use the ndispacket as context in the irp's completion routine
|
|
//
|
|
|
|
#include <precomp.h>
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Global counts
|
|
//-----------------------------------------------------------------------------
|
|
extern UINT BusSendCompletes;
|
|
extern UINT NicSendCompletes;
|
|
extern UINT BusSends;
|
|
extern ULONG MdlsAllocated[NoMoreCodePaths];
|
|
extern ULONG MdlsFreed[NoMoreCodePaths];
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// prototypes implementations (alphabetically)
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NDIS_STATUS
|
|
nicCopyNdisBufferChainToBuffer(
|
|
IN PNDIS_BUFFER pInBuffer,
|
|
IN OUT PVOID pLocalBuffer,
|
|
IN UINT BufferLength )
|
|
{
|
|
|
|
|
|
//
|
|
// This function copies the data the belongs to the
|
|
// pInMdl chain to the local Buffer.
|
|
// BufferLength is used for validation purposes only
|
|
// Fragmentation and insertion of headers will take place here
|
|
//
|
|
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
|
|
UINT LocalBufferIndex = 0; // Used as an index to the LocalBuffer, used for validation
|
|
UINT MdlLength = 0;
|
|
PVOID MdlAddress = 0;
|
|
PNDIS_BUFFER pCurrBuffer;
|
|
|
|
TRACE( TL_T, TM_Send, ( "==>nicCopyNdisBufferChainToBuffer pNdisbuffer %x, Buffer %x, Length %x",
|
|
pInBuffer, pLocalBuffer,BufferLength ) );
|
|
|
|
ASSERT (pLocalBuffer != NULL);
|
|
|
|
pCurrBuffer = pInBuffer;
|
|
|
|
do
|
|
{
|
|
|
|
MdlLength = nicNdisBufferLength(pCurrBuffer);
|
|
MdlAddress= nicNdisBufferVirtualAddress(pCurrBuffer);
|
|
|
|
if (MdlLength != 0)
|
|
{
|
|
if (MdlAddress == NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
TRACE (TL_A, TM_Send, ("Ndis Buffer at %x", pCurrBuffer) );
|
|
BREAK (TM_Send, (" nicCopyNdisBufferChainToBuffer: Mdl Address = NULL") );
|
|
|
|
}
|
|
|
|
if ( LocalBufferIndex + MdlLength > BufferLength)
|
|
{
|
|
|
|
ASSERT(LocalBufferIndex + MdlLength <= BufferLength);
|
|
|
|
NdisStatus = NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
|
|
BREAK (TM_Send, ("nicCopyNdisBufferChainToBuffer Copy Failed" ) );
|
|
}
|
|
|
|
//
|
|
// Copy the Data to local memory.
|
|
//
|
|
|
|
|
|
NdisMoveMemory((PVOID)((ULONG_PTR)pLocalBuffer+LocalBufferIndex),
|
|
MdlAddress,
|
|
MdlLength);
|
|
|
|
LocalBufferIndex += MdlLength;
|
|
}
|
|
|
|
pCurrBuffer = pCurrBuffer->Next;
|
|
|
|
} while (pCurrBuffer!= NULL);
|
|
|
|
TRACE( TL_T, TM_Send, ( "<==nicCopyNdisBufferChainToBuffer %x",NdisStatus ) );
|
|
|
|
return NdisStatus;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
nicFreeIrb(PIRB pIrb)
|
|
//
|
|
// Frees the Memory occcupied by the Irb
|
|
//
|
|
|
|
{
|
|
ASSERT(pIrb != NULL);
|
|
|
|
TRACE( TL_T, TM_Irp, ( "==>nicFreeIrb %x", pIrb ) );
|
|
|
|
if (pIrb != NULL)
|
|
{
|
|
FREE_NONPAGED(pIrb);
|
|
}
|
|
|
|
TRACE( TL_T, TM_Irp, ( "<==nicFreeIrb") );
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
nicFreeIrp(PIRP pIrp)
|
|
|
|
//
|
|
// Frees the memory occupied by the Irp
|
|
//
|
|
|
|
|
|
{
|
|
ASSERT(pIrp != NULL);
|
|
|
|
TRACE( TL_T, TM_Irp, ( "==>nicFreeIrp at %x",pIrp ) );
|
|
|
|
if (pIrp != NULL)
|
|
{
|
|
IoFreeIrp(pIrp);
|
|
}
|
|
|
|
TRACE( TL_T, TM_Irp, ( "<==nicFreeIrp") );
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
nicFreeLocalBuffer (
|
|
IN UINT Length,
|
|
IN PVOID Address )
|
|
//
|
|
// Free the Memory pointed to by Address.
|
|
// The Length parameter is superfluous and will be removed
|
|
// once I am sure we don;t need it
|
|
//
|
|
{
|
|
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
ASSERT(Address != NULL);
|
|
|
|
TRACE( TL_T, TM_Send, ( "==>nicFreeLocalBuffer , Address %x", Address) );
|
|
|
|
if (Address != NULL)
|
|
{
|
|
FREE_NONPAGED((PVOID)Address);
|
|
}
|
|
|
|
TRACE( TL_T, TM_Send, ( "<==niFreeLocalBuffer, NdisStatus %x",NdisStatus ) );
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
nicFreeMdl(PMDL pMdl)
|
|
//
|
|
// This frees the memory belonging to the Mdl. Does not free the
|
|
// memory that the Mdl Points to
|
|
//
|
|
|
|
{
|
|
|
|
ASSERT (pMdl != NULL)
|
|
|
|
TRACE( TL_T, TM_Send, ( "==> nicFreeMdl pMdl %x", pMdl ) );
|
|
|
|
if (pMdl != NULL)
|
|
{
|
|
IoFreeMdl(pMdl);
|
|
}
|
|
|
|
TRACE( TL_T, TM_Send, ( "<== nicFreeMdl") );
|
|
|
|
return ;
|
|
}
|
|
|
|
VOID
|
|
nicFreeToNPagedLookasideList (
|
|
IN PNIC_NPAGED_LOOKASIDE_LIST pLookasideList,
|
|
IN PVOID pBuffer
|
|
)
|
|
|
|
// Function Description:
|
|
// Return the local buffer to the lookaside list
|
|
//
|
|
// Atguments
|
|
// Lookaside list and its buffer
|
|
// Return Value:
|
|
// None
|
|
{
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "==> nicFreeToNPagedLookasideList , Lookaside list %x, plocalbuffer %x",pLookasideList, pBuffer ) );
|
|
|
|
NdisFreeToNPagedLookasideList (&pLookasideList->List, pBuffer);
|
|
NdisInterlockedDecrement (&pLookasideList->OutstandingPackets);
|
|
|
|
TRACE( TL_T, TM_Send, ( "<== nicFreeToNPagedLookasideList ") );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicGetIrb(
|
|
OUT PIRB *ppIrb )
|
|
|
|
|
|
//
|
|
// This function is to be used in retrieving a free IRB.
|
|
// that will be supplied as an argument for an IRP
|
|
//
|
|
// Initially, this will simple allocate an IRB
|
|
// Intiailization could be added here
|
|
//
|
|
|
|
{
|
|
|
|
NDIS_STATUS NdisStatus;
|
|
|
|
|
|
TRACE( TL_T, TM_Irp, ( "==>nicGetIrb" ) );
|
|
|
|
*ppIrb = (PIRB)ALLOC_NONPAGED ( sizeof(IRB), MTAG_HBUFPOOL );
|
|
|
|
if (*ppIrb != NULL)
|
|
{
|
|
NdisZeroMemory ( *ppIrb, sizeof(IRB) );
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
TRACE( TL_V, TM_Send, ( " nicGetIrb: Irb allocated at %x", *ppIrb ) );
|
|
|
|
}
|
|
else
|
|
{
|
|
nicIncrementMallocFailure();
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
TRACE( TL_T, TM_Irp, ( "<==nicGetIrb NdisStatus %x",NdisStatus ) );
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
nicGetIrp(
|
|
IN PDEVICE_OBJECT pPdo,
|
|
OUT PIRP *ppIrp
|
|
)
|
|
|
|
|
|
//
|
|
// This function returns am irp to the calling routine
|
|
// The irp is free and is owned by the nic1394.
|
|
// NEED TO CHANGE THE STACK SIZE
|
|
//
|
|
{
|
|
|
|
NDIS_STATUS NdisStatus;
|
|
PIRP pIrp;
|
|
CCHAR StackSize =0;
|
|
|
|
ASSERT (pPdo != NULL);
|
|
|
|
TRACE( TL_T, TM_Irp, ( "==>nicGetIrp Pdo %x", pPdo ) );
|
|
|
|
if (pPdo == NULL)
|
|
{
|
|
ASSERT (pPdo != NULL);
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
*ppIrp = NULL;
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate the Irp with the correct stacksize
|
|
//
|
|
StackSize = pPdo->StackSize+1;
|
|
|
|
pIrp = IoAllocateIrp (StackSize, FALSE);
|
|
|
|
do
|
|
{
|
|
|
|
if (pIrp == NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
TRACE( TL_V, TM_Send, ( " Irp allocated at %x, Stacksize %x",pIrp , StackSize ) );
|
|
|
|
*ppIrp = pIrp;
|
|
|
|
//
|
|
// Initialize the Irp
|
|
//
|
|
|
|
IoInitializeIrp ( *ppIrp, sizeof(IRP), StackSize );
|
|
|
|
if (*ppIrp != NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
nicIncrementMallocFailure();
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
TRACE( TL_T, TM_Irp, ( "<==nicGetIrp ,irp %x",*ppIrp ) );
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicGetLocalBuffer(
|
|
OPTIONAL IN ULONG Length,
|
|
OUT PVOID *ppLocalBuffer
|
|
)
|
|
|
|
//
|
|
// This function allocates memory of size 'Length' and returns
|
|
// a pointer to this memory
|
|
//
|
|
{
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
|
|
TRACE( TL_T, TM_Send, ( "==>nicGetLocalBuffer Length %x", Length ) );
|
|
|
|
//
|
|
// There is a bug in the Nic if this is zero
|
|
//
|
|
ASSERT (Length != 0 );
|
|
|
|
|
|
//
|
|
// There is no lookaside list, We need to allocate memory
|
|
//
|
|
*ppLocalBuffer = ALLOC_NONPAGED (Length, MTAG_FBUFPOOL);
|
|
|
|
|
|
if (*ppLocalBuffer != NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
nicIncrementMallocFailure();
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "<==nicGetLocalBuffer, NdisStatus %x at %x",NdisStatus,*ppLocalBuffer ) );
|
|
|
|
return NdisStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PVOID
|
|
nicGetLookasideBuffer(
|
|
IN PNIC_NPAGED_LOOKASIDE_LIST pLookasideList
|
|
)
|
|
// Function Description:
|
|
// Allocate an buffer from the lookaside list.
|
|
// will be changed to a macro
|
|
//
|
|
//
|
|
//
|
|
// Arguments
|
|
// Lookaside list - from which the buffer is allocated
|
|
//
|
|
//
|
|
// Return Value:
|
|
// Return buffer can be NULL
|
|
//
|
|
{
|
|
|
|
PVOID pLocalBuffer = NULL;
|
|
|
|
TRACE( TL_T, TM_Send, ( "==>nicGetLookasideBuffer pLookasideList %x", pLookasideList) );
|
|
|
|
ASSERT (pLookasideList != NULL);
|
|
|
|
//
|
|
// Optimize the lookaside list code path
|
|
//
|
|
pLocalBuffer = NdisAllocateFromNPagedLookasideList (&pLookasideList->List);
|
|
|
|
if (pLocalBuffer != NULL)
|
|
{
|
|
NdisZeroMemory (pLocalBuffer, pLookasideList->Size);
|
|
NdisInterlockedIncrement (&pLookasideList->OutstandingPackets);
|
|
}
|
|
else
|
|
{
|
|
nicIncrementMallocFailure();
|
|
}
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "<==nicGetLookasideBuffer, %x", pLocalBuffer ) );
|
|
|
|
return pLocalBuffer ;
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicGetMdl(
|
|
IN UINT Length,
|
|
IN PVOID pLocalBuffer,
|
|
OUT PMDL *ppMyMdl)
|
|
|
|
|
|
//
|
|
// Return a locally owned Mdl to the caller.
|
|
// This will also initialize the MDl with the localbuffer
|
|
// Initial implementation will allocate mdls
|
|
//
|
|
{
|
|
|
|
NDIS_STATUS NdisStatus;
|
|
|
|
TRACE( TL_T, TM_Send, ( "==>nicGetMdl" ) );
|
|
|
|
ASSERT(pLocalBuffer != NULL);
|
|
|
|
//
|
|
// Allocate an MDl to point to the structure
|
|
//
|
|
(*ppMyMdl) = IoAllocateMdl( pLocalBuffer,
|
|
Length,
|
|
FALSE,
|
|
FALSE,
|
|
NULL );
|
|
|
|
//
|
|
// Initialize the data structures with correct values
|
|
//
|
|
|
|
if (*ppMyMdl != NULL)
|
|
{
|
|
MmBuildMdlForNonPagedPool(*ppMyMdl);
|
|
|
|
(*ppMyMdl)->Next = NULL;
|
|
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
nicIncrementMallocFailure();
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
*ppMyMdl = NULL;
|
|
}
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "<==nicGetMdl, Mdl %x, LocalBuffer %x",
|
|
*ppMyMdl, pLocalBuffer) );
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicInitAsyncStreamIrb(
|
|
IN PCHANNEL_VCCB pChannelVc,
|
|
IN PMDL pMdl,
|
|
IN OUT PIRB pIrb
|
|
)
|
|
|
|
// This function initializes the Irb that will be used in the Irb
|
|
// It specifically handles the AsyncStream IRB
|
|
// It arguments are the Vc block (for destination address),
|
|
// Mdl (Memory desctiptor for the data and a pointer to the
|
|
// Irb structure that will be initialized
|
|
|
|
|
|
|
|
|
|
{
|
|
ASSERT (pMdl != NULL);
|
|
ASSERT (pIrb != NULL);
|
|
|
|
NdisZeroMemory (pIrb, sizeof (IRB) );
|
|
pIrb->FunctionNumber = REQUEST_ASYNC_STREAM;
|
|
pIrb->Flags = 0;
|
|
pIrb->u.AsyncStream.nNumberOfBytesToStream = MmGetMdlByteCount(pMdl);
|
|
pIrb->u.AsyncStream.fulFlags = 0;
|
|
|
|
//
|
|
// See comments for ISOCH_TAG
|
|
//
|
|
pIrb->u.AsyncStream.ulTag = g_IsochTag;
|
|
pIrb->u.AsyncStream.nChannel = pChannelVc->Channel;
|
|
pIrb->u.AsyncStream.ulSynch = pChannelVc->ulSynch;
|
|
pIrb->u.AsyncStream.nSpeed = (INT)pChannelVc->Speed;
|
|
pIrb->u.AsyncStream.Mdl = pMdl;
|
|
|
|
|
|
|
|
TRACE( TL_V, TM_Send, ( "Number of Bytes to Stream %x ", pIrb->u.AsyncStream.nNumberOfBytesToStream ) );
|
|
TRACE( TL_V, TM_Send, ( "fulFlags %x ", pIrb->u.AsyncStream.fulFlags ) );
|
|
TRACE( TL_V, TM_Send, ( "ulTag %x ", pIrb->u.AsyncStream.ulTag ) );
|
|
TRACE( TL_V, TM_Send, ( "Channel %x", pIrb->u.AsyncStream.nChannel ) );
|
|
TRACE( TL_V, TM_Send, ( "Synch %x", pIrb->u.AsyncStream.ulSynch ) );
|
|
TRACE( TL_V, TM_Send, ( "Speed %x", pIrb->u.AsyncStream.nSpeed ) );
|
|
TRACE( TL_V, TM_Send, ( "Mdl %x", pIrb->u.AsyncStream.Mdl ) );
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
nicInitAsyncWriteIrb(
|
|
IN PSENDFIFO_VCCB pSendFIFOVc,
|
|
IN PMDL pMyMdl,
|
|
IN OUT PIRB pMyIrb
|
|
)
|
|
|
|
// This function initializes the Irb that will be used in the Irb
|
|
// It specifically handles the AsyncWrite IRB
|
|
// It arguments are the Vc block (for destination address),
|
|
// Mdl (Memory desctiptor for the data and a pointer to the
|
|
// Irb structure that will be initialized
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
//
|
|
// Sanity check
|
|
//
|
|
ASSERT ((*(PULONG)pMyIrb) == 0)
|
|
|
|
pMyIrb->u.AsyncWrite.nNumberOfBytesToWrite = MmGetMdlByteCount(pMyMdl);
|
|
pMyIrb->u.AsyncWrite.nBlockSize = 0;
|
|
pMyIrb->u.AsyncWrite.fulFlags = 0;
|
|
pMyIrb->u.AsyncWrite.Mdl = pMyMdl;
|
|
|
|
pMyIrb->FunctionNumber = REQUEST_ASYNC_WRITE;
|
|
pMyIrb->Flags = 0;
|
|
pMyIrb->u.AsyncWrite.nSpeed = (UCHAR)pSendFIFOVc->MaxSendSpeed ;
|
|
|
|
pMyIrb->u.AsyncWrite.DestinationAddress.IA_Destination_Offset.Off_High = pSendFIFOVc->FifoAddress.Off_High;
|
|
pMyIrb->u.AsyncWrite.DestinationAddress.IA_Destination_Offset.Off_Low = pSendFIFOVc->FifoAddress.Off_Low;
|
|
pMyIrb->u.AsyncWrite.ulGeneration = *pSendFIFOVc->Hdr.pGeneration;
|
|
|
|
|
|
pMyIrb->u.AsyncWrite.nBlockSize = 0;
|
|
pMyIrb->u.AsyncWrite.fulFlags = ASYNC_FLAGS_NONINCREMENTING;
|
|
|
|
pMyIrb->u.AsyncWrite.DestinationAddress.IA_Destination_ID.NA_Bus_Number = 0x3ff;
|
|
|
|
|
|
|
|
TRACE(TL_V, TM_Send, ("DestinationAddress.IA_Destination_ID.NA_Bus_Number = 0x%x\n", pMyIrb->u.AsyncWrite.DestinationAddress.IA_Destination_ID.NA_Bus_Number) );
|
|
TRACE(TL_V, TM_Send, ("DestinationAddress.IA_Destination_ID.NA_Node_Number = 0x%x\n", pMyIrb->u.AsyncWrite.DestinationAddress.IA_Destination_ID.NA_Node_Number) );
|
|
TRACE(TL_V, TM_Send, ("DestinationAddress.IA_Destination_Offset.Off_High = 0x%x at 0x%x\n", pMyIrb->u.AsyncWrite.DestinationAddress.IA_Destination_Offset.Off_High, &pMyIrb->u.AsyncWrite.DestinationAddress.IA_Destination_Offset.Off_High) );
|
|
TRACE(TL_V, TM_Send, ("DestinationAddress.IA_Destination_Offset.Off_Low = 0x%x at 0x%x\n", pMyIrb->u.AsyncWrite.DestinationAddress.IA_Destination_Offset.Off_Low,&pMyIrb->u.AsyncWrite.DestinationAddress.IA_Destination_Offset.Off_Low) );
|
|
TRACE(TL_V, TM_Send, ("nNumberOfBytesToWrite = 0x%x\n", pMyIrb->u.AsyncWrite.nNumberOfBytesToWrite));
|
|
TRACE(TL_V, TM_Send, ("nBlockSize = 0x%x\n", pMyIrb->u.AsyncWrite.nBlockSize));
|
|
TRACE(TL_V, TM_Send, ("fulFlags = 0x%x\n", pMyIrb->u.AsyncWrite.fulFlags));
|
|
TRACE(TL_V, TM_Send, ("Mdl = 0x%x\n", pMyIrb->u.AsyncWrite.Mdl ));
|
|
TRACE(TL_V, TM_Send, ("ulGeneration = 0x%x at 0x%x \n", pMyIrb->u.AsyncWrite.ulGeneration, &pMyIrb->u.AsyncWrite.ulGeneration));
|
|
TRACE(TL_V, TM_Send, ("chPriority = 0x%x\n", pMyIrb->u.AsyncWrite.chPriority));
|
|
TRACE(TL_V, TM_Send, ("nSpeed = 0x%x\n", pMyIrb->u.AsyncWrite.nSpeed));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
DummySendPacketsHandler(
|
|
IN PVCCB pVc,
|
|
IN PNDIS_PACKET pPacket
|
|
)
|
|
//
|
|
// To be used on a non-send VC
|
|
//
|
|
{
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicSendFailureInvalidGeneration(
|
|
PVCCB pVc
|
|
)
|
|
|
|
|
|
// Function Description:
|
|
//
|
|
// An AsyncStream or AnsyncWrite Irp may be completed
|
|
// with a status of InvalidGeneration. This function will try and
|
|
// get a new generation, so that future sends will not be blocked
|
|
//
|
|
// Arguments
|
|
//
|
|
//
|
|
//
|
|
// Return Value:
|
|
//
|
|
//
|
|
//
|
|
//
|
|
|
|
{
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter;
|
|
|
|
TRACE( TL_T, TM_Send, ( "==>nicSendFailureInvalidGeneration ") );
|
|
|
|
ASSERT (pVc != NULL);
|
|
|
|
do
|
|
{
|
|
PNDIS_WORK_ITEM pGetGenerationWorkItem = NULL;
|
|
BOOLEAN fWorkItemAlreadyLaunched = FALSE;
|
|
BOOLEAN fQueueWorkItem = FALSE;
|
|
|
|
|
|
TRACE( TL_A, TM_Send, ( "Cause: Invalid generation on the asyncwrite packet" ) );
|
|
|
|
VC_ACQUIRE_LOCK (pVc);
|
|
|
|
if (VC_ACTIVE(pVc) == TRUE)
|
|
{
|
|
fQueueWorkItem = TRUE;
|
|
}
|
|
|
|
fWorkItemAlreadyLaunched = (VC_TEST_FLAGS (pVc, VCBF_GenerationWorkItem));
|
|
|
|
if (fWorkItemAlreadyLaunched)
|
|
{
|
|
//
|
|
// If the Work Item has already been launched, then do not launch another instance
|
|
//
|
|
fQueueWorkItem = FALSE;
|
|
}
|
|
|
|
if ( fQueueWorkItem )
|
|
{
|
|
nicReferenceCall (pVc, "nicSendFailureInvalidGeneration");
|
|
}
|
|
|
|
VC_RELEASE_LOCK (pVc);
|
|
|
|
|
|
|
|
if (fQueueWorkItem == FALSE)
|
|
{
|
|
// this thread simply exits
|
|
break;
|
|
}
|
|
//
|
|
// We need to update the generation count
|
|
//
|
|
pGetGenerationWorkItem = ALLOC_NONPAGED (sizeof(NDIS_WORK_ITEM), MTAG_WORKITEM);
|
|
|
|
if (pGetGenerationWorkItem == NULL)
|
|
{
|
|
TRACE( TL_A, TM_Cm, ( "Local Alloc failed for WorkItem - GetGeneration FAILED" ) );
|
|
|
|
break;
|
|
}
|
|
|
|
VC_ACQUIRE_LOCK (pVc);
|
|
|
|
VC_SET_FLAG(pVc, VCBF_GenerationWorkItem );
|
|
|
|
VC_RELEASE_LOCK (pVc);
|
|
|
|
NdisInitializeWorkItem ( pGetGenerationWorkItem ,
|
|
(NDIS_PROC)nicGetGenerationWorkItem,
|
|
(PVOID)pVc );
|
|
NdisInterlockedIncrement(&pAdapter->OutstandingWorkItems);
|
|
|
|
NdisScheduleWorkItem (pGetGenerationWorkItem );
|
|
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "<==nicSendFailureInvalidGeneration %x", NdisStatus) );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
nicMakeGaspHeader (
|
|
IN PADAPTERCB pAdapter,
|
|
IN PGASP_HEADER pGaspHeader
|
|
)
|
|
// Function Description:
|
|
// This function will take the adapter structure and construct a Gasp Header out of it.
|
|
// This will be used to make the AsyncStream packets.
|
|
//
|
|
//
|
|
//
|
|
// Arguments
|
|
// pAdapter - Local Host in question
|
|
// pGaspHeader - Location where the Gasp Header is to be stored
|
|
//
|
|
// Return Value:
|
|
// None
|
|
//
|
|
|
|
{
|
|
USHORT SourceID;
|
|
NODE_ADDRESS LocalNodeAddress;
|
|
NDIS_STATUS NdisStatus;
|
|
|
|
TRACE( TL_T, TM_Send, ( "==>nicMakeGaspHeader padapter %x, pGaspNdisBuffer %x ", pAdapter, pGaspHeader) );
|
|
|
|
ASSERT (pGaspHeader != NULL);
|
|
|
|
|
|
TRACE( TL_V, TM_Send, ( "pAdapter->NodeAddress %x", pAdapter->NodeAddress) );
|
|
|
|
|
|
SourceID = *((PUSHORT)&pAdapter->NodeAddress);
|
|
|
|
if(SourceID ==0)
|
|
{
|
|
NdisStatus = nicGet1394AddressFromDeviceObject (pAdapter->pNextDeviceObject,
|
|
&LocalNodeAddress,
|
|
USE_LOCAL_NODE);
|
|
|
|
if ( NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
SourceID = *((PUSHORT)&LocalNodeAddress);
|
|
|
|
ADAPTER_ACQUIRE_LOCK (pAdapter);
|
|
|
|
pAdapter->NodeAddress = LocalNodeAddress;
|
|
|
|
ADAPTER_RELEASE_LOCK (pAdapter);
|
|
}
|
|
//
|
|
// Do not handle failure. As the BCM or a Reset will fix this problem
|
|
//
|
|
}
|
|
|
|
|
|
TRACE( TL_V, TM_Send, ( "SourceId %x at %x", SourceID, &SourceID) );
|
|
|
|
pGaspHeader->FirstQuadlet.Bitmap.GH_Source_ID = SourceID ;
|
|
|
|
pGaspHeader->FirstQuadlet.Bitmap.GH_Specifier_ID_Hi = GASP_SPECIFIER_ID_HI;
|
|
|
|
pGaspHeader->SecondQuadlet.Bitmap.GH_Specifier_ID_Lo = GASP_SPECIFIER_ID_LO;
|
|
|
|
pGaspHeader->SecondQuadlet.Bitmap.GH_Version = 1;
|
|
|
|
pGaspHeader->FirstQuadlet.GaspHeaderHigh = SWAPBYTES_ULONG (pGaspHeader->FirstQuadlet.GaspHeaderHigh );
|
|
pGaspHeader->SecondQuadlet.GaspHeaderLow = SWAPBYTES_ULONG (pGaspHeader->SecondQuadlet.GaspHeaderLow );
|
|
|
|
TRACE( TL_V, TM_Send, ( "Gasp Header High %x", pGaspHeader->FirstQuadlet.GaspHeaderHigh) );
|
|
TRACE( TL_V, TM_Send, ( "Gasp Header Low %x", pGaspHeader->SecondQuadlet.GaspHeaderLow ) );
|
|
|
|
TRACE( TL_T, TM_Send, ( "<==nicFreeGaspHeader %x, %x ", pGaspHeader->FirstQuadlet.GaspHeaderHigh, pGaspHeader->SecondQuadlet.GaspHeaderLow ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AsyncWriteStreamSendComplete(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP pMyIrp,
|
|
IN PVOID Context
|
|
)
|
|
|
|
|
|
//
|
|
// N.B. this completes both Fifo and channels
|
|
//
|
|
//
|
|
// This function is Completion handler for the Irp used to send data.
|
|
// This function will invoke NDisCoSendComplete Handler
|
|
// Needs to use the VC Handle stored in the MiniportReserved[0]
|
|
// of the packet.
|
|
// We free all the data structures allocated on the way down,
|
|
// by SendPacketsHandler (the Irb. Irp and Local memory used and Mdl)
|
|
//
|
|
// The LookasideHeader->OutstandingFragments should normally be one for
|
|
// the defualt ( non-fragmented) case. However, if a failure in SendPackets
|
|
// occurs, Outstanding fragments will be zero or the context will be null,
|
|
// in that case we will only free the lookaside buffer (if it exists) and exit,
|
|
// it will be the responsibility of the SendPacketsHandler
|
|
// to fail the packet.
|
|
//
|
|
|
|
{
|
|
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
|
|
NTSTATUS IrpStatus = STATUS_UNSUCCESSFUL;
|
|
PVOID pLookasideListBuffer = Context;
|
|
PLOOKASIDE_BUFFER_HEADER pLookasideHeader = (PLOOKASIDE_BUFFER_HEADER)pLookasideListBuffer ;
|
|
PNDIS_PACKET pPacket = NULL;
|
|
PVCCB pVc = NULL;
|
|
PREMOTE_NODE pRemoteNode = NULL;
|
|
NDIS_HANDLE NdisVcHandle = NULL;
|
|
ULONG OutstandingFragments = 0;
|
|
BUS_OPERATION AsyncOp;
|
|
PNIC_NPAGED_LOOKASIDE_LIST pLookasideList = NULL;
|
|
STORE_CURRENT_IRQL;
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "==>AsyncWriteStreamSendComplete, pMyIrp %x, Context %x",
|
|
pMyIrp, Context ) );
|
|
|
|
do
|
|
{
|
|
if (pLookasideHeader == NULL)
|
|
{
|
|
TRACE( TL_V, TM_Send, ( " AsyncSendComplete - pLookasideHeader == NULL") );
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// This means that a lookaside buffer was allocated and
|
|
// perhaps MDLS were allocated
|
|
// if this is the last fragment, Free all the MDLs first
|
|
//
|
|
|
|
//
|
|
// Get all the valuable information out of the header.
|
|
//
|
|
|
|
pPacket = pLookasideHeader->pNdisPacket;
|
|
pVc = pLookasideHeader->pVc;
|
|
pRemoteNode = pVc->Hdr.pRemoteNode;
|
|
pLookasideList = pLookasideHeader->pLookasideList;
|
|
AsyncOp = pLookasideHeader->AsyncOp;
|
|
|
|
ASSERT (AsyncOp != InvalidOperation);
|
|
|
|
TRACE( TL_V, TM_Send, ( " Vc %x,, pLookaside Buffer %x, pPacket, %x",
|
|
pVc, pLookasideHeader ,pPacket ) );
|
|
|
|
ASSERT (pLookasideList != NULL);
|
|
|
|
//
|
|
// This will tell us if this thread has received the last fragment
|
|
// OustandingPackets == 0 gets to free the MDLS, and complete the packet
|
|
//
|
|
OutstandingFragments = NdisInterlockedDecrement (&pLookasideHeader->OutstandingFragments );
|
|
|
|
|
|
if (OutstandingFragments == 0)
|
|
{
|
|
//
|
|
// If there are no more fragments, then we need to
|
|
// free all the allocated structures ( the MDLS) on this buffer
|
|
//
|
|
|
|
ULONG MdlsToFree = pLookasideHeader->FragmentsGenerated;
|
|
|
|
PIRB pIrb = &((PUNFRAGMENTED_BUFFER)pLookasideHeader)->Irb;
|
|
|
|
|
|
//
|
|
// The maximum number of MDLS we can have is equal to
|
|
// the maximum number of Fragments that were generated
|
|
//
|
|
while (MdlsToFree != 0)
|
|
{
|
|
PMDL pMdl = NULL;
|
|
|
|
GET_MDL_FROM_IRB (pMdl, pIrb, AsyncOp);
|
|
|
|
|
|
TRACE( TL_V, TM_Send, ( " Freeing Mdl %x of Irb %x ",
|
|
pMdl, pIrb) );
|
|
|
|
|
|
if (pMdl != NULL)
|
|
{
|
|
nicFreeMdl (pMdl);
|
|
if (pVc->Hdr.VcType == NIC1394_SendFIFO)
|
|
{
|
|
nicDecFifoSendMdl();
|
|
}
|
|
else
|
|
{
|
|
nicDecChannelSendMdl();
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Set up for the next iteration
|
|
//
|
|
MdlsToFree --;
|
|
|
|
pIrb = (PVOID)((ULONG_PTR)pIrb + sizeof (IRB));
|
|
|
|
|
|
} //while (MdlsToFree != 0)
|
|
|
|
|
|
|
|
} //if (OutstandingFragments == 0)
|
|
|
|
|
|
//
|
|
// Map the NT_STATUS belonging to the Irp to an NdisStatus and call NdisMCoSendComplete
|
|
// Print Debug Output to help in testing. Need to Add more status cases
|
|
//
|
|
if (pMyIrp == NULL)
|
|
{
|
|
TRACE( TL_V, TM_Send, ( " AsyncSendComplete - pIrp is NULL") );
|
|
IrpStatus = STATUS_UNSUCCESSFUL;
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
//
|
|
// We have a valid IRP, lets see if we failed the IRP and why
|
|
//
|
|
IrpStatus = pMyIrp->IoStatus.Status;
|
|
|
|
nicIncrementBusSendCompletes(pVc);
|
|
}
|
|
|
|
if (IrpStatus != STATUS_SUCCESS)
|
|
{
|
|
TRACE( TL_A, TM_Send, ( "==>IRP FAILED StatusCode = %x",IrpStatus ) );
|
|
|
|
nicIncrementBusFailure();
|
|
nicIncrementVcBusSendFailures(pVc, pPacket);
|
|
|
|
//
|
|
// The generation of the bus has changed. Lets get a new one.
|
|
//
|
|
|
|
if (IrpStatus == STATUS_INVALID_GENERATION)
|
|
{
|
|
nicSendFailureInvalidGeneration((PVCCB)pVc);
|
|
}
|
|
|
|
NdisStatus = NtStatusToNdisStatus(IrpStatus);
|
|
|
|
NdisInterlockedIncrement (&pVc->Hdr.pAF->pAdapter->AdaptStats.ulXmitError);
|
|
}
|
|
else
|
|
{
|
|
NdisInterlockedIncrement(&pVc->Hdr.pAF->pAdapter->AdaptStats.ulXmitOk);
|
|
nicIncrementVcBusSendSucess(pVc, pPacket);
|
|
}
|
|
|
|
//
|
|
// Free the Irp and don't touch it after this
|
|
//
|
|
if (pMyIrp != NULL)
|
|
{
|
|
nicFreeIrp (pMyIrp);
|
|
pMyIrp = NULL;
|
|
}
|
|
|
|
//
|
|
// At this point, we know that the IRP went down to the bus driver
|
|
// We know if this is the last fragment. So lets figure out if we need
|
|
// to Complete the packet
|
|
//
|
|
|
|
if (OutstandingFragments != 0)
|
|
{
|
|
//
|
|
// We need to wait for other fragments to complete
|
|
//
|
|
TRACE( TL_V, TM_Send, ( " AsyncSendComplete = NOT the last fragment") );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// This means that this thread has marked the lookaside header as 'to be freed'
|
|
// and it is this thread's responsibility to free it.
|
|
//
|
|
NdisVcHandle = pVc->Hdr.NdisVcHandle;
|
|
|
|
TRACE( TL_V, TM_Send, ( "Calling NdisCoSendComplete, status %x, VcHandle %x, pPacket %x",
|
|
NdisStatus,NdisVcHandle, pPacket ) );
|
|
|
|
|
|
nicMpCoSendComplete (NdisStatus,
|
|
pVc,
|
|
pPacket);
|
|
|
|
|
|
nicFreeToNPagedLookasideList (pLookasideList, pLookasideListBuffer);
|
|
|
|
nicDereferenceCall (pVc, "AsyncWriteStreamSendComplete");
|
|
|
|
//
|
|
// Remove the reference on the PDO that the IRP was sent to
|
|
//
|
|
if (AsyncOp == AsyncWrite)
|
|
{
|
|
//
|
|
// Async Write references the remote node
|
|
//
|
|
ASSERT (pRemoteNode != NULL);
|
|
nicDereferenceRemoteNode (pRemoteNode, AsyncSendComplete);
|
|
}
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "<== AsyncWriteStreamSendComplete, NdisStatus %x,IrpStatus %x ",
|
|
NdisStatus, IrpStatus ) );
|
|
|
|
//
|
|
// ALWAYS RETURN STATUS_MORE_PROCESSING_REQUIRED
|
|
//
|
|
|
|
MATCH_IRQL;
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AsyncWriteSendPacketsHandler(
|
|
IN PVCCB pVc,
|
|
IN PNDIS_PACKET pPacket
|
|
)
|
|
|
|
//
|
|
// This is the VC handler when packet is sent using the
|
|
// AsyncWrite 1394 Bus Api
|
|
// This function, copies the contents of the packet to locally
|
|
// owned memory, sets up the Irb and the Irp and calls
|
|
// nicSubmitIrp which is the generic cal to do a IoCallDriver
|
|
//
|
|
// The return value is success, if the I/o was successfully pended
|
|
{
|
|
|
|
PSENDFIFO_VCCB pSendFIFOVc = (SENDFIFO_VCCB*)pVc;
|
|
PMDL pMyMdl = NULL;
|
|
PIRB pMyIrb = NULL;
|
|
PIRP pMyIrp = NULL;
|
|
BOOLEAN fVcActive = TRUE;
|
|
PREMOTE_NODE pRemoteNode = NULL;
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
|
|
ULONG PacketLength = 0;
|
|
PVOID pLookasideListBuffer = NULL;
|
|
PADAPTERCB pAdapter = NULL;
|
|
USHORT FragmentLength = 0;
|
|
PNDIS_BUFFER pStartNdisBuffer = NULL;
|
|
PVOID pStartPacketData = NULL;
|
|
PLOOKASIDE_BUFFER_HEADER pLookasideHeader = NULL;
|
|
PNIC_NPAGED_LOOKASIDE_LIST pLookasideList = NULL;
|
|
ENUM_LOOKASIDE_LIST WhichLookasideList = NoLookasideList;
|
|
FRAGMENTATION_STRUCTURE Fragment;
|
|
ULONG NumFragmentsNeeded ;
|
|
STORE_CURRENT_IRQL;
|
|
|
|
NdisZeroMemory (&Fragment, sizeof (FRAGMENTATION_STRUCTURE));
|
|
|
|
TRACE( TL_T, TM_Send, ( "==>AsyncWriteSendPacketHandler, Vc %x,Packet %x, FragmentationStruct %x",
|
|
pSendFIFOVc, pPacket , &Fragment ) );
|
|
|
|
pRemoteNode = pSendFIFOVc->Hdr.pRemoteNode;
|
|
ASSERT (pRemoteNode != NULL);
|
|
|
|
|
|
|
|
do
|
|
{
|
|
|
|
VC_ACQUIRE_LOCK (pSendFIFOVc);
|
|
|
|
//
|
|
// Make sure that the Vc is Activated and that no close calls
|
|
// are pending or that we have already completed a close call
|
|
//
|
|
|
|
|
|
if ( VC_ACTIVE (pSendFIFOVc) == FALSE || REMOTE_NODE_ACTIVE(pRemoteNode) == FALSE)
|
|
{
|
|
fVcActive = FALSE;
|
|
}
|
|
|
|
if (VC_TEST_FLAG( pSendFIFOVc, VCBF_GenerationWorkItem) == TRUE)
|
|
{
|
|
TRACE( TL_N, TM_Send, ( "AsyncWriteSendPacketHandler, Getting a new Gen, Fail send ") );
|
|
|
|
fVcActive = FALSE;
|
|
}
|
|
|
|
//
|
|
// This reference will either be dereferenced below in a call to FreeSendPacketDataStructure
|
|
// below or a call to FreeSendPacketDataStructure made from the Irp's completion routine
|
|
//
|
|
|
|
if (fVcActive == TRUE)
|
|
{
|
|
nicReferenceCall (pVc, "AsyncWriteSendPacketsHandler");
|
|
|
|
nicReferenceRemoteNode (pRemoteNode, AsyncWriteSendPackets);
|
|
|
|
}
|
|
|
|
VC_RELEASE_LOCK (pSendFIFOVc);
|
|
|
|
if (fVcActive == FALSE)
|
|
{
|
|
TRACE( TL_N, TM_Send, ( "AsyncWriteSendPacketHandler, VC Not Active, Vc %x Flag %x", pSendFIFOVc,pSendFIFOVc->Hdr.ulFlags ) );
|
|
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
pAdapter = pSendFIFOVc->Hdr.pAF->pAdapter;
|
|
|
|
//
|
|
// Copy NdisBuffer in Packet to Local Memory and get an Mdl that points
|
|
// to this memory
|
|
//
|
|
NdisQueryPacket( pPacket,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&PacketLength);
|
|
|
|
ASSERT (pPacket->Private.Head != NULL);
|
|
|
|
//
|
|
// Spew out the packet if necessary
|
|
//
|
|
nicDumpPkt (pPacket, "AsyncWriteSendPacketsHandler");
|
|
|
|
//
|
|
// Initialize the start variables
|
|
//
|
|
|
|
pStartNdisBuffer = pPacket->Private.Head;
|
|
pStartPacketData = nicNdisBufferVirtualAddress (pStartNdisBuffer);
|
|
|
|
if (pStartPacketData == NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_RESOURCES;
|
|
TRACE( TL_N, TM_Send, ( "AsyncWriteSendPacketHandler, pStartPacketData ") );
|
|
|
|
break;
|
|
}
|
|
|
|
TRACE( TL_V, TM_Send, ( "PacketLength %x", PacketLength) );
|
|
|
|
//
|
|
// Make a decision on which lookaside list to use. If the tx is unfragmented
|
|
// then copy over the ndis packet as well
|
|
//
|
|
|
|
//
|
|
// first choose the lookaside list. the actual lookaside list is chosen so that the
|
|
// each can accomodate the maximum number of fragments at its payload
|
|
//
|
|
//
|
|
if (PacketLength < PAYLOAD_100)
|
|
{
|
|
pLookasideList = &pAdapter->SendLookasideList100;
|
|
WhichLookasideList = SendLookasideList100;
|
|
TRACE( TL_V, TM_Send, ( " PAYLOAD_100 Lookaside List %x",
|
|
&pAdapter->SendLookasideList100) );
|
|
|
|
}
|
|
else
|
|
if (PacketLength < PAYLOAD_2K)
|
|
{
|
|
pLookasideList = &pAdapter->SendLookasideList2K;
|
|
WhichLookasideList = SendLookasideList2K;
|
|
TRACE( TL_V, TM_Send, ( " PAYLOAD_2K Lookaside List %x",
|
|
&pAdapter->SendLookasideList2K) );
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Large Sends not supported
|
|
// TODO : Add code for local allocation
|
|
//
|
|
ASSERT (!"SendPacket Too Large - Not supported Yet" );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// are we going to fragment
|
|
//
|
|
ASSERT (pLookasideList != NULL)
|
|
|
|
//
|
|
// We are not going to fragment. Optimize this path
|
|
//
|
|
pLookasideListBuffer = nicGetLookasideBuffer (pLookasideList);
|
|
|
|
if (pLookasideListBuffer == NULL )
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
BREAK (TM_Send, ("nicGetLookasideBuffer FAILED") );
|
|
}
|
|
|
|
//
|
|
// Initialize the header with relevant information that the send complete
|
|
// will need
|
|
//
|
|
|
|
pLookasideHeader = (PLOOKASIDE_BUFFER_HEADER)pLookasideListBuffer;
|
|
pLookasideHeader->IsFragmented = FALSE; // Default
|
|
pLookasideHeader->FragmentsGenerated = 0;
|
|
pLookasideHeader->pLookasideList = pLookasideList;
|
|
pLookasideHeader->pNdisPacket = pPacket;
|
|
pLookasideHeader->pVc =(PVCCB)pVc;
|
|
pLookasideHeader->AsyncOp = AsyncWrite;
|
|
|
|
//
|
|
// Initialize the Fragment structure
|
|
//
|
|
//
|
|
// Do we fragment or not. Base it on the MaxPayload possible
|
|
//
|
|
|
|
TRACE( TL_V, TM_Send, ( " PacketLength %x, pSendFIFOVc->MaxPayload%x ",
|
|
PacketLength ,pSendFIFOVc->Hdr.MaxPayload) );
|
|
|
|
|
|
if (PacketLength <= pSendFIFOVc->Hdr.MaxPayload)
|
|
{
|
|
//
|
|
// No need to fragment here. We will use the UNFRAGMENTED Layout
|
|
//
|
|
// First Get a local buffer from our lookaside list
|
|
//
|
|
PUNFRAGMENTED_BUFFER pUnfragmentedBuffer = (PUNFRAGMENTED_BUFFER )pLookasideHeader;
|
|
|
|
NumFragmentsNeeded = 1;
|
|
|
|
NdisStatus = nicCopyNdisBufferChainToBuffer (pStartNdisBuffer,
|
|
(PVOID)&pUnfragmentedBuffer ->Data[0],
|
|
pLookasideList->MaxSendSize );
|
|
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
pLookasideHeader->OutstandingFragments = 1; // this is our refcount
|
|
BREAK ( TM_Send, ( " AsyncStreamSendPacketHandler, nicCopyNdisPacketToUnfragmentedBuffer Failed ") );
|
|
}
|
|
|
|
ASSERT (pLookasideListBuffer != NULL);
|
|
|
|
//
|
|
// Initialize all the variable needed by the Next section of the code.
|
|
// This deals with setting up the Mdl and the IRB
|
|
//
|
|
|
|
pStartNdisBuffer = NULL;
|
|
|
|
Fragment.pStartFragment = (PVOID) &pUnfragmentedBuffer ->Data[0];
|
|
Fragment.FragmentLength = PacketLength;
|
|
Fragment.pCurrNdisBuffer = NULL;
|
|
|
|
pLookasideHeader->FragmentsGenerated = 1;
|
|
pLookasideHeader->IsFragmented = FALSE;
|
|
pLookasideHeader->OutstandingFragments = 1; // this is our refcount
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We need to fragment
|
|
//
|
|
ULONG Dgl = NdisInterlockedIncrement(&pAdapter->dgl);
|
|
|
|
//
|
|
// Fragments will be needed . Make sure the calculation for numFragments catches the boundary conditions
|
|
//
|
|
|
|
|
|
NumFragmentsNeeded = nicNumFragmentsNeeded (PacketLength,
|
|
pSendFIFOVc->Hdr.MaxPayload,
|
|
sizeof (NDIS1394_FRAGMENT_HEADER) );
|
|
|
|
|
|
//
|
|
// Initialize the fragment structure. The unfragmented code path
|
|
// does not care about these fields
|
|
//
|
|
|
|
//
|
|
// This structure is local to this function and this thread.
|
|
//
|
|
Fragment.TxHeaderSize = sizeof (NDIS1394_FRAGMENT_HEADER);
|
|
Fragment.pLookasideListBuffer = pLookasideListBuffer;
|
|
Fragment.AsyncOp = AsyncWrite;
|
|
Fragment.pAdapter = pRemoteNode->pAdapter;
|
|
Fragment.pLookasideList = pLookasideList;
|
|
Fragment.IPDatagramLength = (USHORT)PacketLength - sizeof (NDIS1394_UNFRAGMENTED_HEADER);
|
|
|
|
//
|
|
// Get Start of first Dest fragment
|
|
//
|
|
Fragment.MaxFragmentLength = pSendFIFOVc->Hdr.MaxPayload;
|
|
Fragment.NumFragmentsNeeded = NumFragmentsNeeded;
|
|
|
|
|
|
|
|
|
|
//
|
|
// Set up the Fragment Headers that will be used in fragmentation
|
|
//
|
|
|
|
NdisStatus = nicFirstFragmentInitialization (pPacket->Private.Head,
|
|
Dgl,
|
|
&Fragment);
|
|
|
|
|
|
if (pLookasideListBuffer == NULL || NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
BREAK (TM_Send, (" AsyncWriteSendPacketsHandler: nicFirstFragmentInitialization : FAILED" )) ;
|
|
}
|
|
|
|
ASSERT (pLookasideListBuffer != NULL);
|
|
|
|
pLookasideHeader->IsFragmented = TRUE;
|
|
pLookasideHeader->OutstandingFragments = NumFragmentsNeeded ; // this is our refcount
|
|
|
|
}
|
|
|
|
|
|
TRACE( TL_V, TM_Send, ( "NumFragments %x, pSendFIFOVc->MaxSendSize %x, Packet Size %x",
|
|
NumFragmentsNeeded,pSendFIFOVc->Hdr.MaxPayload, PacketLength) );
|
|
|
|
|
|
//
|
|
// Now begin the loop which will send n fragments
|
|
//
|
|
do
|
|
{
|
|
|
|
//
|
|
// Do we need to fragment. If so , extract one fragment out of the NdisPacket
|
|
//
|
|
if (pLookasideHeader->IsFragmented == TRUE )
|
|
{
|
|
|
|
//
|
|
// We copy one fragment over and this will allocate the lookaside list
|
|
//
|
|
|
|
NdisStatus = nicCopyOneFragment (&Fragment);
|
|
|
|
if (NDIS_STATUS_SUCCESS != NdisStatus)
|
|
{
|
|
BREAK ( TM_Send, ( " AsyncWriteSendPacketHandler, nicCopyOneFragment Failed ") );
|
|
}
|
|
|
|
//
|
|
// Get the pointer to the Irb here . Amd set it up for the next time
|
|
//
|
|
pMyIrb = Fragment.pCurrentIrb;
|
|
Fragment.pCurrentIrb = (PIRB)((ULONG_PTR)Fragment.pCurrentIrb + sizeof (IRB) );
|
|
TRACE( TL_V, TM_Send, ( " pMyIrb %x, Next Irb %x ", pMyIrb , Fragment.pCurrentIrb ) );
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No Curr NdisBuffer as this packet was never fragmented.
|
|
//
|
|
|
|
ASSERT (pLookasideHeader->IsFragmented == FALSE);
|
|
|
|
pMyIrb = &((PUNFRAGMENTED_BUFFER )pLookasideHeader)->Irb;
|
|
}
|
|
|
|
//
|
|
// At this point we have one fragment that needs to be transmitted.
|
|
// Data structures have been updated to set up the MDL and the IRB
|
|
//
|
|
ASSERT (Fragment.pStartFragment != NULL);
|
|
|
|
NdisStatus = nicGetMdl (Fragment.FragmentLength ,
|
|
Fragment.pStartFragment,
|
|
&pMyMdl);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
pMyMdl = NULL;
|
|
BREAK ( TM_Send, ( " AsyncWriteSendPacketHandler, nicCopyNdisBufferChainToBuffer Failed ") );
|
|
}
|
|
|
|
nicIncFifoSendMdl();
|
|
//
|
|
// Fill in the Irb with the correct values from the VC
|
|
// Stuff we need to add to the send VC - BlockSize,Generation
|
|
//
|
|
|
|
nicInitAsyncWriteIrb(pSendFIFOVc, pMyMdl, pMyIrb);
|
|
|
|
//
|
|
// Get a free Irp
|
|
//
|
|
|
|
NdisStatus = nicGetIrp (pRemoteNode->pPdo, &pMyIrp);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
pMyIrp = NULL;
|
|
break;
|
|
}
|
|
//
|
|
// At this point, we have a guarantee that the Completion routine will be called
|
|
//
|
|
ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
|
|
|
|
//
|
|
// Dump the Fragment
|
|
//
|
|
nicDumpMdl (pMyMdl , 0, "AsyncWrite Fragment");
|
|
|
|
NIC1394_LOG_PKT(
|
|
pAdapter,
|
|
NIC1394_LOGFLAGS_SEND_FIFO,
|
|
pAdapter->BCRData.LocalNodeNumber, // SourceID
|
|
pRemoteNode->RemoteAddress.NA_Node_Number, // DestID
|
|
Fragment.pStartFragment,
|
|
Fragment.FragmentLength
|
|
);
|
|
|
|
|
|
//
|
|
// This function implements the common functionality to be implemented by
|
|
// all other send/recv cals to IoCallDriver
|
|
//
|
|
//
|
|
// We IGNORE the NtStatus as the completion handler will be called
|
|
//
|
|
nicIncrementBusSends(pVc);
|
|
|
|
NtStatus = nicSubmitIrp(pRemoteNode->pPdo,
|
|
pMyIrp,
|
|
pMyIrb,
|
|
AsyncWriteStreamSendComplete,
|
|
(PVOID)pLookasideListBuffer);
|
|
|
|
TRACE( TL_V, TM_Send, ( " pCurrNdisBuffer %x, NdisStatus %x ", Fragment.pCurrNdisBuffer , NdisStatus ) );
|
|
|
|
|
|
} while (Fragment.pCurrNdisBuffer != NULL && NdisStatus == NDIS_STATUS_SUCCESS);
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// DO NOT touch the packet if status == NDIS_STATUS_SUCCESS.
|
|
//
|
|
|
|
|
|
//
|
|
// CleanUp if any of the allocations failed. We do not have a pointer
|
|
// to the LocalBuffer (it is embedded in the Mdl) so it remains NULL
|
|
//
|
|
// NdisStatus != Success means that we never got to nicSubmitIrp
|
|
//
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
|
|
ASSERT (pMyIrp == NULL);
|
|
|
|
//
|
|
// fVc Active makes sure that we actually got around to allocating
|
|
// and referencing structures
|
|
//
|
|
|
|
if (fVcActive == TRUE)
|
|
{
|
|
|
|
if (pLookasideListBuffer != NULL)
|
|
{
|
|
|
|
//
|
|
// Complete this fragment, as we never submit'd the IRP to
|
|
// the 1394 bus driver
|
|
//
|
|
AsyncWriteStreamSendComplete(NULL, // PDO
|
|
NULL,
|
|
pLookasideListBuffer);
|
|
|
|
NdisStatus =NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// This thread needs to decrement the refcounts as
|
|
// AsyncWriteStreamSendComplete was not called
|
|
//
|
|
nicDereferenceCall ((PVCCB) pSendFIFOVc, "AsyncWriteSendPacketsHandler");
|
|
|
|
nicDereferenceRemoteNode (pRemoteNode, AsyncWriteSendPackets);
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "<==AsyncWriteSendPacketHandler, NdisStatus %x", NdisStatus ) );
|
|
MATCH_IRQL;
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicCopyOneFragment (
|
|
PFRAGMENTATION_STRUCTURE pFragment
|
|
)
|
|
|
|
// Function Description:
|
|
// This creates one fragment filled with valid data and returns it.
|
|
// The is complex because the Current NDisBuffer could end before the fragment
|
|
// or vice versa.
|
|
//
|
|
// Information from this fragment is stored and will be used in the next fragment
|
|
//
|
|
// Arguments
|
|
// pFragment - Copies one fragment into the next available fragement.
|
|
//
|
|
// Return Value:
|
|
// Status - Success
|
|
//
|
|
//
|
|
{
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
PNDIS_BUFFER pCurrNdisBuffer = pFragment->pCurrNdisBuffer;
|
|
PVOID pSourceAddressInNdisBuffer = pFragment->pSourceAddressInNdisBuffer;
|
|
ULONG FragmentLengthRemaining = pFragment->MaxFragmentLength;
|
|
USHORT FragmentLength=0;
|
|
PVOID pSource = NULL;
|
|
PVOID pDestination = NULL;
|
|
PVOID pStartFragmentData = NULL;
|
|
ULONG NdisBufferLengthRemaining = pFragment->NdisBufferLengthRemaining;
|
|
ULONG LengthToCopy = 0;
|
|
ULONG FragmentCopyStatus=0;
|
|
PLOOKASIDE_BUFFER_HEADER pLookasideHeader = NULL;
|
|
enum
|
|
{
|
|
FRAGMENT_COPY_Invalid,
|
|
FRAGMENT_COPY_NdisBufferCompleted,
|
|
FRAGMENT_COPY_NdisBufferAndFragmentCompleted,
|
|
FRAGMENT_COPY_FragmentCompleted
|
|
};
|
|
|
|
TRACE( TL_T, TM_Send, ( "==>nicCopyOneFragment pFragment %x", pFragment ) );
|
|
ASSERT (pCurrNdisBuffer != NULL);
|
|
do
|
|
{
|
|
|
|
//
|
|
// lets get the destination. We need to account for
|
|
// ther fragment size and add it to the previous start address
|
|
//
|
|
|
|
{
|
|
ULONG CurrFragOffset;
|
|
|
|
CurrFragOffset = pFragment->MaxFragmentLength * (pFragment->CurrFragmentNum++);
|
|
|
|
pStartFragmentData = (PVOID) ((ULONG_PTR) pFragment->pStartOfFirstFragment + CurrFragOffset );
|
|
|
|
}
|
|
|
|
|
|
|
|
pFragment->pStartFragment = pStartFragmentData;
|
|
|
|
TRACE( TL_V, TM_Send, ( " pStartFragmentData %x", pStartFragmentData) );
|
|
|
|
pLookasideHeader = (PLOOKASIDE_BUFFER_HEADER)pFragment->pLookasideListBuffer;
|
|
|
|
|
|
|
|
//
|
|
// Do the bookkeeping , Increase refcount and num of fragments used. Refcount decremented in FreeSendDataStructures
|
|
//
|
|
|
|
NdisInterlockedIncrement (&pLookasideHeader->FragmentsGenerated);
|
|
|
|
//
|
|
// The Start of the data beginning with the fragment header goes here or in the
|
|
// case of async stream fragment header and gasp header go here
|
|
//
|
|
ASSERT (pFragment->TxHeaderSize == 8 || pFragment->TxHeaderSize == 16);
|
|
|
|
|
|
pDestination = (PVOID) ((ULONG_PTR)pStartFragmentData + pFragment->TxHeaderSize );
|
|
|
|
FragmentLengthRemaining -= pFragment->TxHeaderSize;
|
|
|
|
//
|
|
// Now we start the copy. Keep on copying into the current fragment until the MaxLength is reached
|
|
// or the NdisBufferChain is exhausted
|
|
//
|
|
|
|
pSource = pSourceAddressInNdisBuffer;
|
|
|
|
|
|
do
|
|
{
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( " LengthNdisBuffer %x, FragmentLengthRemaining %x, pCurrNdisBuffer %x",
|
|
NdisBufferLengthRemaining , FragmentLengthRemaining ,pCurrNdisBuffer ) );
|
|
|
|
if (FragmentLengthRemaining > NdisBufferLengthRemaining )
|
|
{
|
|
//
|
|
// Copy the complete NdisBuffer over
|
|
//
|
|
|
|
LengthToCopy = NdisBufferLengthRemaining;
|
|
FragmentCopyStatus = FRAGMENT_COPY_NdisBufferCompleted;
|
|
|
|
}
|
|
|
|
|
|
if (FragmentLengthRemaining < NdisBufferLengthRemaining )
|
|
{
|
|
//
|
|
// Copy only as much as required
|
|
//
|
|
|
|
LengthToCopy = FragmentLengthRemaining;
|
|
FragmentCopyStatus = FRAGMENT_COPY_FragmentCompleted;
|
|
|
|
}
|
|
|
|
if (FragmentLengthRemaining == NdisBufferLengthRemaining )
|
|
{
|
|
//
|
|
// Copy the complete Ndis Buffer , move to the next ndis buffer
|
|
// and update the NdisBufferLengthRemaining field
|
|
//
|
|
LengthToCopy = NdisBufferLengthRemaining;
|
|
FragmentCopyStatus = FRAGMENT_COPY_NdisBufferAndFragmentCompleted;
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// Sanity check to make sure we are not overwriting into free memory.
|
|
// As this should never happen, there is no recovery mechanism in place.
|
|
//
|
|
ASSERT (((PUCHAR)pDestination + LengthToCopy) <= (((PUCHAR) pLookasideHeader) + (pLookasideHeader->pLookasideList->Size) ));
|
|
|
|
//
|
|
// Do the copy
|
|
//
|
|
|
|
TRACE ( TL_V, TM_Send, (" nicCopyOneFragment pSource %x , pDestination %x, Length %x", pSource, pDestination, LengthToCopy ) );
|
|
|
|
NdisMoveMemory (pDestination, pSource, LengthToCopy);
|
|
|
|
|
|
//
|
|
// Update the fragment length remaininig and Total Buffer Size
|
|
//
|
|
FragmentLengthRemaining -= LengthToCopy;
|
|
|
|
FragmentLength += (USHORT)LengthToCopy;
|
|
|
|
pDestination = (PVOID) ((ULONG_PTR) pDestination + LengthToCopy);
|
|
//
|
|
// Update the NdisBuffer variables
|
|
//
|
|
ASSERT (pCurrNdisBuffer != NULL);
|
|
|
|
TRACE( TL_V, TM_Send, ( " FragmentCopyStatus %x", FragmentCopyStatus) );
|
|
|
|
switch (FragmentCopyStatus)
|
|
{
|
|
case FRAGMENT_COPY_NdisBufferCompleted:
|
|
case FRAGMENT_COPY_NdisBufferAndFragmentCompleted:
|
|
{
|
|
|
|
//
|
|
// Move to the next Ndisbuffer
|
|
//
|
|
pCurrNdisBuffer = pCurrNdisBuffer->Next;
|
|
|
|
if (pCurrNdisBuffer != NULL)
|
|
{
|
|
NdisBufferLengthRemaining = nicNdisBufferLength (pCurrNdisBuffer);
|
|
|
|
pSourceAddressInNdisBuffer = nicNdisBufferVirtualAddress(pCurrNdisBuffer);
|
|
|
|
if (pSourceAddressInNdisBuffer == NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_RESOURCES;
|
|
BREAK (TM_Send, ("nicNdisBufferVirtualAddress FAILED " ) );
|
|
}
|
|
|
|
//
|
|
// Set up the values for the next iteration
|
|
//
|
|
pSource = pSourceAddressInNdisBuffer;
|
|
NdisBufferLengthRemaining = nicNdisBufferLength (pCurrNdisBuffer);
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we have reached the end of the NdisPAcket. Mark the fragment header as such
|
|
//
|
|
pFragment->lf = lf_LastFragment;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case FRAGMENT_COPY_FragmentCompleted:
|
|
{
|
|
//
|
|
// Fragment has completed. Do not move to the next NdisBuffer
|
|
// However update StartCopy Address in the NdisBuffer
|
|
//
|
|
pSourceAddressInNdisBuffer = (PVOID) ((ULONG_PTR) pSource + LengthToCopy );
|
|
|
|
NdisBufferLengthRemaining -= LengthToCopy ;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
default :
|
|
{
|
|
ASSERT (0);
|
|
}
|
|
|
|
}
|
|
|
|
TRACE( TL_T, TM_Send, ( " LengthToCopy %x, FragmentLength %x, ", LengthToCopy, FragmentLength) );
|
|
TRACE( TL_T, TM_Send, ( " FragmentLengthRemaining %x, pCurrNdisBuffer %x",FragmentLengthRemaining , pCurrNdisBuffer ) );
|
|
|
|
|
|
}while (FragmentLengthRemaining > 0 && pCurrNdisBuffer != NULL);
|
|
|
|
|
|
|
|
|
|
//
|
|
// Now that we have the buffer size. Add the fragment header
|
|
//
|
|
|
|
nicAddFragmentHeader (pStartFragmentData,
|
|
pFragment,
|
|
FragmentLength);
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( " Fragment Header added %x", *(PULONG)pStartFragmentData) );
|
|
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
}while (FALSE);
|
|
|
|
//
|
|
// Now update the output parameters.
|
|
//
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
|
|
//
|
|
// Update the Lookaside Header structure, to reflect the new position of all the pointers
|
|
//
|
|
pFragment->pCurrNdisBuffer = pCurrNdisBuffer;
|
|
pFragment->pSourceAddressInNdisBuffer = pSourceAddressInNdisBuffer;
|
|
|
|
//
|
|
// Update the fragment structure with the length remaining in the NdisBuffer
|
|
//
|
|
|
|
pFragment->NdisBufferLengthRemaining = NdisBufferLengthRemaining ;
|
|
pFragment->FragmentLength = FragmentLength + pFragment->TxHeaderSize;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "<==nicCopyOneFragment pStartFragmentData %x, pLookasideListBuffer %x, pSourceAddressInNdisBuffer %x, NdisStatus %x",
|
|
pStartFragmentData, pSourceAddressInNdisBuffer, NdisStatus) );
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicCopyUnfragmentedHeader (
|
|
IN PNIC1394_UNFRAGMENTED_HEADER pDestUnfragmentedHeader,
|
|
IN PVOID pSrcUnfragmentedHeader
|
|
)
|
|
// Function Description:
|
|
// Expect the Src to be a big Endian unfragmented packet header
|
|
// It will reverse the byte order in a temp variable and copy it into the
|
|
// Destination provided.
|
|
//
|
|
// Arguments
|
|
// pDestUnfragmentedHeader - Destination (Little Endian
|
|
// pSrcUnfragmentedHeader - Source (Big Endian)
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Success if all the pointers and copy is valid
|
|
//
|
|
{
|
|
|
|
ULONG UnfragmentedHeader;
|
|
|
|
TRACE( TL_T, TM_Send, ( "==> nicCopyUnfragmentedHeader pDestUnfragmentedHeader %x, pSrcUnfragmentedHeader %x",
|
|
pDestUnfragmentedHeader, pSrcUnfragmentedHeader ) );
|
|
|
|
ASSERT (pSrcUnfragmentedHeader != NULL && pDestUnfragmentedHeader != NULL) ;
|
|
|
|
*((PULONG)pDestUnfragmentedHeader) = SWAPBYTES_ULONG ( *(PULONG) pSrcUnfragmentedHeader);
|
|
|
|
TRACE( TL_T, TM_Send, ( "pDestUnfragmentedHeader %x, ", *(PULONG)pDestUnfragmentedHeader) );
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( " <== nicCopyUnfragmentedHeader " ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicFirstFragmentInitialization (
|
|
IN PNDIS_BUFFER pStartNdisBuffer,
|
|
IN ULONG DatagramLabelLong,
|
|
IN OUT PFRAGMENTATION_STRUCTURE pFragment
|
|
)
|
|
// Function Description:
|
|
// This will set up the fragement headers that are required for
|
|
// transmitting multiple fragments.
|
|
// Sets up the first source and destination for the first fragment
|
|
//
|
|
// Arguments
|
|
// pAdapter - to be used to get the dgl label and the lookaside list
|
|
// pStartOfData - start of the packet data . To be used in extracting the Unfragmented Header
|
|
// ppLookasideListBuffer Points to the allocated lookaside buffer
|
|
// pplookasideheader - points to the lookaside header
|
|
//
|
|
// Return Value:
|
|
// Success if the allocation succeeds
|
|
//
|
|
//
|
|
{
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
PNDIS1394_FRAGMENT_HEADER pHeader = NULL;
|
|
PVOID pPacketStartData = NULL;
|
|
USHORT dgl = (USHORT) DatagramLabelLong;
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "==> nicFirstFragmentInitialization pStartNdisBuffer%x, pFragment%x dgl %x ",
|
|
pStartNdisBuffer, pFragment, dgl ) );
|
|
|
|
do
|
|
{
|
|
|
|
//
|
|
// Get the start address for the 1st NdisBuffer. This contains
|
|
// the unfragmented header
|
|
//
|
|
pPacketStartData = nicNdisBufferVirtualAddress(pStartNdisBuffer);
|
|
|
|
if (pPacketStartData == NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_RESOURCES;
|
|
BREAK (TM_Send, ("NdisBufferVirtual Address is NULL " ) );
|
|
}
|
|
|
|
|
|
pFragment->UnfragmentedHeader.HeaderUlong =
|
|
SWAPBYTES_ULONG (((PNDIS1394_UNFRAGMENTED_HEADER)pPacketStartData)->HeaderUlong);
|
|
|
|
TRACE ( TL_V, TM_Send, (" Unfragmented Header %x, pPacketStartData %x",
|
|
pFragment->UnfragmentedHeader.HeaderUlong , pPacketStartData) );
|
|
|
|
TRACE ( TL_V, TM_Send, (" original Header lf %x, etherType %x",
|
|
pFragment->UnfragmentedHeader.u.FH_lf,
|
|
pFragment->UnfragmentedHeader.u.FH_EtherType) );
|
|
|
|
|
|
|
|
//
|
|
// Now construct a fragmentation header to be used by all the fragments.
|
|
//
|
|
pHeader = &pFragment->FragmentationHeader;
|
|
|
|
|
|
pHeader ->u.FirstQuadlet.FH_lf = lf_FirstFragment;
|
|
pHeader ->u.FirstQuadlet.FH_buffersize = pFragment->IPDatagramLength-1;
|
|
|
|
pHeader ->u.FirstQuadlet_FirstFragment.FH_EtherType
|
|
= pFragment->UnfragmentedHeader.u.FH_EtherType;
|
|
|
|
pHeader ->u1.SecondQuadlet.FH_dgl = dgl;
|
|
|
|
TRACE ( TL_V, TM_Send, (" fragmented Header Hi %x Lo %x",
|
|
pHeader->u.FH_High,
|
|
pHeader->u1.FH_Low) );
|
|
|
|
TRACE ( TL_V, TM_Send, (" fragmented Header lf %x EtherType %x",
|
|
pHeader ->u.FirstQuadlet_FirstFragment.FH_lf ,
|
|
pHeader ->u.FirstQuadlet_FirstFragment.FH_EtherType ) );
|
|
|
|
//
|
|
// temporaty debug spew
|
|
//
|
|
TRACE (TL_V, TM_Send, (" copy Header at %x, Orig Header at %x",
|
|
&pHeader ->u.FirstQuadlet_FirstFragment,
|
|
pFragment->UnfragmentedHeader) );
|
|
|
|
//
|
|
// Initialize the fragmentation structure with packet's first ndis buffer
|
|
//
|
|
pFragment->pSourceAddressInNdisBuffer = NdisBufferVirtualAddress (pStartNdisBuffer);
|
|
|
|
if (pFragment->pSourceAddressInNdisBuffer == NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
//
|
|
// Set up the copy source . The first four bytes of data contain the unfragmented header.
|
|
// We need to skip past these bytes and start the copy from the next byte
|
|
//
|
|
pFragment->pSourceAddressInNdisBuffer = (PVOID) ((ULONG_PTR)pFragment->pSourceAddressInNdisBuffer +
|
|
sizeof (NDIS1394_UNFRAGMENTED_HEADER) );
|
|
|
|
|
|
pFragment->NdisBufferLengthRemaining = NdisBufferLength (pStartNdisBuffer) - sizeof (NDIS1394_UNFRAGMENTED_HEADER);
|
|
pFragment->pCurrNdisBuffer = pStartNdisBuffer;
|
|
//
|
|
// Set up the destination
|
|
//
|
|
pFragment->pStartFragment = (PVOID)((ULONG_PTR)pFragment->pLookasideListBuffer
|
|
+ (pFragment->NumFragmentsNeeded*sizeof(IRB)));
|
|
|
|
|
|
((PLOOKASIDE_BUFFER_HEADER)pFragment->pLookasideListBuffer)->pStartOfData = pFragment->pStartFragment;
|
|
|
|
pFragment->pStartOfFirstFragment = pFragment->pStartFragment ;
|
|
pFragment->CurrFragmentNum = 0;
|
|
|
|
|
|
pFragment->lf = lf_FirstFragment;
|
|
|
|
//
|
|
// The First IRB will reside at the end of the lookaside-header
|
|
//
|
|
pFragment->pCurrentIrb = &((PUNFRAGMENTED_BUFFER)pFragment->pLookasideListBuffer)->Irb;
|
|
|
|
TRACE( TL_T, TM_Send, ( " pStartFragment %x, pFragment %x,NumFragmentsNeeded %x,MaxFragmentLength %x ",
|
|
pFragment->pStartFragment,
|
|
pFragment->NumFragmentsNeeded,
|
|
pFragment->MaxFragmentLength) );
|
|
|
|
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( " <== nicFirstFragmentInitialization NdisStautus %x, pFragment %x, ",
|
|
NdisStatus, pFragment) );
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicAddFragmentHeader (
|
|
IN PVOID pStartFragmentData,
|
|
IN PFRAGMENTATION_STRUCTURE pFragmentStructure,
|
|
IN ULONG FragmentLength
|
|
)
|
|
// Function Description:
|
|
// Copies the Fragment header over after byteswapping it.
|
|
// For the the first time, the ether type and so forth is already initialized and waiting to be copied.
|
|
// This funciotn also sets up the values for the next invocation of this function
|
|
// Arguments
|
|
// pStartFragmentData - Start of the fragment. Header goes after the gasp header if necessary .
|
|
// pFragmentationHeader - Header to copy over
|
|
// fIsFirstFragment - TRUE if this is the first fragment and needs a special header
|
|
// Return Value:
|
|
// None
|
|
//
|
|
{
|
|
|
|
PNDIS1394_FRAGMENT_HEADER pDestFragmentHeader = (PNDIS1394_FRAGMENT_HEADER)pStartFragmentData;
|
|
PNDIS1394_FRAGMENT_HEADER pSrcFragmentHeader = &pFragmentStructure->FragmentationHeader;
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "==> nicAddFragmentHeader pStartFragmentData %x, pFragmentationHeader %x, , FragmentLength %x, lf %x",
|
|
pStartFragmentData , pSrcFragmentHeader , FragmentLength, pFragmentStructure->lf) );
|
|
|
|
if (pFragmentStructure->AsyncOp == AsyncStream)
|
|
{
|
|
//
|
|
// First Copy the GaspHeader
|
|
//
|
|
NdisMoveMemory (pStartFragmentData ,
|
|
&pFragmentStructure->pAdapter->GaspHeader,
|
|
sizeof (GASP_HEADER) );
|
|
|
|
//
|
|
// Increment the pointers so that the fragment header will be copied after the gasp header
|
|
//
|
|
pStartFragmentData = (PVOID) ((ULONG_PTR) pStartFragmentData + sizeof (GASP_HEADER) );
|
|
pDestFragmentHeader = (PVOID) pStartFragmentData;
|
|
|
|
TRACE( TL_T, TM_Send, ( " nicAddFragmentHeader Added Gasp Header from %x ",
|
|
pFragmentStructure->pAdapter->GaspHeader) );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Sanity check , are we overwriting anybody ?
|
|
//
|
|
ASSERT (*(PULONG)pDestFragmentHeader == 0);
|
|
ASSERT (*(PULONG)pFragmentStructure->pCurrentIrb == 0);
|
|
|
|
TRACE( TL_V, TM_Send, ( " pSrcFragmentHeader Hi %x,Lo %x",
|
|
pSrcFragmentHeader->u.FH_High, pSrcFragmentHeader->u1.FH_Low) );
|
|
|
|
//
|
|
// Copy over the lf;
|
|
//
|
|
pSrcFragmentHeader->u.FirstQuadlet.FH_lf = pFragmentStructure->lf;
|
|
|
|
//
|
|
// Now copy over the 8 bytes of the fragment header and byteswap them into big endian
|
|
//
|
|
|
|
|
|
pDestFragmentHeader->u.FH_High = SWAPBYTES_ULONG ( pSrcFragmentHeader->u.FH_High);
|
|
|
|
pDestFragmentHeader->u1.FH_Low = SWAPBYTES_ULONG ( pSrcFragmentHeader->u1.FH_Low);
|
|
|
|
TRACE( TL_V, TM_Send, ( " Fragment Offset %x", pSrcFragmentHeader->u.FirstQuadlet.FH_fragment_offset ) );
|
|
|
|
//
|
|
// PREPARE the FRAGMENT STRUCTURE FOR THE NEXT ITERATION
|
|
//
|
|
|
|
//
|
|
// Set the first fragment completed flag to true and set up the header for the next fragment
|
|
//
|
|
if (pFragmentStructure->lf == lf_FirstFragment)
|
|
{
|
|
pFragmentStructure->lf = lf_InteriorFragment;
|
|
pSrcFragmentHeader->u.FirstQuadlet.FH_fragment_offset = 0;
|
|
|
|
}
|
|
|
|
//
|
|
// Increase the fragment offset for use in the next fragment
|
|
//
|
|
pSrcFragmentHeader->u.FirstQuadlet.FH_fragment_offset += FragmentLength;
|
|
|
|
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "<== nicAddFragmentHeader lf %x", pFragmentStructure->lf) );
|
|
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
AsyncStreamSendPacketsHandler (
|
|
IN PVCCB pVc,
|
|
IN PNDIS_PACKET pPacket
|
|
)
|
|
// Function Description:
|
|
// This function is used to send packets to the bus
|
|
// via the async stream irp. the Ndis Packet is copied
|
|
// to locally owned buffers and mdls and then sent
|
|
// down to the bus driver
|
|
//
|
|
// This code is borrowed heavily from the AsyncStreamIrp code below
|
|
//
|
|
// Arguments
|
|
// pChannelVc - The Vc which needs to send the packets
|
|
// pPacket - the packet being transmitted
|
|
//
|
|
// Return Value:
|
|
// NdisStatus - if all allocations and irp operations complete
|
|
// successfully, and the i/o will be completed asynchronously
|
|
//
|
|
{
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
|
|
PCHANNEL_VCCB pChannelVc = (PCHANNEL_VCCB) pVc;
|
|
BOOLEAN fVcActive = TRUE;
|
|
PMDL pMyMdl = NULL;
|
|
PIRB pMyIrb = NULL;
|
|
PIRP pMyIrp = NULL;
|
|
ULONG PacketLength = 0;
|
|
PVOID pLookasideListBuffer = NULL;
|
|
PADAPTERCB pAdapter = NULL;
|
|
PNDIS_BUFFER pStartNdisBuffer = NULL ;
|
|
PVOID pStartPacketData= NULL ;
|
|
PNIC_NPAGED_LOOKASIDE_LIST pLookasideList = NULL;
|
|
PLOOKASIDE_BUFFER_HEADER pLookasideHeader = NULL;
|
|
ULONG NumFragmentsNeeded = 0;
|
|
FRAGMENTATION_STRUCTURE Fragment;
|
|
STORE_CURRENT_IRQL;
|
|
|
|
|
|
NdisZeroMemory (&Fragment, sizeof (FRAGMENTATION_STRUCTURE));
|
|
|
|
TRACE( TL_T, TM_Send, ( "==>AsyncStreamSendPacketsHandler , pVc %x, pPacket %x",
|
|
pChannelVc , pPacket ) );
|
|
|
|
pAdapter = pChannelVc->Hdr.pAF->pAdapter;
|
|
//
|
|
// This reference will either be dereferenced below in a call to FreeSendPacketDataStructure
|
|
// below or a call to FreeSendPacketDataStructure made from the Irp's completion routine
|
|
//
|
|
|
|
|
|
|
|
do
|
|
{
|
|
VC_ACQUIRE_LOCK (pVc);
|
|
|
|
|
|
|
|
//
|
|
// Make sure that the Vc is Activated and that no close calls
|
|
// are pending or that we have already completed a close call
|
|
//
|
|
|
|
|
|
if ( VC_ACTIVE (pChannelVc) == FALSE || ADAPTER_ACTIVE(pAdapter) == FALSE)
|
|
{
|
|
fVcActive = FALSE;
|
|
}
|
|
|
|
if (VC_TEST_FLAG( pChannelVc, VCBF_GenerationWorkItem) == TRUE)
|
|
{
|
|
TRACE( TL_N, TM_Send, ( "AsyncStreamSendPacketHandler, Getting a new Gen, Fail send ") );
|
|
|
|
fVcActive = FALSE;
|
|
}
|
|
|
|
if (fVcActive == TRUE)
|
|
{
|
|
nicReferenceCall (pVc, "AsyncStreamSendPacketsHandler");
|
|
}
|
|
|
|
VC_RELEASE_LOCK (pVc);
|
|
|
|
if (fVcActive == FALSE)
|
|
{
|
|
TRACE( TL_N, TM_Send, ( "AsyncStreamSendPacketHandler, VC Not Active VC %x , Flag %x", pVc, pVc->Hdr.ulFlags ) );
|
|
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Copy NdisBuffer in Packet to Local Memory and get an Mdl that points
|
|
// to this memory (we get 1 Mdl only)
|
|
NdisQueryPacket( pPacket,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&PacketLength);
|
|
|
|
ASSERT (pPacket->Private.Head != NULL);
|
|
|
|
|
|
pStartNdisBuffer = pPacket->Private.Head;
|
|
pStartPacketData = nicNdisBufferVirtualAddress (pStartNdisBuffer);
|
|
|
|
if (pStartPacketData == NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_RESOURCES;
|
|
TRACE( TL_N, TM_Send, ( "AsyncStreamSendPacketHandler, pStartPacketData ") );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
TRACE( TL_V, TM_Send, ( "PacketLength %x", PacketLength) );
|
|
|
|
|
|
|
|
NumFragmentsNeeded = nicNumFragmentsNeeded (PacketLength,
|
|
pChannelVc->Hdr.MaxPayload,
|
|
sizeof (NDIS1394_FRAGMENT_HEADER) + ISOCH_PREFIX_LENGTH );
|
|
|
|
TRACE( TL_V, TM_Send, ( "NumFragments %x, pVc->MaxSendSize",
|
|
NumFragmentsNeeded,pVc->Hdr.MaxPayload) );
|
|
|
|
//
|
|
// first choose the lookaside list
|
|
//
|
|
//
|
|
|
|
|
|
if (PacketLength < PAYLOAD_100)
|
|
{
|
|
pLookasideList = &pAdapter->SendLookasideList100;
|
|
TRACE( TL_V, TM_Send, ( " PAYLOAD_100 Lookaside List %x",
|
|
&pAdapter->SendLookasideList100) );
|
|
|
|
}
|
|
else
|
|
if (PacketLength < PAYLOAD_2K)
|
|
{
|
|
pLookasideList = &pAdapter->SendLookasideList2K;
|
|
TRACE( TL_V, TM_Send, ( " PAYLOAD_2K Lookaside List %x",
|
|
&pAdapter->SendLookasideList2K) );
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Add code for local allocation
|
|
//
|
|
ASSERT (0);
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// are we going to fragment
|
|
//
|
|
ASSERT (pLookasideList != NULL)
|
|
|
|
//
|
|
// We are not going to fragment. Optimize this path
|
|
//
|
|
pLookasideListBuffer = nicGetLookasideBuffer (pLookasideList);
|
|
|
|
if (pLookasideListBuffer == NULL )
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
BREAK (TM_Send, ("nicGetLookasideBuffer FAILED") );
|
|
}
|
|
|
|
//
|
|
// Dump out the packet if necessary
|
|
//
|
|
nicDumpPkt (pPacket, "AsyncWriteStreamPacketsHandler");
|
|
|
|
//
|
|
// Initialize the header with relevant information that the send complete
|
|
// will need
|
|
//
|
|
|
|
|
|
pLookasideHeader = (PLOOKASIDE_BUFFER_HEADER)pLookasideListBuffer;
|
|
pLookasideHeader->IsFragmented = FALSE; // Default
|
|
pLookasideHeader->FragmentsGenerated = 0;
|
|
pLookasideHeader->pLookasideList = pLookasideList;
|
|
pLookasideHeader->pNdisPacket = pPacket;
|
|
pLookasideHeader->pVc =(PVCCB)pVc;
|
|
pLookasideHeader->AsyncOp = AsyncStream;
|
|
pLookasideHeader->OutstandingFragments = NumFragmentsNeeded ;
|
|
|
|
//
|
|
// Initialize the Fragment structure
|
|
//
|
|
//
|
|
// Do we fragment or not. Base it on the MaxPayload field
|
|
//
|
|
|
|
TRACE( TL_V, TM_Send, ( " Fragment PacketLength %x, pVc->MaxPayload %x ",
|
|
PacketLength ,pVc->Hdr.MaxPayload) );
|
|
|
|
|
|
//
|
|
// Do we need to fragment. Use the number of fragments generated to figure it out
|
|
//
|
|
|
|
if (NumFragmentsNeeded == 1)
|
|
{
|
|
//
|
|
// No need to fragment here. We will use the UNFRAGMENTED Layout
|
|
//
|
|
// First Get a local buffer from our lookaside list
|
|
//
|
|
PUNFRAGMENTED_BUFFER pUnfragmentedBuffer = (PUNFRAGMENTED_BUFFER )pLookasideHeader;
|
|
PPACKET_FORMAT pDestination = (PPACKET_FORMAT)&pUnfragmentedBuffer->Data[0];
|
|
//
|
|
// Add the gasp header
|
|
//
|
|
NdisMoveMemory ((PVOID)&pDestination->AsyncStreamNonFragmented.GaspHeader,
|
|
&pAdapter->GaspHeader,
|
|
sizeof (GASP_HEADER) );
|
|
|
|
|
|
//
|
|
// copy the data over, to the location just after the Gasp Header
|
|
// In the unfragmented case, the packet already has the correct header
|
|
//
|
|
NdisStatus = nicCopyNdisBufferChainToBuffer (pStartNdisBuffer,
|
|
(PVOID)&pDestination->AsyncStreamNonFragmented.NonFragmentedHeader,
|
|
pLookasideList->MaxSendSize);
|
|
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
BREAK ( TM_Send, ( " AsyncStreamSendPacketHandler, nicCopyNdisPacketToUnfragmentedBuffer Failed ") );
|
|
}
|
|
|
|
|
|
ASSERT (pLookasideListBuffer != NULL);
|
|
|
|
//
|
|
// Initialize all the variable needed by the Next section of the code.
|
|
// This deals with setting up the Mdl and the IRB
|
|
//
|
|
|
|
pStartNdisBuffer = NULL;
|
|
|
|
Fragment.pStartFragment = (PVOID)pDestination;
|
|
Fragment.FragmentLength = PacketLength + sizeof (GASP_HEADER);
|
|
Fragment.pCurrNdisBuffer = NULL;
|
|
|
|
pLookasideHeader->FragmentsGenerated = 1;
|
|
pLookasideHeader->IsFragmented = FALSE;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We need to fragment
|
|
//
|
|
ULONG Dgl = NdisInterlockedIncrement(&pAdapter->dgl);
|
|
|
|
//
|
|
// Initialize the fragment header. The unfragmented code path
|
|
// does not care about these fields
|
|
//
|
|
Fragment.TxHeaderSize = sizeof (NDIS1394_FRAGMENT_HEADER) + sizeof (GASP_HEADER);
|
|
Fragment.AsyncOp = AsyncStream;
|
|
Fragment.pLookasideList = pLookasideList;
|
|
Fragment.pAdapter = pAdapter;
|
|
Fragment.pLookasideListBuffer = pLookasideListBuffer;
|
|
Fragment.IPDatagramLength = (USHORT)PacketLength - sizeof (NDIS1394_UNFRAGMENTED_HEADER);
|
|
|
|
Fragment.MaxFragmentLength = pChannelVc->Hdr.MaxPayload;
|
|
Fragment.NumFragmentsNeeded = NumFragmentsNeeded;
|
|
|
|
//
|
|
// Allocate from the fragmented pool and initialize the fragment header structure
|
|
//
|
|
|
|
|
|
NdisStatus = nicFirstFragmentInitialization (pPacket->Private.Head,
|
|
Dgl,
|
|
&Fragment);
|
|
|
|
|
|
if (pLookasideListBuffer == NULL || NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
BREAK (TM_Send, (" AsyncStreamSendPacketsHandler: nicFirstFragmentInitialization : FAILED" )) ;
|
|
}
|
|
|
|
ASSERT (pLookasideListBuffer != NULL);
|
|
|
|
pLookasideHeader->IsFragmented = TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Now begin the loop which will send n fragments
|
|
//
|
|
do
|
|
{
|
|
|
|
//
|
|
// Do we need to fragment. If so , extract one fragment out of the NdisPacket
|
|
//
|
|
if (pLookasideHeader->IsFragmented == TRUE )
|
|
{
|
|
|
|
//
|
|
// We copy one fragment over and this will allocate the lookaside list
|
|
//
|
|
|
|
NdisStatus = nicCopyOneFragment (&Fragment);
|
|
if (NDIS_STATUS_SUCCESS != NdisStatus)
|
|
{
|
|
BREAK ( TM_Send, ( " AsyncStreamSendPacketHandler, nicCopyOneFragment Failed ") );
|
|
}
|
|
|
|
//
|
|
// Get the pointer to the Irb here. and set it up for the next time
|
|
//
|
|
//
|
|
pMyIrb = Fragment.pCurrentIrb;
|
|
Fragment.pCurrentIrb = (PIRB)((ULONG_PTR)Fragment.pCurrentIrb + sizeof (IRB) );
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No Curr NdisBuffer as this packet was never fragmented.
|
|
//
|
|
|
|
ASSERT (pLookasideHeader->IsFragmented == FALSE);
|
|
|
|
pMyIrb = &((PUNFRAGMENTED_BUFFER )pLookasideHeader)->Irb;
|
|
}
|
|
|
|
//
|
|
// At this point we have one fragment that needs to be transmitted.
|
|
// Data structures have been updated to set up the MDL and the IRB
|
|
//
|
|
|
|
NdisStatus = nicGetMdl (Fragment.FragmentLength ,
|
|
Fragment.pStartFragment ,
|
|
&pMyMdl);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
BREAK ( TM_Send, ( " AsyncStreamSendPacketHandler, nicCopyNdisBufferChainToBuffer Failed ") );
|
|
}
|
|
|
|
nicIncChannelSendMdl()
|
|
//
|
|
// Fill in the Irb with the correct values from the VC
|
|
// Stuff we need to add to the send VC - BlockSize,Generation
|
|
//
|
|
|
|
nicInitAsyncStreamIrb((PCHANNEL_VCCB)pVc, pMyMdl, pMyIrb);
|
|
|
|
//
|
|
// Get a free Irp
|
|
//
|
|
|
|
NdisStatus = nicGetIrp (pAdapter->pNextDeviceObject, &pMyIrp);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
//
|
|
// At this point, we have a guarantee that the Completion routine will be called
|
|
//
|
|
|
|
//
|
|
// Dump the Fragment
|
|
//
|
|
nicDumpMdl (pMyMdl , 0, "AsyncStream Fragment");
|
|
|
|
NIC1394_LOG_PKT(
|
|
pAdapter,
|
|
NIC1394_LOGFLAGS_SEND_CHANNEL,
|
|
pAdapter->BCRData.LocalNodeNumber, // SourceID
|
|
pChannelVc->Channel,
|
|
Fragment.pStartFragment,
|
|
Fragment.FragmentLength
|
|
);
|
|
|
|
//
|
|
// This function implements the common functionality to be implemented by
|
|
// all other send/recv cals to IoCallDriver
|
|
//
|
|
|
|
//
|
|
// We IGNORE the NtStatus as the completion handler will be called
|
|
//
|
|
nicIncrementBusSends(pVc);
|
|
|
|
NtStatus = nicSubmitIrp(pAdapter->pNextDeviceObject,
|
|
pMyIrp,
|
|
pMyIrb,
|
|
AsyncWriteStreamSendComplete,
|
|
(PVOID)pLookasideListBuffer);
|
|
|
|
TRACE( TL_V, TM_Send, ( " pCurrNdisBuffer %x, NdisStatus %x ", Fragment.pCurrNdisBuffer , NdisStatus ) );
|
|
|
|
|
|
|
|
} while (Fragment.pCurrNdisBuffer != NULL && NdisStatus == NDIS_STATUS_SUCCESS);
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// DO NOT touch the packet if status == NDIS_STATUS_SUCCESS.
|
|
//
|
|
|
|
|
|
//
|
|
// CleanUp if any of the allocations failed. We do not have a pointer
|
|
// to the LocalBuffer (it is embedded in the Mdl) so it remains NULL
|
|
//
|
|
// NdisStatus != Success means that we never got to nicSubmitIrp
|
|
//
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
|
|
ASSERT (pMyIrp == NULL);
|
|
|
|
//
|
|
// fVc Active makes sure that we actually got around to allocating
|
|
// and referencing structures
|
|
//
|
|
|
|
if (fVcActive == TRUE)
|
|
{
|
|
|
|
if (pLookasideListBuffer != NULL)
|
|
{
|
|
|
|
//
|
|
// Complete this fragment, as we never submit'd the IRP to
|
|
// the 1394 bus driver
|
|
//
|
|
AsyncWriteStreamSendComplete(NULL, // PDO
|
|
NULL,
|
|
pLookasideListBuffer);
|
|
|
|
NdisStatus =NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// This thread needs to decrement the refcounts as
|
|
// AsyncWriteStreamSendComplete was not called
|
|
//
|
|
nicDereferenceCall ((PVCCB) pVc, "AsyncStreamSendPacketsHandler");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "<==AsyncStreamSendPacketHandler, NdisStatus %x", NdisStatus ) );
|
|
MATCH_IRQL;
|
|
|
|
//
|
|
// Make sure this is NDIS_STATUS_PENDING if the Irp was sent down or
|
|
// AsyncWriteStreamSendCOmplete was called.
|
|
//
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
nicEthernetVcSend(
|
|
IN PVCCB pVc,
|
|
IN PNDIS_PACKET pPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
reroutes all sends on this VC as an CL receive
|
|
It allocates a packet, moves the NDIS buffer chain into the new packet
|
|
, sets status to Resources (to force a copy) and indicates the packet upto
|
|
the protocols.
|
|
|
|
Arguments:
|
|
pVc Ethernet VC on which this Send came in.
|
|
pPacket - which needs to be indicated up to the protocols.
|
|
|
|
|
|
Return Value:
|
|
Failure if the call to Allocate an NDIS packet fails.
|
|
|
|
--*/
|
|
{
|
|
|
|
PETHERNET_VCCB pEthernetVc = (PETHERNET_VCCB)pVc;
|
|
PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter;
|
|
BOOLEAN fVcActive = FALSE;
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
PNDIS_PACKET pMyPacket = NULL;
|
|
NDIS_STATUS IndicatedStatus= NDIS_STATUS_FAILURE;
|
|
PPKT_CONTEXT pPktContext = NULL;
|
|
|
|
TRACE( TL_T, TM_Send, ( "==>nicEthernetVcSend, pVc %x, pPacket %x",
|
|
pVc , pPacket ) );
|
|
|
|
do
|
|
{
|
|
|
|
|
|
ADAPTER_ACQUIRE_LOCK (pAdapter);
|
|
|
|
if (VC_ACTIVE (pEthernetVc)==TRUE)
|
|
{
|
|
fVcActive = TRUE;
|
|
nicReferenceCall (pVc, "nicEthernetVcSend" ) ;
|
|
|
|
}
|
|
|
|
ADAPTER_RELEASE_LOCK (pAdapter);
|
|
|
|
if (fVcActive == FALSE)
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
nicAllocatePacket (&NdisStatus,
|
|
&pMyPacket ,
|
|
&pEthernetVc->PacketPool );
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS || pMyPacket == NULL)
|
|
{
|
|
pMyPacket = NULL;
|
|
BREAK (TM_Send, "Ethernet VC - AllocatePacket failed" ) ;
|
|
}
|
|
|
|
|
|
pMyPacket->Private.Head = pPacket->Private.Head;
|
|
pMyPacket->Private.Tail = pPacket->Private.Tail;
|
|
|
|
|
|
IndicatedStatus = NDIS_STATUS_RESOURCES;
|
|
NDIS_SET_PACKET_STATUS(pMyPacket, IndicatedStatus);
|
|
|
|
//
|
|
// Set up the context
|
|
//
|
|
pPktContext = (PPKT_CONTEXT)&pMyPacket->MiniportReservedEx;
|
|
pPktContext->EthernetSend.pOrigPacket = pPacket;
|
|
|
|
//
|
|
// Dump the packet
|
|
//
|
|
{
|
|
nicDumpPkt (pMyPacket, "Conn Less Rcv ");
|
|
}
|
|
//
|
|
// Now indicate the packet
|
|
//
|
|
|
|
//
|
|
// Bluff the OOB Size. To get past an assert on debug Ndis
|
|
//
|
|
NDIS_SET_PACKET_HEADER_SIZE (pMyPacket, 14);
|
|
NdisMIndicateReceivePacket (pAdapter->MiniportAdapterHandle,
|
|
&pMyPacket,
|
|
1);
|
|
|
|
|
|
|
|
pPktContext = (PPKT_CONTEXT)&pMyPacket->MiniportReservedEx;
|
|
ASSERT ( pPacket == pPktContext->EthernetSend.pOrigPacket );
|
|
|
|
nicMpCoSendComplete (NDIS_STATUS_SUCCESS,
|
|
pVc,
|
|
pPacket);
|
|
|
|
|
|
//
|
|
// We have successfully pended the Io/
|
|
// Now the completion routine will be called
|
|
//
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
if (pMyPacket != NULL)
|
|
{
|
|
//
|
|
// Free the locally allcoate packet
|
|
//
|
|
nicFreePacket(pMyPacket, &pEthernetVc->PacketPool);
|
|
}
|
|
|
|
if (fVcActive == TRUE)
|
|
{
|
|
nicDereferenceCall (pVc, "nicEthernetVcSend" ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Send, ( "<==nicEthernetVcSend, ") );
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicGetGenerationWorkItem(
|
|
NDIS_WORK_ITEM* pGetGenerationWorkItem,
|
|
IN PVOID Context
|
|
)
|
|
// Function Description:
|
|
// Work Item used to submit a Get Generation IRP at Passive Level
|
|
//
|
|
// Arguments
|
|
//
|
|
// Return Value:
|
|
// Generation -
|
|
|
|
|
|
|
|
{
|
|
PVCCB pVc = (PVCCB) Context;
|
|
PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter;
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
UINT Generation = 0;
|
|
|
|
TRACE( TL_T, TM_Mp, ( "==>nicGetGenerationWorkItem, pVc", Context ) );
|
|
|
|
|
|
NdisStatus = nicGetGenerationCount (pAdapter , &Generation);
|
|
|
|
|
|
//
|
|
// Update the generation
|
|
//
|
|
VC_ACQUIRE_LOCK (pVc);
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS && Generation > *pVc->Hdr.pGeneration )
|
|
{
|
|
pAdapter->Generation = Generation;
|
|
|
|
}
|
|
|
|
VC_CLEAR_FLAGS(pVc, VCBF_GenerationWorkItem);
|
|
|
|
VC_RELEASE_LOCK (pVc);
|
|
|
|
// Dereference the call, this will allow the close call to complete. Do not touch VC after this.
|
|
//
|
|
nicDereferenceCall(pVc, "nicSendFailureInvalidGeneration");
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Mp, ( "<==nicGetGenerationWorkItem, Gen %x", Generation) );
|
|
|
|
FREE_NONPAGED (pGetGenerationWorkItem);
|
|
NdisInterlockedDecrement(&pAdapter->OutstandingWorkItems);
|
|
|
|
}
|
|
|
|
VOID
|
|
nicUpdatePacketState (
|
|
IN PNDIS_PACKET pPacket,
|
|
IN ULONG Tag
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Validates and then updates that packet tag. So we can heep track of the packet
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
switch (Tag)
|
|
{
|
|
case NIC1394_TAG_COMPLETED:
|
|
{
|
|
|
|
*(PULONG)(&pPacket->MiniportReserved[0]) = NIC1394_TAG_COMPLETED;
|
|
|
|
break;
|
|
}
|
|
|
|
case NIC1394_TAG_IN_SEND:
|
|
{
|
|
*(PULONG)(&pPacket->MiniportReserved[0]) = NIC1394_TAG_IN_SEND;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
ASSERT (!"Invalid Tag on NdisPacket");
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicMpCoSendComplete (
|
|
NDIS_STATUS NdisStatus,
|
|
PVCCB pVc,
|
|
PNDIS_PACKET pPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Wrapper function around NdisMCoSendComplete
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
nicIncrementSendCompletes (pVc);
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
nicIncrementVcSendPktCount(pVc, pPacket);
|
|
}
|
|
else
|
|
{
|
|
nicIncrementVcSendFailures (pVc, pPacket);
|
|
}
|
|
|
|
nicUpdatePacketState (pPacket, NIC1394_TAG_COMPLETED);
|
|
|
|
NdisMCoSendComplete(NdisStatus,
|
|
pVc->Hdr.NdisVcHandle,
|
|
pPacket);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT
|
|
nicNumFragmentsNeeded (
|
|
UINT PacketLength ,
|
|
UINT MaxPayload,
|
|
UINT FragmentOverhead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Now account for the Fragment headers as well. A fragment header will be added
|
|
at the head of each fragment. The Unfragmented header at the head of the data
|
|
will be removed
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
FragmentOverhead - the size of the fragment header, in the asyncstream it includes the gasp header+fragment header.
|
|
for asyncwrite it is just the fragmentation header
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
{
|
|
|
|
UINT NewPacketSize;
|
|
UINT TotalCapacitySoFar;
|
|
UINT NumFragmentsNeeded ;
|
|
|
|
ASSERT (PacketLength != 0 );
|
|
ASSERT (MaxPayload != 0) ;
|
|
ASSERT (FragmentOverhead != 0);
|
|
|
|
//
|
|
// This division takes care of the case where PacketLength
|
|
// is an integral multiple of the MaxPayload. Since we add 1 to the fragment
|
|
// it takes care of the overhead added by the fragment headers
|
|
//
|
|
NumFragmentsNeeded = (PacketLength / MaxPayload) + 1;
|
|
|
|
|
|
|
|
//
|
|
// If we add the fragment and gasp header to our fragments, we
|
|
// might need another fragment due to an overflow
|
|
//
|
|
|
|
//
|
|
// Calculate the new packet size after fragmentation
|
|
//
|
|
{
|
|
//
|
|
// Add the length of the fragment headers
|
|
//
|
|
NewPacketSize = PacketLength + (NumFragmentsNeeded * FragmentOverhead);
|
|
|
|
//
|
|
// Now remove the default non-fragment header
|
|
//
|
|
NewPacketSize -= sizeof (NDIS1394_UNFRAGMENTED_HEADER) ;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
TotalCapacitySoFar = NumFragmentsNeeded * MaxPayload;
|
|
|
|
if ( NewPacketSize > TotalCapacitySoFar)
|
|
{
|
|
//
|
|
// We'll need one more fragment
|
|
//
|
|
NumFragmentsNeeded ++;
|
|
}
|
|
|
|
return NumFragmentsNeeded ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicCheckForEthArps (
|
|
IN PNDIS_PACKET pPkt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
It will print the pkt if an eth arp or arp response goes
|
|
through nic1394
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
PNDIS_BUFFER pBuffer;
|
|
ULONG Len;
|
|
ENetHeader* pENetHeader = NULL;
|
|
PETH_ARP_PKT pArp = NULL;
|
|
USHORT PacketType;
|
|
USHORT opcode;
|
|
extern ULONG g_ulDumpEthPacket ;
|
|
do
|
|
{
|
|
|
|
if (g_ulDumpEthPacket == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pBuffer = pPkt->Private.Head;
|
|
Len = NdisBufferLength (pBuffer);
|
|
|
|
if (Len < sizeof (ENetHeader) )
|
|
{
|
|
ASSERT (Len >= sizeof (ENetHeader) );
|
|
break;
|
|
}
|
|
|
|
pENetHeader = (ENetHeader*) NdisBufferVirtualAddress (pBuffer);
|
|
|
|
if (pENetHeader == NULL)
|
|
{
|
|
ASSERT ( pENetHeader != NULL);
|
|
break;
|
|
}
|
|
|
|
PacketType = ntohs (pENetHeader->eh_type);
|
|
|
|
|
|
if (PacketType == ARP_ETH_ETYPE_IP)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (PacketType == ARP_ETH_ETYPE_ARP)
|
|
{
|
|
DbgPrint ("Arp Pkt - ");
|
|
}
|
|
|
|
pArp = (ETH_ARP_PKT*)pENetHeader;
|
|
|
|
opcode = ntohs(pArp->opcode);
|
|
|
|
if (opcode == ARP_ETH_REQUEST )
|
|
{
|
|
DbgPrint ("Request ");
|
|
}
|
|
else if (opcode == ARP_ETH_RESPONSE )
|
|
{
|
|
DbgPrint ("Response ");
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Print the packet
|
|
DbgPrint("\n");
|
|
|
|
{
|
|
|
|
ENetAddr Addr;
|
|
|
|
Addr = pArp->sender_hw_address;
|
|
|
|
DbgPrint ("Sender Hw Addr %x %x %x %x %x %x \n",
|
|
Addr.addr[0],
|
|
Addr.addr[1],
|
|
Addr.addr[2],
|
|
Addr.addr[3],
|
|
Addr.addr[4],
|
|
Addr.addr[5]);
|
|
|
|
DbgPrint ("Ip Addr %x\n",pArp->sender_IP_address);
|
|
|
|
Addr = pArp->target_hw_address;
|
|
|
|
DbgPrint ("Target Hw Addr %x %x %x %x %x %x \n",
|
|
Addr.addr[0],
|
|
Addr.addr[1],
|
|
Addr.addr[2],
|
|
Addr.addr[3],
|
|
Addr.addr[4],
|
|
Addr.addr[5]);
|
|
|
|
DbgPrint ("Ip Addr %x\n",pArp->target_IP_address);
|
|
|
|
}
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
}
|
|
|