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.
1864 lines
55 KiB
1864 lines
55 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|