/*++
*******************************************************************************
* Copyright (c) 1990-98 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:

   dxbrap.c

Abstract:

   Routines specific to the tigger chip.

Author:

   Richard Masoner

--*/

#include "digidxb.h"
#include "sradxb.h"
#pragma hdrstop // Stop precomiled header generation


// Dense Firmware
#include "hou2mmap.h"
#include "mipsheader.hh"

// Io and Memory ranges requested by PCI adapters.  
// The RAP/Tigger PCI interface requests 2 PCI ranges: BAR1 points to local memeory on
// the Hercules, and BAR2 points to RAP internal registers.

#define RAP_PCI_MEM_RAM     0
#define RAP_PCI_MEM_TIGGER  1

// offsets in adapter RAM that might be handy

#define RAP_CPU_REGS_OFF                        0x8400  // offset to CPU registers
#define RAP_CPU_INTP                                    (RAP_CPU_REGS_OFF + 0x04)
#define RAP_CPU_INTE                                    (RAP_CPU_REGS_OFF + 0x08)

#define RAP_DMAC_REGS_OFF                       0xc000
#define RAP_DMAC_RXEN                           (RAP_DMAC_REGS_OFF + 0x08)
#define RAP_DMAC_TXEN                           (RAP_DMAC_REGS_OFF + 0x10)
#define RAP_DMAC_TXINTP                         (RAP_DMAC_REGS_OFF + 0x30)
#define RAP_DMAC_RXINTP                         (RAP_DMAC_REGS_OFF + 0x38)
#define RAP_DMAC_RXINTE                         (RAP_DMAC_REGS_OFF + 0x18)
#define RAP_DMAC_TXINTE                         (RAP_DMAC_REGS_OFF + 0x20)

#define RAP_MBOX_REGS_OFF                       0x0000
#define RAP_MBOX_TXFIFO                         (RAP_MBOX_REGS_OFF + 0x00)
#define RAP_MBOX_RXFIFO                         (RAP_MBOX_REGS_OFF + 0x08)

#define RAP_MBOX_XPCI                           (RAP_MBOX_REGS_OFF + 0x10)
#define MB_TX_EMPTY                                     (1 << 0)
#define MB_TX_FULL                                      (1 << 2)
#define MB_RX_EMPTY                                     (1 << 3)
#define MB_RX_FULL                                      (1 << 5)
#define MB_ENABLE_INT_TO_HOST           (1 << 12)

#define RAP_ID_OFF                                      0x8180  // device & vendor ID
#define RAP_REGACCEN_OFF                        0x8160
#define RAP_RESETSTATE_OFF                      0x840c
#define RAP_PROGCNTR_OFF                        0x841c  // tigger program counter

// flags for use in tigger SYSRSTCtrl register 

#define RAP_SYSRSTCTL_OFF                       0x8158  // reset control
#define RAP_SYSRSTCTL_WARMRESET 0x40
#define RAP_SYSRSTCTL_CPURESET  0x20


/* swap a 16 bit int */
STATIC USHORT
swap16(USHORT val)
{
    return ((val << 8) | (val >> 8));
}


/* swap a 32 bit int */
STATIC ULONG
swap32(ULONG val)
{
    ULONG d = (val << 16) | ( val >> 16);
    return ((d >> 8) & 0x00ff00ff) | ((d << 8) & 0xff00ff00);
}


/* Dump the Tigger Program Counter */
#define DUMPPC(P)               dxbRapDumpPC(P, __LINE__)
STATIC VOID
dxbRapDumpPC(IN PDXB_DEVICE_EXTENSION pExt, ULONG Line)
{
    ULONG Reg;

    /* dump the tigger program counter, for debug */
    Reg = READ_REGISTER_ULONG((PVOID)((PUCHAR) pExt->Hardware.Memory2.Virtual + RAP_PROGCNTR_OFF));
}


// Stratus 25/3/02 - Hardware check routines for the Async adapter

NTSTATUS
SraGetSerialNumber(
    PDXB_DEVICE_EXTENSION Adapter,
    PUNICODE_STRING SerialNumber
    );

VOID
dxbRapCheckHardware(
    IN PKDPC Dpc,
    IN PVOID DeferredContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    )
{
    // For now we'll just output the fact that we're running, and then reschedule ourselves
    PDXB_DEVICE_EXTENSION pExt = (PDXB_DEVICE_EXTENSION)DeferredContext;
    LARGE_INTEGER WaitTime;
    ULONG ReadWord;

    if (!pExt->bShutdown && !pExt->bAdapterFailed)
    {
        // Experience says that the BAR 0, offset 0 on the Acceleport should always be 
        // 0xC2 hex, so let's use that as a test...

        ReadWord = READ_REGISTER_UCHAR(
            (PVOID)((PUCHAR) pExt->Hardware.Memory.Virtual));
        if ( ReadWord == 0xff 
#ifdef STRATUS_HAL
             && HalGetSlotStatus(pExt->Hardware.BusNumber,pExt->Hardware.SlotNumber,NULL) != H_ONLINE
#endif
            )
        {
            SRAPRINT(DBGLVL_ALWAYS,("dxbRapCheckHardware: adapter shoot/remove detected!\n"));
            pExt->bAdapterFailed = TRUE;
        }
    }

    if (pExt->bShutdown || pExt->bAdapterFailed)
    {
        // system being shutdown or hardware non-functional - cancel 
        // any outstanding requests
        DxbCancelAdapterIo( pExt, STATUS_IO_DEVICE_ERROR, TRUE/* all */);
    }

    // Schedule us to run again in 2s - do this so we can
    // cancel any future IO that gets scheduled
    if (pExt->bTimerInitialized)
    {
        WaitTime.QuadPart = 2000 * ONE_MILLISECOND;
        KeSetTimer(&pExt->HardwareCheckTimer,
                   WaitTime,
                   &pExt->HardwareCheckDpc);
    }
}

NTSTATUS
dxbRapStartHardwareCheck( IN PDXB_DEVICE_EXTENSION pExt )
{
    LARGE_INTEGER   WaitTime;

    SRAPRINT( DIGIINIT, ( "DxbRapStartHardwareCheck: pExt 0x%x, PnpState 0x%x\n", pExt, pExt->PnpState ) );
    
    if (!pExt->bTimerInitialized)
    {
        KeInitializeTimer(&pExt->HardwareCheckTimer);
        KeInitializeDpc(&pExt->HardwareCheckDpc,dxbRapCheckHardware,(PVOID)pExt);
	    pExt->bTimerInitialized = TRUE;
    }

    WaitTime.QuadPart = 2000 * ONE_MILLISECOND;

    if (KeSetTimer(&pExt->HardwareCheckTimer,
                   WaitTime,
                   &pExt->HardwareCheckDpc))
        return STATUS_SUCCESS;
    else
        return STATUS_UNSUCCESSFUL;
}

