1 /*++
2
3 Copyright (C) Microsoft Corporation. All rights reserved.
4
5 Module Name:
6
7 zpodd.c
8
9 Abstract:
10
11 Code for Zero Power ODD support.
12
13 Environment:
14
15 kernel mode only
16
17 Notes:
18
19
20 Revision History:
21
22 --*/
23
24 #include "ntddk.h"
25 #include "ntddstor.h"
26 #include "wdmguid.h"
27 #include "cdrom.h"
28 #include "mmc.h"
29 #include "ioctl.h"
30 #include "scratch.h"
31
32 #ifdef DEBUG_USE_WPP
33 #include "zpodd.tmh"
34 #endif
35
36 _IRQL_requires_max_(PASSIVE_LEVEL)
37 ULONG
38 DeviceGetZPODDEnabledFromRegistry();
39
40 _IRQL_requires_max_(PASSIVE_LEVEL)
41 NTSTATUS
42 DeviceQueryD3ColdInterface(
43 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
44 _Out_ PD3COLD_SUPPORT_INTERFACE D3ColdInterface
45 );
46
47 _IRQL_requires_max_(PASSIVE_LEVEL)
48 NTSTATUS
49 DeviceSendEnableIdlePowerIoctl(
50 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
51 _In_ BOOLEAN WakeCapable,
52 _In_ BOOLEAN Enable,
53 _In_ ULONG D3IdleTimeout
54 );
55
56 #if ALLOC_PRAGMA
57
58 #pragma alloc_text(PAGE, DeviceInitializeZPODD)
59 #pragma alloc_text(PAGE, DeviceGetZPODDEnabledFromRegistry)
60 #pragma alloc_text(PAGE, DeviceQueryD3ColdInterface)
61 #pragma alloc_text(PAGE, DeviceSendEnableIdlePowerIoctl)
62 #pragma alloc_text(PAGE, DeviceReleaseZPODDResources)
63 #pragma alloc_text(PAGE, DeviceZPODDIsInHomePosition)
64 #pragma alloc_text(PAGE, DeviceMarkActive)
65
66 #endif
67
68 #pragma warning(push)
69 #pragma warning(disable:4152) // nonstandard extension, function/data pointer conversion in expression
70 #pragma warning(disable:26000) // read overflow reported because of pointer type conversion
71
_IRQL_requires_max_(PASSIVE_LEVEL)72 _IRQL_requires_max_(PASSIVE_LEVEL)
73 NTSTATUS
74 DeviceInitializeZPODD(
75 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
76 )
77 /*++
78
79 Routine Description:
80
81 This routine initialize the contents of ZPODD structure.
82
83 Arguments:
84
85 DeviceExtension - the device extension
86
87 Return Value:
88 NTSTATUS
89
90 --*/
91 {
92 NTSTATUS status = STATUS_SUCCESS;
93 NTSTATUS tempStatus = STATUS_SUCCESS;
94 PZERO_POWER_ODD_INFO zpoddInfo = NULL;
95 PFEATURE_DATA_REMOVABLE_MEDIUM removableMediumHeader = NULL;
96 ULONG ZPODDEnabledInRegistry = 0;
97 PD3COLD_SUPPORT_INTERFACE d3ColdInterface = NULL;
98 DEVICE_WAKE_DEPTH deepestWakeableDstate = DeviceWakeDepthNotWakeable;
99 BOOLEAN inHomePosition = FALSE;
100
101 PAGED_CODE();
102
103 if (DeviceExtension->ZeroPowerODDInfo != NULL)
104 {
105 //
106 // Already initialized.
107 //
108
109 goto Cleanup;
110 }
111
112 ZPODDEnabledInRegistry = DeviceGetZPODDEnabledFromRegistry();
113
114 if (ZPODDEnabledInRegistry == 0)
115 {
116 //
117 // User has explicitly disabled Zero Power ODD.
118 //
119
120 status = STATUS_NOT_SUPPORTED;
121
122 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
123 "DeviceInitializeZPODD: ZPODD not enabled due to registry settings.\n"
124 ));
125
126 goto Cleanup;
127 }
128
129 zpoddInfo = ExAllocatePoolWithTag(NonPagedPoolNx,
130 sizeof(ZERO_POWER_ODD_INFO),
131 CDROM_TAG_ZERO_POWER_ODD);
132
133 if (zpoddInfo == NULL)
134 {
135 status = STATUS_INSUFFICIENT_RESOURCES;
136
137 goto Cleanup;
138 }
139
140 RtlZeroMemory(zpoddInfo, sizeof (ZERO_POWER_ODD_INFO));
141
142 //
143 // Check the system for the following prerequisites:
144 //
145 // 1. SATA: Device Attention line
146 // 2. SATA: Asynchronous Notification
147 // 3. ODD: LoChange / MediaRemoval
148 // 4. ACPI: Wake capable
149 //
150 // Only drawer and slot loading types have well defined behaviors in the spec, so only these two
151 // types are supported.
152 //
153
154 //
155 // Check for DA & AN
156 //
157
158 if ((DeviceExtension->PowerDescriptor == NULL) ||
159 (DeviceExtension->PowerDescriptor->DeviceAttentionSupported == FALSE) ||
160 (DeviceExtension->PowerDescriptor->AsynchronousNotificationSupported == FALSE))
161 {
162 status = STATUS_NOT_SUPPORTED;
163
164 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
165 "DeviceInitializeZPODD: ZPODD not enabled due to SATA features not present.\n"
166 ));
167
168 goto Cleanup;
169 }
170
171 //
172 // Check for LoChange / MediaRemoval
173 //
174
175 removableMediumHeader = (PFEATURE_DATA_REMOVABLE_MEDIUM)
176 DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer,
177 DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize,
178 FeatureRemovableMedium);
179
180 if ((removableMediumHeader == NULL) ||
181 (!((removableMediumHeader->LoadingMechanism == LOADING_MECHANISM_TRAY) && (removableMediumHeader->Load == 0) && // Drawer ...
182 (removableMediumHeader->DBML != FALSE)) && // requires LoChange/NotBusy
183 !((removableMediumHeader->LoadingMechanism == LOADING_MECHANISM_CADDY) && (removableMediumHeader->Load == 0) && // Slot ...
184 (DeviceExtension->MediaChangeDetectionInfo->Gesn.Supported != FALSE)))) // requires MediaRemoval
185 {
186 status = STATUS_NOT_SUPPORTED;
187
188 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
189 "DeviceInitializeZPODD: ZPODD not enabled due to ODD features not present.\n"
190 ));
191
192 goto Cleanup;
193 }
194
195 zpoddInfo->LoadingMechanism = removableMediumHeader->LoadingMechanism;
196 zpoddInfo->Load = removableMediumHeader->Load;
197
198 //
199 // Check for ACPI
200 //
201
202 status = DeviceQueryD3ColdInterface(DeviceExtension, &zpoddInfo->D3ColdInterface);
203
204 if (!NT_SUCCESS(status))
205 {
206 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
207 "DeviceInitializeZPODD: Query D3Cold support interface failed.\n"
208 ));
209
210 goto Cleanup;
211 }
212
213 //
214 // If the platform supports Zero Power ODD, the following conditions must be met:
215 //
216 // 1. The deepest wakeable D-state for the device is D3Cold;
217 // 2. The platform supports D3Cold for the device.
218 //
219
220 d3ColdInterface = &zpoddInfo->D3ColdInterface;
221
222 status = d3ColdInterface->GetIdleWakeInfo(d3ColdInterface->Context,
223 PowerSystemWorking,
224 &deepestWakeableDstate);
225
226 if (!NT_SUCCESS(status))
227 {
228 goto Cleanup;
229 }
230
231 //
232 // DeviceExtension->PowerDescriptor->D3ColdSupported is retrieved from lower layer.
233 // It has more accurate supportive information than just uses d3ColdInterface->GetD3ColdCapability
234 //
235 if ((deepestWakeableDstate != DeviceWakeDepthD3cold) ||
236 (DeviceExtension->PowerDescriptor->D3ColdSupported == FALSE))
237 {
238 status = STATUS_NOT_SUPPORTED;
239
240 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
241 "DeviceInitializeZPODD: ZPODD not enabled due to ACPI support not present.\n"
242 ));
243
244 goto Cleanup;
245 }
246
247 //
248 // The system meets all requirements. Go ahead and enable ZPODD.
249 //
250
251 //
252 // Register with the runtime power framework.
253 // Note that no un-registration is needed during tear-down.
254 // D3Cold will be enabled (success case of following call) or disabled by port driver during processing Enable Idle Power IOCTL.
255 //
256
257 status = DeviceSendEnableIdlePowerIoctl(DeviceExtension, TRUE, TRUE, DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS);
258
259 if (!NT_SUCCESS(status))
260 {
261 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
262 "DeviceInitializeZPODD: ZPODD not enabled due to runtime power framework.\n"
263 ));
264
265 goto Cleanup;
266 }
267
268 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
269 "DeviceInitializeZPODD: ZPODD is enabled.\n"
270 ));
271
272 DeviceExtension->ZeroPowerODDInfo = zpoddInfo;
273
274 //
275 // If device is not in home position, then we should take an active reference here
276 // to prevent it from being powered off.
277 //
278
279 inHomePosition = DeviceZPODDIsInHomePosition(DeviceExtension);
280
281 if (inHomePosition == FALSE)
282 {
283 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
284 "DeviceInitializeZPODD: not ready to power off, device marked as active\n"));
285
286 DeviceMarkActive(DeviceExtension, TRUE, FALSE);
287 }
288 else
289 {
290 //
291 // cache get configuration response.
292 // failing is not critical, so we don't want to check for status here.
293 //
294
295 if (zpoddInfo->GetConfigurationBuffer == NULL)
296 {
297 tempStatus = DeviceGetConfigurationWithAlloc(DeviceExtension->Device,
298 &zpoddInfo->GetConfigurationBuffer,
299 &zpoddInfo->GetConfigurationBufferSize,
300 FeatureProfileList,
301 SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
302
303 UNREFERENCED_PARAMETER(tempStatus); // Avoid PREFAST warning.
304 }
305 }
306
307 Cleanup:
308
309 if (!NT_SUCCESS(status))
310 {
311 //
312 // We register always even in non-ZPODD case, per request from storport.
313 //
314
315 tempStatus = DeviceSendEnableIdlePowerIoctl(DeviceExtension, FALSE, FALSE, DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS);
316
317 if (NT_SUCCESS(tempStatus))
318 {
319 //
320 // Mark the device active; this reference will never be released unless the system enters a
321 // low power state.
322 //
323
324 DeviceMarkActive(DeviceExtension, TRUE, FALSE);
325 }
326
327 FREE_POOL(zpoddInfo);
328 }
329
330 //
331 // If Zero Power ODD is not supported, we should not block the device init sequence.
332 //
333
334 return STATUS_SUCCESS;
335 }
336
_IRQL_requires_max_(PASSIVE_LEVEL)337 _IRQL_requires_max_(PASSIVE_LEVEL)
338 ULONG
339 DeviceGetZPODDEnabledFromRegistry()
340 /*++
341
342 Routine Description:
343
344 Get the ZeroPowerODDEnabled value from registry, which dictates if Zero Power ODD
345 should be enabled or not. If the value is not in registry, by default Zero
346 Power ODD is enabled.
347
348 Arguments:
349
350 None
351
352 Return Value:
353
354 ULONG
355
356 --*/
357 {
358 NTSTATUS status = STATUS_SUCCESS;
359 WDFKEY registryKey = NULL;
360 ULONG ZPODDEnabled = 0;
361
362 DECLARE_CONST_UNICODE_STRING(registryValueName, L"ZeroPowerODDEnabled");
363
364 PAGED_CODE();
365
366 //
367 // open the Parameters key under the service key.
368 //
369
370 status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(),
371 KEY_READ,
372 WDF_NO_OBJECT_ATTRIBUTES,
373 ®istryKey);
374
375 if (NT_SUCCESS(status))
376 {
377 status = WdfRegistryQueryULong(registryKey,
378 ®istryValueName,
379 &ZPODDEnabled);
380
381 WdfRegistryClose(registryKey);
382 }
383
384 if (!NT_SUCCESS(status))
385 {
386 //
387 // By default, Zero Power ODD is enabled
388 //
389
390 ZPODDEnabled = 1;
391 }
392
393 return ZPODDEnabled;
394 }
395
_IRQL_requires_max_(PASSIVE_LEVEL)396 _IRQL_requires_max_(PASSIVE_LEVEL)
397 NTSTATUS
398 DeviceQueryD3ColdInterface(
399 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
400 _Out_ PD3COLD_SUPPORT_INTERFACE D3ColdInterface
401 )
402 /*++
403
404 Routine Description:
405
406 Queries ACPI for the D3Cold support interface.
407
408 Arguments:
409
410 DeviceExtension - the device extension
411 D3ColdInterface - output buffer receiving the interface
412
413 Return Value:
414
415 NTSTATUS
416
417 --*/
418 {
419 PIRP irp = NULL;
420 KEVENT event;
421 NTSTATUS status = STATUS_SUCCESS;
422 PDEVICE_OBJECT targetDevice = NULL;
423 IO_STATUS_BLOCK ioStatus = {0};
424 PIO_STACK_LOCATION irpStack = NULL;
425
426 PAGED_CODE();
427
428 RtlZeroMemory(D3ColdInterface, sizeof(D3COLD_SUPPORT_INTERFACE));
429
430 //
431 // Query D3COLD support interface synchronously
432 //
433
434 KeInitializeEvent(&event, NotificationEvent, FALSE);
435
436 targetDevice = IoGetAttachedDeviceReference(DeviceExtension->DeviceObject);
437
438 irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
439 targetDevice,
440 NULL,
441 0,
442 0,
443 &event,
444 &ioStatus);
445
446 if (irp == NULL)
447 {
448 status = STATUS_INSUFFICIENT_RESOURCES;
449
450 goto Cleanup;
451 }
452
453 irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
454 irp->IoStatus.Information = 0;
455
456 irpStack = IoGetNextIrpStackLocation(irp);
457 irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
458 irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_D3COLD_SUPPORT_INTERFACE;
459 irpStack->Parameters.QueryInterface.Size = sizeof (D3COLD_SUPPORT_INTERFACE);
460 irpStack->Parameters.QueryInterface.Version = D3COLD_SUPPORT_INTERFACE_VERSION;
461 irpStack->Parameters.QueryInterface.Interface = (PINTERFACE) D3ColdInterface;
462 irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
463
464 status = IoCallDriver(targetDevice, irp);
465
466 if (status == STATUS_PENDING)
467 {
468 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
469
470 status = ioStatus.Status;
471 }
472
473 if (!NT_SUCCESS(status))
474 {
475 goto Cleanup;
476 }
477
478 NT_ASSERT(D3ColdInterface->SetD3ColdSupport != NULL);
479 NT_ASSERT(D3ColdInterface->GetIdleWakeInfo != NULL);
480 NT_ASSERT(D3ColdInterface->GetD3ColdCapability != NULL);
481
482 Cleanup:
483
484 ObDereferenceObject(targetDevice);
485
486 return status;
487 }
488
_IRQL_requires_max_(PASSIVE_LEVEL)489 _IRQL_requires_max_(PASSIVE_LEVEL)
490 NTSTATUS
491 DeviceSendEnableIdlePowerIoctl(
492 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
493 _In_ BOOLEAN WakeCapable,
494 _In_ BOOLEAN Enable,
495 _In_ ULONG D3IdleTimeout
496 )
497 /*++
498
499 Routine Description:
500
501 Enables idle power support.
502
503 Arguments:
504
505 DeviceExtension - the device extension
506 WakeCapable - whether the device is wake capable
507 Enable - enable / disable idle power management
508
509 Return Value:
510
511 NTSTATUS
512
513 --*/
514 {
515 NTSTATUS status = STATUS_SUCCESS;
516 STORAGE_IDLE_POWER idlePower = {0};
517 IO_STATUS_BLOCK ioStatus = {0};
518 PIRP irp = NULL;
519 KEVENT event;
520
521 PAGED_CODE();
522
523 idlePower.Version = 1;
524 idlePower.Size = sizeof (STORAGE_IDLE_POWER);
525 idlePower.WakeCapableHint = WakeCapable;
526 idlePower.D3ColdSupported = Enable;
527 idlePower.D3IdleTimeout = D3IdleTimeout;
528
529 KeInitializeEvent(&event, NotificationEvent, FALSE);
530
531 irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_ENABLE_IDLE_POWER,
532 DeviceExtension->LowerPdo,
533 &idlePower,
534 sizeof(STORAGE_IDLE_POWER),
535 NULL,
536 0,
537 FALSE,
538 &event,
539 &ioStatus);
540
541 if (irp == NULL)
542 {
543 status = STATUS_INSUFFICIENT_RESOURCES;
544 }
545 else
546 {
547 //
548 // Send the synchronous request to port driver.
549 //
550
551 status = IoCallDriver(DeviceExtension->LowerPdo, irp);
552
553 if (status == STATUS_PENDING)
554 {
555 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
556
557 status = ioStatus.Status;
558 }
559 }
560
561 TracePrint((TRACE_LEVEL_INFORMATION,
562 TRACE_FLAG_POWER,
563 "DeviceSendEnableIdlePowerIoctl: Port driver returned status (%x) for FDO (%p)\n"
564 "\tD3ColdSupported: %u\n"
565 "\tD3IdleTimeout: %u (ms)",
566 status,
567 DeviceExtension->DeviceObject,
568 Enable,
569 DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS));
570
571 return status;
572 }
573
_IRQL_requires_max_(APC_LEVEL)574 _IRQL_requires_max_(APC_LEVEL)
575 VOID
576 DeviceReleaseZPODDResources(
577 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
578 )
579 /*++
580
581 Routine Description:
582
583 This routine will cleanup any resources allocated for ZPODD.
584
585 Arguments:
586
587 DeviceExtension - the device context
588
589 Return Value:
590 None.
591
592 --*/
593 {
594 PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo;
595
596 PAGED_CODE()
597
598 if (zpoddInfo != NULL)
599 {
600 FREE_POOL(zpoddInfo->GetConfigurationBuffer);
601 FREE_POOL(zpoddInfo);
602 }
603
604 return;
605 }
606
607 NTSTATUS
DeviceZPODDGetPowerupReason(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,_Out_ PSTORAGE_IDLE_POWERUP_REASON PowerupReason)608 DeviceZPODDGetPowerupReason(
609 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
610 _Out_ PSTORAGE_IDLE_POWERUP_REASON PowerupReason
611 )
612 /*++
613
614 Routine Description:
615
616 This routine queries the port driver for what caused the power up.
617
618 Arguments:
619
620 DeviceExtension - device extension.
621 PowerupReason - what caused the power up.
622
623 Return Value:
624 NTSTATUS
625
626 --*/
627 {
628 NTSTATUS status = STATUS_SUCCESS;
629 PIRP irp = NULL;
630 IO_STATUS_BLOCK ioStatus = {0};
631 KEVENT event;
632
633 RtlZeroMemory(PowerupReason, sizeof (STORAGE_IDLE_POWERUP_REASON));
634
635 PowerupReason->Size = sizeof (STORAGE_IDLE_POWERUP_REASON);
636 PowerupReason->Version = STORAGE_IDLE_POWERUP_REASON_VERSION_V1;
637
638 //
639 // Setup a synchronous irp.
640 //
641
642 KeInitializeEvent(&event, NotificationEvent, FALSE);
643
644 irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_IDLE_POWERUP_REASON,
645 DeviceExtension->LowerPdo,
646 PowerupReason,
647 sizeof (STORAGE_IDLE_POWERUP_REASON),
648 PowerupReason,
649 sizeof (STORAGE_IDLE_POWERUP_REASON),
650 FALSE,
651 &event,
652 &ioStatus);
653
654 if (irp == NULL)
655 {
656 status = STATUS_INSUFFICIENT_RESOURCES;
657 }
658 else
659 {
660 //
661 // Send the synchronous request to port driver.
662 //
663
664 status = IoCallDriver(DeviceExtension->LowerPdo, irp);
665
666 if (status == STATUS_PENDING)
667 {
668 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
669
670 status = ioStatus.Status;
671 }
672 }
673
674 return status;
675 }
676
_IRQL_requires_max_(PASSIVE_LEVEL)677 _IRQL_requires_max_(PASSIVE_LEVEL)
678 BOOLEAN
679 DeviceZPODDIsInHomePosition(
680 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
681 )
682 /*++
683
684 Routine Description:
685
686 Checks to see if the device is ready to be powered off.
687 Requirements are: 1. tray closed 2. no media present.
688
689 Arguments:
690
691 DeviceExtension - device extension.
692
693 Return Value:
694 BOOLEAN
695
696 --*/
697 {
698 NTSTATUS status = STATUS_SUCCESS;
699 PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo;
700 SCSI_REQUEST_BLOCK srb = {0};
701 PCDB cdb = (PCDB) srb.Cdb;
702 BOOLEAN inHomePosition = FALSE;
703
704 PAGED_CODE();
705
706 if (zpoddInfo != NULL)
707 {
708 //
709 // Clear sense data.
710 //
711
712 zpoddInfo->SenseKey = 0;
713 zpoddInfo->AdditionalSenseCode = 0;
714 zpoddInfo->AdditionalSenseCodeQualifier = 0;
715
716 //
717 // Send a Test Unit Ready to check media & tray status.
718 //
719
720 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
721
722 srb.CdbLength = 6;
723 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
724
725 srb.TimeOutValue = CDROM_TEST_UNIT_READY_TIMEOUT;
726
727 status = DeviceSendSrbSynchronously(DeviceExtension->Device,
728 &srb,
729 NULL,
730 0,
731 FALSE,
732 NULL);
733
734 #ifdef __REACTOS__
735 if (!NT_SUCCESS(status))
736 {
737 return FALSE;
738 }
739 #endif
740
741 //
742 // At this time, sense data, if available, is already copied into zpoddInfo.
743 //
744 // We don't check for status because we expect it to fail in case there is no media in device.
745 //
746 // Should enter Zero Power state if:
747 //
748 // Drawer: 02/3A/01
749 // Slot: 02/3A/xx
750 //
751
752 if (((zpoddInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) && (zpoddInfo->Load == 0) && // Drawer
753 (zpoddInfo->SenseKey == SCSI_SENSE_NOT_READY) &&
754 (zpoddInfo->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE) &&
755 (zpoddInfo->AdditionalSenseCodeQualifier == 0x01)) ||
756 ((zpoddInfo->LoadingMechanism == LOADING_MECHANISM_CADDY) && (zpoddInfo->Load == 0) && // Slot
757 (zpoddInfo->SenseKey == SCSI_SENSE_NOT_READY) &&
758 (zpoddInfo->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)))
759 {
760 inHomePosition = TRUE;
761 }
762 }
763
764 return inHomePosition;
765 }
766
_IRQL_requires_max_(PASSIVE_LEVEL)767 _IRQL_requires_max_(PASSIVE_LEVEL)
768 VOID
769 DeviceMarkActive(
770 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
771 _In_ BOOLEAN IsActive,
772 _In_ BOOLEAN SetIdleTimeout
773 )
774 /*++
775
776 Routine Description:
777
778 This routine will mark the device as active / idle.
779
780 Arguments:
781
782 DeviceExtension - the device context
783 IsActive - if the device should be marked as active
784
785 Return Value:
786 None.
787
788 --*/
789 {
790 NTSTATUS status = STATUS_SUCCESS;
791 PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo;
792
793 PAGED_CODE()
794
795 if (DeviceExtension->IsActive != IsActive)
796 {
797 if ((IsActive == FALSE) && (zpoddInfo != NULL))
798 {
799 // cache get configuration response.
800 // failing is not critical, so we don't want to check for status here.
801 if (zpoddInfo->GetConfigurationBuffer == NULL)
802 {
803 (VOID)DeviceGetConfigurationWithAlloc(DeviceExtension->Device,
804 &zpoddInfo->GetConfigurationBuffer,
805 &zpoddInfo->GetConfigurationBufferSize,
806 FeatureProfileList,
807 SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
808 }
809 }
810
811 if (SetIdleTimeout)
812 {
813 status = DeviceSendEnableIdlePowerIoctl(DeviceExtension,
814 FALSE,
815 FALSE,
816 IsActive ? DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS : DELAY_TIME_TO_ENTER_AOAC_IDLE_POWER_IN_MS);
817 }
818
819 if (NT_SUCCESS(status))
820 {
821 DeviceSendIoctlAsynchronously(DeviceExtension,
822 IsActive ? IOCTL_STORAGE_POWER_ACTIVE : IOCTL_STORAGE_POWER_IDLE,
823 DeviceExtension->LowerPdo);
824 }
825
826 DeviceExtension->IsActive = IsActive;
827 }
828 }
829
830 #pragma warning(pop) // un-sets any local warning changes
831
832
833