/*++
*******************************************************************************
* Copyright (c) 1999 Digi International Inc., All Rights Reserved                                  *
*                                                                                                                                                                                                               *
* This software contains proprietary and confidential information of Digi               *
* International Inc.  By accepting transfer of this copy, Recipient agrees              *
* to retain this software in confidence, to prevent disclosure to others,               *
* and to make no use of this software other than that for which it was                  *
* delivered.  This is an unpublished copyrighted work of Digi International     *
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly     *
* prohibited.                                                                                                                                                                           *
*                                                                                                                                                                                                               *
* Restricted Rights Legend                                                                                                                                              *
*                                                                                                                                                                                                               *
* Use, duplication, or disclosure by the Government is subject to                                       *
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in                   *
* Technical Data and Computer Software clause at DFARS 252.227-7031 or                  *
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -                            *
* Restricted Rights at 48 CFR 52.227-19, as applicable.                                                         *
*                                                                                                                                                                                                               *
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343                            *
*                                                                                                                                                                                                               *
*******************************************************************************

Module Name:

   dxbdma.c

Abstract:

   DMA buffer allocation/initialization/cleanup routines.

Author:

   Michael Zarns

--*/
#include "digidxb.h"
#pragma hdrstop

#ifdef STRATUS_DEVICE
#include "sradxb.h"
#endif




STATIC PADAPTER_OBJECT
DxbGetAdapter(
        PDEVICE_OBJECT pPdo,
        ULONG BusNumber,
        ULONG cbMaxDma )
/*++

Description:

        Wrapper for HalGetAdapter.  The returned adapter object is used for allocating 
        busmaster buffers.

Parameters:

        BusNumber
                Bus number on which this adapter lives. 

        cbMaxDma
                Maximum number of bytes the device allows per dma operation.  Typically, use the
                buffer size.

Return Value:

        Pointer to adapter object if successful, otherwise NULL.

--*/
{
    ULONG nMapRegisters;
    DEVICE_DESCRIPTION Device = {0};
    Device.Version = DEVICE_DESCRIPTION_VERSION;
    Device.Master = TRUE;
    Device.ScatterGather = FALSE;
    Device.DemandMode = FALSE;
    Device.AutoInitialize = FALSE;
    Device.Dma32BitAddresses = TRUE;
    Device.IgnoreCount = FALSE;
    Device.BusNumber = BusNumber;
    Device.DmaWidth = Width32Bits;
    Device.DmaSpeed = Compatible;
    Device.MaximumLength = cbMaxDma;

    return HalGetAdapter( &Device, &nMapRegisters );

}


STATIC NTSTATUS
DxbAllocQueueBuffers(
        IN PADAPTER_OBJECT        pDmaAdapter, 
        IN OUT PDXB_MESSAGE_QUEUE pDesc, 
        IN ULONG                  nBuffers, 
        IN ULONG                  cbBuffer,
        IN OUT PDXB_DEVICE_EXTENSION  pExt)
