UInt32 AgereET131x::outputPacket(mbuf_t m, void * param) { int status = 0; /************************************************************************** Queue is not empty or TCB is not available *************************************************************************/ if( MP_TCB_RESOURCES_NOT_AVAILABLE( &adapter )) { /********************************************************************** NOTE - If there's an error on send, no need to queue the packet under Linux; if we just send an error up to the netif layer, it will resend the skb to us. *********************************************************************/ // IOLog("TCB Resources Not Available\n" ); freePacket(m); netStats->outputErrors += 1; return kIOReturnOutputDropped; } /********************************************************************** We need to see if the link is up; if it's not, make the netif layer think we're good and drop the packet *********************************************************************/ if( MP_SHOULD_FAIL_SEND( &adapter ) ){ freePacket( m ); netStats->outputErrors += 1; return kIOReturnOutputDropped; } status = send_packet( m ); if( status != 0 ){ IOLog( "General error, drop packet(%d)\n", status ); freePacket( m ); netStats->outputErrors += 1; return kIOReturnOutputDropped; } return kIOReturnSuccess; }
NTSTATUS NICWrite( __in PFDO_DATA FdoData, __in PIRP Irp ) /*++ Routine Description: This routine handles the hardware specific write request. If the device is not ready, fail the request. Otherwise get scatter-gather list for the request buffer and send the list to the hardware for DMA. Arguments: FdoData - Pointer to the device context. Irp - Pointer to the write request. Return Value: NT Status code. --*/ { NTSTATUS returnStatus, status; PVOID virtualAddress; ULONG pageCount = 0, length = 0; PMDL tempMdl, mdl; KIRQL oldIrql; #if defined(DMA_VER2) PVOID sgListBuffer; #endif DebugPrint(TRACE, DBG_WRITE, "--> PciDrvWrite %p\n", Irp); Irp->Tail.Overlay.DriverContext[3] = NULL; Irp->Tail.Overlay.DriverContext[2] = NULL; returnStatus = status = STATUS_SUCCESS; // // Is this adapter ready for sending? // if (MP_SHOULD_FAIL_SEND(FdoData)) { DebugPrint(ERROR, DBG_WRITE, "Device not ready %p\n", Irp); returnStatus = status = STATUS_DEVICE_NOT_READY; goto Error; } tempMdl = mdl = Irp->MdlAddress; // // Check for zero length buffer // if (mdl == NULL || MmGetMdlByteCount(mdl) == 0) { DebugPrint(ERROR, DBG_WRITE, "Zero length buffer %p\n", Irp); status = returnStatus = STATUS_INVALID_DEVICE_REQUEST; goto Error; } // // Calculate the total packet length and the number of pages // spanned by all the buffers by walking the MDL chain. // NOTE: If this driver is used in the miniport configuration, it will // not get chained MDLs because the upper filter (NDISEDGE.SYS) // coalesces the fragements to a single contiguous buffer before presenting // the packet to us. // while(tempMdl != NULL) { virtualAddress = MmGetMdlVirtualAddress(tempMdl); length += MmGetMdlByteCount(tempMdl); pageCount += ADDRESS_AND_SIZE_TO_SPAN_PAGES(virtualAddress, length); tempMdl = tempMdl->Next; } if (length < NIC_MIN_PACKET_SIZE) { // // This will never happen in our case because the ndis-edge // pads smaller size packets with zero to make it NIC_MIN_PACKET_SIZE // long. // DebugPrint(ERROR, DBG_WRITE, "Packet size is less than %d\n", NIC_MIN_PACKET_SIZE); status = returnStatus = STATUS_INVALID_DEVICE_REQUEST; goto Error; } // // Check to see if the packet spans more than the physical pages // our hardware can handle or the pageCount exceeds the total number of // map registers allocated. If so, we should coalesce the scattered // buffers to fit the limit. We can't really break the transfers and // DMA in small chunks because each packets has to be DMA'ed in one shot. // The code on how to colesce the packet for this hardware is present // in the original E100BEX sample. // if (pageCount > NIC_MAX_PHYS_BUF_COUNT || pageCount > FdoData->AllocatedMapRegisters) { // TODO: Packet needs to be coalesced DebugPrint(ERROR, DBG_WRITE, "Packet needs to be coalesced\n"); status = returnStatus = STATUS_INVALID_DEVICE_REQUEST; goto Error; } // // Build a scatter-gather list of the packet buffer and send the packet. // // If DMA_VER2 is not defined, use GetScatterGatherList. If the driver // is meant to work on XP and above, define DMA_VER2, so that you can // use BuildScatterGatherList. // // Since Build/GetScatterGatherList should be called at DISPATCH_LEVEL // let us raise the IRQL. // KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); // // Let us mark the IRP pending, because NICProcessSGList is an asynchronous // callback and we wouldn't know the status of the IRP. This IRP may either // get completed by the DPC handler after the DMA transfer or may // get queued if we are low on resources. So the safest thing // to do for us here is return STATUS_PENDING irrespective of what happens // to the IRP. // IoMarkIrpPending(Irp); returnStatus = STATUS_PENDING; #if defined(DMA_VER2) sgListBuffer = ExAllocateFromNPagedLookasideList( &FdoData->SGListLookasideList); if (sgListBuffer) { Irp->Tail.Overlay.DriverContext[2] = sgListBuffer; status = FdoData->DmaAdapterObject->DmaOperations->BuildScatterGatherList( FdoData->DmaAdapterObject, FdoData->Self, mdl, MmGetMdlVirtualAddress(mdl), length, NICProcessSGList, Irp, TRUE, sgListBuffer, FdoData->ScatterGatherListSize); if (!NT_SUCCESS(status)) { DebugPrint(ERROR, DBG_WRITE, "BuildScatterGatherList %x\n", status); ExFreeToNPagedLookasideList(&FdoData->SGListLookasideList, sgListBuffer); Irp->Tail.Overlay.DriverContext[2] = NULL; } } #else status = FdoData->DmaAdapterObject->DmaOperations->GetScatterGatherList( FdoData->DmaAdapterObject, FdoData->Self, mdl, MmGetMdlVirtualAddress(mdl), length, NICProcessSGList, Irp, TRUE); if (!NT_SUCCESS(status)) { DebugPrint(ERROR, DBG_WRITE, "GetScatterGatherList %x\n", status); } #endif KeLowerIrql(oldIrql); Error: if(!NT_SUCCESS(status)){ // // Our call to get the scatter-gather list failed. We know the // NICProcessSGList is not called for sure in that case. So let us // complete the IRP here with failure status. Since we marked the // IRP pending, we have no choice but to return status-pending // even though we are completing the IRP in the incoming thread // context. // NICCompleteSendRequest(FdoData, Irp, status, 0, FALSE); } DebugPrint(LOUD, DBG_WRITE, "<-- PciDrvWrite %x\n", returnStatus); return returnStatus; }