/*++

Copyright (C) Microsoft Corporation, 1992 - 1999

Module Name:

    scsikd.c

Abstract:

    Debugger Extension Api for interpretting scsiport structures

Author:

    Peter Wieland (peterwie) 16-Oct-1995

Environment:

    User Mode.

Revision History:

    John Strange (johnstra) 17-Apr-2000 : make 64b friendly

--*/

#include "pch.h"

#include "port.h"

FLAG_NAME LuFlags[] = {
    FLAG_NAME(LU_QUEUE_FROZEN),             // 0001
    FLAG_NAME(LU_LOGICAL_UNIT_IS_ACTIVE),   // 0002
    FLAG_NAME(LU_NEED_REQUEST_SENSE),       // 0004
    FLAG_NAME(LU_LOGICAL_UNIT_IS_BUSY),     // 0008
    FLAG_NAME(LU_QUEUE_IS_FULL),            // 0010
    FLAG_NAME(LU_PENDING_LU_REQUEST),       // 0020
    FLAG_NAME(LU_QUEUE_LOCKED),             // 0040
    FLAG_NAME(LU_QUEUE_PAUSED),             // 0080
    {0,0}
};

FLAG_NAME AdapterFlags[] = {
    FLAG_NAME(PD_DEVICE_IS_BUSY),            // 0X00001
    FLAG_NAME(PD_NOTIFICATION_REQUIRED),     // 0X00004
    FLAG_NAME(PD_READY_FOR_NEXT_REQUEST),    // 0X00008
    FLAG_NAME(PD_FLUSH_ADAPTER_BUFFERS),     // 0X00010
    FLAG_NAME(PD_MAP_TRANSFER),              // 0X00020
    FLAG_NAME(PD_LOG_ERROR),                 // 0X00040
    FLAG_NAME(PD_RESET_HOLD),                // 0X00080
    FLAG_NAME(PD_HELD_REQUEST),              // 0X00100
    FLAG_NAME(PD_RESET_REPORTED),            // 0X00200
    FLAG_NAME(PD_PENDING_DEVICE_REQUEST),    // 0X00800
    FLAG_NAME(PD_DISCONNECT_RUNNING),        // 0X01000
    FLAG_NAME(PD_DISABLE_CALL_REQUEST),      // 0X02000
    FLAG_NAME(PD_DISABLE_INTERRUPTS),        // 0X04000
    FLAG_NAME(PD_ENABLE_CALL_REQUEST),       // 0X08000
    FLAG_NAME(PD_TIMER_CALL_REQUEST),        // 0X10000
    FLAG_NAME(PD_WMI_REQUEST),               // 0X20000
    {0,0}
};

VOID
ScsiDumpPdo(
    IN ULONG64 LunAddress,
    IN ULONG Detail,
    IN ULONG Depth
    );

VOID
ScsiDumpFdo(
    ULONG64 Address,
    ULONG Detail,
    ULONG Depth
    );

VOID
ScsiDumpSrbData(
    ULONG64 SrbData,
    ULONG Depth
    );
VOID
ScsiDumpAdapterPerfCounters(
    ULONG64 Adapter,
    ULONG Depth
    );

VOID
ScsiDumpScatterGatherList(
    ULONG64 List,
    ULONG Entries,
    ULONG Depth
    );

VOID
ScsiDumpActiveRequests(
    IN ULONG64 ListHead,
    IN ULONG TickCount,
    IN ULONG Depth
    );

VOID
ScsiDumpScsiportExtension(
    IN ULONG64 Address,
    IN ULONG Detail,
    IN ULONG Depth
    );

VOID
ScsiDumpInterruptData(
    IN ULONG64 Address,
    IN ULONG Detail,
    IN ULONG Depth
    );

VOID
ScsiDumpChildren(
    IN ULONG64 Adapter,
    IN ULONG Depth
    );

PUCHAR 
SecondsToString(
    ULONG Count
    );

VOID
ScsiDumpLocks(
    ULONG64 CommonExtension,
    ULONG Depth
    );

VOID
ScsiDumpQueuedRequests(
    IN ULONG64 DeviceObject,
    IN ULONG TickCount,
    IN ULONG Depth
    );

DECLARE_API(scsiext)

/*++

Routine Description:

    Dumps the device extension for a given device object, or dumps the
    given device extension

Arguments:

    args - string containing the address of the device object or device
           extension

Return Value:

    none

--*/

{
    ULONG64 address;
    ULONG result;
    ULONG detail = 0;
    CSHORT Type;

    //
    // Parse the argument string for the address to dump and for any additional
    // details the caller wishes to have dumped.
    //

    GetAddressAndDetailLevel64(args, &address, &detail);

    //
    // The supplied address may be either the address of a device object or the
    // address of a device extension.  To distinguish which, we treat the 
    // address as a device object and read what would be its type field.  If
    // the 
    //

    result = GetFieldData(address,
                          "scsiport!_DEVICE_OBJECT",
                          "Type",
                          sizeof(CSHORT),
                          &Type
                          );
    if (result) {
        SCSIKD_PRINT_ERROR(result);
        return E_FAIL;
    }
    
    //
    // See if the supplied address holds a device object.  If it does, read the
    // address of the device extension.  Otherwise, we assume the supplied
    // addres holds a device extension and we use it directly.
    //

    if (Type == IO_TYPE_DEVICE) {

        result = GetFieldData(address,
                              "scsiport!_DEVICE_OBJECT",
                              "DeviceExtension",
                              sizeof(ULONG64),
                              &address
                              );
        if (result) {
            SCSIKD_PRINT_ERROR(result);
            return E_FAIL;
        }
    }

    //
    // Call worker routine to dump the information.
    //

    ScsiDumpScsiportExtension(address, detail, 0);

    return S_OK;
}