/*++

Description:

        Alloc dma busmaster buffers for a single dxb queue (command or event queue, 
        otherwise called a2h and h2a queues).  Fill in descriptor defining the alloc'd 
        buffers.

Parameters:

        pDmaAdapter
                Adapter object from previous call to DxbGetAdapter.

        pDesc
                Queue descriptor structure.  On successful return, this struct completely 
                describes the 

        nBuffers
                Count of buffers to alloc.  Typically, this is either 1 or n, where n is the max
                supported by the card.  In busmaster_flat mode, there is 1 buffer per queue.  In
                busmaster_paged mode, there are n equally sized buffers (4096 bytes) per queue.

        cbBuffer
                Size of each buffer.  Typically, either 4096 bytes (paged mode) or 
                max_buffer_size (flat mode).

Return Value:

        STATUS_SUCCESS, or error.

--*/
{
    NTSTATUS Status;
    ULONG i;
        
    PULONG pDword;

    ULONG ulPhysical;
    PVOID pvPhysical;

    DigiDump( DIGIINIT,  ( "Enter DxbAllocQueueBuffers: cbPage 0x%08x, nPages 0x%x\n", cbBuffer, nBuffers ) );

    pDesc->cbPage = cbBuffer;
    pDesc->cbTotal = nBuffers * cbBuffer;
    pDesc->Mode.Master.nPages = nBuffers;

    for ( i = 0; i < nBuffers; i++ )
    {
#ifdef STRATUS_IOVA
        if (pExt->bIOVAEnabled)
        {
            pDesc->Mode.Master.VirtualPages[i] = 
                HalAllocateCommonBuffer( pDmaAdapter, 
                                         pDesc->cbPage, 
                                         &pDesc->Mode.Master.PhysicalPagestemp[i],
                                         FALSE );
        }
        else
#endif
        {
            pDesc->Mode.Master.VirtualPages[i] = 
                HalAllocateCommonBuffer( pDmaAdapter, 
                                         pDesc->cbPage, 
                                         &pDesc->Mode.Master.PhysicalPages[i], 
                                         FALSE );
        }


        // Just Check the Virtual Address
        if ( pDesc->Mode.Master.VirtualPages[i] == NULL)
        {
            SRAPRINT(SRA_LOW_LEVEL,("Invalid virtual adress from HalAllocateCommonBuffer\n"));
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto Exit;
        }

#ifdef STRATUS_IOVA
        if (pExt->bIOVAEnabled)
        {
            // Now Check the Physical address
            if ( &pDesc->Mode.Master.PhysicalPagestemp[i].QuadPart == 0)
            {
                SRAPRINT(SRA_LOW_LEVEL,("Invalid Physical Address for Stratus, ignoring HalMapCommonBuffer\n"));
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto Exit;
            }

            pvPhysical = 
                HalMapCommonBuffer(pExt->Hardware.BusNumber,           // DXB Bus number        
                                   pExt->Hardware.SlotNumber,  // DXB Slot Number       
                                   pDesc->Mode.Master.PhysicalPagestemp[i],               // Address to map     
                                   pDesc->cbPage,                 //  Size of memory to map     
                                   (PPHYSICAL_ADDRESS)&pDesc->Mode.Master.PhysicalPages[i] // IOVA phys_address to fill in
                    );

            if(pvPhysical == NULL)
            {
                SRAPRINT(SRA_LOW_LEVEL,("\nFAILED STRATUS IOVA ALLOCATION for bus %d and slot %d Total Number of Allocations %d\n",
                                        pExt->Hardware.BusNumber, pExt->Hardware.SlotNumber, pExt->ulNumberofAllocations));
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto Exit;
            }
            else
                ulPhysical =(ULONG)pvPhysical;
              

            if(pDesc->Mode.Master.PhysicalPages[i].QuadPart == 0) {
                SRAPRINT(SRA_LOW_LEVEL,("\nFAILED STRATUS IOVA ALLOCATION for bus %d and slot %d Total Number of Allocations %d\n",
                            pExt->Hardware.BusNumber, pExt->Hardware.SlotNumber, pExt->ulNumberofAllocations));
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto Exit;
                   

            }
            SRAPRINT(SRA_LOW_LEVEL,("File %s, Line %d\n",__FILE__, __LINE__));
            DigiDump( DIGIINIT,  ( "Stratus IOVA Allocation #%d Page %d, Virtual 0x%08x, IOVA Physical 0x%08x \n",
                                   pExt->ulNumberofAllocations, i,  pDesc->Mode.Master.VirtualPages[i],
                                   pDesc->Mode.Master.PhysicalPages[i]
                          ) );

            // Stroe the Allocated Physical address in the Adapter Device Extension
            //       pDesc->Mode.Master.PhysicalPages[i] = (PHYSICAL_ADDRESS)Adapter->ppTempPhysical;
            pExt->IOVAPhysical_Address[pExt->ulNumberofAllocations] = pDesc->Mode.Master.PhysicalPages[i];
            pExt->ulIOVAbufferSize[pExt->ulNumberofAllocations] = pDesc->cbPage;
            pExt->ulNumberofAllocations++;
        }
        else
#endif
        {
            // Just Check the Physical Address
            if ( pDesc->Mode.Master.PhysicalPages[i].QuadPart == 0)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto Exit;
            }
        }


        pDword = pDesc->Mode.Master.VirtualPages[i];
        pDword[0] = MAGIC_HOSTBUF;
        pDword[1] = i;


#if DBG
        {
            PCHAR const pChar = (PVOID)pDword;
            DigiDump( DIGIINIT,  ( "      Page %d, Virtual 0x%08x, Physical 0x%08x\n", i, 
                                   pDesc->Mode.Master.VirtualPages[i], pDesc->Mode.Master.PhysicalPages[i] ) );
        }
#endif

    }

    Status = STATUS_SUCCESS;

 Exit:
    return Status;
}


VOID
DxbCleanupAdapterQueues(
        IN PDXB_DEVICE_EXTENSION pExt )