NTSTATUS
dxbRapStopHardwareCheck(IN PDXB_DEVICE_EXTENSION pExt)
{
    LARGE_INTEGER Timeout;

    SRAPRINT( DIGIINIT, ( "DxbRapStopHardwareCheck: pExt 0x%x, PnpState 0x%x\n", pExt, pExt->PnpState ) );

    if (pExt->bTimerInitialized) {
        pExt->bTimerInitialized = FALSE;
        if (!KeCancelTimer(&pExt->HardwareCheckTimer))
        {
            // Wait a second for the timer to finish 
            Timeout.QuadPart = 500 * ONE_MILLISECOND;
            KeDelayExecutionThread(KernelMode,FALSE,&Timeout);
        }
    }

    return STATUS_SUCCESS;
}

STATIC NTSTATUS
dxbRapGetGlobalCommonOffset( 
        IN PDXB_DEVICE_EXTENSION pExt, 
        OUT PULONG               pOffset, 
        IN BOOLEAN               fNoDelay )
/*++

Description:

        Read the offset of the GLOBAL_COMMON struct from the card.  

Parameters:

        pExt
                Device extension defining the adapter

        pOffset
                Output Offset value, if successful.

        fNoDelay
                Return after only 1 test.

Return Value:

        STATUS_SUCCESS if pOffset was set correctly, or error.

--*/
{
    LARGE_INTEGER Timeout;
    ULONG i;
    ULONG Count = fNoDelay ? 1 : 50;
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    Timeout.QuadPart = 20 * ONE_MILLISECOND;

    *pOffset = 0;
    for ( i = 0; i < Count; i++ )
    {
        ULONG Offset = DxbAdapterReadDword( pExt, GLOBAL_DATA_OFFSET );
        if ( Offset > 0 && 
             Offset < pExt->Hardware.Memory.Length - sizeof ( GLOBAL_COMMON ) )
        {
            *pOffset = Offset;
            Status = STATUS_SUCCESS;
            break;
        }

        (void)KeDelayExecutionThread( KernelMode, FALSE, &Timeout );
    }

    return Status;
}


STATIC VOID
dxbRapDumpGlobalCommon(
        IN PDXB_DEVICE_EXTENSION pExt)  // ptr to card structure
{
    UCHAR Reg;
    ULONG Offset;
    int i;

    /*
      global_common looks like this:

      u_int32_t         magic;
      u_int32_t         status;
      u_int32_t         revision;
      u_int32_t         heartbeat;
      u_int32_t         bigendian_board;
      u_int32_t         pad1[5];
      RWDATA            rw;
    */
    NTSTATUS Status = dxbRapGetGlobalCommonOffset( pExt, &Offset, TRUE );
    if ( NT_SUCCESS( Status ) )
    {
        // read magic, status, revision, heartbeat, and bigendian_board
        for (i = 0; i < 5*4; i++)
        {
            Reg = READ_REGISTER_UCHAR(
                (PVOID)((PUCHAR) pExt->Hardware.Memory.Virtual + Offset + (i)));
        }
    }
    return;
}


STATIC NTSTATUS
dxbRapAssertReset(
        PDXB_DEVICE_EXTENSION pExt )
/*++

Description:

        Asserts the reset signal to the adapter to hold it in reset.

Parameters:

        pExt
                Device extension for the adapter.

Return Value:

        STATUS_SUCCESS if adapter successfully reset.  Or error status.

--*/
{
    NTSTATUS Status;
    UCHAR Reg;

    Status = STATUS_SUCCESS;

    Reg = READ_REGISTER_UCHAR(
        (PVOID)((PUCHAR) pExt->Hardware.Memory2.Virtual + RAP_SYSRSTCTL_OFF));

    // set warm reset and CPU reset bits.
    // Reset  is cleared later.

    Reg = (RAP_SYSRSTCTL_WARMRESET | RAP_SYSRSTCTL_CPURESET);

    WRITE_REGISTER_UCHAR(
        (PVOID)((PUCHAR)pExt->Hardware.Memory2.Virtual + 0x815b), Reg);

    Reg = READ_REGISTER_UCHAR(
        (PVOID)((PUCHAR) pExt->Hardware.Memory2.Virtual + RAP_SYSRSTCTL_OFF));

    return Status;
}


STATIC NTSTATUS
dxbRapVerifyPost(
        PDXB_DEVICE_EXTENSION pExt )
/*++

Description:

        Verifies the result status of the hardware POST.

Parameters:

        pExt
                Device extension for the adapter

Return Value:

        STATUS_SUCCESS or error

--*/
{
    NTSTATUS Status;
    ULONG CommonOffset;
    ULONG MagicOffset;

    DigiDump( DIGIINIT, ( "DXB: Waiting for Post to start" ) );
    Status = DxbHlcWaitForRunning( pExt, MAGIC_POST, 10000 );

    if ( NT_SUCCESS( Status ) )
    {
        Status = dxbRapGetGlobalCommonOffset( pExt, &CommonOffset, FALSE );
        if ( NT_ERROR( Status ) )
            goto Exit;

        MagicOffset = CommonOffset + FIELD_OFFSET( GLOBAL_COMMON, magic );
        Status = DxbHlcWaitFor( pExt, MagicOffset, MAGIC_POST, 20 );
    }

 Exit:
    DigiDump( DIGIINIT, ( "POST Status %d\n", Status ) );
    return Status;
}


STATIC NTSTATUS
dxbRapPostErrors(
        PDXB_DEVICE_EXTENSION pExt )
/*++

Description:

        Verifies the error count provided by the POST.  If non-zero, fail to load the 
        board.

Parameters:

        pExt
                Device extension for the adapter

Return Value:

        STATUS_SUCCESS or error

--*/
{
    NTSTATUS Status;
    ULONG CommonOffset;
    ULONG ErrorOffset;
    ULONG nErrors;

    Status = DxbHlcWaitForRunning( pExt, MAGIC_POST, 10000 );
    if ( NT_SUCCESS( Status ) )
    {
        Status = dxbRapGetGlobalCommonOffset( pExt, &CommonOffset, FALSE );
        if ( NT_SUCCESS( Status ) )
        {
            ErrorOffset = CommonOffset + FIELD_OFFSET( GLOBAL_POST_DATA, summary.error_count );
            nErrors = DxbAdapterReadDword( pExt, ErrorOffset );
            if ( nErrors )
            {
                Status = STATUS_UNSUCCESSFUL;
                DigiDump( DIGIERROR, ( "*** Dxb!RapPostErrors: Post errors found, count 0x%x! ***\n", nErrors ) );
            }
            else
            {
                Status = STATUS_SUCCESS;
            }
        }
    }
    DigiDump( DIGIINIT, ( "\n" ) );
    return Status;
}


