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