VOID
ScsiDumpScsiportExtension(
    IN ULONG64 CommonExtension,
    IN ULONG Detail,
    IN ULONG Depth
    )
{
    ULONG tmp;
    ULONG result;

    ULONG64 DeviceObject = 0;
    ULONG IsPdo = 0;
    ULONG IsInitialized = 0;
    ULONG WmiInitialized = 0;
    ULONG WmiMiniPortSupport = 0;
    ULONG CurrentPnpState = 0;    
    ULONG PreviousPnpState = 0;
    ULONG IsRemoved = 0;
    ULONG64 LowerDeviceObject = 0;
    ULONG SrbFlags = 0;
    ULONG64 MajorFunction = 0;
    SYSTEM_POWER_STATE CurrentSystemState = 0;
    DEVICE_POWER_STATE CurrentDeviceState = 0;
    DEVICE_POWER_STATE DesiredDeviceState = 0;
    ULONG64 IdleTimer = 0;
    ULONG64 WmiScsiPortRegInfoBuf = 0;
    ULONG WmiScsiPortRegInfoBufSize = 0;   
    ULONG PagingPathCount = 0;
    ULONG HibernatePathCount = 0;
    ULONG DumpPathCount = 0;
    
    FIELD_INFO deviceFields[] = {
       {"DeviceObject", NULL, 0, COPY, 0, (PVOID) &DeviceObject},
       {"IsPdo", NULL, 0, COPY, 0, (PVOID) &IsPdo},
       {"IsInitialized", NULL, 0, COPY, 0, (PVOID) &IsInitialized},
       {"WmiInitialized", NULL, 0, COPY, 0, (PVOID) &WmiInitialized},
       {"WmiMiniPortSupport", NULL, 0, COPY, 0, (PVOID) &WmiMiniPortSupport},
       {"CurrentPnpState", NULL, 0, COPY, 0, (PVOID) &CurrentPnpState},
       {"PreviousPnpState", NULL, 0, COPY, 0, (PVOID) &PreviousPnpState},
       {"IsRemoved", NULL, 0, COPY, 0, (PVOID) &IsRemoved},
       {"LowerDeviceObject", NULL, 0, COPY, 0, (PVOID) &LowerDeviceObject},
       {"SrbFlags", NULL, 0, COPY, 0, (PVOID) &SrbFlags},
       {"MajorFunction", NULL, 0, COPY, 0, (PVOID) &MajorFunction},
       {"CurrentSystemState", NULL, 0, COPY, 0, (PVOID) &CurrentSystemState},
       {"CurrentDeviceState", NULL, 0, COPY, 0, (PVOID) &CurrentDeviceState},
       {"DesiredDeviceState", NULL, 0, COPY, 0, (PVOID) &DesiredDeviceState},
       {"IdleTimer", NULL, 0, COPY, 0, (PVOID) &IdleTimer},
       {"WmiScsiPortRegInfoBuf", NULL, 0, COPY, 0, (PVOID) &WmiScsiPortRegInfoBuf},
       {"WmiScsiPortRegInfoBufSize", NULL, 0, COPY, 0, (PVOID) &WmiScsiPortRegInfoBufSize},
       {"PagingPathCount", NULL, 0, COPY, 0, (PVOID) &PagingPathCount},
       {"HibernatePathCount", NULL, 0, COPY, 0, (PVOID) &HibernatePathCount},
       {"DumpPathCount", NULL, 0, COPY, 0, (PVOID) &DumpPathCount},
    };

    SYM_DUMP_PARAM DevSym = {
       sizeof (SYM_DUMP_PARAM), 
       "scsiport!_COMMON_EXTENSION", 
       DBG_DUMP_NO_PRINT, 
       CommonExtension,
       NULL, NULL, NULL, 
       sizeof (deviceFields) / sizeof (FIELD_INFO), 
       &deviceFields[0]
    };
    
    result = Ioctl(IG_DUMP_SYMBOL_INFO, &DevSym, DevSym.size);
    if (result) {
        dprintf("%08p: Could not read device object\n", CommonExtension);
        return;
    }
    
    xdprintfEx(Depth, ("Scsiport %s device extension at address %p\n",
               IsPdo ? "physical" : "functional", CommonExtension));

    xdprintfEx(Depth, ("Common Extension:\n"));

    Depth += 1;

    tmp = Depth;

    if(IsInitialized) {
        xdprintfEx(tmp, ("Initialized "));
        tmp = 0;
    }

    if(IsRemoved) {
        xdprintfEx(tmp, ("Removed " ));
        tmp = 0;
    }

    switch(IsRemoved) {
        case REMOVE_PENDING: {
            xdprintfEx(tmp, ("RemovePending"));
            tmp = 0;
            break;
        }

        case REMOVE_COMPLETE: {
            xdprintfEx(tmp, ("RemoveComplete"));
            tmp = 0;
            break;
        }
    }

    if(WmiMiniPortSupport) {
        if(WmiInitialized) {
            xdprintfEx(tmp, ("WmiInit"));
        } else {
            xdprintfEx(tmp, ("Wmi"));
        }
        tmp = 0;
    }

    if(tmp == 0) {
        dprintf("\n");
    }

    tmp = 0;

    xdprintfEx(Depth, ("DO 0x%08p  LowerObject 0x%08p  SRB Flags %#08lx\n",
               DeviceObject,
               LowerDeviceObject,
               SrbFlags));

    xdprintfEx(Depth, ("Current Power (D%d,S%d)  Desired Power D%d Idle %#08lx\n",
               CurrentDeviceState - 1,
               CurrentSystemState - 1,
               DesiredDeviceState - 1,
               IdleTimer));

    xdprintfEx(Depth, ("Current PnP state 0x%x    Previous state 0x%x\n",
               CurrentPnpState,
               PreviousPnpState));

    xdprintfEx(Depth, ("DispatchTable %08p   UsePathCounts (P%d, H%d, C%d)\n",
               MajorFunction,
               PagingPathCount,
               HibernatePathCount,
               DumpPathCount));

    if(WmiMiniPortSupport) {
        xdprintfEx(Depth, ("DispatchTable 0x%08p   WmiInfoSize %#08lx\n",
                   WmiScsiPortRegInfoBuf,
                   WmiScsiPortRegInfoBufSize));
    }

    if(IsPdo) {
        xdprintfEx(Depth - 1, ("Logical Unit Extension:\n"));
        ScsiDumpPdo(CommonExtension, Detail, Depth);
    } else {
        xdprintfEx(Depth - 1, ("Adapter Extension:\n"));
        ScsiDumpFdo(CommonExtension, Detail, Depth);
    }

    if(Detail > 1) {
        ScsiDumpLocks(CommonExtension, Depth - 1);
    }

    return;
}

