|
|
/*++
Copyright (C) Microsoft Corporation, 1997 - 1999
Module Name:
wmi.c
Abstract:
This module contains the WMI support code for SCSIPORT's functional and physical device objects.
Authors:
Dan Markarian
Environment:
Kernel mode only.
Notes:
None.
Revision History:
19-Mar-1997, Original Writing, Dan Markarian
--*/
#include "port.h"
#define __FILE_ID__ 'wmi '
#if DBG
static const char *__file__ = __FILE__; #endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, ScsiPortSystemControlIrp)
#pragma alloc_text(PAGE, SpWmiIrpNormalRequest)
#pragma alloc_text(PAGE, SpWmiIrpRegisterRequest)
#pragma alloc_text(PAGE, SpWmiHandleOnMiniPortBehalf)
#pragma alloc_text(PAGE, SpWmiPassToMiniPort)
#pragma alloc_text(PAGE, SpWmiDestroySpRegInfo)
#pragma alloc_text(PAGE, SpWmiGetSpRegInfo)
#pragma alloc_text(PAGE, SpWmiInitializeSpRegInfo)
#pragma alloc_text(PAGE, SpWmiInitializeFreeRequestList)
#pragma alloc_text(PAGE, SpAdapterConfiguredForSenseDataEvents)
#pragma alloc_text(PAGE, SpInitAdapterWmiRegInfo)
#endif
#define SP_WMI_EVENT 1
NTSTATUS ScsiPortSystemControlIrp( PDEVICE_OBJECT DeviceObject, PIRP Irp )
/*++
Routine Description:
Process an IRP_MJ_SYSTEM_CONTROL request packet.
Arguments:
DeviceObject - Pointer to the functional or physical device object.
Irp - Pointer to the request packet.
Return Value:
NTSTATUS result code.
--*/
{ PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension; PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_SUCCESS; WMI_PARAMETERS wmiParameters;
ULONG isRemoved;
PAGED_CODE();
isRemoved = SpAcquireRemoveLock(DeviceObject, Irp);
if (isRemoved) { Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; SpReleaseRemoveLock(DeviceObject, Irp); SpCompleteRequest(DeviceObject, Irp, NULL, IO_NO_INCREMENT); return STATUS_DEVICE_DOES_NOT_EXIST; }
//
// Obtain a pointer to the current IRP stack location.
//
irpSp = IoGetCurrentIrpStackLocation(Irp);
ASSERT(irpSp->MajorFunction == IRP_MJ_SYSTEM_CONTROL);
//
// Determine if this WMI request was destined to us. If not, pass the IRP
// down.
//
if ( (PDEVICE_OBJECT)irpSp->Parameters.WMI.ProviderId == DeviceObject) { BOOLEAN forwardDown = FALSE;
DebugPrint((SP_WMI_EVENT, "ScsiPortSystemControlIrp: MinorFunction %x\n", irpSp->MinorFunction)); //
// Copy the WMI parameters into our local WMISRB structure.
//
wmiParameters.ProviderId = irpSp->Parameters.WMI.ProviderId; wmiParameters.DataPath = irpSp->Parameters.WMI.DataPath; wmiParameters.Buffer = irpSp->Parameters.WMI.Buffer; wmiParameters.BufferSize = irpSp->Parameters.WMI.BufferSize; //
// Determine what the WMI request wants of us.
//
switch (irpSp->MinorFunction) { case IRP_MN_QUERY_ALL_DATA: //
// Query for all instances of a data block.
//
case IRP_MN_QUERY_SINGLE_INSTANCE: //
// Query for a single instance of a data block.
//
case IRP_MN_CHANGE_SINGLE_INSTANCE: //
// Change all data items in a data block for a single instance.
//
case IRP_MN_CHANGE_SINGLE_ITEM: //
// Change a single data item in a data block for a single instance.
//
case IRP_MN_ENABLE_EVENTS: //
// Enable events.
//
case IRP_MN_DISABLE_EVENTS: //
// Disable events.
//
case IRP_MN_ENABLE_COLLECTION: //
// Enable data collection for the given GUID.
//
case IRP_MN_DISABLE_COLLECTION: //
// Disable data collection for the given GUID.
//
status = SpWmiIrpNormalRequest(DeviceObject, irpSp->MinorFunction, &wmiParameters); break; case IRP_MN_EXECUTE_METHOD: //
// Execute method
//
status = SpWmiIrpNormalRequest(DeviceObject, irpSp->MinorFunction, &wmiParameters); break; case IRP_MN_REGINFO: //
// Query for registration and registration update information.
//
status = SpWmiIrpRegisterRequest(DeviceObject, &wmiParameters); break; default: //
// Unsupported WMI request. According to some rule in the WMI
// spec we're supposed to send unsupported WMI requests down
// the stack even if we're marked as the provider.
//
forwardDown = TRUE; break; }
if(forwardDown == FALSE) { //
// Complete this WMI IRP request.
//
Irp->IoStatus.Status = status; Irp->IoStatus.Information= (NT_SUCCESS(status) ? wmiParameters.BufferSize : 0); SpReleaseRemoveLock(DeviceObject, Irp); SpCompleteRequest(DeviceObject, Irp, NULL, IO_NO_INCREMENT);
return status; } }
//
// Request should be forwarded down the stack. If we're a pdo that means
// we should complete it as is.
//
SpReleaseRemoveLock(DeviceObject, Irp);
if(commonExtension->IsPdo) { //
// Get the current status out of the irp.
//
status = Irp->IoStatus.Status;
//
// Complete the irp.
//
SpCompleteRequest(DeviceObject, Irp, NULL, IO_NO_INCREMENT); } else { //
// Copy parameters from our stack location to the next stack location.
//
IoCopyCurrentIrpStackLocationToNext(Irp); //
// Pass the IRP on to the next driver.
//
status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); }
return status; }
NTSTATUS SpWmiIrpNormalRequest( IN PDEVICE_OBJECT DeviceObject, IN UCHAR WmiMinorCode, IN OUT PWMI_PARAMETERS WmiParameters )
/*++
Routine Description:
Process an IRP_MJ_SYSTEM_CONTROL request packet (for all requests except registration IRP_MN_REGINFO requests).
Arguments:
DeviceObject - Pointer to the functional or physical device object.
WmiMinorCode - WMI action to perform.
WmiParameters - Pointer to the WMI request parameters.
Return Value:
NTSTATUS result code to complete the WMI IRP with.
Notes:
If this WMI request is completed with STATUS_SUCCESS, the WmiParameters BufferSize field will reflect the actual size of the WMI return buffer.
--*/
{ PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension; NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
//
// Determine if SCSIPORT will repond to this WMI request on behalf of
// the miniport driver.
//
status = SpWmiHandleOnMiniPortBehalf(DeviceObject, WmiMinorCode, WmiParameters);
//
// If not, pass the request onto the miniport driver, provided the
// miniport driver does support WMI.
//
if (status == STATUS_WMI_GUID_NOT_FOUND && commonExtension->WmiMiniPortSupport) {
//
// Send off the WMI request to the miniport.
//
status = SpWmiPassToMiniPort(DeviceObject, WmiMinorCode, WmiParameters);
if (NT_SUCCESS(status)) {
//
// Fill in fields miniport cannot fill in for itself.
//
if ( WmiMinorCode == IRP_MN_QUERY_ALL_DATA || WmiMinorCode == IRP_MN_QUERY_SINGLE_INSTANCE ) { PWNODE_HEADER wnodeHeader = WmiParameters->Buffer;
ASSERT( WmiParameters->BufferSize >= sizeof(WNODE_HEADER) );
KeQuerySystemTime(&wnodeHeader->TimeStamp); } } else {
//
// Translate SRB status into a meaningful NTSTATUS status.
//
status = STATUS_INVALID_DEVICE_REQUEST; } }
return status; }
NTSTATUS SpWmiIrpRegisterRequest( IN PDEVICE_OBJECT DeviceObject, IN OUT PWMI_PARAMETERS WmiParameters )
/*++
Routine Description:
Process an IRP_MJ_SYSTEM_CONTROL registration request.
Arguments:
DeviceObject - Pointer to the functional or physical device object.
WmiParameters - Pointer to the WMI request parameters.
Return Value:
NTSTATUS result code to complete the WMI IRP with.
Notes:
If this WMI request is completed with STATUS_SUCCESS, the WmiParameters BufferSize field will reflect the actual size of the WMI return buffer.
--*/
{ PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension; PSCSIPORT_DRIVER_EXTENSION driverExtension = NULL;
ULONG countedRegistryPathSize = 0; ULONG retSz; PWMIREGINFO spWmiRegInfoBuf; ULONG spWmiRegInfoBufSize; NTSTATUS status = STATUS_SUCCESS; BOOLEAN wmiUpdateRequest; ULONG i; PDEVICE_OBJECT pDO;
WMI_PARAMETERS paranoidBackup = *WmiParameters;
PAGED_CODE();
DebugPrint((SP_WMI_EVENT, "SpWmiRegisterRequest: DO %p WMIParams %p\n", DeviceObject, WmiParameters));
//
// Validate our assumptions for this function's code.
//
ASSERT(WmiParameters->BufferSize >= sizeof(ULONG));
//
// Validate the registration mode.
//
switch ( (ULONG)(ULONG_PTR)WmiParameters->DataPath ) { case WMIUPDATE: //
// No SCSIPORT registration information will be piggybacked
// on behalf of the miniport for a WMIUPDATE request.
//
wmiUpdateRequest = TRUE; break;
case WMIREGISTER: wmiUpdateRequest = FALSE; break;
default: //
// Unsupported registration mode.
//
ASSERT(FALSE); return STATUS_INVALID_PARAMETER; }
//
// Obtain the driver extension for this miniport (FDO/PDO).
//
driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, ScsiPortInitialize);
ASSERT(driverExtension != NULL); //
// Make Prefix Happy -- we'll quit if
// driverExtension is NULL
//
if (driverExtension == NULL) { return (STATUS_UNSUCCESSFUL); }
//
// Obtain a pointer to the SCSIPORT WMI registration information
// buffer, which is registered on behalf of the miniport driver.
//
SpWmiGetSpRegInfo(DeviceObject, &spWmiRegInfoBuf, &spWmiRegInfoBufSize);
DebugPrint((SP_WMI_EVENT, "SpWmiIrpRegisterRequest: spWmiRegInfoBuf %p SpWmiReginfoBufSize %d\n", spWmiRegInfoBuf, spWmiRegInfoBufSize));
//
// Pass the WMI registration request to the miniport. This is not
// necessary if we know the miniport driver does not support WMI.
//
if (commonExtension->WmiMiniPortSupport == TRUE && (commonExtension->WmiMiniPortInitialized == TRUE || commonExtension->IsPdo == TRUE)) {
DebugPrint((SP_WMI_EVENT, "SpWmiIrpRegisterRequest: add miniport data\n")); //
// Note that we shrink the buffer size by the size necessary
// to hold SCSIPORT's own registration information, which we
// register on behalf of the miniport. This information is
// piggybacked into the WMI return buffer after the call to
// the miniport. We ensure that the BufferSize passed to the
// miniport is no smaller than "sizeof(ULONG)" so that it can
// tell us the required buffer size should the buffer be too
// small [by filling in this ULONG].
//
// Note that we must also make enough room for a copy of the
// miniport registry path in the buffer, since the WMIREGINFO
// structures from the miniport DO NOT set their registry
// path fields.
//
if (WmiParameters->BufferSize < sizeof(ULONG)) { return STATUS_INVALID_PARAMETER; }
//
// Calculate size of required miniport registry path.
//
countedRegistryPathSize = driverExtension->RegistryPath.Length + sizeof(USHORT);
//
// Shrink buffer by the appropriate size. Note that the extra
// 7 bytes (possibly extraneous) is subtracted to ensure that
// the piggybacked data added later on is 8-byte aligned (if
// any).
//
if (spWmiRegInfoBufSize && !wmiUpdateRequest) { WmiParameters->BufferSize = (WmiParameters->BufferSize > spWmiRegInfoBufSize + countedRegistryPathSize + 7 + sizeof(ULONG)) ? WmiParameters->BufferSize - spWmiRegInfoBufSize - countedRegistryPathSize - 7 : sizeof(ULONG); } else { // no data to piggyback
WmiParameters->BufferSize = (WmiParameters->BufferSize > countedRegistryPathSize + sizeof(ULONG)) ? WmiParameters->BufferSize - countedRegistryPathSize : sizeof(ULONG); }
//
// Call the minidriver.
//
status = SpWmiPassToMiniPort(DeviceObject, IRP_MN_REGINFO, WmiParameters);
ASSERT(WmiParameters->ProviderId == paranoidBackup.ProviderId); ASSERT(WmiParameters->DataPath == paranoidBackup.DataPath); ASSERT(WmiParameters->Buffer == paranoidBackup.Buffer); ASSERT(WmiParameters->BufferSize <= paranoidBackup.BufferSize);
//
// Assign WmiParameters->BufferSize to retSz temporarily.
//
// Note that on return from the above call, the wmiParameters'
// BufferSize field has been _modified_ to reflect the current
// size of the return buffer.
//
retSz = WmiParameters->BufferSize;
} else if (WmiParameters->BufferSize < spWmiRegInfoBufSize && !wmiUpdateRequest) {
//
// Insufficient space to hold SCSIPORT WMI registration information
// alone. Inform WMI appropriately of the required buffer size.
//
*((ULONG*)WmiParameters->Buffer) = spWmiRegInfoBufSize; WmiParameters->BufferSize = sizeof(ULONG);
return STATUS_SUCCESS;
} else { // no miniport support for WMI, sufficient space for scsiport info
//
// Fake having the miniport return zero WMIREGINFO structures.
//
retSz = 0; }
//
// Piggyback SCSIPORT's registration information into the WMI
// registration buffer.
//
if ((status == STATUS_BUFFER_TOO_SMALL) || (NT_SUCCESS(status) && (retSz == sizeof(ULONG)))) { //
// Miniport could not fit registration information into the
// pre-shrunk buffer.
//
// Buffer currently contains a ULONG specifying required buffer
// size of miniport registration info, but does not include the
// SCSIPORT registration info's size. Add it in.
//
if (spWmiRegInfoBufSize && !wmiUpdateRequest) {
*((ULONG*)WmiParameters->Buffer) += spWmiRegInfoBufSize;
//
// Add an extra 7 bytes (possibly extraneous) which is used to
// ensure that the piggybacked data structure 8-byte aligned.
//
*((ULONG*)WmiParameters->Buffer) += 7; }
//
// Add in size of the miniport registry path.
//
*((ULONG*)WmiParameters->Buffer) += countedRegistryPathSize;
//
// Return STATUS_SUCCESS, even though this is a BUFFER TOO
// SMALL failure, while ensuring retSz = sizeof(ULONG), as
// the WMI protocol calls us to do.
//
retSz = sizeof(ULONG); status = STATUS_SUCCESS;
} else if ( NT_SUCCESS(status) ) {
DebugPrint((SP_WMI_EVENT, "SpWmiIrpRegisterRequest: add scsiport stuff...\n")); //
// Zero or more WMIREGINFOs exist in buffer from miniport.
//
//
// Piggyback the miniport registry path transparently, if at least one
// WMIREGINFO was returned by the minport.
//
if (retSz) {
ULONG offsetToRegPath = retSz; PWMIREGINFO wmiRegInfo = WmiParameters->Buffer;
DebugPrint((SP_WMI_EVENT, "SpWmiIrpRegisterRequest: piggybacking...\n"));
//
// Build a counted wide-character string, containing the
// registry path, into the WMI buffer.
//
*( (PUSHORT)( (PUCHAR)WmiParameters->Buffer + retSz ) ) = driverExtension->RegistryPath.Length, RtlCopyMemory( (PUCHAR)WmiParameters->Buffer + retSz + sizeof(USHORT), driverExtension->RegistryPath.Buffer, driverExtension->RegistryPath.Length);
//
// Traverse the WMIREGINFO structures returned by the mini-
// driver and set the missing RegistryPath fields to point
// to our registry path location. We also jam in the PDO for
// the device stack so that the device instance name is used for
// the wmi instance names.
//
pDO = commonExtension->IsPdo ? DeviceObject : ((PADAPTER_EXTENSION)commonExtension)->LowerPdo;
while (1) { wmiRegInfo->RegistryPath = offsetToRegPath;
for (i = 0; i < wmiRegInfo->GuidCount; i++) { if ((wmiRegInfo->WmiRegGuid[i].Flags & (WMIREG_FLAG_INSTANCE_BASENAME | WMIREG_FLAG_INSTANCE_LIST)) != 0) { wmiRegInfo->WmiRegGuid[i].InstanceInfo = (ULONG_PTR)pDO; wmiRegInfo->WmiRegGuid[i].Flags &= ~(WMIREG_FLAG_INSTANCE_BASENAME | WMIREG_FLAG_INSTANCE_LIST); wmiRegInfo->WmiRegGuid[i].Flags |= WMIREG_FLAG_INSTANCE_PDO; } }
if (wmiRegInfo->NextWmiRegInfo == 0) { break; }
offsetToRegPath -= wmiRegInfo->NextWmiRegInfo; wmiRegInfo = (PWMIREGINFO)( (PUCHAR)wmiRegInfo + wmiRegInfo->NextWmiRegInfo ); }
//
// Adjust retSz to reflect new size of the WMI buffer.
//
retSz += countedRegistryPathSize; wmiRegInfo->BufferSize = retSz; } // else, no WMIREGINFOs registered whatsoever, nothing to piggyback
//
// Do we have any SCSIPORT WMIREGINFOs to piggyback?
//
if (spWmiRegInfoBufSize && !wmiUpdateRequest) {
//
// Adjust retSz so that the data we piggyback is 8-byte aligned
// (safe if retSz = 0).
//
retSz = (retSz + 7) & ~7;
//
// Piggyback SCSIPORT's registration info into the buffer.
//
RtlCopyMemory( (PUCHAR)WmiParameters->Buffer + retSz, spWmiRegInfoBuf, spWmiRegInfoBufSize);
//
// Was at least one WMIREGINFO returned by the minidriver?
// Otherwise, we have nothing else to add to the WMI buffer.
//
if (retSz) { // at least one WMIREGINFO returned by minidriver
PWMIREGINFO wmiRegInfo = WmiParameters->Buffer;
//
// Traverse to the end of the WMIREGINFO structures returned
// by the miniport.
//
while (wmiRegInfo->NextWmiRegInfo) { wmiRegInfo = (PWMIREGINFO)( (PUCHAR)wmiRegInfo + wmiRegInfo->NextWmiRegInfo ); }
//
// Chain minidriver's WMIREGINFO structures to SCSIPORT's
// WMIREGINFO structures.
//
wmiRegInfo->NextWmiRegInfo = retSz - (ULONG)((PUCHAR)wmiRegInfo - (PUCHAR)WmiParameters->Buffer); }
//
// Adjust retSz to reflect new size of the WMI buffer.
//
retSz += spWmiRegInfoBufSize;
} // we had SCSIPORT REGINFO data to piggyback
} // else, unknown error, complete IRP with this error status
//
// Save new buffer size to WmiParameters->BufferSize.
//
WmiParameters->BufferSize = retSz;
DebugPrint((SP_WMI_EVENT, "SpWmiIrpRegisterRequest: done status %08x WMIParams %p\n", status, WmiParameters));
return status; }
NTSTATUS SpWmiHandleOnMiniPortBehalf( IN PDEVICE_OBJECT DeviceObject, IN UCHAR WmiMinorCode, IN OUT PWMI_PARAMETERS WmiParameters )
/*++
Routine Description:
Handle the WMI request on the miniport's behalf, if possible.
Arguments:
DeviceObject - Pointer to the functional or physical device object.
WmiMinorCode - WMI action to perform.
WmiParameters - WMI parameters.
Return Value:
If STATUS_UNSUCCESSFUL is returned, SCSIPORT did not handle this WMI request. It must be passed on to the miniport driver for processing.
Otherwise, this function returns an NTSTATUS code describing the result of handling the WMI request. Complete the IRP with this status.
Notes:
If this WMI request is completed with STATUS_SUCCESS, the WmiParameters BufferSize field will reflect the actual size of the WMI return buffer.
--*/ { PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
PAGED_CODE();
if (commonExtension->IsPdo) { //
/// Placeholder for code to check if this is a PDO-relevant GUID which
// SCSIPORT must handle, and handle it if so.
//
} else { // FDO
NTSTATUS status; GUID guid = *(GUID*)WmiParameters->DataPath; PADAPTER_EXTENSION Adapter = (PADAPTER_EXTENSION) commonExtension; SIZE_T size;
DebugPrint((SP_WMI_EVENT, "SpWmiHandleOnMiniPortBehalf: WmiMinorCode:%x guid:" "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", WmiMinorCode, guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]));
//
// Check the guid to verify that it represents a data block supported
// by scsiport. If it does not, we return failure and let the
// miniports have a look at it.
//
size = RtlCompareMemory(&guid, &Adapter->SenseDataEventClass, sizeof(GUID)); if (size != sizeof(GUID)) {
//
// WMI spec says to fail the irp w/ STATUS_WMI_GUID_NOT_FOUND if the
// guid does not represent a data block we understand.
//
DebugPrint((SP_WMI_EVENT, "SpWmiHandleOnMiniPortBehalf: not handling data block\n")); return STATUS_WMI_GUID_NOT_FOUND; }
//
// Handle the request. At this point, we've decided that the IRP
// is intended for this device and that this is a datablock
// supported by the device. Therefore, the code below returns the
// appropriate result as per the wmi spec.
//
switch (WmiMinorCode) { case IRP_MN_QUERY_ALL_DATA: case IRP_MN_QUERY_SINGLE_INSTANCE: case IRP_MN_CHANGE_SINGLE_INSTANCE: case IRP_MN_CHANGE_SINGLE_ITEM: case IRP_MN_ENABLE_COLLECTION: case IRP_MN_DISABLE_COLLECTION: case IRP_MN_REGINFO: case IRP_MN_EXECUTE_METHOD: status = STATUS_INVALID_DEVICE_REQUEST; break; case IRP_MN_ENABLE_EVENTS: DebugPrint((SP_WMI_EVENT, "SenseData event enabled\n")); Adapter->EnableSenseDataEvent = TRUE; WmiParameters->BufferSize = 0; status = STATUS_SUCCESS; break;
case IRP_MN_DISABLE_EVENTS: DebugPrint((SP_WMI_EVENT, "SenseData event disabled\n")); Adapter->EnableSenseDataEvent = FALSE; WmiParameters->BufferSize = 0; status = STATUS_SUCCESS; break;
default: status = STATUS_INVALID_DEVICE_REQUEST; break; };
return status;
}
return STATUS_WMI_GUID_NOT_FOUND; }
NTSTATUS SpWmiPassToMiniPort( IN PDEVICE_OBJECT DeviceObject, IN UCHAR WmiMinorCode, IN OUT PWMI_PARAMETERS WmiParameters ) /*++
Routine Description:
This function pass a WMI request to the miniport driver for processing. It creates an SRB which is processed normally by the port driver. This call is synchronous.
Callers of SpWmiPassToMiniPort must be running at IRQL PASSIVE_LEVEL.
Arguments:
DeviceObject - Pointer to the functional or physical device object.
WmiMinorCode - WMI action to perform.
WmiParameters - WMI parameters.
Return Value:
An NTSTATUS code describing the result of handling the WMI request. Complete the IRP with this status.
Notes:
If this WMI request is completed with STATUS_SUCCESS, the WmiParameters BufferSize field will reflect the actual size of the WMI return buffer.
--*/ { PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension; PADAPTER_EXTENSION fdoExtension; SCSI_WMI_REQUEST_BLOCK srb; LARGE_INTEGER startingOffset; PLOGICAL_UNIT_EXTENSION logicalUnit;
ULONG commonBufferSize; PUCHAR commonBuffer; PHYSICAL_ADDRESS physicalAddress; PVOID removeTag = (PVOID)((ULONG_PTR)WmiParameters+3); PWNODE_HEADER wnode;
NTSTATUS status;
PAGED_CODE();
startingOffset.QuadPart = (LONGLONG) 1;
//
// Zero out the SRB.
//
RtlZeroMemory(&srb, sizeof(SCSI_WMI_REQUEST_BLOCK));
//
// Initialize the SRB for a WMI request.
//
if (commonExtension->IsPdo) { // [PDO]
//
// Set the logical unit addressing from this PDO's device extension.
//
logicalUnit = DeviceObject->DeviceExtension;
SpAcquireRemoveLock(DeviceObject, removeTag);
srb.PathId = logicalUnit->PathId; srb.TargetId = logicalUnit->TargetId; srb.Lun = logicalUnit->Lun;
fdoExtension = logicalUnit->AdapterExtension;
} else { // [FDO]
//
// Set the logical unit addressing to the first logical unit. This is
// merely used for addressing purposes for adapter requests only.
// NOTE: SpFindSafeLogicalUnit will acquire the remove lock
//
logicalUnit = SpFindSafeLogicalUnit(DeviceObject, 0xff, removeTag);
if (logicalUnit == NULL) { return(STATUS_DEVICE_DOES_NOT_EXIST); }
fdoExtension = DeviceObject->DeviceExtension;
srb.WMIFlags = SRB_WMI_FLAGS_ADAPTER_REQUEST; srb.PathId = logicalUnit->PathId; srb.TargetId = logicalUnit->TargetId; srb.Lun = logicalUnit->Lun; }
//
// HACK - allocate a chunk of common buffer for the actual request to
// get processed in. We need to determine the size of buffer to allocate
// this is the larger of the input or output buffers
//
if (WmiMinorCode == IRP_MN_EXECUTE_METHOD) { wnode = (PWNODE_HEADER)WmiParameters->Buffer; commonBufferSize = (WmiParameters->BufferSize > wnode->BufferSize) ? WmiParameters->BufferSize : wnode->BufferSize; } else { commonBufferSize = WmiParameters->BufferSize; }
commonBuffer = AllocateCommonBuffer(fdoExtension->DmaAdapterObject, commonBufferSize, &physicalAddress, FALSE);
if(commonBuffer == NULL) { DebugPrint((SP_WMI_EVENT, "SpWmiPassToMiniPort: Unable to allocate %#x bytes of " "common buffer\n", commonBufferSize));
SpReleaseRemoveLock(logicalUnit->DeviceObject, removeTag);
return STATUS_INSUFFICIENT_RESOURCES; }
try { KEVENT event; PIRP irp; PMDL mdl; PIO_STACK_LOCATION irpStack;
RtlCopyMemory(commonBuffer, WmiParameters->Buffer, commonBufferSize);
srb.DataBuffer = commonBuffer; // [already non-paged]
srb.DataTransferLength = WmiParameters->BufferSize; srb.Function = SRB_FUNCTION_WMI; srb.Length = sizeof(SCSI_REQUEST_BLOCK); srb.WMISubFunction = WmiMinorCode; srb.DataPath = WmiParameters->DataPath; srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_NO_QUEUE_FREEZE; srb.TimeOutValue = 10; // [ten seconds]
//
// Note that the value in DataBuffer may be used regardless of the value
// of the MapBuffers field.
//
//
// Initialize the notification event.
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
//
// Build IRP for this request.
// Note we do this synchronously for two reasons. If it was done
// asynchonously then the completion code would have to make a special
// check to deallocate the buffer. Second if a completion routine were
// used then an additional IRP stack location would be needed.
//
irp = SpAllocateIrp(logicalUnit->DeviceObject->StackSize, FALSE, DeviceObject->DriverObject);
if(irp == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; leave; }
mdl = SpAllocateMdl(commonBuffer, WmiParameters->BufferSize, FALSE, FALSE, irp, DeviceObject->DriverObject);
if(mdl == NULL) { IoFreeIrp(irp); status = STATUS_INSUFFICIENT_RESOURCES; leave; }
MmBuildMdlForNonPagedPool(mdl);
srb.OriginalRequest = irp;
irpStack = IoGetNextIrpStackLocation(irp);
//
// Set major code.
//
irpStack->MajorFunction = IRP_MJ_SCSI;
//
// Set SRB pointer.
//
irpStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)&srb;
//
// Setup a completion routine so we know when the request has completed.
//
IoSetCompletionRoutine(irp, SpSignalCompletion, &event, TRUE, TRUE, TRUE);
//
// Flush the data buffer for output. This will insure that the data is
// written back to memory. Since the data-in flag is the the port driver
// will flush the data again for input which will ensure the data is not
// in the cache.
//
KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
//
// Call port driver to handle this request.
//
IoCallDriver(logicalUnit->CommonExtension.DeviceObject, irp);
//
// Wait for request to complete.
//
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = irp->IoStatus.Status;
//
// Relay the return buffer's size to the caller on success.
//
if (NT_SUCCESS(status)) { WmiParameters->BufferSize = srb.DataTransferLength; }
//
// Copy back the correct number of bytes into the caller provided buffer.
//
RtlCopyMemory(WmiParameters->Buffer, commonBuffer, WmiParameters->BufferSize);
//
// Free the irp and MDL.
//
IoFreeMdl(mdl); IoFreeIrp(irp);
} finally {
FreeCommonBuffer(fdoExtension->DmaAdapterObject, commonBufferSize, physicalAddress, commonBuffer, FALSE);
SpReleaseRemoveLock(logicalUnit->CommonExtension.DeviceObject, removeTag); }
//
// Return the IRP's status.
//
return status; }
VOID SpWmiGetSpRegInfo( IN PDEVICE_OBJECT DeviceObject, OUT PWMIREGINFO * SpRegInfoBuf, OUT ULONG * SpRegInfoBufSize ) /*++
Routine Description:
This function retrieves a pointer to the WMI registration information buffer for the given device object.
Arguments:
DeviceObject - Pointer to the functional or physical device object.
Return Values:
SpRegInfoBuf - Pointer to the registration information buffer, which will point to the WMIREGINFO structures that SCSIPORT should register on behalf of the miniport driver.
SpRegInfoBufSize - Size of the registration information buffer in bytes.
--*/ { PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
PAGED_CODE();
//
// Retrieve a pointer to the WMI registration information buffer for the
// given device object.
//
if (commonExtension->WmiScsiPortRegInfoBuf == NULL || commonExtension->WmiScsiPortRegInfoBufSize == 0) { *SpRegInfoBuf = NULL; *SpRegInfoBufSize = 0; } else { *SpRegInfoBuf = commonExtension->WmiScsiPortRegInfoBuf; *SpRegInfoBufSize = commonExtension->WmiScsiPortRegInfoBufSize; }
return; }
VOID SpWmiInitializeSpRegInfo( IN PDEVICE_OBJECT DeviceObject )
/*++
Routine Description:
This function allocates space for and builds the WMI registration information buffer for this device object.
The WMI registration information consists of zero or more WMIREGINFO structures which are used to register and identify SCSIPORT-handled WMI GUIDs on behalf of the miniport driver. This information is not the complete set of WMI GUIDs supported by for device object, only the ones supported by SCSIPORT. It is actually piggybacked onto the WMIREGINFO structures provided by the miniport driver during registration.
The WMI registration information is allocated and stored on a per-device basis because, concievably, each device may support differing WMI GUIDs and/or instances during its lifetime.
Arguments:
DeviceObject - Pointer to the functional or physical device object.
Return Value:
None.
--*/ { PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
PAGED_CODE();
ASSERT(commonExtension->WmiScsiPortRegInfoBuf == NULL); ASSERT(commonExtension->WmiScsiPortRegInfoBufSize == 0);
if (commonExtension->IsPdo) {
//
/// Placeholder for code to build PDO-relevant GUIDs into the
// registration buffer.
//
/// commonExtension->WmiScsiPortRegInfo = ExAllocatePool( PagedPool, <size> );
// commonExtension->WmiScsiPortRegInfoSize = <size>;
// <code to fill in wmireginfo struct(s) into buffer>
//
// * use L"SCSIPORT" as the RegistryPath
} else { // FDO
BOOLEAN DoesSenseEvents; GUID SenseDataClass;
//
// Determine if the supplied adapter is configured to generate sense
// data events. If it is, copy the guid into the adapter extension
// and initialize the WMIREGINFO structure pointed to by the
// adapter extension.
//
DoesSenseEvents = SpAdapterConfiguredForSenseDataEvents( DeviceObject, &SenseDataClass); if (DoesSenseEvents) { ((PADAPTER_EXTENSION)commonExtension)->SenseDataEventClass = SenseDataClass; SpInitAdapterWmiRegInfo(DeviceObject); } }
return; }
VOID SpWmiDestroySpRegInfo( IN PDEVICE_OBJECT DeviceObject )
/*++
Routine Description:
This function de-allocates the space for the WMI registration information buffer for this device object, if one exists.
Arguments:
DeviceObject - Pointer to the functional or physical device object.
Return Value:
None.
--*/ { PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
PAGED_CODE();
if (commonExtension->WmiScsiPortRegInfoBuf) { ExFreePool(commonExtension->WmiScsiPortRegInfoBuf); commonExtension->WmiScsiPortRegInfoBuf = NULL; }
commonExtension->WmiScsiPortRegInfoBufSize = 0;
return; }
NTSTATUS SpWmiInitializeFreeRequestList( IN PDEVICE_OBJECT DeviceObject, IN ULONG NumberOfItems ) /*++
Routine Description:
Call that initializes the WmiFreeMiniPortRequestList, this call MUST be completed prior to any manipulatio of the WmiFreeMiniPortRequestList
The list will be initialized with at most the number of cells requested.
If the list has already been initialized, we raise the watermark by the number of Items requested.
Arguments:
DeviceObject - Device Object that this list belongs to NumberOfItems - requested number of free cells
Return Value:
Return the SUCESS if list was initialized succesfully
STATUS_INSUFFICIENT_REOSOURCES - Indicates that we could not allocate enough memory for the list header
Notes:
--*/ { PADAPTER_EXTENSION fdoExtension; ULONG itemsInserted; KIRQL oldIrql;
PAGED_CODE(); // Routine is paged until locked down.
//
// Obtain a pointer to the functional device extension (for the adapter).
//
if ( ((PCOMMON_EXTENSION)DeviceObject->DeviceExtension)->IsPdo ) { fdoExtension = ((PLOGICAL_UNIT_EXTENSION)DeviceObject->DeviceExtension) ->AdapterExtension; } else { fdoExtension = DeviceObject->DeviceExtension; }
// If the list has been initalized increase the watermark
if (fdoExtension->WmiFreeMiniPortRequestInitialized) { DebugPrint((SP_WMI_EVENT, "SpWmiInitializeFreeRequestList:" " Increased watermark for : %p\n", fdoExtension));
InterlockedExchangeAdd (&(fdoExtension->WmiFreeMiniPortRequestWatermark), NumberOfItems);
while (fdoExtension->WmiFreeMiniPortRequestCount < fdoExtension->WmiFreeMiniPortRequestWatermark) {
// Add free cells until the count reaches the watermark
SpWmiPushFreeRequestItem(fdoExtension); }
return (STATUS_SUCCESS); }
// Only FDO's should be calling when the list has not been initialized
ASSERT_FDO(DeviceObject);
// Assignt he list we just initialized to the pointer in the
// fdoExtension (and save the lock pointer also)
KeInitializeSpinLock(&(fdoExtension->WmiFreeMiniPortRequestLock)); ExInitializeSListHead(&(fdoExtension->WmiFreeMiniPortRequestList));
DebugPrint((SP_WMI_EVENT, "SpWmiInitializeFreeRequestList:" " Initialized WmiFreeRequestList for: %p\n", fdoExtension));
// Set the initialized flag
fdoExtension->WmiFreeMiniPortRequestInitialized = TRUE;
// Set the watermark, and the count to 0
fdoExtension->WmiFreeMiniPortRequestWatermark = 0; fdoExtension->WmiFreeMiniPortRequestCount = 0;
// Attempt to add free cells to the free list
for (itemsInserted = 0; itemsInserted < NumberOfItems; itemsInserted++) {
// Make a request to push a NULL item, so that the
// allocation will be done by the next function
//
// At this point we don't care about the return value
// because after we set the watermark, scsiport's free-cell
// repopulation code will try to get the free list cell count
// back to the watermark. (So if we fail to add all the requested
// free cells, the repopulation code will attempt again for us
// at a later time)
SpWmiPushFreeRequestItem(fdoExtension); }
// Now set the watermark to the correct value
fdoExtension->WmiFreeMiniPortRequestWatermark = NumberOfItems;
return(STATUS_SUCCESS); }
VOID SpWmiPushExistingFreeRequestItem( IN PADAPTER_EXTENSION Adapter, IN PWMI_MINIPORT_REQUEST_ITEM WmiRequestItem ) /*++
Routine Description:
Inserts the entry into the interlocked list of free request items.
Arguments:
WmiRequestItem - Pointer to the request item to insert into the free list.
Return Value:
VOID
--*/ { //
// The WMI request list must be initialized.
//
if (!Adapter->WmiFreeMiniPortRequestInitialized) { ASSERT(FALSE); return; }
//
// This request doesn't point to another one.
//
WmiRequestItem->NextRequest = NULL;
//
// Insert Cell into interlocked list.
//
ExInterlockedPushEntrySList( &(Adapter->WmiFreeMiniPortRequestList), (PSLIST_ENTRY)WmiRequestItem, &(Adapter->WmiFreeMiniPortRequestLock));
//
// Increment the value of the free count.
//
InterlockedIncrement(&(Adapter->WmiFreeMiniPortRequestCount)); }
NTSTATUS SpWmiPushFreeRequestItem( IN PADAPTER_EXTENSION fdoExtension ) /*++
Routine Description:
Inserts the Entry into the interlocked SLIST. (Of Free items)
Arguments:
fdoExtension - The extension on the adapter
Return Value:
STATUS_SUCESS - If succesful STATUS_INSUFFICIENT_RESOURCES - If memory allocation fails STATUS_UNSUCCESSFUL - Free List not initialized
Notes:
This code cannot be marked as pageable since it will be called from DPC level
Theoricatlly this call can fail, but no one should call this function before we've been initialized
--*/ { PWMI_MINIPORT_REQUEST_ITEM Entry = NULL;
if (!fdoExtension->WmiFreeMiniPortRequestInitialized) { return (STATUS_UNSUCCESSFUL); }
Entry = SpAllocatePool(NonPagedPool, sizeof(WMI_MINIPORT_REQUEST_ITEM), SCSIPORT_TAG_WMI_EVENT, fdoExtension->DeviceObject->DriverObject);
if (!Entry) { return(STATUS_INSUFFICIENT_RESOURCES); }
Entry->NextRequest = NULL;
// Insert Cell into interlocked list
ExInterlockedPushEntrySList( &(fdoExtension->WmiFreeMiniPortRequestList), (PSLIST_ENTRY)Entry, &(fdoExtension->WmiFreeMiniPortRequestLock));
// Increment the value of the free count
InterlockedIncrement(&(fdoExtension->WmiFreeMiniPortRequestCount));
return(STATUS_SUCCESS); }
PWMI_MINIPORT_REQUEST_ITEM SpWmiPopFreeRequestItem( IN PADAPTER_EXTENSION fdoExtension ) /*++
Routine Description:
Pops an Entry from the interlocked SLIST. (Of Free items)
Arguments:
fdoExtension - The extension on the adapter
Return Value:
A pointer to a REQUEST_ITEM or NULL if none are available
Notes:
This code cannot be paged, it will be called a DIRLQL
--*/ { PWMI_MINIPORT_REQUEST_ITEM requestItem;
if (!fdoExtension->WmiFreeMiniPortRequestInitialized) { return (NULL); }
// Pop Cell from interlocked list
requestItem = (PWMI_MINIPORT_REQUEST_ITEM) ExInterlockedPopEntrySList( &(fdoExtension->WmiFreeMiniPortRequestList), &(fdoExtension->WmiFreeMiniPortRequestLock));
if (requestItem) { // Decrement the count of free cells
InterlockedDecrement(&(fdoExtension->WmiFreeMiniPortRequestCount));
}
return (requestItem); }
BOOLEAN SpWmiRemoveFreeMiniPortRequestItems( IN PADAPTER_EXTENSION fdoExtension )
/*++
Routine Description:
This function removes WMI_MINIPORT_REQUEST_ITEM structures from the "free" queue of the adapter extension.
It removed all the free cells.
Arguments:
fdoExtension - The device_extension
Return Value:
TRUE always.
--*/
{ PWMI_MINIPORT_REQUEST_ITEM tmpRequestItem; PWMI_MINIPORT_REQUEST_ITEM wmiRequestItem;
//
// Set the watermark to 0
// No need to grab a lock we're just setting it
fdoExtension->WmiFreeMiniPortRequestWatermark = 0;
DebugPrint((SP_WMI_EVENT, "SpWmiRemoveFreeMiniPortRequestItems: Removing %p", fdoExtension));
//
// Walk the queue of items and de-allocate as many as we need to.
//
for (;;) { // Pop
wmiRequestItem = SpWmiPopFreeRequestItem(fdoExtension); if (wmiRequestItem == NULL) { break; } else { ExFreePool(wmiRequestItem); } }
return TRUE; }
const GUID GUID_NULL = { 0 };
BOOLEAN SpAdapterConfiguredForSenseDataEvents( IN PDEVICE_OBJECT DeviceObject, OUT GUID *SenseDataClass )
/*++
Routine Description:
This function answers whether a specified device is configured to generate sense data events. This is determined by the presense of a string value containing the GUID for the event class responsible for generating the events.
Arguments:
DeviceObject - Points to the device object SenseDataClass - Points to a GUID into which the sense data class, if found, is copied. If none is found, GUID_NULL is copied into the location. If the function's return value is FALSE, SenseDataClass will be set to GUID_NULL.
Return Value:
Answers TRUE if a GUID is registed for the device. Otherwise, returns FALSE.
--*/
{ NTSTATUS status; PADAPTER_EXTENSION adapterExtension = DeviceObject->DeviceExtension; HANDLE instanceHandle = NULL; HANDLE handle = NULL; RTL_QUERY_REGISTRY_TABLE queryTable[2]; UNICODE_STRING unicodeString; UNICODE_STRING stringValue; OBJECT_ATTRIBUTES objectAttributes;
//
// Initialize the guid pointed to by SenseDataClass to GUID_NULL.
//
*SenseDataClass = GUID_NULL;
//
// If this isn't a pnp device, don't attempt to determine
// if it supports sense data events. Just return FALSE.
//
if (!adapterExtension->IsPnp) {
return FALSE;
}
//
// Open the device registry key.
//
status = IoOpenDeviceRegistryKey(adapterExtension->LowerPdo, PLUGPLAY_REGKEY_DEVICE, KEY_ALL_ACCESS, &instanceHandle); if (!NT_SUCCESS(status)) { return FALSE; }
//
// Open the scsiport subkey under the device's Device Parameters key.
//
RtlInitUnicodeString(&unicodeString, L"Scsiport"); InitializeObjectAttributes( &objectAttributes, &unicodeString, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, instanceHandle, NULL);
status = ZwOpenKey(&handle, KEY_READ, &objectAttributes);
if (!NT_SUCCESS(status)) { goto cleanup; }
//
// Read the device's sense data class guid. We have to initialize the
// maximum size of the string and init the buffer to NULL so
// RtlQueryRegistryValues will allocate a buffer for us. If the specified
// value is not in the registry, the query will fail
//
stringValue.MaximumLength = 40; stringValue.Buffer = NULL; RtlZeroMemory(queryTable, sizeof(queryTable));
queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; queryTable[0].Name = L"SenseDataEventClass"; queryTable[0].EntryContext = &stringValue;
status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE | RTL_REGISTRY_OPTIONAL, (PWSTR) handle, queryTable, NULL, NULL); if (!NT_SUCCESS(status)) { goto cleanup; } //
// Convert the registry string to a GUID.
//
ASSERT(stringValue.Buffer); status = RtlGUIDFromString(&stringValue, SenseDataClass); ExFreePool(stringValue.Buffer);
cleanup:
if(handle != NULL) { ZwClose(handle); }
ASSERT(instanceHandle != NULL); ZwClose(instanceHandle);
return (NT_SUCCESS(status)) ? TRUE : FALSE; } NTSTATUS SpInitAdapterWmiRegInfo( IN PDEVICE_OBJECT DeviceObject )
/*++
Routine Description:
This function initializes a the WMIREGINFO structure pointed to by the specified device's extension. This structure will be used later to register scsiport to handle WMI IRPs on behalf of the device.
Arguments:
DeviceObject - The device object Return Value:
STATUS_SUCCESS STATUS_INSUFFICIENT_RESOURCES
--*/
{ ULONG TotalSize; PWMIREGINFO TempInfo; PWCHAR TempString; ULONG OffsetToRegPath; ULONG OffsetToRsrcName; PADAPTER_EXTENSION adapterExtension = DeviceObject->DeviceExtension; PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
//
// The registry path name follows the WMIREGINFO struct and the
// contiguous array of WMIREGGUIDW structs.
//
OffsetToRegPath = sizeof(WMIREGINFO) + sizeof(WMIREGGUIDW);
//
// The name of the resource follows the registry path name and
// its size.
//
OffsetToRsrcName = OffsetToRegPath + sizeof(WCHAR) + sizeof(SPMOFREGISTRYPATH);
//
// The total size of the block of memory we need to allocate is the size
// of the WMIREGINFO struct, plus the size of however many WMIREGGUIDW
// structs we need, plus the size of the registry path and and resource
// name strings. The size is aligned on an 8 byte boundary.
//
TotalSize = OffsetToRsrcName + sizeof(WCHAR) + sizeof(SPMOFRESOURCENAME); TotalSize = (TotalSize + 7) & ~7;
//
// Try to allocate the memory.
//
TempInfo = SpAllocatePool(NonPagedPool, TotalSize, SCSIPORT_TAG_WMI_EVENT, DeviceObject->DriverObject);
if (TempInfo == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
//
// Initialize the WMIREGINFO struct.
//
TempInfo->BufferSize = TotalSize; TempInfo->NextWmiRegInfo = 0; TempInfo->RegistryPath = OffsetToRegPath; TempInfo->MofResourceName = OffsetToRsrcName;
TempString = (PWCHAR)((ULONG_PTR)TempInfo + OffsetToRegPath); *TempString++ = sizeof(SPMOFREGISTRYPATH); RtlCopyMemory(TempString, SPMOFREGISTRYPATH, sizeof(SPMOFREGISTRYPATH));
TempString = (PWCHAR)((ULONG_PTR)TempInfo + OffsetToRsrcName); *TempString++ = sizeof(SPMOFRESOURCENAME); RtlCopyMemory(TempString, SPMOFRESOURCENAME, sizeof(SPMOFRESOURCENAME));
TempInfo->GuidCount = 1;
TempInfo->WmiRegGuid[0].Guid = adapterExtension->SenseDataEventClass; TempInfo->WmiRegGuid[0].Flags = WMIREG_FLAG_INSTANCE_PDO | WMIREG_FLAG_EVENT_ONLY_GUID; TempInfo->WmiRegGuid[0].InstanceCount = 1;
//
// This must be a physical device object.
//
TempInfo->WmiRegGuid[0].Pdo = (ULONG_PTR) adapterExtension->LowerPdo;
//
// Update the common extension members.
//
commonExtension->WmiScsiPortRegInfoBuf = TempInfo; commonExtension->WmiScsiPortRegInfoBufSize = TotalSize;
DebugPrint((SP_WMI_EVENT, "SpInitAdapterWmiRegInfo: commonExtension %p " "WmiScsiPortRegInfoBuf %p WmiScsiPortRegInfoBufSize %x\n", commonExtension, commonExtension->WmiScsiPortRegInfoBuf, commonExtension->WmiScsiPortRegInfoBufSize));
return STATUS_SUCCESS; }
|