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