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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 */ 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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