Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1227 lines
31 KiB

#include "precomp.h" // Precompiled header
/****************************************************************************************
* *
* Module: SPX_UTILS.C *
* *
* Creation: 15th October 1998 *
* *
* Author: Paul Smith *
* *
* Version: 1.0.0 *
* *
* Description: Utility functions. *
* *
****************************************************************************************/
#define FILE_ID SPX_UTILS_C // File ID for Event Logging see SPX_DEFS.H for values.
// Paging...
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, Spx_InitMultiString)
#pragma alloc_text (PAGE, Spx_GetRegistryKeyValue)
#pragma alloc_text (PAGE, Spx_PutRegistryKeyValue)
#pragma alloc_text (PAGE, Spx_LogMessage)
#pragma alloc_text (PAGE, Spx_LogError)
#pragma alloc_text (PAGE, Spx_MemCompare)
#endif
/////////////////////////////////////////////////////////////////////////////////////////
//
// Description:
//
// This routine will take a null terminated list of ascii strings and combine
// them together to generate a unicode multi-string block
//
// Arguments:
//
// Multi - TRUE if a MULTI_SZ list is required, FALSE for a simple UNICODE
//
// MultiString - a unicode structure in which a multi-string will be built
// ... - a null terminated list of narrow strings which will be
// combined together. This list must contain at least a trailing NULL
//
// Return Value:
//
// NTSTATUS
//
/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS
Spx_InitMultiString(BOOLEAN multi, PUNICODE_STRING MultiString, ...)
{
ANSI_STRING ansiString;
NTSTATUS status;
PCSTR rawString;
PWSTR unicodeLocation;
ULONG multiLength = 0;
UNICODE_STRING unicodeString;
va_list ap;
ULONG i;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
va_start(ap,MultiString);
// Make sure that we won't leak memory
ASSERT(MultiString->Buffer == NULL);
rawString = va_arg(ap, PCSTR);
while (rawString != NULL)
{
RtlInitAnsiString(&ansiString, rawString);
multiLength += RtlAnsiStringToUnicodeSize(&(ansiString));
rawString = va_arg(ap, PCSTR);
}
va_end( ap );
if (multiLength == 0)
{
// Done
RtlInitUnicodeString(MultiString, NULL);
SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Leaving Spx_InitMultiString (1)\n", PRODUCT_NAME));
return STATUS_SUCCESS;
}
if(multi)
multiLength += sizeof(WCHAR); // We need an extra null if we want a MULTI_SZ list
MultiString->MaximumLength = (USHORT)multiLength;
MultiString->Buffer = SpxAllocateMem(PagedPool, multiLength);
MultiString->Length = 0;
if (MultiString->Buffer == NULL)
{
SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Leaving Spx_InitMultiString (2) - FAILURE\n", PRODUCT_NAME));
return STATUS_INSUFFICIENT_RESOURCES;
}
SpxDbgMsg(SPX_MISC_DBG, ("%s: Allocated %lu bytes for buffer\n", PRODUCT_NAME, multiLength));
#if DBG
RtlFillMemory(MultiString->Buffer, multiLength, 0xff);
#endif
unicodeString.Buffer = MultiString->Buffer;
unicodeString.MaximumLength = (USHORT) multiLength;
va_start(ap, MultiString);
rawString = va_arg(ap, PCSTR);
while (rawString != NULL)
{
RtlInitAnsiString(&ansiString,rawString);
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE);
// We don't allocate memory, so if something goes wrong here,
// its the function that's at fault
ASSERT(SPX_SUCCESS(status));
// Check for any commas and replace them with NULLs
ASSERT(unicodeString.Length % sizeof(WCHAR) == 0);
for (i = 0; i < (unicodeString.Length / sizeof(WCHAR)); i++)
{
if (unicodeString.Buffer[i] == L'\x2C' || unicodeString.Buffer[i] == L'\x0C' )
{
unicodeString.Buffer[i] = L'\0';
}
}
SpxDbgMsg(SPX_MISC_DBG, ("%s: unicode buffer: %ws\n", PRODUCT_NAME, unicodeString.Buffer));
// Move the buffers along
unicodeString.Buffer += ((unicodeString.Length / sizeof(WCHAR)) + 1);
unicodeString.MaximumLength -= (unicodeString.Length + sizeof(WCHAR));
unicodeString.Length = 0;
// Next
rawString = va_arg(ap, PCSTR);
} // while
va_end(ap);
if(multi)
{
ASSERT(unicodeString.MaximumLength == sizeof(WCHAR));
}
else
{
ASSERT(unicodeString.MaximumLength == 0);
}
// Stick the final null there
SpxDbgMsg(SPX_MISC_DBG, ("%s: unicode buffer last addr: 0x%X\n", PRODUCT_NAME, unicodeString.Buffer));
if(multi)
unicodeString.Buffer[0] = L'\0'; // We need an extra null if we want a MULTI_SZ list
MultiString->Length = (USHORT)multiLength - sizeof(WCHAR);
MultiString->MaximumLength = (USHORT)multiLength;
SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Leaving Spx_InitMultiString (3) - SUCCESS\n", PRODUCT_NAME));
return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// Routine Description:
// Reads a registry key value from an already opened registry key.
//
// Arguments:
//
// Handle Handle to the opened registry key
//
// KeyNameString ANSI string to the desired key
//
// KeyNameStringLength Length of the KeyNameString
//
// Data Buffer to place the key value in
//
// DataLength Length of the data buffer
//
// Return Value:
//
// STATUS_SUCCESS if all works, otherwise status of system call that
// went wrong.
//
/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS
Spx_GetRegistryKeyValue(
IN HANDLE Handle,
IN PWCHAR KeyNameString,
IN ULONG KeyNameStringLength,
IN PVOID Data,
IN ULONG DataLength
)
{
UNICODE_STRING keyName;
ULONG length;
PKEY_VALUE_FULL_INFORMATION fullInfo;
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Enter Spx_GetRegistryKeyValue\n", PRODUCT_NAME));
RtlInitUnicodeString (&keyName, KeyNameString);
length = sizeof(KEY_VALUE_FULL_INFORMATION) + KeyNameStringLength + DataLength;
fullInfo = SpxAllocateMem(PagedPool, length);
if(fullInfo)
{
status = ZwQueryValueKey( Handle,
&keyName,
KeyValueFullInformation,
fullInfo,
length,
&length);
if(SPX_SUCCESS(status))
{
// If there is enough room in the data buffer, copy the output
if(DataLength >= fullInfo->DataLength)
RtlCopyMemory (Data, ((PUCHAR) fullInfo) + fullInfo->DataOffset, fullInfo->DataLength);
}
SpxFreeMem(fullInfo);
}
return status;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// Routine Description:
//
// Writes a registry key value to an already opened registry key.
//
// Arguments:
//
// Handle Handle to the opened registry key
//
// PKeyNameString ANSI string to the desired key
//
// KeyNameStringLength Length of the KeyNameString
//
// Dtype REG_XYZ value type
//
// PData Buffer to place the key value in
//
// DataLength Length of the data buffer
//
// Return Value:
//
// STATUS_SUCCESS if all works, otherwise status of system call that
// went wrong.
//
/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS
Spx_PutRegistryKeyValue(
IN HANDLE Handle,
IN PWCHAR PKeyNameString,
IN ULONG KeyNameStringLength,
IN ULONG Dtype,
IN PVOID PData,
IN ULONG DataLength
)
{
NTSTATUS status;
UNICODE_STRING keyname;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
SpxDbgMsg(SPX_TRACE_CALLS,("%s: Enter Spx_PutRegistryKeyValue\n", PRODUCT_NAME));
RtlInitUnicodeString(&keyname, NULL);
keyname.MaximumLength = (USHORT)(KeyNameStringLength + sizeof(WCHAR));
keyname.Buffer = SpxAllocateMem(PagedPool, keyname.MaximumLength);
if(keyname.Buffer == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
RtlAppendUnicodeToString(&keyname, PKeyNameString);
status = ZwSetValueKey(Handle, &keyname, 0, Dtype, PData, DataLength);
SpxFreeMem(keyname.Buffer);
return status;
}
VOID
Spx_LogMessage(
IN ULONG MessageSeverity,
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
IN PHYSICAL_ADDRESS P1,
IN PHYSICAL_ADDRESS P2,
IN ULONG SequenceNumber,
IN UCHAR MajorFunctionCode,
IN UCHAR RetryCount,
IN ULONG UniqueErrorValue,
IN NTSTATUS FinalStatus,
IN PCHAR szTemp) // Limited to 51 characters + 1 null
{
UNICODE_STRING ErrorMsg;
ErrorMsg.Length = 0;
ErrorMsg.Buffer = 0;
Spx_InitMultiString(FALSE, &ErrorMsg, szTemp, NULL);
switch(MessageSeverity)
{
case STATUS_SEVERITY_SUCCESS:
Spx_LogError( DriverObject, // Driver Object
DeviceObject, // Device Object (Optional)
P1, // Physical Address 1
P2, // Physical Address 2
SequenceNumber, // SequenceNumber
MajorFunctionCode, // Major Function Code
RetryCount, // RetryCount
UniqueErrorValue, // UniqueErrorValue
FinalStatus, // FinalStatus
SPX_SEVERITY_SUCCESS, // SpecificIOStatus
ErrorMsg.Length + sizeof(WCHAR), // LengthOfInsert1
ErrorMsg.Buffer, // Insert1
0, // LengthOfInsert2
NULL); // Insert2
break;
case STATUS_SEVERITY_INFORMATIONAL:
Spx_LogError( DriverObject, // Driver Object
DeviceObject, // Device Object (Optional)
P1, // Physical Address 1
P2, // Physical Address 2
SequenceNumber, // SequenceNumber
MajorFunctionCode, // Major Function Code
RetryCount, // RetryCount
UniqueErrorValue, // UniqueErrorValue
FinalStatus, // FinalStatus
SPX_SEVERITY_INFORMATIONAL, // SpecificIOStatus
ErrorMsg.Length + sizeof(WCHAR), // LengthOfInsert1
ErrorMsg.Buffer, // Insert1
0, // LengthOfInsert2
NULL); // Insert2
break;
case STATUS_SEVERITY_WARNING:
Spx_LogError( DriverObject, // Driver Object
DeviceObject, // Device Object (Optional)
P1, // Physical Address 1
P2, // Physical Address 2
SequenceNumber, // SequenceNumber
MajorFunctionCode, // Major Function Code
RetryCount, // RetryCount
UniqueErrorValue, // UniqueErrorValue
FinalStatus, // FinalStatus
SPX_SEVERITY_WARNING, // SpecificIOStatus
ErrorMsg.Length + sizeof(WCHAR), // LengthOfInsert1
ErrorMsg.Buffer, // Insert1
0, // LengthOfInsert2
NULL); // Insert2
break;
case STATUS_SEVERITY_ERROR:
default:
Spx_LogError( DriverObject, // Driver Object
DeviceObject, // Device Object (Optional)
P1, // Physical Address 1
P2, // Physical Address 2
SequenceNumber, // SequenceNumber
MajorFunctionCode, // Major Function Code
RetryCount, // RetryCount
UniqueErrorValue, // UniqueErrorValue
FinalStatus, // FinalStatus
SPX_SEVERITY_ERROR, // SpecificIOStatus
ErrorMsg.Length + sizeof(WCHAR), // LengthOfInsert1
ErrorMsg.Buffer, // Insert1
0, // LengthOfInsert2
NULL); // Insert2
break;
}
if(ErrorMsg.Buffer != NULL)
SpxFreeMem(ErrorMsg.Buffer);
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// Spx_LogError
//
/////////////////////////////////////////////////////////////////////////////////////////
/*
Routine Description:
This routine allocates an error log entry, copies the supplied data
to it, and requests that it be written to the error log file.
Arguments:
DriverObject - A pointer to the driver object for the device.
DeviceObject - A pointer to the device object associated with the
device that had the error, early in initialization, one may not
yet exist.
P1,P2 - If phyical addresses for the controller ports involved
with the error are available, put them through as dump data.
SequenceNumber - A ulong value that is unique to an IRP over the
life of the irp in this driver - 0 generally means an error not
associated with an irp.
MajorFunctionCode - If there is an error associated with the irp,
this is the major function code of that irp.
RetryCount - The number of times a particular operation has been retried.
UniqueErrorValue - A unique long word that identifies the particular
call to this function.
FinalStatus - The final status given to the irp that was associated
with this error. If this log entry is being made during one of
the retries this value will be STATUS_SUCCESS.
SpecificIOStatus - The IO status for a particular error.
LengthOfInsert1 - The length in bytes (including the terminating NULL)
of the first insertion string.
Insert1 - The first insertion string.
LengthOfInsert2 - The length in bytes (including the terminating NULL)
of the second insertion string. NOTE, there must
be a first insertion string for their to be
a second insertion string.
Insert2 - The second insertion string.
Return Value: None.
*/
VOID
Spx_LogError(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
IN PHYSICAL_ADDRESS P1,
IN PHYSICAL_ADDRESS P2,
IN ULONG SequenceNumber,
IN UCHAR MajorFunctionCode,
IN UCHAR RetryCount,
IN ULONG UniqueErrorValue,
IN NTSTATUS FinalStatus,
IN NTSTATUS SpecificIOStatus,
IN ULONG LengthOfInsert1,
IN PWCHAR Insert1,
IN ULONG LengthOfInsert2,
IN PWCHAR Insert2
)
{
PIO_ERROR_LOG_PACKET ErrorLogEntry;
PVOID objectToUse;
SHORT dumpToAllocate = 0;
PUCHAR ptrToFirstInsert;
PUCHAR ptrToSecondInsert;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
if(Insert1 == NULL)
LengthOfInsert1 = 0;
if(Insert2 == NULL)
LengthOfInsert2 = 0;
if(ARGUMENT_PRESENT(DeviceObject))
objectToUse = DeviceObject;
else
objectToUse = DriverObject;
if(Spx_MemCompare(P1, (ULONG)1, PhysicalZero, (ULONG)1 ) != AddressesAreEqual)
{
dumpToAllocate = (SHORT)sizeof(PHYSICAL_ADDRESS);
}
if(Spx_MemCompare(P2, (ULONG)1, PhysicalZero, (ULONG)1 ) != AddressesAreEqual)
{
dumpToAllocate += (SHORT)sizeof(PHYSICAL_ADDRESS);
}
ErrorLogEntry = IoAllocateErrorLogEntry(objectToUse,
(UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + dumpToAllocate
+ LengthOfInsert1 + LengthOfInsert2)
);
if(ErrorLogEntry != NULL)
{
ErrorLogEntry->ErrorCode = SpecificIOStatus;
ErrorLogEntry->SequenceNumber = SequenceNumber;
ErrorLogEntry->MajorFunctionCode = MajorFunctionCode;
ErrorLogEntry->RetryCount = RetryCount;
ErrorLogEntry->UniqueErrorValue = UniqueErrorValue;
ErrorLogEntry->FinalStatus = FinalStatus;
ErrorLogEntry->DumpDataSize = dumpToAllocate;
if(dumpToAllocate)
{
RtlCopyMemory(&ErrorLogEntry->DumpData[0], &P1, sizeof(PHYSICAL_ADDRESS));
if(dumpToAllocate > sizeof(PHYSICAL_ADDRESS))
{
RtlCopyMemory( ((PUCHAR)&ErrorLogEntry->DumpData[0]) + sizeof(PHYSICAL_ADDRESS),
&P2,
sizeof(PHYSICAL_ADDRESS)
);
ptrToFirstInsert = ((PUCHAR)&ErrorLogEntry->DumpData[0]) + (2*sizeof(PHYSICAL_ADDRESS));
}
else
{
ptrToFirstInsert = ((PUCHAR)&ErrorLogEntry->DumpData[0]) + sizeof(PHYSICAL_ADDRESS);
}
}
else
{
ptrToFirstInsert = (PUCHAR)&ErrorLogEntry->DumpData[0];
}
ptrToSecondInsert = ptrToFirstInsert + LengthOfInsert1;
if(LengthOfInsert1)
{
ErrorLogEntry->NumberOfStrings = 1;
ErrorLogEntry->StringOffset = (USHORT)(ptrToFirstInsert - (PUCHAR)ErrorLogEntry);
RtlCopyMemory(ptrToFirstInsert, Insert1, LengthOfInsert1);
if(LengthOfInsert2)
{
ErrorLogEntry->NumberOfStrings = 2;
RtlCopyMemory(ptrToSecondInsert, Insert2, LengthOfInsert2);
}
}
IoWriteErrorLogEntry(ErrorLogEntry);
}
}
SPX_MEM_COMPARES
Spx_MemCompare(IN PHYSICAL_ADDRESS A, IN ULONG SpanOfA, IN PHYSICAL_ADDRESS B, IN ULONG SpanOfB)
/*++
Routine Description:
Compare two phsical address.
Arguments:
A - One half of the comparison.
SpanOfA - In units of bytes, the span of A.
B - One half of the comparison.
SpanOfB - In units of bytes, the span of B.
Return Value:
The result of the comparison.
--*/
{
LARGE_INTEGER a;
LARGE_INTEGER b;
LARGE_INTEGER lower;
ULONG lowerSpan;
LARGE_INTEGER higher;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
a = A;
b = B;
if(a.QuadPart == b.QuadPart)
return AddressesAreEqual;
if(a.QuadPart > b.QuadPart)
{
higher = a;
lower = b;
lowerSpan = SpanOfB;
}
else
{
higher = b;
lower = a;
lowerSpan = SpanOfA;
}
if((higher.QuadPart - lower.QuadPart) >= lowerSpan)
return AddressesAreDisjoint;
return AddressesOverlap;
}
NTSTATUS
PLX_9050_CNTRL_REG_FIX(IN PCARD_DEVICE_EXTENSION pCard)
{
/********************************************************
* Setting bit 17 in the CNTRL register of the PLX 9050 *
* chip forces a retry on writes while a read is pending.*
* This is to prevent the card locking up on Intel Xeon *
* multiprocessor systems with the NX chipset. *
********************************************************/
#define CNTRL_REG_OFFSET 0x14 // DWORD Offset (BYTE Offset 0x50)
NTSTATUS status = STATUS_SUCCESS;
PULONG pPCIConfigRegisters = NULL; // Pointer to PCI Config Registers.
CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Entering PLX_9050_CNTRL_REG_FIX for Card %d.\n",
PRODUCT_NAME, pCard->CardNumber));
pPCIConfigRegisters = MmMapIoSpace(pCard->PCIConfigRegisters, pCard->SpanOfPCIConfigRegisters, FALSE);
if(pPCIConfigRegisters != NULL)
{
/* NOTE: If bit 7 of the PLX9050 config space physical address is set in either I/O Space or Memory...
* ...then reads from the registers will only return 0. However, writes are OK. */
if(pPCIConfigRegisters[CNTRL_REG_OFFSET] == 0) // If bit 7 is set Config Registers are zero (unreadable)
{
// We have to blindly write the value to the register.
((PUCHAR)pPCIConfigRegisters)[CNTRL_REG_OFFSET*4 + 2] |= 0x26; // Set bits 17 & 21 of PLX CNTRL register
}
else
{
((PUCHAR)pPCIConfigRegisters)[CNTRL_REG_OFFSET*4 + 1] &= ~0x40; // Clear bit 14 of PLX CNTRL register
((PUCHAR)pPCIConfigRegisters)[CNTRL_REG_OFFSET*4 + 2] |= 0x26; // Set bits 17 & 21 of PLX CNTRL register
}
MmUnmapIoSpace(pPCIConfigRegisters, pCard->SpanOfPCIConfigRegisters);
}
else
{
SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Insufficient resources available for Card %d.\n",
PRODUCT_NAME, pCard->CardNumber));
sprintf(szErrorMsg, "Card at %08X%08X: Insufficient resources.", pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pCard->DriverObject, // Driver Object
pCard->DeviceObject, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
0, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
return STATUS_INSUFFICIENT_RESOURCES;
}
return status;
}
//
// Definitely NON PAGABLE !!!
//
VOID
SpxSetOrClearPnpPowerFlags(IN PCOMMON_OBJECT_DATA pDevExt, IN ULONG Value, IN BOOLEAN Set)
{
KIRQL oldIrql;
KeAcquireSpinLock(&pDevExt->PnpPowerFlagsLock, &oldIrql);
if(Set)
pDevExt->PnpPowerFlags |= Value;
else
pDevExt->PnpPowerFlags &= ~Value;
KeReleaseSpinLock(&pDevExt->PnpPowerFlagsLock, oldIrql);
}
// Definitely NON PAGABLE !!!
//
VOID
SpxSetOrClearUnstallingFlag(IN PCOMMON_OBJECT_DATA pDevExt, IN BOOLEAN Set)
{
KIRQL oldIrql;
KeAcquireSpinLock(&pDevExt->StalledIrpLock, &oldIrql);
pDevExt->UnstallingFlag = Set;
KeReleaseSpinLock(&pDevExt->StalledIrpLock, oldIrql);
}
// Definitely NON PAGABLE !!!
//
BOOLEAN
SpxCheckPnpPowerFlags(IN PCOMMON_OBJECT_DATA pDevExt, IN ULONG ulSetFlags, IN ULONG ulClearedFlags, IN BOOLEAN bAll)
{
KIRQL oldIrql;
BOOLEAN bRet = FALSE;
KeAcquireSpinLock(&pDevExt->PnpPowerFlagsLock, &oldIrql);
if(bAll)
{
// If all the requested SetFlags are set
// and if all of the requested ClearedFlags are cleared then return true.
if(((ulSetFlags & pDevExt->PnpPowerFlags) == ulSetFlags) && !(ulClearedFlags & pDevExt->PnpPowerFlags))
bRet = TRUE;
}
else
{
// If any of the requested SetFlags are set
// or if any of the requested ClearedFlags are cleared then return true.
if((ulSetFlags & pDevExt->PnpPowerFlags) || (ulClearedFlags & ~pDevExt->PnpPowerFlags))
bRet = TRUE;
}
KeReleaseSpinLock(&pDevExt->PnpPowerFlagsLock, oldIrql);
return bRet;
}
PVOID
SpxAllocateMem(IN POOL_TYPE PoolType, IN ULONG NumberOfBytes)
{
PVOID pRet = NULL;
pRet = ExAllocatePoolWithTag(PoolType, NumberOfBytes, MEMORY_TAG);
if(pRet)
RtlZeroMemory(pRet, NumberOfBytes); // Zero memory.
return pRet;
}
PVOID
SpxAllocateMemWithQuota(IN POOL_TYPE PoolType, IN ULONG NumberOfBytes)
{
PVOID pRet = NULL;
pRet = ExAllocatePoolWithQuotaTag(PoolType, NumberOfBytes, MEMORY_TAG);
if(pRet)
RtlZeroMemory(pRet, NumberOfBytes); // Zero memory.
return pRet;
}
#ifndef BUILD_SPXMINIPORT
void
SpxFreeMem(PVOID pMem)
{
ASSERT(pMem != NULL); // Assert if the pointer is NULL.
ExFreePool(pMem);
}
#endif
///////////////////////////////////////////////////////////////////////////////////////////
// Must be called just before an IoCompleteRequest if IrpCondition == IRP_SUBMITTED
//
///////////////////////////////////////////////////////////////////////////////////////////
VOID
SpxIRPCounter(IN PPORT_DEVICE_EXTENSION pPort, IN PIRP pIrp, IN ULONG IrpCondition)
{
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
switch(pIrpStack->MajorFunction) // Don't filter Plug and Play IRPs
{
case IRP_MJ_FLUSH_BUFFERS:
{
switch(IrpCondition)
{
case IRP_SUBMITTED:
pPort->PerfStats.FlushIrpsSubmitted++; // Increment counter for performance stats.
break;
case IRP_COMPLETED:
{
switch(pIrp->IoStatus.Status)
{
case STATUS_SUCCESS:
pPort->PerfStats.FlushIrpsCompleted++; // Increment counter for performance stats.
break;
case STATUS_CANCELLED:
pPort->PerfStats.FlushIrpsCancelled++; // Increment counter for performance stats.
break;
default:
pPort->PerfStats.FlushIrpsCompleted++; // Increment counter for performance stats.
break;
}
break;
}
case IRP_QUEUED:
// InterlockedIncrement(&pPort->PerfStats.FlushIrpsQueued);
pPort->PerfStats.FlushIrpsQueued++; // Increment counter for performance stats.
break;
case IRP_DEQUEUED:
// InterlockedDecrement(&pPort->PerfStats.FlushIrpsQueued);
if(pPort->PerfStats.FlushIrpsQueued)
pPort->PerfStats.FlushIrpsQueued--; // Decrement counter for performance stats.
break;
default:
break;
}
break;
}
case IRP_MJ_WRITE:
{
switch(IrpCondition)
{
case IRP_SUBMITTED:
pPort->PerfStats.WriteIrpsSubmitted++; // Increment counter for performance stats.
break;
case IRP_COMPLETED:
{
switch(pIrp->IoStatus.Status)
{
case STATUS_SUCCESS:
pPort->PerfStats.WriteIrpsCompleted++; // Increment counter for performance stats.
break;
case STATUS_CANCELLED:
pPort->PerfStats.WriteIrpsCancelled++; // Increment counter for performance stats.
break;
case STATUS_TIMEOUT:
pPort->PerfStats.WriteIrpsTimedOut++; // Increment counter for performance stats.
break;
default:
pPort->PerfStats.WriteIrpsCompleted++; // Increment counter for performance stats.
break;
}
break;
}
case IRP_QUEUED:
// InterlockedIncrement(&pPort->PerfStats.WriteIrpsQueued);
pPort->PerfStats.WriteIrpsQueued++; // Increment counter for performance stats.
break;
case IRP_DEQUEUED:
// InterlockedDecrement(&pPort->PerfStats.WriteIrpsQueued);
if(pPort->PerfStats.WriteIrpsQueued)
pPort->PerfStats.WriteIrpsQueued--; // Decrement counter for performance stats.
break;
default:
break;
}
break;
}
case IRP_MJ_READ:
{
switch(IrpCondition)
{
case IRP_SUBMITTED:
pPort->PerfStats.ReadIrpsSubmitted++; // Increment counter for performance stats.
break;
case IRP_COMPLETED:
{
switch(pIrp->IoStatus.Status)
{
case STATUS_SUCCESS:
pPort->PerfStats.ReadIrpsCompleted++; // Increment counter for performance stats.
break;
case STATUS_CANCELLED:
pPort->PerfStats.ReadIrpsCancelled++; // Increment counter for performance stats.
break;
case STATUS_TIMEOUT:
pPort->PerfStats.ReadIrpsTimedOut++; // Increment counter for performance stats.
break;
default:
pPort->PerfStats.ReadIrpsCompleted++; // Increment counter for performance stats.
break;
}
break;
}
case IRP_QUEUED:
// InterlockedIncrement(&pPort->PerfStats.ReadIrpsQueued);
pPort->PerfStats.ReadIrpsQueued++; // Increment counter for performance stats.
break;
case IRP_DEQUEUED:
// InterlockedDecrement(&pPort->PerfStats.ReadIrpsQueued);
if(pPort->PerfStats.ReadIrpsQueued)
pPort->PerfStats.ReadIrpsQueued--; // Decrement counter for performance stats.
break;
default:
break;
}
break;
}
case IRP_MJ_DEVICE_CONTROL:
{
switch(IrpCondition)
{
case IRP_SUBMITTED:
pPort->PerfStats.IoctlIrpsSubmitted++; // Increment counter for performance stats.
break;
case IRP_COMPLETED:
{
switch(pIrp->IoStatus.Status)
{
case STATUS_SUCCESS:
pPort->PerfStats.IoctlIrpsCompleted++; // Increment counter for performance stats.
break;
case STATUS_CANCELLED:
pPort->PerfStats.IoctlIrpsCancelled++; // Increment counter for performance stats.
break;
default:
pPort->PerfStats.IoctlIrpsCompleted++; // Increment counter for performance stats.
break;
}
break;
}
default:
break;
}
break;
}
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
{
switch(IrpCondition)
{
case IRP_SUBMITTED:
pPort->PerfStats.InternalIoctlIrpsSubmitted++; // Increment counter for performance stats.
break;
case IRP_COMPLETED:
{
switch(pIrp->IoStatus.Status)
{
case STATUS_SUCCESS:
pPort->PerfStats.InternalIoctlIrpsCompleted++; // Increment counter for performance stats.
break;
case STATUS_CANCELLED:
pPort->PerfStats.InternalIoctlIrpsCancelled++; // Increment counter for performance stats.
break;
default:
pPort->PerfStats.InternalIoctlIrpsCompleted++; // Increment counter for performance stats.
break;
}
break;
}
default:
break;
}
break;
}
case IRP_MJ_CREATE:
{
switch(IrpCondition)
{
case IRP_SUBMITTED:
pPort->PerfStats.CreateIrpsSubmitted++; // Increment counter for performance stats.
break;
case IRP_COMPLETED:
{
switch(pIrp->IoStatus.Status)
{
case STATUS_SUCCESS:
pPort->PerfStats.CreateIrpsCompleted++; // Increment counter for performance stats.
break;
case STATUS_CANCELLED:
pPort->PerfStats.CreateIrpsCancelled++; // Increment counter for performance stats.
break;
default:
pPort->PerfStats.CreateIrpsCompleted++; // Increment counter for performance stats.
break;
}
break;
}
default:
break;
}
break;
}
case IRP_MJ_CLOSE:
{
switch(IrpCondition)
{
case IRP_SUBMITTED:
pPort->PerfStats.CloseIrpsSubmitted++; // Increment counter for performance stats.
break;
case IRP_COMPLETED:
{
switch(pIrp->IoStatus.Status)
{
case STATUS_SUCCESS:
pPort->PerfStats.CloseIrpsCompleted++; // Increment counter for performance stats.
break;
case STATUS_CANCELLED:
pPort->PerfStats.CloseIrpsCancelled++; // Increment counter for performance stats.
break;
default:
pPort->PerfStats.CloseIrpsCompleted++; // Increment counter for performance stats.
break;
}
break;
}
default:
break;
}
break;
}
case IRP_MJ_CLEANUP:
{
switch(IrpCondition)
{
case IRP_SUBMITTED:
pPort->PerfStats.CleanUpIrpsSubmitted++; // Increment counter for performance stats.
break;
case IRP_COMPLETED:
{
switch(pIrp->IoStatus.Status)
{
case STATUS_SUCCESS:
pPort->PerfStats.CleanUpIrpsCompleted++; // Increment counter for performance stats.
break;
case STATUS_CANCELLED:
pPort->PerfStats.CleanUpIrpsCancelled++; // Increment counter for performance stats.
break;
default:
pPort->PerfStats.CleanUpIrpsCompleted++; // Increment counter for performance stats.
break;
}
break;
}
default:
break;
}
break;
}
case IRP_MJ_QUERY_INFORMATION:
case IRP_MJ_SET_INFORMATION:
{
switch(IrpCondition)
{
case IRP_SUBMITTED:
pPort->PerfStats.InfoIrpsSubmitted++; // Increment counter for performance stats.
break;
case IRP_COMPLETED:
{
switch(pIrp->IoStatus.Status)
{
case STATUS_SUCCESS:
pPort->PerfStats.InfoIrpsCompleted++; // Increment counter for performance stats.
break;
case STATUS_CANCELLED:
pPort->PerfStats.InfoIrpsCancelled++; // Increment counter for performance stats.
break;
default:
pPort->PerfStats.InfoIrpsCompleted++; // Increment counter for performance stats.
break;
}
break;
}
default:
break;
}
break;
}
default:
break;
}
}
////////////////////////////////////////////////////////////////////////////////
// Prototype: BOOLEAN SpxClearAllPortStats(IN PPORT_DEVICE_EXTENSION pPort)
//
// Routine Description:
// In sync with the interrpt service routine (which sets the perf stats)
// clear the perf stats.
//
// Arguments:
// pPort - Pointer to a the Port Device Extension.
//
////////////////////////////////////////////////////////////////////////////////
BOOLEAN SpxClearAllPortStats(IN PPORT_DEVICE_EXTENSION pPort)
{
RtlZeroMemory(&pPort->PerfStats, sizeof(PORT_PERFORMANCE_STATS));
return FALSE;
}