VOID
ScsiDumpFdo(
    ULONG64 Address,
    ULONG Detail,
    ULONG Depth
    )
{
    ULONG tmp = Depth;
    ULONG result;
    ULONG NumOfFields;

    ULONG   PortNumber = 0;
    UCHAR   IsPnp = 0;
    UCHAR   IsMiniportDetected = 0;
    UCHAR   IsInVirtualSlot = 0;
    UCHAR   HasInterrupt = 0;
    UCHAR   DisablePower = 0;
    UCHAR   DisableStop = 0;
    ULONG64 LowerPdo = 0;
    ULONG64 HwDeviceExtension = 0;
    LONG    ActiveRequestCount = 0;
    ULONG   NumberOfBuses = 0;
    ULONG   MaximumTargetIds = 0;
    ULONG   MaxLuCount = 0;
    ULONG   Flags = 0;
    ULONG64 NonCachedExtension = 0;
    ULONG   IoAddress = 0;
    ULONG   InterruptLevel = 0;
    ULONG   RealBusNumber = 0;
    ULONG   RealSlotNumber = 0;
    LONG    PortTimeoutCounter = 0;
    ULONG   DpcFlags = 0;
    ULONG   SequenceNumber = 0;
    ULONG64 SrbExtensionListHeader = 0;
    ULONG   NumberOfRequests = 0;
    ULONG64 QueueTagBitMap = 0;
    ULONG   QueueTagHint = 0;
    ULONG   HwLogicalUnitExtensionSize = 0;
    ULONG   SrbExtensionSize = 0;
    ULONG   LargeScatterGatherListSize = 0;
    ULONG64 EmergencySrbData = 0;
    ULONG   CommonBufferSize = 0;
    ULONG64 PhysicalCommonBuffer = 0;
    ULONG64 SrbExtensionBuffer = 0;
    ULONG64 InterruptObject = 0;
    ULONG64 InterruptObject2 = 0;
    ULONG64 DmaAdapterObject = 0;
    ULONG64 AllocatedResources = 0;
    ULONG64 TranslatedResources = 0;
    ULONG64 PortConfig = 0;
    ULONG64 PortDeviceMapKey = 0;
    ULONG64 BusDeviceMapKeys = 0;
    UCHAR   RemoveTrackingLookasideListInitialized = 0;
    ULONG64 AddrOfMaxQueueTag = 0;
    ULONG64 SrbDataBlockedRequests = 0;
    ULONG64 SrbDataLookasideList = 0;
    ULONG64 MediumScatterGatherLookasideList = 0;
    ULONG64 RemoveTrackingLookasideList = 0;
    ULONG64 InterruptData = 0;
    UCHAR   MaxQueueTag = 0;
    
    FIELD_INFO deviceFields[] = {
       {"PortNumber", NULL, 0, COPY, 0, (PVOID) &PortNumber},
       {"IsPnp", NULL, 0, COPY, 0, (PVOID) &IsPnp},
       {"IsMiniportDetected", NULL, 0, COPY, 0, (PVOID) &IsMiniportDetected},
       {"IsInVirtualSlot", NULL, 0, COPY, 0, (PVOID) &IsInVirtualSlot},
       {"HasInterrupt", NULL, 0, COPY, 0, (PVOID) &HasInterrupt},
       {"DisablePower", NULL, 0, COPY, 0, (PVOID) &DisablePower},
       {"DisableStop", NULL, 0, COPY, 0, (PVOID) &DisableStop},
       {"LowerPdo", NULL, 0, COPY, 0, (PVOID) &LowerPdo},
       {"HwDeviceExtension", NULL, 0, COPY, 0, (PVOID) &HwDeviceExtension},
       {"ActiveRequestCount", NULL, 0, COPY, 0, (PVOID) &ActiveRequestCount},
       {"NumberOfBuses", NULL, 0, COPY, 0, (PVOID) &NumberOfBuses},
       {"MaximumTargetIds", NULL, 0, COPY, 0, (PVOID) &MaximumTargetIds},
       {"MaxLuCount", NULL, 0, COPY, 0, (PVOID) &MaxLuCount},
       {"Flags", NULL, 0, COPY, 0, (PVOID) &Flags},
       {"NonCachedExtension", NULL, 0, COPY, 0, (PVOID) &NonCachedExtension},
       {"IoAddress", NULL, 0, COPY, 0, (PVOID) &IoAddress},
       {"InterruptLevel", NULL, 0, COPY, 0, (PVOID) &InterruptLevel},
       {"RealBusNumber", NULL, 0, COPY, 0, (PVOID) &RealBusNumber},
       {"RealSlotNumber", NULL, 0, COPY, 0, (PVOID) &RealSlotNumber},
       {"PortTimeoutCounter", NULL, 0, COPY, 0, (PVOID) &PortTimeoutCounter},
       {"DpcFlags", NULL, 0, COPY, 0, (PVOID) &DpcFlags},
       {"SequenceNumber", NULL, 0, COPY, 0, (PVOID) &SequenceNumber},
       {"SrbExtensionListHeader", NULL, 0, COPY, 0, (PVOID) &SrbExtensionListHeader},
       {"NumberOfRequests", NULL, 0, COPY, 0, (PVOID) &NumberOfRequests},
       {"QueueTagBitMap", NULL, 0, COPY, 0, (PVOID) &QueueTagBitMap},
       {"QueueTagHint", NULL, 0, COPY, 0, (PVOID) &QueueTagHint},
       {"HwLogicalUnitExtensionSize", NULL, 0, COPY, 0, (PVOID) &HwLogicalUnitExtensionSize},
       {"SrbExtensionSize", NULL, 0, COPY, 0, (PVOID) &SrbExtensionSize},
       {"LargeScatterGatherListSize", NULL, 0, COPY, 0, (PVOID) &LargeScatterGatherListSize},
       {"EmergencySrbData", NULL, 0, COPY, 0, (PVOID) &EmergencySrbData},
       {"CommonBufferSize", NULL, 0, COPY, 0, (PVOID) &CommonBufferSize},
       {"PhysicalCommonBuffer.QuadPart", NULL, 0, COPY, 0, (PVOID) &PhysicalCommonBuffer},
       {"SrbExtensionBuffer", NULL, 0, COPY, 0, (PVOID) &SrbExtensionBuffer},
       {"InterruptObject", NULL, 0, COPY, 0, (PVOID) &InterruptObject},
       {"InterruptObject2", NULL, 0, COPY, 0, (PVOID) &InterruptObject2},
       {"DmaAdapterObject", NULL, 0, COPY, 0, (PVOID) &DmaAdapterObject},
       {"AllocatedResources", NULL, 0, COPY, 0, (PVOID) &AllocatedResources},
       {"TranslatedResources", NULL, 0, COPY, 0, (PVOID) &TranslatedResources},
       {"PortConfig", NULL, 0, COPY, 0, (PVOID) &PortConfig},
       {"PortDeviceMapKey", NULL, 0, COPY, 0, (PVOID) &PortDeviceMapKey},
       {"BusDeviceMapKeys", NULL, 0, COPY, 0, (PVOID) &BusDeviceMapKeys},
       {"CommonExtension.RemoveTrackingLookasideListInitialized", NULL, 0, COPY, 0, (PVOID) &RemoveTrackingLookasideListInitialized},
       {"MaxQueueTag", NULL, 0, ADDROF, 0, NULL},
       {"SrbDataBlockedRequests", NULL, 0, ADDROF, 0, NULL},
       {"SrbDataLookasideList", NULL, 0, ADDROF, 0, NULL},
       {"MediumScatterGatherLookasideList", NULL, 0, ADDROF, 0, NULL},
       {"CommonExtension.RemoveTrackingLookasideList", NULL, 0, ADDROF, 0, NULL},
       {"InterruptData", NULL, 0, ADDROF, 0, NULL},
    };

    SYM_DUMP_PARAM DevSym = {
       sizeof (SYM_DUMP_PARAM), 
       "scsiport!_ADAPTER_EXTENSION", 
       DBG_DUMP_NO_PRINT, 
       Address,
       NULL, NULL, NULL, 
       sizeof (deviceFields) / sizeof (FIELD_INFO), 
       &deviceFields[0]
    };
    
    result = Ioctl(IG_DUMP_SYMBOL_INFO, &DevSym, DevSym.size);
    if (result) {
        SCSIKD_PRINT_ERROR(result);
        return;
    }

    result = GetFieldData(Address,
                          "scsiport!_ADAPTER_EXTENSION",
                          "MaxQueueTag",
                          sizeof(UCHAR),
                          &MaxQueueTag
                          );
    if (result) {
        SCSIKD_PRINT_ERROR(result);
        return;
    }

    NumOfFields = sizeof (deviceFields) / sizeof (FIELD_INFO);
    InterruptData = deviceFields[NumOfFields-1].address;
    RemoveTrackingLookasideList = deviceFields[NumOfFields-2].address;
    MediumScatterGatherLookasideList = deviceFields[NumOfFields-3].address;
    SrbDataLookasideList = deviceFields[NumOfFields-4].address;
    SrbDataBlockedRequests = deviceFields[NumOfFields-5].address;
    AddrOfMaxQueueTag = deviceFields[NumOfFields-6].address;

    xdprintfEx(Depth, ("Port %d   ", PortNumber));

    if(IsPnp) {
        xdprintfEx(tmp, ("IsPnp "));
        tmp = 0;
    }

    if(IsMiniportDetected) {
        xdprintfEx(tmp, ("MpDetected "));
        tmp = 0;
    }

    if(IsInVirtualSlot) {
        xdprintfEx(tmp, ("VirtualSlot "));
        tmp = 0;
    }

    if(HasInterrupt) {
        xdprintfEx(tmp, ("HasInterrupt"));
        tmp = 0;
    }

    if(DisablePower) {
        xdprintfEx(tmp, ("NoPower"));
        tmp = 0;
    }

    if(DisableStop) {
        xdprintfEx(tmp, ("NoStop"));
        tmp = 0;
    }

    dprintf("\n");

    xdprintfEx(Depth, ("LowerPdo 0x%08p   HwDevExt 0x%08p   Active Requests 0x%08lx\n",
               LowerPdo,
               HwDeviceExtension,
               ActiveRequestCount));

    xdprintfEx(Depth, ("MaxBus 0x%02x   MaxTarget 0x%02x   MaxLun 0x%02x\n",
               NumberOfBuses,
               MaximumTargetIds,
               MaxLuCount));

    DumpFlags(Depth, "Port Flags", Flags, AdapterFlags);

    xdprintfEx(Depth, ("NonCacheExt 0x%08p  IoBase 0x%08x   Int 0x%02x\n",
               NonCachedExtension,
               IoAddress,
               InterruptLevel));

    xdprintfEx(Depth, ("RealBus# 0x%0x  RealSlot# 0x%0x\n",
               RealBusNumber,
               RealSlotNumber));

    xdprintfEx(Depth, ("Timeout 0x%08x   DpcFlags 0x%08x   Sequence 0x%08x\n",
               PortTimeoutCounter,
               DpcFlags,
               SequenceNumber));

    xdprintfEx(Depth, ("Srb Ext Header 0x%08p   No. Requests 0x%08lx\n",
               SrbExtensionListHeader, NumberOfRequests));

    xdprintfEx(Depth, ("QueueTag BitMap 0x%08p   Hint 0x%08lx\n",
               QueueTagBitMap, QueueTagHint));

    xdprintfEx(Depth, ("MaxQueueTag 0x%2x (@0x%08p)\n",
               MaxQueueTag, AddrOfMaxQueueTag));

    xdprintfEx(Depth, ("LuExt Size 0x%08lx   SrbExt Size 0x%08lx\n",
               HwLogicalUnitExtensionSize,
               SrbExtensionSize));

    xdprintfEx(Depth + 1, ("SG List Size - Small %d   Large %d\n",
               SP_SMALL_PHYSICAL_BREAK_VALUE,
               LargeScatterGatherListSize));

    Depth++;

    xdprintfEx(Depth, ("Emergency  - SrbData 0x%08p  Blocked List @0x%08p\n",
               EmergencySrbData,
               SrbDataBlockedRequests));

    xdprintfEx(Depth, ("CommonBuff - Size: 0x%08lx    PA: 0x%016I64x  VA: 0x%08p\n",
               CommonBufferSize,
               PhysicalCommonBuffer,
               SrbExtensionBuffer));

    xdprintfEx(Depth, ("Ke Objects - Int1: 0x%08p    Int2: 0x%08p        Dma: 0x%08p\n",
               InterruptObject,
               InterruptObject2,
               DmaAdapterObject));

    xdprintfEx(Depth, ("Lookaside  - SrbData @ 0x%08p SgList @0x%08p  Remove: @0x%08p\n",
               SrbDataLookasideList,
               MediumScatterGatherLookasideList,
               (RemoveTrackingLookasideListInitialized ?
                  RemoveTrackingLookasideList : 0)));

    xdprintfEx(Depth, ("Resources  - Raw: 0x%08p     Translated: 0x%08p\n",
               AllocatedResources,
               TranslatedResources));

    xdprintfEx(Depth, ("Port Config %08p\n", PortConfig));

    xdprintfEx(Depth, ("DeviceMap Handles: Port %p    Busses %p\n",
               PortDeviceMapKey, BusDeviceMapKeys));

    Depth--;
    ScsiDumpInterruptData(InterruptData,
                          Detail,
                          Depth);

    ScsiDumpAdapterPerfCounters(Address, Depth);

    ScsiDumpChildren(Address, Depth);
    return;
}