/*++

Description:

        Releases resources acquired by InitAdapterQueues

Parameters:

        pExt
                Device extension defining the adapter 

--*/
{
    ULONG ulTempPhysical;
    if ( pExt->pDmaAdapter != NULL )
    {
        ULONG i;
        for ( i = 0; i < MAX_PAGES; i++ )
        {
            if ( pExt->DxbCmdQ.Mode.Master.VirtualPages[i] != NULL )
            {
                          
                SRAPRINT(SRA_LOW_LEVEL,("DxbCleanupAdapterQueues -HalFreeCommonBuffer i=%d,"
                                        "pExt->DxbCmdQ.Mode.Master.VirtualPages[i]( 0x%08x),"
                                        "pExt->DxbCmdQ.Mode.Master.PhysicalPages[i]( 0x%08x)\n\n",
                                        i,pExt->DxbCmdQ.Mode.Master.VirtualPages[i],
                                        pExt->DxbCmdQ.Mode.Master.PhysicalPages[i]
                             ));
#ifdef STRATUS_IOVA
                if (pExt->bIOVAEnabled)
                {
                    SRAPRINT(SRA_LOW_LEVEL,("HalUnmapCommonBuffer Allocation # %d File %s, Line %d\n",
                                            pExt->ulNumberofAllocations, __FILE__, __LINE__));


                        
                    // Stratus Unmap IOVA
                    HalUnmapCommonBuffer(
                        pExt->Hardware.BusNumber,
                        pExt->Hardware.SlotNumber,
                        pExt->DxbCmdQ.cbPage,
                        (ULONG)pExt->DxbCmdQ.Mode.Master.PhysicalPages[i].LowPart
                        );


                    if(pExt->ulNumberofAllocations > 0)
                        pExt->ulNumberofAllocations--;


#if DBG
                    ulTempPhysical = pExt->DxbCmdQ.Mode.Master.PhysicalPages[i].LowPart;
    
                    DigiDump( DIGIINIT,  ( "HalFreeCommonBuffer pExt->DxbCmdQ.Mode.Master.PhysicalPages[i].LowPart"
                                           " Temp Physical ul: 0x%08X"
                                           " or physical: 0x%08X or 0x%08X \n",
                                           ulTempPhysical,pExt->DxbCmdQ.Mode.Master.PhysicalPages[i].LowPart,
                                           pExt->DxbCmdQ.Mode.Master.PhysicalPages[i]
                                  ));
#endif

                    HalFreeCommonBuffer( pExt->pDmaAdapter, pExt->DxbCmdQ.cbPage, 
                                         pExt->DxbCmdQ.Mode.Master.PhysicalPagestemp[i], 
                                         pExt->DxbCmdQ.Mode.Master.VirtualPages[i], FALSE );

                    pExt->DxbCmdQ.Mode.Master.VirtualPages[i] = NULL;


                }
                else
#endif
                {
                    HalFreeCommonBuffer( pExt->pDmaAdapter, pExt->DxbCmdQ.cbPage, 
                                         pExt->DxbCmdQ.Mode.Master.PhysicalPages[i], 
                                         pExt->DxbCmdQ.Mode.Master.VirtualPages[i], FALSE );


                    pExt->DxbCmdQ.Mode.Master.VirtualPages[i] = NULL;
                }

            }
            if ( pExt->DxbEventQ.Mode.Master.VirtualPages[i] != NULL )
            {
                SRAPRINT(SRA_LOW_LEVEL,("DxbCleanupAdapterQueues - i=%d,"
                                        "pExt->DxbEventQ.Mode.Master.VirtualPages[i]( 0x%08x),"
                                        "pExt->DxbEventQ.Mode.Master.PhysicalPages[i]( 0x%08x)\n",
                                        i,pExt->DxbEventQ.Mode.Master.VirtualPages[i],
                                        pExt->DxbEventQ.Mode.Master.PhysicalPages[i]
                             ));
#ifdef STRATUS_IOVA
                if (pExt->bIOVAEnabled)
                {
                    SRAPRINT(SRA_LOW_LEVEL,("HalUnmapCommonBuffer Allocation # %d File %s, Line %d\n",
                                            pExt->ulNumberofAllocations, __FILE__, __LINE__));
                                                    
                    HalUnmapCommonBuffer(
                        pExt->Hardware.BusNumber,
                        pExt->Hardware.SlotNumber,
                        pExt->DxbEventQ.cbPage,
                        (ULONG)pExt->DxbEventQ.Mode.Master.PhysicalPages[i].LowPart
                        );

                    if(pExt->ulNumberofAllocations > 0)
                        pExt->ulNumberofAllocations--;
                                
#if DBG                             
                    ulTempPhysical = pExt->DxbCmdQ.Mode.Master.PhysicalPages[i].LowPart;
    
                    DigiDump( DIGIINIT,  ( "HalFreeCommonBuffer pExt->DxbEventQ.Mode.Master.PhysicalPagestemp[i]"
                                           " Temp Physical ul: 0x%08X"
                                           " or physical: 0x%08X or 0x%08X \n",
                                           ulTempPhysical,pExt->DxbEventQ.Mode.Master.PhysicalPagestemp[i].LowPart,
                                           pExt->DxbEventQ.Mode.Master.PhysicalPagestemp[i]
                                  ));                                
#endif                            
                    
                    
                    
                    HalFreeCommonBuffer( pExt->pDmaAdapter, pExt->DxbEventQ.cbPage, 
                                         pExt->DxbEventQ.Mode.Master.PhysicalPagestemp[i], 
                                         pExt->DxbEventQ.Mode.Master.VirtualPages[i], FALSE );

                    pExt->DxbEventQ.Mode.Master.VirtualPages[i] = NULL;

                }
                else
#endif
                {
                    HalFreeCommonBuffer( pExt->pDmaAdapter, pExt->DxbEventQ.cbPage, 
                                         pExt->DxbEventQ.Mode.Master.PhysicalPages[i], 
                                         pExt->DxbEventQ.Mode.Master.VirtualPages[i], FALSE );

                    pExt->DxbCmdQ.Mode.Master.VirtualPages[i] = NULL;

                }
            }
        }
        pExt->pDmaAdapter = NULL;
    }
}


