xref: /reactos/drivers/storage/class/disk/diskwmi.c (revision 3088717b)
1*3088717bSVictor Perevertkin /*++
2*3088717bSVictor Perevertkin 
3*3088717bSVictor Perevertkin Copyright (C) Microsoft Corporation, 1991 - 2010
4*3088717bSVictor Perevertkin 
5*3088717bSVictor Perevertkin Module Name:
6*3088717bSVictor Perevertkin 
7*3088717bSVictor Perevertkin     diskwmi.c
8*3088717bSVictor Perevertkin 
9*3088717bSVictor Perevertkin Abstract:
10*3088717bSVictor Perevertkin 
11*3088717bSVictor Perevertkin     SCSI disk class driver - WMI support routines
12*3088717bSVictor Perevertkin 
13*3088717bSVictor Perevertkin Environment:
14*3088717bSVictor Perevertkin 
15*3088717bSVictor Perevertkin     kernel mode only
16*3088717bSVictor Perevertkin 
17*3088717bSVictor Perevertkin Notes:
18*3088717bSVictor Perevertkin 
19*3088717bSVictor Perevertkin Revision History:
20*3088717bSVictor Perevertkin 
21*3088717bSVictor Perevertkin --*/
22*3088717bSVictor Perevertkin 
23*3088717bSVictor Perevertkin #include "disk.h"
24*3088717bSVictor Perevertkin 
25*3088717bSVictor Perevertkin #ifdef DEBUG_USE_WPP
26*3088717bSVictor Perevertkin #include "diskwmi.tmh"
27*3088717bSVictor Perevertkin #endif
28*3088717bSVictor Perevertkin 
29*3088717bSVictor Perevertkin NTSTATUS
30*3088717bSVictor Perevertkin DiskSendFailurePredictIoctl(
31*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
32*3088717bSVictor Perevertkin     PSTORAGE_PREDICT_FAILURE checkFailure
33*3088717bSVictor Perevertkin     );
34*3088717bSVictor Perevertkin 
35*3088717bSVictor Perevertkin NTSTATUS
36*3088717bSVictor Perevertkin DiskGetIdentifyInfo(
37*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
38*3088717bSVictor Perevertkin     PBOOLEAN SupportSmart
39*3088717bSVictor Perevertkin     );
40*3088717bSVictor Perevertkin 
41*3088717bSVictor Perevertkin NTSTATUS
42*3088717bSVictor Perevertkin DiskDetectFailurePrediction(
43*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
44*3088717bSVictor Perevertkin     PFAILURE_PREDICTION_METHOD FailurePredictCapability,
45*3088717bSVictor Perevertkin     BOOLEAN ScsiAddressAvailable
46*3088717bSVictor Perevertkin     );
47*3088717bSVictor Perevertkin 
48*3088717bSVictor Perevertkin NTSTATUS
49*3088717bSVictor Perevertkin DiskReadFailurePredictThresholds(
50*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
51*3088717bSVictor Perevertkin     PSTORAGE_FAILURE_PREDICT_THRESHOLDS DiskSmartThresholds
52*3088717bSVictor Perevertkin     );
53*3088717bSVictor Perevertkin 
54*3088717bSVictor Perevertkin NTSTATUS
55*3088717bSVictor Perevertkin DiskReadSmartLog(
56*3088717bSVictor Perevertkin     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
57*3088717bSVictor Perevertkin     IN UCHAR SectorCount,
58*3088717bSVictor Perevertkin     IN UCHAR LogAddress,
59*3088717bSVictor Perevertkin     OUT PUCHAR Buffer
60*3088717bSVictor Perevertkin     );
61*3088717bSVictor Perevertkin 
62*3088717bSVictor Perevertkin NTSTATUS
63*3088717bSVictor Perevertkin DiskWriteSmartLog(
64*3088717bSVictor Perevertkin     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
65*3088717bSVictor Perevertkin     IN UCHAR SectorCount,
66*3088717bSVictor Perevertkin     IN UCHAR LogAddress,
67*3088717bSVictor Perevertkin     IN PUCHAR Buffer
68*3088717bSVictor Perevertkin     );
69*3088717bSVictor Perevertkin 
70*3088717bSVictor Perevertkin IO_WORKITEM_ROUTINE DiskReregWorker;
71*3088717bSVictor Perevertkin 
72*3088717bSVictor Perevertkin IO_COMPLETION_ROUTINE DiskInfoExceptionComplete;
73*3088717bSVictor Perevertkin 
74*3088717bSVictor Perevertkin //
75*3088717bSVictor Perevertkin // WMI reregistration globals
76*3088717bSVictor Perevertkin //
77*3088717bSVictor Perevertkin // Since it will take too long to do a mode sense on some drive, we
78*3088717bSVictor Perevertkin // need a good way to effect the mode sense for the info exceptions
79*3088717bSVictor Perevertkin // mode page so that we can determine if SMART is supported and enabled
80*3088717bSVictor Perevertkin // for the drive. So the strategy is to do an asynchronous mode sense
81*3088717bSVictor Perevertkin // when the device starts and then look at the info exceptions mode
82*3088717bSVictor Perevertkin // page within the completion routine. Now within the completion
83*3088717bSVictor Perevertkin // routine we cannot call IoWMIRegistrationControl since we are at DPC
84*3088717bSVictor Perevertkin // level, so we create a stack of device objects that will be processed
85*3088717bSVictor Perevertkin // by a single work item that is fired off only when the stack
86*3088717bSVictor Perevertkin // transitions from empty to non empty.
87*3088717bSVictor Perevertkin //
88*3088717bSVictor Perevertkin SINGLE_LIST_ENTRY DiskReregHead;
89*3088717bSVictor Perevertkin KSPIN_LOCK DiskReregSpinlock;
90*3088717bSVictor Perevertkin LONG DiskReregWorkItems;
91*3088717bSVictor Perevertkin 
92*3088717bSVictor Perevertkin GUIDREGINFO DiskWmiFdoGuidList[] =
93*3088717bSVictor Perevertkin {
94*3088717bSVictor Perevertkin     {
95*3088717bSVictor Perevertkin         WMI_DISK_GEOMETRY_GUID,
96*3088717bSVictor Perevertkin         1,
97*3088717bSVictor Perevertkin         0
98*3088717bSVictor Perevertkin     },
99*3088717bSVictor Perevertkin 
100*3088717bSVictor Perevertkin     {
101*3088717bSVictor Perevertkin         WMI_STORAGE_FAILURE_PREDICT_STATUS_GUID,
102*3088717bSVictor Perevertkin         1,
103*3088717bSVictor Perevertkin         WMIREG_FLAG_EXPENSIVE
104*3088717bSVictor Perevertkin     },
105*3088717bSVictor Perevertkin 
106*3088717bSVictor Perevertkin     {
107*3088717bSVictor Perevertkin         WMI_STORAGE_FAILURE_PREDICT_DATA_GUID,
108*3088717bSVictor Perevertkin         1,
109*3088717bSVictor Perevertkin         WMIREG_FLAG_EXPENSIVE
110*3088717bSVictor Perevertkin     },
111*3088717bSVictor Perevertkin 
112*3088717bSVictor Perevertkin     {
113*3088717bSVictor Perevertkin         WMI_STORAGE_FAILURE_PREDICT_FUNCTION_GUID,
114*3088717bSVictor Perevertkin         1,
115*3088717bSVictor Perevertkin         WMIREG_FLAG_EXPENSIVE
116*3088717bSVictor Perevertkin     },
117*3088717bSVictor Perevertkin 
118*3088717bSVictor Perevertkin     {
119*3088717bSVictor Perevertkin         WMI_STORAGE_PREDICT_FAILURE_EVENT_GUID,
120*3088717bSVictor Perevertkin         1,
121*3088717bSVictor Perevertkin         WMIREG_FLAG_EVENT_ONLY_GUID
122*3088717bSVictor Perevertkin     },
123*3088717bSVictor Perevertkin 
124*3088717bSVictor Perevertkin     {
125*3088717bSVictor Perevertkin         WMI_STORAGE_FAILURE_PREDICT_THRESHOLDS_GUID,
126*3088717bSVictor Perevertkin         1,
127*3088717bSVictor Perevertkin         WMIREG_FLAG_EXPENSIVE
128*3088717bSVictor Perevertkin     },
129*3088717bSVictor Perevertkin 
130*3088717bSVictor Perevertkin     {
131*3088717bSVictor Perevertkin         WMI_STORAGE_SCSI_INFO_EXCEPTIONS_GUID,
132*3088717bSVictor Perevertkin         1,
133*3088717bSVictor Perevertkin         0
134*3088717bSVictor Perevertkin     }
135*3088717bSVictor Perevertkin };
136*3088717bSVictor Perevertkin 
137*3088717bSVictor Perevertkin 
138*3088717bSVictor Perevertkin GUID DiskPredictFailureEventGuid = WMI_STORAGE_PREDICT_FAILURE_EVENT_GUID;
139*3088717bSVictor Perevertkin 
140*3088717bSVictor Perevertkin #define DiskGeometryGuid           0
141*3088717bSVictor Perevertkin #define SmartStatusGuid            1
142*3088717bSVictor Perevertkin #define SmartDataGuid              2
143*3088717bSVictor Perevertkin #define SmartPerformFunction       3
144*3088717bSVictor Perevertkin     #define AllowDisallowPerformanceHit                 1
145*3088717bSVictor Perevertkin     #define EnableDisableHardwareFailurePrediction      2
146*3088717bSVictor Perevertkin     #define EnableDisableFailurePredictionPolling       3
147*3088717bSVictor Perevertkin     #define GetFailurePredictionCapability              4
148*3088717bSVictor Perevertkin     #define EnableOfflineDiags                          5
149*3088717bSVictor Perevertkin 
150*3088717bSVictor Perevertkin #define SmartEventGuid             4
151*3088717bSVictor Perevertkin #define SmartThresholdsGuid        5
152*3088717bSVictor Perevertkin #define ScsiInfoExceptionsGuid     6
153*3088717bSVictor Perevertkin 
154*3088717bSVictor Perevertkin #ifdef ALLOC_PRAGMA
155*3088717bSVictor Perevertkin 
156*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskWmiFunctionControl)
157*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskFdoQueryWmiRegInfo)
158*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskFdoQueryWmiDataBlock)
159*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskFdoSetWmiDataBlock)
160*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskFdoSetWmiDataItem)
161*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskFdoExecuteWmiMethod)
162*3088717bSVictor Perevertkin 
163*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskDetectFailurePrediction)
164*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskEnableDisableFailurePrediction)
165*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskEnableDisableFailurePredictPolling)
166*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskReadFailurePredictStatus)
167*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskReadFailurePredictData)
168*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskReadFailurePredictThresholds)
169*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskGetIdentifyInfo)
170*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskReadSmartLog)
171*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskWriteSmartLog)
172*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskPerformSmartCommand)
173*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskSendFailurePredictIoctl)
174*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskReregWorker)
175*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskInitializeReregistration)
176*3088717bSVictor Perevertkin 
177*3088717bSVictor Perevertkin #if (NTDDI_VERSION >= NTDDI_WINBLUE)
178*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskGetModePage)
179*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DiskEnableInfoExceptions)
180*3088717bSVictor Perevertkin #endif // (NTDDI_VERSION >= NTDDI_WINBLUE)
181*3088717bSVictor Perevertkin 
182*3088717bSVictor Perevertkin #endif
183*3088717bSVictor Perevertkin 
184*3088717bSVictor Perevertkin 
185*3088717bSVictor Perevertkin //
186*3088717bSVictor Perevertkin // Note:
187*3088717bSVictor Perevertkin // Some port drivers assume that the SENDCMDINPARAMS structure will always be atleast
188*3088717bSVictor Perevertkin // sizeof(SENDCMDINPARAMS). So do not adjust for the [pBuffer] if it isn't being used
189*3088717bSVictor Perevertkin //
190*3088717bSVictor Perevertkin 
191*3088717bSVictor Perevertkin //
192*3088717bSVictor Perevertkin // SMART/IDE specific routines
193*3088717bSVictor Perevertkin //
194*3088717bSVictor Perevertkin 
195*3088717bSVictor Perevertkin //
196*3088717bSVictor Perevertkin // Read SMART data attributes.
197*3088717bSVictor Perevertkin // SrbControl should be : sizeof(SRB_IO_CONTROL) + MAX[ sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + READ_ATTRIBUTE_BUFFER_SIZE ]
198*3088717bSVictor Perevertkin // Attribute data returned at &SendCmdOutParams->bBuffer[0]
199*3088717bSVictor Perevertkin //
200*3088717bSVictor Perevertkin #define DiskReadSmartData(FdoExtension,                                 \
201*3088717bSVictor Perevertkin                           SrbControl,                                   \
202*3088717bSVictor Perevertkin                           BufferSize)                                   \
203*3088717bSVictor Perevertkin     DiskPerformSmartCommand(FdoExtension,                               \
204*3088717bSVictor Perevertkin                             IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS,     \
205*3088717bSVictor Perevertkin                             SMART_CMD,                                  \
206*3088717bSVictor Perevertkin                             READ_ATTRIBUTES,                            \
207*3088717bSVictor Perevertkin                             0,                                          \
208*3088717bSVictor Perevertkin                             0,                                          \
209*3088717bSVictor Perevertkin                             (SrbControl),                               \
210*3088717bSVictor Perevertkin                             (BufferSize))
211*3088717bSVictor Perevertkin 
212*3088717bSVictor Perevertkin 
213*3088717bSVictor Perevertkin //
214*3088717bSVictor Perevertkin // Read SMART data thresholds.
215*3088717bSVictor Perevertkin // SrbControl should be : sizeof(SRB_IO_CONTROL) + MAX[ sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + READ_THRESHOLD_BUFFER_SIZE ]
216*3088717bSVictor Perevertkin // Attribute data returned at &SendCmdOutParams->bBuffer[0]
217*3088717bSVictor Perevertkin //
218*3088717bSVictor Perevertkin #define DiskReadSmartThresholds(FdoExtension,                           \
219*3088717bSVictor Perevertkin                                 SrbControl,                             \
220*3088717bSVictor Perevertkin                                 BufferSize)                             \
221*3088717bSVictor Perevertkin     DiskPerformSmartCommand(FdoExtension,                               \
222*3088717bSVictor Perevertkin                             IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS,  \
223*3088717bSVictor Perevertkin                             SMART_CMD,                                  \
224*3088717bSVictor Perevertkin                             READ_THRESHOLDS,                            \
225*3088717bSVictor Perevertkin                             0,                                          \
226*3088717bSVictor Perevertkin                             0,                                          \
227*3088717bSVictor Perevertkin                             (SrbControl),                               \
228*3088717bSVictor Perevertkin                             (BufferSize))
229*3088717bSVictor Perevertkin 
230*3088717bSVictor Perevertkin 
231*3088717bSVictor Perevertkin //
232*3088717bSVictor Perevertkin // Read SMART status
233*3088717bSVictor Perevertkin // SrbControl should be : sizeof(SRB_IO_CONTROL) + MAX[ sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS) ]
234*3088717bSVictor Perevertkin // Failure predicted if SendCmdOutParams->bBuffer[3] == 0xf4 and SendCmdOutParams->bBuffer[4] == 0x2c
235*3088717bSVictor Perevertkin //
236*3088717bSVictor Perevertkin #define DiskReadSmartStatus(FdoExtension,                               \
237*3088717bSVictor Perevertkin                             SrbControl,                                 \
238*3088717bSVictor Perevertkin                             BufferSize)                                 \
239*3088717bSVictor Perevertkin     DiskPerformSmartCommand(FdoExtension,                               \
240*3088717bSVictor Perevertkin                             IOCTL_SCSI_MINIPORT_RETURN_STATUS,          \
241*3088717bSVictor Perevertkin                             SMART_CMD,                                  \
242*3088717bSVictor Perevertkin                             RETURN_SMART_STATUS,                        \
243*3088717bSVictor Perevertkin                             0,                                          \
244*3088717bSVictor Perevertkin                             0,                                          \
245*3088717bSVictor Perevertkin                             (SrbControl),                               \
246*3088717bSVictor Perevertkin                             (BufferSize))
247*3088717bSVictor Perevertkin 
248*3088717bSVictor Perevertkin 
249*3088717bSVictor Perevertkin //
250*3088717bSVictor Perevertkin // Read disks IDENTIFY data
251*3088717bSVictor Perevertkin // SrbControl should be : sizeof(SRB_IO_CONTROL) + MAX[ sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE ]
252*3088717bSVictor Perevertkin // Identify data returned at &SendCmdOutParams->bBuffer[0]
253*3088717bSVictor Perevertkin //
254*3088717bSVictor Perevertkin #define DiskGetIdentifyData(FdoExtension,                               \
255*3088717bSVictor Perevertkin                             SrbControl,                                 \
256*3088717bSVictor Perevertkin                             BufferSize)                                 \
257*3088717bSVictor Perevertkin     DiskPerformSmartCommand(FdoExtension,                               \
258*3088717bSVictor Perevertkin                             IOCTL_SCSI_MINIPORT_IDENTIFY,               \
259*3088717bSVictor Perevertkin                             ID_CMD,                                     \
260*3088717bSVictor Perevertkin                             0,                                          \
261*3088717bSVictor Perevertkin                             0,                                          \
262*3088717bSVictor Perevertkin                             0,                                          \
263*3088717bSVictor Perevertkin                             (SrbControl),                               \
264*3088717bSVictor Perevertkin                             (BufferSize))
265*3088717bSVictor Perevertkin 
266*3088717bSVictor Perevertkin 
267*3088717bSVictor Perevertkin //
268*3088717bSVictor Perevertkin // Enable SMART
269*3088717bSVictor Perevertkin //
270*3088717bSVictor Perevertkin static NTSTATUS
DiskEnableSmart(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)271*3088717bSVictor Perevertkin DiskEnableSmart(
272*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
273*3088717bSVictor Perevertkin     )
274*3088717bSVictor Perevertkin {
275*3088717bSVictor Perevertkin     UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0};
276*3088717bSVictor Perevertkin     ULONG bufferSize = sizeof(srbControl);
277*3088717bSVictor Perevertkin 
278*3088717bSVictor Perevertkin     return DiskPerformSmartCommand(FdoExtension,
279*3088717bSVictor Perevertkin                                    IOCTL_SCSI_MINIPORT_ENABLE_SMART,
280*3088717bSVictor Perevertkin                                    SMART_CMD,
281*3088717bSVictor Perevertkin                                    ENABLE_SMART,
282*3088717bSVictor Perevertkin                                    0,
283*3088717bSVictor Perevertkin                                    0,
284*3088717bSVictor Perevertkin                                    (PSRB_IO_CONTROL)srbControl,
285*3088717bSVictor Perevertkin                                    &bufferSize);
286*3088717bSVictor Perevertkin }
287*3088717bSVictor Perevertkin 
288*3088717bSVictor Perevertkin 
289*3088717bSVictor Perevertkin //
290*3088717bSVictor Perevertkin // Disable SMART
291*3088717bSVictor Perevertkin //
292*3088717bSVictor Perevertkin static NTSTATUS
DiskDisableSmart(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)293*3088717bSVictor Perevertkin DiskDisableSmart(
294*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
295*3088717bSVictor Perevertkin     )
296*3088717bSVictor Perevertkin {
297*3088717bSVictor Perevertkin     UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0};
298*3088717bSVictor Perevertkin     ULONG bufferSize = sizeof(srbControl);
299*3088717bSVictor Perevertkin 
300*3088717bSVictor Perevertkin     return DiskPerformSmartCommand(FdoExtension,
301*3088717bSVictor Perevertkin                                    IOCTL_SCSI_MINIPORT_DISABLE_SMART,
302*3088717bSVictor Perevertkin                                    SMART_CMD,
303*3088717bSVictor Perevertkin                                    DISABLE_SMART,
304*3088717bSVictor Perevertkin                                    0,
305*3088717bSVictor Perevertkin                                    0,
306*3088717bSVictor Perevertkin                                    (PSRB_IO_CONTROL)srbControl,
307*3088717bSVictor Perevertkin                                    &bufferSize);
308*3088717bSVictor Perevertkin }
309*3088717bSVictor Perevertkin 
310*3088717bSVictor Perevertkin #ifndef __REACTOS__ // functions are not used
311*3088717bSVictor Perevertkin //
312*3088717bSVictor Perevertkin // Enable Attribute Autosave
313*3088717bSVictor Perevertkin //
314*3088717bSVictor Perevertkin _inline NTSTATUS
DiskEnableSmartAttributeAutosave(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)315*3088717bSVictor Perevertkin DiskEnableSmartAttributeAutosave(
316*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
317*3088717bSVictor Perevertkin     )
318*3088717bSVictor Perevertkin {
319*3088717bSVictor Perevertkin     UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0};
320*3088717bSVictor Perevertkin     ULONG bufferSize = sizeof(srbControl);
321*3088717bSVictor Perevertkin 
322*3088717bSVictor Perevertkin     return DiskPerformSmartCommand(FdoExtension,
323*3088717bSVictor Perevertkin                                    IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE,
324*3088717bSVictor Perevertkin                                    SMART_CMD,
325*3088717bSVictor Perevertkin                                    ENABLE_DISABLE_AUTOSAVE,
326*3088717bSVictor Perevertkin                                    0xf1,
327*3088717bSVictor Perevertkin                                    0,
328*3088717bSVictor Perevertkin                                    (PSRB_IO_CONTROL)srbControl,
329*3088717bSVictor Perevertkin                                    &bufferSize);
330*3088717bSVictor Perevertkin }
331*3088717bSVictor Perevertkin 
332*3088717bSVictor Perevertkin 
333*3088717bSVictor Perevertkin //
334*3088717bSVictor Perevertkin // Disable Attribute Autosave
335*3088717bSVictor Perevertkin //
336*3088717bSVictor Perevertkin _inline NTSTATUS
DiskDisableSmartAttributeAutosave(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)337*3088717bSVictor Perevertkin DiskDisableSmartAttributeAutosave(
338*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
339*3088717bSVictor Perevertkin     )
340*3088717bSVictor Perevertkin {
341*3088717bSVictor Perevertkin     UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0};
342*3088717bSVictor Perevertkin     ULONG bufferSize = sizeof(srbControl);
343*3088717bSVictor Perevertkin 
344*3088717bSVictor Perevertkin     return DiskPerformSmartCommand(FdoExtension,
345*3088717bSVictor Perevertkin                                    IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE,
346*3088717bSVictor Perevertkin                                    SMART_CMD,
347*3088717bSVictor Perevertkin                                    ENABLE_DISABLE_AUTOSAVE,
348*3088717bSVictor Perevertkin                                    0x00,
349*3088717bSVictor Perevertkin                                    0,
350*3088717bSVictor Perevertkin                                    (PSRB_IO_CONTROL)srbControl,
351*3088717bSVictor Perevertkin                                    &bufferSize);
352*3088717bSVictor Perevertkin }
353*3088717bSVictor Perevertkin #endif
354*3088717bSVictor Perevertkin 
355*3088717bSVictor Perevertkin //
356*3088717bSVictor Perevertkin // Initialize execution of SMART online diagnostics
357*3088717bSVictor Perevertkin //
358*3088717bSVictor Perevertkin static NTSTATUS
DiskExecuteSmartDiagnostics(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,UCHAR Subcommand)359*3088717bSVictor Perevertkin DiskExecuteSmartDiagnostics(
360*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
361*3088717bSVictor Perevertkin     UCHAR Subcommand
362*3088717bSVictor Perevertkin     )
363*3088717bSVictor Perevertkin {
364*3088717bSVictor Perevertkin     UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0};
365*3088717bSVictor Perevertkin     ULONG bufferSize = sizeof(srbControl);
366*3088717bSVictor Perevertkin 
367*3088717bSVictor Perevertkin     return DiskPerformSmartCommand(FdoExtension,
368*3088717bSVictor Perevertkin                                    IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS,
369*3088717bSVictor Perevertkin                                    SMART_CMD,
370*3088717bSVictor Perevertkin                                    EXECUTE_OFFLINE_DIAGS,
371*3088717bSVictor Perevertkin                                    0,
372*3088717bSVictor Perevertkin                                    Subcommand,
373*3088717bSVictor Perevertkin                                    (PSRB_IO_CONTROL)srbControl,
374*3088717bSVictor Perevertkin                                    &bufferSize);
375*3088717bSVictor Perevertkin }
376*3088717bSVictor Perevertkin 
377*3088717bSVictor Perevertkin 
378*3088717bSVictor Perevertkin NTSTATUS
DiskReadSmartLog(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN UCHAR SectorCount,IN UCHAR LogAddress,OUT PUCHAR Buffer)379*3088717bSVictor Perevertkin DiskReadSmartLog(
380*3088717bSVictor Perevertkin     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
381*3088717bSVictor Perevertkin     IN UCHAR SectorCount,
382*3088717bSVictor Perevertkin     IN UCHAR LogAddress,
383*3088717bSVictor Perevertkin     OUT PUCHAR Buffer
384*3088717bSVictor Perevertkin     )
385*3088717bSVictor Perevertkin {
386*3088717bSVictor Perevertkin     PSRB_IO_CONTROL srbControl;
387*3088717bSVictor Perevertkin     NTSTATUS status;
388*3088717bSVictor Perevertkin     PSENDCMDOUTPARAMS sendCmdOutParams;
389*3088717bSVictor Perevertkin     ULONG logSize, bufferSize;
390*3088717bSVictor Perevertkin 
391*3088717bSVictor Perevertkin     PAGED_CODE();
392*3088717bSVictor Perevertkin 
393*3088717bSVictor Perevertkin     logSize = SectorCount * SMART_LOG_SECTOR_SIZE;
394*3088717bSVictor Perevertkin     bufferSize = sizeof(SRB_IO_CONTROL) +  max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + logSize );
395*3088717bSVictor Perevertkin 
396*3088717bSVictor Perevertkin     srbControl = ExAllocatePoolWithTag(NonPagedPoolNx,
397*3088717bSVictor Perevertkin                                        bufferSize,
398*3088717bSVictor Perevertkin                                        DISK_TAG_SMART);
399*3088717bSVictor Perevertkin 
400*3088717bSVictor Perevertkin     if (srbControl != NULL)
401*3088717bSVictor Perevertkin     {
402*3088717bSVictor Perevertkin         status = DiskPerformSmartCommand(FdoExtension,
403*3088717bSVictor Perevertkin                                          IOCTL_SCSI_MINIPORT_READ_SMART_LOG,
404*3088717bSVictor Perevertkin                                          SMART_CMD,
405*3088717bSVictor Perevertkin                                          SMART_READ_LOG,
406*3088717bSVictor Perevertkin                                          SectorCount,
407*3088717bSVictor Perevertkin                                          LogAddress,
408*3088717bSVictor Perevertkin                                          srbControl,
409*3088717bSVictor Perevertkin                                          &bufferSize);
410*3088717bSVictor Perevertkin 
411*3088717bSVictor Perevertkin         if (NT_SUCCESS(status))
412*3088717bSVictor Perevertkin         {
413*3088717bSVictor Perevertkin             sendCmdOutParams = (PSENDCMDOUTPARAMS)((PUCHAR)srbControl +
414*3088717bSVictor Perevertkin                                                    sizeof(SRB_IO_CONTROL));
415*3088717bSVictor Perevertkin             RtlCopyMemory(Buffer,
416*3088717bSVictor Perevertkin                           &sendCmdOutParams->bBuffer[0],
417*3088717bSVictor Perevertkin                           logSize);
418*3088717bSVictor Perevertkin         }
419*3088717bSVictor Perevertkin 
420*3088717bSVictor Perevertkin         FREE_POOL(srbControl);
421*3088717bSVictor Perevertkin     } else {
422*3088717bSVictor Perevertkin         status = STATUS_INSUFFICIENT_RESOURCES;
423*3088717bSVictor Perevertkin     }
424*3088717bSVictor Perevertkin     return(status);
425*3088717bSVictor Perevertkin }
426*3088717bSVictor Perevertkin 
427*3088717bSVictor Perevertkin 
428*3088717bSVictor Perevertkin NTSTATUS
DiskWriteSmartLog(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN UCHAR SectorCount,IN UCHAR LogAddress,IN PUCHAR Buffer)429*3088717bSVictor Perevertkin DiskWriteSmartLog(
430*3088717bSVictor Perevertkin     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
431*3088717bSVictor Perevertkin     IN UCHAR SectorCount,
432*3088717bSVictor Perevertkin     IN UCHAR LogAddress,
433*3088717bSVictor Perevertkin     IN PUCHAR Buffer
434*3088717bSVictor Perevertkin     )
435*3088717bSVictor Perevertkin {
436*3088717bSVictor Perevertkin     PSRB_IO_CONTROL srbControl;
437*3088717bSVictor Perevertkin     NTSTATUS status;
438*3088717bSVictor Perevertkin     PSENDCMDINPARAMS sendCmdInParams;
439*3088717bSVictor Perevertkin     ULONG logSize, bufferSize;
440*3088717bSVictor Perevertkin 
441*3088717bSVictor Perevertkin     PAGED_CODE();
442*3088717bSVictor Perevertkin 
443*3088717bSVictor Perevertkin     logSize = SectorCount * SMART_LOG_SECTOR_SIZE;
444*3088717bSVictor Perevertkin     bufferSize = sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1 +
445*3088717bSVictor Perevertkin                  logSize;
446*3088717bSVictor Perevertkin 
447*3088717bSVictor Perevertkin     srbControl = ExAllocatePoolWithTag(NonPagedPoolNx,
448*3088717bSVictor Perevertkin                                        bufferSize,
449*3088717bSVictor Perevertkin                                        DISK_TAG_SMART);
450*3088717bSVictor Perevertkin 
451*3088717bSVictor Perevertkin     if (srbControl != NULL)
452*3088717bSVictor Perevertkin     {
453*3088717bSVictor Perevertkin         sendCmdInParams = (PSENDCMDINPARAMS)((PUCHAR)srbControl +
454*3088717bSVictor Perevertkin                                                sizeof(SRB_IO_CONTROL));
455*3088717bSVictor Perevertkin         RtlCopyMemory(&sendCmdInParams->bBuffer[0],
456*3088717bSVictor Perevertkin                       Buffer,
457*3088717bSVictor Perevertkin                       logSize);
458*3088717bSVictor Perevertkin         status = DiskPerformSmartCommand(FdoExtension,
459*3088717bSVictor Perevertkin                                          IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG,
460*3088717bSVictor Perevertkin                                          SMART_CMD,
461*3088717bSVictor Perevertkin                                          SMART_WRITE_LOG,
462*3088717bSVictor Perevertkin                                          SectorCount,
463*3088717bSVictor Perevertkin                                          LogAddress,
464*3088717bSVictor Perevertkin                                          srbControl,
465*3088717bSVictor Perevertkin                                          &bufferSize);
466*3088717bSVictor Perevertkin 
467*3088717bSVictor Perevertkin         FREE_POOL(srbControl);
468*3088717bSVictor Perevertkin     } else {
469*3088717bSVictor Perevertkin         status = STATUS_INSUFFICIENT_RESOURCES;
470*3088717bSVictor Perevertkin     }
471*3088717bSVictor Perevertkin     return(status);
472*3088717bSVictor Perevertkin }
473*3088717bSVictor Perevertkin 
474*3088717bSVictor Perevertkin 
475*3088717bSVictor Perevertkin NTSTATUS
DiskPerformSmartCommand(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN ULONG SrbControlCode,IN UCHAR Command,IN UCHAR Feature,IN UCHAR SectorCount,IN UCHAR SectorNumber,IN OUT PSRB_IO_CONTROL SrbControl,OUT PULONG BufferSize)476*3088717bSVictor Perevertkin DiskPerformSmartCommand(
477*3088717bSVictor Perevertkin     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
478*3088717bSVictor Perevertkin     IN ULONG SrbControlCode,
479*3088717bSVictor Perevertkin     IN UCHAR Command,
480*3088717bSVictor Perevertkin     IN UCHAR Feature,
481*3088717bSVictor Perevertkin     IN UCHAR SectorCount,
482*3088717bSVictor Perevertkin     IN UCHAR SectorNumber,
483*3088717bSVictor Perevertkin     IN OUT PSRB_IO_CONTROL SrbControl,
484*3088717bSVictor Perevertkin     OUT PULONG BufferSize
485*3088717bSVictor Perevertkin     )
486*3088717bSVictor Perevertkin /*++
487*3088717bSVictor Perevertkin 
488*3088717bSVictor Perevertkin Routine Description:
489*3088717bSVictor Perevertkin 
490*3088717bSVictor Perevertkin     This routine will perform some SMART command
491*3088717bSVictor Perevertkin 
492*3088717bSVictor Perevertkin Arguments:
493*3088717bSVictor Perevertkin 
494*3088717bSVictor Perevertkin     FdoExtension is the FDO device extension
495*3088717bSVictor Perevertkin 
496*3088717bSVictor Perevertkin     SrbControlCode is the SRB control code to use for the request
497*3088717bSVictor Perevertkin 
498*3088717bSVictor Perevertkin     Command is the SMART command to be executed. It may be SMART_CMD or
499*3088717bSVictor Perevertkin         ID_CMD.
500*3088717bSVictor Perevertkin 
501*3088717bSVictor Perevertkin     Feature is the value to place in the IDE feature register.
502*3088717bSVictor Perevertkin 
503*3088717bSVictor Perevertkin     SectorCount is the value to place in the IDE SectorCount register
504*3088717bSVictor Perevertkin 
505*3088717bSVictor Perevertkin     SrbControl is the buffer used to build the SRB_IO_CONTROL and pass
506*3088717bSVictor Perevertkin         any input parameters. It also returns the output parameters.
507*3088717bSVictor Perevertkin 
508*3088717bSVictor Perevertkin     *BufferSize on entry has total size of SrbControl and on return has
509*3088717bSVictor Perevertkin         the size used in SrbControl.
510*3088717bSVictor Perevertkin 
511*3088717bSVictor Perevertkin 
512*3088717bSVictor Perevertkin 
513*3088717bSVictor Perevertkin Return Value:
514*3088717bSVictor Perevertkin 
515*3088717bSVictor Perevertkin     status
516*3088717bSVictor Perevertkin 
517*3088717bSVictor Perevertkin --*/
518*3088717bSVictor Perevertkin {
519*3088717bSVictor Perevertkin     PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
520*3088717bSVictor Perevertkin     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
521*3088717bSVictor Perevertkin     PUCHAR buffer;
522*3088717bSVictor Perevertkin     PSENDCMDINPARAMS cmdInParameters;
523*3088717bSVictor Perevertkin     NTSTATUS status;
524*3088717bSVictor Perevertkin     ULONG availableBufferSize;
525*3088717bSVictor Perevertkin     KEVENT event;
526*3088717bSVictor Perevertkin     PIRP irp;
527*3088717bSVictor Perevertkin     IO_STATUS_BLOCK ioStatus = { 0 };
528*3088717bSVictor Perevertkin     SCSI_REQUEST_BLOCK srb = {0};
529*3088717bSVictor Perevertkin     LARGE_INTEGER startingOffset;
530*3088717bSVictor Perevertkin     ULONG length;
531*3088717bSVictor Perevertkin     PIO_STACK_LOCATION irpStack;
532*3088717bSVictor Perevertkin     UCHAR srbExBuffer[CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE] = {0};
533*3088717bSVictor Perevertkin     PSTORAGE_REQUEST_BLOCK srbEx = (PSTORAGE_REQUEST_BLOCK)srbExBuffer;
534*3088717bSVictor Perevertkin     PSTOR_ADDR_BTL8 storAddrBtl8;
535*3088717bSVictor Perevertkin 
536*3088717bSVictor Perevertkin     PAGED_CODE();
537*3088717bSVictor Perevertkin 
538*3088717bSVictor Perevertkin     //
539*3088717bSVictor Perevertkin     // Point to the 'buffer' portion of the SRB_CONTROL and compute how
540*3088717bSVictor Perevertkin     // much room we have left in the srb control. Abort if the buffer
541*3088717bSVictor Perevertkin     // isn't at least the size of SRB_IO_CONTROL.
542*3088717bSVictor Perevertkin     //
543*3088717bSVictor Perevertkin 
544*3088717bSVictor Perevertkin     buffer = (PUCHAR)SrbControl + sizeof(SRB_IO_CONTROL);
545*3088717bSVictor Perevertkin 
546*3088717bSVictor Perevertkin     cmdInParameters = (PSENDCMDINPARAMS)buffer;
547*3088717bSVictor Perevertkin 
548*3088717bSVictor Perevertkin     if (*BufferSize >= sizeof(SRB_IO_CONTROL)) {
549*3088717bSVictor Perevertkin         availableBufferSize = *BufferSize - sizeof(SRB_IO_CONTROL);
550*3088717bSVictor Perevertkin     } else {
551*3088717bSVictor Perevertkin         return STATUS_BUFFER_TOO_SMALL;
552*3088717bSVictor Perevertkin     }
553*3088717bSVictor Perevertkin 
554*3088717bSVictor Perevertkin #if DBG
555*3088717bSVictor Perevertkin 
556*3088717bSVictor Perevertkin     //
557*3088717bSVictor Perevertkin     // Ensure control codes and buffer lengths passed are correct
558*3088717bSVictor Perevertkin     //
559*3088717bSVictor Perevertkin     {
560*3088717bSVictor Perevertkin         ULONG controlCode = 0;
561*3088717bSVictor Perevertkin         ULONG lengthNeeded = sizeof(SENDCMDINPARAMS);
562*3088717bSVictor Perevertkin 
563*3088717bSVictor Perevertkin         if (Command == SMART_CMD)
564*3088717bSVictor Perevertkin         {
565*3088717bSVictor Perevertkin             switch (Feature)
566*3088717bSVictor Perevertkin             {
567*3088717bSVictor Perevertkin                 case ENABLE_SMART:
568*3088717bSVictor Perevertkin                 {
569*3088717bSVictor Perevertkin                     controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
570*3088717bSVictor Perevertkin                     break;
571*3088717bSVictor Perevertkin                 }
572*3088717bSVictor Perevertkin 
573*3088717bSVictor Perevertkin                 case DISABLE_SMART:
574*3088717bSVictor Perevertkin                 {
575*3088717bSVictor Perevertkin                     controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
576*3088717bSVictor Perevertkin                     break;
577*3088717bSVictor Perevertkin                 }
578*3088717bSVictor Perevertkin 
579*3088717bSVictor Perevertkin                 case RETURN_SMART_STATUS:
580*3088717bSVictor Perevertkin                 {
581*3088717bSVictor Perevertkin                     controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
582*3088717bSVictor Perevertkin                     lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS) );
583*3088717bSVictor Perevertkin                     break;
584*3088717bSVictor Perevertkin                 }
585*3088717bSVictor Perevertkin 
586*3088717bSVictor Perevertkin                 case ENABLE_DISABLE_AUTOSAVE:
587*3088717bSVictor Perevertkin                 {
588*3088717bSVictor Perevertkin                     controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
589*3088717bSVictor Perevertkin                     break;
590*3088717bSVictor Perevertkin                 }
591*3088717bSVictor Perevertkin 
592*3088717bSVictor Perevertkin                 case SAVE_ATTRIBUTE_VALUES:
593*3088717bSVictor Perevertkin                 {
594*3088717bSVictor Perevertkin                     controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
595*3088717bSVictor Perevertkin                     break;
596*3088717bSVictor Perevertkin                 }
597*3088717bSVictor Perevertkin 
598*3088717bSVictor Perevertkin 
599*3088717bSVictor Perevertkin                 case EXECUTE_OFFLINE_DIAGS:
600*3088717bSVictor Perevertkin                 {
601*3088717bSVictor Perevertkin                     controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
602*3088717bSVictor Perevertkin                     break;
603*3088717bSVictor Perevertkin                 }
604*3088717bSVictor Perevertkin 
605*3088717bSVictor Perevertkin                 case READ_ATTRIBUTES:
606*3088717bSVictor Perevertkin                 {
607*3088717bSVictor Perevertkin                     controlCode  = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
608*3088717bSVictor Perevertkin                     lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + READ_ATTRIBUTE_BUFFER_SIZE );
609*3088717bSVictor Perevertkin                     break;
610*3088717bSVictor Perevertkin                 }
611*3088717bSVictor Perevertkin 
612*3088717bSVictor Perevertkin                 case READ_THRESHOLDS:
613*3088717bSVictor Perevertkin                 {
614*3088717bSVictor Perevertkin                     controlCode  = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
615*3088717bSVictor Perevertkin                     lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + READ_THRESHOLD_BUFFER_SIZE );
616*3088717bSVictor Perevertkin                     break;
617*3088717bSVictor Perevertkin                 }
618*3088717bSVictor Perevertkin 
619*3088717bSVictor Perevertkin                 case SMART_READ_LOG:
620*3088717bSVictor Perevertkin                 {
621*3088717bSVictor Perevertkin                     controlCode  = IOCTL_SCSI_MINIPORT_READ_SMART_LOG;
622*3088717bSVictor Perevertkin                     lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + (SectorCount * SMART_LOG_SECTOR_SIZE) );
623*3088717bSVictor Perevertkin                     break;
624*3088717bSVictor Perevertkin                 }
625*3088717bSVictor Perevertkin 
626*3088717bSVictor Perevertkin                 case SMART_WRITE_LOG:
627*3088717bSVictor Perevertkin                 {
628*3088717bSVictor Perevertkin                     controlCode  = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG;
629*3088717bSVictor Perevertkin                     lengthNeeded = lengthNeeded - 1 + (SectorCount * SMART_LOG_SECTOR_SIZE);
630*3088717bSVictor Perevertkin                     break;
631*3088717bSVictor Perevertkin                 }
632*3088717bSVictor Perevertkin 
633*3088717bSVictor Perevertkin             }
634*3088717bSVictor Perevertkin 
635*3088717bSVictor Perevertkin         } else if (Command == ID_CMD) {
636*3088717bSVictor Perevertkin 
637*3088717bSVictor Perevertkin             controlCode  = IOCTL_SCSI_MINIPORT_IDENTIFY;
638*3088717bSVictor Perevertkin             lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE );
639*3088717bSVictor Perevertkin 
640*3088717bSVictor Perevertkin         } else {
641*3088717bSVictor Perevertkin 
642*3088717bSVictor Perevertkin             NT_ASSERT(FALSE);
643*3088717bSVictor Perevertkin         }
644*3088717bSVictor Perevertkin 
645*3088717bSVictor Perevertkin         NT_ASSERT(controlCode == SrbControlCode);
646*3088717bSVictor Perevertkin         NT_ASSERT(availableBufferSize >= lengthNeeded);
647*3088717bSVictor Perevertkin     }
648*3088717bSVictor Perevertkin 
649*3088717bSVictor Perevertkin #endif
650*3088717bSVictor Perevertkin 
651*3088717bSVictor Perevertkin     //
652*3088717bSVictor Perevertkin     // Build SrbControl and input to SMART command
653*3088717bSVictor Perevertkin     //
654*3088717bSVictor Perevertkin     SrbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
655*3088717bSVictor Perevertkin     RtlMoveMemory (SrbControl->Signature, "SCSIDISK", 8);
656*3088717bSVictor Perevertkin     SrbControl->Timeout      = FdoExtension->TimeOutValue;
657*3088717bSVictor Perevertkin     SrbControl->Length       = availableBufferSize;
658*3088717bSVictor Perevertkin     SrbControl->ControlCode  = SrbControlCode;
659*3088717bSVictor Perevertkin 
660*3088717bSVictor Perevertkin     cmdInParameters->cBufferSize  = sizeof(SENDCMDINPARAMS);
661*3088717bSVictor Perevertkin     cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
662*3088717bSVictor Perevertkin     cmdInParameters->irDriveRegs.bFeaturesReg     = Feature;
663*3088717bSVictor Perevertkin     cmdInParameters->irDriveRegs.bSectorCountReg  = SectorCount;
664*3088717bSVictor Perevertkin     cmdInParameters->irDriveRegs.bSectorNumberReg = SectorNumber;
665*3088717bSVictor Perevertkin     cmdInParameters->irDriveRegs.bCylLowReg       = SMART_CYL_LOW;
666*3088717bSVictor Perevertkin     cmdInParameters->irDriveRegs.bCylHighReg      = SMART_CYL_HI;
667*3088717bSVictor Perevertkin     cmdInParameters->irDriveRegs.bCommandReg      = Command;
668*3088717bSVictor Perevertkin 
669*3088717bSVictor Perevertkin     //
670*3088717bSVictor Perevertkin     // Create and send irp
671*3088717bSVictor Perevertkin     //
672*3088717bSVictor Perevertkin     KeInitializeEvent(&event, NotificationEvent, FALSE);
673*3088717bSVictor Perevertkin 
674*3088717bSVictor Perevertkin     startingOffset.QuadPart = (LONGLONG) 1;
675*3088717bSVictor Perevertkin 
676*3088717bSVictor Perevertkin     length = SrbControl->HeaderLength + SrbControl->Length;
677*3088717bSVictor Perevertkin 
678*3088717bSVictor Perevertkin     irp = IoBuildSynchronousFsdRequest(
679*3088717bSVictor Perevertkin                 IRP_MJ_SCSI,
680*3088717bSVictor Perevertkin                 commonExtension->LowerDeviceObject,
681*3088717bSVictor Perevertkin                 SrbControl,
682*3088717bSVictor Perevertkin                 length,
683*3088717bSVictor Perevertkin                 &startingOffset,
684*3088717bSVictor Perevertkin                 &event,
685*3088717bSVictor Perevertkin                 &ioStatus);
686*3088717bSVictor Perevertkin 
687*3088717bSVictor Perevertkin     if (irp == NULL) {
688*3088717bSVictor Perevertkin         return STATUS_INSUFFICIENT_RESOURCES;
689*3088717bSVictor Perevertkin     }
690*3088717bSVictor Perevertkin 
691*3088717bSVictor Perevertkin     irpStack = IoGetNextIrpStackLocation(irp);
692*3088717bSVictor Perevertkin 
693*3088717bSVictor Perevertkin     //
694*3088717bSVictor Perevertkin     // Set major and minor codes.
695*3088717bSVictor Perevertkin     //
696*3088717bSVictor Perevertkin 
697*3088717bSVictor Perevertkin     irpStack->MajorFunction = IRP_MJ_SCSI;
698*3088717bSVictor Perevertkin     irpStack->MinorFunction = 1;
699*3088717bSVictor Perevertkin 
700*3088717bSVictor Perevertkin     //
701*3088717bSVictor Perevertkin     // Fill in SRB fields.
702*3088717bSVictor Perevertkin     //
703*3088717bSVictor Perevertkin 
704*3088717bSVictor Perevertkin     if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
705*3088717bSVictor Perevertkin         irpStack->Parameters.Others.Argument1 = srbEx;
706*3088717bSVictor Perevertkin 
707*3088717bSVictor Perevertkin         //
708*3088717bSVictor Perevertkin         // Set up STORAGE_REQUEST_BLOCK fields
709*3088717bSVictor Perevertkin         //
710*3088717bSVictor Perevertkin 
711*3088717bSVictor Perevertkin         srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
712*3088717bSVictor Perevertkin         srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
713*3088717bSVictor Perevertkin         srbEx->Signature = SRB_SIGNATURE;
714*3088717bSVictor Perevertkin         srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
715*3088717bSVictor Perevertkin         srbEx->SrbLength = sizeof(srbExBuffer);
716*3088717bSVictor Perevertkin         srbEx->SrbFunction = SRB_FUNCTION_IO_CONTROL;
717*3088717bSVictor Perevertkin         srbEx->RequestPriority = IoGetIoPriorityHint(irp);
718*3088717bSVictor Perevertkin         srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
719*3088717bSVictor Perevertkin 
720*3088717bSVictor Perevertkin         srbEx->SrbFlags = FdoExtension->SrbFlags;
721*3088717bSVictor Perevertkin         SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_DATA_IN);
722*3088717bSVictor Perevertkin         SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
723*3088717bSVictor Perevertkin         SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE);
724*3088717bSVictor Perevertkin 
725*3088717bSVictor Perevertkin         srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST;
726*3088717bSVictor Perevertkin         srbEx->RequestTag = SP_UNTAGGED;
727*3088717bSVictor Perevertkin 
728*3088717bSVictor Perevertkin         srbEx->OriginalRequest = irp;
729*3088717bSVictor Perevertkin 
730*3088717bSVictor Perevertkin         //
731*3088717bSVictor Perevertkin         // Set timeout to requested value.
732*3088717bSVictor Perevertkin         //
733*3088717bSVictor Perevertkin 
734*3088717bSVictor Perevertkin         srbEx->TimeOutValue = SrbControl->Timeout;
735*3088717bSVictor Perevertkin 
736*3088717bSVictor Perevertkin         //
737*3088717bSVictor Perevertkin         // Set the data buffer.
738*3088717bSVictor Perevertkin         //
739*3088717bSVictor Perevertkin 
740*3088717bSVictor Perevertkin         srbEx->DataBuffer = SrbControl;
741*3088717bSVictor Perevertkin         srbEx->DataTransferLength = length;
742*3088717bSVictor Perevertkin 
743*3088717bSVictor Perevertkin         //
744*3088717bSVictor Perevertkin         // Set up address fields
745*3088717bSVictor Perevertkin         //
746*3088717bSVictor Perevertkin 
747*3088717bSVictor Perevertkin         storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
748*3088717bSVictor Perevertkin         storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
749*3088717bSVictor Perevertkin         storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
750*3088717bSVictor Perevertkin         storAddrBtl8->Path = diskData->ScsiAddress.PathId;
751*3088717bSVictor Perevertkin         storAddrBtl8->Target = diskData->ScsiAddress.TargetId;
752*3088717bSVictor Perevertkin         storAddrBtl8->Lun = srb.Lun = diskData->ScsiAddress.Lun;
753*3088717bSVictor Perevertkin 
754*3088717bSVictor Perevertkin     } else {
755*3088717bSVictor Perevertkin         irpStack->Parameters.Others.Argument1 = &srb;
756*3088717bSVictor Perevertkin 
757*3088717bSVictor Perevertkin         srb.PathId = diskData->ScsiAddress.PathId;
758*3088717bSVictor Perevertkin         srb.TargetId = diskData->ScsiAddress.TargetId;
759*3088717bSVictor Perevertkin         srb.Lun = diskData->ScsiAddress.Lun;
760*3088717bSVictor Perevertkin 
761*3088717bSVictor Perevertkin         srb.Function = SRB_FUNCTION_IO_CONTROL;
762*3088717bSVictor Perevertkin         srb.Length = sizeof(SCSI_REQUEST_BLOCK);
763*3088717bSVictor Perevertkin 
764*3088717bSVictor Perevertkin         srb.SrbFlags = FdoExtension->SrbFlags;
765*3088717bSVictor Perevertkin         SET_FLAG(srb.SrbFlags, SRB_FLAGS_DATA_IN);
766*3088717bSVictor Perevertkin         SET_FLAG(srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
767*3088717bSVictor Perevertkin         SET_FLAG(srb.SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE);
768*3088717bSVictor Perevertkin 
769*3088717bSVictor Perevertkin         srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;
770*3088717bSVictor Perevertkin         srb.QueueTag = SP_UNTAGGED;
771*3088717bSVictor Perevertkin 
772*3088717bSVictor Perevertkin         srb.OriginalRequest = irp;
773*3088717bSVictor Perevertkin 
774*3088717bSVictor Perevertkin         //
775*3088717bSVictor Perevertkin         // Set timeout to requested value.
776*3088717bSVictor Perevertkin         //
777*3088717bSVictor Perevertkin 
778*3088717bSVictor Perevertkin         srb.TimeOutValue = SrbControl->Timeout;
779*3088717bSVictor Perevertkin 
780*3088717bSVictor Perevertkin         //
781*3088717bSVictor Perevertkin         // Set the data buffer.
782*3088717bSVictor Perevertkin         //
783*3088717bSVictor Perevertkin 
784*3088717bSVictor Perevertkin         srb.DataBuffer = SrbControl;
785*3088717bSVictor Perevertkin         srb.DataTransferLength = length;
786*3088717bSVictor Perevertkin     }
787*3088717bSVictor Perevertkin 
788*3088717bSVictor Perevertkin     //
789*3088717bSVictor Perevertkin     // Flush the data buffer for output. This will insure that the data is
790*3088717bSVictor Perevertkin     // written back to memory.  Since the data-in flag is the the port driver
791*3088717bSVictor Perevertkin     // will flush the data again for input which will ensure the data is not
792*3088717bSVictor Perevertkin     // in the cache.
793*3088717bSVictor Perevertkin     //
794*3088717bSVictor Perevertkin 
795*3088717bSVictor Perevertkin     KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
796*3088717bSVictor Perevertkin 
797*3088717bSVictor Perevertkin     //
798*3088717bSVictor Perevertkin     // Call port driver to handle this request.
799*3088717bSVictor Perevertkin     //
800*3088717bSVictor Perevertkin 
801*3088717bSVictor Perevertkin     status = IoCallDriver(commonExtension->LowerDeviceObject, irp);
802*3088717bSVictor Perevertkin 
803*3088717bSVictor Perevertkin     if (status == STATUS_PENDING) {
804*3088717bSVictor Perevertkin         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
805*3088717bSVictor Perevertkin         status = ioStatus.Status;
806*3088717bSVictor Perevertkin     }
807*3088717bSVictor Perevertkin 
808*3088717bSVictor Perevertkin     return status;
809*3088717bSVictor Perevertkin }
810*3088717bSVictor Perevertkin 
811*3088717bSVictor Perevertkin 
812*3088717bSVictor Perevertkin NTSTATUS
DiskGetIdentifyInfo(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,PBOOLEAN SupportSmart)813*3088717bSVictor Perevertkin DiskGetIdentifyInfo(
814*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
815*3088717bSVictor Perevertkin     PBOOLEAN SupportSmart
816*3088717bSVictor Perevertkin     )
817*3088717bSVictor Perevertkin {
818*3088717bSVictor Perevertkin     UCHAR outBuffer[sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE )] = {0};
819*3088717bSVictor Perevertkin     ULONG outBufferSize = sizeof(outBuffer);
820*3088717bSVictor Perevertkin     NTSTATUS status;
821*3088717bSVictor Perevertkin 
822*3088717bSVictor Perevertkin     PAGED_CODE();
823*3088717bSVictor Perevertkin 
824*3088717bSVictor Perevertkin     status = DiskGetIdentifyData(FdoExtension,
825*3088717bSVictor Perevertkin                                  (PSRB_IO_CONTROL)outBuffer,
826*3088717bSVictor Perevertkin                                  &outBufferSize);
827*3088717bSVictor Perevertkin 
828*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
829*3088717bSVictor Perevertkin     {
830*3088717bSVictor Perevertkin         PUSHORT identifyData = (PUSHORT)&(outBuffer[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS) - 1]);
831*3088717bSVictor Perevertkin         USHORT commandSetSupported = identifyData[82];
832*3088717bSVictor Perevertkin 
833*3088717bSVictor Perevertkin         *SupportSmart = ((commandSetSupported != 0xffff) &&
834*3088717bSVictor Perevertkin                          (commandSetSupported != 0) &&
835*3088717bSVictor Perevertkin                          ((commandSetSupported & 1) == 1));
836*3088717bSVictor Perevertkin     } else {
837*3088717bSVictor Perevertkin         *SupportSmart = FALSE;
838*3088717bSVictor Perevertkin     }
839*3088717bSVictor Perevertkin 
840*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskGetIdentifyInfo: SMART %s supported for device %p, status %lx\n",
841*3088717bSVictor Perevertkin                    *SupportSmart ? "is" : "is not",
842*3088717bSVictor Perevertkin                    FdoExtension->DeviceObject,
843*3088717bSVictor Perevertkin                    status));
844*3088717bSVictor Perevertkin 
845*3088717bSVictor Perevertkin     return status;
846*3088717bSVictor Perevertkin }
847*3088717bSVictor Perevertkin 
848*3088717bSVictor Perevertkin 
849*3088717bSVictor Perevertkin //
850*3088717bSVictor Perevertkin // FP Ioctl specific routines
851*3088717bSVictor Perevertkin //
852*3088717bSVictor Perevertkin 
853*3088717bSVictor Perevertkin NTSTATUS
DiskSendFailurePredictIoctl(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,PSTORAGE_PREDICT_FAILURE checkFailure)854*3088717bSVictor Perevertkin DiskSendFailurePredictIoctl(
855*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
856*3088717bSVictor Perevertkin     PSTORAGE_PREDICT_FAILURE checkFailure
857*3088717bSVictor Perevertkin     )
858*3088717bSVictor Perevertkin {
859*3088717bSVictor Perevertkin     KEVENT event;
860*3088717bSVictor Perevertkin     PDEVICE_OBJECT deviceObject;
861*3088717bSVictor Perevertkin     IO_STATUS_BLOCK ioStatus = { 0 };
862*3088717bSVictor Perevertkin     PIRP irp;
863*3088717bSVictor Perevertkin     NTSTATUS status;
864*3088717bSVictor Perevertkin 
865*3088717bSVictor Perevertkin     PAGED_CODE();
866*3088717bSVictor Perevertkin 
867*3088717bSVictor Perevertkin     KeInitializeEvent(&event, SynchronizationEvent, FALSE);
868*3088717bSVictor Perevertkin 
869*3088717bSVictor Perevertkin     deviceObject = IoGetAttachedDeviceReference(FdoExtension->DeviceObject);
870*3088717bSVictor Perevertkin 
871*3088717bSVictor Perevertkin     irp = IoBuildDeviceIoControlRequest(
872*3088717bSVictor Perevertkin                     IOCTL_STORAGE_PREDICT_FAILURE,
873*3088717bSVictor Perevertkin                     deviceObject,
874*3088717bSVictor Perevertkin                     NULL,
875*3088717bSVictor Perevertkin                     0,
876*3088717bSVictor Perevertkin                     checkFailure,
877*3088717bSVictor Perevertkin                     sizeof(STORAGE_PREDICT_FAILURE),
878*3088717bSVictor Perevertkin                     FALSE,
879*3088717bSVictor Perevertkin                     &event,
880*3088717bSVictor Perevertkin                     &ioStatus);
881*3088717bSVictor Perevertkin 
882*3088717bSVictor Perevertkin     if (irp != NULL)
883*3088717bSVictor Perevertkin     {
884*3088717bSVictor Perevertkin         status = IoCallDriver(deviceObject, irp);
885*3088717bSVictor Perevertkin         if (status == STATUS_PENDING)
886*3088717bSVictor Perevertkin         {
887*3088717bSVictor Perevertkin             KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
888*3088717bSVictor Perevertkin             status = ioStatus.Status;
889*3088717bSVictor Perevertkin         }
890*3088717bSVictor Perevertkin 
891*3088717bSVictor Perevertkin     } else {
892*3088717bSVictor Perevertkin         status = STATUS_INSUFFICIENT_RESOURCES;
893*3088717bSVictor Perevertkin     }
894*3088717bSVictor Perevertkin 
895*3088717bSVictor Perevertkin     ObDereferenceObject(deviceObject);
896*3088717bSVictor Perevertkin 
897*3088717bSVictor Perevertkin     return status;
898*3088717bSVictor Perevertkin }
899*3088717bSVictor Perevertkin 
900*3088717bSVictor Perevertkin #if (NTDDI_VERSION >= NTDDI_WINBLUE)
901*3088717bSVictor Perevertkin 
902*3088717bSVictor Perevertkin NTSTATUS
DiskGetModePage(_In_ PDEVICE_OBJECT Fdo,_In_ UCHAR PageMode,_In_ UCHAR PageControl,_In_ PMODE_PARAMETER_HEADER ModeData,_Inout_ PULONG ModeDataSize,_Out_ PVOID * PageData)903*3088717bSVictor Perevertkin DiskGetModePage(
904*3088717bSVictor Perevertkin     _In_ PDEVICE_OBJECT Fdo,
905*3088717bSVictor Perevertkin     _In_ UCHAR PageMode,
906*3088717bSVictor Perevertkin     _In_ UCHAR PageControl,
907*3088717bSVictor Perevertkin     _In_ PMODE_PARAMETER_HEADER ModeData,
908*3088717bSVictor Perevertkin     _Inout_ PULONG ModeDataSize,
909*3088717bSVictor Perevertkin     _Out_ PVOID* PageData
910*3088717bSVictor Perevertkin     )
911*3088717bSVictor Perevertkin {
912*3088717bSVictor Perevertkin     ULONG size = 0;
913*3088717bSVictor Perevertkin     PVOID pageData = NULL;
914*3088717bSVictor Perevertkin 
915*3088717bSVictor Perevertkin     PAGED_CODE();
916*3088717bSVictor Perevertkin 
917*3088717bSVictor Perevertkin     if (ModeData == NULL ||
918*3088717bSVictor Perevertkin         ModeDataSize == NULL ||
919*3088717bSVictor Perevertkin         *ModeDataSize < sizeof(MODE_PARAMETER_HEADER) ||
920*3088717bSVictor Perevertkin         PageData == NULL) {
921*3088717bSVictor Perevertkin         return STATUS_INVALID_PARAMETER;
922*3088717bSVictor Perevertkin     }
923*3088717bSVictor Perevertkin 
924*3088717bSVictor Perevertkin     RtlZeroMemory (ModeData, *ModeDataSize);
925*3088717bSVictor Perevertkin 
926*3088717bSVictor Perevertkin     size = ClassModeSenseEx(Fdo,
927*3088717bSVictor Perevertkin                             (PCHAR) ModeData,
928*3088717bSVictor Perevertkin                             *ModeDataSize,
929*3088717bSVictor Perevertkin                             PageMode,
930*3088717bSVictor Perevertkin                             PageControl);
931*3088717bSVictor Perevertkin 
932*3088717bSVictor Perevertkin     if (size < sizeof(MODE_PARAMETER_HEADER)) {
933*3088717bSVictor Perevertkin 
934*3088717bSVictor Perevertkin         //
935*3088717bSVictor Perevertkin         // Retry the request in case of a check condition.
936*3088717bSVictor Perevertkin         //
937*3088717bSVictor Perevertkin         size = ClassModeSenseEx(Fdo,
938*3088717bSVictor Perevertkin                             (PCHAR) ModeData,
939*3088717bSVictor Perevertkin                             *ModeDataSize,
940*3088717bSVictor Perevertkin                             PageMode,
941*3088717bSVictor Perevertkin                             PageControl);
942*3088717bSVictor Perevertkin 
943*3088717bSVictor Perevertkin         if (size < sizeof(MODE_PARAMETER_HEADER)) {
944*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskGetModePage: Mode Sense for Page Mode %d with Page Control %d failed\n",
945*3088717bSVictor Perevertkin                 PageMode, PageControl));
946*3088717bSVictor Perevertkin             *ModeDataSize = 0;
947*3088717bSVictor Perevertkin             return STATUS_IO_DEVICE_ERROR;
948*3088717bSVictor Perevertkin         }
949*3088717bSVictor Perevertkin     }
950*3088717bSVictor Perevertkin 
951*3088717bSVictor Perevertkin     //
952*3088717bSVictor Perevertkin     // If the length is greater than length indicated by the mode data reset
953*3088717bSVictor Perevertkin     // the data to the mode data.
954*3088717bSVictor Perevertkin     //
955*3088717bSVictor Perevertkin     if (size > (ULONG) (ModeData->ModeDataLength + 1)) {
956*3088717bSVictor Perevertkin         size = ModeData->ModeDataLength + 1;
957*3088717bSVictor Perevertkin     }
958*3088717bSVictor Perevertkin 
959*3088717bSVictor Perevertkin     *ModeDataSize = size;
960*3088717bSVictor Perevertkin 
961*3088717bSVictor Perevertkin     //
962*3088717bSVictor Perevertkin     // Find the mode page
963*3088717bSVictor Perevertkin     //
964*3088717bSVictor Perevertkin     pageData = ClassFindModePage((PCHAR) ModeData,
965*3088717bSVictor Perevertkin                                  size,
966*3088717bSVictor Perevertkin                                  PageMode,
967*3088717bSVictor Perevertkin                                  TRUE);
968*3088717bSVictor Perevertkin 
969*3088717bSVictor Perevertkin     if (pageData) {
970*3088717bSVictor Perevertkin         *PageData = pageData;
971*3088717bSVictor Perevertkin         return STATUS_SUCCESS;
972*3088717bSVictor Perevertkin     } else {
973*3088717bSVictor Perevertkin         *PageData = NULL;
974*3088717bSVictor Perevertkin         return STATUS_NOT_SUPPORTED;
975*3088717bSVictor Perevertkin     }
976*3088717bSVictor Perevertkin }
977*3088717bSVictor Perevertkin 
978*3088717bSVictor Perevertkin NTSTATUS
DiskEnableInfoExceptions(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,_In_ BOOLEAN Enable)979*3088717bSVictor Perevertkin DiskEnableInfoExceptions(
980*3088717bSVictor Perevertkin     _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
981*3088717bSVictor Perevertkin     _In_ BOOLEAN Enable
982*3088717bSVictor Perevertkin     )
983*3088717bSVictor Perevertkin {
984*3088717bSVictor Perevertkin     PDISK_DATA diskData = (PDISK_DATA)(FdoExtension->CommonExtension.DriverData);
985*3088717bSVictor Perevertkin     NTSTATUS status = STATUS_NOT_SUPPORTED;
986*3088717bSVictor Perevertkin     PMODE_PARAMETER_HEADER modeData;
987*3088717bSVictor Perevertkin     PMODE_INFO_EXCEPTIONS pageData;
988*3088717bSVictor Perevertkin     MODE_INFO_EXCEPTIONS changeablePageData;
989*3088717bSVictor Perevertkin     ULONG modeDataSize;
990*3088717bSVictor Perevertkin 
991*3088717bSVictor Perevertkin     PAGED_CODE();
992*3088717bSVictor Perevertkin 
993*3088717bSVictor Perevertkin     modeDataSize = MODE_DATA_SIZE;
994*3088717bSVictor Perevertkin 
995*3088717bSVictor Perevertkin     modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
996*3088717bSVictor Perevertkin                                          modeDataSize,
997*3088717bSVictor Perevertkin                                          DISK_TAG_INFO_EXCEPTION);
998*3088717bSVictor Perevertkin 
999*3088717bSVictor Perevertkin     if (modeData == NULL) {
1000*3088717bSVictor Perevertkin 
1001*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskEnableInfoExceptions: Unable to allocate mode "
1002*3088717bSVictor Perevertkin                        "data buffer\n"));
1003*3088717bSVictor Perevertkin         return STATUS_INSUFFICIENT_RESOURCES;
1004*3088717bSVictor Perevertkin     }
1005*3088717bSVictor Perevertkin 
1006*3088717bSVictor Perevertkin     //
1007*3088717bSVictor Perevertkin     // First see which data is actually changeable.
1008*3088717bSVictor Perevertkin     //
1009*3088717bSVictor Perevertkin     status = DiskGetModePage(FdoExtension->DeviceObject,
1010*3088717bSVictor Perevertkin                              MODE_PAGE_FAULT_REPORTING,
1011*3088717bSVictor Perevertkin                              1, // Page Control = 1 indicates we want changeable values.
1012*3088717bSVictor Perevertkin                              modeData,
1013*3088717bSVictor Perevertkin                              &modeDataSize,
1014*3088717bSVictor Perevertkin                              (PVOID*)&pageData);
1015*3088717bSVictor Perevertkin 
1016*3088717bSVictor Perevertkin     if (!NT_SUCCESS(status) || pageData == NULL) {
1017*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskEnableInfoExceptions: does NOT support SMART for device %p\n",
1018*3088717bSVictor Perevertkin                   FdoExtension->DeviceObject));
1019*3088717bSVictor Perevertkin         FREE_POOL(modeData);
1020*3088717bSVictor Perevertkin         return STATUS_NOT_SUPPORTED;
1021*3088717bSVictor Perevertkin     }
1022*3088717bSVictor Perevertkin 
1023*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskEnableInfoExceptions: DOES support SMART for device %p\n",
1024*3088717bSVictor Perevertkin                 FdoExtension->DeviceObject));
1025*3088717bSVictor Perevertkin 
1026*3088717bSVictor Perevertkin     //
1027*3088717bSVictor Perevertkin     // At the very least, the DEXCPT bit must be changeable.
1028*3088717bSVictor Perevertkin     // If it's not, bail out now.
1029*3088717bSVictor Perevertkin     //
1030*3088717bSVictor Perevertkin     if (pageData->Dexcpt == 0) {
1031*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskEnableInfoExceptions: does NOT support DEXCPT bit for device %p\n",
1032*3088717bSVictor Perevertkin                   FdoExtension->DeviceObject));
1033*3088717bSVictor Perevertkin         FREE_POOL(modeData);
1034*3088717bSVictor Perevertkin         return STATUS_NOT_SUPPORTED;
1035*3088717bSVictor Perevertkin     }
1036*3088717bSVictor Perevertkin 
1037*3088717bSVictor Perevertkin     //
1038*3088717bSVictor Perevertkin     // Cache away which values are changeable.
1039*3088717bSVictor Perevertkin     //
1040*3088717bSVictor Perevertkin     RtlCopyMemory(&changeablePageData, pageData, sizeof(MODE_INFO_EXCEPTIONS));
1041*3088717bSVictor Perevertkin 
1042*3088717bSVictor Perevertkin     //
1043*3088717bSVictor Perevertkin     // Now get the current values.
1044*3088717bSVictor Perevertkin     //
1045*3088717bSVictor Perevertkin     status = DiskGetModePage(FdoExtension->DeviceObject,
1046*3088717bSVictor Perevertkin                              MODE_PAGE_FAULT_REPORTING,
1047*3088717bSVictor Perevertkin                              0, // Page Control = 0 indicates we want current values.
1048*3088717bSVictor Perevertkin                              modeData,
1049*3088717bSVictor Perevertkin                              &modeDataSize,
1050*3088717bSVictor Perevertkin                              (PVOID*)&pageData);
1051*3088717bSVictor Perevertkin 
1052*3088717bSVictor Perevertkin     if (!NT_SUCCESS(status) || pageData == NULL) {
1053*3088717bSVictor Perevertkin         //
1054*3088717bSVictor Perevertkin         // At this point we know the device supports this mode page so
1055*3088717bSVictor Perevertkin         // assert if something goes wrong here.
1056*3088717bSVictor Perevertkin         //
1057*3088717bSVictor Perevertkin         NT_ASSERT(NT_SUCCESS(status) && pageData);
1058*3088717bSVictor Perevertkin         FREE_POOL(modeData);
1059*3088717bSVictor Perevertkin         return STATUS_NOT_SUPPORTED;
1060*3088717bSVictor Perevertkin     }
1061*3088717bSVictor Perevertkin 
1062*3088717bSVictor Perevertkin     //
1063*3088717bSVictor Perevertkin     // If the device is currently configured to not report any informational
1064*3088717bSVictor Perevertkin     // exceptions and we cannot change the value of that field, there's
1065*3088717bSVictor Perevertkin     // nothing to be done.
1066*3088717bSVictor Perevertkin     //
1067*3088717bSVictor Perevertkin     if (pageData->ReportMethod == 0 && changeablePageData.ReportMethod == 0) {
1068*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskEnableInfoExceptions: MRIE field is 0 and is not changeable for device %p\n",
1069*3088717bSVictor Perevertkin                   FdoExtension->DeviceObject));
1070*3088717bSVictor Perevertkin         FREE_POOL(modeData);
1071*3088717bSVictor Perevertkin         return STATUS_NOT_SUPPORTED;
1072*3088717bSVictor Perevertkin     }
1073*3088717bSVictor Perevertkin 
1074*3088717bSVictor Perevertkin     //
1075*3088717bSVictor Perevertkin     // If the PERF bit is changeable, set it now.
1076*3088717bSVictor Perevertkin     //
1077*3088717bSVictor Perevertkin     if (changeablePageData.Perf) {
1078*3088717bSVictor Perevertkin         pageData->Perf = diskData->AllowFPPerfHit ? 0 : 1;
1079*3088717bSVictor Perevertkin     }
1080*3088717bSVictor Perevertkin 
1081*3088717bSVictor Perevertkin     //
1082*3088717bSVictor Perevertkin     // If the MRIE field is changeable, set it to 4 so that informational
1083*3088717bSVictor Perevertkin     // exceptions get reported with the "Recovered Error" sense key.
1084*3088717bSVictor Perevertkin     //
1085*3088717bSVictor Perevertkin     if (changeablePageData.ReportMethod) {
1086*3088717bSVictor Perevertkin         pageData->ReportMethod = 4;
1087*3088717bSVictor Perevertkin     }
1088*3088717bSVictor Perevertkin 
1089*3088717bSVictor Perevertkin     //
1090*3088717bSVictor Perevertkin     // Finally, set the DEXCPT bit appropriately to enable/disable
1091*3088717bSVictor Perevertkin     // informational exception reporting and send the Mode Select.
1092*3088717bSVictor Perevertkin     //
1093*3088717bSVictor Perevertkin     pageData->Dexcpt = !Enable;
1094*3088717bSVictor Perevertkin 
1095*3088717bSVictor Perevertkin     status = ClassModeSelect(FdoExtension->DeviceObject,
1096*3088717bSVictor Perevertkin                                 (PCHAR)modeData,
1097*3088717bSVictor Perevertkin                                 modeDataSize,
1098*3088717bSVictor Perevertkin                                 pageData->PSBit);
1099*3088717bSVictor Perevertkin 
1100*3088717bSVictor Perevertkin     //
1101*3088717bSVictor Perevertkin     // Update the failure prediction state.  Note that for this particular
1102*3088717bSVictor Perevertkin     // mode FailurePredictionNone is used when it's not enabled.
1103*3088717bSVictor Perevertkin     //
1104*3088717bSVictor Perevertkin     if (NT_SUCCESS(status)) {
1105*3088717bSVictor Perevertkin         if (Enable) {
1106*3088717bSVictor Perevertkin             diskData->FailurePredictionCapability = FailurePredictionSense;
1107*3088717bSVictor Perevertkin             diskData->FailurePredictionEnabled = TRUE;
1108*3088717bSVictor Perevertkin         } else {
1109*3088717bSVictor Perevertkin             diskData->FailurePredictionCapability = FailurePredictionNone;
1110*3088717bSVictor Perevertkin             diskData->FailurePredictionEnabled = FALSE;
1111*3088717bSVictor Perevertkin         }
1112*3088717bSVictor Perevertkin     }
1113*3088717bSVictor Perevertkin 
1114*3088717bSVictor Perevertkin     FREE_POOL(modeData);
1115*3088717bSVictor Perevertkin 
1116*3088717bSVictor Perevertkin     return status;
1117*3088717bSVictor Perevertkin }
1118*3088717bSVictor Perevertkin #endif
1119*3088717bSVictor Perevertkin 
1120*3088717bSVictor Perevertkin 
1121*3088717bSVictor Perevertkin //
1122*3088717bSVictor Perevertkin // FP type independent routines
1123*3088717bSVictor Perevertkin //
1124*3088717bSVictor Perevertkin 
1125*3088717bSVictor Perevertkin NTSTATUS
DiskEnableDisableFailurePrediction(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,BOOLEAN Enable)1126*3088717bSVictor Perevertkin DiskEnableDisableFailurePrediction(
1127*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
1128*3088717bSVictor Perevertkin     BOOLEAN Enable
1129*3088717bSVictor Perevertkin     )
1130*3088717bSVictor Perevertkin /*++
1131*3088717bSVictor Perevertkin 
1132*3088717bSVictor Perevertkin Routine Description:
1133*3088717bSVictor Perevertkin 
1134*3088717bSVictor Perevertkin     Enable or disable failure prediction at the hardware level
1135*3088717bSVictor Perevertkin 
1136*3088717bSVictor Perevertkin Arguments:
1137*3088717bSVictor Perevertkin 
1138*3088717bSVictor Perevertkin     FdoExtension
1139*3088717bSVictor Perevertkin 
1140*3088717bSVictor Perevertkin     Enable
1141*3088717bSVictor Perevertkin 
1142*3088717bSVictor Perevertkin Return Value:
1143*3088717bSVictor Perevertkin 
1144*3088717bSVictor Perevertkin     NT Status
1145*3088717bSVictor Perevertkin 
1146*3088717bSVictor Perevertkin --*/
1147*3088717bSVictor Perevertkin {
1148*3088717bSVictor Perevertkin     NTSTATUS status;
1149*3088717bSVictor Perevertkin     PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension);
1150*3088717bSVictor Perevertkin     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
1151*3088717bSVictor Perevertkin 
1152*3088717bSVictor Perevertkin     PAGED_CODE();
1153*3088717bSVictor Perevertkin 
1154*3088717bSVictor Perevertkin     switch(diskData->FailurePredictionCapability)
1155*3088717bSVictor Perevertkin     {
1156*3088717bSVictor Perevertkin         case FailurePredictionSmart:
1157*3088717bSVictor Perevertkin         {
1158*3088717bSVictor Perevertkin             if (Enable)
1159*3088717bSVictor Perevertkin             {
1160*3088717bSVictor Perevertkin                 status = DiskEnableSmart(FdoExtension);
1161*3088717bSVictor Perevertkin             } else {
1162*3088717bSVictor Perevertkin                 status = DiskDisableSmart(FdoExtension);
1163*3088717bSVictor Perevertkin             }
1164*3088717bSVictor Perevertkin 
1165*3088717bSVictor Perevertkin             if (NT_SUCCESS(status)) {
1166*3088717bSVictor Perevertkin                 diskData->FailurePredictionEnabled = Enable;
1167*3088717bSVictor Perevertkin             }
1168*3088717bSVictor Perevertkin 
1169*3088717bSVictor Perevertkin             break;
1170*3088717bSVictor Perevertkin         }
1171*3088717bSVictor Perevertkin 
1172*3088717bSVictor Perevertkin         case  FailurePredictionSense:
1173*3088717bSVictor Perevertkin         case  FailurePredictionIoctl:
1174*3088717bSVictor Perevertkin         {
1175*3088717bSVictor Perevertkin             //
1176*3088717bSVictor Perevertkin             // We assume that the drive is already setup properly for
1177*3088717bSVictor Perevertkin             // failure prediction
1178*3088717bSVictor Perevertkin             //
1179*3088717bSVictor Perevertkin             status = STATUS_SUCCESS;
1180*3088717bSVictor Perevertkin             break;
1181*3088717bSVictor Perevertkin         }
1182*3088717bSVictor Perevertkin 
1183*3088717bSVictor Perevertkin         default:
1184*3088717bSVictor Perevertkin         {
1185*3088717bSVictor Perevertkin             status = STATUS_INVALID_DEVICE_REQUEST;
1186*3088717bSVictor Perevertkin         }
1187*3088717bSVictor Perevertkin     }
1188*3088717bSVictor Perevertkin     return status;
1189*3088717bSVictor Perevertkin }
1190*3088717bSVictor Perevertkin 
1191*3088717bSVictor Perevertkin 
1192*3088717bSVictor Perevertkin NTSTATUS
DiskEnableDisableFailurePredictPolling(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,BOOLEAN Enable,ULONG PollTimeInSeconds)1193*3088717bSVictor Perevertkin DiskEnableDisableFailurePredictPolling(
1194*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
1195*3088717bSVictor Perevertkin     BOOLEAN Enable,
1196*3088717bSVictor Perevertkin     ULONG PollTimeInSeconds
1197*3088717bSVictor Perevertkin     )
1198*3088717bSVictor Perevertkin /*++
1199*3088717bSVictor Perevertkin 
1200*3088717bSVictor Perevertkin Routine Description:
1201*3088717bSVictor Perevertkin 
1202*3088717bSVictor Perevertkin     Enable or disable polling for hardware failure detection
1203*3088717bSVictor Perevertkin 
1204*3088717bSVictor Perevertkin Arguments:
1205*3088717bSVictor Perevertkin 
1206*3088717bSVictor Perevertkin     FdoExtension
1207*3088717bSVictor Perevertkin 
1208*3088717bSVictor Perevertkin     Enable
1209*3088717bSVictor Perevertkin 
1210*3088717bSVictor Perevertkin     PollTimeInSeconds - if 0 then no change to current polling timer
1211*3088717bSVictor Perevertkin 
1212*3088717bSVictor Perevertkin Return Value:
1213*3088717bSVictor Perevertkin 
1214*3088717bSVictor Perevertkin     NT Status
1215*3088717bSVictor Perevertkin 
1216*3088717bSVictor Perevertkin --*/
1217*3088717bSVictor Perevertkin {
1218*3088717bSVictor Perevertkin     NTSTATUS status;
1219*3088717bSVictor Perevertkin     PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
1220*3088717bSVictor Perevertkin     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
1221*3088717bSVictor Perevertkin 
1222*3088717bSVictor Perevertkin     PAGED_CODE();
1223*3088717bSVictor Perevertkin 
1224*3088717bSVictor Perevertkin     if (Enable)
1225*3088717bSVictor Perevertkin     {
1226*3088717bSVictor Perevertkin         status = DiskEnableDisableFailurePrediction(FdoExtension,
1227*3088717bSVictor Perevertkin                                            Enable);
1228*3088717bSVictor Perevertkin     } else {
1229*3088717bSVictor Perevertkin         status = STATUS_SUCCESS;
1230*3088717bSVictor Perevertkin     }
1231*3088717bSVictor Perevertkin 
1232*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
1233*3088717bSVictor Perevertkin     {
1234*3088717bSVictor Perevertkin         status = ClassSetFailurePredictionPoll(FdoExtension,
1235*3088717bSVictor Perevertkin                         Enable ? diskData->FailurePredictionCapability :
1236*3088717bSVictor Perevertkin                                  FailurePredictionNone,
1237*3088717bSVictor Perevertkin                                      PollTimeInSeconds);
1238*3088717bSVictor Perevertkin 
1239*3088717bSVictor Perevertkin         //
1240*3088717bSVictor Perevertkin         // Even if this failed we do not want to disable FP on the
1241*3088717bSVictor Perevertkin         // hardware. FP is only ever disabled on the hardware by
1242*3088717bSVictor Perevertkin         // specific command of the user.
1243*3088717bSVictor Perevertkin         //
1244*3088717bSVictor Perevertkin     }
1245*3088717bSVictor Perevertkin 
1246*3088717bSVictor Perevertkin     return status;
1247*3088717bSVictor Perevertkin }
1248*3088717bSVictor Perevertkin 
1249*3088717bSVictor Perevertkin 
1250*3088717bSVictor Perevertkin NTSTATUS
DiskReadFailurePredictStatus(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,PSTORAGE_FAILURE_PREDICT_STATUS DiskSmartStatus)1251*3088717bSVictor Perevertkin DiskReadFailurePredictStatus(
1252*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
1253*3088717bSVictor Perevertkin     PSTORAGE_FAILURE_PREDICT_STATUS DiskSmartStatus
1254*3088717bSVictor Perevertkin     )
1255*3088717bSVictor Perevertkin /*++
1256*3088717bSVictor Perevertkin 
1257*3088717bSVictor Perevertkin Routine Description:
1258*3088717bSVictor Perevertkin 
1259*3088717bSVictor Perevertkin     Obtains current failure prediction status
1260*3088717bSVictor Perevertkin 
1261*3088717bSVictor Perevertkin Arguments:
1262*3088717bSVictor Perevertkin 
1263*3088717bSVictor Perevertkin     FdoExtension
1264*3088717bSVictor Perevertkin 
1265*3088717bSVictor Perevertkin     DiskSmartStatus
1266*3088717bSVictor Perevertkin 
1267*3088717bSVictor Perevertkin Return Value:
1268*3088717bSVictor Perevertkin 
1269*3088717bSVictor Perevertkin     NT Status
1270*3088717bSVictor Perevertkin 
1271*3088717bSVictor Perevertkin --*/
1272*3088717bSVictor Perevertkin {
1273*3088717bSVictor Perevertkin     PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
1274*3088717bSVictor Perevertkin     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
1275*3088717bSVictor Perevertkin     NTSTATUS status;
1276*3088717bSVictor Perevertkin 
1277*3088717bSVictor Perevertkin     PAGED_CODE();
1278*3088717bSVictor Perevertkin 
1279*3088717bSVictor Perevertkin     DiskSmartStatus->PredictFailure = FALSE;
1280*3088717bSVictor Perevertkin 
1281*3088717bSVictor Perevertkin     switch(diskData->FailurePredictionCapability)
1282*3088717bSVictor Perevertkin     {
1283*3088717bSVictor Perevertkin         case FailurePredictionSmart:
1284*3088717bSVictor Perevertkin         {
1285*3088717bSVictor Perevertkin             UCHAR outBuffer[sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS) )] = {0};
1286*3088717bSVictor Perevertkin             ULONG outBufferSize = sizeof(outBuffer);
1287*3088717bSVictor Perevertkin             PSENDCMDOUTPARAMS cmdOutParameters;
1288*3088717bSVictor Perevertkin 
1289*3088717bSVictor Perevertkin             status = DiskReadSmartStatus(FdoExtension,
1290*3088717bSVictor Perevertkin                                      (PSRB_IO_CONTROL)outBuffer,
1291*3088717bSVictor Perevertkin                                      &outBufferSize);
1292*3088717bSVictor Perevertkin 
1293*3088717bSVictor Perevertkin             if (NT_SUCCESS(status))
1294*3088717bSVictor Perevertkin             {
1295*3088717bSVictor Perevertkin                 cmdOutParameters = (PSENDCMDOUTPARAMS)(outBuffer +
1296*3088717bSVictor Perevertkin                                                sizeof(SRB_IO_CONTROL));
1297*3088717bSVictor Perevertkin 
1298*3088717bSVictor Perevertkin                 DiskSmartStatus->Reason = 0; // Unknown;
1299*3088717bSVictor Perevertkin                 DiskSmartStatus->PredictFailure = ((cmdOutParameters->bBuffer[3] == 0xf4) &&
1300*3088717bSVictor Perevertkin                                                    (cmdOutParameters->bBuffer[4] == 0x2c));
1301*3088717bSVictor Perevertkin             }
1302*3088717bSVictor Perevertkin             break;
1303*3088717bSVictor Perevertkin         }
1304*3088717bSVictor Perevertkin 
1305*3088717bSVictor Perevertkin         case FailurePredictionSense:
1306*3088717bSVictor Perevertkin         {
1307*3088717bSVictor Perevertkin             DiskSmartStatus->Reason = FdoExtension->FailureReason;
1308*3088717bSVictor Perevertkin             DiskSmartStatus->PredictFailure = FdoExtension->FailurePredicted;
1309*3088717bSVictor Perevertkin             status = STATUS_SUCCESS;
1310*3088717bSVictor Perevertkin             break;
1311*3088717bSVictor Perevertkin         }
1312*3088717bSVictor Perevertkin 
1313*3088717bSVictor Perevertkin         case FailurePredictionIoctl:
1314*3088717bSVictor Perevertkin         case FailurePredictionNone:
1315*3088717bSVictor Perevertkin         default:
1316*3088717bSVictor Perevertkin         {
1317*3088717bSVictor Perevertkin             status = STATUS_INVALID_DEVICE_REQUEST;
1318*3088717bSVictor Perevertkin             break;
1319*3088717bSVictor Perevertkin         }
1320*3088717bSVictor Perevertkin     }
1321*3088717bSVictor Perevertkin 
1322*3088717bSVictor Perevertkin     return status;
1323*3088717bSVictor Perevertkin }
1324*3088717bSVictor Perevertkin 
1325*3088717bSVictor Perevertkin 
1326*3088717bSVictor Perevertkin NTSTATUS
DiskReadFailurePredictData(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,PSTORAGE_FAILURE_PREDICT_DATA DiskSmartData)1327*3088717bSVictor Perevertkin DiskReadFailurePredictData(
1328*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
1329*3088717bSVictor Perevertkin     PSTORAGE_FAILURE_PREDICT_DATA DiskSmartData
1330*3088717bSVictor Perevertkin     )
1331*3088717bSVictor Perevertkin /*++
1332*3088717bSVictor Perevertkin 
1333*3088717bSVictor Perevertkin Routine Description:
1334*3088717bSVictor Perevertkin 
1335*3088717bSVictor Perevertkin     Obtains current failure prediction data. Not available for
1336*3088717bSVictor Perevertkin     FAILURE_PREDICT_SENSE types.
1337*3088717bSVictor Perevertkin 
1338*3088717bSVictor Perevertkin Arguments:
1339*3088717bSVictor Perevertkin 
1340*3088717bSVictor Perevertkin     FdoExtension
1341*3088717bSVictor Perevertkin 
1342*3088717bSVictor Perevertkin     DiskSmartData
1343*3088717bSVictor Perevertkin 
1344*3088717bSVictor Perevertkin Return Value:
1345*3088717bSVictor Perevertkin 
1346*3088717bSVictor Perevertkin     NT Status
1347*3088717bSVictor Perevertkin 
1348*3088717bSVictor Perevertkin --*/
1349*3088717bSVictor Perevertkin {
1350*3088717bSVictor Perevertkin     PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
1351*3088717bSVictor Perevertkin     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
1352*3088717bSVictor Perevertkin     NTSTATUS status;
1353*3088717bSVictor Perevertkin 
1354*3088717bSVictor Perevertkin     PAGED_CODE();
1355*3088717bSVictor Perevertkin 
1356*3088717bSVictor Perevertkin     switch(diskData->FailurePredictionCapability)
1357*3088717bSVictor Perevertkin     {
1358*3088717bSVictor Perevertkin         case FailurePredictionSmart:
1359*3088717bSVictor Perevertkin         {
1360*3088717bSVictor Perevertkin             PUCHAR outBuffer;
1361*3088717bSVictor Perevertkin             ULONG outBufferSize;
1362*3088717bSVictor Perevertkin             PSENDCMDOUTPARAMS cmdOutParameters;
1363*3088717bSVictor Perevertkin 
1364*3088717bSVictor Perevertkin             outBufferSize = sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + READ_ATTRIBUTE_BUFFER_SIZE );
1365*3088717bSVictor Perevertkin 
1366*3088717bSVictor Perevertkin             outBuffer = ExAllocatePoolWithTag(NonPagedPoolNx,
1367*3088717bSVictor Perevertkin                                               outBufferSize,
1368*3088717bSVictor Perevertkin                                               DISK_TAG_SMART);
1369*3088717bSVictor Perevertkin 
1370*3088717bSVictor Perevertkin             if (outBuffer != NULL)
1371*3088717bSVictor Perevertkin             {
1372*3088717bSVictor Perevertkin                 status = DiskReadSmartData(FdoExtension,
1373*3088717bSVictor Perevertkin                                            (PSRB_IO_CONTROL)outBuffer,
1374*3088717bSVictor Perevertkin                                            &outBufferSize);
1375*3088717bSVictor Perevertkin 
1376*3088717bSVictor Perevertkin                 if (NT_SUCCESS(status))
1377*3088717bSVictor Perevertkin                 {
1378*3088717bSVictor Perevertkin                     cmdOutParameters = (PSENDCMDOUTPARAMS)(outBuffer +
1379*3088717bSVictor Perevertkin                                                     sizeof(SRB_IO_CONTROL));
1380*3088717bSVictor Perevertkin 
1381*3088717bSVictor Perevertkin                     DiskSmartData->Length = READ_ATTRIBUTE_BUFFER_SIZE;
1382*3088717bSVictor Perevertkin                     RtlCopyMemory(DiskSmartData->VendorSpecific,
1383*3088717bSVictor Perevertkin                                   cmdOutParameters->bBuffer,
1384*3088717bSVictor Perevertkin                                   min(READ_ATTRIBUTE_BUFFER_SIZE, sizeof(DiskSmartData->VendorSpecific)));
1385*3088717bSVictor Perevertkin                 }
1386*3088717bSVictor Perevertkin                 FREE_POOL(outBuffer);
1387*3088717bSVictor Perevertkin             } else {
1388*3088717bSVictor Perevertkin                 status = STATUS_INSUFFICIENT_RESOURCES;
1389*3088717bSVictor Perevertkin             }
1390*3088717bSVictor Perevertkin 
1391*3088717bSVictor Perevertkin             break;
1392*3088717bSVictor Perevertkin         }
1393*3088717bSVictor Perevertkin 
1394*3088717bSVictor Perevertkin         case FailurePredictionSense:
1395*3088717bSVictor Perevertkin         {
1396*3088717bSVictor Perevertkin             DiskSmartData->Length = sizeof(ULONG);
1397*3088717bSVictor Perevertkin             *((PULONG)DiskSmartData->VendorSpecific) = FdoExtension->FailureReason;
1398*3088717bSVictor Perevertkin 
1399*3088717bSVictor Perevertkin             status = STATUS_SUCCESS;
1400*3088717bSVictor Perevertkin             break;
1401*3088717bSVictor Perevertkin         }
1402*3088717bSVictor Perevertkin 
1403*3088717bSVictor Perevertkin         case FailurePredictionIoctl:
1404*3088717bSVictor Perevertkin         case FailurePredictionNone:
1405*3088717bSVictor Perevertkin         default:
1406*3088717bSVictor Perevertkin         {
1407*3088717bSVictor Perevertkin             status = STATUS_INVALID_DEVICE_REQUEST;
1408*3088717bSVictor Perevertkin             break;
1409*3088717bSVictor Perevertkin         }
1410*3088717bSVictor Perevertkin     }
1411*3088717bSVictor Perevertkin 
1412*3088717bSVictor Perevertkin     return status;
1413*3088717bSVictor Perevertkin }
1414*3088717bSVictor Perevertkin 
1415*3088717bSVictor Perevertkin 
1416*3088717bSVictor Perevertkin NTSTATUS
DiskReadFailurePredictThresholds(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,PSTORAGE_FAILURE_PREDICT_THRESHOLDS DiskSmartThresholds)1417*3088717bSVictor Perevertkin DiskReadFailurePredictThresholds(
1418*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
1419*3088717bSVictor Perevertkin     PSTORAGE_FAILURE_PREDICT_THRESHOLDS DiskSmartThresholds
1420*3088717bSVictor Perevertkin     )
1421*3088717bSVictor Perevertkin /*++
1422*3088717bSVictor Perevertkin 
1423*3088717bSVictor Perevertkin Routine Description:
1424*3088717bSVictor Perevertkin 
1425*3088717bSVictor Perevertkin     Obtains current failure prediction thresholds. Not available for
1426*3088717bSVictor Perevertkin     FAILURE_PREDICT_SENSE types.
1427*3088717bSVictor Perevertkin 
1428*3088717bSVictor Perevertkin Arguments:
1429*3088717bSVictor Perevertkin 
1430*3088717bSVictor Perevertkin     FdoExtension
1431*3088717bSVictor Perevertkin 
1432*3088717bSVictor Perevertkin     DiskSmartData
1433*3088717bSVictor Perevertkin 
1434*3088717bSVictor Perevertkin Return Value:
1435*3088717bSVictor Perevertkin 
1436*3088717bSVictor Perevertkin     NT Status
1437*3088717bSVictor Perevertkin 
1438*3088717bSVictor Perevertkin --*/
1439*3088717bSVictor Perevertkin {
1440*3088717bSVictor Perevertkin     PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
1441*3088717bSVictor Perevertkin     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
1442*3088717bSVictor Perevertkin     NTSTATUS status;
1443*3088717bSVictor Perevertkin 
1444*3088717bSVictor Perevertkin     PAGED_CODE();
1445*3088717bSVictor Perevertkin 
1446*3088717bSVictor Perevertkin     switch(diskData->FailurePredictionCapability)
1447*3088717bSVictor Perevertkin     {
1448*3088717bSVictor Perevertkin         case FailurePredictionSmart:
1449*3088717bSVictor Perevertkin         {
1450*3088717bSVictor Perevertkin             PUCHAR outBuffer;
1451*3088717bSVictor Perevertkin             PSENDCMDOUTPARAMS cmdOutParameters;
1452*3088717bSVictor Perevertkin             ULONG outBufferSize;
1453*3088717bSVictor Perevertkin 
1454*3088717bSVictor Perevertkin             outBufferSize = sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + READ_THRESHOLD_BUFFER_SIZE );
1455*3088717bSVictor Perevertkin 
1456*3088717bSVictor Perevertkin             outBuffer = ExAllocatePoolWithTag(NonPagedPoolNx,
1457*3088717bSVictor Perevertkin                                               outBufferSize,
1458*3088717bSVictor Perevertkin                                               DISK_TAG_SMART);
1459*3088717bSVictor Perevertkin 
1460*3088717bSVictor Perevertkin             if (outBuffer != NULL)
1461*3088717bSVictor Perevertkin             {
1462*3088717bSVictor Perevertkin                 status = DiskReadSmartThresholds(FdoExtension,
1463*3088717bSVictor Perevertkin                                                 (PSRB_IO_CONTROL)outBuffer,
1464*3088717bSVictor Perevertkin                                                 &outBufferSize);
1465*3088717bSVictor Perevertkin 
1466*3088717bSVictor Perevertkin                 if (NT_SUCCESS(status))
1467*3088717bSVictor Perevertkin                 {
1468*3088717bSVictor Perevertkin                     cmdOutParameters = (PSENDCMDOUTPARAMS)(outBuffer +
1469*3088717bSVictor Perevertkin                                            sizeof(SRB_IO_CONTROL));
1470*3088717bSVictor Perevertkin 
1471*3088717bSVictor Perevertkin                     RtlCopyMemory(DiskSmartThresholds->VendorSpecific,
1472*3088717bSVictor Perevertkin                                   cmdOutParameters->bBuffer,
1473*3088717bSVictor Perevertkin                                   min(READ_THRESHOLD_BUFFER_SIZE, sizeof(DiskSmartThresholds->VendorSpecific)));
1474*3088717bSVictor Perevertkin                 }
1475*3088717bSVictor Perevertkin                 FREE_POOL(outBuffer);
1476*3088717bSVictor Perevertkin             } else {
1477*3088717bSVictor Perevertkin                 status = STATUS_INSUFFICIENT_RESOURCES;
1478*3088717bSVictor Perevertkin             }
1479*3088717bSVictor Perevertkin 
1480*3088717bSVictor Perevertkin             break;
1481*3088717bSVictor Perevertkin         }
1482*3088717bSVictor Perevertkin 
1483*3088717bSVictor Perevertkin         case FailurePredictionSense:
1484*3088717bSVictor Perevertkin         case FailurePredictionIoctl:
1485*3088717bSVictor Perevertkin         case FailurePredictionNone:
1486*3088717bSVictor Perevertkin         default:
1487*3088717bSVictor Perevertkin         {
1488*3088717bSVictor Perevertkin             status = STATUS_INVALID_DEVICE_REQUEST;
1489*3088717bSVictor Perevertkin             break;
1490*3088717bSVictor Perevertkin         }
1491*3088717bSVictor Perevertkin     }
1492*3088717bSVictor Perevertkin 
1493*3088717bSVictor Perevertkin     return status;
1494*3088717bSVictor Perevertkin }
1495*3088717bSVictor Perevertkin 
1496*3088717bSVictor Perevertkin 
1497*3088717bSVictor Perevertkin VOID
1498*3088717bSVictor Perevertkin NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskReregWorker(IN PDEVICE_OBJECT DevObject,IN PVOID Context)1499*3088717bSVictor Perevertkin DiskReregWorker(
1500*3088717bSVictor Perevertkin     IN PDEVICE_OBJECT DevObject,
1501*3088717bSVictor Perevertkin     IN PVOID Context
1502*3088717bSVictor Perevertkin     )
1503*3088717bSVictor Perevertkin {
1504*3088717bSVictor Perevertkin     PDISKREREGREQUEST reregRequest;
1505*3088717bSVictor Perevertkin     NTSTATUS status;
1506*3088717bSVictor Perevertkin     PDEVICE_OBJECT deviceObject;
1507*3088717bSVictor Perevertkin     PIRP irp;
1508*3088717bSVictor Perevertkin 
1509*3088717bSVictor Perevertkin     PAGED_CODE();
1510*3088717bSVictor Perevertkin     UNREFERENCED_PARAMETER(DevObject);
1511*3088717bSVictor Perevertkin 
1512*3088717bSVictor Perevertkin     NT_ASSERT(Context != NULL);
1513*3088717bSVictor Perevertkin     _Analysis_assume_(Context != NULL);
1514*3088717bSVictor Perevertkin 
1515*3088717bSVictor Perevertkin     do
1516*3088717bSVictor Perevertkin     {
1517*3088717bSVictor Perevertkin         reregRequest = (PDISKREREGREQUEST)ExInterlockedPopEntryList(
1518*3088717bSVictor Perevertkin                              &DiskReregHead,
1519*3088717bSVictor Perevertkin                              &DiskReregSpinlock);
1520*3088717bSVictor Perevertkin 
1521*3088717bSVictor Perevertkin         if (reregRequest != NULL)
1522*3088717bSVictor Perevertkin         {
1523*3088717bSVictor Perevertkin             deviceObject = reregRequest->DeviceObject;
1524*3088717bSVictor Perevertkin             irp = reregRequest->Irp;
1525*3088717bSVictor Perevertkin 
1526*3088717bSVictor Perevertkin             status = IoWMIRegistrationControl(deviceObject,
1527*3088717bSVictor Perevertkin                                               WMIREG_ACTION_UPDATE_GUIDS);
1528*3088717bSVictor Perevertkin 
1529*3088717bSVictor Perevertkin             //
1530*3088717bSVictor Perevertkin             // Release remove lock and free irp, now that we are done
1531*3088717bSVictor Perevertkin             // processing this
1532*3088717bSVictor Perevertkin             //
1533*3088717bSVictor Perevertkin             ClassReleaseRemoveLock(deviceObject, irp);
1534*3088717bSVictor Perevertkin 
1535*3088717bSVictor Perevertkin             IoFreeMdl(irp->MdlAddress);
1536*3088717bSVictor Perevertkin             IoFreeIrp(irp);
1537*3088717bSVictor Perevertkin 
1538*3088717bSVictor Perevertkin             FREE_POOL(reregRequest);
1539*3088717bSVictor Perevertkin 
1540*3088717bSVictor Perevertkin         } else {
1541*3088717bSVictor Perevertkin 
1542*3088717bSVictor Perevertkin             NT_ASSERTMSG("Disk Re-registration request list should not be empty", FALSE);
1543*3088717bSVictor Perevertkin 
1544*3088717bSVictor Perevertkin             status = STATUS_INTERNAL_ERROR;
1545*3088717bSVictor Perevertkin         }
1546*3088717bSVictor Perevertkin 
1547*3088717bSVictor Perevertkin         if (!NT_SUCCESS(status))
1548*3088717bSVictor Perevertkin         {
1549*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskReregWorker: Reregistration failed %x\n",
1550*3088717bSVictor Perevertkin                         status));
1551*3088717bSVictor Perevertkin         }
1552*3088717bSVictor Perevertkin 
1553*3088717bSVictor Perevertkin     } while (InterlockedDecrement(&DiskReregWorkItems));
1554*3088717bSVictor Perevertkin 
1555*3088717bSVictor Perevertkin     IoFreeWorkItem((PIO_WORKITEM)Context);
1556*3088717bSVictor Perevertkin }
1557*3088717bSVictor Perevertkin 
1558*3088717bSVictor Perevertkin 
1559*3088717bSVictor Perevertkin NTSTATUS
DiskInitializeReregistration(VOID)1560*3088717bSVictor Perevertkin DiskInitializeReregistration(
1561*3088717bSVictor Perevertkin     VOID
1562*3088717bSVictor Perevertkin     )
1563*3088717bSVictor Perevertkin {
1564*3088717bSVictor Perevertkin     PAGED_CODE();
1565*3088717bSVictor Perevertkin 
1566*3088717bSVictor Perevertkin     //
1567*3088717bSVictor Perevertkin     // Initialize the spinlock used to manage the
1568*3088717bSVictor Perevertkin     // list of disks reregistering their guids
1569*3088717bSVictor Perevertkin     //
1570*3088717bSVictor Perevertkin     KeInitializeSpinLock(&DiskReregSpinlock);
1571*3088717bSVictor Perevertkin 
1572*3088717bSVictor Perevertkin     return(STATUS_SUCCESS);
1573*3088717bSVictor Perevertkin }
1574*3088717bSVictor Perevertkin 
1575*3088717bSVictor Perevertkin 
1576*3088717bSVictor Perevertkin NTSTATUS
DiskPostReregisterRequest(PDEVICE_OBJECT DeviceObject,PIRP Irp)1577*3088717bSVictor Perevertkin DiskPostReregisterRequest(
1578*3088717bSVictor Perevertkin     PDEVICE_OBJECT DeviceObject,
1579*3088717bSVictor Perevertkin     PIRP Irp
1580*3088717bSVictor Perevertkin     )
1581*3088717bSVictor Perevertkin {
1582*3088717bSVictor Perevertkin     PDISKREREGREQUEST reregRequest;
1583*3088717bSVictor Perevertkin     PIO_WORKITEM workItem;
1584*3088717bSVictor Perevertkin     NTSTATUS status;
1585*3088717bSVictor Perevertkin 
1586*3088717bSVictor Perevertkin     workItem = IoAllocateWorkItem(DeviceObject);
1587*3088717bSVictor Perevertkin 
1588*3088717bSVictor Perevertkin     if (!workItem) {
1589*3088717bSVictor Perevertkin         return STATUS_INSUFFICIENT_RESOURCES;
1590*3088717bSVictor Perevertkin     }
1591*3088717bSVictor Perevertkin 
1592*3088717bSVictor Perevertkin     reregRequest = ExAllocatePoolWithTag(NonPagedPoolNx,
1593*3088717bSVictor Perevertkin                                          sizeof(DISKREREGREQUEST),
1594*3088717bSVictor Perevertkin                                          DISK_TAG_SMART);
1595*3088717bSVictor Perevertkin     if (reregRequest != NULL)
1596*3088717bSVictor Perevertkin     {
1597*3088717bSVictor Perevertkin         //
1598*3088717bSVictor Perevertkin         // add the disk that needs reregistration to the stack of disks
1599*3088717bSVictor Perevertkin         // to reregister. If the list is transitioning from empty to
1600*3088717bSVictor Perevertkin         // non empty then also kick off the work item so that the
1601*3088717bSVictor Perevertkin         // reregistration worker can do the reregister.
1602*3088717bSVictor Perevertkin         //
1603*3088717bSVictor Perevertkin         reregRequest->DeviceObject = DeviceObject;
1604*3088717bSVictor Perevertkin         reregRequest->Irp = Irp;
1605*3088717bSVictor Perevertkin         ExInterlockedPushEntryList(
1606*3088717bSVictor Perevertkin                                    &DiskReregHead,
1607*3088717bSVictor Perevertkin                                    &reregRequest->Next,
1608*3088717bSVictor Perevertkin                                    &DiskReregSpinlock);
1609*3088717bSVictor Perevertkin 
1610*3088717bSVictor Perevertkin         if (InterlockedIncrement(&DiskReregWorkItems) == 1)
1611*3088717bSVictor Perevertkin         {
1612*3088717bSVictor Perevertkin             //
1613*3088717bSVictor Perevertkin             // There is no worker routine running, queue this one.
1614*3088717bSVictor Perevertkin             // When the work item runs, it will process the reregistration
1615*3088717bSVictor Perevertkin             // list.
1616*3088717bSVictor Perevertkin             //
1617*3088717bSVictor Perevertkin 
1618*3088717bSVictor Perevertkin             IoQueueWorkItem(workItem,
1619*3088717bSVictor Perevertkin                             DiskReregWorker,
1620*3088717bSVictor Perevertkin                             DelayedWorkQueue,
1621*3088717bSVictor Perevertkin                             workItem);
1622*3088717bSVictor Perevertkin         } else {
1623*3088717bSVictor Perevertkin 
1624*3088717bSVictor Perevertkin             //
1625*3088717bSVictor Perevertkin             // There is a worker routine already running, so we
1626*3088717bSVictor Perevertkin             // can free this unused work item.
1627*3088717bSVictor Perevertkin             //
1628*3088717bSVictor Perevertkin 
1629*3088717bSVictor Perevertkin             IoFreeWorkItem(workItem);
1630*3088717bSVictor Perevertkin         }
1631*3088717bSVictor Perevertkin 
1632*3088717bSVictor Perevertkin         status = STATUS_SUCCESS;
1633*3088717bSVictor Perevertkin 
1634*3088717bSVictor Perevertkin     } else {
1635*3088717bSVictor Perevertkin 
1636*3088717bSVictor Perevertkin         IoFreeWorkItem(workItem);
1637*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskPostReregisterRequest: could not allocate reregRequest for %p\n",
1638*3088717bSVictor Perevertkin                     DeviceObject));
1639*3088717bSVictor Perevertkin         status = STATUS_INSUFFICIENT_RESOURCES;
1640*3088717bSVictor Perevertkin     }
1641*3088717bSVictor Perevertkin 
1642*3088717bSVictor Perevertkin     return(status);
1643*3088717bSVictor Perevertkin }
1644*3088717bSVictor Perevertkin 
1645*3088717bSVictor Perevertkin 
1646*3088717bSVictor Perevertkin NTSTATUS
1647*3088717bSVictor Perevertkin NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskInfoExceptionComplete(PDEVICE_OBJECT DeviceObject,PIRP Irp,PVOID Context)1648*3088717bSVictor Perevertkin DiskInfoExceptionComplete(
1649*3088717bSVictor Perevertkin     PDEVICE_OBJECT DeviceObject,
1650*3088717bSVictor Perevertkin     PIRP Irp,
1651*3088717bSVictor Perevertkin     PVOID Context
1652*3088717bSVictor Perevertkin     )
1653*3088717bSVictor Perevertkin {
1654*3088717bSVictor Perevertkin     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1655*3088717bSVictor Perevertkin     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
1656*3088717bSVictor Perevertkin     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1657*3088717bSVictor Perevertkin     PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
1658*3088717bSVictor Perevertkin     PSCSI_REQUEST_BLOCK srb = Context;
1659*3088717bSVictor Perevertkin     NTSTATUS status;
1660*3088717bSVictor Perevertkin     BOOLEAN retry;
1661*3088717bSVictor Perevertkin     ULONG retryInterval;
1662*3088717bSVictor Perevertkin     ULONG srbStatus;
1663*3088717bSVictor Perevertkin     BOOLEAN freeLockAndIrp = TRUE;
1664*3088717bSVictor Perevertkin     PVOID originalSenseInfoBuffer = irpStack->Parameters.Others.Argument3;
1665*3088717bSVictor Perevertkin     PSTORAGE_REQUEST_BLOCK srbEx = NULL;
1666*3088717bSVictor Perevertkin     PVOID dataBuffer = NULL;
1667*3088717bSVictor Perevertkin     ULONG dataLength = 0;
1668*3088717bSVictor Perevertkin     PVOID senseBuffer = NULL;
1669*3088717bSVictor Perevertkin     UCHAR cdbLength8 = 0;
1670*3088717bSVictor Perevertkin     ULONG cdbLength32 = 0;
1671*3088717bSVictor Perevertkin     UCHAR senseBufferLength = 0;
1672*3088717bSVictor Perevertkin 
1673*3088717bSVictor Perevertkin     srbStatus = SRB_STATUS(srb->SrbStatus);
1674*3088717bSVictor Perevertkin 
1675*3088717bSVictor Perevertkin     if (srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) {
1676*3088717bSVictor Perevertkin         srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
1677*3088717bSVictor Perevertkin         dataBuffer = srbEx->DataBuffer;
1678*3088717bSVictor Perevertkin         dataLength = srbEx->DataTransferLength;
1679*3088717bSVictor Perevertkin         if ((srbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI) &&
1680*3088717bSVictor Perevertkin             (srbEx->NumSrbExData > 0)) {
1681*3088717bSVictor Perevertkin             (void)GetSrbScsiData(srbEx, &cdbLength8, &cdbLength32, NULL, &senseBuffer, &senseBufferLength);
1682*3088717bSVictor Perevertkin         }
1683*3088717bSVictor Perevertkin     } else {
1684*3088717bSVictor Perevertkin         dataBuffer = srb->DataBuffer;
1685*3088717bSVictor Perevertkin         dataLength = srb->DataTransferLength;
1686*3088717bSVictor Perevertkin         senseBuffer = srb->SenseInfoBuffer;
1687*3088717bSVictor Perevertkin     }
1688*3088717bSVictor Perevertkin 
1689*3088717bSVictor Perevertkin     //
1690*3088717bSVictor Perevertkin     // Check SRB status for success of completing request.
1691*3088717bSVictor Perevertkin     // SRB_STATUS_DATA_OVERRUN also indicates success.
1692*3088717bSVictor Perevertkin     //
1693*3088717bSVictor Perevertkin     if ((srbStatus != SRB_STATUS_SUCCESS) &&
1694*3088717bSVictor Perevertkin         (srbStatus != SRB_STATUS_DATA_OVERRUN))
1695*3088717bSVictor Perevertkin     {
1696*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskInfoExceptionComplete: IRP %p, SRB %p\n", Irp, srb));
1697*3088717bSVictor Perevertkin 
1698*3088717bSVictor Perevertkin         if (TEST_FLAG(srb->SrbStatus, SRB_STATUS_QUEUE_FROZEN))
1699*3088717bSVictor Perevertkin         {
1700*3088717bSVictor Perevertkin             ClassReleaseQueue(DeviceObject);
1701*3088717bSVictor Perevertkin         }
1702*3088717bSVictor Perevertkin 
1703*3088717bSVictor Perevertkin         retry = ClassInterpretSenseInfo(
1704*3088717bSVictor Perevertkin                     DeviceObject,
1705*3088717bSVictor Perevertkin                     srb,
1706*3088717bSVictor Perevertkin                     irpStack->MajorFunction,
1707*3088717bSVictor Perevertkin                      0,
1708*3088717bSVictor Perevertkin                     MAXIMUM_RETRIES -
1709*3088717bSVictor Perevertkin                         ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
1710*3088717bSVictor Perevertkin                     &status,
1711*3088717bSVictor Perevertkin                     &retryInterval);
1712*3088717bSVictor Perevertkin 
1713*3088717bSVictor Perevertkin         //
1714*3088717bSVictor Perevertkin         // If the status is verified required and the this request
1715*3088717bSVictor Perevertkin         // should bypass verify required then retry the request.
1716*3088717bSVictor Perevertkin         //
1717*3088717bSVictor Perevertkin 
1718*3088717bSVictor Perevertkin         if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
1719*3088717bSVictor Perevertkin             status == STATUS_VERIFY_REQUIRED)
1720*3088717bSVictor Perevertkin         {
1721*3088717bSVictor Perevertkin             status = STATUS_IO_DEVICE_ERROR;
1722*3088717bSVictor Perevertkin             retry = TRUE;
1723*3088717bSVictor Perevertkin         }
1724*3088717bSVictor Perevertkin 
1725*3088717bSVictor Perevertkin         retry = retry && irpStack->Parameters.Others.Argument4;
1726*3088717bSVictor Perevertkin 
1727*3088717bSVictor Perevertkin         irpStack->Parameters.Others.Argument4 = (PVOID)((ULONG_PTR)irpStack->Parameters.Others.Argument4 - 1);
1728*3088717bSVictor Perevertkin 
1729*3088717bSVictor Perevertkin         if (retry)
1730*3088717bSVictor Perevertkin         {
1731*3088717bSVictor Perevertkin             //
1732*3088717bSVictor Perevertkin             // Retry request.
1733*3088717bSVictor Perevertkin             //
1734*3088717bSVictor Perevertkin 
1735*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskInfoExceptionComplete: Retry request %p\n", Irp));
1736*3088717bSVictor Perevertkin 
1737*3088717bSVictor Perevertkin             NT_ASSERT(dataBuffer == MmGetMdlVirtualAddress(Irp->MdlAddress));
1738*3088717bSVictor Perevertkin 
1739*3088717bSVictor Perevertkin             if (srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) {
1740*3088717bSVictor Perevertkin 
1741*3088717bSVictor Perevertkin                 //
1742*3088717bSVictor Perevertkin                 // Reset byte count of transfer in SRB Extension.
1743*3088717bSVictor Perevertkin                 //
1744*3088717bSVictor Perevertkin                 srbEx->DataTransferLength = Irp->MdlAddress->ByteCount;
1745*3088717bSVictor Perevertkin 
1746*3088717bSVictor Perevertkin                 //
1747*3088717bSVictor Perevertkin                 // Zero SRB statuses.
1748*3088717bSVictor Perevertkin                 //
1749*3088717bSVictor Perevertkin 
1750*3088717bSVictor Perevertkin                 srbEx->SrbStatus = 0;
1751*3088717bSVictor Perevertkin                 if ((srbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI) &&
1752*3088717bSVictor Perevertkin                     (srbEx->NumSrbExData > 0)) {
1753*3088717bSVictor Perevertkin                     SetSrbScsiData(srbEx, cdbLength8, cdbLength32, 0, senseBuffer, senseBufferLength);
1754*3088717bSVictor Perevertkin                 }
1755*3088717bSVictor Perevertkin 
1756*3088717bSVictor Perevertkin                 //
1757*3088717bSVictor Perevertkin                 // Set the no disconnect flag, disable synchronous data transfers and
1758*3088717bSVictor Perevertkin                 // disable tagged queuing. This fixes some errors.
1759*3088717bSVictor Perevertkin                 //
1760*3088717bSVictor Perevertkin 
1761*3088717bSVictor Perevertkin                 SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT);
1762*3088717bSVictor Perevertkin                 SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
1763*3088717bSVictor Perevertkin                 CLEAR_FLAG(srbEx->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
1764*3088717bSVictor Perevertkin 
1765*3088717bSVictor Perevertkin                 srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST;
1766*3088717bSVictor Perevertkin                 srbEx->RequestTag = SP_UNTAGGED;
1767*3088717bSVictor Perevertkin 
1768*3088717bSVictor Perevertkin             } else {
1769*3088717bSVictor Perevertkin 
1770*3088717bSVictor Perevertkin                 //
1771*3088717bSVictor Perevertkin                 // Reset byte count of transfer in SRB Extension.
1772*3088717bSVictor Perevertkin                 //
1773*3088717bSVictor Perevertkin                 srb->DataTransferLength = Irp->MdlAddress->ByteCount;
1774*3088717bSVictor Perevertkin 
1775*3088717bSVictor Perevertkin                 //
1776*3088717bSVictor Perevertkin                 // Zero SRB statuses.
1777*3088717bSVictor Perevertkin                 //
1778*3088717bSVictor Perevertkin 
1779*3088717bSVictor Perevertkin                 srb->SrbStatus = srb->ScsiStatus = 0;
1780*3088717bSVictor Perevertkin 
1781*3088717bSVictor Perevertkin                 //
1782*3088717bSVictor Perevertkin                 // Set the no disconnect flag, disable synchronous data transfers and
1783*3088717bSVictor Perevertkin                 // disable tagged queuing. This fixes some errors.
1784*3088717bSVictor Perevertkin                 //
1785*3088717bSVictor Perevertkin 
1786*3088717bSVictor Perevertkin                 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT);
1787*3088717bSVictor Perevertkin                 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
1788*3088717bSVictor Perevertkin                 CLEAR_FLAG(srb->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
1789*3088717bSVictor Perevertkin 
1790*3088717bSVictor Perevertkin                 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
1791*3088717bSVictor Perevertkin                 srb->QueueTag = SP_UNTAGGED;
1792*3088717bSVictor Perevertkin             }
1793*3088717bSVictor Perevertkin 
1794*3088717bSVictor Perevertkin             //
1795*3088717bSVictor Perevertkin             // Set up major SCSI function.
1796*3088717bSVictor Perevertkin             //
1797*3088717bSVictor Perevertkin 
1798*3088717bSVictor Perevertkin             nextIrpStack->MajorFunction = IRP_MJ_SCSI;
1799*3088717bSVictor Perevertkin 
1800*3088717bSVictor Perevertkin             //
1801*3088717bSVictor Perevertkin             // Save SRB address in next stack for port driver.
1802*3088717bSVictor Perevertkin             //
1803*3088717bSVictor Perevertkin 
1804*3088717bSVictor Perevertkin             nextIrpStack->Parameters.Scsi.Srb = srb;
1805*3088717bSVictor Perevertkin 
1806*3088717bSVictor Perevertkin 
1807*3088717bSVictor Perevertkin             IoSetCompletionRoutine(Irp,
1808*3088717bSVictor Perevertkin                                    DiskInfoExceptionComplete,
1809*3088717bSVictor Perevertkin                                    srb,
1810*3088717bSVictor Perevertkin                                    TRUE, TRUE, TRUE);
1811*3088717bSVictor Perevertkin 
1812*3088717bSVictor Perevertkin             (VOID)IoCallDriver(commonExtension->LowerDeviceObject, Irp);
1813*3088717bSVictor Perevertkin 
1814*3088717bSVictor Perevertkin             return STATUS_MORE_PROCESSING_REQUIRED;
1815*3088717bSVictor Perevertkin         }
1816*3088717bSVictor Perevertkin 
1817*3088717bSVictor Perevertkin     } else {
1818*3088717bSVictor Perevertkin 
1819*3088717bSVictor Perevertkin         //
1820*3088717bSVictor Perevertkin         // Get the results from the mode sense
1821*3088717bSVictor Perevertkin         //
1822*3088717bSVictor Perevertkin         PMODE_INFO_EXCEPTIONS pageData;
1823*3088717bSVictor Perevertkin         PMODE_PARAMETER_HEADER modeData;
1824*3088717bSVictor Perevertkin         ULONG modeDataLength;
1825*3088717bSVictor Perevertkin 
1826*3088717bSVictor Perevertkin         modeData = dataBuffer;
1827*3088717bSVictor Perevertkin         modeDataLength = dataLength;
1828*3088717bSVictor Perevertkin 
1829*3088717bSVictor Perevertkin         pageData = ClassFindModePage((PCHAR)modeData,
1830*3088717bSVictor Perevertkin                                      modeDataLength,
1831*3088717bSVictor Perevertkin                                      MODE_PAGE_FAULT_REPORTING,
1832*3088717bSVictor Perevertkin                                      TRUE);
1833*3088717bSVictor Perevertkin         if (pageData != NULL)
1834*3088717bSVictor Perevertkin         {
1835*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskInfoExceptionComplete: %p supports SMART\n",
1836*3088717bSVictor Perevertkin                         DeviceObject));
1837*3088717bSVictor Perevertkin 
1838*3088717bSVictor Perevertkin             diskData->ScsiInfoExceptionsSupported = TRUE;
1839*3088717bSVictor Perevertkin 
1840*3088717bSVictor Perevertkin             //
1841*3088717bSVictor Perevertkin             // The DEXCPT bit must be 0 and the MRIE field must be valid.
1842*3088717bSVictor Perevertkin             //
1843*3088717bSVictor Perevertkin             if (pageData->Dexcpt == 0 &&
1844*3088717bSVictor Perevertkin                 pageData->ReportMethod >= 2 &&
1845*3088717bSVictor Perevertkin                 pageData->ReportMethod <= 6)
1846*3088717bSVictor Perevertkin             {
1847*3088717bSVictor Perevertkin                 diskData->FailurePredictionCapability = FailurePredictionSense;
1848*3088717bSVictor Perevertkin                 diskData->FailurePredictionEnabled = TRUE;
1849*3088717bSVictor Perevertkin                 status = DiskPostReregisterRequest(DeviceObject, Irp);
1850*3088717bSVictor Perevertkin 
1851*3088717bSVictor Perevertkin                 if (NT_SUCCESS(status))
1852*3088717bSVictor Perevertkin                 {
1853*3088717bSVictor Perevertkin                     //
1854*3088717bSVictor Perevertkin                     // Make sure we won't free the remove lock and the irp
1855*3088717bSVictor Perevertkin                     // since we need to keep these until after the work
1856*3088717bSVictor Perevertkin                     // item has completed running
1857*3088717bSVictor Perevertkin                     //
1858*3088717bSVictor Perevertkin                     freeLockAndIrp = FALSE;
1859*3088717bSVictor Perevertkin                 }
1860*3088717bSVictor Perevertkin             } else {
1861*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionComplete: %p is not enabled for SMART\n",
1862*3088717bSVictor Perevertkin                         DeviceObject));
1863*3088717bSVictor Perevertkin 
1864*3088717bSVictor Perevertkin             }
1865*3088717bSVictor Perevertkin 
1866*3088717bSVictor Perevertkin         } else {
1867*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionComplete: %p does not supports SMART\n",
1868*3088717bSVictor Perevertkin                         DeviceObject));
1869*3088717bSVictor Perevertkin 
1870*3088717bSVictor Perevertkin         }
1871*3088717bSVictor Perevertkin 
1872*3088717bSVictor Perevertkin         //
1873*3088717bSVictor Perevertkin         // Set status for successful request
1874*3088717bSVictor Perevertkin         //
1875*3088717bSVictor Perevertkin 
1876*3088717bSVictor Perevertkin         status = STATUS_SUCCESS;
1877*3088717bSVictor Perevertkin 
1878*3088717bSVictor Perevertkin     } // end if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)
1879*3088717bSVictor Perevertkin 
1880*3088717bSVictor Perevertkin     //
1881*3088717bSVictor Perevertkin     // Free the srb
1882*3088717bSVictor Perevertkin     //
1883*3088717bSVictor Perevertkin     if (senseBuffer != originalSenseInfoBuffer)
1884*3088717bSVictor Perevertkin     {
1885*3088717bSVictor Perevertkin         //
1886*3088717bSVictor Perevertkin         // Free the original sense info buffer in case the port driver has overwritten it
1887*3088717bSVictor Perevertkin         //
1888*3088717bSVictor Perevertkin         FREE_POOL(originalSenseInfoBuffer);
1889*3088717bSVictor Perevertkin     }
1890*3088717bSVictor Perevertkin 
1891*3088717bSVictor Perevertkin     FREE_POOL(senseBuffer);
1892*3088717bSVictor Perevertkin     FREE_POOL(dataBuffer);
1893*3088717bSVictor Perevertkin     FREE_POOL(srb);
1894*3088717bSVictor Perevertkin 
1895*3088717bSVictor Perevertkin     if (freeLockAndIrp)
1896*3088717bSVictor Perevertkin     {
1897*3088717bSVictor Perevertkin         //
1898*3088717bSVictor Perevertkin         // Set status in completing IRP.
1899*3088717bSVictor Perevertkin         //
1900*3088717bSVictor Perevertkin 
1901*3088717bSVictor Perevertkin         Irp->IoStatus.Status = status;
1902*3088717bSVictor Perevertkin 
1903*3088717bSVictor Perevertkin         //
1904*3088717bSVictor Perevertkin         // If pending has be returned for this irp then mark the current stack as
1905*3088717bSVictor Perevertkin         // pending.
1906*3088717bSVictor Perevertkin         //
1907*3088717bSVictor Perevertkin 
1908*3088717bSVictor Perevertkin         if (Irp->PendingReturned) {
1909*3088717bSVictor Perevertkin             IoMarkIrpPending(Irp);
1910*3088717bSVictor Perevertkin         }
1911*3088717bSVictor Perevertkin 
1912*3088717bSVictor Perevertkin         ClassReleaseRemoveLock(DeviceObject, Irp);
1913*3088717bSVictor Perevertkin         IoFreeMdl(Irp->MdlAddress);
1914*3088717bSVictor Perevertkin         IoFreeIrp(Irp);
1915*3088717bSVictor Perevertkin     }
1916*3088717bSVictor Perevertkin 
1917*3088717bSVictor Perevertkin     return(STATUS_MORE_PROCESSING_REQUIRED);
1918*3088717bSVictor Perevertkin }
1919*3088717bSVictor Perevertkin 
1920*3088717bSVictor Perevertkin 
1921*3088717bSVictor Perevertkin NTSTATUS
DiskInfoExceptionCheck(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)1922*3088717bSVictor Perevertkin DiskInfoExceptionCheck(
1923*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
1924*3088717bSVictor Perevertkin     )
1925*3088717bSVictor Perevertkin {
1926*3088717bSVictor Perevertkin     PUCHAR modeData;
1927*3088717bSVictor Perevertkin     PSCSI_REQUEST_BLOCK srb;
1928*3088717bSVictor Perevertkin     PCDB cdb;
1929*3088717bSVictor Perevertkin     PIRP irp;
1930*3088717bSVictor Perevertkin     PIO_STACK_LOCATION irpStack;
1931*3088717bSVictor Perevertkin     PVOID senseInfoBuffer = NULL;
1932*3088717bSVictor Perevertkin     UCHAR senseInfoBufferLength = 0;
1933*3088717bSVictor Perevertkin     ULONG isRemoved;
1934*3088717bSVictor Perevertkin     ULONG srbSize;
1935*3088717bSVictor Perevertkin     PSTORAGE_REQUEST_BLOCK srbEx = NULL;
1936*3088717bSVictor Perevertkin     PSTOR_ADDR_BTL8 storAddrBtl8 = NULL;
1937*3088717bSVictor Perevertkin     PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL;
1938*3088717bSVictor Perevertkin 
1939*3088717bSVictor Perevertkin     modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
1940*3088717bSVictor Perevertkin                                      MODE_DATA_SIZE,
1941*3088717bSVictor Perevertkin                                      DISK_TAG_INFO_EXCEPTION);
1942*3088717bSVictor Perevertkin     if (modeData == NULL)
1943*3088717bSVictor Perevertkin     {
1944*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionCheck: Can't allocate mode data "
1945*3088717bSVictor Perevertkin                         "buffer\n"));
1946*3088717bSVictor Perevertkin         return(STATUS_INSUFFICIENT_RESOURCES);
1947*3088717bSVictor Perevertkin     }
1948*3088717bSVictor Perevertkin 
1949*3088717bSVictor Perevertkin     if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1950*3088717bSVictor Perevertkin         srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
1951*3088717bSVictor Perevertkin     } else {
1952*3088717bSVictor Perevertkin         srbSize = SCSI_REQUEST_BLOCK_SIZE;
1953*3088717bSVictor Perevertkin     }
1954*3088717bSVictor Perevertkin     srb = ExAllocatePoolWithTag(NonPagedPoolNx,
1955*3088717bSVictor Perevertkin                                 srbSize,
1956*3088717bSVictor Perevertkin                                 DISK_TAG_SRB);
1957*3088717bSVictor Perevertkin     if (srb == NULL)
1958*3088717bSVictor Perevertkin     {
1959*3088717bSVictor Perevertkin         FREE_POOL(modeData);
1960*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionCheck: Can't allocate srb "
1961*3088717bSVictor Perevertkin                         "buffer\n"));
1962*3088717bSVictor Perevertkin         return(STATUS_INSUFFICIENT_RESOURCES);
1963*3088717bSVictor Perevertkin     }
1964*3088717bSVictor Perevertkin     RtlZeroMemory(srb, srbSize);
1965*3088717bSVictor Perevertkin 
1966*3088717bSVictor Perevertkin     //
1967*3088717bSVictor Perevertkin     // Sense buffer is in aligned nonpaged pool.
1968*3088717bSVictor Perevertkin     //
1969*3088717bSVictor Perevertkin 
1970*3088717bSVictor Perevertkin     senseInfoBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
1971*3088717bSVictor Perevertkin                                             SENSE_BUFFER_SIZE_EX,
1972*3088717bSVictor Perevertkin                                             '7CcS');
1973*3088717bSVictor Perevertkin 
1974*3088717bSVictor Perevertkin     if (senseInfoBuffer == NULL)
1975*3088717bSVictor Perevertkin     {
1976*3088717bSVictor Perevertkin         FREE_POOL(srb);
1977*3088717bSVictor Perevertkin         FREE_POOL(modeData);
1978*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionCheck: Can't allocate request sense "
1979*3088717bSVictor Perevertkin                         "buffer\n"));
1980*3088717bSVictor Perevertkin         return(STATUS_INSUFFICIENT_RESOURCES);
1981*3088717bSVictor Perevertkin     }
1982*3088717bSVictor Perevertkin 
1983*3088717bSVictor Perevertkin     senseInfoBufferLength = SENSE_BUFFER_SIZE_EX;
1984*3088717bSVictor Perevertkin 
1985*3088717bSVictor Perevertkin     //
1986*3088717bSVictor Perevertkin     // Build device I/O control request with METHOD_NEITHER data transfer.
1987*3088717bSVictor Perevertkin     // We'll queue a completion routine to cleanup the MDL's and such ourself.
1988*3088717bSVictor Perevertkin     //
1989*3088717bSVictor Perevertkin 
1990*3088717bSVictor Perevertkin     irp = IoAllocateIrp(
1991*3088717bSVictor Perevertkin             (CCHAR) (FdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1),
1992*3088717bSVictor Perevertkin             FALSE);
1993*3088717bSVictor Perevertkin 
1994*3088717bSVictor Perevertkin     if (irp == NULL)
1995*3088717bSVictor Perevertkin     {
1996*3088717bSVictor Perevertkin         FREE_POOL(senseInfoBuffer);
1997*3088717bSVictor Perevertkin         FREE_POOL(srb);
1998*3088717bSVictor Perevertkin         FREE_POOL(modeData);
1999*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionCheck: Can't allocate Irp\n"));
2000*3088717bSVictor Perevertkin         return(STATUS_INSUFFICIENT_RESOURCES);
2001*3088717bSVictor Perevertkin     }
2002*3088717bSVictor Perevertkin 
2003*3088717bSVictor Perevertkin     isRemoved = ClassAcquireRemoveLock(FdoExtension->DeviceObject, irp);
2004*3088717bSVictor Perevertkin 
2005*3088717bSVictor Perevertkin     if (isRemoved)
2006*3088717bSVictor Perevertkin     {
2007*3088717bSVictor Perevertkin         ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp);
2008*3088717bSVictor Perevertkin         IoFreeIrp(irp);
2009*3088717bSVictor Perevertkin         FREE_POOL(senseInfoBuffer);
2010*3088717bSVictor Perevertkin         FREE_POOL(srb);
2011*3088717bSVictor Perevertkin         FREE_POOL(modeData);
2012*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskInfoExceptionCheck: RemoveLock says isRemoved\n"));
2013*3088717bSVictor Perevertkin         return(STATUS_DEVICE_DOES_NOT_EXIST);
2014*3088717bSVictor Perevertkin     }
2015*3088717bSVictor Perevertkin 
2016*3088717bSVictor Perevertkin     //
2017*3088717bSVictor Perevertkin     // Get next stack location.
2018*3088717bSVictor Perevertkin     //
2019*3088717bSVictor Perevertkin 
2020*3088717bSVictor Perevertkin     IoSetNextIrpStackLocation(irp);
2021*3088717bSVictor Perevertkin     irpStack = IoGetCurrentIrpStackLocation(irp);
2022*3088717bSVictor Perevertkin     irpStack->DeviceObject = FdoExtension->DeviceObject;
2023*3088717bSVictor Perevertkin 
2024*3088717bSVictor Perevertkin     //
2025*3088717bSVictor Perevertkin     // Save retry count in current Irp stack.
2026*3088717bSVictor Perevertkin     //
2027*3088717bSVictor Perevertkin     irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
2028*3088717bSVictor Perevertkin 
2029*3088717bSVictor Perevertkin     //
2030*3088717bSVictor Perevertkin     // Save allocated sense info buffer in case the port driver overwrites it
2031*3088717bSVictor Perevertkin     //
2032*3088717bSVictor Perevertkin     irpStack->Parameters.Others.Argument3 = senseInfoBuffer;
2033*3088717bSVictor Perevertkin 
2034*3088717bSVictor Perevertkin     irpStack = IoGetNextIrpStackLocation(irp);
2035*3088717bSVictor Perevertkin 
2036*3088717bSVictor Perevertkin     //
2037*3088717bSVictor Perevertkin     // Set up SRB for execute scsi request. Save SRB address in next stack
2038*3088717bSVictor Perevertkin     // for the port driver.
2039*3088717bSVictor Perevertkin     //
2040*3088717bSVictor Perevertkin 
2041*3088717bSVictor Perevertkin     irpStack->MajorFunction = IRP_MJ_SCSI;
2042*3088717bSVictor Perevertkin     irpStack->Parameters.Scsi.Srb = srb;
2043*3088717bSVictor Perevertkin 
2044*3088717bSVictor Perevertkin     IoSetCompletionRoutine(irp,
2045*3088717bSVictor Perevertkin                            DiskInfoExceptionComplete,
2046*3088717bSVictor Perevertkin                            srb,
2047*3088717bSVictor Perevertkin                            TRUE,
2048*3088717bSVictor Perevertkin                            TRUE,
2049*3088717bSVictor Perevertkin                            TRUE);
2050*3088717bSVictor Perevertkin 
2051*3088717bSVictor Perevertkin     irp->MdlAddress = IoAllocateMdl( modeData,
2052*3088717bSVictor Perevertkin                                      MODE_DATA_SIZE,
2053*3088717bSVictor Perevertkin                                      FALSE,
2054*3088717bSVictor Perevertkin                                      FALSE,
2055*3088717bSVictor Perevertkin                                      irp );
2056*3088717bSVictor Perevertkin     if (irp->MdlAddress == NULL)
2057*3088717bSVictor Perevertkin     {
2058*3088717bSVictor Perevertkin         ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp);
2059*3088717bSVictor Perevertkin         FREE_POOL(srb);
2060*3088717bSVictor Perevertkin         FREE_POOL(modeData);
2061*3088717bSVictor Perevertkin         FREE_POOL(senseInfoBuffer);
2062*3088717bSVictor Perevertkin         IoFreeIrp( irp );
2063*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskINfoExceptionCheck: Can't allocate MDL\n"));
2064*3088717bSVictor Perevertkin         return STATUS_INSUFFICIENT_RESOURCES;
2065*3088717bSVictor Perevertkin     }
2066*3088717bSVictor Perevertkin 
2067*3088717bSVictor Perevertkin     MmBuildMdlForNonPagedPool(irp->MdlAddress);
2068*3088717bSVictor Perevertkin 
2069*3088717bSVictor Perevertkin     //
2070*3088717bSVictor Perevertkin     // Build the MODE SENSE CDB.
2071*3088717bSVictor Perevertkin     //
2072*3088717bSVictor Perevertkin 
2073*3088717bSVictor Perevertkin     if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2074*3088717bSVictor Perevertkin 
2075*3088717bSVictor Perevertkin         //
2076*3088717bSVictor Perevertkin         // Set up STORAGE_REQUEST_BLOCK fields
2077*3088717bSVictor Perevertkin         //
2078*3088717bSVictor Perevertkin 
2079*3088717bSVictor Perevertkin         srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
2080*3088717bSVictor Perevertkin         srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
2081*3088717bSVictor Perevertkin         srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
2082*3088717bSVictor Perevertkin         srbEx->Signature = SRB_SIGNATURE;
2083*3088717bSVictor Perevertkin         srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
2084*3088717bSVictor Perevertkin         srbEx->SrbLength = srbSize;
2085*3088717bSVictor Perevertkin         srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
2086*3088717bSVictor Perevertkin         srbEx->RequestPriority = IoGetIoPriorityHint(irp);
2087*3088717bSVictor Perevertkin         srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
2088*3088717bSVictor Perevertkin         srbEx->NumSrbExData = 1;
2089*3088717bSVictor Perevertkin 
2090*3088717bSVictor Perevertkin         // Set timeout value from device extension.
2091*3088717bSVictor Perevertkin         srbEx->TimeOutValue = FdoExtension->TimeOutValue;
2092*3088717bSVictor Perevertkin 
2093*3088717bSVictor Perevertkin         // Set the transfer length.
2094*3088717bSVictor Perevertkin         srbEx->DataTransferLength = MODE_DATA_SIZE;
2095*3088717bSVictor Perevertkin         srbEx->DataBuffer = modeData;
2096*3088717bSVictor Perevertkin 
2097*3088717bSVictor Perevertkin         srbEx->SrbFlags = FdoExtension->SrbFlags;
2098*3088717bSVictor Perevertkin 
2099*3088717bSVictor Perevertkin         SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_DATA_IN);
2100*3088717bSVictor Perevertkin 
2101*3088717bSVictor Perevertkin         //
2102*3088717bSVictor Perevertkin         // Disable synchronous transfer for these requests.
2103*3088717bSVictor Perevertkin         //
2104*3088717bSVictor Perevertkin         SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2105*3088717bSVictor Perevertkin 
2106*3088717bSVictor Perevertkin         //
2107*3088717bSVictor Perevertkin         // Don't freeze the queue on an error
2108*3088717bSVictor Perevertkin         //
2109*3088717bSVictor Perevertkin         SET_FLAG(srbEx->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
2110*3088717bSVictor Perevertkin 
2111*3088717bSVictor Perevertkin         srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST;
2112*3088717bSVictor Perevertkin         srbEx->RequestTag = SP_UNTAGGED;
2113*3088717bSVictor Perevertkin 
2114*3088717bSVictor Perevertkin         // Set up IRP Address.
2115*3088717bSVictor Perevertkin         srbEx->OriginalRequest = irp;
2116*3088717bSVictor Perevertkin 
2117*3088717bSVictor Perevertkin         //
2118*3088717bSVictor Perevertkin         // Set up address fields
2119*3088717bSVictor Perevertkin         //
2120*3088717bSVictor Perevertkin 
2121*3088717bSVictor Perevertkin         storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
2122*3088717bSVictor Perevertkin         storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
2123*3088717bSVictor Perevertkin         storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
2124*3088717bSVictor Perevertkin 
2125*3088717bSVictor Perevertkin         //
2126*3088717bSVictor Perevertkin         // Set up SCSI SRB extended data fields
2127*3088717bSVictor Perevertkin         //
2128*3088717bSVictor Perevertkin 
2129*3088717bSVictor Perevertkin         srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
2130*3088717bSVictor Perevertkin             sizeof(STOR_ADDR_BTL8);
2131*3088717bSVictor Perevertkin         if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
2132*3088717bSVictor Perevertkin             srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
2133*3088717bSVictor Perevertkin             srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
2134*3088717bSVictor Perevertkin             srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
2135*3088717bSVictor Perevertkin             srbExDataCdb16->CdbLength = 6;
2136*3088717bSVictor Perevertkin 
2137*3088717bSVictor Perevertkin             // Enable auto request sense.
2138*3088717bSVictor Perevertkin             srbExDataCdb16->SenseInfoBufferLength = senseInfoBufferLength;
2139*3088717bSVictor Perevertkin             srbExDataCdb16->SenseInfoBuffer = senseInfoBuffer;
2140*3088717bSVictor Perevertkin 
2141*3088717bSVictor Perevertkin             cdb = (PCDB)srbExDataCdb16->Cdb;
2142*3088717bSVictor Perevertkin         } else {
2143*3088717bSVictor Perevertkin             // Should not happen
2144*3088717bSVictor Perevertkin             NT_ASSERT(FALSE);
2145*3088717bSVictor Perevertkin 
2146*3088717bSVictor Perevertkin             ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp);
2147*3088717bSVictor Perevertkin             FREE_POOL(srb);
2148*3088717bSVictor Perevertkin             FREE_POOL(modeData);
2149*3088717bSVictor Perevertkin             FREE_POOL(senseInfoBuffer);
2150*3088717bSVictor Perevertkin             IoFreeIrp( irp );
2151*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DiskINfoExceptionCheck: Insufficient extended SRB size\n"));
2152*3088717bSVictor Perevertkin             return STATUS_INTERNAL_ERROR;
2153*3088717bSVictor Perevertkin         }
2154*3088717bSVictor Perevertkin 
2155*3088717bSVictor Perevertkin     } else {
2156*3088717bSVictor Perevertkin 
2157*3088717bSVictor Perevertkin         //
2158*3088717bSVictor Perevertkin         // Write length to SRB.
2159*3088717bSVictor Perevertkin         //
2160*3088717bSVictor Perevertkin         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2161*3088717bSVictor Perevertkin 
2162*3088717bSVictor Perevertkin         //
2163*3088717bSVictor Perevertkin         // Set SCSI bus address.
2164*3088717bSVictor Perevertkin         //
2165*3088717bSVictor Perevertkin 
2166*3088717bSVictor Perevertkin         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2167*3088717bSVictor Perevertkin 
2168*3088717bSVictor Perevertkin         //
2169*3088717bSVictor Perevertkin         // Enable auto request sense.
2170*3088717bSVictor Perevertkin         //
2171*3088717bSVictor Perevertkin 
2172*3088717bSVictor Perevertkin         srb->SenseInfoBufferLength = senseInfoBufferLength;
2173*3088717bSVictor Perevertkin         srb->SenseInfoBuffer = senseInfoBuffer;
2174*3088717bSVictor Perevertkin 
2175*3088717bSVictor Perevertkin         //
2176*3088717bSVictor Perevertkin         // Set timeout value from device extension.
2177*3088717bSVictor Perevertkin         //
2178*3088717bSVictor Perevertkin         srb->TimeOutValue = FdoExtension->TimeOutValue;
2179*3088717bSVictor Perevertkin 
2180*3088717bSVictor Perevertkin         //
2181*3088717bSVictor Perevertkin         // Set the transfer length.
2182*3088717bSVictor Perevertkin         //
2183*3088717bSVictor Perevertkin         srb->DataTransferLength = MODE_DATA_SIZE;
2184*3088717bSVictor Perevertkin         srb->DataBuffer = modeData;
2185*3088717bSVictor Perevertkin 
2186*3088717bSVictor Perevertkin         srb->SrbFlags = FdoExtension->SrbFlags;
2187*3088717bSVictor Perevertkin 
2188*3088717bSVictor Perevertkin         SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
2189*3088717bSVictor Perevertkin 
2190*3088717bSVictor Perevertkin         //
2191*3088717bSVictor Perevertkin         // Disable synchronous transfer for these requests.
2192*3088717bSVictor Perevertkin         //
2193*3088717bSVictor Perevertkin         SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2194*3088717bSVictor Perevertkin 
2195*3088717bSVictor Perevertkin         //
2196*3088717bSVictor Perevertkin         // Don't freeze the queue on an error
2197*3088717bSVictor Perevertkin         //
2198*3088717bSVictor Perevertkin         SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
2199*3088717bSVictor Perevertkin 
2200*3088717bSVictor Perevertkin         srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
2201*3088717bSVictor Perevertkin         srb->QueueTag = SP_UNTAGGED;
2202*3088717bSVictor Perevertkin 
2203*3088717bSVictor Perevertkin         //
2204*3088717bSVictor Perevertkin         // Set up IRP Address.
2205*3088717bSVictor Perevertkin         //
2206*3088717bSVictor Perevertkin         srb->OriginalRequest = irp;
2207*3088717bSVictor Perevertkin 
2208*3088717bSVictor Perevertkin         srb->CdbLength = 6;
2209*3088717bSVictor Perevertkin         cdb = (PCDB)srb->Cdb;
2210*3088717bSVictor Perevertkin 
2211*3088717bSVictor Perevertkin     }
2212*3088717bSVictor Perevertkin 
2213*3088717bSVictor Perevertkin     cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2214*3088717bSVictor Perevertkin     cdb->MODE_SENSE.PageCode = MODE_PAGE_FAULT_REPORTING;
2215*3088717bSVictor Perevertkin     cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
2216*3088717bSVictor Perevertkin 
2217*3088717bSVictor Perevertkin     //
2218*3088717bSVictor Perevertkin     // Call the port driver with the request and wait for it to complete.
2219*3088717bSVictor Perevertkin     //
2220*3088717bSVictor Perevertkin 
2221*3088717bSVictor Perevertkin     IoMarkIrpPending(irp);
2222*3088717bSVictor Perevertkin     IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject,
2223*3088717bSVictor Perevertkin                           irp);
2224*3088717bSVictor Perevertkin 
2225*3088717bSVictor Perevertkin     return(STATUS_PENDING);
2226*3088717bSVictor Perevertkin }
2227*3088717bSVictor Perevertkin 
2228*3088717bSVictor Perevertkin 
2229*3088717bSVictor Perevertkin NTSTATUS
DiskDetectFailurePrediction(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,PFAILURE_PREDICTION_METHOD FailurePredictCapability,BOOLEAN ScsiAddressAvailable)2230*3088717bSVictor Perevertkin DiskDetectFailurePrediction(
2231*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
2232*3088717bSVictor Perevertkin     PFAILURE_PREDICTION_METHOD FailurePredictCapability,
2233*3088717bSVictor Perevertkin     BOOLEAN ScsiAddressAvailable
2234*3088717bSVictor Perevertkin     )
2235*3088717bSVictor Perevertkin /*++
2236*3088717bSVictor Perevertkin 
2237*3088717bSVictor Perevertkin Routine Description:
2238*3088717bSVictor Perevertkin 
2239*3088717bSVictor Perevertkin     Detect if device has any failure prediction capabilities. First we
2240*3088717bSVictor Perevertkin     check for IDE SMART capability. This is done by sending the drive an
2241*3088717bSVictor Perevertkin     IDENTIFY command and checking if the SMART command set bit is set.
2242*3088717bSVictor Perevertkin 
2243*3088717bSVictor Perevertkin     Next we check if SCSI SMART (aka Information Exception Control Page,
2244*3088717bSVictor Perevertkin     X3T10/94-190 Rev 4). This is done by querying for the Information
2245*3088717bSVictor Perevertkin     Exception mode page.
2246*3088717bSVictor Perevertkin 
2247*3088717bSVictor Perevertkin     Lastly we check if the device has IOCTL failure prediction. This mechanism
2248*3088717bSVictor Perevertkin     a filter driver implements IOCTL_STORAGE_PREDICT_FAILURE and will respond
2249*3088717bSVictor Perevertkin     with the information in the IOCTL. We do this by sending the ioctl and
2250*3088717bSVictor Perevertkin     if the status returned is STATUS_SUCCESS we assume that it is supported.
2251*3088717bSVictor Perevertkin 
2252*3088717bSVictor Perevertkin Arguments:
2253*3088717bSVictor Perevertkin 
2254*3088717bSVictor Perevertkin     FdoExtension
2255*3088717bSVictor Perevertkin 
2256*3088717bSVictor Perevertkin     *FailurePredictCapability
2257*3088717bSVictor Perevertkin 
2258*3088717bSVictor Perevertkin     ScsiAddressAvailable TRUE if there is a valid SCSI_ADDRESS available
2259*3088717bSVictor Perevertkin                          for this device, FALSE otherwise.
2260*3088717bSVictor Perevertkin                          If FALSE we do not allow SMART IOCTLs (FailurePredictionSmart capability)
2261*3088717bSVictor Perevertkin                          which require a valid SCSI_ADDRESS. The other capabilities
2262*3088717bSVictor Perevertkin                          <FailurePredictionIoctl, FailurePredictionSense) do not requere
2263*3088717bSVictor Perevertkin                          SCSI_ADDRESS so we'll still try to initialize them.
2264*3088717bSVictor Perevertkin 
2265*3088717bSVictor Perevertkin Return Value:
2266*3088717bSVictor Perevertkin 
2267*3088717bSVictor Perevertkin     NT Status
2268*3088717bSVictor Perevertkin 
2269*3088717bSVictor Perevertkin --*/
2270*3088717bSVictor Perevertkin {
2271*3088717bSVictor Perevertkin     PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
2272*3088717bSVictor Perevertkin     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
2273*3088717bSVictor Perevertkin     BOOLEAN supportFP;
2274*3088717bSVictor Perevertkin     NTSTATUS status;
2275*3088717bSVictor Perevertkin     STORAGE_PREDICT_FAILURE checkFailure;
2276*3088717bSVictor Perevertkin     STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus;
2277*3088717bSVictor Perevertkin 
2278*3088717bSVictor Perevertkin     PAGED_CODE();
2279*3088717bSVictor Perevertkin 
2280*3088717bSVictor Perevertkin     //
2281*3088717bSVictor Perevertkin     // Assume no failure predict mechanisms
2282*3088717bSVictor Perevertkin     //
2283*3088717bSVictor Perevertkin     *FailurePredictCapability = FailurePredictionNone;
2284*3088717bSVictor Perevertkin 
2285*3088717bSVictor Perevertkin     //
2286*3088717bSVictor Perevertkin     // See if this is an IDE drive that supports SMART. If so enable SMART
2287*3088717bSVictor Perevertkin     // and then ensure that it suports the SMART READ STATUS command
2288*3088717bSVictor Perevertkin     //
2289*3088717bSVictor Perevertkin 
2290*3088717bSVictor Perevertkin     if (ScsiAddressAvailable)
2291*3088717bSVictor Perevertkin     {
2292*3088717bSVictor Perevertkin         DiskGetIdentifyInfo(FdoExtension, &supportFP);
2293*3088717bSVictor Perevertkin 
2294*3088717bSVictor Perevertkin         if (supportFP)
2295*3088717bSVictor Perevertkin         {
2296*3088717bSVictor Perevertkin             status = DiskEnableSmart(FdoExtension);
2297*3088717bSVictor Perevertkin             if (NT_SUCCESS(status))
2298*3088717bSVictor Perevertkin             {
2299*3088717bSVictor Perevertkin                 *FailurePredictCapability = FailurePredictionSmart;
2300*3088717bSVictor Perevertkin                 diskData->FailurePredictionEnabled = TRUE;
2301*3088717bSVictor Perevertkin 
2302*3088717bSVictor Perevertkin                 status = DiskReadFailurePredictStatus(FdoExtension,
2303*3088717bSVictor Perevertkin                                                   &diskSmartStatus);
2304*3088717bSVictor Perevertkin 
2305*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: Device %p %s IDE SMART\n",
2306*3088717bSVictor Perevertkin                            FdoExtension->DeviceObject,
2307*3088717bSVictor Perevertkin                            NT_SUCCESS(status) ? "does" : "does not"));
2308*3088717bSVictor Perevertkin 
2309*3088717bSVictor Perevertkin                 if (!NT_SUCCESS(status))
2310*3088717bSVictor Perevertkin                 {
2311*3088717bSVictor Perevertkin                     *FailurePredictCapability = FailurePredictionNone;
2312*3088717bSVictor Perevertkin                     diskData->FailurePredictionEnabled = FALSE;
2313*3088717bSVictor Perevertkin                 }
2314*3088717bSVictor Perevertkin             }
2315*3088717bSVictor Perevertkin             return(status);
2316*3088717bSVictor Perevertkin         }
2317*3088717bSVictor Perevertkin     }
2318*3088717bSVictor Perevertkin     //
2319*3088717bSVictor Perevertkin     // See if there is a a filter driver to intercept
2320*3088717bSVictor Perevertkin     // IOCTL_STORAGE_PREDICT_FAILURE
2321*3088717bSVictor Perevertkin     //
2322*3088717bSVictor Perevertkin     status = DiskSendFailurePredictIoctl(FdoExtension,
2323*3088717bSVictor Perevertkin                                          &checkFailure);
2324*3088717bSVictor Perevertkin 
2325*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: Device %p %s IOCTL_STORAGE_FAILURE_PREDICT\n",
2326*3088717bSVictor Perevertkin                        FdoExtension->DeviceObject,
2327*3088717bSVictor Perevertkin                        NT_SUCCESS(status) ? "does" : "does not"));
2328*3088717bSVictor Perevertkin 
2329*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
2330*3088717bSVictor Perevertkin     {
2331*3088717bSVictor Perevertkin         *FailurePredictCapability = FailurePredictionIoctl;
2332*3088717bSVictor Perevertkin         diskData->FailurePredictionEnabled = TRUE;
2333*3088717bSVictor Perevertkin         if (checkFailure.PredictFailure)
2334*3088717bSVictor Perevertkin         {
2335*3088717bSVictor Perevertkin             checkFailure.PredictFailure = 512;
2336*3088717bSVictor Perevertkin             ClassNotifyFailurePredicted(FdoExtension,
2337*3088717bSVictor Perevertkin                                         (PUCHAR)&checkFailure,
2338*3088717bSVictor Perevertkin                                         sizeof(checkFailure),
2339*3088717bSVictor Perevertkin                                         (BOOLEAN)(FdoExtension->FailurePredicted == FALSE),
2340*3088717bSVictor Perevertkin                                         0x11,
2341*3088717bSVictor Perevertkin                                         diskData->ScsiAddress.PathId,
2342*3088717bSVictor Perevertkin                                         diskData->ScsiAddress.TargetId,
2343*3088717bSVictor Perevertkin                                         diskData->ScsiAddress.Lun);
2344*3088717bSVictor Perevertkin 
2345*3088717bSVictor Perevertkin             FdoExtension->FailurePredicted = TRUE;
2346*3088717bSVictor Perevertkin         }
2347*3088717bSVictor Perevertkin         return(status);
2348*3088717bSVictor Perevertkin     }
2349*3088717bSVictor Perevertkin 
2350*3088717bSVictor Perevertkin     //
2351*3088717bSVictor Perevertkin     // Finally we assume it will not be a scsi smart drive. but
2352*3088717bSVictor Perevertkin     // we'll also send off an asynchronous mode sense so that if
2353*3088717bSVictor Perevertkin     // it is SMART we'll reregister the device object
2354*3088717bSVictor Perevertkin     //
2355*3088717bSVictor Perevertkin 
2356*3088717bSVictor Perevertkin     *FailurePredictCapability = FailurePredictionNone;
2357*3088717bSVictor Perevertkin 
2358*3088717bSVictor Perevertkin     DiskInfoExceptionCheck(FdoExtension);
2359*3088717bSVictor Perevertkin 
2360*3088717bSVictor Perevertkin     return(STATUS_SUCCESS);
2361*3088717bSVictor Perevertkin }
2362*3088717bSVictor Perevertkin 
2363*3088717bSVictor Perevertkin 
2364*3088717bSVictor Perevertkin NTSTATUS
2365*3088717bSVictor Perevertkin NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskWmiFunctionControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN ULONG GuidIndex,IN CLASSENABLEDISABLEFUNCTION Function,IN BOOLEAN Enable)2366*3088717bSVictor Perevertkin DiskWmiFunctionControl(
2367*3088717bSVictor Perevertkin     IN PDEVICE_OBJECT DeviceObject,
2368*3088717bSVictor Perevertkin     IN PIRP Irp,
2369*3088717bSVictor Perevertkin     IN ULONG GuidIndex,
2370*3088717bSVictor Perevertkin     IN CLASSENABLEDISABLEFUNCTION Function,
2371*3088717bSVictor Perevertkin     IN BOOLEAN Enable
2372*3088717bSVictor Perevertkin     )
2373*3088717bSVictor Perevertkin /*++
2374*3088717bSVictor Perevertkin 
2375*3088717bSVictor Perevertkin Routine Description:
2376*3088717bSVictor Perevertkin 
2377*3088717bSVictor Perevertkin     This routine is a callback into the driver to enabled or disable event
2378*3088717bSVictor Perevertkin     generation or data block collection. A device should only expect a
2379*3088717bSVictor Perevertkin     single enable when the first event or data consumer enables events or
2380*3088717bSVictor Perevertkin     data collection and a single disable when the last event or data
2381*3088717bSVictor Perevertkin     consumer disables events or data collection. Data blocks will only
2382*3088717bSVictor Perevertkin     receive collection enable/disable if they were registered as requiring
2383*3088717bSVictor Perevertkin     it.
2384*3088717bSVictor Perevertkin 
2385*3088717bSVictor Perevertkin 
2386*3088717bSVictor Perevertkin     When NT boots, failure prediction is not automatically enabled, although
2387*3088717bSVictor Perevertkin     it may have been persistantly enabled on a previous boot. Polling is also
2388*3088717bSVictor Perevertkin     not automatically enabled. When the first data block that accesses SMART
2389*3088717bSVictor Perevertkin     such as SmartStatusGuid, SmartDataGuid, SmartPerformFunction, or
2390*3088717bSVictor Perevertkin     SmartEventGuid is accessed then SMART is automatically enabled in the
2391*3088717bSVictor Perevertkin     hardware. Polling is enabled when SmartEventGuid is enabled and disabled
2392*3088717bSVictor Perevertkin     when it is disabled. Hardware SMART is only disabled when the DisableSmart
2393*3088717bSVictor Perevertkin     method is called. Polling is also disabled when this is called regardless
2394*3088717bSVictor Perevertkin     of the status of the other guids or events.
2395*3088717bSVictor Perevertkin 
2396*3088717bSVictor Perevertkin Arguments:
2397*3088717bSVictor Perevertkin 
2398*3088717bSVictor Perevertkin     DeviceObject is the device whose data block is being queried
2399*3088717bSVictor Perevertkin 
2400*3088717bSVictor Perevertkin     GuidIndex is the index into the list of guids provided when the
2401*3088717bSVictor Perevertkin         device registered
2402*3088717bSVictor Perevertkin 
2403*3088717bSVictor Perevertkin     Function specifies which functionality is being enabled or disabled
2404*3088717bSVictor Perevertkin 
2405*3088717bSVictor Perevertkin     Enable is TRUE then the function is being enabled else disabled
2406*3088717bSVictor Perevertkin 
2407*3088717bSVictor Perevertkin Return Value:
2408*3088717bSVictor Perevertkin 
2409*3088717bSVictor Perevertkin     status
2410*3088717bSVictor Perevertkin 
2411*3088717bSVictor Perevertkin --*/
2412*3088717bSVictor Perevertkin {
2413*3088717bSVictor Perevertkin     NTSTATUS status = STATUS_SUCCESS;
2414*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
2415*3088717bSVictor Perevertkin 
2416*3088717bSVictor Perevertkin     PAGED_CODE();
2417*3088717bSVictor Perevertkin 
2418*3088717bSVictor Perevertkin     if ((Function == DataBlockCollection) && Enable)
2419*3088717bSVictor Perevertkin     {
2420*3088717bSVictor Perevertkin         if ((GuidIndex == SmartStatusGuid) ||
2421*3088717bSVictor Perevertkin             (GuidIndex == SmartDataGuid) ||
2422*3088717bSVictor Perevertkin             (GuidIndex == SmartThresholdsGuid) ||
2423*3088717bSVictor Perevertkin             (GuidIndex == SmartPerformFunction))
2424*3088717bSVictor Perevertkin         {
2425*3088717bSVictor Perevertkin             status = DiskEnableDisableFailurePrediction(fdoExtension,
2426*3088717bSVictor Perevertkin                                                         TRUE);
2427*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DeviceObject %p, Irp %p Enable -> %lx\n",
2428*3088717bSVictor Perevertkin                        DeviceObject,
2429*3088717bSVictor Perevertkin                        Irp,
2430*3088717bSVictor Perevertkin                        status));
2431*3088717bSVictor Perevertkin 
2432*3088717bSVictor Perevertkin         } else {
2433*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DeviceObject %p, Irp %p, GuidIndex %d %s for Collection\n",
2434*3088717bSVictor Perevertkin                       DeviceObject, Irp,
2435*3088717bSVictor Perevertkin                       GuidIndex,
2436*3088717bSVictor Perevertkin                       Enable ? "Enabled" : "Disabled"));
2437*3088717bSVictor Perevertkin         }
2438*3088717bSVictor Perevertkin     } else if (Function == EventGeneration) {
2439*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DeviceObject %p, Irp %p, GuidIndex %d %s for Event Generation\n",
2440*3088717bSVictor Perevertkin                   DeviceObject, Irp,
2441*3088717bSVictor Perevertkin                   GuidIndex,
2442*3088717bSVictor Perevertkin                   Enable ? "Enabled" : "Disabled"));
2443*3088717bSVictor Perevertkin 
2444*3088717bSVictor Perevertkin 
2445*3088717bSVictor Perevertkin         if ((GuidIndex == SmartEventGuid) && Enable)
2446*3088717bSVictor Perevertkin         {
2447*3088717bSVictor Perevertkin             status = DiskEnableDisableFailurePredictPolling(fdoExtension,
2448*3088717bSVictor Perevertkin                                                    Enable,
2449*3088717bSVictor Perevertkin                                                    0);
2450*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DeviceObject %p, Irp %p %s -> %lx\n",
2451*3088717bSVictor Perevertkin                        DeviceObject,
2452*3088717bSVictor Perevertkin                        Irp,
2453*3088717bSVictor Perevertkin                        Enable ? "DiskEnableSmartPolling" : "DiskDisableSmartPolling",
2454*3088717bSVictor Perevertkin                        status));
2455*3088717bSVictor Perevertkin         }
2456*3088717bSVictor Perevertkin 
2457*3088717bSVictor Perevertkin #if DBG
2458*3088717bSVictor Perevertkin     } else {
2459*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DeviceObject %p, Irp %p, GuidIndex %d %s for function %d\n",
2460*3088717bSVictor Perevertkin                   DeviceObject, Irp,
2461*3088717bSVictor Perevertkin                   GuidIndex,
2462*3088717bSVictor Perevertkin                   Enable ? "Enabled" : "Disabled",
2463*3088717bSVictor Perevertkin                   Function));
2464*3088717bSVictor Perevertkin #endif
2465*3088717bSVictor Perevertkin     }
2466*3088717bSVictor Perevertkin 
2467*3088717bSVictor Perevertkin     status = ClassWmiCompleteRequest(DeviceObject,
2468*3088717bSVictor Perevertkin                                      Irp,
2469*3088717bSVictor Perevertkin                                      status,
2470*3088717bSVictor Perevertkin                                      0,
2471*3088717bSVictor Perevertkin                                      IO_NO_INCREMENT);
2472*3088717bSVictor Perevertkin     return status;
2473*3088717bSVictor Perevertkin }
2474*3088717bSVictor Perevertkin 
2475*3088717bSVictor Perevertkin 
2476*3088717bSVictor Perevertkin 
2477*3088717bSVictor Perevertkin NTSTATUS
2478*3088717bSVictor Perevertkin NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoQueryWmiRegInfo(IN PDEVICE_OBJECT DeviceObject,OUT ULONG * RegFlags,OUT PUNICODE_STRING InstanceName)2479*3088717bSVictor Perevertkin DiskFdoQueryWmiRegInfo(
2480*3088717bSVictor Perevertkin     IN PDEVICE_OBJECT DeviceObject,
2481*3088717bSVictor Perevertkin     OUT ULONG *RegFlags,
2482*3088717bSVictor Perevertkin     OUT PUNICODE_STRING InstanceName
2483*3088717bSVictor Perevertkin     )
2484*3088717bSVictor Perevertkin /*++
2485*3088717bSVictor Perevertkin 
2486*3088717bSVictor Perevertkin Routine Description:
2487*3088717bSVictor Perevertkin 
2488*3088717bSVictor Perevertkin     This routine is a callback into the driver to retrieve the list of
2489*3088717bSVictor Perevertkin     guids or data blocks that the driver wants to register with WMI. This
2490*3088717bSVictor Perevertkin     routine may not pend or block. Driver should NOT call
2491*3088717bSVictor Perevertkin     ClassWmiCompleteRequest.
2492*3088717bSVictor Perevertkin 
2493*3088717bSVictor Perevertkin Arguments:
2494*3088717bSVictor Perevertkin 
2495*3088717bSVictor Perevertkin     DeviceObject is the device whose data block is being queried
2496*3088717bSVictor Perevertkin 
2497*3088717bSVictor Perevertkin     *RegFlags returns with a set of flags that describe the guids being
2498*3088717bSVictor Perevertkin         registered for this device. If the device wants enable and disable
2499*3088717bSVictor Perevertkin         collection callbacks before receiving queries for the registered
2500*3088717bSVictor Perevertkin         guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
2501*3088717bSVictor Perevertkin         returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
2502*3088717bSVictor Perevertkin         the instance name is determined from the PDO associated with the
2503*3088717bSVictor Perevertkin         device object. Note that the PDO must have an associated devnode. If
2504*3088717bSVictor Perevertkin         WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
2505*3088717bSVictor Perevertkin         name for the device.
2506*3088717bSVictor Perevertkin 
2507*3088717bSVictor Perevertkin     InstanceName returns with the instance name for the guids if
2508*3088717bSVictor Perevertkin         WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
2509*3088717bSVictor Perevertkin         caller will call ExFreePool with the buffer returned.
2510*3088717bSVictor Perevertkin 
2511*3088717bSVictor Perevertkin 
2512*3088717bSVictor Perevertkin Return Value:
2513*3088717bSVictor Perevertkin 
2514*3088717bSVictor Perevertkin     status
2515*3088717bSVictor Perevertkin 
2516*3088717bSVictor Perevertkin --*/
2517*3088717bSVictor Perevertkin {
2518*3088717bSVictor Perevertkin     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
2519*3088717bSVictor Perevertkin     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
2520*3088717bSVictor Perevertkin 
2521*3088717bSVictor Perevertkin     PAGED_CODE();
2522*3088717bSVictor Perevertkin     UNREFERENCED_PARAMETER(InstanceName);
2523*3088717bSVictor Perevertkin 
2524*3088717bSVictor Perevertkin     SET_FLAG(DiskWmiFdoGuidList[SmartThresholdsGuid].Flags,  WMIREG_FLAG_REMOVE_GUID);
2525*3088717bSVictor Perevertkin     SET_FLAG(DiskWmiFdoGuidList[ScsiInfoExceptionsGuid].Flags,  WMIREG_FLAG_REMOVE_GUID);
2526*3088717bSVictor Perevertkin 
2527*3088717bSVictor Perevertkin     switch (diskData->FailurePredictionCapability)
2528*3088717bSVictor Perevertkin     {
2529*3088717bSVictor Perevertkin         case FailurePredictionSmart:
2530*3088717bSVictor Perevertkin         {
2531*3088717bSVictor Perevertkin             CLEAR_FLAG(DiskWmiFdoGuidList[SmartThresholdsGuid].Flags,  WMIREG_FLAG_REMOVE_GUID);
2532*3088717bSVictor Perevertkin             //
2533*3088717bSVictor Perevertkin             // Fall Through
2534*3088717bSVictor Perevertkin             //
2535*3088717bSVictor Perevertkin         }
2536*3088717bSVictor Perevertkin         case FailurePredictionIoctl:
2537*3088717bSVictor Perevertkin         {
2538*3088717bSVictor Perevertkin             CLEAR_FLAG(DiskWmiFdoGuidList[SmartStatusGuid].Flags,      WMIREG_FLAG_REMOVE_GUID);
2539*3088717bSVictor Perevertkin             CLEAR_FLAG(DiskWmiFdoGuidList[SmartDataGuid].Flags,        WMIREG_FLAG_REMOVE_GUID);
2540*3088717bSVictor Perevertkin             CLEAR_FLAG(DiskWmiFdoGuidList[SmartEventGuid].Flags,       WMIREG_FLAG_REMOVE_GUID);
2541*3088717bSVictor Perevertkin             CLEAR_FLAG(DiskWmiFdoGuidList[SmartPerformFunction].Flags, WMIREG_FLAG_REMOVE_GUID);
2542*3088717bSVictor Perevertkin 
2543*3088717bSVictor Perevertkin             break;
2544*3088717bSVictor Perevertkin         }
2545*3088717bSVictor Perevertkin 
2546*3088717bSVictor Perevertkin         case FailurePredictionSense:
2547*3088717bSVictor Perevertkin         {
2548*3088717bSVictor Perevertkin             CLEAR_FLAG(DiskWmiFdoGuidList[SmartStatusGuid].Flags,      WMIREG_FLAG_REMOVE_GUID);
2549*3088717bSVictor Perevertkin             CLEAR_FLAG(DiskWmiFdoGuidList[SmartEventGuid].Flags,       WMIREG_FLAG_REMOVE_GUID);
2550*3088717bSVictor Perevertkin             CLEAR_FLAG(DiskWmiFdoGuidList[SmartPerformFunction].Flags, WMIREG_FLAG_REMOVE_GUID);
2551*3088717bSVictor Perevertkin             CLEAR_FLAG(DiskWmiFdoGuidList[ScsiInfoExceptionsGuid].Flags,  WMIREG_FLAG_REMOVE_GUID);
2552*3088717bSVictor Perevertkin             SET_FLAG  (DiskWmiFdoGuidList[SmartDataGuid].Flags,        WMIREG_FLAG_REMOVE_GUID);
2553*3088717bSVictor Perevertkin             break;
2554*3088717bSVictor Perevertkin         }
2555*3088717bSVictor Perevertkin 
2556*3088717bSVictor Perevertkin 
2557*3088717bSVictor Perevertkin         default:
2558*3088717bSVictor Perevertkin         {
2559*3088717bSVictor Perevertkin             SET_FLAG  (DiskWmiFdoGuidList[SmartStatusGuid].Flags,      WMIREG_FLAG_REMOVE_GUID);
2560*3088717bSVictor Perevertkin             SET_FLAG  (DiskWmiFdoGuidList[SmartDataGuid].Flags,        WMIREG_FLAG_REMOVE_GUID);
2561*3088717bSVictor Perevertkin             SET_FLAG  (DiskWmiFdoGuidList[SmartEventGuid].Flags,       WMIREG_FLAG_REMOVE_GUID);
2562*3088717bSVictor Perevertkin             SET_FLAG  (DiskWmiFdoGuidList[SmartPerformFunction].Flags, WMIREG_FLAG_REMOVE_GUID);
2563*3088717bSVictor Perevertkin             break;
2564*3088717bSVictor Perevertkin         }
2565*3088717bSVictor Perevertkin     }
2566*3088717bSVictor Perevertkin 
2567*3088717bSVictor Perevertkin     //
2568*3088717bSVictor Perevertkin     // Use devnode for FDOs
2569*3088717bSVictor Perevertkin     *RegFlags = WMIREG_FLAG_INSTANCE_PDO;
2570*3088717bSVictor Perevertkin 
2571*3088717bSVictor Perevertkin     return STATUS_SUCCESS;
2572*3088717bSVictor Perevertkin }
2573*3088717bSVictor Perevertkin 
2574*3088717bSVictor Perevertkin 
2575*3088717bSVictor Perevertkin NTSTATUS
2576*3088717bSVictor Perevertkin NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoQueryWmiRegInfoEx(IN PDEVICE_OBJECT DeviceObject,OUT ULONG * RegFlags,OUT PUNICODE_STRING InstanceName,OUT PUNICODE_STRING MofName)2577*3088717bSVictor Perevertkin DiskFdoQueryWmiRegInfoEx(
2578*3088717bSVictor Perevertkin     IN PDEVICE_OBJECT DeviceObject,
2579*3088717bSVictor Perevertkin     OUT ULONG *RegFlags,
2580*3088717bSVictor Perevertkin     OUT PUNICODE_STRING InstanceName,
2581*3088717bSVictor Perevertkin     OUT PUNICODE_STRING MofName
2582*3088717bSVictor Perevertkin     )
2583*3088717bSVictor Perevertkin /*++
2584*3088717bSVictor Perevertkin 
2585*3088717bSVictor Perevertkin Routine Description:
2586*3088717bSVictor Perevertkin 
2587*3088717bSVictor Perevertkin     This routine is a callback into the driver to retrieve the list of
2588*3088717bSVictor Perevertkin     guids or data blocks that the driver wants to register with WMI. This
2589*3088717bSVictor Perevertkin     routine may not pend or block. Driver should NOT call
2590*3088717bSVictor Perevertkin     ClassWmiCompleteRequest.
2591*3088717bSVictor Perevertkin 
2592*3088717bSVictor Perevertkin Arguments:
2593*3088717bSVictor Perevertkin 
2594*3088717bSVictor Perevertkin     DeviceObject is the device whose data block is being queried
2595*3088717bSVictor Perevertkin 
2596*3088717bSVictor Perevertkin     *RegFlags returns with a set of flags that describe the guids being
2597*3088717bSVictor Perevertkin         registered for this device. If the device wants enable and disable
2598*3088717bSVictor Perevertkin         collection callbacks before receiving queries for the registered
2599*3088717bSVictor Perevertkin         guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
2600*3088717bSVictor Perevertkin         returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
2601*3088717bSVictor Perevertkin         the instance name is determined from the PDO associated with the
2602*3088717bSVictor Perevertkin         device object. Note that the PDO must have an associated devnode. If
2603*3088717bSVictor Perevertkin         WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
2604*3088717bSVictor Perevertkin         name for the device.
2605*3088717bSVictor Perevertkin 
2606*3088717bSVictor Perevertkin     InstanceName returns with the instance name for the guids if
2607*3088717bSVictor Perevertkin         WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
2608*3088717bSVictor Perevertkin         caller will call ExFreePool with the buffer returned.
2609*3088717bSVictor Perevertkin 
2610*3088717bSVictor Perevertkin     MofName returns initialized with the mof resource name for the
2611*3088717bSVictor Perevertkin         binary mof resource attached to the driver's image file. If the
2612*3088717bSVictor Perevertkin         driver does not have a mof resource then it should leave this
2613*3088717bSVictor Perevertkin         parameter untouched.
2614*3088717bSVictor Perevertkin 
2615*3088717bSVictor Perevertkin Return Value:
2616*3088717bSVictor Perevertkin 
2617*3088717bSVictor Perevertkin     status
2618*3088717bSVictor Perevertkin 
2619*3088717bSVictor Perevertkin --*/
2620*3088717bSVictor Perevertkin {
2621*3088717bSVictor Perevertkin     NTSTATUS status;
2622*3088717bSVictor Perevertkin 
2623*3088717bSVictor Perevertkin     UNREFERENCED_PARAMETER(MofName);
2624*3088717bSVictor Perevertkin 
2625*3088717bSVictor Perevertkin     status = DiskFdoQueryWmiRegInfo(DeviceObject,
2626*3088717bSVictor Perevertkin                                     RegFlags,
2627*3088717bSVictor Perevertkin                                     InstanceName);
2628*3088717bSVictor Perevertkin 
2629*3088717bSVictor Perevertkin     //
2630*3088717bSVictor Perevertkin     // Leave MofName alone since disk doesn't have one
2631*3088717bSVictor Perevertkin     //
2632*3088717bSVictor Perevertkin     return(status);
2633*3088717bSVictor Perevertkin }
2634*3088717bSVictor Perevertkin 
2635*3088717bSVictor Perevertkin 
2636*3088717bSVictor Perevertkin NTSTATUS
2637*3088717bSVictor Perevertkin NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoQueryWmiDataBlock(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN ULONG GuidIndex,IN ULONG BufferAvail,OUT PUCHAR Buffer)2638*3088717bSVictor Perevertkin DiskFdoQueryWmiDataBlock(
2639*3088717bSVictor Perevertkin     IN PDEVICE_OBJECT DeviceObject,
2640*3088717bSVictor Perevertkin     IN PIRP Irp,
2641*3088717bSVictor Perevertkin     IN ULONG GuidIndex,
2642*3088717bSVictor Perevertkin     IN ULONG BufferAvail,
2643*3088717bSVictor Perevertkin     OUT PUCHAR Buffer
2644*3088717bSVictor Perevertkin     )
2645*3088717bSVictor Perevertkin /*++
2646*3088717bSVictor Perevertkin 
2647*3088717bSVictor Perevertkin Routine Description:
2648*3088717bSVictor Perevertkin 
2649*3088717bSVictor Perevertkin     This routine is a callback into the driver to query for the contents of
2650*3088717bSVictor Perevertkin     a data block. When the driver has finished filling the data block it
2651*3088717bSVictor Perevertkin     must call ClassWmiCompleteRequest to complete the irp. The driver can
2652*3088717bSVictor Perevertkin     return STATUS_PENDING if the irp cannot be completed immediately.
2653*3088717bSVictor Perevertkin 
2654*3088717bSVictor Perevertkin Arguments:
2655*3088717bSVictor Perevertkin 
2656*3088717bSVictor Perevertkin     DeviceObject is the device whose data block is being queried
2657*3088717bSVictor Perevertkin 
2658*3088717bSVictor Perevertkin     Irp is the Irp that makes this request
2659*3088717bSVictor Perevertkin 
2660*3088717bSVictor Perevertkin     GuidIndex is the index into the list of guids provided when the
2661*3088717bSVictor Perevertkin         device registered
2662*3088717bSVictor Perevertkin 
2663*3088717bSVictor Perevertkin     BufferAvail on has the maximum size available to write the data
2664*3088717bSVictor Perevertkin         block.
2665*3088717bSVictor Perevertkin 
2666*3088717bSVictor Perevertkin     Buffer on return is filled with the returned data block
2667*3088717bSVictor Perevertkin 
2668*3088717bSVictor Perevertkin 
2669*3088717bSVictor Perevertkin Return Value:
2670*3088717bSVictor Perevertkin 
2671*3088717bSVictor Perevertkin     status
2672*3088717bSVictor Perevertkin 
2673*3088717bSVictor Perevertkin --*/
2674*3088717bSVictor Perevertkin {
2675*3088717bSVictor Perevertkin     NTSTATUS status;
2676*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
2677*3088717bSVictor Perevertkin     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
2678*3088717bSVictor Perevertkin     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
2679*3088717bSVictor Perevertkin     ULONG sizeNeeded;
2680*3088717bSVictor Perevertkin 
2681*3088717bSVictor Perevertkin     PAGED_CODE();
2682*3088717bSVictor Perevertkin 
2683*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskQueryWmiDataBlock, Device %p, Irp %p, GuiIndex %d\n"
2684*3088717bSVictor Perevertkin              "      BufferAvail %lx Buffer %p\n",
2685*3088717bSVictor Perevertkin              DeviceObject, Irp,
2686*3088717bSVictor Perevertkin              GuidIndex, BufferAvail, Buffer));
2687*3088717bSVictor Perevertkin 
2688*3088717bSVictor Perevertkin     switch (GuidIndex)
2689*3088717bSVictor Perevertkin     {
2690*3088717bSVictor Perevertkin         case DiskGeometryGuid:
2691*3088717bSVictor Perevertkin         {
2692*3088717bSVictor Perevertkin             sizeNeeded = sizeof(DISK_GEOMETRY);
2693*3088717bSVictor Perevertkin             if (BufferAvail >= sizeNeeded)
2694*3088717bSVictor Perevertkin             {
2695*3088717bSVictor Perevertkin                 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
2696*3088717bSVictor Perevertkin                 {
2697*3088717bSVictor Perevertkin                     //
2698*3088717bSVictor Perevertkin                     // Issue ReadCapacity to update device extension
2699*3088717bSVictor Perevertkin                     // with information for current media.
2700*3088717bSVictor Perevertkin                     status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject);
2701*3088717bSVictor Perevertkin 
2702*3088717bSVictor Perevertkin                     //
2703*3088717bSVictor Perevertkin                     // Note whether the drive is ready.
2704*3088717bSVictor Perevertkin                     diskData->ReadyStatus = status;
2705*3088717bSVictor Perevertkin 
2706*3088717bSVictor Perevertkin                     if (!NT_SUCCESS(status))
2707*3088717bSVictor Perevertkin                     {
2708*3088717bSVictor Perevertkin                         break;
2709*3088717bSVictor Perevertkin                     }
2710*3088717bSVictor Perevertkin                 }
2711*3088717bSVictor Perevertkin 
2712*3088717bSVictor Perevertkin                 //
2713*3088717bSVictor Perevertkin                 // Copy drive geometry information from device extension.
2714*3088717bSVictor Perevertkin                 RtlMoveMemory(Buffer,
2715*3088717bSVictor Perevertkin                               &(fdoExtension->DiskGeometry),
2716*3088717bSVictor Perevertkin                               sizeof(DISK_GEOMETRY));
2717*3088717bSVictor Perevertkin 
2718*3088717bSVictor Perevertkin                 status = STATUS_SUCCESS;
2719*3088717bSVictor Perevertkin             } else {
2720*3088717bSVictor Perevertkin                 status = STATUS_BUFFER_TOO_SMALL;
2721*3088717bSVictor Perevertkin             }
2722*3088717bSVictor Perevertkin             break;
2723*3088717bSVictor Perevertkin         }
2724*3088717bSVictor Perevertkin 
2725*3088717bSVictor Perevertkin         case SmartStatusGuid:
2726*3088717bSVictor Perevertkin         {
2727*3088717bSVictor Perevertkin             PSTORAGE_FAILURE_PREDICT_STATUS diskSmartStatus;
2728*3088717bSVictor Perevertkin 
2729*3088717bSVictor Perevertkin             NT_ASSERT(diskData->FailurePredictionCapability != FailurePredictionNone);
2730*3088717bSVictor Perevertkin 
2731*3088717bSVictor Perevertkin             sizeNeeded = sizeof(STORAGE_FAILURE_PREDICT_STATUS);
2732*3088717bSVictor Perevertkin             if (BufferAvail >= sizeNeeded)
2733*3088717bSVictor Perevertkin             {
2734*3088717bSVictor Perevertkin                 STORAGE_PREDICT_FAILURE checkFailure;
2735*3088717bSVictor Perevertkin 
2736*3088717bSVictor Perevertkin                 diskSmartStatus = (PSTORAGE_FAILURE_PREDICT_STATUS)Buffer;
2737*3088717bSVictor Perevertkin 
2738*3088717bSVictor Perevertkin                 status = DiskSendFailurePredictIoctl(fdoExtension,
2739*3088717bSVictor Perevertkin                                                      &checkFailure);
2740*3088717bSVictor Perevertkin 
2741*3088717bSVictor Perevertkin                 if (NT_SUCCESS(status))
2742*3088717bSVictor Perevertkin                 {
2743*3088717bSVictor Perevertkin                     if (diskData->FailurePredictionCapability ==
2744*3088717bSVictor Perevertkin                                                       FailurePredictionSense)
2745*3088717bSVictor Perevertkin                     {
2746*3088717bSVictor Perevertkin                         diskSmartStatus->Reason =  *((PULONG)checkFailure.VendorSpecific);
2747*3088717bSVictor Perevertkin                     } else {
2748*3088717bSVictor Perevertkin                         diskSmartStatus->Reason =  0; // unknown
2749*3088717bSVictor Perevertkin                     }
2750*3088717bSVictor Perevertkin 
2751*3088717bSVictor Perevertkin                     diskSmartStatus->PredictFailure = (checkFailure.PredictFailure != 0);
2752*3088717bSVictor Perevertkin                 }
2753*3088717bSVictor Perevertkin             } else {
2754*3088717bSVictor Perevertkin                 status = STATUS_BUFFER_TOO_SMALL;
2755*3088717bSVictor Perevertkin             }
2756*3088717bSVictor Perevertkin             break;
2757*3088717bSVictor Perevertkin         }
2758*3088717bSVictor Perevertkin 
2759*3088717bSVictor Perevertkin         case SmartDataGuid:
2760*3088717bSVictor Perevertkin         {
2761*3088717bSVictor Perevertkin             PSTORAGE_FAILURE_PREDICT_DATA diskSmartData;
2762*3088717bSVictor Perevertkin 
2763*3088717bSVictor Perevertkin             NT_ASSERT((diskData->FailurePredictionCapability ==
2764*3088717bSVictor Perevertkin                                                   FailurePredictionSmart) ||
2765*3088717bSVictor Perevertkin                    (diskData->FailurePredictionCapability ==
2766*3088717bSVictor Perevertkin                                                   FailurePredictionIoctl));
2767*3088717bSVictor Perevertkin 
2768*3088717bSVictor Perevertkin             sizeNeeded = sizeof(STORAGE_FAILURE_PREDICT_DATA);
2769*3088717bSVictor Perevertkin             if (BufferAvail >= sizeNeeded)
2770*3088717bSVictor Perevertkin             {
2771*3088717bSVictor Perevertkin                 PSTORAGE_PREDICT_FAILURE checkFailure = (PSTORAGE_PREDICT_FAILURE)Buffer;
2772*3088717bSVictor Perevertkin 
2773*3088717bSVictor Perevertkin                 diskSmartData = (PSTORAGE_FAILURE_PREDICT_DATA)Buffer;
2774*3088717bSVictor Perevertkin 
2775*3088717bSVictor Perevertkin                 status = DiskSendFailurePredictIoctl(fdoExtension,
2776*3088717bSVictor Perevertkin                                                      checkFailure);
2777*3088717bSVictor Perevertkin 
2778*3088717bSVictor Perevertkin                 if (NT_SUCCESS(status))
2779*3088717bSVictor Perevertkin                 {
2780*3088717bSVictor Perevertkin                     diskSmartData->Length = 512;
2781*3088717bSVictor Perevertkin                 }
2782*3088717bSVictor Perevertkin             } else {
2783*3088717bSVictor Perevertkin                 status = STATUS_BUFFER_TOO_SMALL;
2784*3088717bSVictor Perevertkin             }
2785*3088717bSVictor Perevertkin 
2786*3088717bSVictor Perevertkin             break;
2787*3088717bSVictor Perevertkin         }
2788*3088717bSVictor Perevertkin 
2789*3088717bSVictor Perevertkin         case SmartThresholdsGuid:
2790*3088717bSVictor Perevertkin         {
2791*3088717bSVictor Perevertkin             PSTORAGE_FAILURE_PREDICT_THRESHOLDS diskSmartThresholds;
2792*3088717bSVictor Perevertkin 
2793*3088717bSVictor Perevertkin             NT_ASSERT((diskData->FailurePredictionCapability ==
2794*3088717bSVictor Perevertkin                                                   FailurePredictionSmart));
2795*3088717bSVictor Perevertkin 
2796*3088717bSVictor Perevertkin             sizeNeeded = sizeof(STORAGE_FAILURE_PREDICT_THRESHOLDS);
2797*3088717bSVictor Perevertkin             if (BufferAvail >= sizeNeeded)
2798*3088717bSVictor Perevertkin             {
2799*3088717bSVictor Perevertkin                 diskSmartThresholds = (PSTORAGE_FAILURE_PREDICT_THRESHOLDS)Buffer;
2800*3088717bSVictor Perevertkin                 status = DiskReadFailurePredictThresholds(fdoExtension,
2801*3088717bSVictor Perevertkin                                                           diskSmartThresholds);
2802*3088717bSVictor Perevertkin             } else {
2803*3088717bSVictor Perevertkin                 status = STATUS_BUFFER_TOO_SMALL;
2804*3088717bSVictor Perevertkin             }
2805*3088717bSVictor Perevertkin 
2806*3088717bSVictor Perevertkin             break;
2807*3088717bSVictor Perevertkin         }
2808*3088717bSVictor Perevertkin 
2809*3088717bSVictor Perevertkin         case SmartPerformFunction:
2810*3088717bSVictor Perevertkin         {
2811*3088717bSVictor Perevertkin             sizeNeeded = 0;
2812*3088717bSVictor Perevertkin             status = STATUS_SUCCESS;
2813*3088717bSVictor Perevertkin             break;
2814*3088717bSVictor Perevertkin         }
2815*3088717bSVictor Perevertkin 
2816*3088717bSVictor Perevertkin         case ScsiInfoExceptionsGuid:
2817*3088717bSVictor Perevertkin         {
2818*3088717bSVictor Perevertkin             PSTORAGE_SCSI_INFO_EXCEPTIONS infoExceptions;
2819*3088717bSVictor Perevertkin             MODE_INFO_EXCEPTIONS modeInfo;
2820*3088717bSVictor Perevertkin 
2821*3088717bSVictor Perevertkin             NT_ASSERT((diskData->FailurePredictionCapability ==
2822*3088717bSVictor Perevertkin                                                   FailurePredictionSense));
2823*3088717bSVictor Perevertkin 
2824*3088717bSVictor Perevertkin             sizeNeeded = sizeof(STORAGE_SCSI_INFO_EXCEPTIONS);
2825*3088717bSVictor Perevertkin             if (BufferAvail >= sizeNeeded)
2826*3088717bSVictor Perevertkin             {
2827*3088717bSVictor Perevertkin                 infoExceptions = (PSTORAGE_SCSI_INFO_EXCEPTIONS)Buffer;
2828*3088717bSVictor Perevertkin                 status = DiskGetInfoExceptionInformation(fdoExtension,
2829*3088717bSVictor Perevertkin                                                          &modeInfo);
2830*3088717bSVictor Perevertkin                 if (NT_SUCCESS(status))
2831*3088717bSVictor Perevertkin                 {
2832*3088717bSVictor Perevertkin                     infoExceptions->PageSavable = modeInfo.PSBit;
2833*3088717bSVictor Perevertkin                     infoExceptions->Flags = modeInfo.Flags;
2834*3088717bSVictor Perevertkin                     infoExceptions->MRIE = modeInfo.ReportMethod;
2835*3088717bSVictor Perevertkin                     infoExceptions->Padding = 0;
2836*3088717bSVictor Perevertkin                     REVERSE_BYTES(&infoExceptions->IntervalTimer,
2837*3088717bSVictor Perevertkin                                   &modeInfo.IntervalTimer);
2838*3088717bSVictor Perevertkin                     REVERSE_BYTES(&infoExceptions->ReportCount,
2839*3088717bSVictor Perevertkin                                   &modeInfo.ReportCount)
2840*3088717bSVictor Perevertkin                 }
2841*3088717bSVictor Perevertkin             } else {
2842*3088717bSVictor Perevertkin                 status = STATUS_BUFFER_TOO_SMALL;
2843*3088717bSVictor Perevertkin             }
2844*3088717bSVictor Perevertkin 
2845*3088717bSVictor Perevertkin             break;
2846*3088717bSVictor Perevertkin         }
2847*3088717bSVictor Perevertkin 
2848*3088717bSVictor Perevertkin         default:
2849*3088717bSVictor Perevertkin         {
2850*3088717bSVictor Perevertkin             sizeNeeded = 0;
2851*3088717bSVictor Perevertkin             status = STATUS_WMI_GUID_NOT_FOUND;
2852*3088717bSVictor Perevertkin         }
2853*3088717bSVictor Perevertkin     }
2854*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskQueryWmiDataBlock Device %p, Irp %p returns %lx\n",
2855*3088717bSVictor Perevertkin              DeviceObject, Irp, status));
2856*3088717bSVictor Perevertkin 
2857*3088717bSVictor Perevertkin     status = ClassWmiCompleteRequest(DeviceObject,
2858*3088717bSVictor Perevertkin                                      Irp,
2859*3088717bSVictor Perevertkin                                      status,
2860*3088717bSVictor Perevertkin                                      sizeNeeded,
2861*3088717bSVictor Perevertkin                                      IO_NO_INCREMENT);
2862*3088717bSVictor Perevertkin 
2863*3088717bSVictor Perevertkin     return status;
2864*3088717bSVictor Perevertkin }
2865*3088717bSVictor Perevertkin 
2866*3088717bSVictor Perevertkin 
2867*3088717bSVictor Perevertkin NTSTATUS
2868*3088717bSVictor Perevertkin NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoSetWmiDataBlock(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN ULONG GuidIndex,IN ULONG BufferSize,IN PUCHAR Buffer)2869*3088717bSVictor Perevertkin DiskFdoSetWmiDataBlock(
2870*3088717bSVictor Perevertkin     IN PDEVICE_OBJECT DeviceObject,
2871*3088717bSVictor Perevertkin     IN PIRP Irp,
2872*3088717bSVictor Perevertkin     IN ULONG GuidIndex,
2873*3088717bSVictor Perevertkin     IN ULONG BufferSize,
2874*3088717bSVictor Perevertkin     IN PUCHAR Buffer
2875*3088717bSVictor Perevertkin     )
2876*3088717bSVictor Perevertkin /*++
2877*3088717bSVictor Perevertkin 
2878*3088717bSVictor Perevertkin Routine Description:
2879*3088717bSVictor Perevertkin 
2880*3088717bSVictor Perevertkin     This routine is a callback into the driver to query for the contents of
2881*3088717bSVictor Perevertkin     a data block. When the driver has finished filling the data block it
2882*3088717bSVictor Perevertkin     must call ClassWmiCompleteRequest to complete the irp. The driver can
2883*3088717bSVictor Perevertkin     return STATUS_PENDING if the irp cannot be completed immediately.
2884*3088717bSVictor Perevertkin 
2885*3088717bSVictor Perevertkin Arguments:
2886*3088717bSVictor Perevertkin 
2887*3088717bSVictor Perevertkin     DeviceObject is the device whose data block is being queried
2888*3088717bSVictor Perevertkin 
2889*3088717bSVictor Perevertkin     Irp is the Irp that makes this request
2890*3088717bSVictor Perevertkin 
2891*3088717bSVictor Perevertkin     GuidIndex is the index into the list of guids provided when the
2892*3088717bSVictor Perevertkin         device registered
2893*3088717bSVictor Perevertkin 
2894*3088717bSVictor Perevertkin     BufferSize has the size of the data block passed
2895*3088717bSVictor Perevertkin 
2896*3088717bSVictor Perevertkin     Buffer has the new values for the data block
2897*3088717bSVictor Perevertkin 
2898*3088717bSVictor Perevertkin 
2899*3088717bSVictor Perevertkin Return Value:
2900*3088717bSVictor Perevertkin 
2901*3088717bSVictor Perevertkin     status
2902*3088717bSVictor Perevertkin 
2903*3088717bSVictor Perevertkin --*/
2904*3088717bSVictor Perevertkin {
2905*3088717bSVictor Perevertkin     NTSTATUS status;
2906*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
2907*3088717bSVictor Perevertkin     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
2908*3088717bSVictor Perevertkin     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
2909*3088717bSVictor Perevertkin 
2910*3088717bSVictor Perevertkin     PAGED_CODE();
2911*3088717bSVictor Perevertkin 
2912*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskSetWmiDataBlock, Device %p, Irp %p, GuiIndex %d\n"
2913*3088717bSVictor Perevertkin              "      BufferSize %#x Buffer %p\n",
2914*3088717bSVictor Perevertkin              DeviceObject, Irp,
2915*3088717bSVictor Perevertkin              GuidIndex, BufferSize, Buffer));
2916*3088717bSVictor Perevertkin 
2917*3088717bSVictor Perevertkin     if (GuidIndex == ScsiInfoExceptionsGuid)
2918*3088717bSVictor Perevertkin     {
2919*3088717bSVictor Perevertkin         PSTORAGE_SCSI_INFO_EXCEPTIONS infoExceptions;
2920*3088717bSVictor Perevertkin         MODE_INFO_EXCEPTIONS modeInfo = {0};
2921*3088717bSVictor Perevertkin 
2922*3088717bSVictor Perevertkin         if (BufferSize >= sizeof(STORAGE_SCSI_INFO_EXCEPTIONS))
2923*3088717bSVictor Perevertkin         {
2924*3088717bSVictor Perevertkin             infoExceptions = (PSTORAGE_SCSI_INFO_EXCEPTIONS)Buffer;
2925*3088717bSVictor Perevertkin 
2926*3088717bSVictor Perevertkin             modeInfo.PageCode = MODE_PAGE_FAULT_REPORTING;
2927*3088717bSVictor Perevertkin             modeInfo.PageLength = sizeof(MODE_INFO_EXCEPTIONS) - 2;
2928*3088717bSVictor Perevertkin 
2929*3088717bSVictor Perevertkin             modeInfo.PSBit = 0;
2930*3088717bSVictor Perevertkin             modeInfo.Flags = infoExceptions->Flags;
2931*3088717bSVictor Perevertkin 
2932*3088717bSVictor Perevertkin             modeInfo.ReportMethod = infoExceptions->MRIE;
2933*3088717bSVictor Perevertkin 
2934*3088717bSVictor Perevertkin             REVERSE_BYTES(&modeInfo.IntervalTimer[0],
2935*3088717bSVictor Perevertkin                           &infoExceptions->IntervalTimer);
2936*3088717bSVictor Perevertkin 
2937*3088717bSVictor Perevertkin             REVERSE_BYTES(&modeInfo.ReportCount[0],
2938*3088717bSVictor Perevertkin                           &infoExceptions->ReportCount);
2939*3088717bSVictor Perevertkin 
2940*3088717bSVictor Perevertkin             if (modeInfo.Perf == 1)
2941*3088717bSVictor Perevertkin             {
2942*3088717bSVictor Perevertkin                 diskData->AllowFPPerfHit = FALSE;
2943*3088717bSVictor Perevertkin             } else {
2944*3088717bSVictor Perevertkin                 diskData->AllowFPPerfHit = TRUE;
2945*3088717bSVictor Perevertkin             }
2946*3088717bSVictor Perevertkin 
2947*3088717bSVictor Perevertkin             status = DiskSetInfoExceptionInformation(fdoExtension,
2948*3088717bSVictor Perevertkin                                                      &modeInfo);
2949*3088717bSVictor Perevertkin         } else {
2950*3088717bSVictor Perevertkin             status = STATUS_INVALID_PARAMETER;
2951*3088717bSVictor Perevertkin         }
2952*3088717bSVictor Perevertkin 
2953*3088717bSVictor Perevertkin     } else if (GuidIndex <= SmartThresholdsGuid)
2954*3088717bSVictor Perevertkin     {
2955*3088717bSVictor Perevertkin         status = STATUS_WMI_READ_ONLY;
2956*3088717bSVictor Perevertkin     } else {
2957*3088717bSVictor Perevertkin         status = STATUS_WMI_GUID_NOT_FOUND;
2958*3088717bSVictor Perevertkin     }
2959*3088717bSVictor Perevertkin 
2960*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskSetWmiDataBlock Device %p, Irp %p returns %lx\n",
2961*3088717bSVictor Perevertkin              DeviceObject, Irp, status));
2962*3088717bSVictor Perevertkin 
2963*3088717bSVictor Perevertkin     status = ClassWmiCompleteRequest(DeviceObject,
2964*3088717bSVictor Perevertkin                                      Irp,
2965*3088717bSVictor Perevertkin                                      status,
2966*3088717bSVictor Perevertkin                                      0,
2967*3088717bSVictor Perevertkin                                      IO_NO_INCREMENT);
2968*3088717bSVictor Perevertkin 
2969*3088717bSVictor Perevertkin     return status;
2970*3088717bSVictor Perevertkin }
2971*3088717bSVictor Perevertkin 
2972*3088717bSVictor Perevertkin 
2973*3088717bSVictor Perevertkin NTSTATUS
2974*3088717bSVictor Perevertkin NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoSetWmiDataItem(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN ULONG GuidIndex,IN ULONG DataItemId,IN ULONG BufferSize,IN PUCHAR Buffer)2975*3088717bSVictor Perevertkin DiskFdoSetWmiDataItem(
2976*3088717bSVictor Perevertkin     IN PDEVICE_OBJECT DeviceObject,
2977*3088717bSVictor Perevertkin     IN PIRP Irp,
2978*3088717bSVictor Perevertkin     IN ULONG GuidIndex,
2979*3088717bSVictor Perevertkin     IN ULONG DataItemId,
2980*3088717bSVictor Perevertkin     IN ULONG BufferSize,
2981*3088717bSVictor Perevertkin     IN PUCHAR Buffer
2982*3088717bSVictor Perevertkin     )
2983*3088717bSVictor Perevertkin /*++
2984*3088717bSVictor Perevertkin 
2985*3088717bSVictor Perevertkin Routine Description:
2986*3088717bSVictor Perevertkin 
2987*3088717bSVictor Perevertkin     This routine is a callback into the driver to query for the contents of
2988*3088717bSVictor Perevertkin     a data block. When the driver has finished filling the data block it
2989*3088717bSVictor Perevertkin     must call ClassWmiCompleteRequest to complete the irp. The driver can
2990*3088717bSVictor Perevertkin     return STATUS_PENDING if the irp cannot be completed immediately.
2991*3088717bSVictor Perevertkin 
2992*3088717bSVictor Perevertkin Arguments:
2993*3088717bSVictor Perevertkin 
2994*3088717bSVictor Perevertkin     DeviceObject is the device whose data block is being queried
2995*3088717bSVictor Perevertkin 
2996*3088717bSVictor Perevertkin     Irp is the Irp that makes this request
2997*3088717bSVictor Perevertkin 
2998*3088717bSVictor Perevertkin     GuidIndex is the index into the list of guids provided when the
2999*3088717bSVictor Perevertkin         device registered
3000*3088717bSVictor Perevertkin 
3001*3088717bSVictor Perevertkin     DataItemId has the id of the data item being set
3002*3088717bSVictor Perevertkin 
3003*3088717bSVictor Perevertkin     BufferSize has the size of the data item passed
3004*3088717bSVictor Perevertkin 
3005*3088717bSVictor Perevertkin     Buffer has the new values for the data item
3006*3088717bSVictor Perevertkin 
3007*3088717bSVictor Perevertkin 
3008*3088717bSVictor Perevertkin Return Value:
3009*3088717bSVictor Perevertkin 
3010*3088717bSVictor Perevertkin     status
3011*3088717bSVictor Perevertkin 
3012*3088717bSVictor Perevertkin --*/
3013*3088717bSVictor Perevertkin {
3014*3088717bSVictor Perevertkin     NTSTATUS status;
3015*3088717bSVictor Perevertkin 
3016*3088717bSVictor Perevertkin     PAGED_CODE();
3017*3088717bSVictor Perevertkin 
3018*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskSetWmiDataItem, Device %p, Irp %p, GuiIndex %d, DataId %d\n"
3019*3088717bSVictor Perevertkin              "      BufferSize %#x Buffer %p\n",
3020*3088717bSVictor Perevertkin              DeviceObject, Irp,
3021*3088717bSVictor Perevertkin              GuidIndex, DataItemId, BufferSize, Buffer));
3022*3088717bSVictor Perevertkin 
3023*3088717bSVictor Perevertkin     if (GuidIndex <= SmartThresholdsGuid)
3024*3088717bSVictor Perevertkin     {
3025*3088717bSVictor Perevertkin         status = STATUS_WMI_READ_ONLY;
3026*3088717bSVictor Perevertkin     } else {
3027*3088717bSVictor Perevertkin         status = STATUS_WMI_GUID_NOT_FOUND;
3028*3088717bSVictor Perevertkin     }
3029*3088717bSVictor Perevertkin 
3030*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskSetWmiDataItem Device %p, Irp %p returns %lx\n",
3031*3088717bSVictor Perevertkin              DeviceObject, Irp, status));
3032*3088717bSVictor Perevertkin 
3033*3088717bSVictor Perevertkin     status = ClassWmiCompleteRequest(DeviceObject,
3034*3088717bSVictor Perevertkin                                      Irp,
3035*3088717bSVictor Perevertkin                                      status,
3036*3088717bSVictor Perevertkin                                      0,
3037*3088717bSVictor Perevertkin                                      IO_NO_INCREMENT);
3038*3088717bSVictor Perevertkin 
3039*3088717bSVictor Perevertkin     return status;
3040*3088717bSVictor Perevertkin }
3041*3088717bSVictor Perevertkin 
3042*3088717bSVictor Perevertkin 
3043*3088717bSVictor Perevertkin NTSTATUS
3044*3088717bSVictor Perevertkin NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoExecuteWmiMethod(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN ULONG GuidIndex,IN ULONG MethodId,IN ULONG InBufferSize,IN ULONG OutBufferSize,IN PUCHAR Buffer)3045*3088717bSVictor Perevertkin DiskFdoExecuteWmiMethod(
3046*3088717bSVictor Perevertkin     IN PDEVICE_OBJECT DeviceObject,
3047*3088717bSVictor Perevertkin     IN PIRP Irp,
3048*3088717bSVictor Perevertkin     IN ULONG GuidIndex,
3049*3088717bSVictor Perevertkin     IN ULONG MethodId,
3050*3088717bSVictor Perevertkin     IN ULONG InBufferSize,
3051*3088717bSVictor Perevertkin     IN ULONG OutBufferSize,
3052*3088717bSVictor Perevertkin     IN PUCHAR Buffer
3053*3088717bSVictor Perevertkin     )
3054*3088717bSVictor Perevertkin /*++
3055*3088717bSVictor Perevertkin 
3056*3088717bSVictor Perevertkin Routine Description:
3057*3088717bSVictor Perevertkin 
3058*3088717bSVictor Perevertkin     This routine is a callback into the driver to execute a method. When the
3059*3088717bSVictor Perevertkin     driver has finished filling the data block it must call
3060*3088717bSVictor Perevertkin     ClassWmiCompleteRequest to complete the irp. The driver can
3061*3088717bSVictor Perevertkin     return STATUS_PENDING if the irp cannot be completed immediately.
3062*3088717bSVictor Perevertkin 
3063*3088717bSVictor Perevertkin Arguments:
3064*3088717bSVictor Perevertkin 
3065*3088717bSVictor Perevertkin     DeviceObject is the device whose data block is being queried
3066*3088717bSVictor Perevertkin 
3067*3088717bSVictor Perevertkin     Irp is the Irp that makes this request
3068*3088717bSVictor Perevertkin 
3069*3088717bSVictor Perevertkin     GuidIndex is the index into the list of guids provided when the
3070*3088717bSVictor Perevertkin         device registered
3071*3088717bSVictor Perevertkin 
3072*3088717bSVictor Perevertkin     MethodId has the id of the method being called
3073*3088717bSVictor Perevertkin 
3074*3088717bSVictor Perevertkin     InBufferSize has the size of the data block passed in as the input to
3075*3088717bSVictor Perevertkin         the method.
3076*3088717bSVictor Perevertkin 
3077*3088717bSVictor Perevertkin     OutBufferSize on entry has the maximum size available to write the
3078*3088717bSVictor Perevertkin         returned data block.
3079*3088717bSVictor Perevertkin 
3080*3088717bSVictor Perevertkin     Buffer is filled with the returned data block
3081*3088717bSVictor Perevertkin 
3082*3088717bSVictor Perevertkin 
3083*3088717bSVictor Perevertkin Return Value:
3084*3088717bSVictor Perevertkin 
3085*3088717bSVictor Perevertkin     status
3086*3088717bSVictor Perevertkin 
3087*3088717bSVictor Perevertkin --*/
3088*3088717bSVictor Perevertkin {
3089*3088717bSVictor Perevertkin     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3090*3088717bSVictor Perevertkin     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3091*3088717bSVictor Perevertkin     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
3092*3088717bSVictor Perevertkin     ULONG sizeNeeded = 0;
3093*3088717bSVictor Perevertkin     NTSTATUS status;
3094*3088717bSVictor Perevertkin 
3095*3088717bSVictor Perevertkin     PAGED_CODE();
3096*3088717bSVictor Perevertkin 
3097*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskExecuteWmiMethod, DeviceObject %p, Irp %p, Guid Id %d, MethodId %d\n"
3098*3088717bSVictor Perevertkin              "      InBufferSize %#x, OutBufferSize %#x, Buffer %p\n",
3099*3088717bSVictor Perevertkin              DeviceObject, Irp,
3100*3088717bSVictor Perevertkin              GuidIndex, MethodId, InBufferSize, OutBufferSize, Buffer));
3101*3088717bSVictor Perevertkin 
3102*3088717bSVictor Perevertkin     switch(GuidIndex)
3103*3088717bSVictor Perevertkin     {
3104*3088717bSVictor Perevertkin         case SmartPerformFunction:
3105*3088717bSVictor Perevertkin         {
3106*3088717bSVictor Perevertkin 
3107*3088717bSVictor Perevertkin             NT_ASSERT((diskData->FailurePredictionCapability ==
3108*3088717bSVictor Perevertkin                                                   FailurePredictionSmart) ||
3109*3088717bSVictor Perevertkin                    (diskData->FailurePredictionCapability ==
3110*3088717bSVictor Perevertkin                                                   FailurePredictionIoctl) ||
3111*3088717bSVictor Perevertkin                    (diskData->FailurePredictionCapability ==
3112*3088717bSVictor Perevertkin                                                   FailurePredictionSense));
3113*3088717bSVictor Perevertkin 
3114*3088717bSVictor Perevertkin 
3115*3088717bSVictor Perevertkin             switch(MethodId)
3116*3088717bSVictor Perevertkin             {
3117*3088717bSVictor Perevertkin                 //
3118*3088717bSVictor Perevertkin                 // void AllowPerformanceHit([in] boolean Allow)
3119*3088717bSVictor Perevertkin                 //
3120*3088717bSVictor Perevertkin                 case AllowDisallowPerformanceHit:
3121*3088717bSVictor Perevertkin                 {
3122*3088717bSVictor Perevertkin                     BOOLEAN allowPerfHit;
3123*3088717bSVictor Perevertkin 
3124*3088717bSVictor Perevertkin                     sizeNeeded = 0;
3125*3088717bSVictor Perevertkin                     if (InBufferSize >= sizeof(BOOLEAN))
3126*3088717bSVictor Perevertkin                     {
3127*3088717bSVictor Perevertkin                         status = STATUS_SUCCESS;
3128*3088717bSVictor Perevertkin 
3129*3088717bSVictor Perevertkin                         allowPerfHit = *((PBOOLEAN)Buffer);
3130*3088717bSVictor Perevertkin                         if (diskData->AllowFPPerfHit != allowPerfHit)
3131*3088717bSVictor Perevertkin                         {
3132*3088717bSVictor Perevertkin                             diskData->AllowFPPerfHit = allowPerfHit;
3133*3088717bSVictor Perevertkin                             if (diskData->FailurePredictionCapability ==
3134*3088717bSVictor Perevertkin                                 FailurePredictionSense)
3135*3088717bSVictor Perevertkin                             {
3136*3088717bSVictor Perevertkin                                 MODE_INFO_EXCEPTIONS modeInfo;
3137*3088717bSVictor Perevertkin 
3138*3088717bSVictor Perevertkin                                 status = DiskGetInfoExceptionInformation(fdoExtension,
3139*3088717bSVictor Perevertkin                                                                          &modeInfo);
3140*3088717bSVictor Perevertkin                                 if (NT_SUCCESS(status))
3141*3088717bSVictor Perevertkin                                 {
3142*3088717bSVictor Perevertkin                                     modeInfo.Perf = allowPerfHit ? 0 : 1;
3143*3088717bSVictor Perevertkin                                     status = DiskSetInfoExceptionInformation(fdoExtension,
3144*3088717bSVictor Perevertkin                                                                              &modeInfo);
3145*3088717bSVictor Perevertkin                                 }
3146*3088717bSVictor Perevertkin                             }
3147*3088717bSVictor Perevertkin                             else
3148*3088717bSVictor Perevertkin                             {
3149*3088717bSVictor Perevertkin                                 status = STATUS_INVALID_DEVICE_REQUEST;
3150*3088717bSVictor Perevertkin                             }
3151*3088717bSVictor Perevertkin                         }
3152*3088717bSVictor Perevertkin 
3153*3088717bSVictor Perevertkin                         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskFdoWmiExecuteMethod: AllowPerformanceHit %x for device %p --> %lx\n",
3154*3088717bSVictor Perevertkin                                     allowPerfHit,
3155*3088717bSVictor Perevertkin                                     fdoExtension->DeviceObject,
3156*3088717bSVictor Perevertkin                                     status));
3157*3088717bSVictor Perevertkin                     } else {
3158*3088717bSVictor Perevertkin                         status = STATUS_INVALID_PARAMETER;
3159*3088717bSVictor Perevertkin                     }
3160*3088717bSVictor Perevertkin                     break;
3161*3088717bSVictor Perevertkin                 }
3162*3088717bSVictor Perevertkin 
3163*3088717bSVictor Perevertkin                 //
3164*3088717bSVictor Perevertkin                 // void EnableDisableHardwareFailurePrediction([in] boolean Enable)
3165*3088717bSVictor Perevertkin                 //
3166*3088717bSVictor Perevertkin                 case EnableDisableHardwareFailurePrediction:
3167*3088717bSVictor Perevertkin                 {
3168*3088717bSVictor Perevertkin                     BOOLEAN enable;
3169*3088717bSVictor Perevertkin 
3170*3088717bSVictor Perevertkin                     sizeNeeded = 0;
3171*3088717bSVictor Perevertkin                     if (InBufferSize >= sizeof(BOOLEAN))
3172*3088717bSVictor Perevertkin                     {
3173*3088717bSVictor Perevertkin                         status = STATUS_SUCCESS;
3174*3088717bSVictor Perevertkin                         enable = *((PBOOLEAN)Buffer);
3175*3088717bSVictor Perevertkin                         if (!enable)
3176*3088717bSVictor Perevertkin                         {
3177*3088717bSVictor Perevertkin                             //
3178*3088717bSVictor Perevertkin                             // If we are disabling we need to also disable
3179*3088717bSVictor Perevertkin                             // polling
3180*3088717bSVictor Perevertkin                             //
3181*3088717bSVictor Perevertkin                             DiskEnableDisableFailurePredictPolling(
3182*3088717bSVictor Perevertkin                                                                fdoExtension,
3183*3088717bSVictor Perevertkin                                                                enable,
3184*3088717bSVictor Perevertkin                                                                0);
3185*3088717bSVictor Perevertkin                         }
3186*3088717bSVictor Perevertkin 
3187*3088717bSVictor Perevertkin                         status = DiskEnableDisableFailurePrediction(
3188*3088717bSVictor Perevertkin                                                            fdoExtension,
3189*3088717bSVictor Perevertkin                                                            enable);
3190*3088717bSVictor Perevertkin 
3191*3088717bSVictor Perevertkin                         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskFdoWmiExecuteMethod: EnableDisableHardwareFailurePrediction: %x for device %p --> %lx\n",
3192*3088717bSVictor Perevertkin                                     enable,
3193*3088717bSVictor Perevertkin                                     fdoExtension->DeviceObject,
3194*3088717bSVictor Perevertkin                                     status));
3195*3088717bSVictor Perevertkin                     } else {
3196*3088717bSVictor Perevertkin                         status = STATUS_INVALID_PARAMETER;
3197*3088717bSVictor Perevertkin                     }
3198*3088717bSVictor Perevertkin                     break;
3199*3088717bSVictor Perevertkin                 }
3200*3088717bSVictor Perevertkin 
3201*3088717bSVictor Perevertkin                 //
3202*3088717bSVictor Perevertkin                 // void EnableDisableFailurePredictionPolling(
3203*3088717bSVictor Perevertkin                 //                               [in] uint32 Period,
3204*3088717bSVictor Perevertkin                 //                               [in] boolean Enable)
3205*3088717bSVictor Perevertkin                 //
3206*3088717bSVictor Perevertkin                 case EnableDisableFailurePredictionPolling:
3207*3088717bSVictor Perevertkin                 {
3208*3088717bSVictor Perevertkin                     BOOLEAN enable;
3209*3088717bSVictor Perevertkin                     ULONG period;
3210*3088717bSVictor Perevertkin 
3211*3088717bSVictor Perevertkin                     sizeNeeded = 0;
3212*3088717bSVictor Perevertkin                     if (InBufferSize >= (sizeof(ULONG) + sizeof(BOOLEAN)))
3213*3088717bSVictor Perevertkin                     {
3214*3088717bSVictor Perevertkin                         period = *((PULONG)Buffer);
3215*3088717bSVictor Perevertkin                         Buffer += sizeof(ULONG);
3216*3088717bSVictor Perevertkin                         enable = *((PBOOLEAN)Buffer);
3217*3088717bSVictor Perevertkin 
3218*3088717bSVictor Perevertkin                            status = DiskEnableDisableFailurePredictPolling(
3219*3088717bSVictor Perevertkin                                                                fdoExtension,
3220*3088717bSVictor Perevertkin                                                                enable,
3221*3088717bSVictor Perevertkin                                                                period);
3222*3088717bSVictor Perevertkin 
3223*3088717bSVictor Perevertkin                            TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskFdoWmiExecuteMethod: EnableDisableFailurePredictionPolling: %x %x for device %p --> %lx\n",
3224*3088717bSVictor Perevertkin                                     enable,
3225*3088717bSVictor Perevertkin                                     period,
3226*3088717bSVictor Perevertkin                                     fdoExtension->DeviceObject,
3227*3088717bSVictor Perevertkin                                     status));
3228*3088717bSVictor Perevertkin                     } else {
3229*3088717bSVictor Perevertkin                         status = STATUS_INVALID_PARAMETER;
3230*3088717bSVictor Perevertkin                     }
3231*3088717bSVictor Perevertkin                     break;
3232*3088717bSVictor Perevertkin                 }
3233*3088717bSVictor Perevertkin 
3234*3088717bSVictor Perevertkin                 //
3235*3088717bSVictor Perevertkin                 // void GetFailurePredictionCapability([out] uint32 Capability)
3236*3088717bSVictor Perevertkin                 //
3237*3088717bSVictor Perevertkin                 case GetFailurePredictionCapability:
3238*3088717bSVictor Perevertkin                 {
3239*3088717bSVictor Perevertkin                     sizeNeeded = sizeof(ULONG);
3240*3088717bSVictor Perevertkin                     if (OutBufferSize >= sizeNeeded)
3241*3088717bSVictor Perevertkin                     {
3242*3088717bSVictor Perevertkin                         status = STATUS_SUCCESS;
3243*3088717bSVictor Perevertkin                         *((PFAILURE_PREDICTION_METHOD)Buffer) = diskData->FailurePredictionCapability;
3244*3088717bSVictor Perevertkin                         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskFdoWmiExecuteMethod: GetFailurePredictionCapability: %x for device %p --> %lx\n",
3245*3088717bSVictor Perevertkin                                     *((PFAILURE_PREDICTION_METHOD)Buffer),
3246*3088717bSVictor Perevertkin                                     fdoExtension->DeviceObject,
3247*3088717bSVictor Perevertkin                                     status));
3248*3088717bSVictor Perevertkin                     } else {
3249*3088717bSVictor Perevertkin                         status = STATUS_BUFFER_TOO_SMALL;
3250*3088717bSVictor Perevertkin                     }
3251*3088717bSVictor Perevertkin                     break;
3252*3088717bSVictor Perevertkin                 }
3253*3088717bSVictor Perevertkin 
3254*3088717bSVictor Perevertkin                 //
3255*3088717bSVictor Perevertkin                 // void EnableOfflineDiags([out] boolean Success);
3256*3088717bSVictor Perevertkin                 //
3257*3088717bSVictor Perevertkin                 case EnableOfflineDiags:
3258*3088717bSVictor Perevertkin                 {
3259*3088717bSVictor Perevertkin                     sizeNeeded = sizeof(BOOLEAN);
3260*3088717bSVictor Perevertkin                     if (OutBufferSize >= sizeNeeded)
3261*3088717bSVictor Perevertkin                     {
3262*3088717bSVictor Perevertkin                         if (diskData->FailurePredictionCapability ==
3263*3088717bSVictor Perevertkin                                   FailurePredictionSmart)
3264*3088717bSVictor Perevertkin                         {
3265*3088717bSVictor Perevertkin                             //
3266*3088717bSVictor Perevertkin                             // Initiate or resume offline diagnostics.
3267*3088717bSVictor Perevertkin                             // This may cause a loss of performance
3268*3088717bSVictor Perevertkin                             // to the disk, but mayincrease the amount
3269*3088717bSVictor Perevertkin                             // of disk checking.
3270*3088717bSVictor Perevertkin                             //
3271*3088717bSVictor Perevertkin                             status = DiskExecuteSmartDiagnostics(fdoExtension,
3272*3088717bSVictor Perevertkin                                                                 0);
3273*3088717bSVictor Perevertkin 
3274*3088717bSVictor Perevertkin                         } else {
3275*3088717bSVictor Perevertkin                             status = STATUS_INVALID_DEVICE_REQUEST;
3276*3088717bSVictor Perevertkin                         }
3277*3088717bSVictor Perevertkin 
3278*3088717bSVictor Perevertkin                         *((PBOOLEAN)Buffer) = NT_SUCCESS(status);
3279*3088717bSVictor Perevertkin 
3280*3088717bSVictor Perevertkin                         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskFdoWmiExecuteMethod: EnableOfflineDiags for device %p --> %lx\n",
3281*3088717bSVictor Perevertkin                                     fdoExtension->DeviceObject,
3282*3088717bSVictor Perevertkin                                     status));
3283*3088717bSVictor Perevertkin                     } else {
3284*3088717bSVictor Perevertkin                         status = STATUS_BUFFER_TOO_SMALL;
3285*3088717bSVictor Perevertkin                     }
3286*3088717bSVictor Perevertkin                     break;
3287*3088717bSVictor Perevertkin                 }
3288*3088717bSVictor Perevertkin 
3289*3088717bSVictor Perevertkin                 //
3290*3088717bSVictor Perevertkin                 //    void ReadLogSectors([in] uint8 LogAddress,
3291*3088717bSVictor Perevertkin                 //        [in] uint8 SectorCount,
3292*3088717bSVictor Perevertkin                 //        [out] uint32 Length,
3293*3088717bSVictor Perevertkin                 //        [out, WmiSizeIs("Length")] uint8 LogSectors[]
3294*3088717bSVictor Perevertkin                 //       );
3295*3088717bSVictor Perevertkin                 //
3296*3088717bSVictor Perevertkin                 case ReadLogSectors:
3297*3088717bSVictor Perevertkin                 {
3298*3088717bSVictor Perevertkin                     if (diskData->FailurePredictionCapability ==
3299*3088717bSVictor Perevertkin                                   FailurePredictionSmart)
3300*3088717bSVictor Perevertkin                     {
3301*3088717bSVictor Perevertkin                         if (InBufferSize >= sizeof(READ_LOG_SECTORS_IN))
3302*3088717bSVictor Perevertkin                         {
3303*3088717bSVictor Perevertkin                             PREAD_LOG_SECTORS_IN inParams;
3304*3088717bSVictor Perevertkin                             PREAD_LOG_SECTORS_OUT outParams;
3305*3088717bSVictor Perevertkin                             ULONG readSize;
3306*3088717bSVictor Perevertkin 
3307*3088717bSVictor Perevertkin                             inParams = (PREAD_LOG_SECTORS_IN)Buffer;
3308*3088717bSVictor Perevertkin                             readSize = inParams->SectorCount * SMART_LOG_SECTOR_SIZE;
3309*3088717bSVictor Perevertkin                             sizeNeeded = FIELD_OFFSET(READ_LOG_SECTORS_OUT,
3310*3088717bSVictor Perevertkin                                                   LogSectors) + readSize;
3311*3088717bSVictor Perevertkin 
3312*3088717bSVictor Perevertkin                             if (OutBufferSize >= sizeNeeded)
3313*3088717bSVictor Perevertkin                             {
3314*3088717bSVictor Perevertkin                                 outParams = (PREAD_LOG_SECTORS_OUT)Buffer;
3315*3088717bSVictor Perevertkin                                 status = DiskReadSmartLog(fdoExtension,
3316*3088717bSVictor Perevertkin                                                         inParams->SectorCount,
3317*3088717bSVictor Perevertkin                                                         inParams->LogAddress,
3318*3088717bSVictor Perevertkin                                                         outParams->LogSectors);
3319*3088717bSVictor Perevertkin 
3320*3088717bSVictor Perevertkin                                 if (NT_SUCCESS(status))
3321*3088717bSVictor Perevertkin                                 {
3322*3088717bSVictor Perevertkin                                     outParams->Length = readSize;
3323*3088717bSVictor Perevertkin                                 } else {
3324*3088717bSVictor Perevertkin                                     //
3325*3088717bSVictor Perevertkin                                     // SMART command failure is
3326*3088717bSVictor Perevertkin                                     // indicated by successful
3327*3088717bSVictor Perevertkin                                     // execution, but no data returned
3328*3088717bSVictor Perevertkin                                     //
3329*3088717bSVictor Perevertkin                                     outParams->Length = 0;
3330*3088717bSVictor Perevertkin                                     status = STATUS_SUCCESS;
3331*3088717bSVictor Perevertkin                                 }
3332*3088717bSVictor Perevertkin                             } else {
3333*3088717bSVictor Perevertkin                                 status = STATUS_BUFFER_TOO_SMALL;
3334*3088717bSVictor Perevertkin                             }
3335*3088717bSVictor Perevertkin 
3336*3088717bSVictor Perevertkin                         } else {
3337*3088717bSVictor Perevertkin                             status = STATUS_INVALID_PARAMETER;
3338*3088717bSVictor Perevertkin                         }
3339*3088717bSVictor Perevertkin                     } else {
3340*3088717bSVictor Perevertkin                         status = STATUS_INVALID_DEVICE_REQUEST;
3341*3088717bSVictor Perevertkin                     }
3342*3088717bSVictor Perevertkin                     break;
3343*3088717bSVictor Perevertkin                 }
3344*3088717bSVictor Perevertkin 
3345*3088717bSVictor Perevertkin                 //    void WriteLogSectors([in] uint8 LogAddress,
3346*3088717bSVictor Perevertkin                 //        [in] uint8 SectorCount,
3347*3088717bSVictor Perevertkin                 //        [in] uint32 Length,
3348*3088717bSVictor Perevertkin                 //        [in, WmiSizeIs("Length")] uint8 LogSectors[],
3349*3088717bSVictor Perevertkin                 //        [out] boolean Success
3350*3088717bSVictor Perevertkin                 //       );
3351*3088717bSVictor Perevertkin                 case WriteLogSectors:
3352*3088717bSVictor Perevertkin                 {
3353*3088717bSVictor Perevertkin                     if (diskData->FailurePredictionCapability ==
3354*3088717bSVictor Perevertkin                                   FailurePredictionSmart)
3355*3088717bSVictor Perevertkin                     {
3356*3088717bSVictor Perevertkin                         if ((LONG)InBufferSize >= FIELD_OFFSET(WRITE_LOG_SECTORS_IN,
3357*3088717bSVictor Perevertkin                                                         LogSectors))
3358*3088717bSVictor Perevertkin                         {
3359*3088717bSVictor Perevertkin                             PWRITE_LOG_SECTORS_IN inParams;
3360*3088717bSVictor Perevertkin                             PWRITE_LOG_SECTORS_OUT outParams;
3361*3088717bSVictor Perevertkin                             ULONG writeSize;
3362*3088717bSVictor Perevertkin 
3363*3088717bSVictor Perevertkin                             inParams = (PWRITE_LOG_SECTORS_IN)Buffer;
3364*3088717bSVictor Perevertkin                             writeSize = inParams->SectorCount * SMART_LOG_SECTOR_SIZE;
3365*3088717bSVictor Perevertkin                             if (InBufferSize >= (FIELD_OFFSET(WRITE_LOG_SECTORS_IN,
3366*3088717bSVictor Perevertkin                                                              LogSectors) +
3367*3088717bSVictor Perevertkin                                                  writeSize))
3368*3088717bSVictor Perevertkin                             {
3369*3088717bSVictor Perevertkin                                 sizeNeeded = sizeof(WRITE_LOG_SECTORS_OUT);
3370*3088717bSVictor Perevertkin 
3371*3088717bSVictor Perevertkin                                 if (OutBufferSize >= sizeNeeded)
3372*3088717bSVictor Perevertkin                                 {
3373*3088717bSVictor Perevertkin                                     outParams = (PWRITE_LOG_SECTORS_OUT)Buffer;
3374*3088717bSVictor Perevertkin                                     status = DiskWriteSmartLog(fdoExtension,
3375*3088717bSVictor Perevertkin                                                         inParams->SectorCount,
3376*3088717bSVictor Perevertkin                                                         inParams->LogAddress,
3377*3088717bSVictor Perevertkin                                                         inParams->LogSectors);
3378*3088717bSVictor Perevertkin 
3379*3088717bSVictor Perevertkin                                     if (NT_SUCCESS(status))
3380*3088717bSVictor Perevertkin                                     {
3381*3088717bSVictor Perevertkin                                         outParams->Success = TRUE;
3382*3088717bSVictor Perevertkin                                     } else {
3383*3088717bSVictor Perevertkin                                         outParams->Success = FALSE;
3384*3088717bSVictor Perevertkin                                         status = STATUS_SUCCESS;
3385*3088717bSVictor Perevertkin                                     }
3386*3088717bSVictor Perevertkin                                 } else {
3387*3088717bSVictor Perevertkin                                     status = STATUS_BUFFER_TOO_SMALL;
3388*3088717bSVictor Perevertkin                                 }
3389*3088717bSVictor Perevertkin                             } else {
3390*3088717bSVictor Perevertkin                                 status = STATUS_INVALID_PARAMETER;
3391*3088717bSVictor Perevertkin                             }
3392*3088717bSVictor Perevertkin                         } else {
3393*3088717bSVictor Perevertkin                             status = STATUS_INVALID_PARAMETER;
3394*3088717bSVictor Perevertkin                         }
3395*3088717bSVictor Perevertkin                     } else {
3396*3088717bSVictor Perevertkin                         status = STATUS_INVALID_DEVICE_REQUEST;
3397*3088717bSVictor Perevertkin                     }
3398*3088717bSVictor Perevertkin                     break;
3399*3088717bSVictor Perevertkin                 }
3400*3088717bSVictor Perevertkin 
3401*3088717bSVictor Perevertkin                 //    void ExecuteSelfTest([in] uint8 Subcommand,
3402*3088717bSVictor Perevertkin                 //         [out,
3403*3088717bSVictor Perevertkin                 //          Values{"0", "1", "2"},
3404*3088717bSVictor Perevertkin                 //          ValueMap{"Successful Completion",
3405*3088717bSVictor Perevertkin                 //                   "Captive Mode Required",
3406*3088717bSVictor Perevertkin                 //                   "Unsuccessful Completion"}
3407*3088717bSVictor Perevertkin                 //         ]
3408*3088717bSVictor Perevertkin                 //         uint32 ReturnCode);
3409*3088717bSVictor Perevertkin                 case ExecuteSelfTest:
3410*3088717bSVictor Perevertkin                 {
3411*3088717bSVictor Perevertkin                     if (diskData->FailurePredictionCapability ==
3412*3088717bSVictor Perevertkin                               FailurePredictionSmart)
3413*3088717bSVictor Perevertkin                     {
3414*3088717bSVictor Perevertkin                         if (InBufferSize >= sizeof(EXECUTE_SELF_TEST_IN))
3415*3088717bSVictor Perevertkin                         {
3416*3088717bSVictor Perevertkin                             sizeNeeded = sizeof(EXECUTE_SELF_TEST_OUT);
3417*3088717bSVictor Perevertkin                             if (OutBufferSize >= sizeNeeded)
3418*3088717bSVictor Perevertkin                             {
3419*3088717bSVictor Perevertkin                                 PEXECUTE_SELF_TEST_IN inParam;
3420*3088717bSVictor Perevertkin                                 PEXECUTE_SELF_TEST_OUT outParam;
3421*3088717bSVictor Perevertkin 
3422*3088717bSVictor Perevertkin                                 inParam = (PEXECUTE_SELF_TEST_IN)Buffer;
3423*3088717bSVictor Perevertkin                                 outParam = (PEXECUTE_SELF_TEST_OUT)Buffer;
3424*3088717bSVictor Perevertkin 
3425*3088717bSVictor Perevertkin                                 if (DiskIsValidSmartSelfTest(inParam->Subcommand))
3426*3088717bSVictor Perevertkin                                 {
3427*3088717bSVictor Perevertkin                                    status = DiskExecuteSmartDiagnostics(fdoExtension,
3428*3088717bSVictor Perevertkin                                                             inParam->Subcommand);
3429*3088717bSVictor Perevertkin                                    if (NT_SUCCESS(status))
3430*3088717bSVictor Perevertkin                                    {
3431*3088717bSVictor Perevertkin                                        //
3432*3088717bSVictor Perevertkin                                        // Return self test executed
3433*3088717bSVictor Perevertkin                                        // without a problem
3434*3088717bSVictor Perevertkin                                        //
3435*3088717bSVictor Perevertkin                                        outParam->ReturnCode = 0;
3436*3088717bSVictor Perevertkin                                    } else {
3437*3088717bSVictor Perevertkin                                        //
3438*3088717bSVictor Perevertkin                                        // Return Self test execution
3439*3088717bSVictor Perevertkin                                        // failed status
3440*3088717bSVictor Perevertkin                                        //
3441*3088717bSVictor Perevertkin                                        outParam->ReturnCode = 2;
3442*3088717bSVictor Perevertkin                                        status = STATUS_SUCCESS;
3443*3088717bSVictor Perevertkin                                    }
3444*3088717bSVictor Perevertkin                                 } else {
3445*3088717bSVictor Perevertkin                                     //
3446*3088717bSVictor Perevertkin                                     // If self test subcommand requires
3447*3088717bSVictor Perevertkin                                     // captive mode then return that
3448*3088717bSVictor Perevertkin                                     // status
3449*3088717bSVictor Perevertkin                                     //
3450*3088717bSVictor Perevertkin                                     outParam->ReturnCode = 1;
3451*3088717bSVictor Perevertkin                                     status = STATUS_SUCCESS;
3452*3088717bSVictor Perevertkin                                 }
3453*3088717bSVictor Perevertkin 
3454*3088717bSVictor Perevertkin                             } else {
3455*3088717bSVictor Perevertkin                                 status = STATUS_BUFFER_TOO_SMALL;
3456*3088717bSVictor Perevertkin                             }
3457*3088717bSVictor Perevertkin 
3458*3088717bSVictor Perevertkin                         } else {
3459*3088717bSVictor Perevertkin                             status = STATUS_INVALID_PARAMETER;
3460*3088717bSVictor Perevertkin                         }
3461*3088717bSVictor Perevertkin                     } else {
3462*3088717bSVictor Perevertkin                         status = STATUS_INVALID_DEVICE_REQUEST;
3463*3088717bSVictor Perevertkin                     }
3464*3088717bSVictor Perevertkin 
3465*3088717bSVictor Perevertkin                     break;
3466*3088717bSVictor Perevertkin                 }
3467*3088717bSVictor Perevertkin 
3468*3088717bSVictor Perevertkin                 default :
3469*3088717bSVictor Perevertkin                 {
3470*3088717bSVictor Perevertkin                     sizeNeeded = 0;
3471*3088717bSVictor Perevertkin                     status = STATUS_WMI_ITEMID_NOT_FOUND;
3472*3088717bSVictor Perevertkin                     break;
3473*3088717bSVictor Perevertkin                 }
3474*3088717bSVictor Perevertkin             }
3475*3088717bSVictor Perevertkin 
3476*3088717bSVictor Perevertkin             break;
3477*3088717bSVictor Perevertkin         }
3478*3088717bSVictor Perevertkin 
3479*3088717bSVictor Perevertkin         case DiskGeometryGuid:
3480*3088717bSVictor Perevertkin         case SmartStatusGuid:
3481*3088717bSVictor Perevertkin         case SmartDataGuid:
3482*3088717bSVictor Perevertkin         case SmartEventGuid:
3483*3088717bSVictor Perevertkin         case SmartThresholdsGuid:
3484*3088717bSVictor Perevertkin         case ScsiInfoExceptionsGuid:
3485*3088717bSVictor Perevertkin         {
3486*3088717bSVictor Perevertkin             sizeNeeded = 0;
3487*3088717bSVictor Perevertkin             status = STATUS_INVALID_DEVICE_REQUEST;
3488*3088717bSVictor Perevertkin             break;
3489*3088717bSVictor Perevertkin         }
3490*3088717bSVictor Perevertkin 
3491*3088717bSVictor Perevertkin         default:
3492*3088717bSVictor Perevertkin         {
3493*3088717bSVictor Perevertkin             sizeNeeded = 0;
3494*3088717bSVictor Perevertkin             status = STATUS_WMI_GUID_NOT_FOUND;
3495*3088717bSVictor Perevertkin         }
3496*3088717bSVictor Perevertkin     }
3497*3088717bSVictor Perevertkin 
3498*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "Disk: DiskExecuteMethod Device %p, Irp %p returns %lx\n",
3499*3088717bSVictor Perevertkin              DeviceObject, Irp, status));
3500*3088717bSVictor Perevertkin 
3501*3088717bSVictor Perevertkin     status = ClassWmiCompleteRequest(DeviceObject,
3502*3088717bSVictor Perevertkin                                      Irp,
3503*3088717bSVictor Perevertkin                                      status,
3504*3088717bSVictor Perevertkin                                      sizeNeeded,
3505*3088717bSVictor Perevertkin                                      IO_NO_INCREMENT);
3506*3088717bSVictor Perevertkin 
3507*3088717bSVictor Perevertkin     return status;
3508*3088717bSVictor Perevertkin }
3509*3088717bSVictor Perevertkin 
3510*3088717bSVictor Perevertkin 
3511