VOID
ScsiDumpChildren(
    IN ULONG64 AdapterExtensionAddr,
    IN ULONG Depth
    )

{
    ULONG i;
    ULONG64 realLun;
    ULONG64 realLuns[8];
    ULONG64 lun;
    UCHAR   CurrentPnpState=0, PreviousPnpState=0;
    ULONG   CurrentDeviceState=0;
    ULONG   DesiredDeviceState=0, CurrentSystemState=0;
    ULONG64 DeviceObject=0, NextLogicalUnit=0;
    ULONG   result;
    UCHAR   PathId=0, TargetId=0, Lun=0;
    UCHAR   IsClaimed=0, IsMissing=0, IsEnumerated=0, IsVisible=0, IsMismatched=0;
    ULONG64 b6, b7, b8;

    InitTypeRead(AdapterExtensionAddr, scsiport!_ADAPTER_EXTENSION);
    realLuns[0] = ReadField(LogicalUnitList[0].List);
    realLuns[1] = ReadField(LogicalUnitList[1].List);
    realLuns[2] = ReadField(LogicalUnitList[2].List);
    realLuns[3] = ReadField(LogicalUnitList[3].List);
    realLuns[4] = ReadField(LogicalUnitList[4].List);
    realLuns[5] = ReadField(LogicalUnitList[5].List);
    realLuns[6] = ReadField(LogicalUnitList[6].List);
    realLuns[7] = ReadField(LogicalUnitList[7].List);

    Depth++;

    for (i = 0; i < NUMBER_LOGICAL_UNIT_BINS; i++) {

        realLun = realLuns[i];
        
        while ((realLun != 0) && (!CheckControlC())) {

            FIELD_INFO deviceFields[] = {
               {"PathId",          NULL, 0, COPY, 0, (PVOID) &PathId},
               {"TargetId",        NULL, 0, COPY, 0, (PVOID) &TargetId},
               {"IsClaimed",       NULL, 0, COPY, 0, (PVOID) &IsClaimed},
               {"IsMissing",       NULL, 0, COPY, 0, (PVOID) &IsMissing},
               {"IsEnumerated",    NULL, 0, COPY, 0, (PVOID) &IsEnumerated},
               {"IsVisible",       NULL, 0, COPY, 0, (PVOID) &IsVisible},
               {"IsMismatched",    NULL, 0, COPY, 0, (PVOID) &IsMismatched},
               {"DeviceObject",    NULL, 0, COPY, 0, (PVOID) &DeviceObject},
               {"NextLogicalUnit", NULL, 0, COPY, 0, (PVOID) &NextLogicalUnit},
               {"CommonExtension.CurrentPnpState",    NULL, 0, COPY, 0, (PVOID) &CurrentPnpState},
               {"CommonExtension.PreviousPnpState" ,  NULL, 0, COPY, 0, (PVOID) &PreviousPnpState},
               {"CommonExtension.CurrentDeviceState", NULL, 0, COPY, 0, (PVOID) &CurrentDeviceState},
               {"CommonExtension.DesiredDeviceState", NULL, 0, COPY, 0, (PVOID) &DesiredDeviceState},
               {"CommonExtension.CurrentSystemState", NULL, 0, COPY, 0, (PVOID) &CurrentSystemState},
            };
            SYM_DUMP_PARAM DevSym = {
               sizeof (SYM_DUMP_PARAM), 
               "scsiport!_LOGICAL_UNIT_EXTENSION", 
               DBG_DUMP_NO_PRINT, 
               realLun,
               NULL, NULL, NULL, 
               sizeof (deviceFields) / sizeof (FIELD_INFO), 
               &deviceFields[0]
            };
            
            xdprintfEx(Depth, ("LUN "));
            dprintf("%08p ", realLun);

            if ((Ioctl(IG_DUMP_SYMBOL_INFO, &DevSym, DevSym.size))) {
                dprintf("%08lx: Could not read device object\n", realLun);
                return;
            }

            result = (ULONG) InitTypeRead(realLun, scsiport!_LOGICAL_UNIT_EXTENSION);
            if (result != 0) {
                dprintf("could not init read type (%x)\n", result);
                return;
            }
            lun = ReadField(Lun);
            Lun = (UCHAR) lun;
#if 0
            PathId = ReadField(PathId);
            TargetId = ReadField(TargetId);
            IsClaimed = ReadField(IsClaimed);
            IsMissing = ReadField(IsMissing);
            IsEnumerated = ReadField(IsEnumerated);
            IsVisible = ReadField(IsVisible);
            IsMismatched = ReadField(IsMismatched);
#endif
            dprintf("@ (%3d,%3d,%3d) %c%c%c%c%c pnp(%02x/%02x) pow(%d%c,%d) DevObj %08p\n",
                    PathId,
                    TargetId,
                    Lun,
                    (IsClaimed ? 'c' : ' '),
                    (IsMissing ? 'm' : ' '),
                    (IsEnumerated ? 'e' : ' '),
                    (IsVisible ? 'v' : ' '),
                    (IsMismatched ? 'r' : ' '),
                    CurrentPnpState,
                    PreviousPnpState,
                    CurrentDeviceState - 1,
                    ((DesiredDeviceState == PowerDeviceUnspecified) ? ' ' : '*'),
                    CurrentSystemState - 1,
                    DeviceObject);

            realLun = ReadField(NextLogicalUnit);
        }
    }

    return;
}



VOID
ScsiDumpInterruptData(
    IN ULONG64 Address,
    IN ULONG Detail,
    IN ULONG Depth
    )

{
    ULONG result;
    ULONG NumOfFields;

    //
    // Architecture independent fields declarations.
    //
    //

    ULONG   InterruptFlags;
    ULONG64 CompletedRequests;
    ULONG64 AddrOfCompletedRequests;
    ULONG64 ReadyLogicalUnit;
    ULONG64 WmiMiniPortRequests;
    
    FIELD_INFO deviceFields[] = {
       {"InterruptFlags",      NULL, 0, COPY,   0, (PVOID) &InterruptFlags},
       {"ReadyLogicalUnit",    NULL, 0, COPY,   0, (PVOID) &ReadyLogicalUnit},
       {"WmiMiniPortRequests", NULL, 0, COPY,   0, (PVOID) &WmiMiniPortRequests},
       {"CompletedRequests",   NULL, 0, ADDROF, 0, NULL},
    };
    
    SYM_DUMP_PARAM DevSym = {
       sizeof (SYM_DUMP_PARAM), 
       "scsiport!_INTERRUPT_DATA", 
       DBG_DUMP_NO_PRINT, 
       Address,
       NULL, NULL, NULL, 
       sizeof (deviceFields) / sizeof (FIELD_INFO), 
       &deviceFields[0]
    };

    //
    // Read in the top-level field data.  Quit on failure.
    //

    result = Ioctl(IG_DUMP_SYMBOL_INFO, &DevSym, DevSym.size);
    if (result) {
        dprintf("error reading INTERRUPT_DATA @ %08p\n", Address);
        return;
    }

    //
    // Get address-of information.
    //

    NumOfFields = sizeof (deviceFields) / sizeof (FIELD_INFO);
    AddrOfCompletedRequests = deviceFields[NumOfFields-1].address;

    //
    // Do a separate get of the CompleteRequests field.  This is necessary
    // because the typedump Ioctl doesn't like retreiving both the addr-of
    // and the data-of a field.
    //

    result = GetFieldData(Address,
                          "scsiport!_INTERRUPT_DATA",
                          "CompletedRequests",
                          sizeof(ULONG64),
                          &CompletedRequests
                          );
    if (result) {
        dprintf("error (%08x): @ %s %d\n", result, __FILE__, __LINE__);
        return;
    }
    
    xdprintfEx(Depth, ("Interrupt Data @0x%08p:\n", Address));

    Depth++;

    DumpFlags(Depth, "Flags", InterruptFlags, AdapterFlags);

    xdprintfEx(Depth, ("Ready LUN 0x%08p   Wmi Events 0x%08p\n",
               ReadyLogicalUnit,
               WmiMiniPortRequests));

    {
        ULONG count = 0;
        ULONG64 request = CompletedRequests;

        xdprintfEx(Depth, ("Completed Request List (@0x%08p): ",
                   AddrOfCompletedRequests));

        Depth += 1;

        while((request != 0) && (!CheckControlC())) {
            ULONG64 CompletedRequests;

            if(Detail != 0) {
                if(count == 0) {
                    dprintf("\n");
                }
                xdprintfEx(Depth, ("SrbData 0x%08p   ", request));
            }

            count++;

            result = GetFieldData(request,
                                  "scsiport!_SRB_DATA",
                                  "CompletedRequests",
                                  sizeof(ULONG64),
                                  &CompletedRequests
                                  );
            if (result) {
                dprintf("error (%08x): @ %s %d\n", result, __FILE__, __LINE__);
                return;
            }

            if(Detail != 0) {
                ULONG64 CurrentSrb, CurrentIrp;
                result = GetFieldData(request,
                                      "scsiport!_SRB_DATA",
                                      "CurrentSrb",
                                      sizeof(ULONG64),
                                      &CurrentSrb
                                      );
                if (result) {
                    dprintf("error (%08x): @ %s %d\n", result, __FILE__, __LINE__);
                    return;
                }
                result = GetFieldData(request,
                                      "scsiport!_SRB_DATA",
                                      "CurrentIrp",
                                      sizeof(ULONG64),
                                      &CurrentIrp
                                      );
                if (result) {
                    dprintf("error (%08x): @ %s %d\n", result, __FILE__, __LINE__);
                    return;
                }
                dprintf("Srb 0x%08p   Irp 0x%08p\n",
                        CurrentSrb,
                        CurrentIrp);
            }

            request = CompletedRequests;
        }

        Depth -= 1;

        if((Detail == 0) || (count == 0)) {
            dprintf("%d entries\n", count);
        } else {
            xdprintfEx(Depth + 1, ("%d entries\n", count));
        }
    }

    return;
}