NTSTATUS
DxbInitAdapterQueues(
        IN PDXB_DEVICE_EXTENSION pExt, 
        IN DXB_BUS_MODE          BusMode,
        IN ULONG                 cbPage,
        IN ULONG                 nPages )
/*++

Description:

        Sets up dxb command and event queues for communicating with the adapter.
        Initializes the device extension for the specified BusMode.  Alloc's
        busmaster buffers if in busmaster mode.

Parameters:

        pExt
                Device extension defining the adapter 

        BusMode
                Defines the mode of operation, MASTER_FLAT, SLAVE, etc.

        cbPage
                The size of a single buffer within the dxb queue.  The dxb queues will be split 
                up into multiple buffers when in BUSMODE_MASTER_WINDOWED mode.

        nPages
                Number of buffers that make up the queue.

Return Value:

        STATUS_SUCCESS or error.

--*/
{
    NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;

    pExt->DxbCmdQ.cbTotal = pExt->DxbEventQ.cbTotal = cbPage * nPages;
    pExt->DxbCmdQ.cbPage  = pExt->DxbEventQ.cbPage  = cbPage;
    pExt->DxbCmdQ.Mode.Master.nPages = pExt->DxbEventQ.Mode.Master.nPages = nPages;
    pExt->DxbBusMode = BusMode;
    pExt->DxbEventQ.QOffset = 0;
    pExt->DxbCmdQ.QOffset = 0;

    dxbQueueInitAccessMethods( pExt, BusMode );
    DigiInitializeSpinLock( &pExt->DxbCmdQ.Lock );
    DigiInitializeSpinLock( &pExt->DxbEventQ.Lock );

    switch ( BusMode )
    {
    case DXB_BUSMODE_MASTER_WINDOWED:
    case DXB_BUSMODE_MASTER_FLAT:
#ifdef STRATUS_IOVA
        if (pExt->bIOVAEnabled)
        {
            SRAPRINT(SRA_LOW_LEVEL,("\nDxbInitAdapterQueues, zero counter\n"));
            pExt->ulNumberofAllocations = 0;
        }
#endif
#if NT5_BUILD
        pExt->pDmaAdapter = DxbGetAdapter( pExt->pPdo, pExt->Hardware.BusNumber, cbPage );
#else
        pExt->pDmaAdapter = DxbGetAdapter( NULL, pExt->Hardware.BusNumber, cbPage );
#endif
        DigiDump(DIGIINIT, ("DXB Device Bus Number: \n", pExt->Hardware.BusNumber));

        if ( pExt->pDmaAdapter == NULL )
            goto Exit;

        DigiDump( DIGIINIT, ( "DXB: Busmaster mode setup:\n"
                              "   Command Queue\n" ) );

        Status = DxbAllocQueueBuffers( pExt->pDmaAdapter, &pExt->DxbCmdQ, nPages, cbPage, pExt);
        if ( NT_ERROR(Status) )
            goto Exit;

        DigiDump( DIGIINIT, ( "   Event Queue\n" ) );
        Status = DxbAllocQueueBuffers( pExt->pDmaAdapter, &pExt->DxbEventQ, nPages, cbPage, pExt );
        break;

    case DXB_BUSMODE_SLAVE:
        Status = STATUS_SUCCESS;
        break;

    default:
        DigiDump( DIGIERROR, ( "Dxb!InitAdapterQueues: Unsupported BusMode 0x%x\n", BusMode ) );
        break;
    }

 Exit:
    if ( NT_ERROR(Status) )
        DxbCleanupAdapterQueues( pExt );

    return Status;
}


