3 Copyright (C) Microsoft Corporation, 1991 - 1999
11 SCSI disk class driver - WMI support routines
26 DiskSendFailurePredictIoctl(
27 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
28 PSTORAGE_PREDICT_FAILURE checkFailure
33 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
38 DiskDetectFailurePrediction(
39 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
40 PFAILURE_PREDICTION_METHOD FailurePredictCapability
44 DiskReadFailurePredictThresholds(
45 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
46 PSTORAGE_FAILURE_PREDICT_THRESHOLDS DiskSmartThresholds
51 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
59 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
70 // WMI reregistration globals
72 // Since it will take too long to do a mode sense on some drive, we
73 // need a good way to effect the mode sense for the info exceptions
74 // mode page so that we can determine if SMART is supported and enabled
75 // for the drive. So the strategy is to do an asynchronous mode sense
76 // when the device starts and then look at the info exceptions mode
77 // page within the completion routine. Now within the completion
78 // routine we cannot call IoWMIRegistrationControl since we are at DPC
79 // level, so we create a stack of device objects that will be processed
80 // by a single work item that is fired off only when the stack
81 // transitions from empty to non empty.
83 WORK_QUEUE_ITEM DiskReregWorkItem
;
84 SINGLE_LIST_ENTRY DiskReregHead
;
85 KSPIN_LOCK DiskReregSpinlock
;
86 LONG DiskReregWorkItems
;
88 GUIDREGINFO DiskWmiFdoGuidList
[] =
91 WMI_DISK_GEOMETRY_GUID
,
97 WMI_STORAGE_FAILURE_PREDICT_STATUS_GUID
,
103 WMI_STORAGE_FAILURE_PREDICT_DATA_GUID
,
105 WMIREG_FLAG_EXPENSIVE
109 WMI_STORAGE_FAILURE_PREDICT_FUNCTION_GUID
,
111 WMIREG_FLAG_EXPENSIVE
115 WMI_STORAGE_PREDICT_FAILURE_EVENT_GUID
,
117 WMIREG_FLAG_EVENT_ONLY_GUID
121 WMI_STORAGE_FAILURE_PREDICT_THRESHOLDS_GUID
,
123 WMIREG_FLAG_EXPENSIVE
127 WMI_STORAGE_SCSI_INFO_EXCEPTIONS_GUID
,
136 GUID DiskPredictFailureEventGuid
= WMI_STORAGE_PREDICT_FAILURE_EVENT_GUID
;
138 #define DiskGeometryGuid 0
139 #define SmartStatusGuid 1
140 #define SmartDataGuid 2
141 #define SmartPerformFunction 3
142 #define AllowDisallowPerformanceHit 1
143 #define EnableDisableHardwareFailurePrediction 2
144 #define EnableDisableFailurePredictionPolling 3
145 #define GetFailurePredictionCapability 4
146 #define EnableOfflineDiags 5
148 #define SmartEventGuid 4
149 #define SmartThresholdsGuid 5
150 #define ScsiInfoExceptionsGuid 6
154 // Enable this to add WMI support for PDOs
155 GUIDREGINFO DiskWmiPdoGuidList
[] =
158 // {25007F51-57C2-11d1-A528-00A0C9062910}
159 { 0x25007f52, 0x57c2, 0x11d1,
160 { 0xa5, 0x28, 0x0, 0xa0, 0xc9, 0x6, 0x29, 0x10 } },
166 ULONG DiskDummyData
[4] = { 1, 2, 3, 4};
171 #pragma alloc_text(PAGE, DiskWmiFunctionControl)
172 #pragma alloc_text(PAGE, DiskFdoQueryWmiRegInfo)
173 #pragma alloc_text(PAGE, DiskFdoQueryWmiDataBlock)
174 #pragma alloc_text(PAGE, DiskFdoSetWmiDataBlock)
175 #pragma alloc_text(PAGE, DiskFdoSetWmiDataItem)
176 #pragma alloc_text(PAGE, DiskFdoExecuteWmiMethod)
178 #pragma alloc_text(PAGE, DiskDetectFailurePrediction)
179 #pragma alloc_text(PAGE, DiskEnableDisableFailurePrediction)
180 #pragma alloc_text(PAGE, DiskEnableDisableFailurePredictPolling)
181 #pragma alloc_text(PAGE, DiskReadFailurePredictStatus)
182 #pragma alloc_text(PAGE, DiskReadFailurePredictData)
183 #pragma alloc_text(PAGE, DiskReadFailurePredictThresholds)
184 #pragma alloc_text(PAGE, DiskGetIdentifyInfo)
185 #pragma alloc_text(PAGE, DiskReadSmartLog)
186 #pragma alloc_text(PAGE, DiskWriteSmartLog)
188 #pragma alloc_text(PAGE, DiskPerformSmartCommand)
190 #pragma alloc_text(PAGE, DiskSendFailurePredictIoctl)
192 #pragma alloc_text(PAGE, DiskReregWorker)
193 #pragma alloc_text(PAGE, DiskInitializeReregistration)
199 // SMART/IDE specific routines
202 // Read SMART data attributes.
203 // SrbControl should be sizeof(SRB_IO_CONTROL) +
204 // (sizeof(SENDCMDINPARAMS)-1) +
205 // READ_ATTRIBUTE_BUFFER_SIZE
206 // Attribute data returned at &SendCmdOutParams->bBuffer[0]
208 #define DiskReadSmartData(FdoExtension, \
211 DiskPerformSmartCommand(FdoExtension, \
212 IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS, \
222 // Read SMART data thresholds.
223 // SrbControl should be sizeof(SRB_IO_CONTROL) +
224 // (sizeof(SENDCMDINPARAMS)-1) +
225 // READ_THRESHOLD_BUFFER_SIZE
226 // Attribute data returned at &SendCmdOutParams->bBuffer[0]
228 #define DiskReadSmartThresholds(FdoExtension, \
231 DiskPerformSmartCommand(FdoExtension, \
232 IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS, \
243 // SrbControl should be sizeof(SRB_IO_CONTROL) +
244 // (sizeof(SENDCMDINPARAMS)-1) +
246 // Failure predicted if cmdOutParameters[3] == 0xf4 and [4] == 0x2c
248 #define DiskReadSmartStatus(FdoExtension, \
251 DiskPerformSmartCommand(FdoExtension, \
252 IOCTL_SCSI_MINIPORT_RETURN_STATUS, \
254 RETURN_SMART_STATUS, \
262 // Read disks IDENTIFY data
263 // SrbControl should be sizeof(SRB_IO_CONTROL) +
264 // (sizeof(SENDCMDINPARAMS)-1) +
265 // sizeof(IDENTIFY_BUFFER_SIZE)
266 // Identify data returned at &cmdOutParams.bBuffer[0]
268 #define DiskGetIdentifyData(FdoExtension, \
271 DiskPerformSmartCommand(FdoExtension, \
272 IOCTL_SCSI_MINIPORT_IDENTIFY, \
286 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
289 UCHAR srbControl
[sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
)];
290 ULONG bufferSize
= sizeof(srbControl
);
292 return DiskPerformSmartCommand(FdoExtension
,
293 IOCTL_SCSI_MINIPORT_ENABLE_SMART
,
298 (PSRB_IO_CONTROL
)srbControl
,
307 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
310 UCHAR srbControl
[sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
)];
311 ULONG bufferSize
= sizeof(srbControl
);
312 return DiskPerformSmartCommand(FdoExtension
,
313 IOCTL_SCSI_MINIPORT_DISABLE_SMART
,
318 (PSRB_IO_CONTROL
)srbControl
,
323 // Enable Attribute Autosave
326 DiskEnableSmartAttributeAutosave(
327 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
330 UCHAR srbControl
[sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
)];
331 ULONG bufferSize
= sizeof(srbControl
);
332 return DiskPerformSmartCommand(FdoExtension
,
333 IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
,
335 ENABLE_DISABLE_AUTOSAVE
,
338 (PSRB_IO_CONTROL
)srbControl
,
343 // Disable Attribute Autosave
346 DiskDisableSmartAttributeAutosave(
347 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
350 UCHAR srbControl
[sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
)];
351 ULONG bufferSize
= sizeof(srbControl
);
352 return DiskPerformSmartCommand(FdoExtension
,
353 IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
,
355 ENABLE_DISABLE_AUTOSAVE
,
358 (PSRB_IO_CONTROL
)srbControl
,
363 // Initialize execution of SMART online diagnostics
366 DiskExecuteSmartDiagnostics(
367 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
371 UCHAR srbControl
[sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
)];
372 ULONG bufferSize
= sizeof(srbControl
);
373 return DiskPerformSmartCommand(FdoExtension
,
374 IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
,
376 EXECUTE_OFFLINE_DIAGS
,
379 (PSRB_IO_CONTROL
)srbControl
,
386 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
387 IN UCHAR SectorCount
,
392 PSRB_IO_CONTROL srbControl
;
394 PSENDCMDOUTPARAMS sendCmdOutParams
;
395 ULONG logSize
, bufferSize
;
399 logSize
= SectorCount
* SMART_LOG_SECTOR_SIZE
;
400 bufferSize
= sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1 +
403 srbControl
= ExAllocatePoolWithTag(NonPagedPool
,
407 if (srbControl
!= NULL
)
409 status
= DiskPerformSmartCommand(FdoExtension
,
410 IOCTL_SCSI_MINIPORT_READ_SMART_LOG
,
418 if (NT_SUCCESS(status
))
420 sendCmdOutParams
= (PSENDCMDOUTPARAMS
)((PUCHAR
)srbControl
+
421 sizeof(SRB_IO_CONTROL
));
422 RtlCopyMemory(Buffer
,
423 &sendCmdOutParams
->bBuffer
[0],
427 ExFreePool(srbControl
);
429 status
= STATUS_INSUFFICIENT_RESOURCES
;
437 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
438 IN UCHAR SectorCount
,
443 PSRB_IO_CONTROL srbControl
;
445 PSENDCMDINPARAMS sendCmdInParams
;
446 ULONG logSize
, bufferSize
;
450 logSize
= SectorCount
* SMART_LOG_SECTOR_SIZE
;
451 bufferSize
= sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1 +
454 srbControl
= ExAllocatePoolWithTag(NonPagedPool
,
458 if (srbControl
!= NULL
)
460 sendCmdInParams
= (PSENDCMDINPARAMS
)((PUCHAR
)srbControl
+
461 sizeof(SRB_IO_CONTROL
));
462 RtlCopyMemory(&sendCmdInParams
->bBuffer
[0],
465 status
= DiskPerformSmartCommand(FdoExtension
,
466 IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG
,
474 ExFreePool(srbControl
);
476 status
= STATUS_INSUFFICIENT_RESOURCES
;
482 DiskPerformSmartCommand(
483 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
484 IN ULONG SrbControlCode
,
487 IN UCHAR SectorCount
,
488 IN UCHAR SectorNumber
,
489 IN OUT PSRB_IO_CONTROL SrbControl
,
490 OUT PULONG BufferSize
496 This routine will perform some SMART command
500 FdoExtension is the FDO device extension
502 SrbControlCode is the SRB control code to use for the request
504 Command is the SMART command to be executed. It may be SMART_CMD or
507 Feature is the value to place in the IDE feature register.
509 SectorCount is the value to place in the IDE SectorCount register
511 SrbControl is the buffer used to build the SRB_IO_CONTROL and pass
512 any input parameters. It also returns the output parameters.
514 *BufferSize on entry has total size of SrbControl and on return has
515 the size used in SrbControl.
525 PCOMMON_DEVICE_EXTENSION commonExtension
= (PCOMMON_DEVICE_EXTENSION
)FdoExtension
;
526 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
528 PSENDCMDINPARAMS cmdInParameters
;
529 PSENDCMDOUTPARAMS cmdOutParameters
;
532 ULONG availableBufferSize
;
535 IO_STATUS_BLOCK ioStatus
;
536 SCSI_REQUEST_BLOCK srb
;
537 LARGE_INTEGER startingOffset
;
539 PIO_STACK_LOCATION irpStack
;
544 // Point to the 'buffer' portion of the SRB_CONTROL and compute how
545 // much room we have left in the srb control
548 buffer
= (PUCHAR
)SrbControl
;
549 buffer
+= sizeof(SRB_IO_CONTROL
);
551 cmdInParameters
= (PSENDCMDINPARAMS
)buffer
;
552 cmdOutParameters
= (PSENDCMDOUTPARAMS
)buffer
;
554 availableBufferSize
= *BufferSize
- sizeof(SRB_IO_CONTROL
);
558 // Ensure control codes and buffer lengths passed are correct
562 ULONG lengthNeeded
= sizeof(SENDCMDINPARAMS
) - 1;
564 if (Command
== SMART_CMD
)
571 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
;
578 controlCode
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
;
582 case RETURN_SMART_STATUS
:
585 // Ensure bBuffer is at least 2 bytes (to hold the values of
586 // cylinderLow and cylinderHigh).
589 lengthNeeded
= sizeof(SENDCMDINPARAMS
) - 1 + sizeof(IDEREGS
);
591 controlCode
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
;
595 case ENABLE_DISABLE_AUTOSAVE
:
597 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
;
601 case SAVE_ATTRIBUTE_VALUES
:
603 controlCode
= IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
;
608 case EXECUTE_OFFLINE_DIAGS
:
610 controlCode
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
;
614 case READ_ATTRIBUTES
:
616 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
;
617 lengthNeeded
= READ_ATTRIBUTE_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
) - 1;
621 case READ_THRESHOLDS
:
623 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
;
624 lengthNeeded
= READ_THRESHOLD_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
) - 1;
630 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_LOG
;
631 lengthNeeded
= (SectorCount
* SMART_LOG_SECTOR_SIZE
) +
632 sizeof(SENDCMDINPARAMS
) - 1;
636 case SMART_WRITE_LOG
:
638 controlCode
= IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG
;
639 lengthNeeded
= (SectorCount
* SMART_LOG_SECTOR_SIZE
) +
640 sizeof(SENDCMDINPARAMS
) - 1;
649 } else if (Command
== ID_CMD
) {
650 controlCode
= IOCTL_SCSI_MINIPORT_IDENTIFY
;
651 lengthNeeded
= IDENTIFY_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
) -1;
657 ASSERT(controlCode
== SrbControlCode
);
658 ASSERT(availableBufferSize
>= lengthNeeded
);
663 // Build SrbControl and input to SMART command
666 SrbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
667 RtlMoveMemory (SrbControl
->Signature
, "SCSIDISK", 8);
668 SrbControl
->Timeout
= FdoExtension
->TimeOutValue
;
669 SrbControl
->Length
= availableBufferSize
;
671 SrbControl
->ControlCode
= SrbControlCode
;
673 cmdInParameters
->cBufferSize
= sizeof(SENDCMDINPARAMS
);
674 cmdInParameters
->bDriveNumber
= diskData
->ScsiAddress
.TargetId
;
675 cmdInParameters
->irDriveRegs
.bFeaturesReg
= Feature
;
676 cmdInParameters
->irDriveRegs
.bSectorCountReg
= SectorCount
;
677 cmdInParameters
->irDriveRegs
.bSectorNumberReg
= SectorNumber
;
678 cmdInParameters
->irDriveRegs
.bCylLowReg
= SMART_CYL_LOW
;
679 cmdInParameters
->irDriveRegs
.bCylHighReg
= SMART_CYL_HI
;
680 cmdInParameters
->irDriveRegs
.bCommandReg
= Command
;
684 // Create and send irp
686 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
688 startingOffset
.QuadPart
= (LONGLONG
) 1;
690 length
= SrbControl
->HeaderLength
+ SrbControl
->Length
;
692 irp
= IoBuildSynchronousFsdRequest(
694 commonExtension
->LowerDeviceObject
,
702 return STATUS_INSUFFICIENT_RESOURCES
;
705 irpStack
= IoGetNextIrpStackLocation(irp
);
708 // Set major and minor codes.
711 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
712 irpStack
->MinorFunction
= 1;
715 // Fill in SRB fields.
718 irpStack
->Parameters
.Others
.Argument1
= &srb
;
724 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
726 srb
.PathId
= diskData
->ScsiAddress
.PathId
;
727 srb
.TargetId
= diskData
->ScsiAddress
.TargetId
;
728 srb
.Lun
= diskData
->ScsiAddress
.Lun
;
730 srb
.Function
= SRB_FUNCTION_IO_CONTROL
;
731 srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
733 srb
.SrbFlags
= FdoExtension
->SrbFlags
;
734 SET_FLAG(srb
.SrbFlags
, SRB_FLAGS_DATA_IN
);
735 SET_FLAG(srb
.SrbFlags
, SRB_FLAGS_NO_QUEUE_FREEZE
);
736 SET_FLAG(srb
.SrbFlags
, SRB_FLAGS_NO_KEEP_AWAKE
);
738 srb
.QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
739 srb
.QueueTag
= SP_UNTAGGED
;
741 srb
.OriginalRequest
= irp
;
744 // Set timeout to requested value.
747 srb
.TimeOutValue
= SrbControl
->Timeout
;
750 // Set the data buffer.
753 srb
.DataBuffer
= SrbControl
;
754 srb
.DataTransferLength
= length
;
757 // Flush the data buffer for output. This will insure that the data is
758 // written back to memory. Since the data-in flag is the the port driver
759 // will flush the data again for input which will ensure the data is not
763 KeFlushIoBuffers(irp
->MdlAddress
, FALSE
, TRUE
);
766 // Call port driver to handle this request.
769 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, irp
);
771 if (status
== STATUS_PENDING
) {
772 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
773 status
= ioStatus
.Status
;
782 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
783 PBOOLEAN SupportSmart
786 UCHAR outBuffer
[sizeof(SRB_IO_CONTROL
) + (sizeof(SENDCMDINPARAMS
)-1) + IDENTIFY_BUFFER_SIZE
];
787 ULONG outBufferSize
= sizeof(outBuffer
);
792 status
= DiskGetIdentifyData(FdoExtension
,
793 (PSRB_IO_CONTROL
)outBuffer
,
796 if (NT_SUCCESS(status
))
798 PUSHORT identifyData
= (PUSHORT
)&(outBuffer
[sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDOUTPARAMS
)-1]);
799 USHORT commandSetSupported
= identifyData
[82];
801 *SupportSmart
= ((commandSetSupported
!= 0xffff) &&
802 (commandSetSupported
!= 0) &&
803 ((commandSetSupported
& 1) == 1));
805 *SupportSmart
= FALSE
;
808 DebugPrint((3, "DiskGetIdentifyInfo: SMART %s supported for device %p, status %lx\n",
809 *SupportSmart
? "is" : "is not",
810 FdoExtension
->DeviceObject
,
818 // FP Ioctl specific routines
822 DiskSendFailurePredictIoctl(
823 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
824 PSTORAGE_PREDICT_FAILURE checkFailure
828 PDEVICE_OBJECT deviceObject
;
829 IO_STATUS_BLOCK ioStatus
;
835 KeInitializeEvent(&event
, SynchronizationEvent
, FALSE
);
837 deviceObject
= IoGetAttachedDeviceReference(FdoExtension
->DeviceObject
);
839 irp
= IoBuildDeviceIoControlRequest(
840 IOCTL_STORAGE_PREDICT_FAILURE
,
845 sizeof(STORAGE_PREDICT_FAILURE
),
852 status
= IoCallDriver(deviceObject
, irp
);
853 if (status
== STATUS_PENDING
)
855 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
856 status
= ioStatus
.Status
;
860 status
= STATUS_INSUFFICIENT_RESOURCES
;
863 ObDereferenceObject(deviceObject
);
870 // FP type independent routines
874 DiskEnableDisableFailurePrediction(
875 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
882 Enable or disable failure prediction at the hardware level
897 PCOMMON_DEVICE_EXTENSION commonExtension
= &(FdoExtension
->CommonExtension
);
898 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
902 switch(diskData
->FailurePredictionCapability
)
904 case FailurePredictionSmart
:
909 status
= DiskEnableSmart(FdoExtension
);
911 status
= DiskDisableSmart(FdoExtension
);
917 case FailurePredictionSense
:
918 case FailurePredictionIoctl
:
921 // We assume that the drive is already setup properly for
922 // failure prediction
924 status
= STATUS_SUCCESS
;
930 status
= STATUS_INVALID_DEVICE_REQUEST
;
937 DiskEnableDisableFailurePredictPolling(
938 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
940 ULONG PollTimeInSeconds
946 Enable or disable polling for hardware failure detection
954 PollTimeInSeconds - if 0 then no change to current polling timer
963 PCOMMON_DEVICE_EXTENSION commonExtension
= (PCOMMON_DEVICE_EXTENSION
)FdoExtension
;
964 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
970 status
= DiskEnableDisableFailurePrediction(FdoExtension
,
973 status
= STATUS_SUCCESS
;
976 if (NT_SUCCESS(status
))
978 status
= ClassSetFailurePredictionPoll(FdoExtension
,
979 Enable
? diskData
->FailurePredictionCapability
:
980 FailurePredictionNone
,
984 // Even if this failed we do not want to disable FP on the
985 // hardware. FP is only ever disabled on the hardware by
986 // specific command of the user.
995 DiskReadFailurePredictStatus(
996 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
997 PSTORAGE_FAILURE_PREDICT_STATUS DiskSmartStatus
1001 Routine Description:
1003 Obtains current failure prediction status
1017 PCOMMON_DEVICE_EXTENSION commonExtension
= (PCOMMON_DEVICE_EXTENSION
)FdoExtension
;
1018 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
1023 DiskSmartStatus
->PredictFailure
= FALSE
;
1025 switch(diskData
->FailurePredictionCapability
)
1027 case FailurePredictionSmart
:
1029 UCHAR outBuffer
[sizeof(SRB_IO_CONTROL
) + (sizeof(SENDCMDINPARAMS
) - 1 + sizeof(IDEREGS
))];
1030 ULONG outBufferSize
= sizeof(outBuffer
);
1031 PSENDCMDOUTPARAMS cmdOutParameters
;
1033 status
= DiskReadSmartStatus(FdoExtension
,
1034 (PSRB_IO_CONTROL
)outBuffer
,
1037 if (NT_SUCCESS(status
))
1039 cmdOutParameters
= (PSENDCMDOUTPARAMS
)(outBuffer
+
1040 sizeof(SRB_IO_CONTROL
));
1042 DiskSmartStatus
->Reason
= 0; // Unknown;
1043 DiskSmartStatus
->PredictFailure
= ((cmdOutParameters
->bBuffer
[3] == 0xf4) &&
1044 (cmdOutParameters
->bBuffer
[4] == 0x2c));
1049 case FailurePredictionSense
:
1051 DiskSmartStatus
->Reason
= FdoExtension
->FailureReason
;
1052 DiskSmartStatus
->PredictFailure
= FdoExtension
->FailurePredicted
;
1053 status
= STATUS_SUCCESS
;
1057 case FailurePredictionIoctl
:
1058 case FailurePredictionNone
:
1061 status
= STATUS_INVALID_DEVICE_REQUEST
;
1070 DiskReadFailurePredictData(
1071 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
1072 PSTORAGE_FAILURE_PREDICT_DATA DiskSmartData
1076 Routine Description:
1078 Obtains current failure prediction data. Not available for
1079 FAILURE_PREDICT_SENSE types.
1093 PCOMMON_DEVICE_EXTENSION commonExtension
= (PCOMMON_DEVICE_EXTENSION
)FdoExtension
;
1094 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
1099 switch(diskData
->FailurePredictionCapability
)
1101 case FailurePredictionSmart
:
1104 ULONG outBufferSize
;
1105 PSENDCMDOUTPARAMS cmdOutParameters
;
1107 outBufferSize
= sizeof(SRB_IO_CONTROL
) +
1108 (sizeof(SENDCMDOUTPARAMS
)-1) +
1109 READ_ATTRIBUTE_BUFFER_SIZE
;
1111 outBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
1115 if (outBuffer
!= NULL
)
1117 status
= DiskReadSmartData(FdoExtension
,
1118 (PSRB_IO_CONTROL
)outBuffer
,
1121 if (NT_SUCCESS(status
))
1123 cmdOutParameters
= (PSENDCMDOUTPARAMS
)(outBuffer
+
1124 sizeof(SRB_IO_CONTROL
));
1126 DiskSmartData
->Length
= READ_ATTRIBUTE_BUFFER_SIZE
;
1127 RtlCopyMemory(DiskSmartData
->VendorSpecific
,
1128 cmdOutParameters
->bBuffer
,
1129 READ_ATTRIBUTE_BUFFER_SIZE
);
1131 ExFreePool(outBuffer
);
1133 status
= STATUS_INSUFFICIENT_RESOURCES
;
1139 case FailurePredictionSense
:
1141 DiskSmartData
->Length
= sizeof(ULONG
);
1142 *((PULONG
)DiskSmartData
->VendorSpecific
) = FdoExtension
->FailureReason
;
1144 status
= STATUS_SUCCESS
;
1148 case FailurePredictionIoctl
:
1149 case FailurePredictionNone
:
1152 status
= STATUS_INVALID_DEVICE_REQUEST
;
1161 DiskReadFailurePredictThresholds(
1162 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
1163 PSTORAGE_FAILURE_PREDICT_THRESHOLDS DiskSmartThresholds
1167 Routine Description:
1169 Obtains current failure prediction thresholds. Not available for
1170 FAILURE_PREDICT_SENSE types.
1184 PCOMMON_DEVICE_EXTENSION commonExtension
= (PCOMMON_DEVICE_EXTENSION
)FdoExtension
;
1185 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
1190 switch(diskData
->FailurePredictionCapability
)
1192 case FailurePredictionSmart
:
1195 PSENDCMDOUTPARAMS cmdOutParameters
;
1196 ULONG outBufferSize
;
1198 outBufferSize
= sizeof(SRB_IO_CONTROL
) +
1199 (sizeof(SENDCMDOUTPARAMS
)-1) +
1200 READ_THRESHOLD_BUFFER_SIZE
;
1202 outBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
1206 if (outBuffer
!= NULL
)
1208 status
= DiskReadSmartThresholds(FdoExtension
,
1209 (PSRB_IO_CONTROL
)outBuffer
,
1212 if (NT_SUCCESS(status
))
1214 cmdOutParameters
= (PSENDCMDOUTPARAMS
)(outBuffer
+
1215 sizeof(SRB_IO_CONTROL
));
1217 RtlCopyMemory(DiskSmartThresholds
->VendorSpecific
,
1218 cmdOutParameters
->bBuffer
,
1219 READ_THRESHOLD_BUFFER_SIZE
);
1221 ExFreePool(outBuffer
);
1223 status
= STATUS_INSUFFICIENT_RESOURCES
;
1229 case FailurePredictionSense
:
1230 case FailurePredictionIoctl
:
1231 case FailurePredictionNone
:
1234 status
= STATUS_INVALID_DEVICE_REQUEST
;
1242 void DiskReregWorker(
1246 PDISKREREGREQUEST reregRequest
;
1248 PDEVICE_OBJECT deviceObject
;
1255 reregRequest
= (PDISKREREGREQUEST
)ExInterlockedPopEntryList(
1257 &DiskReregSpinlock
);
1259 deviceObject
= reregRequest
->DeviceObject
;
1260 irp
= reregRequest
->Irp
;
1262 status
= IoWMIRegistrationControl(deviceObject
,
1263 WMIREG_ACTION_UPDATE_GUIDS
);
1265 if (! NT_SUCCESS(status
))
1267 DebugPrint((1, "DiskReregWorker: Reregistration failed %x\n",
1272 // Release remove lock and free irp, now that we are done
1275 ClassReleaseRemoveLock(deviceObject
, irp
);
1277 IoFreeMdl(irp
->MdlAddress
);
1280 ExFreePool(reregRequest
);
1282 } while (InterlockedDecrement(&DiskReregWorkItems
));
1287 NTSTATUS
DiskInitializeReregistration(
1294 // Initialize the global work item and spinlock used to manage the
1295 // list of disks reregistering their guids
1297 ExInitializeWorkItem( &DiskReregWorkItem
,
1301 KeInitializeSpinLock(&DiskReregSpinlock
);
1303 return(STATUS_SUCCESS
);
1306 NTSTATUS
DiskPostReregisterRequest(
1307 PDEVICE_OBJECT DeviceObject
,
1311 PDISKREREGREQUEST reregRequest
;
1314 reregRequest
= ExAllocatePoolWithTag(NonPagedPool
,
1315 sizeof(DISKREREGREQUEST
),
1318 if (reregRequest
!= NULL
)
1321 // add the disk that needs reregistration to the stack of disks
1322 // to reregister. If the list is transitioning from empty to
1323 // non empty then also kick off the work item so that the
1324 // reregistration worker can do the reregister.
1326 reregRequest
->DeviceObject
= DeviceObject
;
1327 reregRequest
->Irp
= Irp
;
1328 ExInterlockedPushEntryList(
1330 &reregRequest
->Next
,
1331 &DiskReregSpinlock
);
1333 if (InterlockedIncrement(&DiskReregWorkItems
) == 1)
1335 ExQueueWorkItem( &DiskReregWorkItem
, DelayedWorkQueue
);
1337 status
= STATUS_SUCCESS
;
1339 DebugPrint((1, "DiskPostReregisterRequest: could not allocate reregRequest for %p\n",
1341 status
= STATUS_INSUFFICIENT_RESOURCES
;
1347 NTSTATUS
DiskInfoExceptionComplete(
1348 PDEVICE_OBJECT DeviceObject
,
1353 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
1354 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1355 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
1356 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1357 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1358 PSCSI_REQUEST_BLOCK srb
= Context
;
1361 ULONG retryInterval
;
1363 BOOLEAN freeLockAndIrp
= TRUE
;
1366 ASSERT(fdoExtension
->CommonExtension
.IsFdo
);
1368 srbStatus
= SRB_STATUS(srb
->SrbStatus
);
1371 // Check SRB status for success of completing request.
1372 // SRB_STATUS_DATA_OVERRUN also indicates success.
1374 if ((srbStatus
!= SRB_STATUS_SUCCESS
) &&
1375 (srbStatus
!= SRB_STATUS_DATA_OVERRUN
))
1377 DebugPrint((2, "DiskInfoExceptionComplete: IRP %p, SRB %p\n", Irp
, srb
));
1379 retry
= ClassInterpretSenseInfo(
1382 irpStack
->MajorFunction
,
1385 ((ULONG
)(ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
),
1390 // If the status is verified required and the this request
1391 // should bypass verify required then retry the request.
1394 if (TEST_FLAG(irpStack
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
) &&
1395 status
== STATUS_VERIFY_REQUIRED
)
1397 status
= STATUS_IO_DEVICE_ERROR
;
1401 if (retry
&& irpStack
->Parameters
.Others
.Argument4
)
1403 irpStack
->Parameters
.Others
.Argument4
=
1404 (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
- 1);
1410 DebugPrint((1, "DiskInfoExceptionComplete: Retry request %p\n", Irp
));
1412 ASSERT(srb
->DataBuffer
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
1415 // Reset byte count of transfer in SRB Extension.
1417 srb
->DataTransferLength
= Irp
->MdlAddress
->ByteCount
;
1420 // Zero SRB statuses.
1423 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1426 // Set the no disconnect flag, disable synchronous data transfers and
1427 // disable tagged queuing. This fixes some errors.
1430 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_DISCONNECT
);
1431 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
1432 CLEAR_FLAG(srb
->SrbFlags
, SRB_FLAGS_QUEUE_ACTION_ENABLE
);
1434 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
1435 srb
->QueueTag
= SP_UNTAGGED
;
1438 // Set up major SCSI function.
1441 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1444 // Save SRB address in next stack for port driver.
1447 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
1450 IoSetCompletionRoutine(Irp
,
1451 DiskInfoExceptionComplete
,
1455 (VOID
)IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
1457 return STATUS_MORE_PROCESSING_REQUIRED
;
1463 // Get the results from the mode sense
1465 PMODE_INFO_EXCEPTIONS pageData
;
1466 PMODE_PARAMETER_HEADER modeData
;
1467 ULONG modeDataLength
;
1469 modeData
= srb
->DataBuffer
;
1470 modeDataLength
= srb
->DataTransferLength
;
1472 pageData
= ClassFindModePage((PUCHAR
) modeData
,
1474 MODE_PAGE_FAULT_REPORTING
,
1476 if (pageData
!= NULL
)
1478 DebugPrint((1, "DiskInfoExceptionComplete: %p supports SMART\n",
1481 if (pageData
->Dexcpt
== 0)
1483 diskData
->FailurePredictionCapability
= FailurePredictionSense
;
1484 status
= DiskPostReregisterRequest(DeviceObject
, Irp
);
1486 if (NT_SUCCESS(status
))
1489 // Make sure we won't free the remove lock and the irp
1490 // since we need to keep these until after the work
1491 // item has completed running
1493 freeLockAndIrp
= FALSE
;
1496 DebugPrint((1, "DiskInfoExceptionComplete: %p is not enabled for SMART\n",
1502 DebugPrint((1, "DiskInfoExceptionComplete: %p does not supports SMART\n",
1508 // Set status for successful request
1511 status
= STATUS_SUCCESS
;
1513 } // end if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)
1518 ExFreePool(srb
->SenseInfoBuffer
);
1519 ExFreePool(srb
->DataBuffer
);
1525 // Set status in completing IRP.
1528 Irp
->IoStatus
.Status
= status
;
1531 // If pending has be returned for this irp then mark the current stack as
1535 if (Irp
->PendingReturned
) {
1536 IoMarkIrpPending(Irp
);
1539 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1540 IoFreeMdl(Irp
->MdlAddress
);
1544 return(STATUS_MORE_PROCESSING_REQUIRED
);
1548 NTSTATUS
DiskInfoExceptionCheck(
1549 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
1553 PSCSI_REQUEST_BLOCK srb
;
1556 PIO_STACK_LOCATION irpStack
;
1557 PVOID senseInfoBuffer
;
1560 modeData
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
1562 DISK_TAG_INFO_EXCEPTION
);
1563 if (modeData
== NULL
)
1565 DebugPrint((1, "DiskInfoExceptionCheck: Can't allocate mode data "
1567 return(STATUS_INSUFFICIENT_RESOURCES
);
1570 srb
= ExAllocatePoolWithTag(NonPagedPool
,
1571 SCSI_REQUEST_BLOCK_SIZE
,
1575 ExFreePool(modeData
);
1576 DebugPrint((1, "DiskInfoExceptionCheck: Can't allocate srb "
1578 return(STATUS_INSUFFICIENT_RESOURCES
);
1582 // Build the MODE SENSE CDB.
1584 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1586 cdb
= (PCDB
)srb
->Cdb
;
1588 cdb
= (PCDB
)srb
->Cdb
;
1591 // Set timeout value from device extension.
1593 srb
->TimeOutValue
= FdoExtension
->TimeOutValue
;
1595 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
1596 cdb
->MODE_SENSE
.PageCode
= MODE_PAGE_FAULT_REPORTING
;
1597 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
1600 // Write length to SRB.
1602 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1605 // Set SCSI bus address.
1608 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1611 // Enable auto request sense.
1614 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1617 // Sense buffer is in aligned nonpaged pool.
1620 senseInfoBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
1624 if (senseInfoBuffer
== NULL
)
1627 ExFreePool(modeData
);
1628 DebugPrint((1, "DiskInfoExceptionCheck: Can't allocate request sense "
1630 return(STATUS_INSUFFICIENT_RESOURCES
);
1633 srb
->SenseInfoBuffer
= senseInfoBuffer
;
1634 srb
->DataBuffer
= modeData
;
1636 srb
->SrbFlags
= FdoExtension
->SrbFlags
;
1639 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
1642 // Disable synchronous transfer for these requests.
1644 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
1647 // Don't freeze the queue on an error
1649 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_QUEUE_FREEZE
);
1651 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
1652 srb
->QueueTag
= SP_UNTAGGED
;
1656 // Build device I/O control request with METHOD_NEITHER data transfer.
1657 // We'll queue a completion routine to cleanup the MDL's and such ourself.
1660 irp
= IoAllocateIrp(
1661 (CCHAR
) (FdoExtension
->CommonExtension
.LowerDeviceObject
->StackSize
+ 1),
1666 ExFreePool(senseInfoBuffer
);
1668 ExFreePool(modeData
);
1669 DebugPrint((1, "DiskInfoExceptionCheck: Can't allocate Irp\n"));
1670 return(STATUS_INSUFFICIENT_RESOURCES
);
1673 isRemoved
= ClassAcquireRemoveLock(FdoExtension
->DeviceObject
, irp
);
1677 ClassReleaseRemoveLock(FdoExtension
->DeviceObject
, irp
);
1679 ExFreePool(senseInfoBuffer
);
1681 ExFreePool(modeData
);
1682 DebugPrint((1, "DiskInfoExceptionCheck: RemoveLock says isRemoved\n"));
1683 return(STATUS_DEVICE_DOES_NOT_EXIST
);
1687 // Get next stack location.
1690 IoSetNextIrpStackLocation(irp
);
1691 irpStack
= IoGetCurrentIrpStackLocation(irp
);
1692 irpStack
->DeviceObject
= FdoExtension
->DeviceObject
;
1695 // Save retry count in current Irp stack.
1697 irpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
1700 irpStack
= IoGetNextIrpStackLocation(irp
);
1703 // Set up SRB for execute scsi request. Save SRB address in next stack
1704 // for the port driver.
1707 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1708 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1710 IoSetCompletionRoutine(irp
,
1711 DiskInfoExceptionComplete
,
1717 irp
->MdlAddress
= IoAllocateMdl( modeData
,
1722 if (irp
->MdlAddress
== NULL
)
1724 ClassReleaseRemoveLock(FdoExtension
->DeviceObject
, irp
);
1726 ExFreePool(modeData
);
1727 ExFreePool(senseInfoBuffer
);
1729 DebugPrint((1, "DiskINfoExceptionCheck: Can't allocate MDL\n"));
1730 return STATUS_INSUFFICIENT_RESOURCES
;
1733 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
1736 // Set the transfer length.
1738 srb
->DataTransferLength
= MODE_DATA_SIZE
;
1743 srb
->ScsiStatus
= srb
->SrbStatus
= 0;
1747 // Set up IRP Address.
1749 srb
->OriginalRequest
= irp
;
1752 // Call the port driver with the request and wait for it to complete.
1755 IoMarkIrpPending(irp
);
1756 IoCallDriver(FdoExtension
->CommonExtension
.LowerDeviceObject
,
1759 return(STATUS_PENDING
);
1763 DiskDetectFailurePrediction(
1764 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
1765 PFAILURE_PREDICTION_METHOD FailurePredictCapability
1769 Routine Description:
1771 Detect if device has any failure prediction capabilities. First we
1772 check for IDE SMART capability. This is done by sending the drive an
1773 IDENTIFY command and checking if the SMART command set bit is set.
1775 Next we check if SCSI SMART (aka Information Exception Control Page,
1776 X3T10/94-190 Rev 4). This is done by querying for the Information
1777 Exception mode page.
1779 Lastly we check if the device has IOCTL failure prediction. This mechanism
1780 a filter driver implements IOCTL_STORAGE_PREDICT_FAILURE and will respond
1781 with the information in the IOCTL. We do this by sending the ioctl and
1782 if the status returned is STATUS_SUCCESS we assume that it is supported.
1788 *FailurePredictCapability
1796 PCOMMON_DEVICE_EXTENSION commonExtension
= (PCOMMON_DEVICE_EXTENSION
)FdoExtension
;
1797 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
1800 STORAGE_PREDICT_FAILURE checkFailure
;
1801 STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus
;
1807 // Assume no failure predict mechanisms
1809 *FailurePredictCapability
= FailurePredictionNone
;
1812 // See if this is an IDE drive that supports SMART. If so enable SMART
1813 // and then ensure that it suports the SMART READ STATUS command
1815 status
= DiskGetIdentifyInfo(FdoExtension
,
1820 status
= DiskEnableSmart(FdoExtension
);
1821 if (NT_SUCCESS(status
))
1823 *FailurePredictCapability
= FailurePredictionSmart
;
1825 status
= DiskReadFailurePredictStatus(FdoExtension
,
1828 DebugPrint((1, "Disk: Device %p %s IDE SMART\n",
1829 FdoExtension
->DeviceObject
,
1830 NT_SUCCESS(status
) ? "does" : "does not"));
1832 if (! NT_SUCCESS(status
))
1834 *FailurePredictCapability
= FailurePredictionNone
;
1841 // See if there is a a filter driver to intercept
1842 // IOCTL_STORAGE_PREDICT_FAILURE
1844 status
= DiskSendFailurePredictIoctl(FdoExtension
,
1847 DebugPrint((1, "Disk: Device %p %s IOCTL_STORAGE_FAILURE_PREDICT\n",
1848 FdoExtension
->DeviceObject
,
1849 NT_SUCCESS(status
) ? "does" : "does not"));
1851 if (NT_SUCCESS(status
))
1853 *FailurePredictCapability
= FailurePredictionIoctl
;
1854 if (checkFailure
.PredictFailure
)
1856 checkFailure
.PredictFailure
= 512;
1857 ClassNotifyFailurePredicted(FdoExtension
,
1858 (PUCHAR
)&checkFailure
,
1859 sizeof(checkFailure
),
1860 (BOOLEAN
)(FdoExtension
->FailurePredicted
== FALSE
),
1862 diskData
->ScsiAddress
.PathId
,
1863 diskData
->ScsiAddress
.TargetId
,
1864 diskData
->ScsiAddress
.Lun
);
1866 FdoExtension
->FailurePredicted
= TRUE
;
1872 // Finally we assume it will not be a scsi smart drive. but
1873 // we'll also send off an asynchronous mode sense so that if
1874 // it is SMART we'll reregister the device object
1877 DiskInfoExceptionCheck(FdoExtension
);
1879 *FailurePredictCapability
= FailurePredictionNone
;
1881 return(STATUS_SUCCESS
);
1886 DiskWmiFunctionControl(
1887 IN PDEVICE_OBJECT DeviceObject
,
1890 IN CLASSENABLEDISABLEFUNCTION Function
,
1895 Routine Description:
1897 This routine is a callback into the driver to enabled or disable event
1898 generation or data block collection. A device should only expect a
1899 single enable when the first event or data consumer enables events or
1900 data collection and a single disable when the last event or data
1901 consumer disables events or data collection. Data blocks will only
1902 receive collection enable/disable if they were registered as requiring
1906 When NT boots, failure prediction is not automatically enabled, although
1907 it may have been persistantly enabled on a previous boot. Polling is also
1908 not automatically enabled. When the first data block that accesses SMART
1909 such as SmartStatusGuid, SmartDataGuid, SmartPerformFunction, or
1910 SmartEventGuid is accessed then SMART is automatically enabled in the
1911 hardware. Polling is enabled when SmartEventGuid is enabled and disabled
1912 when it is disabled. Hardware SMART is only disabled when the DisableSmart
1913 method is called. Polling is also disabled when this is called regardless
1914 of the status of the other guids or events.
1918 DeviceObject is the device whose data block is being queried
1920 GuidIndex is the index into the list of guids provided when the
1923 Function specifies which functionality is being enabled or disabled
1925 Enable is TRUE then the function is being enabled else disabled
1933 NTSTATUS status
= STATUS_SUCCESS
;
1934 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1935 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
1936 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
1941 if ((Function
== DataBlockCollection
) && Enable
)
1943 if ((GuidIndex
== SmartStatusGuid
) ||
1944 (GuidIndex
== SmartDataGuid
) ||
1945 (GuidIndex
== SmartThresholdsGuid
) ||
1946 (GuidIndex
== SmartPerformFunction
))
1948 status
= DiskEnableDisableFailurePrediction(fdoExtension
,
1950 DebugPrint((3, "Disk: DeviceObject %p, Irp %p Enable -> %lx\n",
1956 DebugPrint((3, "Disk: DeviceObject %p, Irp %p, GuidIndex %d %s for Collection\n",
1959 Enable
? "Enabled" : "Disabled")); }
1960 } else if (Function
== EventGeneration
) {
1961 DebugPrint((3, "Disk: DeviceObject %p, Irp %p, GuidIndex %d %s for Event Generation\n",
1964 Enable
? "Enabled" : "Disabled"));
1967 if ((GuidIndex
== SmartEventGuid
) && Enable
)
1969 status
= DiskEnableDisableFailurePredictPolling(fdoExtension
,
1972 DebugPrint((3, "Disk: DeviceObject %p, Irp %p %s -> %lx\n",
1975 Enable
? "DiskEnableSmartPolling" : "DiskDisableSmartPolling",
1981 DebugPrint((3, "Disk: DeviceObject %p, Irp %p, GuidIndex %d %s for function %d\n",
1984 Enable
? "Enabled" : "Disabled",
1989 status
= ClassWmiCompleteRequest(DeviceObject
,
2000 DiskFdoQueryWmiRegInfo(
2001 IN PDEVICE_OBJECT DeviceObject
,
2002 OUT ULONG
*RegFlags
,
2003 OUT PUNICODE_STRING InstanceName
2007 Routine Description:
2009 This routine is a callback into the driver to retrieve the list of
2010 guids or data blocks that the driver wants to register with WMI. This
2011 routine may not pend or block. Driver should NOT call
2012 ClassWmiCompleteRequest.
2016 DeviceObject is the device whose data block is being queried
2018 *RegFlags returns with a set of flags that describe the guids being
2019 registered for this device. If the device wants enable and disable
2020 collection callbacks before receiving queries for the registered
2021 guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
2022 returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
2023 the instance name is determined from the PDO associated with the
2024 device object. Note that the PDO must have an associated devnode. If
2025 WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
2026 name for the device.
2028 InstanceName returns with the instance name for the guids if
2029 WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
2030 caller will call ExFreePool with the buffer returned.
2039 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
2040 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
2041 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
2046 SET_FLAG(DiskWmiFdoGuidList
[SmartThresholdsGuid
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2047 SET_FLAG(DiskWmiFdoGuidList
[ScsiInfoExceptionsGuid
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2049 switch (diskData
->FailurePredictionCapability
)
2051 case FailurePredictionSmart
:
2053 CLEAR_FLAG(DiskWmiFdoGuidList
[SmartThresholdsGuid
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2058 case FailurePredictionIoctl
:
2060 CLEAR_FLAG(DiskWmiFdoGuidList
[SmartStatusGuid
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2061 CLEAR_FLAG(DiskWmiFdoGuidList
[SmartDataGuid
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2062 CLEAR_FLAG(DiskWmiFdoGuidList
[SmartEventGuid
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2063 CLEAR_FLAG(DiskWmiFdoGuidList
[SmartPerformFunction
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2068 case FailurePredictionSense
:
2070 CLEAR_FLAG(DiskWmiFdoGuidList
[SmartStatusGuid
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2071 CLEAR_FLAG(DiskWmiFdoGuidList
[SmartEventGuid
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2072 CLEAR_FLAG(DiskWmiFdoGuidList
[SmartPerformFunction
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2073 CLEAR_FLAG(DiskWmiFdoGuidList
[ScsiInfoExceptionsGuid
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2074 SET_FLAG (DiskWmiFdoGuidList
[SmartDataGuid
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2081 SET_FLAG (DiskWmiFdoGuidList
[SmartStatusGuid
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2082 SET_FLAG (DiskWmiFdoGuidList
[SmartDataGuid
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2083 SET_FLAG (DiskWmiFdoGuidList
[SmartEventGuid
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2084 SET_FLAG (DiskWmiFdoGuidList
[SmartPerformFunction
].Flags
, WMIREG_FLAG_REMOVE_GUID
);
2090 // Use devnode for FDOs
2091 *RegFlags
= WMIREG_FLAG_INSTANCE_PDO
;
2093 return STATUS_SUCCESS
;
2097 DiskFdoQueryWmiRegInfoEx(
2098 IN PDEVICE_OBJECT DeviceObject
,
2099 OUT ULONG
*RegFlags
,
2100 OUT PUNICODE_STRING InstanceName
,
2101 OUT PUNICODE_STRING MofName
2105 Routine Description:
2107 This routine is a callback into the driver to retrieve the list of
2108 guids or data blocks that the driver wants to register with WMI. This
2109 routine may not pend or block. Driver should NOT call
2110 ClassWmiCompleteRequest.
2114 DeviceObject is the device whose data block is being queried
2116 *RegFlags returns with a set of flags that describe the guids being
2117 registered for this device. If the device wants enable and disable
2118 collection callbacks before receiving queries for the registered
2119 guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
2120 returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
2121 the instance name is determined from the PDO associated with the
2122 device object. Note that the PDO must have an associated devnode. If
2123 WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
2124 name for the device.
2126 InstanceName returns with the instance name for the guids if
2127 WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
2128 caller will call ExFreePool with the buffer returned.
2130 MofName returns initialized with the mof resource name for the
2131 binary mof resource attached to the driver's image file. If the
2132 driver does not have a mof resource then it should leave this
2133 parameter untouched.
2143 status
= DiskFdoQueryWmiRegInfo(DeviceObject
,
2148 // Leave MofName alone since disk doesn't have one
2155 DiskFdoQueryWmiDataBlock(
2156 IN PDEVICE_OBJECT DeviceObject
,
2159 IN ULONG BufferAvail
,
2164 Routine Description:
2166 This routine is a callback into the driver to query for the contents of
2167 a data block. When the driver has finished filling the data block it
2168 must call ClassWmiCompleteRequest to complete the irp. The driver can
2169 return STATUS_PENDING if the irp cannot be completed immediately.
2173 DeviceObject is the device whose data block is being queried
2175 Irp is the Irp that makes this request
2177 GuidIndex is the index into the list of guids provided when the
2180 BufferAvail on has the maximum size available to write the data
2183 Buffer on return is filled with the returned data block
2193 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
2194 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
2195 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
2200 DebugPrint((3, "Disk: DiskQueryWmiDataBlock, Device %p, Irp %p, GuiIndex %d\n"
2201 " BufferAvail %lx Buffer %lx\n",
2203 GuidIndex
, BufferAvail
, Buffer
));
2207 case DiskGeometryGuid
:
2209 sizeNeeded
= sizeof(DISK_GEOMETRY
);
2210 if (BufferAvail
>= sizeNeeded
)
2212 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
2215 // Issue ReadCapacity to update device extension
2216 // with information for current media.
2217 status
= DiskReadDriveCapacity(commonExtension
->PartitionZeroExtension
->DeviceObject
);
2220 // Note whether the drive is ready.
2221 diskData
->ReadyStatus
= status
;
2223 if (!NT_SUCCESS(status
))
2230 // Copy drive geometry information from device extension.
2231 RtlMoveMemory(Buffer
,
2232 &(fdoExtension
->DiskGeometry
),
2233 sizeof(DISK_GEOMETRY
));
2235 status
= STATUS_SUCCESS
;
2237 status
= STATUS_BUFFER_TOO_SMALL
;
2242 case SmartStatusGuid
:
2244 PSTORAGE_FAILURE_PREDICT_STATUS diskSmartStatus
;
2246 ASSERT(diskData
->FailurePredictionCapability
!= FailurePredictionNone
);
2249 sizeNeeded
= sizeof(STORAGE_FAILURE_PREDICT_STATUS
);
2250 if (BufferAvail
>= sizeNeeded
)
2252 STORAGE_PREDICT_FAILURE checkFailure
;
2254 diskSmartStatus
= (PSTORAGE_FAILURE_PREDICT_STATUS
)Buffer
;
2256 status
= DiskSendFailurePredictIoctl(fdoExtension
,
2259 if (NT_SUCCESS(status
))
2261 if (diskData
->FailurePredictionCapability
==
2262 FailurePredictionSense
)
2264 diskSmartStatus
->Reason
= *((PULONG
)checkFailure
.VendorSpecific
);
2266 diskSmartStatus
->Reason
= 0; // unknown
2269 diskSmartStatus
->PredictFailure
= (checkFailure
.PredictFailure
!= 0);
2272 status
= STATUS_BUFFER_TOO_SMALL
;
2279 PSTORAGE_FAILURE_PREDICT_DATA diskSmartData
;
2281 ASSERT((diskData
->FailurePredictionCapability
==
2282 FailurePredictionSmart
) ||
2283 (diskData
->FailurePredictionCapability
==
2284 FailurePredictionIoctl
));
2286 sizeNeeded
= sizeof(STORAGE_FAILURE_PREDICT_DATA
);
2287 if (BufferAvail
>= sizeNeeded
)
2289 PSTORAGE_PREDICT_FAILURE checkFailure
= (PSTORAGE_PREDICT_FAILURE
)Buffer
;
2291 diskSmartData
= (PSTORAGE_FAILURE_PREDICT_DATA
)Buffer
;
2293 status
= DiskSendFailurePredictIoctl(fdoExtension
,
2296 if (NT_SUCCESS(status
))
2298 diskSmartData
->Length
= 512;
2301 status
= STATUS_BUFFER_TOO_SMALL
;
2307 case SmartThresholdsGuid
:
2309 PSTORAGE_FAILURE_PREDICT_THRESHOLDS diskSmartThresholds
;
2311 ASSERT((diskData
->FailurePredictionCapability
==
2312 FailurePredictionSmart
));
2314 sizeNeeded
= sizeof(STORAGE_FAILURE_PREDICT_THRESHOLDS
);
2315 if (BufferAvail
>= sizeNeeded
)
2317 diskSmartThresholds
= (PSTORAGE_FAILURE_PREDICT_THRESHOLDS
)Buffer
;
2318 status
= DiskReadFailurePredictThresholds(fdoExtension
,
2319 diskSmartThresholds
);
2321 status
= STATUS_BUFFER_TOO_SMALL
;
2327 case SmartPerformFunction
:
2330 status
= STATUS_SUCCESS
;
2334 case ScsiInfoExceptionsGuid
:
2336 PSTORAGE_SCSI_INFO_EXCEPTIONS infoExceptions
;
2337 MODE_INFO_EXCEPTIONS modeInfo
;
2339 ASSERT((diskData
->FailurePredictionCapability
==
2340 FailurePredictionSense
));
2342 sizeNeeded
= sizeof(STORAGE_SCSI_INFO_EXCEPTIONS
);
2343 if (BufferAvail
>= sizeNeeded
)
2345 infoExceptions
= (PSTORAGE_SCSI_INFO_EXCEPTIONS
)Buffer
;
2346 status
= DiskGetInfoExceptionInformation(fdoExtension
,
2349 if (NT_SUCCESS(status
))
2351 infoExceptions
->PageSavable
= modeInfo
.PSBit
;
2352 infoExceptions
->Flags
= modeInfo
.Flags
;
2353 infoExceptions
->MRIE
= modeInfo
.ReportMethod
;
2354 infoExceptions
->Padding
= 0;
2355 REVERSE_BYTES(&infoExceptions
->IntervalTimer
,
2356 &modeInfo
.IntervalTimer
);
2357 REVERSE_BYTES(&infoExceptions
->ReportCount
,
2358 &modeInfo
.ReportCount
)
2361 status
= STATUS_BUFFER_TOO_SMALL
;
2370 status
= STATUS_WMI_GUID_NOT_FOUND
;
2373 DebugPrint((3, "Disk: DiskQueryWmiDataBlock Device %p, Irp %p returns %lx\n",
2374 DeviceObject
, Irp
, status
));
2376 status
= ClassWmiCompleteRequest(DeviceObject
,
2386 DiskFdoSetWmiDataBlock(
2387 IN PDEVICE_OBJECT DeviceObject
,
2390 IN ULONG BufferSize
,
2395 Routine Description:
2397 This routine is a callback into the driver to query for the contents of
2398 a data block. When the driver has finished filling the data block it
2399 must call ClassWmiCompleteRequest to complete the irp. The driver can
2400 return STATUS_PENDING if the irp cannot be completed immediately.
2404 DeviceObject is the device whose data block is being queried
2406 Irp is the Irp that makes this request
2408 GuidIndex is the index into the list of guids provided when the
2411 BufferSize has the size of the data block passed
2413 Buffer has the new values for the data block
2423 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
2424 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
2425 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
2429 DebugPrint((3, "Disk: DiskSetWmiDataBlock, Device %p, Irp %p, GuiIndex %d\n"
2430 " BufferSize %#x Buffer %p\n",
2432 GuidIndex
, BufferSize
, Buffer
));
2434 if (GuidIndex
== ScsiInfoExceptionsGuid
)
2436 PSTORAGE_SCSI_INFO_EXCEPTIONS infoExceptions
;
2437 MODE_INFO_EXCEPTIONS modeInfo
;
2439 if (BufferSize
>= sizeof(STORAGE_SCSI_INFO_EXCEPTIONS
))
2441 infoExceptions
= (PSTORAGE_SCSI_INFO_EXCEPTIONS
)Buffer
;
2443 modeInfo
.PageCode
= MODE_PAGE_FAULT_REPORTING
;
2444 modeInfo
.PageLength
= sizeof(MODE_INFO_EXCEPTIONS
) - 2;
2447 modeInfo
.Flags
= infoExceptions
->Flags
;
2449 modeInfo
.ReportMethod
= infoExceptions
->MRIE
;
2451 REVERSE_BYTES(&modeInfo
.IntervalTimer
[0],
2452 &infoExceptions
->IntervalTimer
);
2454 REVERSE_BYTES(&modeInfo
.ReportCount
[0],
2455 &infoExceptions
->ReportCount
);
2457 if (modeInfo
.Perf
== 1)
2459 diskData
->AllowFPPerfHit
= FALSE
;
2461 diskData
->AllowFPPerfHit
= TRUE
;
2464 status
= DiskSetInfoExceptionInformation(fdoExtension
,
2467 status
= STATUS_INVALID_PARAMETER
;
2470 } else if (GuidIndex
<= SmartEventGuid
)
2472 status
= STATUS_WMI_READ_ONLY
;
2474 status
= STATUS_WMI_GUID_NOT_FOUND
;
2477 DebugPrint((3, "Disk: DiskSetWmiDataBlock Device %p, Irp %p returns %lx\n",
2478 DeviceObject
, Irp
, status
));
2480 status
= ClassWmiCompleteRequest(DeviceObject
,
2490 DiskFdoSetWmiDataItem(
2491 IN PDEVICE_OBJECT DeviceObject
,
2494 IN ULONG DataItemId
,
2495 IN ULONG BufferSize
,
2500 Routine Description:
2502 This routine is a callback into the driver to query for the contents of
2503 a data block. When the driver has finished filling the data block it
2504 must call ClassWmiCompleteRequest to complete the irp. The driver can
2505 return STATUS_PENDING if the irp cannot be completed immediately.
2509 DeviceObject is the device whose data block is being queried
2511 Irp is the Irp that makes this request
2513 GuidIndex is the index into the list of guids provided when the
2516 DataItemId has the id of the data item being set
2518 BufferSize has the size of the data item passed
2520 Buffer has the new values for the data item
2533 DebugPrint((3, "Disk: DiskSetWmiDataItem, Device %p, Irp %p, GuiIndex %d, DataId %d\n"
2534 " BufferSize %#x Buffer %p\n",
2536 GuidIndex
, DataItemId
, BufferSize
, Buffer
));
2538 if (GuidIndex
<= SmartEventGuid
)
2540 status
= STATUS_WMI_READ_ONLY
;
2542 status
= STATUS_WMI_GUID_NOT_FOUND
;
2545 DebugPrint((3, "Disk: DiskSetWmiDataItem Device %p, Irp %p returns %lx\n",
2546 DeviceObject
, Irp
, status
));
2548 status
= ClassWmiCompleteRequest(DeviceObject
,
2559 DiskFdoExecuteWmiMethod(
2560 IN PDEVICE_OBJECT DeviceObject
,
2564 IN ULONG InBufferSize
,
2565 IN ULONG OutBufferSize
,
2570 Routine Description:
2572 This routine is a callback into the driver to execute a method. When the
2573 driver has finished filling the data block it must call
2574 ClassWmiCompleteRequest to complete the irp. The driver can
2575 return STATUS_PENDING if the irp cannot be completed immediately.
2579 DeviceObject is the device whose data block is being queried
2581 Irp is the Irp that makes this request
2583 GuidIndex is the index into the list of guids provided when the
2586 MethodId has the id of the method being called
2588 InBufferSize has the size of the data block passed in as the input to
2591 OutBufferSize on entry has the maximum size available to write the
2592 returned data block.
2594 Buffer is filled with the returned data block
2603 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
2604 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
2605 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
2611 DebugPrint((3, "Disk: DiskExecuteWmiMethod, DeviceObject %p, Irp %p, Guid Id %d, MethodId %d\n"
2612 " InBufferSize %#x, OutBufferSize %#x, Buffer %p\n",
2614 GuidIndex
, MethodId
, InBufferSize
, OutBufferSize
, Buffer
));
2618 case SmartPerformFunction
:
2621 ASSERT((diskData
->FailurePredictionCapability
==
2622 FailurePredictionSmart
) ||
2623 (diskData
->FailurePredictionCapability
==
2624 FailurePredictionIoctl
) ||
2625 (diskData
->FailurePredictionCapability
==
2626 FailurePredictionSense
));
2632 // void AllowPerformanceHit([in] boolean Allow)
2634 case AllowDisallowPerformanceHit
:
2636 BOOLEAN allowPerfHit
;
2639 if (InBufferSize
>= sizeof(BOOLEAN
))
2641 status
= STATUS_SUCCESS
;
2643 allowPerfHit
= *((PBOOLEAN
)Buffer
);
2644 if (diskData
->AllowFPPerfHit
!= allowPerfHit
)
2646 diskData
->AllowFPPerfHit
= allowPerfHit
;
2647 if (diskData
->FailurePredictionCapability
==
2648 FailurePredictionSense
)
2650 MODE_INFO_EXCEPTIONS modeInfo
;
2652 status
= DiskGetInfoExceptionInformation(fdoExtension
,
2654 if (NT_SUCCESS(status
))
2656 modeInfo
.Perf
= allowPerfHit
? 0 : 1;
2657 status
= DiskSetInfoExceptionInformation(fdoExtension
,
2663 DebugPrint((3, "DiskFdoWmiExecuteMethod: AllowPerformanceHit %x for device %p --> %lx\n",
2665 fdoExtension
->DeviceObject
,
2668 status
= STATUS_INVALID_PARAMETER
;
2674 // void EnableDisableHardwareFailurePrediction([in] boolean Enable)
2676 case EnableDisableHardwareFailurePrediction
:
2681 if (InBufferSize
>= sizeof(BOOLEAN
))
2683 status
= STATUS_SUCCESS
;
2684 enable
= *((PBOOLEAN
)Buffer
);
2688 // If we are disabling we need to also disable
2691 DiskEnableDisableFailurePredictPolling(
2697 status
= DiskEnableDisableFailurePrediction(
2701 DebugPrint((3, "DiskFdoWmiExecuteMethod: EnableDisableHardwareFailurePrediction: %x for device %p --> %lx\n",
2703 fdoExtension
->DeviceObject
,
2706 status
= STATUS_INVALID_PARAMETER
;
2712 // void EnableDisableFailurePredictionPolling(
2713 // [in] uint32 Period,
2714 // [in] boolean Enable)
2716 case EnableDisableFailurePredictionPolling
:
2722 if (InBufferSize
>= (sizeof(ULONG
) + sizeof(BOOLEAN
)))
2724 period
= *((PULONG
)Buffer
);
2725 Buffer
+= sizeof(ULONG
);
2726 enable
= *((PBOOLEAN
)Buffer
);
2728 status
= DiskEnableDisableFailurePredictPolling(
2733 DebugPrint((3, "DiskFdoWmiExecuteMethod: EnableDisableFailurePredictionPolling: %x %x for device %p --> %lx\n",
2736 fdoExtension
->DeviceObject
,
2739 status
= STATUS_INVALID_PARAMETER
;
2745 // void GetFailurePredictionCapability([out] uint32 Capability)
2747 case GetFailurePredictionCapability
:
2749 sizeNeeded
= sizeof(ULONG
);
2750 if (OutBufferSize
>= sizeNeeded
)
2752 status
= STATUS_SUCCESS
;
2753 *((PFAILURE_PREDICTION_METHOD
)Buffer
) = diskData
->FailurePredictionCapability
;
2754 DebugPrint((3, "DiskFdoWmiExecuteMethod: GetFailurePredictionCapability: %x for device %p --> %lx\n",
2755 *((PFAILURE_PREDICTION_METHOD
)Buffer
),
2756 fdoExtension
->DeviceObject
,
2759 status
= STATUS_BUFFER_TOO_SMALL
;
2765 // void EnableOfflineDiags([out] boolean Success);
2767 case EnableOfflineDiags
:
2769 sizeNeeded
= sizeof(BOOLEAN
);
2770 if (OutBufferSize
>= sizeNeeded
)
2772 if (diskData
->FailurePredictionCapability
==
2773 FailurePredictionSmart
)
2776 // Initiate or resume offline diagnostics.
2777 // This may cause a loss of performance
2778 // to the disk, but mayincrease the amount
2779 // of disk checking.
2781 status
= DiskExecuteSmartDiagnostics(fdoExtension
,
2785 status
= STATUS_INVALID_DEVICE_REQUEST
;
2788 *((PBOOLEAN
)Buffer
) = NT_SUCCESS(status
);
2790 DebugPrint((3, "DiskFdoWmiExecuteMethod: EnableOfflineDiags for device %p --> %lx\n",
2791 fdoExtension
->DeviceObject
,
2794 status
= STATUS_BUFFER_TOO_SMALL
;
2800 // void ReadLogSectors([in] uint8 LogAddress,
2801 // [in] uint8 SectorCount,
2802 // [out] uint32 Length,
2803 // [out, WmiSizeIs("Length")] uint8 LogSectors[]
2806 case ReadLogSectors
:
2809 if (diskData
->FailurePredictionCapability
==
2810 FailurePredictionSmart
)
2812 if (InBufferSize
>= sizeof(READ_LOG_SECTORS_IN
))
2814 PREAD_LOG_SECTORS_IN inParams
;
2815 PREAD_LOG_SECTORS_OUT outParams
;
2818 inParams
= (PREAD_LOG_SECTORS_IN
)Buffer
;
2819 readSize
= inParams
->SectorCount
* SMART_LOG_SECTOR_SIZE
;
2820 sizeNeeded
= FIELD_OFFSET(READ_LOG_SECTORS_OUT
,
2821 LogSectors
) + readSize
;
2823 if (OutBufferSize
>= sizeNeeded
)
2825 outParams
= (PREAD_LOG_SECTORS_OUT
)Buffer
;
2826 status
= DiskReadSmartLog(fdoExtension
,
2827 inParams
->SectorCount
,
2828 inParams
->LogAddress
,
2829 outParams
->LogSectors
);
2831 if (NT_SUCCESS(status
))
2833 outParams
->Length
= readSize
;
2836 // SMART command failure is
2837 // indicated by successful
2838 // execution, but no data returned
2840 outParams
->Length
= 0;
2841 status
= STATUS_SUCCESS
;
2844 status
= STATUS_BUFFER_TOO_SMALL
;
2848 status
= STATUS_INVALID_PARAMETER
;
2851 status
= STATUS_INVALID_DEVICE_REQUEST
;
2856 // void WriteLogSectors([in] uint8 LogAddress,
2857 // [in] uint8 SectorCount,
2858 // [in] uint32 Length,
2859 // [in, WmiSizeIs("Length")] uint8 LogSectors[],
2860 // [out] boolean Success
2862 case WriteLogSectors
:
2865 if (diskData
->FailurePredictionCapability
==
2866 FailurePredictionSmart
)
2868 if (InBufferSize
>= FIELD_OFFSET(WRITE_LOG_SECTORS_IN
,
2871 PWRITE_LOG_SECTORS_IN inParams
;
2872 PWRITE_LOG_SECTORS_OUT outParams
;
2875 inParams
= (PWRITE_LOG_SECTORS_IN
)Buffer
;
2876 writeSize
= inParams
->SectorCount
* SMART_LOG_SECTOR_SIZE
;
2877 if (InBufferSize
>= (FIELD_OFFSET(WRITE_LOG_SECTORS_IN
,
2881 sizeNeeded
= sizeof(WRITE_LOG_SECTORS_OUT
);
2883 if (OutBufferSize
>= sizeNeeded
)
2885 outParams
= (PWRITE_LOG_SECTORS_OUT
)Buffer
;
2886 status
= DiskWriteSmartLog(fdoExtension
,
2887 inParams
->SectorCount
,
2888 inParams
->LogAddress
,
2889 inParams
->LogSectors
);
2891 if (NT_SUCCESS(status
))
2893 outParams
->Success
= TRUE
;
2895 outParams
->Success
= FALSE
;
2896 status
= STATUS_SUCCESS
;
2899 status
= STATUS_BUFFER_TOO_SMALL
;
2902 status
= STATUS_INVALID_PARAMETER
;
2905 status
= STATUS_INVALID_PARAMETER
;
2908 status
= STATUS_INVALID_DEVICE_REQUEST
;
2913 // void ExecuteSelfTest([in] uint8 Subcommand,
2915 // Values{"0", "1", "2"},
2916 // ValueMap{"Successful Completion",
2917 // "Captive Mode Required",
2918 // "Unsuccessful Completion"}
2920 // uint32 ReturnCode);
2921 case ExecuteSelfTest
:
2924 if (diskData
->FailurePredictionCapability
==
2925 FailurePredictionSmart
)
2927 if (InBufferSize
>= sizeof(EXECUTE_SELF_TEST_IN
))
2929 sizeNeeded
= sizeof(EXECUTE_SELF_TEST_OUT
);
2930 if (OutBufferSize
>= sizeNeeded
)
2932 PEXECUTE_SELF_TEST_IN inParam
;
2933 PEXECUTE_SELF_TEST_OUT outParam
;
2935 inParam
= (PEXECUTE_SELF_TEST_IN
)Buffer
;
2936 outParam
= (PEXECUTE_SELF_TEST_OUT
)Buffer
;
2938 if (DiskIsValidSmartSelfTest(inParam
->Subcommand
))
2940 status
= DiskExecuteSmartDiagnostics(fdoExtension
,
2941 inParam
->Subcommand
);
2942 if (NT_SUCCESS(status
))
2945 // Return self test executed
2946 // without a problem
2948 outParam
->ReturnCode
= 0;
2951 // Return Self test execution
2954 outParam
->ReturnCode
= 2;
2955 status
= STATUS_SUCCESS
;
2959 // If self test subcommand requires
2960 // captive mode then return that
2963 outParam
->ReturnCode
= 1;
2964 status
= STATUS_SUCCESS
;
2968 status
= STATUS_BUFFER_TOO_SMALL
;
2972 status
= STATUS_INVALID_PARAMETER
;
2975 status
= STATUS_INVALID_DEVICE_REQUEST
;
2984 status
= STATUS_WMI_ITEMID_NOT_FOUND
;
2992 case DiskGeometryGuid
:
2993 case SmartStatusGuid
:
2998 status
= STATUS_INVALID_DEVICE_REQUEST
;
3005 status
= STATUS_WMI_GUID_NOT_FOUND
;
3009 DebugPrint((3, "Disk: DiskExecuteMethod Device %p, Irp %p returns %lx\n",
3010 DeviceObject
, Irp
, status
));
3012 status
= ClassWmiCompleteRequest(DeviceObject
,
3024 // Enable this to add WMI support for PDOs
3026 DiskPdoQueryWmiRegInfo(
3027 IN PDEVICE_OBJECT DeviceObject
,
3028 OUT ULONG
*RegFlags
,
3029 OUT PUNICODE_STRING InstanceName
3033 Routine Description:
3035 This routine is a callback into the driver to retrieve the list of
3036 guids or data blocks that the driver wants to register with WMI. This
3037 routine may not pend or block. Driver should NOT call
3038 ClassWmiCompleteRequest.
3042 DeviceObject is the device whose data block is being queried
3044 *RegFlags returns with a set of flags that describe the guids being
3045 registered for this device. If the device wants enable and disable
3046 collection callbacks before receiving queries for the registered
3047 guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
3048 returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
3049 the instance name is determined from the PDO associated with the
3050 device object. Note that the PDO must have an associated devnode. If
3051 WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
3052 name for the device.
3054 InstanceName returns with the instance name for the guids if
3055 WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
3056 caller will call ExFreePool with the buffer returned.
3065 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
3066 PFUNCTIONAL_DEVICE_EXTENSION parentFunctionalExtension
;
3067 ANSI_STRING ansiString
;
3072 // We need to pick a name for PDOs since they do not have a devnode
3073 parentFunctionalExtension
= commonExtension
->PartitionZeroExtension
;
3075 "Disk(%d)_Partition(%d)_Start(%#I64x)_Length(%#I64x)",
3076 parentFunctionalExtension
->DeviceNumber
,
3077 commonExtension
->PartitionNumber
,
3078 commonExtension
->StartingOffset
.QuadPart
,
3079 commonExtension
->PartitionLength
.QuadPart
);
3080 RtlInitAnsiString(&ansiString
,
3083 status
= RtlAnsiStringToUnicodeString(InstanceName
,
3091 DiskPdoQueryWmiDataBlock(
3092 IN PDEVICE_OBJECT DeviceObject
,
3095 IN ULONG BufferAvail
,
3100 Routine Description:
3102 This routine is a callback into the driver to query for the contents of
3103 a data block. When the driver has finished filling the data block it
3104 must call ClassWmiCompleteRequest to complete the irp. The driver can
3105 return STATUS_PENDING if the irp cannot be completed immediately.
3109 DeviceObject is the device whose data block is being queried
3111 Irp is the Irp that makes this request
3113 GuidIndex is the index into the list of guids provided when the
3116 BufferAvail on has the maximum size available to write the data
3119 Buffer on return is filled with the returned data block
3129 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
3130 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
3133 DebugPrint((3, "Disk: DiskQueryWmiDataBlock, Device %p, Irp %p, GuiIndex %d\n"
3134 " BufferAvail %#x Buffer %p\n",
3136 GuidIndex
, BufferAvail
, Buffer
));
3142 sizeNeeded
= 4 * sizeof(ULONG
);
3143 if (BufferAvail
>= sizeNeeded
)
3145 RtlCopyMemory(Buffer
, DiskDummyData
, sizeNeeded
);
3146 status
= STATUS_SUCCESS
;
3148 status
= STATUS_BUFFER_TOO_SMALL
;
3155 status
= STATUS_WMI_GUID_NOT_FOUND
;
3159 DebugPrint((3, "Disk: DiskQueryWmiDataBlock Device %p, Irp %p returns %lx\n",
3160 DeviceObject
, Irp
, status
));
3162 status
= ClassWmiCompleteRequest(DeviceObject
,
3172 DiskPdoSetWmiDataBlock(
3173 IN PDEVICE_OBJECT DeviceObject
,
3176 IN ULONG BufferSize
,
3181 Routine Description:
3183 This routine is a callback into the driver to query for the contents of
3184 a data block. When the driver has finished filling the data block it
3185 must call ClassWmiCompleteRequest to complete the irp. The driver can
3186 return STATUS_PENDING if the irp cannot be completed immediately.
3190 DeviceObject is the device whose data block is being queried
3192 Irp is the Irp that makes this request
3194 GuidIndex is the index into the list of guids provided when the
3197 BufferSize has the size of the data block passed
3199 Buffer has the new values for the data block
3209 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
3212 DebugPrint((3, "Disk: DiskSetWmiDataBlock, Device %p, Irp %p, GuiIndex %d\n"
3213 " BufferSize %#x Buffer %p\n",
3215 GuidIndex
, BufferSize
, Buffer
));
3221 sizeNeeded
= 4 * sizeof(ULONG
);
3222 if (BufferSize
== sizeNeeded
)
3224 RtlCopyMemory(DiskDummyData
, Buffer
, sizeNeeded
);
3225 status
= STATUS_SUCCESS
;
3227 status
= STATUS_INFO_LENGTH_MISMATCH
;
3234 status
= STATUS_WMI_GUID_NOT_FOUND
;
3238 DebugPrint((3, "Disk: DiskSetWmiDataBlock Device %p, Irp %p returns %lx\n",
3239 DeviceObject
, Irp
, status
));
3241 status
= ClassWmiCompleteRequest(DeviceObject
,
3251 DiskPdoSetWmiDataItem(
3252 IN PDEVICE_OBJECT DeviceObject
,
3255 IN ULONG DataItemId
,
3256 IN ULONG BufferSize
,
3261 Routine Description:
3263 This routine is a callback into the driver to query for the contents of
3264 a data block. When the driver has finished filling the data block it
3265 must call ClassWmiCompleteRequest to complete the irp. The driver can
3266 return STATUS_PENDING if the irp cannot be completed immediately.
3270 DeviceObject is the device whose data block is being queried
3272 Irp is the Irp that makes this request
3274 GuidIndex is the index into the list of guids provided when the
3277 DataItemId has the id of the data item being set
3279 BufferSize has the size of the data item passed
3281 Buffer has the new values for the data item
3292 DebugPrint((3, "Disk: DiskSetWmiDataItem, Device %p, Irp %p, GuiIndex %d, DataId %d\n"
3293 " BufferSize %#x Buffer %p\n",
3295 GuidIndex
, DataItemId
, BufferSize
, Buffer
));
3301 if ((BufferSize
== sizeof(ULONG
)) &&
3304 DiskDummyData
[DataItemId
] = *((PULONG
)Buffer
);
3305 status
= STATUS_SUCCESS
;
3307 status
= STATUS_INVALID_DEVICE_REQUEST
;
3314 status
= STATUS_WMI_GUID_NOT_FOUND
;
3319 DebugPrint((3, "Disk: DiskSetWmiDataItem Device %p, Irp %p returns %lx\n",
3320 DeviceObject
, Irp
, status
));
3322 status
= ClassWmiCompleteRequest(DeviceObject
,
3333 DiskPdoExecuteWmiMethod(
3334 IN PDEVICE_OBJECT DeviceObject
,
3338 IN ULONG InBufferSize
,
3339 IN ULONG OutBufferSize
,
3344 Routine Description:
3346 This routine is a callback into the driver to execute a method. When the
3347 driver has finished filling the data block it must call
3348 ClassWmiCompleteRequest to complete the irp. The driver can
3349 return STATUS_PENDING if the irp cannot be completed immediately.
3353 DeviceObject is the device whose data block is being queried
3355 Irp is the Irp that makes this request
3357 GuidIndex is the index into the list of guids provided when the
3360 MethodId has the id of the method being called
3362 InBufferSize has the size of the data block passed in as the input to
3365 OutBufferSize on entry has the maximum size available to write the
3366 returned data block.
3368 Buffer is filled with the returned data block
3377 ULONG sizeNeeded
= 4 * sizeof(ULONG
);
3381 DebugPrint((3, "Disk: DiskExecuteWmiMethod, DeviceObject %p, Irp %p, Guid Id %d, MethodId %d\n"
3382 " InBufferSize %#x, OutBufferSize %#x, Buffer %p\n",
3384 GuidIndex
, MethodId
, InBufferSize
, OutBufferSize
, Buffer
));
3392 if (OutBufferSize
>= sizeNeeded
)
3395 if (InBufferSize
== sizeNeeded
)
3397 RtlCopyMemory(tempData
, Buffer
, sizeNeeded
);
3398 RtlCopyMemory(Buffer
, DiskDummyData
, sizeNeeded
);
3399 RtlCopyMemory(DiskDummyData
, tempData
, sizeNeeded
);
3401 status
= STATUS_SUCCESS
;
3403 status
= STATUS_INVALID_DEVICE_REQUEST
;
3406 status
= STATUS_BUFFER_TOO_SMALL
;
3409 status
= STATUS_INVALID_DEVICE_REQUEST
;
3416 status
= STATUS_WMI_GUID_NOT_FOUND
;
3420 DebugPrint((3, "Disk: DiskExecuteMethod Device %p, Irp %p returns %lx\n",
3421 DeviceObject
, Irp
, status
));
3423 status
= ClassWmiCompleteRequest(DeviceObject
,