VOID
ScsiDumpPdo(
    IN ULONG64 LunAddress,
    IN ULONG Detail,
    IN ULONG Depth
    )
{
    ULONG result;
    ULONG Fields;

    UCHAR   PathId;
    UCHAR   TargetId;
    UCHAR   Lun;
    ULONG   PortNumber;
    UCHAR   IsClaimed;
    UCHAR   IsMissing;
    UCHAR   IsEnumerated;
    UCHAR   IsVisible;
    UCHAR   IsMismatched;
    ULONG   LunLuFlags;
    UCHAR   RetryCount;
    ULONG   CurrentKey;
    ULONG   QueueLockCount;
    ULONG   QueuePauseCount;
    ULONG64 HwLogicalUnitExtension;
    ULONG64 AdapterExtension;
    LONG    RequestTimeoutCounter;
    ULONG64 NextLogicalUnit;
    ULONG64 ReadyLogicalUnit;
    ULONG64 PendingRequest;
    ULONG64 BusyRequest;
    ULONG64 CurrentUntaggedRequest;
    ULONG64 CompletedAbort;
    ULONG64 AbortSrb;
    ULONG   QueueCount;
    ULONG   MaxQueueDepth;
    ULONG64 TargetDeviceMapKey;
    ULONG64 LunDeviceMapKey;
    ULONG64 ActiveFailedRequest;
    ULONG64 BlockedFailedRequest;
    ULONG64 RequestSenseIrp;
    ULONG64 BypassSrbDataList_Next;
    ULONG64 RequestList_Flink;
    ULONG64 CommonExtension_DeviceObject;
    ULONG64 AddrOf_InquiryData;
    ULONG64 AddrOf_RequestSenseSrb;
    ULONG64 AddrOf_RequestSenseMdl;
    ULONG64 AddrOf_BypassSrbDataBlocks;
    ULONG64 AddrOf_RequestList;

    ULONG Adapter_TickCount;

    FIELD_INFO deviceFields[] = {
       {"PathId", NULL, 0, COPY, 0, (PVOID) &PathId},
       {"TargetId", NULL, 0, COPY, 0, (PVOID) &TargetId},
       {"Lun", NULL, 0, COPY, 0, (PVOID) &Lun},
       {"PortNumber", NULL, 0, COPY, 0, (PVOID) &PortNumber},
       {"IsClaimed", NULL, 0, COPY, 0, (PVOID) &IsClaimed},
       {"IsMissing", NULL, 0, COPY, 0, (PVOID) &IsMissing},
       {"IsEnumerated", NULL, 0, COPY, 0, (PVOID) &IsEnumerated},
       {"IsVisible", NULL, 0, COPY, 0, (PVOID) &IsVisible},
       {"IsMismatched", NULL, 0, COPY, 0, (PVOID) &IsMismatched},
       {"LuFlags", NULL, 0, COPY, 0, (PVOID) &LunLuFlags},
       {"RetryCount", NULL, 0, COPY, 0, (PVOID) &RetryCount},
       {"CurrentKey", NULL, 0, COPY, 0, (PVOID) &CurrentKey},
       {"QueueCount", NULL, 0, COPY, 0, (PVOID) &QueueCount},
       {"QueueLockCount", NULL, 0, COPY, 0, (PVOID) &QueueLockCount},
       {"QueuePauseCount", NULL, 0, COPY, 0, (PVOID) &QueuePauseCount},       
       {"HwLogicalUnitExtension", NULL, 0, COPY, 0, (PVOID) &HwLogicalUnitExtension},
       {"AdapterExtension", NULL, 0, COPY, 0, (PVOID) &AdapterExtension},
       {"RequestTimeoutCounter", NULL, 0, COPY, 0, (PVOID) &RequestTimeoutCounter},
       {"NextLogicalUnit", NULL, 0, COPY, 0, (PVOID) &NextLogicalUnit},
       {"ReadyLogicalUnit", NULL, 0, COPY, 0, (PVOID) &ReadyLogicalUnit},
       {"PendingRequest", NULL, 0, COPY, 0, (PVOID) &PendingRequest},       
       {"BusyRequest", NULL, 0, COPY, 0, (PVOID) &BusyRequest},
       {"CurrentUntaggedRequest", NULL, 0, COPY, 0, (PVOID) &CurrentUntaggedRequest},
       {"CompletedAbort", NULL, 0, COPY, 0, (PVOID) &CompletedAbort},    
       {"AbortSrb", NULL, 0, COPY, 0, (PVOID) &AbortSrb},
       {"MaxQueueDepth", NULL, 0, COPY, 0, (PVOID) &MaxQueueDepth},
       {"TargetDeviceMapKey", NULL, 0, COPY, 0, (PVOID) &TargetDeviceMapKey},
       {"LunDeviceMapKey", NULL, 0, COPY, 0, (PVOID) &LunDeviceMapKey},
       {"ActiveFailedRequest", NULL, 0, COPY, 0, (PVOID) &ActiveFailedRequest},
       {"BlockedFailedRequest", NULL, 0, COPY, 0, (PVOID) &BlockedFailedRequest},
       {"RequestSenseIrp", NULL, 0, COPY, 0, (PVOID) &RequestSenseIrp},
       {"BypassSrbDataList.Next", NULL, 0, COPY, 0, (PVOID) &BypassSrbDataList_Next},
       {"InquiryData", NULL, 0, ADDROF, 0, NULL},
       {"RequestSenseSrb", NULL, 0, ADDROF, 0, NULL},
       {"RequestSenseMdl", NULL, 0, ADDROF, 0, NULL},
       {"BypassSrbDataBlocks", NULL, 0, ADDROF, 0, NULL},
       {"RequestList", NULL, 0, ADDROF, 0, NULL},
    };

    SYM_DUMP_PARAM DevSym = {
       sizeof (SYM_DUMP_PARAM), 
       "scsiport!_LOGICAL_UNIT_EXTENSION", 
       DBG_DUMP_NO_PRINT, 
       LunAddress,
       NULL, NULL, NULL,
       sizeof (deviceFields) / sizeof (FIELD_INFO),
       &deviceFields[0]
    };

    result = Ioctl(IG_DUMP_SYMBOL_INFO, &DevSym, DevSym.size);
    if (result) {
        dprintf("%08p: Could not read _LOGICAL_UNIT_EXTENSION\n", LunAddress);
        return;
    }

    Fields = sizeof (deviceFields) / sizeof (FIELD_INFO);
    AddrOf_RequestList = deviceFields[Fields-1].address;
    AddrOf_BypassSrbDataBlocks = deviceFields[Fields-2].address;
    AddrOf_RequestSenseMdl = deviceFields[Fields-3].address;
    AddrOf_RequestSenseSrb = deviceFields[Fields-4].address;
    AddrOf_InquiryData = deviceFields[Fields-5].address;

    result = GetFieldData(AddrOf_RequestList,
                          "scsiport!LIST_ENTRY",
                          "Flink",
                          sizeof(ULONG64),
                          &RequestList_Flink);
    if (result) {
        dprintf("Error reading request list from adapter extension @%p\n", AdapterExtension);
        return;
    }

    result = GetFieldData(AdapterExtension,
                          "scsiport!_ADAPTER_EXTENSION",
                          "TickCount",
                          sizeof(ULONG),
                          &Adapter_TickCount);
    if (result) {
        dprintf("Error reading TickCount from adapter extension @%p\n", AdapterExtension);
        return;
    }

    InitTypeRead(LunAddress, scsiport!_LOGICAL_UNIT_EXTENSION);
    QueueCount = (ULONG)ReadField(QueueCount);

    xdprintfEx(Depth, ("Address (%d, %d, %d, %d) %s %s %s %s %s\n",
               PortNumber, PathId, TargetId, Lun,
               (IsClaimed ? "Claimed" : ""),
               (IsMissing ? "Missing" : ""),
               (IsEnumerated ? "Enumerated" : ""),
               (IsVisible ? "Visible" : ""),
               (IsMismatched ? "Mismatched" : "")));

    //
    // Print out the various LU flags
    //

    DumpFlags(Depth, "LuFlags", LunLuFlags, LuFlags);

    xdprintfEx(Depth, ("Retry 0x%02x          Key 0x%08lx\n",
               RetryCount, CurrentKey));

    xdprintfEx(Depth, ("Lock 0x%08lx  Pause 0x%08lx   CurrentLock: 0x%p\n",
               QueueLockCount, QueuePauseCount, NULL));

    xdprintfEx(Depth, ("HwLuExt 0x%08p  Adapter 0x%08p  Timeout 0x%08x\n",
               HwLogicalUnitExtension, AdapterExtension,
               RequestTimeoutCounter));

    xdprintfEx(Depth, ("NextLun 0x%p  ReadyLun 0x%p\n",
               NextLogicalUnit, ReadyLogicalUnit));

    xdprintfEx(Depth, ("Pending 0x%p  Busy 0x%p     Untagged 0x%p\n",
               PendingRequest,
               BusyRequest,
               CurrentUntaggedRequest));

    if((CompletedAbort != 0) || (AbortSrb != 0)) {
        xdprintfEx(Depth, ("Abort 0x%p    Completed Abort 0x%p\n",
                   AbortSrb, CompletedAbort));
    }

    xdprintfEx(Depth, ("Q Depth %03d (%03d)   InquiryData 0x%p\n",
               QueueCount, MaxQueueDepth, AddrOf_InquiryData));

    xdprintfEx(Depth, ("DeviceMap Keys: Target %#08lx   Lun %#08lx\n",
               TargetDeviceMapKey, LunDeviceMapKey));

    xdprintfEx(Depth, ("Bypass SRB_DATA blocks %d @ %08p   List %08p\n", 
               NUMBER_BYPASS_SRB_DATA_BLOCKS, 
               AddrOf_BypassSrbDataBlocks,
               BypassSrbDataList_Next));

    if((ActiveFailedRequest != 0) ||
       (BlockedFailedRequest != 0)) {
        xdprintfEx(Depth, ("Failed Requests - "));

        if(ActiveFailedRequest != 0) {
            dprintf("Active %#08I ", ActiveFailedRequest);
        }

        if(BlockedFailedRequest != 0) {
            dprintf("Blocked %#08I ", BlockedFailedRequest);
        }
        dprintf("\n");
    }

    xdprintfEx(Depth, ("RS Irp %p  Srb @ %p   MDL @ %p\n", 
               RequestSenseIrp,
               AddrOf_RequestSenseSrb,
               AddrOf_RequestSenseMdl));

    if((RequestList_Flink) == AddrOf_RequestList) {
        xdprintfEx(Depth, ("Request List @0x%p is empty\n",
                   AddrOf_RequestList));
    } else {
        xdprintfEx(Depth, ("Request list @0x%p:\n", AddrOf_RequestList));
        ScsiDumpActiveRequests(AddrOf_RequestList,
                               Adapter_TickCount,
                               Depth + 2);
    }

    if (Detail != 0) {

        //
        // The caller wants additional detail.  Dump the queued requests.
        // Extract the address of the device object from the common extension
        // and pass it to the routine that dumps queued requests.
        //

        ULONG64 DeviceObject;
        result = GetFieldData(LunAddress,
                              "scsiport!_COMMON_EXTENSION",
                              "DeviceObject",
                              sizeof(ULONG64),
                              &DeviceObject);
        if (result) {
            dprintf("Error reading DeviceObject @%p\n", LunAddress);
            return;
        }
        
        xdprintfEx(Depth, ("Queued requests:\n"));
        ScsiDumpQueuedRequests(
            DeviceObject,       
            Adapter_TickCount,
            Depth + 2
            );
    }
    return;
}