VOID
DxbCleanupGlobalHostData( 
        IN PDXB_DEVICE_EXTENSION pExt )
{
    ULONG ulTempPhysical;
    if ( pExt->HlcGlobalHost.Virtual )
    {
        SRAPRINT(SRA_LOW_LEVEL,("DxbCleanupGlobalHostData -(HlcGlobalHost) Virtual 0x%08x Physical 0x%08x\n",
                                pExt->HlcGlobalHost.Virtual, pExt->HlcGlobalHost.Physical));

#ifdef STRATUS_IOVA
        if (pExt->bIOVAEnabled)
        {
            SRAPRINT(SRA_LOW_LEVEL,("HalUnmapCommonBuffer Allocation # %d File %s, Line %d\n",
                                    pExt->ulNumberofAllocations, __FILE__, __LINE__));

            // Stratus Unmap IOVA
            HalUnmapCommonBuffer(
                pExt->Hardware.BusNumber,
                pExt->Hardware.SlotNumber,
                pExt->HlcGlobalHost.Length,
                (ULONG)pExt->HlcGlobalHost.Physical.LowPart
                );

            if(pExt->ulNumberofAllocations > 0)
                pExt->ulNumberofAllocations--;

#if DBG
            // For Debug print out the HalAllocateBuffer Physical Address
            // When IOVA is enabled these are only used for to IOVA address.
            ulTempPhysical = pExt->HlcGlobalHost.Physicaltemp.LowPart;

            DigiDump( DIGIINIT,  ( "HalFreeCommonBuffer pExt->HlcGlobalHost.Physical"
                                   " Temp Physical ul: 0x%08X"
                                   " or physical: 0x%08X or 0x%08X \n",
                                   ulTempPhysical, pExt->HlcGlobalHost.Physicaltemp.LowPart,
                                   pExt->HlcGlobalHost.Physicaltemp
                          ));
#endif


            HalFreeCommonBuffer( pExt->pDmaAdapter, 
                                 pExt->HlcGlobalHost.Length, 
                                 pExt->HlcGlobalHost.Physicaltemp, 
                                 pExt->HlcGlobalHost.Virtual, 
                                 FALSE 
                );
            pExt->HlcGlobalHost.Virtual = NULL;
        }
        else
#endif
        {
            HalFreeCommonBuffer( pExt->pDmaAdapter, 
                                 pExt->HlcGlobalHost.Length, 
                                 pExt->HlcGlobalHost.Physical, 
                                 pExt->HlcGlobalHost.Virtual, FALSE );
            pExt->HlcGlobalHost.Virtual = NULL;
        }
    }

    if ( pExt->HlcQueue.Virtual )
    {
        SRAPRINT(SRA_LOW_LEVEL,("DxbCleanupGlobalHostData  (HlcQueue) Virtual 0x%08x Physical 0x%08x\n",
                                pExt->HlcQueue.Virtual, pExt->HlcQueue.Physical));
#ifdef STRATUS_IOVA
        if (pExt->bIOVAEnabled)                
        {
            SRAPRINT(SRA_LOW_LEVEL,("HalUnmapCommonBuffer Allocation # %d File %s, Line %d\n",
                                    pExt->ulNumberofAllocations, __FILE__, __LINE__));

            // Stratus Unmap IOVA
            HalUnmapCommonBuffer(
                pExt->Hardware.BusNumber,
                pExt->Hardware.SlotNumber,
                pExt->HlcQueue.Length,
                (ULONG)pExt->HlcQueue.Physical.LowPart
                );
            if(pExt->ulNumberofAllocations > 0)
                pExt->ulNumberofAllocations--;

#if DBG
            ulTempPhysical = pExt->HlcQueue.Physicaltemp.LowPart;

            DigiDump( DIGIINIT,  ( "HalFreeCommonBuffer pExt->HlcQueue.Physicaltemp "
                                   " Temp Physical ul: 0x%08X"
                                   " or physical: 0x%08X or 0x%08X \n",
                                   ulTempPhysical, pExt->HlcQueue.Physicaltemp.LowPart,
                                   pExt->HlcQueue.Physicaltemp
                          ));
#endif

            HalFreeCommonBuffer( pExt->pDmaAdapter, 
                                 pExt->HlcQueue.Length, 
                                 pExt->HlcQueue.Physicaltemp, 
                                 pExt->HlcQueue.Virtual, 
                                 FALSE 
                );
            pExt->HlcQueue.Virtual = NULL;
        }
        else
#endif
        {
            HalFreeCommonBuffer( pExt->pDmaAdapter, 
                                 pExt->HlcQueue.Length, 
                                 pExt->HlcQueue.Physical, 
                                 pExt->HlcQueue.Virtual, 
                                 FALSE 
                );
            pExt->HlcQueue.Virtual = NULL;
        }
    }
}


NTSTATUS
DxbAllocGlobalHostData(
        IN PDXB_DEVICE_EXTENSION pExt,
        IN ULONG                 AdapterOffset )
