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;
}
Esempio n. 2
0
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;
}