VOID
ScsiDumpActiveRequests(
    IN ULONG64 ListHead,
    IN ULONG TickCount,
    IN ULONG Depth
    )
{
    ULONG result;

    ULONG64 lastEntry = 0;
    ULONG64 entry = 0;
    ULONG64 realEntry = 0;
    ULONG64 CurrentSrb = 0;
    ULONG64 CurrentIrp = 0;
    ULONG64 RequestList = 0;
    ULONG OffsetOfRequestList = 0;
    ULONG SrbTickCount = 0;
    ULONG Key = 0;

    FIELD_INFO deviceFields[] = {
        {"CurrentSrb", NULL, 0, COPY, 0, (PVOID) &CurrentSrb},
        {"CurrentIrp", NULL, 0, COPY, 0, (PVOID) &CurrentIrp},
        {"TickCount", NULL, 0, COPY, 0, (PVOID) &SrbTickCount},
        {"RequestList", NULL, 0, ADDROF, 0, NULL},
    };

    SYM_DUMP_PARAM DevSym = {
       sizeof (SYM_DUMP_PARAM), 
       "scsiport!_SRB_DATA", 
       DBG_DUMP_NO_PRINT, 
       0,
       NULL, NULL, NULL, 
       sizeof (deviceFields) / sizeof (FIELD_INFO), 
       &deviceFields[0]
    };

    result = GetFieldOffset("scsiport!_SRB_DATA", 
                            "RequestList",
                            &OffsetOfRequestList);
    if (result) {
        dprintf("failed to get offset of request list (%08X)\n", result);
        return;
    }
    
    entry = ListHead;
    realEntry = entry;
    
    InitTypeRead(ListHead, nt!_LIST_ENTRY);
    lastEntry = ReadField(Blink);

    xdprintfEx(Depth, ("Tick count is %d\n", TickCount));

    do {

        ULONG64 realSrbData;
        ULONG result;

        GetFieldData(realEntry,
                     "scsiport!_LIST_ENTRY",
                     "Flink",
                     sizeof(ULONG64),
                     &entry);

        //
        // entry points to the list entry element of the srb data.  Calculate
        // the address of the start of the srb data block.
        //

        realSrbData = entry - OffsetOfRequestList;

        xdprintfEx(Depth, ("SrbData %08p   ", realSrbData));

        //
        // Read the SRB_DATA information we need.
        //

        DevSym.addr = realSrbData;
        if ((Ioctl(IG_DUMP_SYMBOL_INFO, &DevSym, DevSym.size))) {
            dprintf("%08p: Could not read device object\n", realSrbData);
            return;
        }
        RequestList = deviceFields[3].address;
        

        InitTypeRead(CurrentSrb, scsiport!_SCSI_REQUEST_BLOCK);
        Key = (ULONG)ReadField(QueueSortKey);

        //
        // Update realEntry.
        //

        realEntry = RequestList;

        dprintf("Srb %08p   Irp %08p   Key %x  %s\n",
                CurrentSrb,
                CurrentIrp,
                Key,
                SecondsToString(TickCount - SrbTickCount));

    } while((entry != lastEntry) && (!CheckControlC()));

    return;
}

VOID
ScsiDumpLocks(
    ULONG64 CommonExtension,
    ULONG Depth
    )

/*++

Routine Description:

    dumps the remove locks for a given device object

Arguments:

    CommonExtension - a pointer to the local copy of the device object
                      common extension

Return Value:

    None

--*/