/*++

Description:

        Alloc and init the adapter Global Host Data structure which tells the card where 
        busmaster buffers reside.

Parameters:

        pExt
                Device extension defines the adapter

        AdapterOffset
                Location in card memory at which to place a pointer to the global host data.

Return Value:

        STATUS_SUCCESS or error.

--*/
{
    GLOBAL_HOST_DATA *pGlobal = NULL;
    PDXB_HLC_QUEUE_POINTERS pQueue = NULL;
    NTSTATUS Status;
    ULONG i = 0;

#ifdef STRATUS_IOVA
    // IOVA vars
    PVOID pvPhysical;
    ULONG ulPhysical;
    
    if (pExt->bIOVAEnabled)
    {
        SRAPRINT(SRA_LOW_LEVEL,("DxbInitAdapterQueues,  pExt->ulNumberofAllocations# = %d\n",
                                pExt->ulNumberofAllocations));
    }

    // Alloc buffer for global host data.  

    if (pExt->bIOVAEnabled)
    {
        pGlobal = pExt->HlcGlobalHost.Virtual = HalAllocateCommonBuffer( pExt->pDmaAdapter, 
                                                                         sizeof *pGlobal, 
                                                                         &pExt->HlcGlobalHost.Physicaltemp,
                                                                         FALSE);

    }
    else
#endif
    {
        pGlobal = pExt->HlcGlobalHost.Virtual = HalAllocateCommonBuffer( pExt->pDmaAdapter, 
                                                                         sizeof *pGlobal, 
                                                                         &pExt->HlcGlobalHost.Physical, 
                                                                         FALSE);
    }

    if ( pGlobal == NULL )
    {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto Exit;
    }

#ifdef STRATUS_IOVA
    if (pExt->bIOVAEnabled)
    {
        SRAPRINT(SRA_LOW_LEVEL,("Global host data: HalAllocateCommonBuffer Virtual Addr: "
                                " 0x%08x and Physical Addr: 0x%08x \n",  
                                pExt->HlcGlobalHost.Virtual,
                                pExt->HlcGlobalHost.Physicaltemp));
        // Now Check the Physical address
        if ( pExt->HlcGlobalHost.Physicaltemp.QuadPart == 0)
        {
            SRAPRINT(SRA_LOW_LEVEL,("Invalid Physical Address for Stratus, ignoring HalMapCommonBuffer\n"));
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto Exit;
        }

        pvPhysical =
            HalMapCommonBuffer(pExt->Hardware.BusNumber,           // DXB Bus number            
                               pExt->Hardware.SlotNumber,  // DXB Slot Number   
                               pExt->HlcGlobalHost.Physicaltemp,                  // Address to map     
                               sizeof *pGlobal,                   //  Size of memory to map     
                               (PPHYSICAL_ADDRESS)&pExt->HlcGlobalHost.Physical // IOVA phys_address to fill in
                );

        if(pvPhysical == NULL)
        {
            SRAPRINT(SRA_LOW_LEVEL,("\nFAILED STRATUS IOVA ALLOCATION for bus %d and slot %d "
                                    " Total Number of Allocations %d\n",
                                    pExt->Hardware.BusNumber, pExt->Hardware.SlotNumber, pExt->ulNumberofAllocations));
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto Exit;
        }
        else
            ulPhysical =(ULONG)pvPhysical;
                     
        if(pExt->HlcGlobalHost.Physical.QuadPart == 0) 
        {
            SRAPRINT(SRA_LOW_LEVEL,("\nFAILED STRATUS IOVA ALLOCATION for bus %d and slot %d "
                                    " Total Number of Allocations %d\n",
                                    pExt->Hardware.BusNumber, pExt->Hardware.SlotNumber, pExt->ulNumberofAllocations));
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto Exit;
        }
        SRAPRINT(SRA_LOW_LEVEL,("File %s, Line %d\n",__FILE__, __LINE__));
        DigiDump( DIGIINIT,  ( "Stratus IOVA Allocation #%d  Page %d, Virtual 0x%08x, "
                               " IOVA Physical 0x%08x \n",
                               pExt->ulNumberofAllocations, i,  pExt->HlcGlobalHost.Virtual, 
                               pExt->HlcGlobalHost.Physical                                         
                      ) );

        // Store the Allocated Physical address in the Adapter Device Extension
        pExt->IOVAPhysical_Address[pExt->ulNumberofAllocations] = pExt->HlcGlobalHost.Physical;
        pExt->ulIOVAbufferSize[pExt->ulNumberofAllocations] = sizeof *pGlobal;
        pExt->ulNumberofAllocations++;
    }
    else                // no iova
#endif
    {
        // Just Check the Physical Address
        if ( pExt->HlcGlobalHost.Physical.QuadPart == 0)
        {
            SRAPRINT(SRA_LOW_LEVEL,("IOVA Physical Address not allocated!\n"));
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto Exit;
        }
    }

    RtlZeroMemory( pGlobal, sizeof *pGlobal );

    // Header
    pGlobal->magic = MAGIC_HOST;
    pGlobal->intr_period = pExt->Hardware.Irq.Period;

    // Describe the Command Queue
    pGlobal->dxbphys.host2adapter_q.npages = pExt->DxbCmdQ.Mode.Master.nPages;
    pGlobal->dxbphys.host2adapter_q.pagesize = pExt->DxbCmdQ.cbPage;
    pGlobal->dxbphys.host2adapter_q.pageshift = pGlobal->dxbphys.host2adapter_q.pagesize - 1;
    pGlobal->dxbphys.host2adapter_q.size = pExt->DxbCmdQ.cbTotal;
    pGlobal->dxbphys.host2adapter_q.mask = pGlobal->dxbphys.host2adapter_q.size - 1;
    pGlobal->dxbphys.host2adapter_q.mask4 = pGlobal->dxbphys.host2adapter_q.mask & ~3;
    for ( i = 0; i < pExt->DxbCmdQ.Mode.Master.nPages; i++ )
        pGlobal->dxbphys.host2adapter_q.page[i].bus = pExt->DxbCmdQ.Mode.Master.PhysicalPages[i].LowPart;

    // Describe the Event Queue
    pGlobal->dxbphys.adapter2host_q.npages = pExt->DxbEventQ.Mode.Master.nPages;
    pGlobal->dxbphys.adapter2host_q.pagesize = pExt->DxbEventQ.cbPage;
    pGlobal->dxbphys.adapter2host_q.pageshift = pGlobal->dxbphys.adapter2host_q.pagesize - 1;
    pGlobal->dxbphys.adapter2host_q.size = pExt->DxbEventQ.cbTotal;
    pGlobal->dxbphys.adapter2host_q.mask = pGlobal->dxbphys.adapter2host_q.size - 1;
    pGlobal->dxbphys.adapter2host_q.mask4 = pGlobal->dxbphys.adapter2host_q.mask & ~3;
    for ( i = 0; i < pExt->DxbEventQ.Mode.Master.nPages; i++ )
        pGlobal->dxbphys.adapter2host_q.page[i].bus = pExt->DxbEventQ.Mode.Master.PhysicalPages[i].LowPart;

    // Global host data contains pointers to Queue in/out values.  These must be 
    // cache-line aligned (e.g. 32 byte aligned).  Alloc space for them.

    if (pExt->bIOVAEnabled)
    {
        pQueue = pExt->HlcQueue.Virtual = HalAllocateCommonBuffer( pExt->pDmaAdapter, 
                                                                   sizeof *pQueue,
                                                                   &pExt->HlcQueue.Physicaltemp,
                                                                   FALSE );

    }
    else
    {
        pQueue = pExt->HlcQueue.Virtual = HalAllocateCommonBuffer( pExt->pDmaAdapter, 
                                                                   sizeof *pQueue,
                                                                   &pExt->HlcQueue.Physical, 
                                                                   FALSE );
    }

    if ( pQueue == NULL )
    {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto Exit;
    }
#ifdef STRATUS_IOVA
    if (pExt->bIOVAEnabled)
    {
        SRAPRINT(SRA_LOW_LEVEL,("Global host data: HalAllocateCommonBuffer Virtual Addr: 0x%08x and Physical Addr: 0x%08x \n",  
                                pExt->HlcQueue.Virtual,
                                pExt->HlcQueue.Physicaltemp));
        // Now Check the Physical address
        if ( pExt->HlcQueue.Physicaltemp.QuadPart == 0)
        {
            SRAPRINT(SRA_LOW_LEVEL,("Invalid Physical Address for Stratus DXB QUEUE, ignoring HalMapCommonBuffer\n"));
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto Exit;
        }

        pvPhysical = HalMapCommonBuffer(pExt->Hardware.BusNumber,           // DXB Bus number           
                                        pExt->Hardware.SlotNumber,  // DXB Slot Number  
                                        pExt->HlcQueue.Physicaltemp,              // Address to map     
                                        sizeof *pQueue,                   //  Size of memory to map     
                                        (PPHYSICAL_ADDRESS)&pExt->HlcQueue.Physical // IOVA phys_address to fill in
            );

        if(pvPhysical == NULL)
        {
            SRAPRINT(SRA_LOW_LEVEL,("\nFAILED STRATUS IOVA ALLOCATION DXB QUEUE for bus %d and slot %d Total Number of Allocations %d\n",
                                    pExt->Hardware.BusNumber, pExt->Hardware.SlotNumber, pExt->ulNumberofAllocations));
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto Exit;
        }
        else
            ulPhysical =(ULONG)pvPhysical;
          
        if(pExt->HlcQueue.Physical.QuadPart == 0) 
        {
            SRAPRINT(SRA_LOW_LEVEL,("\nFAILED STRATUS IOVA DXB QUEUE ALLOCATION for bus %d and slot %d Total Number of Allocations %d\n",
                                    pExt->Hardware.BusNumber, pExt->Hardware.SlotNumber, pExt->ulNumberofAllocations));
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto Exit;           
        }
        SRAPRINT(SRA_LOW_LEVEL,("File %s, Line %d\n",__FILE__, __LINE__));
        DigiDump( DIGIINIT,  ( " Stratus IOVA DXB QUEUE Allocation #%d  Page %d, Virtual 0x%08x, IOVA Physical 0x%08x \n",
                               pExt->ulNumberofAllocations, i,  pExt->HlcGlobalHost.Virtual, 
                               pExt->HlcQueue.Physical                                        
                      ) );

        // Stroe the Allocated Physical address in the Adapter Device Extension
        pExt->IOVAPhysical_Address[pExt->ulNumberofAllocations] = pExt->HlcQueue.Physical;
        pExt->ulIOVAbufferSize[pExt->ulNumberofAllocations] = sizeof *pQueue;
        pExt->ulNumberofAllocations++;
    }
    else
#endif
    {
        // Just Check the Physical Address
        if ( pExt->HlcQueue.Physical.QuadPart == 0)
        {
            SRAPRINT(SRA_LOW_LEVEL,("IOVA Physical Address not allocated!\n"));
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto Exit;
        }
    }

    RtlZeroMemory( pQueue, sizeof *pQueue );

    // Point to Queue pointers
    {
        ULONG LogicalBase = pExt->HlcQueue.Physical.LowPart;
        pGlobal->dxbphys.qphys.host2adapter_in  = LogicalBase + FIELD_OFFSET( DXB_HLC_QUEUE_POINTERS, CmdQIn );
        pExt->DxbCmdQ.Descriptor.pQIn = &pQueue->CmdQIn;

        pGlobal->dxbphys.qphys.host2adapter_out = LogicalBase + FIELD_OFFSET( DXB_HLC_QUEUE_POINTERS, CmdQOut );
        pExt->DxbCmdQ.Descriptor.pQOut = &pQueue->CmdQOut;

        pGlobal->dxbphys.qphys.adapter2host_in  = LogicalBase + FIELD_OFFSET( DXB_HLC_QUEUE_POINTERS, EventQIn );
        pExt->DxbEventQ.Descriptor.pQIn = &pQueue->EventQIn;

        pGlobal->dxbphys.qphys.adapter2host_out = LogicalBase + FIELD_OFFSET( DXB_HLC_QUEUE_POINTERS, EventQOut );
        pExt->DxbEventQ.Descriptor.pQOut = &pQueue->EventQOut;
                
        DigiDump( DIGIINIT, ( "Queue Pointers (Virtual Addrs):\n"
                              "   Command Queue: QIn 0x%08x, QOut 0x%08x\n"
                              "   Event Queue:   QIn 0x%08x, QOut 0x%08x\n",
                              pExt->DxbCmdQ.Descriptor.pQIn, pExt->DxbCmdQ.Descriptor.pQOut, 
                              pExt->DxbEventQ.Descriptor.pQIn, pExt->DxbEventQ.Descriptor.pQOut ) );
        DigiDump( DIGIINIT, ( "Queue Pointers (Physical Addrs):\n"
                              "   Command Queue: QIn 0x%08x, QOut 0x%08x\n"
                              "   Event Queue:   QIn 0x%08x, QOut 0x%08x\n",
                              pGlobal->dxbphys.qphys.host2adapter_in, pGlobal->dxbphys.qphys.host2adapter_out, 
                              pGlobal->dxbphys.qphys.adapter2host_in, pGlobal->dxbphys.qphys.adapter2host_out ) );
    }

    DigiDump( DIGIINIT, ( "   Queue Descriptor (GlobalHostOffset):\n"
                          "      Virtual Address: 0x%08x\n"
                          "      Phys Address:    0x%08x\n"
                          "      Magic:           '%c%c%c%c'\n",
                          pExt->HlcGlobalHost.Virtual, pExt->HlcGlobalHost.Physical.LowPart,
                          ((PCHAR)pGlobal)[0], ((PCHAR)pGlobal)[1],((PCHAR)pGlobal)[2],((PCHAR)pGlobal)[3]) );

    // Tell the card where global host data is located
    DxbAdapterWriteDword( pExt, AdapterOffset, pExt->HlcGlobalHost.Physical.LowPart );
    Status = STATUS_SUCCESS;

 Exit:

    if ( NT_ERROR( Status ) )
        DxbCleanupGlobalHostData( pExt );

    return Status;
}