STATIC ULONG 
dxbRapCrc32(
        IN ULONG const CurrentCrc, 
        IN UCHAR const *address, /* this must be unsigned to work */
        IN ULONG const length )
/*++

Description:

        Calculate a CRC on the block of UNSIGNED bytes for the length given.
        The CRC polynomial is 0x04c11db7.

        Swiped from digi mipsbin source.

Parameters:

        pData
                Data block to CRC

        cbData
                Length in bytes of the data block.

Return Value:

        CRC for the data

--*/
{
    ULONG crc_table[256];

    /* build a CRC table */
    {
        ULONG crc_temp;
        ULONG index;
        ULONG index2;
        for (index = 0; index < 256; index++)
        {
            crc_temp = index << 24;
            for (index2 = 0; index2 < 8; index2++)
            {
                if ((crc_temp & 0x80000000) != 0)
                    crc_temp = ((crc_temp << 1) ^ 0x04c11db7);
                else
                    crc_temp = (crc_temp << 1);
            }
            crc_table[index] = crc_temp;
        }
    }

    /* use the table to calculate the CRC for the data */
    {
        ULONG len;
        ULONG Crc = CurrentCrc;

        for (len = length; len > 0; len--)
        {
            ULONG i, j;
            i = (ULONG) *address++;
            i <<= 24;
            Crc ^= i;
            i = Crc;
            i >>= 24;
            j = crc_table[i];
            Crc <<= 8;
            Crc ^= j;
        }
        return Crc;
    }
}


STATIC NTSTATUS
dxbRapVerifyCrc( 
        IN PUCHAR pBuffer, 
        IN ULONG  cbBuf )
{
    ULONG Original = swap32(((struct digiheader *)pBuffer)->checksum);
    ULONG Checksum1 = dxbRapCrc32( 0xFFFFFFFF, pBuffer, FIELD_OFFSET( struct digiheader, checksum ) );
    ULONG Checksum2 = dxbRapCrc32( Checksum1, pBuffer + sizeof (struct digiheader), cbBuf - sizeof (struct digiheader) );

    return Checksum2 == Original ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
}
        


#define HLC_DXB_QUEUE_SIZE                                      0x20000

#define HLC_MASTER_WINDOWED_PAGE_SIZE   0x1000
#define HLC_MASTER_WINDOWED_PAGE_COUNT  32

#if MAX_PAGES < HLC_MASTER_WINDOWED_PAGE_COUNT || MAX_PAGES < HLC_MASTER_WINDOWED_PAGE_COUNT
#error Device Ext has insufficient sized Master.apPages arrays for Hercules adapters!
#endif

#define HLC_MASTER_FLAT_PAGE_SIZE               0x20000
#define HLC_MASTER_FLAT_PAGE_COUNT              1


STATIC VOID
dxbCleanupBusmasterQueues(
        IN PDXB_DEVICE_EXTENSION pExt )
/*++

Description:

        Releases resources acquired by InitBusmasterQueues.

Parameters:

        pExt
                Device extension defining the adapter 

Return Value:

        None

--*/
{
    ULONG ulTempPhysical;
    SRAPRINT(SRA_LOW_LEVEL,("dxbCleanupBusmasterQueues\n"));
    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,("dxbCleanupBusmasterQueues Free Buffers i=%d,"
                                        " pExt->DxbCmdQ.Mode.Master.VirtualPages[i]( 0x%08x), "
                                        " pExt->DxbCmdQ.Mode.Master.PhysicalPages[i]( 0x%08x)\n",
                                        i,pExt->DxbCmdQ.Mode.Master.VirtualPages[i],
                                        pExt->DxbCmdQ.Mode.Master.PhysicalPages[i]
                             ));