{
    ULONG result;

    LONG RemoveLock;
    ULONG64 RemoveTrackingSpinlock;
    ULONG64 RemoveTrackingList;

    InitTypeRead(CommonExtension, scsiport!_COMMON_EXTENSION);
    RemoveLock = (ULONG) ReadField(RemoveLock);
    RemoveTrackingSpinlock = ReadField(RemoveTrackingSpinlock);
    RemoveTrackingList = ReadField(RemoveTrackingList);

    xdprintfEx(Depth, ("RemoveLock count is %d", RemoveLock));

    if((PVOID)RemoveTrackingSpinlock != (PVOID)-1) {

        ULONG64 lockEntryAddress = RemoveTrackingList;

        dprintf(":\n");
        Depth++;

        if(RemoveTrackingSpinlock != 0) {
            xdprintfEx(Depth, ("RemoveTrackingList is in intermediate state"
                       "@ %p\n", RemoveTrackingList));
            return;
        }

        while((lockEntryAddress != 0L) && !CheckControlC()) {

            UCHAR buffer[512];
            ULONG64 File;
            ULONG64 Tag;
            ULONG64 NextBlock;
            ULONG Line;
            
            InitTypeRead(lockEntryAddress, scsiport!REMOVE_TRACKING_BLOCK);
            File = ReadField(File);
            Tag = ReadField(Tag);
            Line = (ULONG) ReadField(Line);
            NextBlock = ReadField(NextBlock);

            result = sizeof(buffer);

            if(!GetAnsiString(File,
                              buffer,
                              &result)) {

                xdprintfEx(Depth, ("Tag 0x%p File 0x%p Line %d\n",
                           Tag,
                           File,
                           Line));
            } else {

                PUCHAR name;

                name = &buffer[result];

                while((result > 0) &&
                      (*(name - 1) != '\\') &&
                      (*(name - 1)  != '/') &&
                      (!CheckControlC())) {
                    name--;
                    result--;
                }

                xdprintfEx(Depth, ("Tag 0x%p   File %s   Line %d\n",
                           Tag,
                           name,
                           Line));
            }

            lockEntryAddress = NextBlock;
        }
    } else {
        dprintf(" (not tracked on free build)\n");
    }
    return;
}

VOID
ScsiDumpSrbData(
    ULONG64 SrbData,
    ULONG Depth
    )
{
    ULONG result;

    CSHORT Type;
    ULONG64 LogicalUnit;
    ULONG64 CurrentSrb;
    ULONG64 CurrentIrp;
    ULONG64 RequestSenseSave;
    ULONG QueueTag;
    ULONG64 CompletedRequests;
    ULONG ErrorLogRetryCount;
    ULONG SequenceNumber;
    ULONG Flags;
    ULONG64 RequestListFlink;
    ULONG64 RequestListBlink;
    ULONG64 DataOffset;
    ULONG64 OriginalDataBuffer;
    ULONG64 MapRegisterBase;
    ULONG NumberOfMapRegisters;
    ULONG64 ScatterGatherList;

    FIELD_INFO deviceFields[] = {
       {"Type", NULL, 0, COPY, 0, (PVOID) &Type},
       {"LogicalUnit", NULL, 0, COPY, 0, (PVOID) &LogicalUnit},
       {"CurrentSrb", NULL, 0, COPY, 0, (PVOID) &CurrentSrb},
       {"CurrentIrp", NULL, 0, COPY, 0, (PVOID) &CurrentIrp},
       {"RequestSenseSave", NULL, 0, COPY, 0, (PVOID) &RequestSenseSave},
       {"QueueTag", NULL, 0, COPY, 0, (PVOID) &QueueTag},
       {"CompletedRequests", NULL, 0, COPY, 0, (PVOID) &CompletedRequests},
       {"ErrorLogRetryCount", NULL, 0, COPY, 0, (PVOID) &ErrorLogRetryCount},
       {"SequenceNumber", NULL, 0, COPY, 0, (PVOID) &SequenceNumber},
       {"Flags", NULL, 0, COPY, 0, (PVOID) &Flags},
       {"RequestList.Flink", NULL, 0, COPY, 0, (PVOID) &RequestListFlink},
       {"RequestList.Blink", NULL, 0, COPY, 0, (PVOID) &RequestListBlink},
       {"DataOffset", NULL, 0, COPY, 0, (PVOID) &DataOffset},
       {"OriginalDataBuffer", NULL, 0, COPY, 0, (PVOID) &OriginalDataBuffer},
       {"MapRegisterBase", NULL, 0, COPY, 0, (PVOID) &MapRegisterBase},
       {"NumberOfMapRegisters", NULL, 0, COPY, 0, (PVOID) &NumberOfMapRegisters},
       {"ScatterGatherList", NULL, 0, COPY, 0, (PVOID) &ScatterGatherList},
    };

    SYM_DUMP_PARAM DevSym = {
       sizeof (SYM_DUMP_PARAM), 
       "scsiport!_SRB_DATA", 
       DBG_DUMP_NO_PRINT, 
       SrbData,
       NULL, NULL, NULL,
       sizeof (deviceFields) / sizeof (FIELD_INFO),
       &deviceFields[0]
    };

    result = Ioctl(IG_DUMP_SYMBOL_INFO, &DevSym, DevSym.size);
    if (result) {
        SCSIKD_PRINT_ERROR(result);
        return;
    }

    if(Type != SRB_DATA_TYPE) {
        dprintf("Type (%#x) does not match SRB_DATA_TYPE (%#x)\n",
                Type, SRB_DATA_TYPE);
    }

    xdprintfEx(Depth, ("Lun  0x%p   Srb 0x%p   Irp 0x%p\n",
             LogicalUnit, CurrentSrb, CurrentIrp));

    xdprintfEx(Depth, ("Sense 0x%p  Tag  0x%08lx  Next Completed 0x%p\n",
             RequestSenseSave,
             QueueTag, CompletedRequests));

    xdprintfEx(Depth, ("Retry 0x%02x        Seq 0x%08lx   Flags 0x%08lx\n",
             ErrorLogRetryCount, SequenceNumber,
             Flags));

    xdprintfEx(Depth, ("Request List:     Next 0x%p  Previous 0x%p\n",
             RequestListFlink, RequestListBlink));

    xdprintfEx(Depth, ("Data Offset 0x%p    Original Data Buffer 0x%p\n", DataOffset, OriginalDataBuffer));

    xdprintfEx(Depth, ("Map Registers 0x%p (0x%02x)    SG List 0x%p\n",
             MapRegisterBase,
             NumberOfMapRegisters,
             ScatterGatherList));

    if(ScatterGatherList != 0) {
        
        ScsiDumpScatterGatherList(ScatterGatherList, 
                                  NumberOfMapRegisters, 
                                  Depth + 1);
    }

    return;

}


VOID
ScsiDumpScatterGatherList(
    ULONG64 List,
    ULONG Entries,
    ULONG Depth
    )
{
    ULONG result;
    ULONG i;
    ULONG start = TRUE;
    ULONG64 PhysicalAddress;
    ULONG Length;

    for(i = 0; i < Entries; i++) {

        InitTypeRead(List, nt!_SCATTER_GATHER_ELEMENT);
        PhysicalAddress = ReadField(Address);
        Length = (ULONG) ReadField(Length);

        if(start) {
            xdprintfEx(Depth, ("0x%016I64x (0x%08lx), ",
                     PhysicalAddress,
                     Length));
        } else {
            dprintf("0x%016I64x (0x%08lx),\n",
                    PhysicalAddress,
                    Length);
        }

        start = !start;
        List += (IsPtr64() != 0) ? 0x18 : 0xc;
    }

    if(!start) {
        dprintf("\n");
    }
}

DECLARE_API(srbdata)
{
    ULONG64 address;

    GetAddress(args, &address);

    dprintf("SrbData structure at %#p\n", address);

    ScsiDumpSrbData(address, 1);

    return S_OK;
}

