We are working on a SCSI STORPORT driver for Windows 8 (and others if it really matters but this discussion is being limited to Win8).
The driver implements RAID support utilizing the motherboard AHCI controller.
We are attempting to implement power control for an optical device - ZPODD to be exact.
For reasons I won’t go into here we are doing this via method calls to ACPI. [This as opposed to utilizing WIN8 PoFxDevice support… Leave it that we have a support ticket open with Microsoft to work that aspect that remains unresolved after several months.]
The driver can successfully control the power to the ODD by invoking the appropriate _PS0 and _PS3 methods but this assumes that the driver makes the decision to turn power off or on.
Our problem is that when the user attempts to wake the device (by pressing the eject button on the front), we have been unsuccessful in getting any notification from ACPI. [The driver needs to receive a notification that the user wishes to power on the device and then the driver needs to invoke the _PS0 method to actually power on the ODD.]
Using windbg, we can step through the code and verify that the call to RegisterForDeviceNotifications() is returning a status of SUCCESS, and that ACPI is posting a NOTIFY for the press of the eject button.
The callback function (RC_HandleAcpiNotification()) is never called and I’m not sure where to go from here…
Any pointers or helpful knowledge would be greatly appreciated.
Thanks.
-Joe Thomas
I’ve include relevant code, as well as trace messages from windbg and my observations of trying to step through the ACPI code…
For complete information, the PCI VID is 1022, DID is 7805, and device class/subclass is 0104 (Mass Storage, SCSI Controller). [The thought at Microsoft is that there may be problems with the PoFxDevice support and ACPI when the device subclass does NOT equal 06 (SATA Controller) so the fact that the subclass is different may be pertinent.]
We currently register for ACPI notifications as follows:
VOID
RC_HandleAcpiNotification(
PVOID Context,
ULONG Code
)
{
ULONG tmp;
tmp = Code;
//RC_HW_OS_DebugPrintf(“RC_HandleAcpiNotification(): Context = 0x%x, Code = 0x%x\n”,
// Context, Code);
}
ULONG
RC_RegisterForAcpiNotifications(
IN PVOID hwDevExt,
IN PVOID Pdo
)
{
ULONG status = STATUS_SUCCESS;
ACPI_INTERFACE_STANDARD AcpiInterfaces = { 0 };
if ((status = RC_GetAcpiInterfaces((PDEVICE_OBJECT) Pdo, &AcpiInterfaces)) == STATUS_SUCCESS)
{
if (AcpiInterfaces.RegisterForDeviceNotifications)
{
status = AcpiInterfaces.RegisterForDeviceNotifications(
(PDEVICE_OBJECT) AcpiInterfaces.Context,
RC_HandleAcpiNotification,
(PDEVICE_OBJECT) Pdo
);
}
}
return status;
}
BOOLEAN
HwInitialization(
IN PVOID HwDeviceExtension
)
{
PVOID adapterDeviceObject;
PVOID physicalDeviceObject;
PVOID lowerDeviceObject;
StorPortGetDeviceObjects(
HwDeviceExtension,
&adapterDeviceObject,
&physicalDeviceObject,
&lowerDeviceObject
);
(VOID) RC_RegisterForAcpiNotifications(
HwDeviceExtension,
lowerDeviceObject
);
}
Windbg shows the following when the button is pressed:
ACPIWriteGpeEnableRegister: Writing GPE Enable register 0 = 0
ACPIWriteGpeEnableRegister: Writing GPE Enable register 1 = 0
ACPIWriteGpeEnableRegister: Writing GPE Enable register 2 = 0
ACPIWriteGpeEnableRegister: Writing GPE Enable register 3 = 0
AMLI: FFFFFA8008228B00: AsyncEvalObject(_GPE._L06)
AMLI: FFFFFA8008228B00: _GPE._L06()
ACPIWriteGpeEnableRegister: Writing GPE Enable register 0 = 28
ACPIWriteGpeEnableRegister: Writing GPE Enable register 1 = 38
ACPIWriteGpeEnableRegister: Writing GPE Enable register 2 = 1
ACPIWriteGpeEnableRegister: Writing GPE Enable register 3 = 10
fffffa800880d1a1: {
fffffa800880d1a1: | If(LAnd(LNot(LEqual(ODZC=0x1,Zero)=0x0)=0xffffffff,LEqual(SB.PCI0.SMBS.GE16=0x0,Zero)=0xffffffff)=0xffffffff)
fffffa800880d1c1: | {
fffffa800880d1c1: | | If(SB.PCI0.SMBS.G06T=0x0)
fffffa800880d36e: | | {
fffffa800880d36e: | | | Sleep(0x14)
fffffa800880d372: | | | If(LNot(SB.PCI0.SMBS.GE06=0x0)=0xffffffff)
fffffa800880d389: | | | {
fffffa800880d389: | | | | If(LEqual(SB.PCI0.SATA.STCL
OpRegion Access on region FFFFFA800886E768 device FFFFFA800886E438
DeviceHandle 0000000000000000
Return from OR handler - status 0
OpRegion Access on region FFFFFA800886E768 device FFFFFA800886E438
DeviceHandle 0000000000000000
Return from OR handler - status 0
=0x104,0x101)=0x0)
fffffa800880d3a2: | | | | If(LEqual(SB.PCI0.SATA.STCL
OpRegion Access on region FFFFFA800886E768 device FFFFFA800886E438
DeviceHandle 0000000000000000
Return from OR handler - status 0
OpRegion Access on region FFFFFA800886E768 device FFFFFA800886E438
DeviceHandle 0000000000000000
Return from OR handler - status 0
=0x104,0x106)=0x0)
fffffa800880d3f4: | | | | If(LOr(LEqual(SB.PCI0.SATA.SDID
OpRegion Access on region FFFFFA800886E768 device FFFFFA800886E438
DeviceHandle 0000000000000000
Return from OR handler - status 0
OpRegion Access on region FFFFFA800886E768 device FFFFFA800886E438
DeviceHandle 0000000000000000
Return from OR handler - status 0
=0x7805,0x7803)=0x0,LEqual(SB.PCI0.SATA.SDID
OpRegion Access on region FFFFFA800886E768 device FFFFFA800886E438
DeviceHandle 0000000000000000
Return from OR handler - status 0
OpRegion Access on region FFFFFA800886E768 device FFFFFA800886E438
DeviceHandle 0000000000000000
Return from OR handler - status 0
=0x7805,0x7802)=0x0)=0x0)
fffffa800880d45e: | | | | If(LEqual(SB.PCI0.SATA.SDID
OpRegion Access on region FFFFFA800886E768 device FFFFFA800886E438
DeviceHandle 0000000000000000
Return from OR handler - status 0
OpRegion Access on region FFFFFA800886E768 device FFFFFA800886E438
DeviceHandle 0000000000000000
Return from OR handler - status 0
=0x7805,0x7805)=0xffffffff)
fffffa800880d478: | | | | {
fffffa800880d478: | | | | | If(LNot(LLess(TPOS=0x60,0x60)=0x0)=0xffffffff)
fffffa800880d482: | | | | | {
fffffa800880d482: | | | | | | Notify(SB.PCI0.SATA.ODDZ,0x2)
ACPINotifyHandler: Notify on 88760c8 value 2, object type 6
FFFFFA8007F941E0 1ffff OSNotifyDeviceWake - 0xFFFFFA80088760C8 (ODDZ)
ACPIWriteGpeEnableRegister: Writing GPE Enable register 0 = 28
ACPIWriteGpeEnableRegister: Writing GPE Enable register 1 = 38
ACPIWriteGpeEnableRegister: Writing GPE Enable register 2 = 1
ACPIWriteGpeEnableRegister: Writing GPE Enable register 3 = 10
fffffa800880d498: | | | | | }
fffffa800880d4b0: | | | | }
fffffa800880d4b0: | | | | Sleep(0x1f4)
I’ve tried tracing through ACPI!ACPIRegisterForDeviceNotifications and the code is placing the callback address and context into a (unknown) table. I’m somewhat curious about the fact that this function “jmp”'s into ACPIRegisterForDeviceNotificationsByPowerInfo which then “ret”'s to the caller. To me, this implies that there is some type of PowerInfo structure and/or setting that might be required from the driver?
On the back end, the ACPI “Notify(_SB.PCI0.SATA.ODDZ,0x2)” generates a call to ACPI!Notify() which calls ACPI!NotifyHandler() which calls ACPI!OSNotifyDeviceWake() which calls ACPI!ACPIWakeRemoveDevicesAndUpdate(). ACPI!NotifyHandler() also calls ACPI!OSPowerFindPowerInfo() which again makes me question if there’s a power requirement we’re not aware of. Finally, ACPI!NotifyHandler() calls ACPI!DispatchNotification() before (eventually) returning to the caller.
Throughout this, I haven’t been able to discern where the checks are being made to see if my callback handler should be invoked, or if the check is being made at all.
// Joseph Thomas
// Principal Software Engineer
// Dot Hill Systems
// 2905 NorthWest Blvd., Suite 20
// Plymouth, MN 55441
// 763.226.2640