#ifdef STRATUS_DEVICE                                             
                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

                    // For Debug print out the HalAllocateBuffer Physical Address
                    // When IOVA is enabled these are only used for to IOVA address.
                    ulTempPhysical = pExt->DxbCmdQ.Mode.Master.PhysicalPagestemp[i].LowPart;

                    DigiDump( DIGIINIT,  ( "HalFreeCommonBuffer "
                                           " pExt->DxbCmdQ.Mode.Master.PhysicalPagestemp[i]"
                                           " Temp Physical ul: 0x%08X"
                                           " or physical: 0x%08X or 0x%08X \n",
                                           ulTempPhysical, pExt->DxbCmdQ.Mode.Master.PhysicalPagestemp[i].LowPart,
                                           pExt->DxbCmdQ.Mode.Master.PhysicalPagestemp[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,("dxbCleanupBusmasterQueues Free Buffer 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_DEVICE
                if (pExt->bIOVAEnabled)
                {
                    SRAPRINT(SRA_LOW_LEVEL,("dxbCleanupBusmasterQueues Free Buffers, Allocation # %d File %s, "
                                            " Line %d\n",
                                            pExt->ulNumberofAllocations, __FILE__, __LINE__));

                    // Stratus Unmap IOVA
                    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
                    // For Debug Print out the Temp Physical
                    ulTempPhysical = pExt->DxbEventQ.Mode.Master.PhysicalPagestemp[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->DxbEventQ.Mode.Master.VirtualPages[i] = NULL;
                }
            }
        }

        DxbCleanupGlobalHostData( pExt );
        pExt->pDmaAdapter = NULL;
    }
}


STATIC NTSTATUS
dxbAllocBusmasterBuffers( 
        PDXB_DEVICE_EXTENSION pExt,
        IN PADAPTER_OBJECT    pDmaAdapter, 
        IN PDXB_MESSAGE_QUEUE pDesc, 
        IN ULONG              nBuffers, 
        IN ULONG              cbBuffer)
{


    NTSTATUS Status;
    ULONG i;
    
    ULONG             ulTempPhysical = 1;

    PVOID pPhysicalAddress;
    ULONG ulPhysical;

    if (pExt->bIOVAEnabled)
    {
        SRAPRINT(SRA_LOW_LEVEL,("Enter dxbAllocBusmasterBuffers, number of Allocations: %d \n", pExt->ulNumberofAllocations));
    }

    DigiDump( DIGIINIT,  ( " Async dxbAllocBusmasterBuffers 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++ )
    {
        PULONG pDword;

        if (pExt->bIOVAEnabled)
        {
            pDesc->Mode.Master.VirtualPages[i] = HalAllocateCommonBuffer( pDmaAdapter, 
                                                                          pDesc->cbPage, 
                                                                          &pDesc->Mode.Master.PhysicalPagestemp[i],
                                                                          FALSE 
                );
        }
        else
        {
            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 : 0x%08x\n", 
                                    pDesc->Mode.Master.VirtualPages[i]));
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto Exit;
        }

                        

#ifdef STRATUS_DEVICE    
        if (pExt->bIOVAEnabled)
        {

            SRAPRINT(SRA_LOW_LEVEL,("HalAllocateCommonBuffer Virtual Addr: 0x%08X and Physical Addr: 0x%08X \n",
                                    pDesc->Mode.Master.VirtualPages[i],
                                    pDesc->Mode.Master.PhysicalPagestemp[i])); // 0x%08x 

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

            // IOVA returned from HalMapCommonBuffer
            pPhysicalAddress =
                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(pPhysicalAddress == NULL)
            {
                SRAPRINT(SRA_LOW_LEVEL,("FAILED 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;
            }

            ulPhysical = (ULONG) pPhysicalAddress;
                           
            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] 
                          ));
                                       
            // Save IOVA allocations, need when deallocating memory 
            pExt->IOVAPhysical_Address[pExt->ulNumberofAllocations] = pDesc->Mode.Master.PhysicalPages[i];
            pExt->ulIOVAbufferSize[pExt->ulNumberofAllocations] = pDesc->cbPage;
            pExt->ulNumberofAllocations++;
        }
        else
#endif
        {
            if ( pDesc->Mode.Master.PhysicalPages[i].QuadPart == 0 )
            {
                SRAPRINT(SRA_LOW_LEVEL,(" STATUS_INSUFFICIENT_RESOURCES for pDesc->Mode.Master.PhysicalPages[i]\n"));
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto Exit;
            }
        }

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

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

        {
            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


    } // End for loop

    Status = STATUS_SUCCESS;

 Exit:
    return Status;
}


STATIC NTSTATUS
dxbInitBusmasterQueues(
        IN PDXB_DEVICE_EXTENSION pExt, 
        IN ULONG                 nBuffers, 
        IN ULONG                 cbBuffer )
/*++

Description:

        Alloc queue buffers for busmaster, along with the required system Dma Adapter 
        object.

Parameters:

        pExt
                Device extension defining the adapter 

        nBuffers
                Count of buffers to alloc

        cbBuffer
                Count of bytes per buffer

Return Value:

        STATUS_SUCCESS or error.

--*/
{
    NTSTATUS Status;
    DEVICE_DESCRIPTION Device = {0};
    ULONG nMapRegisters;
    ULONG i;
    ULONG             ulTempPhysical = 1;

    if (pExt->bIOVAEnabled)
    {
        SRAPRINT(SRA_LOW_LEVEL,("dxbInitBusmasterQueues, Alloc queue buffers for busmaster, Set the number of tries to 0\n"));
        pExt->ulNumberofAllocations = 0;
    }

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

    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 = pExt->Hardware.BusNumber;
    Device.DmaWidth = Width32Bits;
    Device.DmaSpeed = Compatible;
    Device.MaximumLength = pExt->DxbEventQ.cbPage = cbBuffer;
    pExt->pDmaAdapter = HalGetAdapter( &Device, &nMapRegisters );

    if ( pExt->pDmaAdapter == NULL )
    {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto Exit;
    }

    DigiDump( DIGIINIT,  ( "   Command Queue\n" ) );
    Status = dxbAllocBusmasterBuffers( pExt, 
                                       pExt->pDmaAdapter, 
                                       &pExt->DxbCmdQ, 
                                       nBuffers, 
                                       cbBuffer
        );
#if DBG

    for ( i = 0; i < nBuffers; i++ )
    {
        ulTempPhysical = pExt->DxbCmdQ.Mode.Master.PhysicalPagestemp[i].LowPart;

        DigiDump( DIGIINIT,  ( "Command Queue Temp Physical ul: 0x%08X or physical: 0x%08X or 0x%08X \n",
                               ulTempPhysical, pExt->DxbCmdQ.Mode.Master.PhysicalPagestemp[i].LowPart,
                               pExt->DxbCmdQ.Mode.Master.PhysicalPagestemp[i]
                      ));
        ulTempPhysical = pExt->DxbCmdQ.Mode.Master.PhysicalPagestemp[i].LowPart;
        DigiDump( DIGIINIT,  ( "Command Queue IOVA Allocation Virtual 0x%08x"
                               " IOVA Physical 0x%08x \n",
                               pExt->DxbCmdQ.Mode.Master.VirtualPages[i],  
                               pExt->DxbCmdQ.Mode.Master.PhysicalPages[i] 
                      ));

    }
#endif
                             



    if ( NT_ERROR( Status ) )
        goto Exit;


    DigiDump( DIGIINIT,  ( "   Event Queue\n" ) );
    Status = dxbAllocBusmasterBuffers( pExt, 
                                       pExt->pDmaAdapter, 
                                       &pExt->DxbEventQ, 
                                       nBuffers, 
                                       cbBuffer
        );
    //    pExt->DxbEventQ.Mode.Master.
    if ( NT_ERROR( Status ) )
        goto Exit;

#if DBG
    for ( i = 0; i < nBuffers; i++ )
    {
        ulTempPhysical = pExt->DxbEventQ.Mode.Master.PhysicalPagestemp[i].LowPart;
        DigiDump( DIGIINIT,  ( "Event Queue 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]
                      ));

        DigiDump( DIGIINIT,  ( "Event Queue IOVA Allocation Virtual 0x%08x" 
                               " IOVA Physical[i] 0x%08x \n",
                               pExt->DxbEventQ.Mode.Master.VirtualPages[i],
                               pExt->DxbEventQ.Mode.Master.PhysicalPages[i] 
                      ));

    }
#endif
                         
    if ( NT_ERROR( Status ) )
        goto Exit;

    Status = DxbAllocGlobalHostData( pExt, GLOBAL_HOST_OFFSET );

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

    return Status;
}


STATIC NTSTATUS
dxbRapDownloadFep(
        IN PDXB_DEVICE_EXTENSION pExt, 
        IN HANDLE                hKeyParams, 
        IN PCWSTR                pRegValFilename, 
        IN PCWSTR                pDefaultFilename, 
        OUT PULONG               pExecOffset )
/*++

Description:

        This routine grabs the filename from the registry, crc checks the file, and 
        downloads the image to the adapter.

Parameters:

        pExt
                Device extension defining the adapter to start

        hKeyParams
                Handle to open registry key in which to read the filename

        pRegValFilename
                Name of the registry value to read to find the filename to be downloaded

        pDefaultFilename
                The default name is used if the value cannot be read from the registry.

        ExecOffset
                Output value defining adapter offset to start execution of fep, if successful.

Return Value:

        STATUS_SUCCESS if successfully downloaded the image, otherwise error. 

--*/
{
    UNICODE_STRING Filename;
    HANDLE hFile = NULL;
    ULONG cbFile;
    PUCHAR pFileImage;
    NTSTATUS Status;
    LARGE_INTEGER PhysicalZero = {0};

    DigiDump( DIGIINITLOUD, ( "DXB!dxbRapDownloadFep: pExt 0x%x\n", pExt ) );

    RtlInitUnicodeString( &Filename, NULL );
    DigiRegQuerySz( hKeyParams, pRegValFilename, &Filename, DigiRegFlagOptional, pDefaultFilename );

    DigiOpenFile( &Status, &hFile, &cbFile, &Filename, PhysicalZero );

    if ( NT_SUCCESS( Status ) )
        DigiMapFile( &Status, &pFileImage, hFile );

    if ( NT_ERROR( Status ) )
    {
        dxbLogFileNotFound( &Filename );
        goto Exit;
    }

    // Verify and download fep.
    {
        struct digiheader Header;
        USHORT Type;
        ULONG AdapterOffset;
        LONG  ExecOffset;

        Header = *(struct digiheader *)pFileImage;

        Type = *(PUSHORT)Header.type;

        if ( Type != 'OH' )
        {
            dxbLogBadFepImage( &pExt->Name, &Filename, Type );
            Status = STATUS_UNSUCCESSFUL;
            goto Exit;
        }

        Status = dxbRapVerifyCrc( pFileImage, cbFile );

        if ( NT_ERROR( Status ) )
        {
            dxbLogBadFepImage( &pExt->Name, &Filename, Type );
            goto Exit;
        }

#define HLC_SEGMENT_SIZE 4096 
        AdapterOffset = swap16(Header.load_segment) * HLC_SEGMENT_SIZE;

        if ( AdapterOffset + swap16(Header.length) * HLC_SEGMENT_SIZE > pExt->Hardware.Memory.Length )
        {
            dxbLogBadFepImage( &pExt->Name, &Filename, Type );
            Status = STATUS_UNSUCCESSFUL;
            goto Exit;
        }

        DxbAdapterWrite( pExt, pFileImage, AdapterOffset, cbFile );

        {
            // Read downloaded image from adapter and see if it matches
            // what we sent.
            PUCHAR pVerify = DigiAllocMem( NonPagedPool, cbFile );
            if ( pVerify != NULL )
            {
                DxbAdapterRead( pExt, pVerify, AdapterOffset, cbFile );
                Status = dxbRapVerifyCrc( pVerify, cbFile );
                DigiFreeMem( pVerify );
            }
            else
            {
                // Couldn't alloc space to verify.  Assume image is ok.
                Status = STATUS_SUCCESS;
            }
        }

        if ( NT_ERROR( Status ) )
            goto Exit;

        // calculate MIPS start code address
        ExecOffset = AdapterOffset + swap16(Header.exec_start);

        if ( ExecOffset >= swap16(Header.length) * HLC_SEGMENT_SIZE )
        {
            dxbLogBadFepImage( &pExt->Name, &Filename, Type );
            Status = STATUS_UNSUCCESSFUL;
            goto Exit;
        }

        *pExecOffset = ExecOffset;
        Status = STATUS_SUCCESS;
    }

 Exit:

    if ( hFile != NULL )
    {
        DigiUnmapFile( hFile );
        DigiCloseFile( hFile );
    }

    if ( Filename.Buffer )
        DigiRegFreeString( &Filename );

    return Status;      
}


STATIC NTSTATUS
dxbRapStartFep( 
        IN PDXB_DEVICE_EXTENSION pExt, 
        IN HANDLE                hKeyParams )
/*++

Description:

        Read the fep filename from registry, map in file, CRC the file, decode the header, 
        download image to adapter, CRC the image, start the fep and wait for confirmation.

Parameters:

        pExt
                Device extension for the adapter

Return Value:

        STATUS_SUCCESS or error

--*/
{
    NTSTATUS Status;
    ULONG CommonOffset, ExecOffset;

    Status = dxbRapDownloadFep( pExt, hKeyParams, DXB_REGVAL_FEP, 
                                DXB_REGVAL_FEP_ENUM_ACCELEPORT_2000, &ExecOffset );
    if ( NT_ERROR( Status ) )
        goto Exit;

    DigiDump( DIGIINIT, ( "DXB: Fep downloaded successfully\n" ) );

    /* tell firmware that this is a little endian host */
    DxbAdapterWriteDword( pExt, GLOBAL_ENDIAN_OFFSET, 0 );

    /* write MIPS instructions to jump-start the FEP */

    {
        PCHAR pMem;
        ULONG handler = 0xa0000000 + ExecOffset;
        ULONG hihandler = handler >> 16;
        ULONG lohandler = handler & 0xffff;

        /* point to base exception address */
        pMem = (PCHAR) pExt->Hardware.Memory.Virtual + 0;

        WRITE_REGISTER_ULONG( (PVOID)( (PUCHAR)pMem + 0), 
                              swap32(0x3c1a0000 | hihandler)            // lui $k0 hi-half word
            );
        WRITE_REGISTER_ULONG( (PVOID)( (PUCHAR)pMem + 4), 
                              swap32(0x375a0000 | lohandler)            // ori $k0 lo-half word
            );
        WRITE_REGISTER_ULONG( (PVOID)( (PUCHAR)pMem + 8), 
                              swap32(0x03400008)                                                // jr $k0
            );
        WRITE_REGISTER_ULONG( (PVOID)( (PUCHAR)pMem +12), 
                              swap32(0)                                                                 // nop
            );
        WRITE_REGISTER_ULONG( (PVOID)( (PUCHAR)pMem +16), 
                              swap32(0)                                                                 // 0 (cpu number
            );
    }

    /* clear the reset bit */
    {
        UCHAR Reg;

        Reg = READ_REGISTER_UCHAR( (PVOID)((PUCHAR) pExt->Hardware.Memory2.Virtual + RAP_SYSRSTCTL_OFF) );

        // clear the CPU_Reset bit in Sys_RST_Ctrl
        WRITE_REGISTER_UCHAR( (PVOID)((PUCHAR)pExt->Hardware.Memory2.Virtual + 0x815b), 0 );

        Reg = READ_REGISTER_UCHAR( (PVOID)((PUCHAR) pExt->Hardware.Memory2.Virtual + RAP_SYSRSTCTL_OFF) );
    }

    Status = dxbRapGetGlobalCommonOffset( pExt, &CommonOffset, FALSE );
    if ( NT_ERROR( Status ) )
        goto Exit;

    DigiDump( DIGIINIT, ( "DXB: Waiting for fep to start" ) );

    if ( NT_SUCCESS( Status ) )
        Status = DxbHlcWaitForRunning( pExt, MAGIC_FEP, 10000 );

    DigiDump( DIGIINIT, ( "\n" ) );

    if ( NT_SUCCESS( Status ) )
    {
        Status = dxbRapGetGlobalCommonOffset( pExt, &CommonOffset, FALSE );
        if ( NT_SUCCESS( Status ) )
        {
            DigiDump( DIGIINIT,  ( "DXB: Fep started.  Fep Panic offset 0x%x\n", 
                                   CommonOffset + FIELD_OFFSET( GLOBAL_FEP_DATA, panic ) ) );
        }
    }
    else
    {
        NTSTATUS s = dxbRapGetGlobalCommonOffset( pExt, &CommonOffset, FALSE );

        DigiDump( DIGIERROR, ( "DXB: Fep failed to start\n" ) );

        if ( NT_SUCCESS( s ) )
        {
            GLOBAL_FEP_DATA Data;
            DxbAdapterRead( pExt, &Data, CommonOffset, sizeof Data );

            DigiDump( DIGIERROR, ( "DXB: GlobalFepData at 0x%x\n"
                                   "   magic 0x%x\n"
                                   "   status 0x%x\n"
                                   "   revision 0x%x\n"
                                   "   panic offset 0x%x\n", 
                                   CommonOffset, 
                                   Data.common.magic, 
                                   Data.common.status, 
                                   Data.common.revision, 
                                   Data.panic ) );

            if ( Data.common.magic == MAGIC_FEP && Data.panic )
            {
                ULONG Panic;
                DigiDump( DIGIERROR, ( "Panic:\n" ) );

#define ADDR_MASK 0x0FFFFFFF
                Panic = Data.panic & ADDR_MASK; // mask off high byte
                if ( Panic + sizeof Data.panic > pExt->Hardware.Memory.Length )
                {
                    DigiDump( DIGIERROR, ( "   Invalid panic offset!\n" ) );
                    goto Exit;
                }

                {
                    ULONG OffsetErrorString = DxbAdapterReadDword( pExt, Panic ) & ADDR_MASK;
                    if ( OffsetErrorString )
                    {
                        CHAR Buffer[256];
                        DxbAdapterRead( pExt, &Buffer, OffsetErrorString, sizeof Buffer );
                        DigiDump( DIGIERROR, ( "   ErrorString 0x%x (%s)\n", OffsetErrorString, Buffer ) );
                    }
                }
                {

                    ULONG OffsetFileName = DxbAdapterReadDword( pExt, Panic + sizeof(ULONG) ) & ADDR_MASK;
                    if ( OffsetFileName )
                    {
                        CHAR Buffer[256];
                        DxbAdapterRead( pExt, &Buffer, OffsetFileName, sizeof Buffer );
                        DigiDump( DIGIERROR, ( "   Filename 0x%x (%s)\n", OffsetFileName, Buffer ) );
                    }
                }

                {
                    ULONG Linenumber = DxbAdapterReadDword( pExt, Panic + 2 * sizeof(ULONG) );
                    DigiDump( DIGIERROR, ( "   Linenumber %d\n", Linenumber ) );
                }
            }
        }
    }

 Exit:

    return Status;
}


STATIC VOID
dxbRapStopAdapter( 
        IN PDXB_DEVICE_EXTENSION pExt )
{

    if ( pExt->hDsDevice )
    {
        if ( pExt->ControlStreams.Fr )
            (void)DsClose( pExt->ControlStreams.Fr );
        if ( pExt->ControlStreams.Isdn )
            (void)DsClose( pExt->ControlStreams.Isdn );
        if ( pExt->ControlStreams.X25 )
            (void)DsClose( pExt->ControlStreams.X25 );
        if ( pExt->ControlStreams.Lapb )
            (void)DsClose( pExt->ControlStreams.Lapb );

        (void)DsCloseDevice( pExt->hDsDevice );
    }

    // Note that the call to dxbRapStopHardwareCheck is made as late as possible
    // (i.e after the calls to dxbStopxxxTimer() fns) in order to avoid the possibility 
    // of Irp's not getting cancelled properly as a result of stopping too early !

    if ( pExt->Hardware.Memory.fUnmap )
    {
        dxbQueueStopCmdDpcTimer( pExt );
        dxbQueueStopCreditDpcTimer( pExt );

        (void)dxbRapAssertReset( pExt );
//#if !NT5_BUILD || ENABLE_NT5_INTERRUPTS
        if ( pExt->Hardware.Irq.Period > 0 )
        {
            dxbDisconnectInterrupt( pExt );
            pExt->bShutdown = TRUE;
            dxbQueueStopEventDpcTimer( pExt );
        }
        else
//#endif      
        {
            dxbQueueStopEventDpcTimer( pExt );
        }
        dxbRapStopHardwareCheck( pExt );
        dxbAdapterFreeResources( pExt );
    }
    else
    {
        dxbRapStopHardwareCheck( pExt );
    }

    SRAPRINT(SRA_LOW_LEVEL,("dxbRapStopAdapter - Hardware check stopped\n"));

    dxbCleanupBusmasterQueues( pExt );
}


NTSTATUS
dxbRapGetResources(
        IN OUT PDXB_DEVICE_EXTENSION pExt, 
        IN PDIGI_RESOURCE_LIST       pResources )
/*++

Description:

        Map in memory resources.

Parameters:

        pExt
                Device extension for the adapter

        pResources
                Digi resource list defining PCI assigned resources for this adapter.

Return Value:

        STATUS_SUCCESS or failure status.

--*/
{
    // First, map in the PCI Interface Chip
    NTSTATUS Status;

    // The length given for BAR2 (tigger PCI registers) by tigger in RAP2
    // is incorrect
    pResources->Io[RAP_PCI_MEM_TIGGER].Length = 0xd000;

    /* shared memory space */
    Status = dxbMapMemory( &pResources->Io[RAP_PCI_MEM_RAM], &pExt->Hardware.Memory );          

    /* tigger registers */
    if ( NT_SUCCESS( Status ) )
        Status = dxbMapMemory( &pResources->Io[RAP_PCI_MEM_TIGGER], &pExt->Hardware.Memory2 );          

    if ( NT_ERROR( Status ) )
    {
        dxbAdapterFreeResources( pExt );
        goto Exit;
    }

    DigiDump( DIGIINIT,  ( "DXB: Hercules adapter %S resources :\n"
                           " \n\t  Memory:  Physical 0x%08x, Virtual 0x%08x, Length 0x%08x\n"
                           " \n\t  Tigger:  Physical 0x%08x, Virtual 0x%08x, Length 0x%08x\n", 
                           pExt->Name.Buffer, 
                           pExt->Hardware.Memory.Physical.LowPart, 
                           pExt->Hardware.Memory.Virtual, 
                           pExt->Hardware.Memory.Length, 
                           pExt->Hardware.Memory2.Physical.LowPart, 
                           pExt->Hardware.Memory2.Virtual, 
                           pExt->Hardware.Memory2.Length ) );

 Exit:
    return Status;
}


STATIC NTSTATUS
dxbRapStartFirmware(
        IN PDXB_DEVICE_EXTENSION pExt, 
        IN HANDLE                hKeyParams )
/*++

Description:

        Startup a tigger adapter.

Parameters:

        pExt
                Device extension defining the adapter

        hKeyParams
                Handle to opened registry "Parameters" key containing adapter params

Return Value:

        STATUS_SUCCESS or failure status.

--*/
{
    NTSTATUS Status;

    /* reset the adapter */
    Status = dxbRapAssertReset( pExt );

#if 0 // post doesn't work on Tigger yet
    // Verify that POST is running.  If not, try to start it up
    Status = dxbRapVerifyPost( pExt );

    if ( NT_ERROR( Status ) )
    {
        // Post isn't ready.  Reset adapter and try again.
        Status = dxbRapAssertReset( pExt );
        if ( NT_SUCCESS( Status ) )
            Status = dxbRapVerifyPost( pExt );
    }

    if ( NT_ERROR( Status ) )
    {
        dxbLogPostFailed( &pExt->Name );
        goto Exit;
    }

    // Check error count returned by post.  If non-zero, fail
    Status = dxbRapPostErrors( pExt );

    if ( NT_ERROR( Status ) )
    {
        Status = STATUS_UNSUCCESSFUL;
        dxbLogPostErrors( &pExt->Name );
        goto Exit;
    }
#endif

    SRAPRINT( DIGIINIT, ( "DXB!RapStartFirmware: Adapter %S, Post running\n", pExt->Name.Buffer ) );

    dxbQueueInitAccessMethods( pExt, DXB_BUSMODE_MASTER_FLAT );
    DigiInitializeSpinLock( &pExt->DxbCmdQ.Lock );
    DigiInitializeSpinLock( &pExt->DxbEventQ.Lock );
    Status = dxbInitBusmasterQueues(    pExt, HLC_MASTER_FLAT_PAGE_COUNT, HLC_MASTER_FLAT_PAGE_SIZE );
    pExt->DxbBusMode = DXB_BUSMODE_MASTER_FLAT;

    if ( NT_ERROR( Status ) )
    {
        SRAPRINT( DIGIINIT, ( "Failed First Allocation now Try one more time, using !windowed! mode\n"));
        // Try one more time, using "windowed" mode
        dxbQueueInitAccessMethods( pExt, DXB_BUSMODE_MASTER_WINDOWED );
        Status = dxbInitBusmasterQueues(        pExt, HLC_MASTER_WINDOWED_PAGE_COUNT, HLC_MASTER_WINDOWED_PAGE_SIZE );
        pExt->DxbBusMode = DXB_BUSMODE_MASTER_WINDOWED;
    }

    if ( NT_ERROR( Status ) )
        goto Exit;

//#if !NT5_BUILD || ENABLE_NT5_INTERRUPTS
// TODO: The dxbConnectInterrupt needs to be rewritten for W2K. It's using obsolete functions...
    if ( pExt->Hardware.Irq.Period > 0 )
    {
        // The Hercules adapter can be either polled or interrupt driven.
        // If the adpater is polled, then the polling is done through a DPC
        // scheduled through a timer interrupt 100 times per second.
        // If the adapter is interrupt driven, then we set that up instead.
        dxbConnectInterrupt( pExt );
    }
    else
//#endif   
    {
        // Start polling the adapter event queue
        dxbQueueStartEventDpcTimer( pExt );
    }

    SRAPRINT( DIGIINIT, ( "DXB!RapStartFirmware: Adapter %S, starting in %s mode\n", pExt->Name.Buffer, 
                          pExt->DxbBusMode == DXB_BUSMODE_MASTER_FLAT     ? "Busmaster Flat" :
                          pExt->DxbBusMode == DXB_BUSMODE_MASTER_WINDOWED ? "Busmaster Windowed" : "Unknown" ) );

    Status = dxbRapStartFep( pExt, hKeyParams );

    if ( NT_ERROR( Status ) )
    {
        dxbLogFepFailed( &pExt->Name );
        goto Exit;
    }

    // Startup adapter DPC routines
    Status = DsOpenDeviceInternal( pExt->pDeviceObject, &pExt->hDsDevice );
    if ( NT_ERROR( Status ) )
        goto Exit;

    dxbRapStartHardwareCheck( pExt );

    Status = SraMiniportInitialize(pExt);

 Exit:
    return Status;
}


/*
        dxbRapClearIrq()

        To clear the interrupt, we read the mailbox register.
*/
BOOLEAN
dxbRapClearInterrupt( IN PDXB_DEVICE_EXTENSION pExt )
{
    BOOLEAN fOurInterrupt = FALSE;

    ASSERT( pExt != NULL );

    if ( pExt != NULL )
    {
        volatile ULONG xpci = swap32( READ_REGISTER_ULONG( (PVOID)( (PUCHAR) pExt->Hardware.Memory2.Virtual + RAP_MBOX_XPCI ) ) );

        while (( xpci & MB_TX_EMPTY ) == 0 )
        {
            // Read the Tx FIFO until the PCI control register says it's empty
            volatile ULONG txfifo = swap32( READ_REGISTER_ULONG( (PVOID)( (PUCHAR) pExt->Hardware.Memory2.Virtual + RAP_MBOX_TXFIFO ) ) );

            // Indicate to the caller that this board actually generated an interrupt
            fOurInterrupt = TRUE;

            xpci = swap32( READ_REGISTER_ULONG( (PVOID)( (PUCHAR) pExt->Hardware.Memory2.Virtual + RAP_MBOX_XPCI ) ) );
        }
    }

    return fOurInterrupt;
}


NTSTATUS
dxbRapStartAdapterTigger(
        IN PDXB_DEVICE_EXTENSION pExt, 
        IN PUNICODE_STRING       pOption, 
        IN HANDLE                hKeyParams, 
        IN PDIGI_RESOURCE_LIST   pResources )
/*++

Description:

        Startup a Hercules adapter.  Assumes the BusNumber, BusType and
        SlotNumber and Option members of the Ext have been filled in
        from the registry.

Parameters:

        pExt
                Device extension defining the adapter

        pOption
                String defining the adapter type, as read from our registry key, Option.

        hKeyParams
                Handle to opened registry "Parameters" key containing adapter params

        pResources
                Resource assignments (raw and translated) in digi resource format.

Return Value:

        STATUS_SUCCESS or failure status.

--*/
{
    NTSTATUS Status;
    ULONG nLines;

    ASSERT( pExt->Hardware.BusType == PCIBus );

    dxbV2Init( pExt );

    pExt->StopAdapter = dxbRapStopAdapter;
    pExt->AssertReset = dxbRapAssertReset;
    pExt->ClearInterrupt = dxbRapClearInterrupt;

    {
        ULONG fUseInterrupts;
        DigiRegQueryDword( hKeyParams, DXB_REGVAL_USE_INTERRUPTS, &fUseInterrupts, DigiRegFlagOptional, DXB_REGVAL_USE_INTERRUPTS_DEFAULT );

        DigiDump( DIGIINIT,  ( "DXB!dxbRapStartAdapterTigger in Bus %d and Slot %d\n",
                               pExt->Hardware.BusNumber, pExt->Hardware.SlotNumber ) );
//#if !NT5_BUILD || ENABLE_NT5_INTERRUPTS
        if (fUseInterrupts)
        {
#define DXB_REGVAL_INTERRUPTPERIOD                              TEXT( "InterruptPeriod" )
#define DXB_REGVAL_INTERRUPTPERIOD_TYPE         REG_DWORD
#define DXB_REGVAL_INTERRUPTPERIOD_DEFAULT      1
#define DXB_REGVAL_INTERRUPTPERIOD_MAXIMUM      20

            ULONG InterruptPeriod;
            DigiRegQueryDword( hKeyParams, DXB_REGVAL_INTERRUPTPERIOD, &InterruptPeriod, DigiRegFlagOptional, DXB_REGVAL_INTERRUPTPERIOD_DEFAULT );

            if ((InterruptPeriod == 0) || (InterruptPeriod > DXB_REGVAL_INTERRUPTPERIOD_MAXIMUM))
            {
                DigiDump( DIGIWARN,  ( "DXB: Invalid InterruptPeriod value %d read for from registry; resetting to default\n",
                                       InterruptPeriod ) );

                InterruptPeriod = DXB_REGVAL_INTERRUPTPERIOD_DEFAULT;
            }

            DigiDump( DIGIINIT,  ( "DXB: Starting adapter using interrupts (a.k.a low latency)\n"
                                   "   Mode:  LevelSensitive\n"
                                   "   Shared:  TRUE\n"
                                   "   Period:  %d\n", 
                                   InterruptPeriod ) );

#if !NT5_BUILD
            pExt->Hardware.Irq.Mode = LevelSensitive;
#else
            pExt->Hardware.Irq.Mode = pResources->Irq.Mode;
            pExt->Hardware.Irq.Vector = pResources->Irq.Vector;
            pExt->Hardware.Irq.Irql = (UCHAR)pResources->Irq.Level;
            pExt->Hardware.Irq.Affinity = pResources->Irq.Affinity;
#endif
            pExt->Hardware.Irq.fShared = TRUE;
            pExt->Hardware.Irq.Period = InterruptPeriod;
        }
        else
//#endif      
        {
            DigiDump( DIGIINIT,  ( "DXB: Starting adapter in polling mode\n" ) );

            pExt->Hardware.Irq.Mode = 0;
            pExt->Hardware.Irq.fShared = FALSE;
            pExt->Hardware.Irq.Period = 0;
        }
    }

    Status = dxbRapGetResources( pExt, pResources );
    
    if ( NT_ERROR( Status ) )
    {
        dxbLogResourceConflict( &pExt->Name );
        goto Exit;
    }

#ifdef STRATUS_DEVICE
    /*              
                    DigiDump( DIGIINIT, ( "DXB: IRP_MN_START_DEVICE PCI ASYNC Adapter %S resources in Bus %d and Slot %d:\n"
                    "   Memory:  Physical 0x%08x, Virtual 0x%08x, Length 0x%08x\n"
                    "   Control: Physical 0x%08x, Virtual 0x%08x, Length 0x%08x\n"
                    "   Vendor ID: 0x%08x \n",
                    pExt->Name.Buffer, 
                    pExt->Hardware.BusNumber,  // Need to scan for this 
                    pExt->Hardware.SlotNumber, // Also need to scan for this
                    pExt->Hardware.Memory.Physical.LowPart,
                    pExt->Hardware.Memory.Virtual, 
                    pExt->Hardware.Memory.Length, 
                    pExt->Hardware.Memory2.Physical.LowPart,
                    pExt->Hardware.Memory2.Virtual, 
                    pExt->Hardware.Memory2.Length,
                    pExt->Hardware.PciVendorId
                    )); */
    pExt->uBar0Async = (ULONG) pExt->Hardware.Memory.Physical.LowPart;
    pExt->bAsyncDevice = TRUE;
    //Now scan, we have Bar 0 for sync and async
    Status = FindPciSlotEIOVA(pExt);
    if ( NT_SUCCESS( Status ) )  {
                   
        SRAPRINT(SRA_LOW_LEVEL,("Found %s Adapter on Bus %d and Slot%d\n",
                                pExt->Name.Buffer, pExt->Hardware.BusNumber, pExt->Hardware.SlotNumber));
        //Now that we have the BUS and SLOT and State is good we may carry
        //out Miniport Initialization

    }
    else
        SRAPRINT(SRA_LOW_LEVEL,("Could not find DXB Adapter on Bus %d and Slot%d\n",
                                pExt->Hardware.BusNumber, pExt->Hardware.SlotNumber));
            

#endif



    DxbSlaveSetAdapterFlatMemory( pExt );

    if ( NT_SUCCESS( Status ) )
    {
        Status = dxbRapStartFirmware( pExt, hKeyParams );       /* AKA "triboot" */

    }

 Exit:

    if ( NT_ERROR( Status ) )
        dxbRapStopAdapter( pExt );

    return Status;
}
