1318 lines
46 KiB
C
1318 lines
46 KiB
C
|
||
/*++
|
||
|
||
Copyright (C) Microsoft Corporation, 1992 - 1999
|
||
|
||
Module Name:
|
||
|
||
classkd.c
|
||
|
||
Abstract:
|
||
|
||
Debugger Extension Api for interpretting scsiport structures
|
||
|
||
Author:
|
||
|
||
Peter Wieland (peterwie) 16-Oct-1995
|
||
johnstra
|
||
ervinp
|
||
|
||
Environment:
|
||
|
||
User Mode.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
|
||
|
||
#include "classpnp.h" // #defines ALLOCATE_SRB_FROM_POOL as needed
|
||
|
||
#include "classp.h" // Classpnp's private definitions
|
||
#include "cdrom.h"
|
||
|
||
#include "classkd.h" // routines that are useful for all class drivers
|
||
|
||
typedef struct _REMOVE_TRACKING_BLOCK
|
||
REMOVE_TRACKING_BLOCK,
|
||
*PREMOVE_TRACKING_BLOCK;
|
||
|
||
struct _REMOVE_TRACKING_BLOCK {
|
||
PREMOVE_TRACKING_BLOCK NextBlock;
|
||
PVOID Tag;
|
||
LARGE_INTEGER TimeLocked;
|
||
PCSTR File;
|
||
ULONG Line;
|
||
};
|
||
|
||
FLAG_NAME FdoFlags[] = {
|
||
FLAG_NAME(DEV_WRITE_CACHE), // 0x00000001
|
||
FLAG_NAME(DEV_USE_SCSI1), // 0x00000002
|
||
FLAG_NAME(DEV_SAFE_START_UNIT), // 0x00000004
|
||
FLAG_NAME(DEV_NO_12BYTE_CDB), // 0x00000008
|
||
{0,0}
|
||
};
|
||
|
||
DECLARE_API(classext)
|
||
|
||
/*++
|
||
|
||
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 devObjAddr = 0;
|
||
ULONG detail = 0;
|
||
|
||
|
||
GetAddressAndDetailLevel64(args, &devObjAddr, &detail);
|
||
|
||
/*
|
||
* Read the device object and extension into the debugger's address space.
|
||
*/
|
||
if (devObjAddr == 0){
|
||
xdprintf(0, "\n usage: !classext <class fdo> <level [0-2]>\n\n");
|
||
}
|
||
else {
|
||
CSHORT objType = GetUSHORTField(devObjAddr, "nt!_DEVICE_OBJECT", "Type");
|
||
|
||
if (objType == IO_TYPE_DEVICE){
|
||
ULONG64 devExtAddr;
|
||
|
||
devExtAddr = GetULONGField(devObjAddr, "nt!_DEVICE_OBJECT", "DeviceExtension");
|
||
if (devExtAddr != BAD_VALUE){
|
||
ULONG64 commonExtAddr = devExtAddr;
|
||
ULONG64 tmpDevObjAddr;
|
||
BOOLEAN isFdo;
|
||
|
||
/*
|
||
* To sanity-check our device context, check that the 'DeviceObject' field matches our device object.
|
||
*/
|
||
tmpDevObjAddr = GetULONGField(devExtAddr, "classpnp!_FUNCTIONAL_DEVICE_EXTENSION", "DeviceObject");
|
||
isFdo = GetUCHARField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "IsFdo");
|
||
if ((tmpDevObjAddr == devObjAddr) && isFdo && (isFdo != BAD_VALUE)){
|
||
ULONG64 fdoDataAddr;
|
||
|
||
fdoDataAddr = GetULONGField(devExtAddr, "classpnp!_FUNCTIONAL_DEVICE_EXTENSION", "PrivateFdoData");
|
||
if (fdoDataAddr != BAD_VALUE){
|
||
|
||
ClassDumpFdoExtensionInternal(fdoDataAddr, detail, 0);
|
||
|
||
ClassDumpFdoExtensionExternal(devExtAddr, detail, 0);
|
||
|
||
// this hasn't worked in some time
|
||
// ClassDumpCommonExtension(devObjAddr, detail, 0);
|
||
}
|
||
}
|
||
else {
|
||
dprintf("%08p is not a storage class FDO (for PDO information, use !classext on the parent FDO) \n", devObjAddr);
|
||
dprintf(g_genericErrorHelpStr);
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
dprintf("Error: 0x%08p is not a device object\n", devObjAddr);
|
||
dprintf(g_genericErrorHelpStr);
|
||
}
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
|
||
VOID
|
||
ClassDumpCommonExtension(
|
||
IN ULONG64 Address,
|
||
IN ULONG Detail,
|
||
IN ULONG Depth
|
||
)
|
||
{
|
||
ULONG result;
|
||
ULONG offset;
|
||
ULONG tmp;
|
||
|
||
BOOLEAN IsFdo;
|
||
BOOLEAN IsInitialized;
|
||
ULONG IsRemoved;
|
||
ULONG64 DeviceObject;
|
||
ULONG64 LowerDeviceObject;
|
||
UCHAR CurrentState;
|
||
UCHAR PreviousState;
|
||
ULONG64 DriverData;
|
||
ULONG PagingPathCount;
|
||
ULONG DumpPathCount;
|
||
ULONG HibernationPathCount;
|
||
|
||
FIELD_INFO deviceFields[] = {
|
||
{"IsFdo", NULL, 0, COPY, 0, (PVOID) &IsFdo},
|
||
{"IsInitialized", NULL, 0, COPY, 0, (PVOID) &IsInitialized},
|
||
{"IsRemoved", NULL, 0, COPY, 0, (PVOID) &IsRemoved},
|
||
{"DeviceObject", NULL, 0, COPY, 0, (PVOID) &DeviceObject},
|
||
{"LowerDeviceObject", NULL, 0, COPY, 0, (PVOID) &LowerDeviceObject},
|
||
{"CurrentState", NULL, 0, COPY, 0, (PVOID) &CurrentState},
|
||
{"PreviousState", NULL, 0, COPY, 0, (PVOID) &PreviousState},
|
||
{"DriverData", NULL, 0, COPY, 0, (PVOID) &DriverData},
|
||
{"PagingPathCount", NULL, 0, COPY, 0, (PVOID) &PagingPathCount},
|
||
{"DumpPathCount", NULL, 0, COPY, 0, (PVOID) &DumpPathCount},
|
||
{"HibernationPathCount", NULL, 0, COPY, 0, (PVOID) &HibernationPathCount},
|
||
};
|
||
|
||
SYM_DUMP_PARAM DevSym = {
|
||
sizeof (SYM_DUMP_PARAM),
|
||
"classpnp!_COMMON_DEVICE_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;
|
||
}
|
||
|
||
xdprintfEx(Depth, ("Classpnp %s device extension at address %p\n",
|
||
(!IsFdo ? "physical" : "functional"),
|
||
Address));
|
||
|
||
xdprintfEx(Depth, ("Common Extension:\n"));
|
||
|
||
Depth += 1;
|
||
|
||
tmp = Depth;
|
||
|
||
if(IsInitialized) {
|
||
xdprintfEx(tmp, ("Initialized " ));
|
||
tmp = 0;
|
||
}
|
||
|
||
switch(IsRemoved) {
|
||
case REMOVE_PENDING: {
|
||
xdprintfEx(tmp, ("RemovePending"));
|
||
tmp = 0;
|
||
break;
|
||
}
|
||
|
||
case REMOVE_COMPLETE: {
|
||
xdprintfEx(tmp, ("RemoveComplete"));
|
||
tmp = 0;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if(tmp == 0) {
|
||
dprintf("\n");
|
||
}
|
||
|
||
tmp = 0;
|
||
|
||
//
|
||
// Calculate the runtime address of the first field to follow the common
|
||
// device extension. To do this, we query the type info for the offset
|
||
// of the last field, then increment it by the appropriate amount.
|
||
//
|
||
|
||
result = GetFieldOffset("classpnp!_COMMON_DEVICE_EXTENSION",
|
||
"Reserved4",
|
||
&offset);
|
||
if (result) {
|
||
SCSIKD_PRINT_ERROR(result);
|
||
return;
|
||
}
|
||
offset += IsPtr64() ? sizeof(ULONG64) : sizeof(ULONG32);
|
||
|
||
xdprintfEx(Depth, ("DO 0x%p LowerObject 0x%p Other Extension 0x%p\n",
|
||
DeviceObject,
|
||
LowerDeviceObject,
|
||
Address + offset
|
||
));
|
||
|
||
xdprintfEx(Depth, ("Current PnP state 0x%x Previous state 0x%x\n",
|
||
CurrentState,
|
||
PreviousState));
|
||
|
||
xdprintfEx(Depth, ("DriverData 0x%p UsePathCounts (P%d, C%d, H%d)\n",
|
||
DriverData,
|
||
PagingPathCount,
|
||
DumpPathCount,
|
||
HibernationPathCount
|
||
));
|
||
|
||
if(!IsFdo) {
|
||
xdprintfEx(Depth - 1, ("PhysicalExtension:\n"));
|
||
ClassDumpPdo(Address,
|
||
Detail,
|
||
Depth);
|
||
} else {
|
||
xdprintfEx(Depth - 1, ("FunctionalExtension:\n"));
|
||
ClassDumpFdo(Address,
|
||
Detail,
|
||
Depth);
|
||
}
|
||
|
||
ClassDumpLocks(Address, Depth - 1);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
ClassDumpFdoExtensionExternal(
|
||
IN ULONG64 FdoExtAddr,
|
||
IN ULONG Detail,
|
||
IN ULONG Depth
|
||
)
|
||
{
|
||
ULONG64 commonExtAddr = FdoExtAddr;
|
||
ULONG64 mediaChangeInfoAddr;
|
||
ULONG64 childPdoExtAddr;
|
||
ULONG isRemoved;
|
||
UCHAR isInitialized;
|
||
ULONG removeLock;
|
||
UCHAR currentState, previousState;
|
||
ULONG64 lowerDevObjAddr;
|
||
|
||
xdprintf(Depth, "\n");
|
||
xdprintf(Depth, "Classpnp _EXTERNAL_ data:\n\n");
|
||
|
||
/*
|
||
* Print the media change information (which only exists for removable media like cdrom)
|
||
*/
|
||
mediaChangeInfoAddr = GetULONGField(FdoExtAddr, "classpnp!_FUNCTIONAL_DEVICE_EXTENSION", "MediaChangeDetectionInfo");
|
||
if (mediaChangeInfoAddr != BAD_VALUE){
|
||
|
||
if (mediaChangeInfoAddr){
|
||
ULONG64 mediaChangeIrpAddr = GetULONGField(mediaChangeInfoAddr, "classpnp!_MEDIA_CHANGE_DETECTION_INFO", "MediaChangeIrp");
|
||
UCHAR gesnSupported = GetUCHARField(mediaChangeInfoAddr, "classpnp!_MEDIA_CHANGE_DETECTION_INFO", "Gesn.Supported");
|
||
|
||
xdprintf(Depth+1, ""), dprintf("MEDIA_CHANGE_DETECTION_INFO @ %08p:\n", mediaChangeInfoAddr);
|
||
if (gesnSupported){
|
||
xdprintf(Depth+2, "GESN is supported\n");
|
||
}
|
||
else {
|
||
xdprintf(Depth+2, "GESN is NOT supported\n");
|
||
}
|
||
xdprintf(Depth+2, ""), dprintf("MediaChangeIrp = %08p\n", mediaChangeIrpAddr);
|
||
xdprintf(Depth+2, ""), dprintf("(for more info, use 'dt classpnp!_MEDIA_CHANGE_DETECTION_INFO %08p')\n", mediaChangeInfoAddr);
|
||
dprintf("\n");
|
||
}
|
||
else {
|
||
xdprintf(Depth+1, "MediaChangeDetectionInfo is NULL\n");
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Print the media type and geometry information
|
||
*/
|
||
{
|
||
ULONG64 geometryInfoAddr = GetFieldAddr(FdoExtAddr, "classpnp!_FUNCTIONAL_DEVICE_EXTENSION", "DiskGeometry");
|
||
|
||
if (geometryInfoAddr != BAD_VALUE){
|
||
ULONG64 numCylinders = GetULONGField(geometryInfoAddr, "classpnp!_DISK_GEOMETRY", "Cylinders");
|
||
ULONG mediaType = (ULONG)GetULONGField(geometryInfoAddr, "classpnp!_DISK_GEOMETRY", "MediaType");
|
||
ULONG64 tracksPerCylinder = GetULONGField(geometryInfoAddr, "classpnp!_DISK_GEOMETRY", "TracksPerCylinder");
|
||
ULONG64 sectorsPerTrack = GetULONGField(geometryInfoAddr, "classpnp!_DISK_GEOMETRY", "SectorsPerTrack");
|
||
ULONG64 bytesPerSector = GetULONGField(geometryInfoAddr, "classpnp!_DISK_GEOMETRY", "BytesPerSector");
|
||
|
||
if ((numCylinders != BAD_VALUE) && (mediaType != BAD_VALUE) && (tracksPerCylinder != BAD_VALUE) && (sectorsPerTrack != BAD_VALUE) && (bytesPerSector != BAD_VALUE)){
|
||
ULONG64 totalVolume = numCylinders*tracksPerCylinder*sectorsPerTrack*bytesPerSector;
|
||
xdprintf(Depth+1, ""), dprintf("Media type: %s(%xh)\n", DbgGetMediaTypeStr(mediaType), mediaType);
|
||
xdprintf(Depth+1, ""), dprintf("Geometry: %d(%xh)cyl x %d(%xh)tracks x %d(%xh)sectors x %d(%xh)bytes\n",
|
||
(ULONG)numCylinders, (ULONG)numCylinders,
|
||
(ULONG)tracksPerCylinder, (ULONG)tracksPerCylinder,
|
||
(ULONG)sectorsPerTrack, (ULONG)sectorsPerTrack,
|
||
(ULONG)bytesPerSector, (ULONG)bytesPerSector);
|
||
xdprintf(Depth+1+4, ""), dprintf("= %x'%xh", (ULONG)(totalVolume>>32), (ULONG)totalVolume);
|
||
if (totalVolume > (ULONG64)(1 << 30)){
|
||
dprintf(" = ~%d GB\n", (ULONG)(totalVolume >> 30));
|
||
}
|
||
else {
|
||
dprintf(" = ~%d MB\n", (ULONG)(totalVolume >> 20));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Print 'IsInitialized' state.
|
||
*/
|
||
isInitialized = GetUCHARField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "IsInitialized");
|
||
xdprintf(Depth+1, "IsInitialized = %d\n", isInitialized);
|
||
|
||
/*
|
||
* Print the 'IsRemoved' state.
|
||
*/
|
||
isRemoved = (ULONG)GetULONGField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "IsRemoved");
|
||
removeLock = (ULONG)GetULONGField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "RemoveLock");
|
||
xdprintf(Depth+1, "Remove lock count = %d\n", removeLock);
|
||
switch (isRemoved){
|
||
#undef MAKE_CASE
|
||
#define MAKE_CASE(remCase) case remCase: xdprintf(Depth+1, "IsRemoved = " #remCase "(%d)\n", isRemoved); break;
|
||
MAKE_CASE(NO_REMOVE)
|
||
MAKE_CASE(REMOVE_PENDING)
|
||
MAKE_CASE(REMOVE_COMPLETE)
|
||
}
|
||
|
||
/*
|
||
* Print the PnP state.
|
||
*/
|
||
currentState = GetUCHARField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "CurrentState");
|
||
previousState = GetUCHARField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "PreviousState");
|
||
xdprintf(Depth+1, "PnP state: CurrentState:");
|
||
switch (currentState){
|
||
#undef MAKE_CASE
|
||
#define MAKE_CASE(pnpCase) case pnpCase: xdprintf(0, #pnpCase "(%xh)", pnpCase); break;
|
||
MAKE_CASE(IRP_MN_START_DEVICE)
|
||
MAKE_CASE(IRP_MN_STOP_DEVICE)
|
||
MAKE_CASE(IRP_MN_REMOVE_DEVICE)
|
||
MAKE_CASE(IRP_MN_QUERY_STOP_DEVICE)
|
||
MAKE_CASE(IRP_MN_QUERY_REMOVE_DEVICE)
|
||
MAKE_CASE(IRP_MN_CANCEL_STOP_DEVICE)
|
||
MAKE_CASE(IRP_MN_CANCEL_REMOVE_DEVICE)
|
||
default: xdprintf(0, "???(%xh)", currentState); break;
|
||
}
|
||
xdprintf(0, " PreviousState:");
|
||
switch (previousState){
|
||
#undef MAKE_CASE
|
||
#define MAKE_CASE(pnpCase) case pnpCase: xdprintf(0, #pnpCase "(%xh)", pnpCase); break;
|
||
MAKE_CASE(IRP_MN_START_DEVICE)
|
||
MAKE_CASE(IRP_MN_STOP_DEVICE)
|
||
MAKE_CASE(IRP_MN_REMOVE_DEVICE)
|
||
MAKE_CASE(IRP_MN_QUERY_STOP_DEVICE)
|
||
MAKE_CASE(IRP_MN_QUERY_REMOVE_DEVICE)
|
||
MAKE_CASE(IRP_MN_CANCEL_STOP_DEVICE)
|
||
MAKE_CASE(IRP_MN_CANCEL_REMOVE_DEVICE)
|
||
case 0x0FF: xdprintf(0, "(None)"); break;
|
||
default: xdprintf(0, "???(%xh)", previousState); break;
|
||
}
|
||
xdprintf(0, "\n");
|
||
|
||
/*
|
||
* Print target device
|
||
*/
|
||
lowerDevObjAddr = GetULONGField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "LowerDeviceObject");
|
||
xdprintf(Depth+1, ""), dprintf("Target device=%08p\n", lowerDevObjAddr);
|
||
|
||
/*
|
||
* Dump child PDO list
|
||
*/
|
||
xdprintf(Depth+1, "Child PDOs:\n");
|
||
childPdoExtAddr = GetULONGField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "ChildList");
|
||
while (childPdoExtAddr && (childPdoExtAddr != BAD_VALUE)){
|
||
ULONG64 pdoAddr = GetULONGField(childPdoExtAddr, "classpnp!_PHYSICAL_DEVICE_EXTENSION", "DeviceObject");
|
||
UCHAR isEnumerated = GetUCHARField(childPdoExtAddr, "classpnp!_PHYSICAL_DEVICE_EXTENSION", "IsEnumerated");
|
||
UCHAR isMissing = GetUCHARField(childPdoExtAddr, "classpnp!_PHYSICAL_DEVICE_EXTENSION", "IsMissing");
|
||
|
||
xdprintf(Depth+2, ""), dprintf("PDO=%08p IsEnumerated=%d IsMissing=%d\n", pdoAddr, isEnumerated, isMissing);
|
||
|
||
childPdoExtAddr = GetULONGField(childPdoExtAddr, "classpnp!_PHYSICAL_DEVICE_EXTENSION", "CommonExtension.ChildList");
|
||
}
|
||
dprintf("\n");
|
||
|
||
dprintf("\n");
|
||
xdprintf(Depth+2, ""), dprintf("(for more info use 'dt classpnp!_FUNCTIONAL_DEVICE_EXTENSION %08p')\n", FdoExtAddr);
|
||
xdprintf(0, "\n");
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
ClassDumpFdoExtensionInternal(
|
||
IN ULONG64 FdoDataAddr,
|
||
IN ULONG Detail,
|
||
IN ULONG Depth
|
||
)
|
||
{
|
||
ULONG64 keTickCountAddr;
|
||
ULONG keTickCount;
|
||
ULONG len;
|
||
|
||
dprintf("\n");
|
||
xdprintf(Depth, ""), dprintf("Classpnp _INTERNAL_ data (%08p):\n", FdoDataAddr);
|
||
|
||
/*
|
||
* Dump TRANSFER_PACKET lists
|
||
*/
|
||
ClassDumpTransferPacketLists(FdoDataAddr, Detail, Depth+1);
|
||
|
||
/*
|
||
* Dump private error logs
|
||
*/
|
||
ClassDumpPrivateErrorLogs(FdoDataAddr, Detail, Depth+1);
|
||
|
||
/*
|
||
* Show time at trap (for comparison with error log timestamps)
|
||
*/
|
||
keTickCountAddr = GetExpression("nt!KeTickCount");
|
||
if (ReadMemory(keTickCountAddr, &keTickCount, sizeof(ULONG), &len)){
|
||
dprintf("\n");
|
||
xdprintf(Depth, ""), dprintf("KeTickCount trap time: %08xh = %d.%d\n", keTickCount, (ULONG)(keTickCount/1000), (ULONG)(keTickCount%1000));
|
||
}
|
||
|
||
dprintf("\n");
|
||
xdprintf(Depth+2, ""), dprintf("(for more info use 'dt classpnp!_CLASS_PRIVATE_FDO_DATA %08p')\n", FdoDataAddr);
|
||
|
||
}
|
||
|
||
|
||
|
||
VOID ClassDumpTransferPacketLists(ULONG64 FdoDataAddr, ULONG Detail, ULONG Depth)
|
||
{
|
||
ULONG64 allxferPktsListAddr;
|
||
|
||
/*
|
||
* Print transfer packet lists
|
||
*/
|
||
allxferPktsListAddr = GetFieldAddr(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "AllTransferPacketsList");
|
||
if (allxferPktsListAddr != BAD_VALUE){
|
||
ULONG64 listEntryAddr;
|
||
ULONG numTotalXferPkts = (ULONG)GetULONGField(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "NumTotalTransferPackets");
|
||
ULONG numFreeXferPkts = (ULONG)GetULONGField(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "NumFreeTransferPackets");
|
||
ULONG numPackets;
|
||
char *extraSpaces = IsPtr64() ? " " : "";
|
||
|
||
/*
|
||
* Walk AllTransferPacketsList and print only the outstanding packets with full SRB info.
|
||
*/
|
||
xdprintf(Depth, "\n");
|
||
xdprintf(Depth, "Outstanding transfer packets: (out of %d total)\n", numTotalXferPkts);
|
||
xdprintf(Depth, "\n");
|
||
xdprintf(Depth+1, " packet %s irp %s srb %s sense %s status \n", extraSpaces, extraSpaces, extraSpaces, extraSpaces);
|
||
xdprintf(Depth+1, "--------%s --------%s --------%s --------%s -------- \n", extraSpaces, extraSpaces, extraSpaces, extraSpaces);
|
||
numPackets = 0;
|
||
listEntryAddr = GetULONGField(allxferPktsListAddr, "nt!_LIST_ENTRY", "Flink");
|
||
while ((listEntryAddr != allxferPktsListAddr) && (listEntryAddr != BAD_VALUE)){
|
||
ULONG64 pktAddr;
|
||
|
||
pktAddr = GetContainingRecord(listEntryAddr, "classpnp!_TRANSFER_PACKET", "AllPktsListEntry");
|
||
if (pktAddr == BAD_VALUE){
|
||
break;
|
||
}
|
||
else {
|
||
ClassDumpTransferPacket(pktAddr, TRUE, FALSE, TRUE, Depth+1);
|
||
|
||
numPackets++;
|
||
listEntryAddr = GetULONGField(listEntryAddr, "nt!_LIST_ENTRY", "Flink");
|
||
}
|
||
}
|
||
if (numPackets != numTotalXferPkts){
|
||
xdprintf(Depth, "*** Warning: NumTotalTransferPackets(%d) doesn't match length of queue(%d) ***\n", numTotalXferPkts, numPackets);
|
||
}
|
||
|
||
|
||
if (Detail > 0){
|
||
ULONG64 slistEntryAddr;
|
||
|
||
/*
|
||
* Print all transfer packets
|
||
*/
|
||
xdprintf(Depth, "\n");
|
||
xdprintf(Depth, "All transfer packets: (%d total, %d free)\n", numTotalXferPkts, numFreeXferPkts);
|
||
xdprintf(Depth, "\n");
|
||
xdprintf(Depth+1, " packet %s irp %s srb %s sense %s status \n", extraSpaces, extraSpaces, extraSpaces, extraSpaces);
|
||
xdprintf(Depth+1, "--------%s --------%s --------%s --------%s -------- \n", extraSpaces, extraSpaces, extraSpaces, extraSpaces);
|
||
numPackets = 0;
|
||
listEntryAddr = GetULONGField(allxferPktsListAddr, "nt!_LIST_ENTRY", "Flink");
|
||
while ((listEntryAddr != allxferPktsListAddr) && (listEntryAddr != BAD_VALUE)){
|
||
ULONG64 pktAddr;
|
||
|
||
pktAddr = GetContainingRecord(listEntryAddr, "classpnp!_TRANSFER_PACKET", "AllPktsListEntry");
|
||
if (pktAddr == BAD_VALUE){
|
||
break;
|
||
}
|
||
else {
|
||
ClassDumpTransferPacket(pktAddr, TRUE, TRUE, FALSE, Depth+1);
|
||
|
||
listEntryAddr = GetULONGField(listEntryAddr, "nt!_LIST_ENTRY", "Flink");
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Print free packets sList
|
||
*/
|
||
xdprintf(Depth, "\n");
|
||
xdprintf(Depth, "Free transfer packets in fast SLIST: (%d free)\n", numFreeXferPkts);
|
||
if (IsPtr64()){
|
||
xdprintf(Depth, "(Cannot display fast SLIST on 64-bit system)\n");
|
||
}
|
||
else {
|
||
xdprintf(Depth+1, " packet %s irp %s srb %s sense %s status \n", extraSpaces, extraSpaces, extraSpaces, extraSpaces);
|
||
xdprintf(Depth+1, "--------%s --------%s --------%s --------%s -------- \n", extraSpaces, extraSpaces, extraSpaces, extraSpaces);
|
||
numPackets = 0;
|
||
slistEntryAddr = GetULONGField(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "FreeTransferPacketsList.Next.Next");
|
||
while (slistEntryAddr && (slistEntryAddr != BAD_VALUE)){
|
||
ULONG64 pktAddr;
|
||
|
||
pktAddr = GetContainingRecord(slistEntryAddr, "classpnp!_TRANSFER_PACKET", "SlistEntry");
|
||
if (pktAddr == BAD_VALUE){
|
||
break;
|
||
}
|
||
else {
|
||
ClassDumpTransferPacket(pktAddr, TRUE, TRUE, FALSE, Depth+1);
|
||
|
||
numPackets++;
|
||
slistEntryAddr = GetULONGField(pktAddr, "classpnp!_TRANSFER_PACKET", "SlistEntry.Next");
|
||
}
|
||
}
|
||
if (numPackets != numFreeXferPkts){
|
||
xdprintf(Depth, "*** Warning: NumFreeTransferPackets(%d) doesn't match length of queue(%d) ***\n", numFreeXferPkts, numPackets);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
/*
|
||
* ClassDumpTransferPacket
|
||
*
|
||
* Dump TRANSFER_PACKET contents under the following heading:
|
||
*
|
||
* " packet irp srb sense status "
|
||
* " -------- -------- -------- -------- -------- "
|
||
*
|
||
*/
|
||
VOID ClassDumpTransferPacket(
|
||
ULONG64 PktAddr,
|
||
BOOLEAN DumpPendingPkts,
|
||
BOOLEAN DumpFreePkts,
|
||
BOOLEAN DumpFullInfo,
|
||
ULONG Depth)
|
||
{
|
||
|
||
ULONG64 irpAddr = GetULONGField(PktAddr, "classpnp!_TRANSFER_PACKET", "Irp");
|
||
ULONG64 srbAddr = GetFieldAddr(PktAddr, "classpnp!_TRANSFER_PACKET", "Srb");
|
||
ULONG64 senseAddr = GetFieldAddr(PktAddr, "classpnp!_TRANSFER_PACKET", "SrbErrorSenseData");
|
||
|
||
if ((irpAddr == BAD_VALUE) || (srbAddr == BAD_VALUE) || (senseAddr == BAD_VALUE)){
|
||
dprintf("\n ClassDumpTransferPacket: error retrieving contents of packet %08p.\n", PktAddr);
|
||
}
|
||
else {
|
||
UCHAR currentStackLoc = GetUCHARField(irpAddr, "nt!_IRP", "CurrentLocation");
|
||
UCHAR stackCount = GetUCHARField(irpAddr, "nt!_IRP", "StackCount");
|
||
BOOLEAN isPending;
|
||
|
||
isPending = (currentStackLoc != stackCount+1);
|
||
|
||
if ((isPending && DumpPendingPkts) || (!isPending && DumpFreePkts)){
|
||
|
||
/*
|
||
* Print the transfer packet description line
|
||
*/
|
||
xdprintf(Depth, "");
|
||
dprintf("%08p", PktAddr);
|
||
dprintf(" %08p", irpAddr);
|
||
dprintf(" %08p", srbAddr);
|
||
dprintf(" %08p", senseAddr);
|
||
if (isPending){
|
||
xdprintf(0, " pending*");
|
||
}
|
||
else {
|
||
xdprintf(0, " (free)");
|
||
}
|
||
xdprintf(0, "\n");
|
||
|
||
if (DumpFullInfo){
|
||
ULONG64 bufLen = GetULONGField(srbAddr, "classpnp!_SCSI_REQUEST_BLOCK", "DataTransferLength");
|
||
ULONG64 cdbAddr = GetFieldAddr(srbAddr, "classpnp!_SCSI_REQUEST_BLOCK", "Cdb");
|
||
ULONG64 origIrpAddr = GetULONGField(PktAddr, "classpnp!_TRANSFER_PACKET", "OriginalIrp");
|
||
ULONG64 mdlAddr = GetULONGField(origIrpAddr, "nt!_IRP", "MdlAddress");
|
||
UCHAR scsiOp = GetUCHARField(cdbAddr, "classpnp!_CDB", "CDB6GENERIC.OperationCode");
|
||
UCHAR srbStat = GetUCHARField(srbAddr, "classpnp!_SCSI_REQUEST_BLOCK", "SrbStatus");
|
||
ULONG64 bufAddr;
|
||
|
||
/*
|
||
* The the buffer address from the MDL if possible;
|
||
* else from the SRB (which may not be valid).
|
||
*/
|
||
bufAddr = GetULONGField(srbAddr, "classpnp!_SCSI_REQUEST_BLOCK", "DataBuffer");
|
||
if (mdlAddr && (mdlAddr != BAD_VALUE)){
|
||
ULONG mdlFlags = (ULONG)GetULONGField(mdlAddr, "nt!_MDL", "MdlFlags");
|
||
if ((mdlFlags != BAD_VALUE) && (mdlFlags & MDL_PAGES_LOCKED)){
|
||
bufAddr = GetULONGField(mdlAddr, "nt!_MDL", "MappedSystemVa");
|
||
}
|
||
}
|
||
else {
|
||
/*
|
||
* There's no MDL, so bufAddr should be the actual kernel-space pointer.
|
||
* Sanity-check it.
|
||
*/
|
||
if (!IsPtr64() && !(bufAddr & 0x80000000)){
|
||
bufAddr = BAD_VALUE;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Print the SRB description line
|
||
*/
|
||
xdprintf(Depth+1, "(");
|
||
dprintf("%s ", DbgGetScsiOpStr(scsiOp));
|
||
dprintf("status=%s ", DbgGetSrbStatusStr(srbStat));
|
||
|
||
if (mdlAddr && (mdlAddr != BAD_VALUE)){
|
||
if (bufAddr == BAD_VALUE){
|
||
dprintf("mdl=%08p ", mdlAddr);
|
||
}
|
||
else {
|
||
dprintf("mdl+%08p ", bufAddr);
|
||
}
|
||
}
|
||
else if (bufAddr == BAD_VALUE){
|
||
dprintf("buf=??? ");
|
||
}
|
||
else {
|
||
dprintf("buf=%08p ", bufAddr);
|
||
}
|
||
|
||
dprintf("len=%08lx", bufLen);
|
||
dprintf(")\n");
|
||
|
||
/*
|
||
* Print a line with original irp if appropriate
|
||
*/
|
||
if (cdbAddr != BAD_VALUE){
|
||
UCHAR scsiOp = GetUCHARField(cdbAddr, "classpnp!_CDB", "CDB6GENERIC.OperationCode");
|
||
|
||
if ((scsiOp == SCSIOP_READ) || (scsiOp == SCSIOP_WRITE)){
|
||
xdprintf(Depth+1, ""), dprintf("(OriginalIrp=%08p)\n", origIrpAddr);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
VOID ClassDumpPrivateErrorLogs(ULONG64 FdoDataAddr, ULONG Detail, ULONG Depth)
|
||
{
|
||
ULONG64 errLogsAddr;
|
||
|
||
errLogsAddr = GetFieldAddr(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "ErrorLogs");
|
||
if (errLogsAddr != BAD_VALUE){
|
||
ULONG errLogSize = GetTypeSize("classpnp!_CLASS_ERROR_LOG_DATA");
|
||
if (errLogSize != BAD_VALUE){
|
||
ULONG nextErrLogIndex, firstErrLogIndex, lastErrLogIndex;
|
||
|
||
/*
|
||
* Find what should be the index of the last error log (if there were any error logs)
|
||
* See if it is valid by checking for a non-zero timestamp.
|
||
*/
|
||
nextErrLogIndex = (ULONG)GetULONGField(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "ErrorLogNextIndex");
|
||
if (nextErrLogIndex != BAD_VALUE){
|
||
ULONG64 tickCount;
|
||
|
||
lastErrLogIndex = (nextErrLogIndex+NUM_ERROR_LOG_ENTRIES-1) % NUM_ERROR_LOG_ENTRIES;
|
||
|
||
tickCount = GetULONGField(errLogsAddr+lastErrLogIndex*errLogSize, "classpnp!_CLASS_ERROR_LOG_DATA", "TickCount");
|
||
if (tickCount == BAD_VALUE){
|
||
}
|
||
else if (tickCount == 0){
|
||
/*
|
||
* The "latest" error log is not initialized, so there are no error logs
|
||
*/
|
||
dprintf("\n"), xdprintf(Depth, "No Error Logs:\n");
|
||
}
|
||
else {
|
||
/*
|
||
* Search forward through the circular list for the first valid error log.
|
||
*/
|
||
for (firstErrLogIndex = (lastErrLogIndex+1)%NUM_ERROR_LOG_ENTRIES;
|
||
firstErrLogIndex != lastErrLogIndex;
|
||
firstErrLogIndex = (firstErrLogIndex+1)%NUM_ERROR_LOG_ENTRIES){
|
||
|
||
ULONG64 thisErrLogAddr = errLogsAddr+firstErrLogIndex*errLogSize;
|
||
|
||
tickCount = GetULONGField(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "TickCount");
|
||
if (tickCount == BAD_VALUE){
|
||
/*
|
||
* something's screwed up; abort
|
||
*/
|
||
break;
|
||
}
|
||
else if (tickCount != 0){
|
||
/*
|
||
* found the earliest of the recorded error logs, break
|
||
*/
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (tickCount != BAD_VALUE){
|
||
/*
|
||
* Now that we've found the valid range of error logs, print them out.
|
||
*/
|
||
ULONG numErrLogs = (lastErrLogIndex >= firstErrLogIndex) ?
|
||
lastErrLogIndex-firstErrLogIndex+1 :
|
||
lastErrLogIndex+NUM_ERROR_LOG_ENTRIES-firstErrLogIndex+1;
|
||
|
||
dprintf("\n\n"), xdprintf(Depth, "ERROR LOGS (%d):\n", numErrLogs);
|
||
xdprintf(Depth, "---------------------------------------------------\n");
|
||
|
||
do {
|
||
ULONG64 thisErrLogAddr = errLogsAddr+firstErrLogIndex*errLogSize;
|
||
ULONG64 tickCount = GetFieldAddr(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "TickCount");
|
||
ULONG64 senseDataAddr = GetFieldAddr(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "SenseData");
|
||
ULONG64 srbAddr = GetFieldAddr(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "Srb");
|
||
ULONG64 cdbAddr;
|
||
|
||
// GetFieldOffset of an embedded struct gets the wrong address for some reason,
|
||
// so do this manually.
|
||
#if 0
|
||
cdbAddr = GetFieldAddr(thisErrLogAddr, "classpnp!_SCSI_REQUEST_BLOCK", "Cdb");
|
||
#else
|
||
cdbAddr = (srbAddr == BAD_VALUE) ? BAD_VALUE :
|
||
IsPtr64() ? srbAddr + 0x48 :
|
||
srbAddr + 0x30;
|
||
#endif
|
||
|
||
|
||
if ((thisErrLogAddr != BAD_VALUE) && (srbAddr != BAD_VALUE) && (senseDataAddr != BAD_VALUE) && (cdbAddr != BAD_VALUE)){
|
||
UCHAR scsiOp = GetUCHARField(cdbAddr, "classpnp!_CDB", "CDB6GENERIC.OperationCode");
|
||
UCHAR srbStat = GetUCHARField(srbAddr, "classpnp!_SCSI_REQUEST_BLOCK", "SrbStatus");
|
||
UCHAR scsiStat = GetUCHARField(srbAddr, "classpnp!_SCSI_REQUEST_BLOCK", "ScsiStatus");
|
||
UCHAR isPaging = GetUCHARField(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "ErrorPaging");
|
||
UCHAR isRetried = GetUCHARField(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "ErrorRetried");
|
||
UCHAR isUnhandled = GetUCHARField(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "ErrorUnhandled");
|
||
|
||
tickCount = GetULONGField(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "TickCount");
|
||
|
||
if ((scsiOp != BAD_VALUE) && (tickCount != BAD_VALUE)){
|
||
|
||
xdprintf(Depth+1, "");
|
||
dprintf("<tick %d.%d>: ", (ULONG)(tickCount/1000), (ULONG)(tickCount%1000));
|
||
dprintf("%s(%xh)\n",
|
||
DbgGetScsiOpStr(scsiOp),
|
||
(ULONG)scsiOp);
|
||
|
||
xdprintf(Depth+2, "");
|
||
dprintf("srbStat=%s(%xh) scsiStat=%xh \n",
|
||
DbgGetSrbStatusStr(srbStat),
|
||
(ULONG)srbStat,
|
||
(ULONG)scsiStat
|
||
);
|
||
|
||
xdprintf(Depth+2, "");
|
||
dprintf("SenseData = %s/%s/%s \n",
|
||
DbgGetSenseCodeStr(srbStat, senseDataAddr),
|
||
DbgGetAdditionalSenseCodeStr(srbStat, senseDataAddr),
|
||
DbgGetAdditionalSenseCodeQualifierStr(srbStat, senseDataAddr));
|
||
|
||
xdprintf(Depth+2, "");
|
||
if (isPaging) dprintf("Paging; "); else dprintf("(not paging); ");
|
||
if (isRetried) dprintf("Retried; "); else dprintf("(not retried); ");
|
||
if (isUnhandled) dprintf("Unhandled; ");
|
||
dprintf("\n");
|
||
|
||
xdprintf(Depth+2, "");
|
||
dprintf("(for more info, use 'dt classpnp!_CLASS_ERROR_LOG_DATA %08p'\n\n", thisErrLogAddr);
|
||
|
||
firstErrLogIndex = (firstErrLogIndex+1)%NUM_ERROR_LOG_ENTRIES;
|
||
}
|
||
else {
|
||
break;
|
||
}
|
||
}
|
||
else {
|
||
break;
|
||
}
|
||
} while (firstErrLogIndex != (lastErrLogIndex+1)%NUM_ERROR_LOG_ENTRIES);
|
||
|
||
xdprintf(Depth, "---------------------------------------------------\n");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
ClassDumpMediaChangeInfo(
|
||
ULONG64 Address,
|
||
ULONG Detail,
|
||
ULONG Depth
|
||
)
|
||
{
|
||
PUCHAR states[] = {"Unknown", "Present", "Not Present"};
|
||
ULONG result;
|
||
ULONG64 MediaChangeDetectionInfo;
|
||
ULONG offset;
|
||
LONG MediaChangeDetectionDisableCount;
|
||
ULONG MediaChangeDetectionState;
|
||
BOOLEAN MediaChangeIrpLost;
|
||
LONG MediaChangeIrpTimeInUse;
|
||
ULONG64 MediaChangeIrp;
|
||
ULONG64 SenseBuffer;
|
||
|
||
result = GetFieldData(Address,
|
||
"classpnp!_FUNCTIONAL_DEVICE_EXTENSION",
|
||
"MediaChangeDetectionInfo",
|
||
sizeof(ULONG64),
|
||
&MediaChangeDetectionInfo);
|
||
if (result) {
|
||
SCSIKD_PRINT_ERROR(result);
|
||
return;
|
||
}
|
||
|
||
xdprintfEx(Depth, ("MediaChangeNotification:\n"));
|
||
Depth++;
|
||
|
||
if (MediaChangeDetectionInfo == 0) {
|
||
xdprintfEx(Depth, ("MCN is not enabled for this device\n"));
|
||
return;
|
||
}
|
||
|
||
InitTypeRead(MediaChangeDetectionInfo,
|
||
classpnp!_MEDIA_CHANGE_DETECTION_INFO);
|
||
MediaChangeDetectionDisableCount = (LONG) ReadField(MediaChangeDetectionDisableCount);
|
||
MediaChangeDetectionState = (ULONG) ReadField(MediaChangeDetectionState);
|
||
MediaChangeIrpLost = (BOOLEAN) ReadField(MediaChangeIrpLost);
|
||
MediaChangeIrpTimeInUse = (LONG) ReadField(MediaChangeIrpTimeInUse);
|
||
MediaChangeIrp = ReadField(MediaChangeIrp);
|
||
SenseBuffer = ReadField(SenseBuffer);
|
||
|
||
result = GetFieldOffset("classpnp!_MEDIA_CHANGE_DETECTION_INFO",
|
||
"MediaChangeSrb",
|
||
&offset);
|
||
if (result) {
|
||
SCSIKD_PRINT_ERROR(result);
|
||
return;
|
||
}
|
||
|
||
xdprintfEx(Depth, ("MCN is ")); // indent
|
||
if (MediaChangeDetectionDisableCount == 0) {
|
||
dprintf("Enabled ");
|
||
} else {
|
||
dprintf("Disabled ");
|
||
}
|
||
dprintf("Current State %s", states[MediaChangeDetectionState] );
|
||
if (MediaChangeIrpLost != 0) {
|
||
dprintf(" *** MCN Irp Lost for %x ticks *** ",
|
||
MediaChangeIrpTimeInUse);
|
||
}
|
||
dprintf("\n"); // end indent
|
||
|
||
xdprintfEx(Depth, ("Irp %p Srb %p SenseBuffer %p\n",
|
||
MediaChangeIrp,
|
||
MediaChangeDetectionInfo + offset,
|
||
SenseBuffer
|
||
));
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
ClassDumpFdo(
|
||
ULONG64 Address,
|
||
ULONG Detail,
|
||
ULONG Depth
|
||
)
|
||
|
||
{
|
||
ULONG result;
|
||
ULONG offset;
|
||
ULONG tmp;
|
||
|
||
ULONG64 LowerPdo;
|
||
ULONG64 DeviceDescriptor;
|
||
ULONG64 AdapterDescriptor;
|
||
ULONG DevicePowerState;
|
||
ULONG ErrorCount;
|
||
BOOLEAN DMActive;
|
||
ULONG DMByteSkew;
|
||
ULONG DMSkew;
|
||
ULONG64 SenseData;
|
||
ULONG TimeOutValue;
|
||
ULONG DeviceNumber;
|
||
ULONG FSrbFlags;
|
||
USHORT DeviceFlags;
|
||
ULONG64 DiskGeometryCylinders;
|
||
ULONG DiskGeometryMediaType;
|
||
ULONG DiskGeometryTracksPerCylinder;
|
||
ULONG DiskGeometrySectorsPerTrack;
|
||
ULONG DiskGeometryBytesPerSector;
|
||
LONG LockCount;
|
||
LONG ProtectedLockCount;
|
||
LONG InternalLockCount;
|
||
ULONG MediaChangeCount;
|
||
ULONG64 ChildLockOwner;
|
||
ULONG ChildLockAcquisitionCount;
|
||
|
||
FIELD_INFO deviceFields[] = {
|
||
{"LowerPdo", NULL, 0, COPY, 0, (PVOID) &LowerPdo},
|
||
{"DeviceDescriptor", NULL, 0, COPY, 0, (PVOID) &DeviceDescriptor},
|
||
{"AdapterDescriptor", NULL, 0, COPY, 0, (PVOID) &AdapterDescriptor},
|
||
{"DevicePowerState", NULL, 0, COPY, 0, (PVOID) &DevicePowerState},
|
||
{"ErrorCount", NULL, 0, COPY, 0, (PVOID) &ErrorCount},
|
||
{"DMActive", NULL, 0, COPY, 0, (PVOID) &DMActive},
|
||
{"DMByteSkew", NULL, 0, COPY, 0, (PVOID) &DMByteSkew},
|
||
{"DMSkew", NULL, 0, COPY, 0, (PVOID) &DMSkew},
|
||
{"SenseData", NULL, 0, COPY, 0, (PVOID) &SenseData},
|
||
{"TimeOutValue", NULL, 0, COPY, 0, (PVOID) &TimeOutValue},
|
||
{"DeviceNumber", NULL, 0, COPY, 0, (PVOID) &DeviceNumber},
|
||
{"SrbFlags", NULL, 0, COPY, 0, (PVOID) &FSrbFlags},
|
||
{"DeviceFlags", NULL, 0, COPY, 0, (PVOID) &DeviceFlags},
|
||
{"DiskGeometry.Cylinders", NULL, 0, COPY, 0, (PVOID) &DiskGeometryCylinders},
|
||
{"DiskGeometry.MediaType", NULL, 0, COPY, 0, (PVOID) &DiskGeometryMediaType},
|
||
{"DiskGeometry.TracksPerCylinder", NULL, 0, COPY, 0, (PVOID) &DiskGeometryTracksPerCylinder},
|
||
{"DiskGeometry.SectorsPerTrack", NULL, 0, COPY, 0, (PVOID) &DiskGeometrySectorsPerTrack},
|
||
{"DiskGeometry.BytesPerSector", NULL, 0, COPY, 0, (PVOID) &DiskGeometryBytesPerSector},
|
||
{"LockCount", NULL, 0, COPY, 0, (PVOID) &LockCount},
|
||
{"ProtectedLockCount", NULL, 0, COPY, 0, (PVOID) &ProtectedLockCount},
|
||
{"InternalLockCount", NULL, 0, COPY, 0, (PVOID) &InternalLockCount},
|
||
{"MediaChangeCount", NULL, 0, COPY, 0, (PVOID) &MediaChangeCount},
|
||
{"ChildLockOwner", NULL, 0, COPY, 0, (PVOID) &ChildLockOwner},
|
||
{"ChildLockAcquisitionCount", NULL, 0, COPY, 0, (PVOID) &ChildLockAcquisitionCount},
|
||
};
|
||
|
||
SYM_DUMP_PARAM DevSym = {
|
||
sizeof (SYM_DUMP_PARAM),
|
||
"classpnp!_FUNCTIONAL_DEVICE_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;
|
||
}
|
||
|
||
tmp = Depth;
|
||
|
||
xdprintfEx(Depth, ("LowerPdo 0x%p DeviceDesc 0x%p AdapterDesc 0x%p\n",
|
||
LowerPdo,
|
||
DeviceDescriptor,
|
||
AdapterDescriptor));
|
||
|
||
xdprintfEx(Depth, ("DevicePowerState %d ErrorCount %#x\n",
|
||
DevicePowerState,
|
||
ErrorCount
|
||
));
|
||
|
||
if(DMActive) {
|
||
xdprintfEx(Depth, ("DMByteSkew 0x%08lx DmSkew 0x%08lx\n",
|
||
DMByteSkew,
|
||
DMSkew));
|
||
} else {
|
||
xdprintfEx(Depth, ("DM Not Found\n"));
|
||
}
|
||
|
||
xdprintfEx(Depth, ("Sense Data 0x%p Timeout %d DeviceNumber %d\n",
|
||
SenseData,
|
||
TimeOutValue,
|
||
DeviceNumber));
|
||
|
||
DumpFlags(Depth, "Srb Flags", FSrbFlags, SrbFlags);
|
||
DumpFlags(Depth, "Device Flags", DeviceFlags, FdoFlags);
|
||
|
||
xdprintfEx(Depth, ("DiskGeometry:\n"));
|
||
{
|
||
Depth++;
|
||
|
||
xdprintfEx(Depth, ("Cylinders %#I64x MediaType %#x\n",
|
||
DiskGeometryCylinders,
|
||
DiskGeometryMediaType
|
||
));
|
||
|
||
xdprintfEx(Depth, ("Tracks %#x Sectors %#x Bytes %#x\n",
|
||
DiskGeometryTracksPerCylinder,
|
||
DiskGeometrySectorsPerTrack,
|
||
DiskGeometryBytesPerSector));
|
||
Depth--;
|
||
}
|
||
|
||
xdprintfEx(Depth, ("Lock Counts: Normal %#x Protected %#x Internal %#x\n",
|
||
LockCount,
|
||
ProtectedLockCount,
|
||
InternalLockCount));
|
||
|
||
ClassDumpMediaChangeInfo(Address, Detail, Depth);
|
||
|
||
xdprintfEx(Depth, ("Media Change Count %#x\n", MediaChangeCount));
|
||
|
||
result = GetFieldOffset("classpnp!_FUNCTIONAL_DEVICE_EXTENSION",
|
||
"ChildLock",
|
||
&offset);
|
||
if (result) {
|
||
SCSIKD_PRINT_ERROR(result);
|
||
return;
|
||
}
|
||
|
||
xdprintfEx(Depth, ("ChildLock: Event %08p, Owner %08p, Count %#x\n",
|
||
Address + offset,
|
||
ChildLockOwner,
|
||
ChildLockAcquisitionCount
|
||
));
|
||
|
||
ClassDumpChildren(Address, Detail, Depth);
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
ClassDumpChildren(
|
||
IN ULONG64 Fdo,
|
||
IN ULONG Detail,
|
||
IN ULONG Depth
|
||
)
|
||
|
||
{
|
||
ULONG i;
|
||
ULONG64 ChildList;
|
||
ULONG result;
|
||
|
||
xdprintfEx(Depth, ("Children: \n"));
|
||
|
||
Depth++;
|
||
|
||
result = GetFieldData(Fdo,
|
||
"classpnp!_COMMON_DEVICE_EXTENSION",
|
||
"ChildList",
|
||
sizeof(ULONG64),
|
||
&ChildList);
|
||
if (result) {
|
||
SCSIKD_PRINT_ERROR(result);
|
||
return;
|
||
}
|
||
|
||
if (ChildList == 0) {
|
||
xdprintfEx(Depth, ("No Children\n"));
|
||
}
|
||
|
||
while((ChildList != 0) && (!CheckControlC())) {
|
||
|
||
ULONG64 DeviceObject;
|
||
|
||
xdprintfEx(Depth, ("Child 0x%p ", ChildList));
|
||
/*
|
||
result = GetFieldData(ChildList,
|
||
"classpnp!_PHYSICAL_DEVICE_EXTENSION",
|
||
"DeviceObject",
|
||
sizeof(ULONG64),
|
||
&DeviceObject);
|
||
if (result) {
|
||
SCSIKD_PRINT_ERROR(result);
|
||
break;
|
||
}
|
||
*/
|
||
if(Detail > 1) {
|
||
|
||
dprintf("\n");
|
||
ClassDumpCommonExtension(ChildList,
|
||
Detail,
|
||
Depth + 1);
|
||
|
||
} else {
|
||
|
||
dprintf("DevObj 0x%p\n", ChildList);
|
||
}
|
||
|
||
//
|
||
// Get the next child.
|
||
//
|
||
|
||
result = GetFieldData(ChildList,
|
||
"classpnp!_COMMON_DEVICE_EXTENSION",
|
||
"ChildList",
|
||
sizeof(ULONG64),
|
||
&ChildList);
|
||
if (result) {
|
||
SCSIKD_PRINT_ERROR(result);
|
||
break;
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
ClassDumpPdo(
|
||
ULONG64 Address,
|
||
ULONG Detail,
|
||
ULONG Depth
|
||
)
|
||
|
||
{
|
||
ULONG tmp;
|
||
BOOLEAN IsMissing;
|
||
BOOLEAN IsEnumerated;
|
||
|
||
tmp = Depth;
|
||
|
||
InitTypeRead(Address, classpnp!_PHYSICAL_DEVICE_EXTENSION);
|
||
IsMissing = (BOOLEAN)ReadField(IsMissing);
|
||
IsEnumerated = (BOOLEAN)ReadField(IsEnumerated);
|
||
|
||
if(IsMissing) {
|
||
xdprintfEx(tmp, ("Missing " ));
|
||
tmp = 0;
|
||
}
|
||
|
||
if(IsEnumerated) {
|
||
xdprintfEx(tmp, ("Enumerated"));
|
||
tmp = 0;
|
||
}
|
||
|
||
if(tmp == 0) {
|
||
dprintf("\n");
|
||
}
|
||
|
||
tmp = 0;
|
||
|
||
return;
|
||
}
|
||
|
||
BOOLEAN
|
||
ClassIsCheckedVersion(
|
||
ULONG64 RemoveTrackingSpinlock
|
||
)
|
||
{
|
||
if ((PVOID)RemoveTrackingSpinlock == (PVOID)-1) {
|
||
//
|
||
// negative one is an invalid value for a spinlock,
|
||
// therefore this is a FRE build
|
||
//
|
||
return FALSE;
|
||
} else {
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
VOID
|
||
ClassDumpLocks(
|
||
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;
|
||
ULONG64 lockEntryAddress;
|
||
ULONG64 RemoveLock;
|
||
ULONG64 RemoveTrackingSpinlock;
|
||
ULONG64 RemoveTrackingList;
|
||
|
||
InitTypeRead(CommonExtension, classpnp!_COMMON_DEVICE_EXTENSION);
|
||
RemoveLock = ReadField(RemoveLock);
|
||
RemoveTrackingSpinlock = ReadField(RemoveTrackingSpinlock);
|
||
|
||
xdprintfEx(Depth, ("RemoveLock count is %d", RemoveLock));
|
||
|
||
//
|
||
// seeing if RemoveTrackingSpinLock is -1 is our check for the
|
||
// FRE version, which does not contain useful data.
|
||
//
|
||
|
||
if(!ClassIsCheckedVersion(RemoveTrackingSpinlock)) {
|
||
dprintf(" (not tracked on free build)\n");
|
||
return;
|
||
}
|
||
|
||
RemoveTrackingList = ReadField(RemoveTrackingList);
|
||
lockEntryAddress = RemoveTrackingList;
|
||
dprintf(":\n");
|
||
Depth++;
|
||
|
||
if(RemoveTrackingSpinlock != 0) {
|
||
xdprintfEx(Depth, ("RemoveTrackingList at %p is in intermediate state\n",
|
||
RemoveTrackingList));
|
||
return;
|
||
}
|
||
|
||
while((lockEntryAddress != 0L) && !CheckControlC()) {
|
||
|
||
UCHAR buffer[512];
|
||
ULONG64 Tag;
|
||
ULONG64 File;
|
||
ULONG64 Line;
|
||
ULONG64 NextBlock;
|
||
|
||
InitTypeRead(lockEntryAddress, classpnp!_REMOVE_TRACKING_BLOCK);
|
||
Tag = ReadField(Tag);
|
||
File = ReadField(File);
|
||
Line = ReadField(Line);
|
||
NextBlock = ReadField(NextBlock);
|
||
|
||
result = sizeof(buffer)-sizeof(UCHAR);
|
||
|
||
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 %8s Line %d\n",
|
||
Tag,
|
||
name,
|
||
Line));
|
||
}
|
||
|
||
lockEntryAddress = NextBlock;
|
||
}
|
||
return;
|
||
}
|