VOID
ScsiDumpAdapterPerfCounters(
    ULONG64 Adapter,
    ULONG Depth
    )
{
#if TEST_LISTS
    ULONG result;

    ULONG SmallAllocationCount;
    ULONG LargeAllocationCount;
    ULONG64 ScatterGatherAllocationCount;
    ULONG64 SmallAllocationSize;
    ULONG64 MediumAllocationSize;
    ULONG64 LargeAllocationSize;
    ULONG64 SrbDataAllocationCount;
    ULONG64 SrbDataResurrectionCount;
    ULONG64 SrbDataEmergencyFreeCount;

    FIELD_INFO deviceFields[] = {
       {"SmallAllocationCount", NULL, 0, COPY, 0, (PVOID) &SmallAllocationCount},
       {"LargeAllocationCount", NULL, 0, COPY, 0, (PVOID) &LargeAllocationCount},
       {"ScatterGatherAllocationCount", NULL, 0, COPY, 0, (PVOID) &ScatterGatherAllocationCount},
       {"SmallAllocationSize", NULL, 0, COPY, 0, (PVOID) &SmallAllocationSize},
       {"MediumAllocationSize", NULL, 0, COPY, 0, (PVOID) &MediumAllocationSize},
       {"LargeAllocationSize", NULL, 0, COPY, 0, (PVOID) &LargeAllocationSize},
       {"SrbDataAllocationCount", NULL, 0, COPY, 0, (PVOID) &SrbDataAllocationCount},
       {"SrbDataResurrectionCount", NULL, 0, COPY, 0, (PVOID) &SrbDataResurrectionCount},
       {"SrbDataEmergencyFreeCount", NULL, 0, COPY, 0, (PVOID) &SrbDataEmergencyFreeCount},
    };

    SYM_DUMP_PARAM DevSym = {
       sizeof (SYM_DUMP_PARAM), 
       "scsiport!_ADAPTER_EXTENSION", 
       DBG_DUMP_NO_PRINT, 
       Adapter,
       NULL, NULL, NULL,
       sizeof (deviceFields) / sizeof (FIELD_INFO),
       &deviceFields[0]
    };

    result = Ioctl(IG_DUMP_SYMBOL_INFO, &DevSym, DevSym.size);
    if (result) {
        SCSIKD_PRINT_ERROR(result);
        return;
    }

    ULONG mediumAllocationCount = (ULONG)
        (ScatterGatherAllocationCount -
         (SmallAllocationCount +
          LargeAllocationCount));

    double average;

    xdprintfEx(Depth, ("Performance Counters:\n"));

    Depth++;

    xdprintfEx(Depth, ("SGList Allocs - "));
    dprintf("Small: %d, ", SmallAllocationCount);
    dprintf("Med: %d, ",
            (ScatterGatherAllocationCount -
             SmallAllocationCount -
             LargeAllocationCount));
    dprintf("Large: %d, ", LargeAllocationCount);
    dprintf("Total: %I64d\n",
            ScatterGatherAllocationCount);

    xdprintfEx(Depth, ("Average SG Entries - "));

    if(SmallAllocationCount != 0) {
        average = ((double) (SmallAllocationSize)) / SmallAllocationCount;
        dprintf("Small: %.2f   ", average);
    }

    if(mediumAllocationCount != 0) {
        average = ((double) (MediumAllocationSize)) / mediumAllocationCount;
        dprintf("Medium: %.2f   ", average);
    }

    if(Adapter->LargeAllocationCount != 0) {
        average = ((double) (Adapter->LargeAllocationSize)) / LargeAllocationCount;
        dprintf("Large: %.2f", average);
    }

    dprintf("\n");

    xdprintfEx(Depth, ("SrbData - Allocs: %I64d, ",
               SrbDataAllocationCount));

    dprintf("Resurrected: %I64d, ",
            SrbDataResurrectionCount);

    dprintf("Timer Serviced: %I64d,\n",
            SrbDataServicedFromTickHandlerCount);

    xdprintfEx(Depth, ("          Queued: %I64d, ",
               SrbDataQueueInsertionCount));

    dprintf("Emergency Freed: %I64d\n",
            SrbDataEmergencyFreeCount);

#endif
    return;
}

PUCHAR
SecondsToString(
    ULONG Count
    )  
{
    static UCHAR string[64] = "";
    UCHAR tmp[16];

    ULONG seconds = 0;
    ULONG minutes = 0;
    ULONG hours = 0;
    ULONG days = 0;

    string[0] = '\0';

    if(Count == 0) {
        sprintf(string, "<1s");
        return string;
    }

    seconds = Count % 60;
    Count /= 60;

    if(Count != 0) {
        minutes = Count % 60;
        Count /= 60;
    }
        
    if(Count != 0) {
        hours = Count % 24;
        Count /= 24;
    }

    if(Count != 0) {
        days = Count;
    }

    if(days != 0) {
        sprintf(tmp, "%dd", days);
        strcat(string, tmp);
    }

    if(hours != 0) {
        sprintf(tmp, "%dh", hours);
        strcat(string, tmp);
    }

    if(minutes != 0) {
        sprintf(tmp, "%dm", minutes);
        strcat(string, tmp);
    }

    if(seconds != 0) {
        sprintf(tmp, "%ds", seconds);
        strcat(string, tmp);
    }

    return string;
}

VOID
ScsiDumpQueuedRequests(
    IN ULONG64 DeviceObject,
    IN ULONG TickCount,
    IN ULONG Depth
    )
{
    ULONG result;
    ULONG64 ListHeadFlink;
    ULONG64 ListHeadBlink;
    ULONG64 DeviceListHead;
    ULONG64 realEntry;

    //
    // Get the address of the head of the device list in the device queue.
    //

    result = GetFieldData(
                 DeviceObject,
                 "scsiport!_DEVICE_OBJECT",
                 "DeviceQueue.DeviceListHead",
                 sizeof(ULONG64),
                 &DeviceListHead);
    if (result) {
        SCSIKD_PRINT_ERROR(result);
        return;
    }

    //
    // Get the forward and backward link fields from the list head.  If
    // the queue is empty, we're done.
    //

    InitTypeRead(DeviceListHead, scsiport!_LIST_ENTRY);
    ListHeadFlink = ReadField(CurrentSrb);
    ListHeadBlink = ReadField(CurrentIrp);
                 
    if (ListHeadFlink == ListHeadBlink) {
        xdprintfEx(Depth, ("Device Queue is empty\n"));
        return;
    }

    //
    // Initialize a pointer the head of the list.
    //

    realEntry = DeviceListHead;

    do {

        ULONG result;
        ULONG64 realIrp;
        ULONG64 realStack;
        ULONG64 realSrb;
        ULONG64 realSrbData;
        ULONG64 CurrentSrb;
        ULONG64 CurrentIrp;
        ULONG OffsetOfDeviceListEntry;
        ULONG SrbDataTickCount;

        //
        // Get the address of the next entry in the queue.
        //

        result = GetFieldData(realEntry,
                              "scsiport!_LIST_ENTRY",
                              "Flink",
                              sizeof(ULONG64),
                              &realEntry);
        if (result) {
            SCSIKD_PRINT_ERROR(result);
            break;
        }
        
        //
        // We to calculate the address of the IRP using the address of the 
        // list entry.  Can't use static CONTAINING_RECORD; we need a runtime 
        // equivalent.  So we use type info to get the offset of the list 
        // entry and calculate the address of the beginning of the IRP.  This
        // makes the extension work for 32b and 64b debuggees.
        //

        result = GetFieldOffset(
                     "scsiport!_IRP",
                     "Tail.Overlay.DeviceQueueEntry.DeviceListEntry",
                     &OffsetOfDeviceListEntry);
        if (result) {
            SCSIKD_PRINT_ERROR(result);
            break;
        }

        realIrp = realEntry - OffsetOfDeviceListEntry;

        //
        // Now we need to read in the address of the current IO stack 
        // location.
        //

        result = GetFieldData(
                     realIrp,
                     "scsiport!_IRP",
                     "Tail.Overlay.CurrentStackLocation",
                     sizeof(ULONG64),
                     &realStack);
        if (result) {
            SCSIKD_PRINT_ERROR(result);
            break;
        }

        //
        // Load the SRB field of the stack location.
        //

        result = GetFieldData(
                     realStack,
                     "scsiport!_IO_STACK_LOCATION",
                     "Parameters.Scsi.Srb",
                     sizeof(ULONG64),
                     &realSrb);
        if (result) {
            SCSIKD_PRINT_ERROR(result);
            break;
        }

        //
        // Pick out the pointer to the srb data and read that in.
        //

        result = GetFieldData(
                     realSrb,
                     "scsiport!_SCSI_REQUEST_BLOCK",
                     "OriginalRequest",
                     sizeof(ULONG64),
                     &realSrbData);
        if (result) {
            SCSIKD_PRINT_ERROR(result);
            break;
        }

        xdprintfEx(Depth, ("SrbData 0x%p   ", realSrbData));

        //
        // Read the SRB_DATA information we need.
        //

        InitTypeRead(realSrb, scsiport!_SRB_DATA);
        CurrentSrb = ReadField(CurrentSrb);
        CurrentIrp = ReadField(CurrentIrp);
        SrbDataTickCount = (ULONG)ReadField(TickCount);

        dprintf("Srb 0x%p   Irp 0x%p   %s\n",
                CurrentSrb,
                CurrentIrp,
                SecondsToString(TickCount - SrbDataTickCount));

    } while((realEntry != ListHeadBlink) && (!CheckControlC()));

    return;
}