1 /*++ 2 3 Copyright (C) Microsoft Corporation, 1991 - 2010 4 5 Module Name: 6 7 disk.c 8 9 Abstract: 10 11 SCSI disk class driver 12 13 Environment: 14 15 kernel mode only 16 17 Notes: 18 19 Revision History: 20 21 --*/ 22 23 #define DEBUG_MAIN_SOURCE 1 24 #include "disk.h" 25 26 27 // 28 // Now instantiate the GUIDs 29 // 30 31 #include "initguid.h" 32 #include "ntddstor.h" 33 #include "ntddvol.h" 34 #include "ioevent.h" 35 36 #ifdef DEBUG_USE_WPP 37 #include "disk.tmh" 38 #endif 39 40 #ifdef ALLOC_PRAGMA 41 42 #pragma alloc_text(INIT, DriverEntry) 43 #pragma alloc_text(PAGE, DiskUnload) 44 #pragma alloc_text(PAGE, DiskCreateFdo) 45 #pragma alloc_text(PAGE, DiskDetermineMediaTypes) 46 #pragma alloc_text(PAGE, DiskModeSelect) 47 #pragma alloc_text(PAGE, DisableWriteCache) 48 #pragma alloc_text(PAGE, DiskSetSpecialHacks) 49 #pragma alloc_text(PAGE, DiskGetCacheInformation) 50 #pragma alloc_text(PAGE, DiskSetCacheInformation) 51 #pragma alloc_text(PAGE, DiskLogCacheInformation) 52 #pragma alloc_text(PAGE, DiskSetInfoExceptionInformation) 53 #pragma alloc_text(PAGE, DiskGetInfoExceptionInformation) 54 #pragma alloc_text(PAGE, DiskIoctlGetCacheSetting) 55 #pragma alloc_text(PAGE, DiskIoctlSetCacheSetting) 56 #pragma alloc_text(PAGE, DiskIoctlGetLengthInfo) 57 #pragma alloc_text(PAGE, DiskIoctlGetDriveGeometry) 58 #pragma alloc_text(PAGE, DiskIoctlGetDriveGeometryEx) 59 #pragma alloc_text(PAGE, DiskIoctlGetCacheInformation) 60 #pragma alloc_text(PAGE, DiskIoctlSetCacheInformation) 61 #pragma alloc_text(PAGE, DiskIoctlGetMediaTypesEx) 62 #pragma alloc_text(PAGE, DiskIoctlPredictFailure) 63 #pragma alloc_text(PAGE, DiskIoctlEnableFailurePrediction) 64 #pragma alloc_text(PAGE, DiskIoctlReassignBlocks) 65 #pragma alloc_text(PAGE, DiskIoctlReassignBlocksEx) 66 #pragma alloc_text(PAGE, DiskIoctlIsWritable) 67 #pragma alloc_text(PAGE, DiskIoctlUpdateDriveSize) 68 #pragma alloc_text(PAGE, DiskIoctlGetVolumeDiskExtents) 69 #pragma alloc_text(PAGE, DiskIoctlSmartGetVersion) 70 #pragma alloc_text(PAGE, DiskIoctlSmartReceiveDriveData) 71 #pragma alloc_text(PAGE, DiskIoctlSmartSendDriveCommand) 72 #pragma alloc_text(PAGE, DiskIoctlVerifyThread) 73 74 #endif 75 76 // 77 // ETW related globals 78 // 79 BOOLEAN DiskETWEnabled = FALSE; 80 81 BOOLEAN DiskIsPastReinit = FALSE; 82 83 const GUID GUID_NULL = { 0 }; 84 #define DiskCompareGuid(_First,_Second) \ 85 (memcmp ((_First),(_Second), sizeof (GUID))) 86 87 // 88 // This macro is used to work around a bug in the definition of 89 // DISK_CACHE_RETENTION_PRIORITY. The value KeepReadData should be 90 // assigned 0xf rather than 0x2. Since the interface was already published 91 // when this was discovered the disk driver has been modified to translate 92 // between the interface value and the correct scsi value. 93 // 94 // 0x2 is turned into 0xf 95 // 0xf is turned into 0x2 - this ensures that future SCSI defintions can be 96 // accomodated. 97 // 98 99 #define TRANSLATE_RETENTION_PRIORITY(_x)\ 100 ((_x) == 0xf ? 0x2 : \ 101 ((_x) == 0x2 ? 0xf : _x) \ 102 ) 103 104 #define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN CTL_CODE(IOCTL_VOLUME_BASE, 0, METHOD_BUFFERED, FILE_READ_ACCESS) 105 106 VOID 107 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 108 DiskDriverReinit( 109 IN PDRIVER_OBJECT DriverObject, 110 IN PVOID Nothing, 111 IN ULONG Count 112 ) 113 { 114 UNREFERENCED_PARAMETER(DriverObject); 115 UNREFERENCED_PARAMETER(Nothing); 116 UNREFERENCED_PARAMETER(Count); 117 118 DiskIsPastReinit = TRUE; 119 } 120 121 VOID 122 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 123 DiskBootDriverReinit( 124 IN PDRIVER_OBJECT DriverObject, 125 IN PVOID Nothing, 126 IN ULONG Count 127 ) 128 { 129 IoRegisterDriverReinitialization(DriverObject, DiskDriverReinit, NULL); 130 131 #if defined(_X86_) || defined(_AMD64_) 132 133 DiskDriverReinitialization(DriverObject, Nothing, Count); 134 135 #else 136 137 UNREFERENCED_PARAMETER(Nothing); 138 UNREFERENCED_PARAMETER(Count); 139 140 #endif 141 142 } 143 144 NTSTATUS 145 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 146 DriverEntry( 147 IN PDRIVER_OBJECT DriverObject, 148 IN PUNICODE_STRING RegistryPath 149 ) 150 151 /*++ 152 153 Routine Description: 154 155 This routine initializes the SCSI hard disk class driver. 156 157 Arguments: 158 159 DriverObject - Pointer to driver object created by system. 160 161 RegistryPath - Pointer to the name of the services node for this driver. 162 163 Return Value: 164 165 The function value is the final status from the initialization operation. 166 167 --*/ 168 169 { 170 CLASS_INIT_DATA InitializationData = { 0 }; 171 CLASS_QUERY_WMI_REGINFO_EX_LIST classQueryWmiRegInfoExList = { 0 }; 172 GUID guidQueryRegInfoEx = GUID_CLASSPNP_QUERY_REGINFOEX; 173 GUID guidSrbSupport = GUID_CLASSPNP_SRB_SUPPORT; 174 ULONG srbSupport; 175 176 NTSTATUS status; 177 178 // 179 // Initializes tracing 180 // 181 WPP_INIT_TRACING(DriverObject, RegistryPath); 182 183 #if defined(_X86_) || defined(_AMD64_) 184 185 // 186 // Read the information NtDetect squirreled away about the disks in this 187 // system. 188 // 189 190 DiskSaveDetectInfo(DriverObject); 191 192 #endif 193 194 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA); 195 196 // 197 // Setup sizes and entry points for functional device objects 198 // 199 200 InitializationData.FdoData.DeviceExtensionSize = FUNCTIONAL_EXTENSION_SIZE; 201 InitializationData.FdoData.DeviceType = FILE_DEVICE_DISK; 202 InitializationData.FdoData.DeviceCharacteristics = FILE_DEVICE_SECURE_OPEN; 203 204 InitializationData.FdoData.ClassInitDevice = DiskInitFdo; 205 InitializationData.FdoData.ClassStartDevice = DiskStartFdo; 206 InitializationData.FdoData.ClassStopDevice = DiskStopDevice; 207 InitializationData.FdoData.ClassRemoveDevice = DiskRemoveDevice; 208 InitializationData.FdoData.ClassPowerDevice = ClassSpinDownPowerHandler; 209 210 InitializationData.FdoData.ClassError = DiskFdoProcessError; 211 InitializationData.FdoData.ClassReadWriteVerification = DiskReadWriteVerification; 212 InitializationData.FdoData.ClassDeviceControl = DiskDeviceControl; 213 InitializationData.FdoData.ClassShutdownFlush = DiskShutdownFlush; 214 InitializationData.FdoData.ClassCreateClose = NULL; 215 216 217 InitializationData.FdoData.ClassWmiInfo.GuidCount = 7; 218 InitializationData.FdoData.ClassWmiInfo.GuidRegInfo = DiskWmiFdoGuidList; 219 InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiRegInfo = DiskFdoQueryWmiRegInfo; 220 InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiDataBlock = DiskFdoQueryWmiDataBlock; 221 InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataBlock = DiskFdoSetWmiDataBlock; 222 InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataItem = DiskFdoSetWmiDataItem; 223 InitializationData.FdoData.ClassWmiInfo.ClassExecuteWmiMethod = DiskFdoExecuteWmiMethod; 224 InitializationData.FdoData.ClassWmiInfo.ClassWmiFunctionControl = DiskWmiFunctionControl; 225 226 InitializationData.ClassAddDevice = DiskAddDevice; 227 InitializationData.ClassUnload = DiskUnload; 228 229 // 230 // Initialize regregistration data structures 231 // 232 233 DiskInitializeReregistration(); 234 235 // 236 // Call the class init routine 237 // 238 239 status = ClassInitialize(DriverObject, RegistryPath, &InitializationData); 240 241 if (NT_SUCCESS(status)) { 242 243 IoRegisterBootDriverReinitialization(DriverObject, 244 DiskBootDriverReinit, 245 NULL); 246 } 247 248 // 249 // Call class init Ex routine to register a 250 // PCLASS_QUERY_WMI_REGINFO_EX routine 251 // 252 253 classQueryWmiRegInfoExList.Size = sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST); 254 classQueryWmiRegInfoExList.ClassFdoQueryWmiRegInfoEx = DiskFdoQueryWmiRegInfoEx; 255 256 (VOID)ClassInitializeEx(DriverObject, 257 &guidQueryRegInfoEx, 258 &classQueryWmiRegInfoExList); 259 260 // 261 // Call class init Ex routine to register SRB support 262 // 263 srbSupport = CLASS_SRB_SCSI_REQUEST_BLOCK | CLASS_SRB_STORAGE_REQUEST_BLOCK; 264 if (!NT_SUCCESS(ClassInitializeEx(DriverObject, 265 &guidSrbSupport, 266 &srbSupport))) { 267 // 268 // Should not fail 269 // 270 NT_ASSERT(FALSE); 271 } 272 273 274 return status; 275 276 } // end DriverEntry() 277 278 279 VOID 280 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 281 DiskUnload( 282 IN PDRIVER_OBJECT DriverObject 283 ) 284 { 285 PAGED_CODE(); 286 287 #if defined(_X86_) || defined(_AMD64_) 288 DiskCleanupDetectInfo(DriverObject); 289 #else 290 // NB: Need to use UNREFERENCED_PARAMETER to prevent build error 291 // DriverObject is not referenced below in WPP_CLEANUP. 292 // WPP_CLEANUP is currently an "NOOP" marco. 293 UNREFERENCED_PARAMETER(DriverObject); 294 #endif 295 296 297 // 298 // Cleans up tracing 299 // 300 WPP_CLEANUP(DriverObject); 301 302 return; 303 } 304 305 306 NTSTATUS 307 DiskCreateFdo( 308 IN PDRIVER_OBJECT DriverObject, 309 IN PDEVICE_OBJECT PhysicalDeviceObject, 310 IN PULONG DeviceCount, 311 IN BOOLEAN DasdAccessOnly 312 ) 313 314 /*++ 315 316 Routine Description: 317 318 This routine creates an object for the functional device 319 320 Arguments: 321 322 DriverObject - Pointer to driver object created by system. 323 324 PhysicalDeviceObject - Lower level driver we should attach to 325 326 DeviceCount - Number of previously installed devices. 327 328 DasdAccessOnly - indicates whether or not a file system is allowed to mount 329 on this device object. Used to avoid double-mounting of 330 file systems on super-floppies (which can unfortunately be 331 fixed disks). If set the i/o system will only allow rawfs 332 to be mounted. 333 334 Return Value: 335 336 NTSTATUS 337 338 --*/ 339 340 { 341 PCCHAR deviceName = NULL; 342 HANDLE handle = NULL; 343 PDEVICE_OBJECT lowerDevice = NULL; 344 PDEVICE_OBJECT deviceObject = NULL; 345 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 346 NTSTATUS status; 347 348 PAGED_CODE(); 349 350 *DeviceCount = 0; 351 352 // 353 // Set up an object directory to contain the objects for this 354 // device and all its partitions. 355 // 356 357 do { 358 359 WCHAR dirBuffer[64] = { 0 }; 360 UNICODE_STRING dirName; 361 OBJECT_ATTRIBUTES objectAttribs; 362 363 status = RtlStringCchPrintfW(dirBuffer, sizeof(dirBuffer) / sizeof(dirBuffer[0]) - 1, L"\\Device\\Harddisk%d", *DeviceCount); 364 if (!NT_SUCCESS(status)) { 365 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo: Format symbolic link failed with error: 0x%X\n", status)); 366 return status; 367 } 368 369 RtlInitUnicodeString(&dirName, dirBuffer); 370 371 InitializeObjectAttributes(&objectAttribs, 372 &dirName, 373 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE, 374 NULL, 375 NULL); 376 377 status = ZwCreateDirectoryObject(&handle, 378 DIRECTORY_ALL_ACCESS, 379 &objectAttribs); 380 381 (*DeviceCount)++; 382 383 } while((status == STATUS_OBJECT_NAME_COLLISION) || 384 (status == STATUS_OBJECT_NAME_EXISTS)); 385 386 if (!NT_SUCCESS(status)) { 387 388 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo: Could not create directory - %lx\n", status)); 389 390 return(status); 391 } 392 393 // 394 // When this loop exits the count is inflated by one - fix that. 395 // 396 397 (*DeviceCount)--; 398 399 // 400 // Claim the device. 401 // 402 403 lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject); 404 405 status = ClassClaimDevice(lowerDevice, FALSE); 406 407 if (!NT_SUCCESS(status)) { 408 ZwMakeTemporaryObject(handle); 409 ZwClose(handle); 410 ObDereferenceObject(lowerDevice); 411 return status; 412 } 413 414 // 415 // Create a device object for this device. Each physical disk will 416 // have at least one device object. The required device object 417 // describes the entire device. Its directory path is 418 // \Device\HarddiskN\Partition0, where N = device number. 419 // 420 421 status = DiskGenerateDeviceName(*DeviceCount, &deviceName); 422 423 if(!NT_SUCCESS(status)) { 424 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo - couldn't create name %lx\n", status)); 425 426 goto DiskCreateFdoExit; 427 428 } 429 430 status = ClassCreateDeviceObject(DriverObject, 431 deviceName, 432 PhysicalDeviceObject, 433 TRUE, 434 &deviceObject); 435 436 if (!NT_SUCCESS(status)) { 437 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo: Can not create device object %s\n", deviceName)); 438 goto DiskCreateFdoExit; 439 } 440 441 FREE_POOL(deviceName); 442 443 // 444 // Indicate that IRPs should include MDLs for data transfers. 445 // 446 447 SET_FLAG(deviceObject->Flags, DO_DIRECT_IO); 448 449 fdoExtension = deviceObject->DeviceExtension; 450 451 if(DasdAccessOnly) { 452 453 // 454 // Inidicate that only RAW should be allowed to mount on the root 455 // partition object. This ensures that a file system can't doubly 456 // mount on a super-floppy by mounting once on P0 and once on P1. 457 // 458 459 #ifdef _MSC_VER 460 #pragma prefast(suppress:28175); 461 #endif 462 SET_FLAG(deviceObject->Vpb->Flags, VPB_RAW_MOUNT); 463 } 464 465 // 466 // Initialize lock count to zero. The lock count is used to 467 // disable the ejection mechanism on devices that support 468 // removable media. Only the lock count in the physical 469 // device extension is used. 470 // 471 472 fdoExtension->LockCount = 0; 473 474 // 475 // Save system disk number. 476 // 477 478 fdoExtension->DeviceNumber = *DeviceCount; 479 480 // 481 // Set the alignment requirements for the device based on the 482 // host adapter requirements 483 // 484 485 if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) { 486 deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement; 487 } 488 489 // 490 // Finally, attach to the pdo 491 // 492 493 fdoExtension->LowerPdo = PhysicalDeviceObject; 494 495 fdoExtension->CommonExtension.LowerDeviceObject = 496 IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject); 497 498 499 if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) { 500 501 // 502 // Uh - oh, we couldn't attach 503 // cleanup and return 504 // 505 506 status = STATUS_UNSUCCESSFUL; 507 goto DiskCreateFdoExit; 508 } 509 510 // 511 // Clear the init flag. 512 // 513 514 CLEAR_FLAG(deviceObject->Flags, DO_DEVICE_INITIALIZING); 515 516 // 517 // Store a handle to the device object directory for this disk 518 // 519 520 fdoExtension->DeviceDirectory = handle; 521 522 ObDereferenceObject(lowerDevice); 523 524 return STATUS_SUCCESS; 525 526 DiskCreateFdoExit: 527 528 if (deviceObject != NULL) 529 { 530 IoDeleteDevice(deviceObject); 531 } 532 533 FREE_POOL(deviceName); 534 535 ObDereferenceObject(lowerDevice); 536 537 ZwMakeTemporaryObject(handle); 538 ZwClose(handle); 539 540 return status; 541 } 542 543 544 NTSTATUS 545 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 546 DiskReadWriteVerification( 547 IN PDEVICE_OBJECT DeviceObject, 548 IN PIRP Irp 549 ) 550 551 /*++ 552 553 Routine Description: 554 555 I/O System entry for read and write requests to SCSI disks. 556 557 Arguments: 558 559 DeviceObject - Pointer to driver object created by system. 560 Irp - IRP involved. 561 562 Return Value: 563 564 NT Status 565 566 --*/ 567 568 { 569 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 570 PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); 571 ULONG residualBytes; 572 ULONG residualOffset; 573 NTSTATUS status = STATUS_SUCCESS; 574 575 // 576 // Make sure that the request is within the bounds of the partition, 577 // the number of bytes to transfer and the byte offset are a 578 // multiple of the sector size. 579 // 580 581 residualBytes = irpSp->Parameters.Read.Length & (commonExtension->PartitionZeroExtension->DiskGeometry.BytesPerSector - 1); 582 residualOffset = irpSp->Parameters.Read.ByteOffset.LowPart & (commonExtension->PartitionZeroExtension->DiskGeometry.BytesPerSector - 1); 583 584 if ((irpSp->Parameters.Read.ByteOffset.QuadPart > commonExtension->PartitionLength.QuadPart) || 585 (irpSp->Parameters.Read.ByteOffset.QuadPart < 0) || 586 (residualBytes != 0) || 587 (residualOffset != 0)) 588 { 589 NT_ASSERT(residualOffset == 0); 590 status = STATUS_INVALID_PARAMETER; 591 } 592 else 593 { 594 ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - irpSp->Parameters.Read.ByteOffset.QuadPart; 595 596 if ((ULONGLONG)irpSp->Parameters.Read.Length > bytesRemaining) 597 { 598 status = STATUS_INVALID_PARAMETER; 599 } 600 } 601 602 if (!NT_SUCCESS(status)) 603 { 604 // 605 // This error may be caused by the fact that the drive is not ready. 606 // 607 608 status = ((PDISK_DATA) commonExtension->DriverData)->ReadyStatus; 609 610 if (!NT_SUCCESS(status)) { 611 612 // 613 // Flag this as a user error so that a popup is generated. 614 // 615 616 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DiskReadWriteVerification: ReadyStatus is %lx\n", status)); 617 618 if (IoIsErrorUserInduced(status) && Irp->Tail.Overlay.Thread != NULL) { 619 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 620 } 621 622 // 623 // status will keep the current error 624 // 625 626 } else if ((residualBytes == 0) && (residualOffset == 0)) { 627 628 // 629 // This failed because we think the physical disk is too small. 630 // Send it down to the drive and let the hardware decide for 631 // itself. 632 // 633 634 status = STATUS_SUCCESS; 635 636 } else { 637 638 // 639 // Note fastfat depends on this parameter to determine when to 640 // remount due to a sector size change. 641 // 642 643 status = STATUS_INVALID_PARAMETER; 644 } 645 } 646 647 Irp->IoStatus.Status = status; 648 649 return status; 650 651 } // end DiskReadWrite() 652 653 654 NTSTATUS 655 DiskDetermineMediaTypes( 656 IN PDEVICE_OBJECT Fdo, 657 IN PIRP Irp, 658 IN UCHAR MediumType, 659 IN UCHAR DensityCode, 660 IN BOOLEAN MediaPresent, 661 IN BOOLEAN IsWritable 662 ) 663 664 /*++ 665 666 Routine Description: 667 668 Determines number of types based on the physical device, validates the user buffer 669 and builds the MEDIA_TYPE information. 670 671 Arguments: 672 673 DeviceObject - Pointer to functional device object created by system. 674 Irp - IOCTL_STORAGE_GET_MEDIA_TYPES_EX Irp. 675 MediumType - byte returned in mode data header. 676 DensityCode - byte returned in mode data block descriptor. 677 NumberOfTypes - pointer to be updated based on actual device. 678 679 Return Value: 680 681 Status is returned. 682 683 --*/ 684 685 { 686 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 687 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 688 689 PGET_MEDIA_TYPES mediaTypes = Irp->AssociatedIrp.SystemBuffer; 690 PDEVICE_MEDIA_INFO mediaInfo = &mediaTypes->MediaInfo[0]; 691 BOOLEAN deviceMatched = FALSE; 692 693 PAGED_CODE(); 694 695 // 696 // this should be checked prior to calling into this routine 697 // as we use the buffer as mediaTypes 698 // 699 700 NT_ASSERT(irpStack->Parameters.DeviceIoControl.OutputBufferLength >= 701 sizeof(GET_MEDIA_TYPES)); 702 703 // 704 // Determine if this device is removable or fixed. 705 // 706 707 if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { 708 709 // 710 // Fixed disk. 711 // 712 713 mediaTypes->DeviceType = FILE_DEVICE_DISK; 714 mediaTypes->MediaInfoCount = 1; 715 716 mediaInfo->DeviceSpecific.DiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart; 717 mediaInfo->DeviceSpecific.DiskInfo.MediaType = FixedMedia; 718 mediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder; 719 mediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack; 720 mediaInfo->DeviceSpecific.DiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector; 721 mediaInfo->DeviceSpecific.DiskInfo.NumberMediaSides = 1; 722 mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_WRITE); 723 724 if (!IsWritable) { 725 726 SET_FLAG(mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics, 727 MEDIA_WRITE_PROTECTED); 728 } 729 730 } else { 731 732 PCCHAR vendorId = (PCCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->VendorIdOffset; 733 PCCHAR productId = (PCCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductIdOffset; 734 PCCHAR productRevision = (PCCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductRevisionOffset; 735 DISK_MEDIA_TYPES_LIST const *mediaListEntry; 736 ULONG currentMedia; 737 ULONG i; 738 ULONG j; 739 ULONG sizeNeeded; 740 741 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 742 "DiskDetermineMediaTypes: Vendor %s, Product %s\n", 743 vendorId, 744 productId)); 745 746 747 // 748 // If there's an entry with such vendorId & ProductId in the DiskMediaTypesExclude list, 749 // this device shouldn't be looked up in the DiskMediaTypes list to determine a medium type. 750 // The exclude table allows to narrow down the set of devices described by the DiskMediaTypes 751 // list (e.g.: DiskMediaTypes says "all HP devices" and DiskMediaTypesExlclude says 752 // "except for HP RDX") 753 // 754 755 for (i = 0; DiskMediaTypesExclude[i].VendorId != NULL; i++) { 756 mediaListEntry = &DiskMediaTypesExclude[i]; 757 758 if (strncmp(mediaListEntry->VendorId,vendorId,strlen(mediaListEntry->VendorId))) { 759 continue; 760 } 761 762 if ((mediaListEntry->ProductId != NULL) && 763 strncmp(mediaListEntry->ProductId, productId, strlen(mediaListEntry->ProductId))) { 764 continue; 765 } 766 767 goto SkipTable; 768 } 769 770 // 771 // Run through the list until we find the entry with a NULL Vendor Id. 772 // 773 774 for (i = 0; DiskMediaTypes[i].VendorId != NULL; i++) { 775 776 mediaListEntry = &DiskMediaTypes[i]; 777 778 if (strncmp(mediaListEntry->VendorId,vendorId,strlen(mediaListEntry->VendorId))) { 779 continue; 780 } 781 782 if ((mediaListEntry->ProductId != NULL) && 783 strncmp(mediaListEntry->ProductId, productId, strlen(mediaListEntry->ProductId))) { 784 continue; 785 } 786 787 if ((mediaListEntry->Revision != NULL) && 788 strncmp(mediaListEntry->Revision, productRevision, strlen(mediaListEntry->Revision))) { 789 continue; 790 } 791 792 deviceMatched = TRUE; 793 794 mediaTypes->DeviceType = FILE_DEVICE_DISK; 795 mediaTypes->MediaInfoCount = mediaListEntry->NumberOfTypes; 796 797 // 798 // Ensure that buffer is large enough. 799 // 800 801 sizeNeeded = FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) + 802 (mediaListEntry->NumberOfTypes * 803 sizeof(DEVICE_MEDIA_INFO) 804 ); 805 806 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 807 sizeNeeded) { 808 809 // 810 // Buffer too small 811 // 812 813 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 814 return STATUS_BUFFER_TOO_SMALL; 815 } 816 817 for (j = 0; j < mediaListEntry->NumberOfTypes; j++) { 818 819 mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart; 820 mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder; 821 mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack; 822 mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector; 823 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = mediaListEntry->NumberOfSides; 824 825 // 826 // Set the type. 827 // 828 829 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = mediaListEntry->MediaTypes[j]; 830 831 if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == MO_5_WO) { 832 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_WRITE_ONCE; 833 } else { 834 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE; 835 } 836 837 // 838 // Status will either be success, if media is present, or no media. 839 // It would be optimal to base from density code and medium type, but not all devices 840 // have values for these fields. 841 // 842 843 if (MediaPresent) { 844 845 // 846 // The usage of MediumType and DensityCode is device specific, so this may need 847 // to be extended to further key off of product/vendor ids. 848 // Currently, the MO units are the only devices that return this information. 849 // 850 851 if (MediumType == 2) { 852 currentMedia = MO_5_WO; 853 } else if (MediumType == 3) { 854 currentMedia = MO_5_RW; 855 856 if (DensityCode == 0x87) { 857 858 // 859 // Indicate that the pinnacle 4.6 G media 860 // is present. Other density codes will default to normal 861 // RW MO media. 862 // 863 864 currentMedia = PINNACLE_APEX_5_RW; 865 } 866 } else { 867 currentMedia = 0; 868 } 869 870 if (currentMedia) { 871 if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == (STORAGE_MEDIA_TYPE)currentMedia) { 872 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED); 873 } 874 875 } else { 876 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED); 877 } 878 } 879 880 if (!IsWritable) { 881 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED); 882 } 883 884 // 885 // Advance to next entry. 886 // 887 888 mediaInfo++; 889 } 890 } 891 892 SkipTable: 893 894 if (!deviceMatched) { 895 896 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 897 "DiskDetermineMediaTypes: Unknown device. Vendor: %s Product: %s Revision: %s\n", 898 vendorId, 899 productId, 900 productRevision)); 901 // 902 // Build an entry for unknown. 903 // 904 905 mediaTypes->DeviceType = FILE_DEVICE_DISK; 906 mediaTypes->MediaInfoCount = 1; 907 908 mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart; 909 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = RemovableMedia; 910 mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder; 911 mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack; 912 mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector; 913 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1; 914 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE; 915 916 if (MediaPresent) { 917 918 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED); 919 } 920 921 if (!IsWritable) { 922 923 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED); 924 } 925 } 926 } 927 928 Irp->IoStatus.Information = 929 FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) + 930 (mediaTypes->MediaInfoCount * sizeof(DEVICE_MEDIA_INFO)); 931 932 return STATUS_SUCCESS; 933 } 934 935 NTSTATUS 936 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 937 DiskDeviceControl( 938 PDEVICE_OBJECT DeviceObject, 939 PIRP Irp 940 ) 941 942 /*++ 943 944 Routine Description: 945 946 I/O system entry for device controls to SCSI disks. 947 948 Arguments: 949 950 Fdo - Pointer to functional device object created by system. 951 Irp - IRP involved. 952 953 Return Value: 954 955 Status is returned. 956 957 --*/ 958 959 { 960 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 961 NTSTATUS status = STATUS_SUCCESS; 962 ULONG ioctlCode; 963 964 NT_ASSERT(DeviceObject != NULL); 965 966 Irp->IoStatus.Information = 0; 967 ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; 968 969 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DiskDeviceControl: Received IOCTL 0x%X for device %p through IRP %p\n", 970 ioctlCode, DeviceObject, Irp)); 971 972 973 switch (ioctlCode) { 974 975 case IOCTL_DISK_GET_CACHE_INFORMATION: { 976 status = DiskIoctlGetCacheInformation(DeviceObject, Irp); 977 break; 978 } 979 980 case IOCTL_DISK_SET_CACHE_INFORMATION: { 981 status = DiskIoctlSetCacheInformation(DeviceObject, Irp); 982 break; 983 } 984 985 case IOCTL_DISK_GET_CACHE_SETTING: { 986 status = DiskIoctlGetCacheSetting(DeviceObject, Irp); 987 break; 988 } 989 990 case IOCTL_DISK_SET_CACHE_SETTING: { 991 status = DiskIoctlSetCacheSetting(DeviceObject, Irp); 992 break; 993 } 994 995 case IOCTL_DISK_GET_DRIVE_GEOMETRY: { 996 status = DiskIoctlGetDriveGeometry(DeviceObject, Irp); 997 break; 998 } 999 1000 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: { 1001 status = DiskIoctlGetDriveGeometryEx( DeviceObject, Irp ); 1002 break; 1003 } 1004 1005 case IOCTL_DISK_VERIFY: { 1006 status = DiskIoctlVerify(DeviceObject, Irp); 1007 break; 1008 } 1009 1010 case IOCTL_DISK_GET_LENGTH_INFO: { 1011 status = DiskIoctlGetLengthInfo(DeviceObject, Irp); 1012 break; 1013 } 1014 1015 case IOCTL_DISK_IS_WRITABLE: { 1016 status = DiskIoctlIsWritable(DeviceObject, Irp); 1017 break; 1018 } 1019 1020 case IOCTL_DISK_UPDATE_DRIVE_SIZE: { 1021 status = DiskIoctlUpdateDriveSize(DeviceObject, Irp); 1022 break; 1023 } 1024 1025 case IOCTL_DISK_REASSIGN_BLOCKS: { 1026 status = DiskIoctlReassignBlocks(DeviceObject, Irp); 1027 break; 1028 } 1029 1030 case IOCTL_DISK_REASSIGN_BLOCKS_EX: { 1031 status = DiskIoctlReassignBlocksEx(DeviceObject, Irp); 1032 break; 1033 } 1034 1035 case IOCTL_DISK_INTERNAL_SET_VERIFY: { 1036 status = DiskIoctlSetVerify(DeviceObject, Irp); 1037 break; 1038 } 1039 1040 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY: { 1041 status = DiskIoctlClearVerify(DeviceObject, Irp); 1042 break; 1043 } 1044 1045 case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: { 1046 status = DiskIoctlGetMediaTypesEx(DeviceObject, Irp); 1047 break; 1048 } 1049 1050 case IOCTL_STORAGE_PREDICT_FAILURE : { 1051 status = DiskIoctlPredictFailure(DeviceObject, Irp); 1052 break; 1053 } 1054 1055 #if (NTDDI_VERSION >= NTDDI_WINBLUE) 1056 case IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG : { 1057 status = DiskIoctlEnableFailurePrediction(DeviceObject, Irp); 1058 break; 1059 } 1060 #endif 1061 1062 case SMART_GET_VERSION: { 1063 status = DiskIoctlSmartGetVersion(DeviceObject, Irp); 1064 break; 1065 } 1066 1067 case SMART_RCV_DRIVE_DATA: { 1068 status = DiskIoctlSmartReceiveDriveData(DeviceObject, Irp); 1069 break; 1070 } 1071 1072 case SMART_SEND_DRIVE_COMMAND: { 1073 status = DiskIoctlSmartSendDriveCommand(DeviceObject, Irp); 1074 break; 1075 } 1076 1077 case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS: 1078 case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN: { 1079 status = DiskIoctlGetVolumeDiskExtents(DeviceObject, Irp); 1080 break; 1081 } 1082 1083 default: { 1084 1085 // 1086 // Pass the request to the common device control routine. 1087 // 1088 return(ClassDeviceControl(DeviceObject, Irp)); 1089 break; 1090 } 1091 } // end switch 1092 1093 if (!NT_SUCCESS(status)) { 1094 1095 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskDeviceControl: IOCTL 0x%X to device %p failed with error 0x%X\n", 1096 ioctlCode, DeviceObject, status)); 1097 if (IoIsErrorUserInduced(status) && 1098 (Irp->Tail.Overlay.Thread != NULL)) { 1099 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 1100 } 1101 } 1102 1103 // 1104 // DiskIoctlVerify() (IOCTL_DISK_VERIFY) function returns STATUS_PENDING 1105 // and completes the IRP in the work item. Do not touch or complete 1106 // the IRP if STATUS_PENDING is returned. 1107 // 1108 1109 if (status != STATUS_PENDING) { 1110 1111 1112 Irp->IoStatus.Status = status; 1113 ClassReleaseRemoveLock(DeviceObject, Irp); 1114 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 1115 } 1116 1117 return(status); 1118 } // end DiskDeviceControl() 1119 1120 NTSTATUS 1121 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 1122 DiskShutdownFlush( 1123 IN PDEVICE_OBJECT DeviceObject, 1124 IN PIRP Irp 1125 ) 1126 1127 /*++ 1128 1129 Routine Description: 1130 1131 This routine is the handler for shutdown and flush requests. It sends 1132 down a synch cache command to the device if its cache is enabled. If 1133 the request is a shutdown and the media is removable, it sends down 1134 an unlock request 1135 1136 Finally, an SRB_FUNCTION_SHUTDOWN or SRB_FUNCTION_FLUSH is sent down 1137 the stack 1138 1139 Arguments: 1140 1141 DeviceObject - The device object processing the request 1142 Irp - The shutdown | flush request being serviced 1143 1144 Return Value: 1145 1146 STATUS_PENDING if successful, an error code otherwise 1147 1148 --*/ 1149 1150 { 1151 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 1152 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = commonExtension->PartitionZeroExtension; 1153 PDISK_DATA diskData = (PDISK_DATA) commonExtension->DriverData; 1154 PIO_STACK_LOCATION irpStack; 1155 NTSTATUS status = STATUS_SUCCESS; 1156 ULONG srbSize; 1157 PSCSI_REQUEST_BLOCK srb; 1158 PSTORAGE_REQUEST_BLOCK srbEx = NULL; 1159 PSTOR_ADDR_BTL8 storAddrBtl8 = NULL; 1160 PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL; 1161 PCDB cdb; 1162 KIRQL irql; 1163 1164 // 1165 // Flush requests are combined and need to be handled in a special manner 1166 // 1167 1168 irpStack = IoGetCurrentIrpStackLocation(Irp); 1169 1170 if (irpStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS) { 1171 1172 if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED)) { 1173 1174 // 1175 // We've been assured that both the disk 1176 // and adapter caches are battery-backed 1177 // 1178 1179 Irp->IoStatus.Status = STATUS_SUCCESS; 1180 ClassReleaseRemoveLock(DeviceObject, Irp); 1181 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 1182 return STATUS_SUCCESS; 1183 } 1184 1185 KeAcquireSpinLock(&diskData->FlushContext.Spinlock, &irql); 1186 1187 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskShutdownFlush: IRP %p flags = 0x%x\n", Irp, irpStack->Flags)); 1188 1189 // 1190 // This request will most likely be completed asynchronously 1191 // 1192 IoMarkIrpPending(Irp); 1193 1194 // 1195 // Look to see if a flush is in progress 1196 // 1197 1198 if (diskData->FlushContext.CurrIrp != NULL) { 1199 1200 // 1201 // There is an outstanding flush. Queue this 1202 // request to the group that is next in line 1203 // 1204 1205 if (diskData->FlushContext.NextIrp != NULL) { 1206 1207 #if DBG 1208 diskData->FlushContext.DbgTagCount++; 1209 #endif 1210 1211 InsertTailList(&diskData->FlushContext.NextList, &Irp->Tail.Overlay.ListEntry); 1212 1213 KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql); 1214 1215 // 1216 // This request will be completed by its representative 1217 // 1218 1219 } else { 1220 1221 #if DBG 1222 if (diskData->FlushContext.DbgTagCount < 64) { 1223 1224 diskData->FlushContext.DbgRefCount[diskData->FlushContext.DbgTagCount]++; 1225 } 1226 1227 diskData->FlushContext.DbgSavCount += diskData->FlushContext.DbgTagCount; 1228 diskData->FlushContext.DbgTagCount = 0; 1229 #endif 1230 1231 diskData->FlushContext.NextIrp = Irp; 1232 NT_ASSERT(IsListEmpty(&diskData->FlushContext.NextList)); 1233 1234 1235 KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql); 1236 1237 1238 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskShutdownFlush: waiting for event\n")); 1239 1240 // 1241 // Wait for the outstanding flush to complete 1242 // 1243 KeWaitForSingleObject(&diskData->FlushContext.Event, Executive, KernelMode, FALSE, NULL); 1244 1245 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskShutdownFlush: event signal\n")); 1246 1247 // 1248 // Make this group the outstanding one and free up the next slot 1249 // 1250 1251 KeAcquireSpinLock(&diskData->FlushContext.Spinlock, &irql); 1252 1253 NT_ASSERT(IsListEmpty(&diskData->FlushContext.CurrList)); 1254 1255 while (!IsListEmpty(&diskData->FlushContext.NextList)) { 1256 1257 PLIST_ENTRY listEntry = RemoveHeadList(&diskData->FlushContext.NextList); 1258 InsertTailList(&diskData->FlushContext.CurrList, listEntry); 1259 } 1260 1261 #ifndef __REACTOS__ 1262 // ReactOS hits this assert, because CurrIrp can already be freed at this point 1263 // and it's possible that NextIrp has the same pointer value 1264 NT_ASSERT(diskData->FlushContext.CurrIrp != diskData->FlushContext.NextIrp); 1265 #endif 1266 diskData->FlushContext.CurrIrp = diskData->FlushContext.NextIrp; 1267 diskData->FlushContext.NextIrp = NULL; 1268 1269 KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql); 1270 1271 // 1272 // Send this request down to the device 1273 // 1274 DiskFlushDispatch(DeviceObject, &diskData->FlushContext); 1275 } 1276 1277 } else { 1278 1279 diskData->FlushContext.CurrIrp = Irp; 1280 NT_ASSERT(IsListEmpty(&diskData->FlushContext.CurrList)); 1281 1282 NT_ASSERT(diskData->FlushContext.NextIrp == NULL); 1283 NT_ASSERT(IsListEmpty(&diskData->FlushContext.NextList)); 1284 1285 1286 KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql); 1287 1288 DiskFlushDispatch(DeviceObject, &diskData->FlushContext); 1289 } 1290 1291 } else { 1292 1293 // 1294 // Allocate SCSI request block. 1295 // 1296 1297 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1298 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; 1299 } else { 1300 srbSize = sizeof(SCSI_REQUEST_BLOCK); 1301 } 1302 1303 srb = ExAllocatePoolWithTag(NonPagedPoolNx, 1304 srbSize, 1305 DISK_TAG_SRB); 1306 if (srb == NULL) { 1307 1308 // 1309 // Set the status and complete the request. 1310 // 1311 1312 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 1313 ClassReleaseRemoveLock(DeviceObject, Irp); 1314 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 1315 return(STATUS_INSUFFICIENT_RESOURCES); 1316 } 1317 1318 RtlZeroMemory(srb, srbSize); 1319 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1320 1321 srbEx = (PSTORAGE_REQUEST_BLOCK)srb; 1322 1323 // 1324 // Set up STORAGE_REQUEST_BLOCK fields 1325 // 1326 1327 srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); 1328 srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; 1329 srbEx->Signature = SRB_SIGNATURE; 1330 srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; 1331 srbEx->SrbLength = srbSize; 1332 srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 1333 srbEx->RequestPriority = IoGetIoPriorityHint(Irp); 1334 srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); 1335 srbEx->NumSrbExData = 1; 1336 1337 // Set timeout value and mark the request as not being a tagged request. 1338 srbEx->TimeOutValue = fdoExtension->TimeOutValue * 4; 1339 srbEx->RequestTag = SP_UNTAGGED; 1340 srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST; 1341 srbEx->SrbFlags = fdoExtension->SrbFlags; 1342 1343 // 1344 // Set up address fields 1345 // 1346 1347 storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); 1348 storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; 1349 storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; 1350 1351 // 1352 // Set up SCSI SRB extended data fields 1353 // 1354 1355 srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + 1356 sizeof(STOR_ADDR_BTL8); 1357 if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { 1358 srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); 1359 srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; 1360 srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; 1361 1362 cdb = (PCDB)srbExDataCdb16->Cdb; 1363 } else { 1364 // Should not happen 1365 NT_ASSERT(FALSE); 1366 1367 // 1368 // Set the status and complete the request. 1369 // 1370 1371 Irp->IoStatus.Status = STATUS_INTERNAL_ERROR; 1372 ClassReleaseRemoveLock(DeviceObject, Irp); 1373 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 1374 return(STATUS_INTERNAL_ERROR); 1375 } 1376 1377 } else { 1378 1379 // 1380 // Write length to SRB. 1381 // 1382 1383 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 1384 1385 // 1386 // Set timeout value and mark the request as not being a tagged request. 1387 // 1388 1389 srb->TimeOutValue = fdoExtension->TimeOutValue * 4; 1390 srb->QueueTag = SP_UNTAGGED; 1391 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 1392 srb->SrbFlags = fdoExtension->SrbFlags; 1393 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 1394 1395 cdb = (PCDB)srb->Cdb; 1396 } 1397 1398 // 1399 // If the write cache is enabled then send a synchronize cache request. 1400 // 1401 1402 if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE)) { 1403 1404 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1405 srbExDataCdb16->CdbLength = 10; 1406 } else { 1407 srb->CdbLength = 10; 1408 } 1409 1410 cdb->CDB10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE; 1411 1412 status = ClassSendSrbSynchronous(DeviceObject, 1413 srb, 1414 NULL, 1415 0, 1416 TRUE); 1417 1418 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status)); 1419 } 1420 1421 // 1422 // Unlock the device if it contains removable media 1423 // 1424 1425 if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) 1426 { 1427 1428 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1429 1430 // 1431 // Reinitialize status fields to 0 in case there was a previous request 1432 // 1433 1434 srbEx->SrbStatus = 0; 1435 srbExDataCdb16->ScsiStatus = 0; 1436 1437 srbExDataCdb16->CdbLength = 6; 1438 1439 // 1440 // Set timeout value 1441 // 1442 1443 srbEx->TimeOutValue = fdoExtension->TimeOutValue; 1444 1445 } else { 1446 1447 // 1448 // Reinitialize status fields to 0 in case there was a previous request 1449 // 1450 1451 srb->SrbStatus = 0; 1452 srb->ScsiStatus = 0; 1453 1454 srb->CdbLength = 6; 1455 1456 // 1457 // Set timeout value. 1458 // 1459 1460 srb->TimeOutValue = fdoExtension->TimeOutValue; 1461 } 1462 1463 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; 1464 cdb->MEDIA_REMOVAL.Prevent = FALSE; 1465 1466 status = ClassSendSrbSynchronous(DeviceObject, 1467 srb, 1468 NULL, 1469 0, 1470 TRUE); 1471 1472 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskShutdownFlush: Unlock device request sent. Status = %lx\n", status)); 1473 } 1474 1475 // 1476 // Set up a SHUTDOWN SRB 1477 // 1478 1479 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1480 srbEx->NumSrbExData = 0; 1481 srbEx->SrbExDataOffset[0] = 0; 1482 srbEx->SrbFunction = SRB_FUNCTION_SHUTDOWN; 1483 srbEx->OriginalRequest = Irp; 1484 srbEx->SrbLength = CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE; 1485 srbEx->SrbStatus = 0; 1486 } else { 1487 srb->CdbLength = 0; 1488 srb->Function = SRB_FUNCTION_SHUTDOWN; 1489 srb->SrbStatus = 0; 1490 srb->OriginalRequest = Irp; 1491 } 1492 1493 // 1494 // Set the retry count to zero. 1495 // 1496 1497 irpStack->Parameters.Others.Argument4 = (PVOID) 0; 1498 1499 // 1500 // Set up IoCompletion routine address. 1501 // 1502 1503 IoSetCompletionRoutine(Irp, ClassIoComplete, srb, TRUE, TRUE, TRUE); 1504 1505 // 1506 // Get next stack location and 1507 // set major function code. 1508 // 1509 1510 irpStack = IoGetNextIrpStackLocation(Irp); 1511 1512 irpStack->MajorFunction = IRP_MJ_SCSI; 1513 1514 // 1515 // Set up SRB for execute scsi request. 1516 // Save SRB address in next stack for port driver. 1517 // 1518 1519 irpStack->Parameters.Scsi.Srb = srb; 1520 1521 // 1522 // Call the port driver to process the request. 1523 // 1524 1525 IoMarkIrpPending(Irp); 1526 IoCallDriver(commonExtension->LowerDeviceObject, Irp); 1527 } 1528 1529 return STATUS_PENDING; 1530 } 1531 1532 1533 VOID 1534 DiskFlushDispatch( 1535 IN PDEVICE_OBJECT Fdo, 1536 IN PDISK_GROUP_CONTEXT FlushContext 1537 ) 1538 1539 /*++ 1540 1541 Routine Description: 1542 1543 This routine is the handler for flush requests. It sends down a synch 1544 cache command to the device if its cache is enabled. This is followed 1545 by an SRB_FUNCTION_FLUSH 1546 1547 Arguments: 1548 1549 Fdo - The device object processing the flush request 1550 FlushContext - The flush group context 1551 1552 Return Value: 1553 1554 None 1555 1556 --*/ 1557 1558 { 1559 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 1560 PSCSI_REQUEST_BLOCK srb = &FlushContext->Srb.Srb; 1561 PSTORAGE_REQUEST_BLOCK srbEx = &FlushContext->Srb.SrbEx; 1562 PIO_STACK_LOCATION irpSp = NULL; 1563 PSTOR_ADDR_BTL8 storAddrBtl8; 1564 PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16; 1565 NTSTATUS SyncCacheStatus = STATUS_SUCCESS; 1566 1567 // 1568 // Fill in the srb fields appropriately 1569 // 1570 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1571 RtlZeroMemory(srbEx, sizeof(FlushContext->Srb.SrbExBuffer)); 1572 1573 srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); 1574 srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; 1575 srbEx->Signature = SRB_SIGNATURE; 1576 srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; 1577 srbEx->SrbLength = sizeof(FlushContext->Srb.SrbExBuffer); 1578 srbEx->RequestPriority = IoGetIoPriorityHint(FlushContext->CurrIrp); 1579 srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); 1580 srbEx->TimeOutValue = fdoExt->TimeOutValue * 4; 1581 srbEx->RequestTag = SP_UNTAGGED; 1582 srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST; 1583 srbEx->SrbFlags = fdoExt->SrbFlags; 1584 1585 // 1586 // Set up address fields 1587 // 1588 1589 storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); 1590 storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; 1591 storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; 1592 1593 } else { 1594 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 1595 1596 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 1597 srb->TimeOutValue = fdoExt->TimeOutValue * 4; 1598 srb->QueueTag = SP_UNTAGGED; 1599 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 1600 srb->SrbFlags = fdoExt->SrbFlags; 1601 } 1602 1603 // 1604 // If write caching is enabled then send down a synchronize cache request 1605 // 1606 if (TEST_FLAG(fdoExt->DeviceFlags, DEV_WRITE_CACHE)) 1607 { 1608 1609 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1610 srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 1611 srbEx->NumSrbExData = 1; 1612 1613 // 1614 // Set up SCSI SRB extended data fields 1615 // 1616 1617 srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + 1618 sizeof(STOR_ADDR_BTL8); 1619 if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { 1620 srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); 1621 srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; 1622 srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; 1623 srbExDataCdb16->CdbLength = 10; 1624 srbExDataCdb16->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE; 1625 } else { 1626 // Should not happen 1627 NT_ASSERT(FALSE); 1628 return; 1629 } 1630 1631 } else { 1632 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 1633 srb->CdbLength = 10; 1634 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE; 1635 } 1636 1637 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending sync cache\n")); 1638 1639 SyncCacheStatus = ClassSendSrbSynchronous(Fdo, srb, NULL, 0, TRUE); 1640 } 1641 1642 // 1643 // Set up a FLUSH SRB 1644 // 1645 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1646 srbEx->SrbFunction = SRB_FUNCTION_FLUSH; 1647 srbEx->NumSrbExData = 0; 1648 srbEx->SrbExDataOffset[0] = 0; 1649 srbEx->OriginalRequest = FlushContext->CurrIrp; 1650 srbEx->SrbStatus = 0; 1651 1652 // 1653 // Make sure that this srb does not get freed 1654 // 1655 SET_FLAG(srbEx->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT); 1656 1657 } else { 1658 srb->Function = SRB_FUNCTION_FLUSH; 1659 srb->CdbLength = 0; 1660 srb->OriginalRequest = FlushContext->CurrIrp; 1661 srb->SrbStatus = 0; 1662 srb->ScsiStatus = 0; 1663 1664 // 1665 // Make sure that this srb does not get freed 1666 // 1667 SET_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT); 1668 } 1669 1670 // 1671 // Make sure that this request does not get retried 1672 // 1673 irpSp = IoGetCurrentIrpStackLocation(FlushContext->CurrIrp); 1674 1675 irpSp->Parameters.Others.Argument4 = (PVOID) 0; 1676 1677 // 1678 // Fill in the irp fields appropriately 1679 // 1680 irpSp = IoGetNextIrpStackLocation(FlushContext->CurrIrp); 1681 1682 irpSp->MajorFunction = IRP_MJ_SCSI; 1683 irpSp->Parameters.Scsi.Srb = srb; 1684 1685 IoSetCompletionRoutine(FlushContext->CurrIrp, DiskFlushComplete, (PVOID)(ULONG_PTR)SyncCacheStatus, TRUE, TRUE, TRUE); 1686 1687 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending srb flush on irp %p\n", FlushContext->CurrIrp)); 1688 1689 // 1690 // Send down the flush request 1691 // 1692 IoCallDriver(((PCOMMON_DEVICE_EXTENSION)fdoExt)->LowerDeviceObject, FlushContext->CurrIrp); 1693 } 1694 1695 1696 1697 NTSTATUS 1698 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 1699 DiskFlushComplete( 1700 IN PDEVICE_OBJECT Fdo, 1701 IN PIRP Irp, 1702 IN PVOID Context 1703 ) 1704 1705 /*++ 1706 1707 Routine Description: 1708 1709 This completion routine is a wrapper around ClassIoComplete. It 1710 will complete all the flush requests that are tagged to it, set 1711 an event to signal the next group to proceed and return 1712 1713 Arguments: 1714 1715 Fdo - The device object which requested the completion routine 1716 Irp - The irp that is being completed 1717 Context - If disk had write cache enabled and SYNC CACHE command was sent as 1st part of FLUSH processing 1718 then context must carry the completion status of SYNC CACHE request, 1719 else context must be set to STATUS_SUCCESS. 1720 1721 Return Value: 1722 1723 STATUS_SUCCESS if successful, an error code otherwise 1724 1725 --*/ 1726 1727 { 1728 PDISK_GROUP_CONTEXT FlushContext; 1729 NTSTATUS status; 1730 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 1731 PDISK_DATA diskData; 1732 #ifdef _MSC_VER 1733 #pragma warning(suppress:4311) // pointer truncation from 'PVOID' to 'NTSTATUS' 1734 #endif 1735 NTSTATUS SyncCacheStatus = (NTSTATUS)(ULONG_PTR)Context; 1736 1737 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DiskFlushComplete: %p %p\n", Fdo, Irp)); 1738 1739 // 1740 // Get the flush context from the device extension 1741 // 1742 fdoExt = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension; 1743 diskData = (PDISK_DATA)fdoExt->CommonExtension.DriverData; 1744 NT_ASSERT(diskData != NULL); 1745 _Analysis_assume_(diskData != NULL); 1746 1747 FlushContext = &diskData->FlushContext; 1748 1749 // 1750 // Make sure everything is in order 1751 // 1752 NT_ASSERT(Irp == FlushContext->CurrIrp); 1753 1754 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushComplete: completing irp %p\n", Irp)); 1755 status = ClassIoComplete(Fdo, Irp, &FlushContext->Srb.Srb); 1756 1757 // 1758 // Make sure that ClassIoComplete did not decide to retry this request 1759 // 1760 NT_ASSERT(status != STATUS_MORE_PROCESSING_REQUIRED); 1761 1762 // 1763 // If sync cache failed earlier, final status of the flush request needs to be failure 1764 // even if SRB_FUNCTION_FLUSH srb request succeeded 1765 // 1766 if (NT_SUCCESS(status) && 1767 (!NT_SUCCESS(SyncCacheStatus))) { 1768 Irp->IoStatus.Status = status = SyncCacheStatus; 1769 } 1770 1771 // 1772 // Complete the flush requests tagged to this one 1773 // 1774 1775 while (!IsListEmpty(&FlushContext->CurrList)) { 1776 1777 PLIST_ENTRY listEntry = RemoveHeadList(&FlushContext->CurrList); 1778 PIRP tempIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry); 1779 1780 InitializeListHead(&tempIrp->Tail.Overlay.ListEntry); 1781 tempIrp->IoStatus = Irp->IoStatus; 1782 1783 ClassReleaseRemoveLock(Fdo, tempIrp); 1784 ClassCompleteRequest(Fdo, tempIrp, IO_NO_INCREMENT); 1785 } 1786 1787 1788 // 1789 // Notify the next group's representative that it may go ahead now 1790 // 1791 KeSetEvent(&FlushContext->Event, IO_NO_INCREMENT, FALSE); 1792 1793 1794 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushComplete: irp %p status = 0x%x\n", Irp, status)); 1795 1796 return status; 1797 } 1798 1799 1800 1801 NTSTATUS 1802 DiskModeSelect( 1803 IN PDEVICE_OBJECT Fdo, 1804 _In_reads_bytes_(Length) PCHAR ModeSelectBuffer, 1805 IN ULONG Length, 1806 IN BOOLEAN SavePage 1807 ) 1808 1809 /*++ 1810 1811 Routine Description: 1812 1813 This routine sends a mode select command. 1814 1815 Arguments: 1816 1817 DeviceObject - Supplies the device object associated with this request. 1818 1819 ModeSelectBuffer - Supplies a buffer containing the page data. 1820 1821 Length - Supplies the length in bytes of the mode select buffer. 1822 1823 SavePage - Indicates that parameters should be written to disk. 1824 1825 Return Value: 1826 1827 Length of the transferred data is returned. 1828 1829 --*/ 1830 1831 { 1832 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 1833 PCDB cdb; 1834 SCSI_REQUEST_BLOCK srb = {0}; 1835 ULONG retries = 1; 1836 ULONG length2; 1837 NTSTATUS status; 1838 PULONG buffer; 1839 PMODE_PARAMETER_BLOCK blockDescriptor; 1840 UCHAR srbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE] = {0}; 1841 PSTORAGE_REQUEST_BLOCK srbEx = (PSTORAGE_REQUEST_BLOCK)srbExBuffer; 1842 PSTOR_ADDR_BTL8 storAddrBtl8; 1843 PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16; 1844 PSCSI_REQUEST_BLOCK srbPtr; 1845 1846 PAGED_CODE(); 1847 1848 // 1849 // Check whether block length is available 1850 // 1851 1852 if (fdoExtension->DiskGeometry.BytesPerSector == 0) { 1853 1854 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskModeSelect: Block length is not available. Unable to send mode select\n")); 1855 NT_ASSERT(fdoExtension->DiskGeometry.BytesPerSector != 0); 1856 return STATUS_INVALID_PARAMETER; 1857 } 1858 1859 1860 1861 length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK); 1862 1863 // 1864 // Allocate buffer for mode select header, block descriptor, and mode page. 1865 // 1866 1867 buffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, 1868 length2, 1869 DISK_TAG_MODE_DATA); 1870 1871 if (buffer == NULL) { 1872 return STATUS_INSUFFICIENT_RESOURCES; 1873 } 1874 1875 RtlZeroMemory(buffer, length2); 1876 1877 // 1878 // Set length in header to size of mode page. 1879 // 1880 1881 ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK); 1882 1883 blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1); 1884 1885 // 1886 // Set block length from the cached disk geometry 1887 // 1888 1889 blockDescriptor->BlockLength[2] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector >> 16); 1890 blockDescriptor->BlockLength[1] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector >> 8); 1891 blockDescriptor->BlockLength[0] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector); 1892 1893 // 1894 // Copy mode page to buffer. 1895 // 1896 1897 RtlCopyMemory(buffer + 3, ModeSelectBuffer, Length); 1898 1899 // 1900 // Build the MODE SELECT CDB. 1901 // 1902 1903 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1904 1905 // 1906 // Set up STORAGE_REQUEST_BLOCK fields 1907 // 1908 1909 srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); 1910 srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; 1911 srbEx->Signature = SRB_SIGNATURE; 1912 srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; 1913 srbEx->SrbLength = sizeof(srbExBuffer); 1914 srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 1915 srbEx->RequestPriority = IoPriorityNormal; 1916 srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); 1917 srbEx->NumSrbExData = 1; 1918 1919 // Set timeout value from device extension. 1920 srbEx->TimeOutValue = fdoExtension->TimeOutValue * 2; 1921 1922 // 1923 // Set up address fields 1924 // 1925 1926 storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); 1927 storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; 1928 storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; 1929 1930 // 1931 // Set up SCSI SRB extended data fields 1932 // 1933 1934 srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + 1935 sizeof(STOR_ADDR_BTL8); 1936 if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { 1937 srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); 1938 srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; 1939 srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; 1940 srbExDataCdb16->CdbLength = 6; 1941 1942 cdb = (PCDB)srbExDataCdb16->Cdb; 1943 } else { 1944 // Should not happen 1945 NT_ASSERT(FALSE); 1946 1947 FREE_POOL(buffer); 1948 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskModeSelect: Insufficient extended SRB size\n")); 1949 return STATUS_INTERNAL_ERROR; 1950 } 1951 1952 srbPtr = (PSCSI_REQUEST_BLOCK)srbEx; 1953 1954 } else { 1955 1956 srb.CdbLength = 6; 1957 cdb = (PCDB)srb.Cdb; 1958 1959 // 1960 // Set timeout value from device extension. 1961 // 1962 1963 srb.TimeOutValue = fdoExtension->TimeOutValue * 2; 1964 1965 srbPtr = &srb; 1966 } 1967 1968 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; 1969 cdb->MODE_SELECT.SPBit = SavePage; 1970 cdb->MODE_SELECT.PFBit = 1; 1971 cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2); 1972 1973 Retry: 1974 1975 status = ClassSendSrbSynchronous(Fdo, 1976 srbPtr, 1977 buffer, 1978 length2, 1979 TRUE); 1980 1981 if (status == STATUS_VERIFY_REQUIRED) { 1982 1983 // 1984 // Routine ClassSendSrbSynchronous does not retry requests returned with 1985 // this status. 1986 // 1987 1988 if (retries--) { 1989 1990 // 1991 // Retry request. 1992 // 1993 1994 goto Retry; 1995 } 1996 1997 } else if (SRB_STATUS(srbPtr->SrbStatus) == SRB_STATUS_DATA_OVERRUN) { 1998 status = STATUS_SUCCESS; 1999 } 2000 2001 FREE_POOL(buffer); 2002 2003 return status; 2004 } // end DiskModeSelect() 2005 2006 2007 // 2008 // This routine is structured as a work-item routine 2009 // 2010 VOID 2011 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2012 DisableWriteCache( 2013 IN PDEVICE_OBJECT Fdo, 2014 IN PVOID Context 2015 ) 2016 2017 { 2018 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension; 2019 DISK_CACHE_INFORMATION cacheInfo = { 0 }; 2020 NTSTATUS status; 2021 PIO_WORKITEM WorkItem = (PIO_WORKITEM)Context; 2022 2023 PAGED_CODE(); 2024 2025 NT_ASSERT(WorkItem != NULL); 2026 _Analysis_assume_(WorkItem != NULL); 2027 2028 status = DiskGetCacheInformation(fdoExtension, &cacheInfo); 2029 2030 if (NT_SUCCESS(status) && (cacheInfo.WriteCacheEnabled == TRUE)) { 2031 2032 cacheInfo.WriteCacheEnabled = FALSE; 2033 2034 DiskSetCacheInformation(fdoExtension, &cacheInfo); 2035 } 2036 2037 IoFreeWorkItem(WorkItem); 2038 } 2039 2040 2041 // 2042 // This routine is structured as a work-item routine 2043 // 2044 VOID 2045 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2046 DiskIoctlVerifyThread( 2047 IN PDEVICE_OBJECT Fdo, 2048 IN PVOID Context 2049 ) 2050 { 2051 PDISK_VERIFY_WORKITEM_CONTEXT WorkContext = (PDISK_VERIFY_WORKITEM_CONTEXT)Context; 2052 PIRP Irp = NULL; 2053 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension; 2054 PDISK_DATA DiskData = (PDISK_DATA)FdoExtension->CommonExtension.DriverData; 2055 PVERIFY_INFORMATION verifyInfo = NULL; 2056 PSCSI_REQUEST_BLOCK Srb = NULL; 2057 PCDB Cdb = NULL; 2058 LARGE_INTEGER byteOffset; 2059 LARGE_INTEGER sectorOffset; 2060 ULONG sectorCount; 2061 NTSTATUS status = STATUS_SUCCESS; 2062 PSTORAGE_REQUEST_BLOCK srbEx = NULL; 2063 PSTOR_ADDR_BTL8 storAddrBtl8 = NULL; 2064 PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL; 2065 2066 PAGED_CODE(); 2067 2068 NT_ASSERT(WorkContext != NULL); 2069 _Analysis_assume_(WorkContext != NULL); 2070 2071 Srb = WorkContext->Srb; 2072 Irp = WorkContext->Irp; 2073 verifyInfo = (PVERIFY_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 2074 2075 // 2076 // We don't need to hold on to this memory as 2077 // the following operation may take some time 2078 // 2079 2080 IoFreeWorkItem(WorkContext->WorkItem); 2081 2082 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlVerifyThread: Spliting up the request\n")); 2083 2084 // 2085 // Add disk offset to starting the sector 2086 // 2087 2088 byteOffset.QuadPart = FdoExtension->CommonExtension.StartingOffset.QuadPart + 2089 verifyInfo->StartingOffset.QuadPart; 2090 2091 // 2092 // Convert byte offset to the sector offset 2093 // 2094 2095 sectorOffset.QuadPart = byteOffset.QuadPart >> FdoExtension->SectorShift; 2096 2097 // 2098 // Convert byte count to sector count. 2099 // 2100 2101 sectorCount = verifyInfo->Length >> FdoExtension->SectorShift; 2102 2103 // 2104 // Make sure that all previous verify requests have indeed completed 2105 // This greatly reduces the possibility of a Denial-of-Service attack 2106 // 2107 2108 KeWaitForMutexObject(&DiskData->VerifyMutex, 2109 Executive, 2110 KernelMode, 2111 FALSE, 2112 NULL); 2113 2114 // 2115 // Initialize SCSI SRB for a verify CDB 2116 // 2117 if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 2118 RtlZeroMemory(Srb, CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE); 2119 srbEx = (PSTORAGE_REQUEST_BLOCK)Srb; 2120 2121 // 2122 // Set up STORAGE_REQUEST_BLOCK fields 2123 // 2124 2125 srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); 2126 srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; 2127 srbEx->Signature = SRB_SIGNATURE; 2128 srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; 2129 srbEx->SrbLength = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; 2130 srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 2131 srbEx->RequestPriority = IoGetIoPriorityHint(Irp); 2132 srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); 2133 srbEx->NumSrbExData = 1; 2134 2135 // 2136 // Set up address fields 2137 // 2138 2139 storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); 2140 storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; 2141 storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; 2142 2143 // 2144 // Set up SCSI SRB extended data fields 2145 // 2146 2147 srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + 2148 sizeof(STOR_ADDR_BTL8); 2149 if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { 2150 srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); 2151 srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; 2152 srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; 2153 2154 Cdb = (PCDB)srbExDataCdb16->Cdb; 2155 if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) { 2156 srbExDataCdb16->CdbLength = 16; 2157 Cdb->CDB16.OperationCode = SCSIOP_VERIFY16; 2158 } else { 2159 srbExDataCdb16->CdbLength = 10; 2160 Cdb->CDB10.OperationCode = SCSIOP_VERIFY; 2161 } 2162 } else { 2163 // Should not happen 2164 NT_ASSERT(FALSE); 2165 2166 FREE_POOL(Srb); 2167 FREE_POOL(WorkContext); 2168 status = STATUS_INTERNAL_ERROR; 2169 } 2170 2171 } else { 2172 RtlZeroMemory(Srb, SCSI_REQUEST_BLOCK_SIZE); 2173 2174 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); 2175 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 2176 2177 Cdb = (PCDB)Srb->Cdb; 2178 if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) { 2179 Srb->CdbLength = 16; 2180 Cdb->CDB16.OperationCode = SCSIOP_VERIFY16; 2181 } else { 2182 Srb->CdbLength = 10; 2183 Cdb->CDB10.OperationCode = SCSIOP_VERIFY; 2184 } 2185 2186 } 2187 2188 while (NT_SUCCESS(status) && (sectorCount != 0)) { 2189 2190 USHORT numSectors = (USHORT) min(sectorCount, MAX_SECTORS_PER_VERIFY); 2191 2192 if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 2193 2194 // 2195 // Reset status fields 2196 // 2197 2198 srbEx->SrbStatus = 0; 2199 srbExDataCdb16->ScsiStatus = 0; 2200 2201 // 2202 // Calculate the request timeout value based 2203 // on the number of sectors being verified 2204 // 2205 2206 srbEx->TimeOutValue = ((numSectors + 0x7F) >> 7) * FdoExtension->TimeOutValue; 2207 } else { 2208 2209 // 2210 // Reset status fields 2211 // 2212 2213 Srb->SrbStatus = 0; 2214 Srb->ScsiStatus = 0; 2215 2216 // 2217 // Calculate the request timeout value based 2218 // on the number of sectors being verified 2219 // 2220 2221 Srb->TimeOutValue = ((numSectors + 0x7F) >> 7) * FdoExtension->TimeOutValue; 2222 } 2223 2224 // 2225 // Update verify CDB info. 2226 // NOTE - CDB opcode and length has been initialized prior to entering 2227 // the while loop 2228 // 2229 2230 if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) { 2231 2232 REVERSE_BYTES_QUAD(&Cdb->CDB16.LogicalBlock, §orOffset); 2233 REVERSE_BYTES_SHORT(&Cdb->CDB16.TransferLength[2], &numSectors); 2234 } else { 2235 2236 // 2237 // Move little endian values into CDB in big endian format 2238 // 2239 2240 Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)§orOffset)->Byte3; 2241 Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)§orOffset)->Byte2; 2242 Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)§orOffset)->Byte1; 2243 Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)§orOffset)->Byte0; 2244 2245 Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numSectors)->Byte1; 2246 Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numSectors)->Byte0; 2247 } 2248 2249 status = ClassSendSrbSynchronous(Fdo, 2250 Srb, 2251 NULL, 2252 0, 2253 FALSE); 2254 2255 NT_ASSERT(status != STATUS_NONEXISTENT_SECTOR); 2256 2257 sectorCount -= numSectors; 2258 sectorOffset.QuadPart += numSectors; 2259 } 2260 2261 KeReleaseMutex(&DiskData->VerifyMutex, FALSE); 2262 2263 Irp->IoStatus.Status = status; 2264 Irp->IoStatus.Information = 0; 2265 2266 ClassReleaseRemoveLock(Fdo, Irp); 2267 ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT); 2268 2269 FREE_POOL(Srb); 2270 FREE_POOL(WorkContext); 2271 } 2272 2273 2274 VOID 2275 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2276 DiskFdoProcessError( 2277 PDEVICE_OBJECT Fdo, 2278 PSCSI_REQUEST_BLOCK Srb, 2279 NTSTATUS *Status, 2280 BOOLEAN *Retry 2281 ) 2282 2283 /*++ 2284 2285 Routine Description: 2286 2287 This routine checks the type of error. If the error indicates an underrun 2288 then indicate the request should be retried. 2289 2290 Arguments: 2291 2292 Fdo - Supplies a pointer to the functional device object. 2293 2294 Srb - Supplies a pointer to the failing Srb. 2295 2296 Status - Status with which the IRP will be completed. 2297 2298 Retry - Indication of whether the request will be retried. 2299 2300 Return Value: 2301 2302 None. 2303 2304 --*/ 2305 2306 { 2307 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 2308 PSTORAGE_REQUEST_BLOCK srbEx; 2309 PCDB cdb = NULL; 2310 UCHAR scsiStatus = 0; 2311 UCHAR senseBufferLength = 0; 2312 PVOID senseBuffer = NULL; 2313 CDB noOp = {0}; 2314 2315 // 2316 // Get relevant fields from SRB 2317 // 2318 if (Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) { 2319 2320 srbEx = (PSTORAGE_REQUEST_BLOCK)Srb; 2321 2322 // 2323 // Look for SCSI SRB specific fields 2324 // 2325 if ((srbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI) && 2326 (srbEx->NumSrbExData > 0)) { 2327 cdb = GetSrbScsiData(srbEx, NULL, NULL, &scsiStatus, &senseBuffer, &senseBufferLength); 2328 2329 // 2330 // cdb and sense buffer should not be NULL 2331 // 2332 NT_ASSERT(cdb != NULL); 2333 NT_ASSERT(senseBuffer != NULL); 2334 2335 } 2336 2337 if (cdb == NULL) { 2338 2339 // 2340 // Use a cdb that is all 0s 2341 // 2342 cdb = &noOp; 2343 } 2344 2345 } else { 2346 2347 cdb = (PCDB)(Srb->Cdb); 2348 scsiStatus = Srb->ScsiStatus; 2349 senseBufferLength = Srb->SenseInfoBufferLength; 2350 senseBuffer = Srb->SenseInfoBuffer; 2351 } 2352 2353 if (*Status == STATUS_DATA_OVERRUN && 2354 (cdb != NULL) && 2355 (IS_SCSIOP_READWRITE(cdb->CDB10.OperationCode))) { 2356 2357 *Retry = TRUE; 2358 2359 // 2360 // Update the error count for the device. 2361 // 2362 2363 fdoExtension->ErrorCount++; 2364 2365 } else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR && 2366 scsiStatus == SCSISTAT_BUSY) { 2367 2368 // 2369 // a disk drive should never be busy this long. Reset the scsi bus 2370 // maybe this will clear the condition. 2371 // 2372 2373 ResetBus(Fdo); 2374 2375 // 2376 // Update the error count for the device. 2377 // 2378 2379 fdoExtension->ErrorCount++; 2380 2381 } else { 2382 2383 BOOLEAN invalidatePartitionTable = FALSE; 2384 2385 // 2386 // See if this might indicate that something on the drive has changed. 2387 // 2388 2389 if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && 2390 (senseBuffer != NULL) && (cdb != NULL)) { 2391 2392 BOOLEAN validSense = FALSE; 2393 UCHAR senseKey = 0; 2394 UCHAR asc = 0; 2395 UCHAR ascq = 0; 2396 2397 validSense = ScsiGetSenseKeyAndCodes(senseBuffer, 2398 senseBufferLength, 2399 SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED, 2400 &senseKey, 2401 &asc, 2402 &ascq); 2403 2404 if (validSense) { 2405 2406 switch (senseKey) { 2407 2408 case SCSI_SENSE_ILLEGAL_REQUEST: { 2409 2410 switch (asc) { 2411 2412 case SCSI_ADSENSE_INVALID_CDB: 2413 { 2414 // 2415 // Look to see if this is an Io request with the ForceUnitAccess flag set 2416 // 2417 if (((cdb->CDB10.OperationCode == SCSIOP_WRITE) || 2418 (cdb->CDB10.OperationCode == SCSIOP_WRITE16)) && 2419 (cdb->CDB10.ForceUnitAccess)) 2420 { 2421 PDISK_DATA diskData = (PDISK_DATA)fdoExtension->CommonExtension.DriverData; 2422 2423 if (diskData->WriteCacheOverride == DiskWriteCacheEnable) 2424 { 2425 PIO_ERROR_LOG_PACKET logEntry = NULL; 2426 2427 // 2428 // The user has explicitly requested that write caching be turned on. 2429 // Warn the user that writes with FUA enabled are not working and that 2430 // they should disable write cache. 2431 // 2432 2433 logEntry = IoAllocateErrorLogEntry(fdoExtension->DeviceObject, 2434 sizeof(IO_ERROR_LOG_PACKET) + (4 * sizeof(ULONG))); 2435 2436 if (logEntry != NULL) 2437 { 2438 logEntry->FinalStatus = *Status; 2439 logEntry->ErrorCode = IO_WARNING_WRITE_FUA_PROBLEM; 2440 logEntry->SequenceNumber = 0; 2441 logEntry->MajorFunctionCode = IRP_MJ_SCSI; 2442 logEntry->IoControlCode = 0; 2443 logEntry->RetryCount = 0; 2444 logEntry->UniqueErrorValue = 0; 2445 logEntry->DumpDataSize = 4 * sizeof(ULONG); 2446 2447 logEntry->DumpData[0] = diskData->ScsiAddress.PortNumber; 2448 logEntry->DumpData[1] = diskData->ScsiAddress.PathId; 2449 logEntry->DumpData[2] = diskData->ScsiAddress.TargetId; 2450 logEntry->DumpData[3] = diskData->ScsiAddress.Lun; 2451 2452 // 2453 // Write the error log packet. 2454 // 2455 2456 IoWriteErrorLogEntry(logEntry); 2457 } 2458 } 2459 else 2460 { 2461 // 2462 // Turn off write caching on this device. This is so that future 2463 // critical requests need not be sent down with ForceUnitAccess 2464 // 2465 PIO_WORKITEM workItem = IoAllocateWorkItem(Fdo); 2466 2467 if (workItem) 2468 { 2469 IoQueueWorkItem(workItem, DisableWriteCache, CriticalWorkQueue, workItem); 2470 } 2471 } 2472 2473 SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_FUA_NOT_SUPPORTED); 2474 ADJUST_FUA_FLAG(fdoExtension); 2475 2476 2477 cdb->CDB10.ForceUnitAccess = FALSE; 2478 *Retry = TRUE; 2479 2480 } else if ((cdb->CDB6FORMAT.OperationCode == SCSIOP_MODE_SENSE) && 2481 (cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL)) { 2482 2483 // 2484 // Mode sense for all pages failed. This command could fail with 2485 // SCSI_SENSE_ILLEGAL_REQUEST / SCSI_ADSENSE_INVALID_CDB if the data 2486 // to be returned is more than 256 bytes. In which case, try to get 2487 // only MODE_PAGE_CACHING since we only need the block descriptor. 2488 // 2489 // Simply change the page code and retry the request 2490 // 2491 2492 cdb->MODE_SENSE.PageCode = MODE_PAGE_CACHING; 2493 *Retry = TRUE; 2494 } 2495 2496 break; 2497 } 2498 } // end switch(asc) 2499 break; 2500 } 2501 2502 case SCSI_SENSE_NOT_READY: { 2503 2504 switch (asc) { 2505 case SCSI_ADSENSE_LUN_NOT_READY: { 2506 switch (ascq) { 2507 case SCSI_SENSEQ_BECOMING_READY: 2508 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: 2509 case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: { 2510 invalidatePartitionTable = TRUE; 2511 break; 2512 } 2513 } // end switch(ascq) 2514 break; 2515 } 2516 2517 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: { 2518 invalidatePartitionTable = TRUE; 2519 break; 2520 } 2521 } // end switch(asc) 2522 break; 2523 } 2524 2525 case SCSI_SENSE_MEDIUM_ERROR: { 2526 invalidatePartitionTable = TRUE; 2527 break; 2528 } 2529 2530 case SCSI_SENSE_HARDWARE_ERROR: { 2531 invalidatePartitionTable = TRUE; 2532 break; 2533 } 2534 2535 case SCSI_SENSE_UNIT_ATTENTION: 2536 { 2537 invalidatePartitionTable = TRUE; 2538 break; 2539 } 2540 2541 case SCSI_SENSE_RECOVERED_ERROR: { 2542 invalidatePartitionTable = TRUE; 2543 break; 2544 } 2545 2546 } // end switch(senseKey) 2547 } // end if (validSense) 2548 } else { 2549 2550 // 2551 // On any exceptional scsi condition which might indicate that the 2552 // device was changed we will flush out the state of the partition 2553 // table. 2554 // 2555 2556 switch (SRB_STATUS(Srb->SrbStatus)) { 2557 case SRB_STATUS_INVALID_LUN: 2558 case SRB_STATUS_INVALID_TARGET_ID: 2559 case SRB_STATUS_NO_DEVICE: 2560 case SRB_STATUS_NO_HBA: 2561 case SRB_STATUS_INVALID_PATH_ID: 2562 case SRB_STATUS_COMMAND_TIMEOUT: 2563 case SRB_STATUS_TIMEOUT: 2564 case SRB_STATUS_SELECTION_TIMEOUT: 2565 case SRB_STATUS_REQUEST_FLUSHED: 2566 case SRB_STATUS_UNEXPECTED_BUS_FREE: 2567 case SRB_STATUS_PARITY_ERROR: 2568 { 2569 invalidatePartitionTable = TRUE; 2570 break; 2571 } 2572 2573 case SRB_STATUS_ERROR: 2574 { 2575 if (scsiStatus == SCSISTAT_RESERVATION_CONFLICT) 2576 { 2577 invalidatePartitionTable = TRUE; 2578 } 2579 2580 break; 2581 } 2582 } // end switch(Srb->SrbStatus) 2583 } 2584 2585 if (invalidatePartitionTable && TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { 2586 2587 // 2588 // Inform the upper layers that the volume 2589 // on this disk is in need of verification 2590 // 2591 2592 SET_FLAG(Fdo->Flags, DO_VERIFY_VOLUME); 2593 } 2594 } 2595 2596 return; 2597 } 2598 2599 2600 VOID 2601 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2602 DiskSetSpecialHacks( 2603 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 2604 IN ULONG_PTR Data 2605 ) 2606 2607 /*++ 2608 2609 Routine Description: 2610 2611 This function checks to see if an SCSI logical unit requires speical 2612 flags to be set. 2613 2614 Arguments: 2615 2616 Fdo - Supplies the device object to be tested. 2617 2618 InquiryData - Supplies the inquiry data returned by the device of interest. 2619 2620 AdapterDescriptor - Supplies the capabilities of the device object. 2621 2622 Return Value: 2623 2624 None. 2625 2626 --*/ 2627 2628 { 2629 PDEVICE_OBJECT fdo = FdoExtension->DeviceObject; 2630 2631 PAGED_CODE(); 2632 2633 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "Disk SetSpecialHacks, Setting Hacks %p\n", (void*) Data)); 2634 2635 // 2636 // Found a listed controller. Determine what must be done. 2637 // 2638 2639 if (TEST_FLAG(Data, HackDisableTaggedQueuing)) { 2640 2641 // 2642 // Disable tagged queuing. 2643 // 2644 2645 CLEAR_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); 2646 } 2647 2648 if (TEST_FLAG(Data, HackDisableSynchronousTransfers)) { 2649 2650 // 2651 // Disable synchronous data transfers. 2652 // 2653 2654 SET_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); 2655 2656 } 2657 2658 if (TEST_FLAG(Data, HackDisableSpinDown)) { 2659 2660 // 2661 // Disable spinning down of drives. 2662 // 2663 2664 SET_FLAG(FdoExtension->ScanForSpecialFlags, 2665 CLASS_SPECIAL_DISABLE_SPIN_DOWN); 2666 2667 } 2668 2669 if (TEST_FLAG(Data, HackDisableWriteCache)) { 2670 2671 // 2672 // Disable the drive's write cache 2673 // 2674 2675 SET_FLAG(FdoExtension->ScanForSpecialFlags, 2676 CLASS_SPECIAL_DISABLE_WRITE_CACHE); 2677 2678 } 2679 2680 if (TEST_FLAG(Data, HackCauseNotReportableHack)) { 2681 2682 SET_FLAG(FdoExtension->ScanForSpecialFlags, 2683 CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK); 2684 } 2685 2686 if (TEST_FLAG(fdo->Characteristics, FILE_REMOVABLE_MEDIA) && 2687 TEST_FLAG(Data, HackRequiresStartUnitCommand) 2688 ) { 2689 2690 // 2691 // this is a list of vendors who require the START_UNIT command 2692 // 2693 2694 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DiskScanForSpecial (%p) => This unit requires " 2695 " START_UNITS\n", fdo)); 2696 SET_FLAG(FdoExtension->DeviceFlags, DEV_SAFE_START_UNIT); 2697 2698 } 2699 2700 return; 2701 } 2702 2703 2704 VOID 2705 ResetBus( 2706 IN PDEVICE_OBJECT Fdo 2707 ) 2708 2709 /*++ 2710 2711 Routine Description: 2712 2713 This command sends a reset bus command to the SCSI port driver. 2714 2715 Arguments: 2716 2717 Fdo - The functional device object for the logical unit with hardware problem. 2718 2719 Return Value: 2720 2721 None. 2722 2723 --*/ 2724 2725 { 2726 PIO_STACK_LOCATION irpStack; 2727 PIRP irp; 2728 2729 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 2730 PSCSI_REQUEST_BLOCK srb; 2731 PCOMPLETION_CONTEXT context; 2732 PSTORAGE_REQUEST_BLOCK srbEx = NULL; 2733 PSTOR_ADDR_BTL8 storAddrBtl8 = NULL; 2734 2735 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "Disk ResetBus: Sending reset bus request to port driver.\n")); 2736 2737 // 2738 // Allocate Srb from nonpaged pool. 2739 // 2740 2741 context = ExAllocatePoolWithTag(NonPagedPoolNx, 2742 sizeof(COMPLETION_CONTEXT), 2743 DISK_TAG_CCONTEXT); 2744 2745 if(context == NULL) { 2746 return; 2747 } 2748 2749 // 2750 // Save the device object in the context for use by the completion 2751 // routine. 2752 // 2753 2754 context->DeviceObject = Fdo; 2755 srb = &context->Srb.Srb; 2756 2757 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 2758 srbEx = &context->Srb.SrbEx; 2759 2760 // 2761 // Zero out srb 2762 // 2763 2764 RtlZeroMemory(srbEx, sizeof(context->Srb.SrbExBuffer)); 2765 2766 // 2767 // Set up STORAGE_REQUEST_BLOCK fields 2768 // 2769 2770 srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); 2771 srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; 2772 srbEx->Signature = SRB_SIGNATURE; 2773 srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; 2774 srbEx->SrbLength = sizeof(context->Srb.SrbExBuffer); 2775 srbEx->SrbFunction = SRB_FUNCTION_RESET_BUS; 2776 srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); 2777 2778 // 2779 // Set up address fields 2780 // 2781 2782 storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); 2783 storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; 2784 storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; 2785 2786 } else { 2787 2788 // 2789 // Zero out srb. 2790 // 2791 2792 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 2793 2794 // 2795 // Write length to SRB. 2796 // 2797 2798 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 2799 2800 srb->Function = SRB_FUNCTION_RESET_BUS; 2801 2802 } 2803 2804 // 2805 // Build the asynchronous request to be sent to the port driver. 2806 // Since this routine is called from a DPC the IRP should always be 2807 // available. 2808 // 2809 2810 irp = IoAllocateIrp(Fdo->StackSize, FALSE); 2811 2812 if (irp == NULL) { 2813 FREE_POOL(context); 2814 return; 2815 } 2816 2817 ClassAcquireRemoveLock(Fdo, irp); 2818 2819 IoSetCompletionRoutine(irp, 2820 (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion, 2821 context, 2822 TRUE, 2823 TRUE, 2824 TRUE); 2825 2826 irpStack = IoGetNextIrpStackLocation(irp); 2827 2828 irpStack->MajorFunction = IRP_MJ_SCSI; 2829 2830 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 2831 srbEx->RequestPriority = IoGetIoPriorityHint(irp); 2832 srbEx->OriginalRequest = irp; 2833 } else { 2834 srb->OriginalRequest = irp; 2835 } 2836 2837 // 2838 // Store the SRB address in next stack for port driver. 2839 // 2840 2841 irpStack->Parameters.Scsi.Srb = srb; 2842 2843 // 2844 // Call the port driver with the IRP. 2845 // 2846 2847 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp); 2848 2849 return; 2850 2851 } // end ResetBus() 2852 2853 2854 2855 VOID 2856 DiskLogCacheInformation( 2857 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 2858 IN PDISK_CACHE_INFORMATION CacheInfo, 2859 IN NTSTATUS Status 2860 ) 2861 { 2862 PIO_ERROR_LOG_PACKET logEntry = NULL; 2863 2864 PAGED_CODE(); 2865 2866 logEntry = IoAllocateErrorLogEntry(FdoExtension->DeviceObject, sizeof(IO_ERROR_LOG_PACKET) + (4 * sizeof(ULONG))); 2867 2868 if (logEntry != NULL) 2869 { 2870 PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData; 2871 BOOLEAN bIsEnabled = TEST_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE); 2872 2873 logEntry->FinalStatus = Status; 2874 logEntry->ErrorCode = (bIsEnabled) ? IO_WRITE_CACHE_ENABLED : IO_WRITE_CACHE_DISABLED; 2875 logEntry->SequenceNumber = 0; 2876 logEntry->MajorFunctionCode = IRP_MJ_SCSI; 2877 logEntry->IoControlCode = 0; 2878 logEntry->RetryCount = 0; 2879 logEntry->UniqueErrorValue = 0x1; 2880 logEntry->DumpDataSize = 4 * sizeof(ULONG); 2881 2882 logEntry->DumpData[0] = diskData->ScsiAddress.PathId; 2883 logEntry->DumpData[1] = diskData->ScsiAddress.TargetId; 2884 logEntry->DumpData[2] = diskData->ScsiAddress.Lun; 2885 logEntry->DumpData[3] = CacheInfo->WriteCacheEnabled; 2886 2887 // 2888 // Write the error log packet. 2889 // 2890 2891 IoWriteErrorLogEntry(logEntry); 2892 } 2893 } 2894 2895 NTSTATUS 2896 DiskGetInfoExceptionInformation( 2897 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 2898 IN PMODE_INFO_EXCEPTIONS ReturnPageData 2899 ) 2900 { 2901 PMODE_PARAMETER_HEADER modeData; 2902 PMODE_INFO_EXCEPTIONS pageData; 2903 ULONG length; 2904 2905 NTSTATUS status; 2906 2907 PAGED_CODE(); 2908 2909 // 2910 // ReturnPageData is allocated by the caller 2911 // 2912 2913 modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, 2914 MODE_DATA_SIZE, 2915 DISK_TAG_INFO_EXCEPTION); 2916 2917 if (modeData == NULL) { 2918 2919 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: Unable to allocate mode " 2920 "data buffer\n")); 2921 return STATUS_INSUFFICIENT_RESOURCES; 2922 } 2923 2924 RtlZeroMemory(modeData, MODE_DATA_SIZE); 2925 2926 length = ClassModeSense(FdoExtension->DeviceObject, 2927 (PCHAR) modeData, 2928 MODE_DATA_SIZE, 2929 MODE_PAGE_FAULT_REPORTING); 2930 2931 if (length < sizeof(MODE_PARAMETER_HEADER)) { 2932 2933 // 2934 // Retry the request in case of a check condition. 2935 // 2936 2937 length = ClassModeSense(FdoExtension->DeviceObject, 2938 (PCHAR) modeData, 2939 MODE_DATA_SIZE, 2940 MODE_PAGE_FAULT_REPORTING); 2941 2942 if (length < sizeof(MODE_PARAMETER_HEADER)) { 2943 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: Mode Sense failed\n")); 2944 FREE_POOL(modeData); 2945 return STATUS_IO_DEVICE_ERROR; 2946 } 2947 } 2948 2949 // 2950 // If the length is greater than length indicated by the mode data reset 2951 // the data to the mode data. 2952 // 2953 2954 if (length > (ULONG) (modeData->ModeDataLength + 1)) { 2955 length = modeData->ModeDataLength + 1; 2956 } 2957 2958 // 2959 // Find the mode page for info exceptions 2960 // 2961 2962 pageData = ClassFindModePage((PCHAR) modeData, 2963 length, 2964 MODE_PAGE_FAULT_REPORTING, 2965 TRUE); 2966 2967 if (pageData != NULL) { 2968 RtlCopyMemory(ReturnPageData, pageData, sizeof(MODE_INFO_EXCEPTIONS)); 2969 status = STATUS_SUCCESS; 2970 } else { 2971 status = STATUS_NOT_SUPPORTED; 2972 } 2973 2974 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: %s support SMART for device %p\n", 2975 NT_SUCCESS(status) ? "does" : "does not", 2976 FdoExtension->DeviceObject)); 2977 2978 FREE_POOL(modeData); 2979 2980 return(status); 2981 } 2982 2983 2984 NTSTATUS 2985 DiskSetInfoExceptionInformation( 2986 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 2987 IN PMODE_INFO_EXCEPTIONS PageData 2988 ) 2989 2990 { 2991 ULONG i; 2992 NTSTATUS status = STATUS_SUCCESS; 2993 2994 PAGED_CODE(); 2995 2996 // 2997 // We will attempt (twice) to issue the mode select with the page. 2998 // Make the setting persistant so that we don't have to turn it back 2999 // on after a bus reset. 3000 // 3001 3002 for (i = 0; i < 2; i++) 3003 { 3004 status = DiskModeSelect(FdoExtension->DeviceObject, 3005 (PCHAR) PageData, 3006 sizeof(MODE_INFO_EXCEPTIONS), 3007 TRUE); 3008 } 3009 3010 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskSetInfoExceptionInformation: %s for device %p\n", 3011 NT_SUCCESS(status) ? "succeeded" : "failed", 3012 FdoExtension->DeviceObject)); 3013 3014 return status; 3015 } 3016 3017 NTSTATUS 3018 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3019 DiskGetCacheInformation( 3020 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 3021 IN PDISK_CACHE_INFORMATION CacheInfo 3022 ) 3023 /*++ 3024 3025 Routine Description: 3026 3027 This function gets the caching mode page from the drive. This function 3028 is called from DiskIoctlGetCacheInformation() in response to the IOCTL 3029 IOCTL_DISK_GET_CACHE_INFORMATION. This is also called from the 3030 DisableWriteCache() worker thread to disable caching when write commands fail. 3031 3032 Arguments: 3033 3034 FdoExtension - The device extension for this device. 3035 3036 CacheInfo - Buffer to receive the Cache Information. 3037 3038 Return Value: 3039 3040 NTSTATUS code 3041 3042 --*/ 3043 3044 { 3045 PMODE_PARAMETER_HEADER modeData; 3046 PMODE_CACHING_PAGE pageData; 3047 3048 ULONG length; 3049 3050 PAGED_CODE(); 3051 3052 3053 3054 modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, 3055 MODE_DATA_SIZE, 3056 DISK_TAG_DISABLE_CACHE); 3057 3058 if (modeData == NULL) { 3059 3060 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetSetCacheInformation: Unable to allocate mode " 3061 "data buffer\n")); 3062 return STATUS_INSUFFICIENT_RESOURCES; 3063 } 3064 3065 RtlZeroMemory(modeData, MODE_DATA_SIZE); 3066 3067 length = ClassModeSense(FdoExtension->DeviceObject, 3068 (PCHAR) modeData, 3069 MODE_DATA_SIZE, 3070 MODE_PAGE_CACHING); 3071 3072 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3073 3074 // 3075 // Retry the request in case of a check condition. 3076 // 3077 3078 length = ClassModeSense(FdoExtension->DeviceObject, 3079 (PCHAR) modeData, 3080 MODE_DATA_SIZE, 3081 MODE_PAGE_CACHING); 3082 3083 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3084 3085 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetCacheInformation: Mode Sense failed\n")); 3086 3087 FREE_POOL(modeData); 3088 return STATUS_IO_DEVICE_ERROR; 3089 } 3090 } 3091 3092 // 3093 // If the length is greater than length indicated by the mode data reset 3094 // the data to the mode data. 3095 // 3096 3097 if (length > (ULONG) (modeData->ModeDataLength + 1)) { 3098 length = modeData->ModeDataLength + 1; 3099 } 3100 3101 // 3102 // Check to see if the write cache is enabled. 3103 // 3104 3105 pageData = ClassFindModePage((PCHAR) modeData, 3106 length, 3107 MODE_PAGE_CACHING, 3108 TRUE); 3109 3110 // 3111 // Check if valid caching page exists. 3112 // 3113 3114 if (pageData == NULL) { 3115 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetCacheInformation: Unable to find caching mode page.\n")); 3116 FREE_POOL(modeData); 3117 return STATUS_NOT_SUPPORTED; 3118 } 3119 3120 // 3121 // Copy the parameters over. 3122 // 3123 3124 RtlZeroMemory(CacheInfo, sizeof(DISK_CACHE_INFORMATION)); 3125 3126 CacheInfo->ParametersSavable = pageData->PageSavable; 3127 3128 CacheInfo->ReadCacheEnabled = !(pageData->ReadDisableCache); 3129 CacheInfo->WriteCacheEnabled = pageData->WriteCacheEnable; 3130 3131 3132 // 3133 // Translate the values in the mode page into the ones defined in 3134 // ntdddisk.h. 3135 // 3136 3137 CacheInfo->ReadRetentionPriority = 3138 TRANSLATE_RETENTION_PRIORITY(pageData->ReadRetensionPriority); 3139 CacheInfo->WriteRetentionPriority = 3140 TRANSLATE_RETENTION_PRIORITY(pageData->WriteRetensionPriority); 3141 3142 CacheInfo->DisablePrefetchTransferLength = 3143 ((pageData->DisablePrefetchTransfer[0] << 8) + 3144 pageData->DisablePrefetchTransfer[1]); 3145 3146 CacheInfo->ScalarPrefetch.Minimum = 3147 ((pageData->MinimumPrefetch[0] << 8) + pageData->MinimumPrefetch[1]); 3148 3149 CacheInfo->ScalarPrefetch.Maximum = 3150 ((pageData->MaximumPrefetch[0] << 8) + pageData->MaximumPrefetch[1]); 3151 3152 if(pageData->MultiplicationFactor) { 3153 CacheInfo->PrefetchScalar = TRUE; 3154 CacheInfo->ScalarPrefetch.MaximumBlocks = 3155 ((pageData->MaximumPrefetchCeiling[0] << 8) + 3156 pageData->MaximumPrefetchCeiling[1]); 3157 } 3158 3159 3160 FREE_POOL(modeData); 3161 return STATUS_SUCCESS; 3162 } 3163 3164 3165 NTSTATUS 3166 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3167 DiskSetCacheInformation( 3168 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 3169 IN PDISK_CACHE_INFORMATION CacheInfo 3170 ) 3171 /*++ 3172 3173 Routine Description: 3174 3175 This function sets the caching mode page in the drive. This function 3176 is also called from the DisableWriteCache() worker thread to disable 3177 caching when write commands fail. 3178 3179 Arguments: 3180 3181 FdoExtension - The device extension for this device. 3182 3183 CacheInfo - Buffer the contains the Cache Information to be set on the drive. 3184 3185 Return Value: 3186 3187 NTSTATUS code 3188 3189 --*/ 3190 { 3191 PMODE_PARAMETER_HEADER modeData; 3192 ULONG length; 3193 PMODE_CACHING_PAGE pageData; 3194 ULONG i; 3195 NTSTATUS status = STATUS_SUCCESS; 3196 3197 PAGED_CODE(); 3198 3199 modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, 3200 MODE_DATA_SIZE, 3201 DISK_TAG_DISABLE_CACHE); 3202 3203 if (modeData == NULL) { 3204 3205 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskSetCacheInformation: Unable to allocate mode " 3206 "data buffer\n")); 3207 return STATUS_INSUFFICIENT_RESOURCES; 3208 } 3209 3210 RtlZeroMemory(modeData, MODE_DATA_SIZE); 3211 3212 length = ClassModeSense(FdoExtension->DeviceObject, 3213 (PCHAR) modeData, 3214 MODE_DATA_SIZE, 3215 MODE_PAGE_CACHING); 3216 3217 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3218 3219 // 3220 // Retry the request in case of a check condition. 3221 // 3222 3223 length = ClassModeSense(FdoExtension->DeviceObject, 3224 (PCHAR) modeData, 3225 MODE_DATA_SIZE, 3226 MODE_PAGE_CACHING); 3227 3228 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3229 3230 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskSetCacheInformation: Mode Sense failed\n")); 3231 3232 FREE_POOL(modeData); 3233 return STATUS_IO_DEVICE_ERROR; 3234 } 3235 } 3236 3237 // 3238 // If the length is greater than length indicated by the mode data reset 3239 // the data to the mode data. 3240 // 3241 3242 if (length > (ULONG) (modeData->ModeDataLength + 1)) { 3243 length = modeData->ModeDataLength + 1; 3244 } 3245 3246 // 3247 // Check to see if the write cache is enabled. 3248 // 3249 3250 pageData = ClassFindModePage((PCHAR) modeData, 3251 length, 3252 MODE_PAGE_CACHING, 3253 TRUE); 3254 3255 // 3256 // Check if valid caching page exists. 3257 // 3258 3259 if (pageData == NULL) { 3260 FREE_POOL(modeData); 3261 return STATUS_NOT_SUPPORTED; 3262 } 3263 3264 // 3265 // Don't touch any of the normal parameters - not all drives actually 3266 // use the correct size of caching mode page. Just change the things 3267 // which the user could have modified. 3268 // 3269 3270 pageData->PageSavable = FALSE; 3271 3272 pageData->ReadDisableCache = !(CacheInfo->ReadCacheEnabled); 3273 pageData->MultiplicationFactor = CacheInfo->PrefetchScalar; 3274 pageData->WriteCacheEnable = CacheInfo->WriteCacheEnabled; 3275 3276 pageData->WriteRetensionPriority = (UCHAR) 3277 TRANSLATE_RETENTION_PRIORITY(CacheInfo->WriteRetentionPriority); 3278 pageData->ReadRetensionPriority = (UCHAR) 3279 TRANSLATE_RETENTION_PRIORITY(CacheInfo->ReadRetentionPriority); 3280 3281 pageData->DisablePrefetchTransfer[0] = 3282 (UCHAR) (CacheInfo->DisablePrefetchTransferLength >> 8); 3283 pageData->DisablePrefetchTransfer[1] = 3284 (UCHAR) (CacheInfo->DisablePrefetchTransferLength & 0x00ff); 3285 3286 pageData->MinimumPrefetch[0] = 3287 (UCHAR) (CacheInfo->ScalarPrefetch.Minimum >> 8); 3288 pageData->MinimumPrefetch[1] = 3289 (UCHAR) (CacheInfo->ScalarPrefetch.Minimum & 0x00ff); 3290 3291 pageData->MaximumPrefetch[0] = 3292 (UCHAR) (CacheInfo->ScalarPrefetch.Maximum >> 8); 3293 pageData->MaximumPrefetch[1] = 3294 (UCHAR) (CacheInfo->ScalarPrefetch.Maximum & 0x00ff); 3295 3296 if(pageData->MultiplicationFactor) { 3297 3298 pageData->MaximumPrefetchCeiling[0] = 3299 (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks >> 8); 3300 pageData->MaximumPrefetchCeiling[1] = 3301 (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks & 0x00ff); 3302 } 3303 3304 // 3305 // We will attempt (twice) to issue the mode select with the page. 3306 // 3307 3308 for (i = 0; i < 2; i++) { 3309 3310 status = DiskModeSelect(FdoExtension->DeviceObject, 3311 (PCHAR) pageData, 3312 (pageData->PageLength + 2), 3313 CacheInfo->ParametersSavable); 3314 3315 if (NT_SUCCESS(status)) { 3316 3317 if (CacheInfo->WriteCacheEnabled) 3318 { 3319 SET_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE); 3320 } 3321 else 3322 { 3323 CLEAR_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE); 3324 } 3325 ADJUST_FUA_FLAG(FdoExtension); 3326 3327 break; 3328 } 3329 } 3330 3331 if (NT_SUCCESS(status)) 3332 { 3333 } else { 3334 3335 // 3336 // We were unable to modify the disk write cache setting 3337 // 3338 3339 SET_FLAG(FdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_MODIFY_CACHE_UNSUCCESSFUL); 3340 } 3341 3342 FREE_POOL(modeData); 3343 return status; 3344 } 3345 3346 NTSTATUS 3347 DiskIoctlGetCacheSetting( 3348 IN PDEVICE_OBJECT DeviceObject, 3349 IN PIRP Irp 3350 ) 3351 3352 /*++ 3353 3354 Routine description: 3355 3356 This routine services IOCTL_DISK_GET_CACHE_SETTING. It looks to 3357 see if there are any issues with the disk cache and whether the 3358 user had previously indicated that the cache is power-protected 3359 3360 Arguments: 3361 3362 Fdo - The functional device object processing the request 3363 Irp - The ioctl to be processed 3364 3365 Return Value: 3366 3367 STATUS_SUCCESS if successful, an error code otherwise 3368 3369 --*/ 3370 3371 { 3372 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 3373 PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); 3374 NTSTATUS status = STATUS_SUCCESS; 3375 3376 PAGED_CODE(); 3377 3378 if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_CACHE_SETTING)) 3379 { 3380 status = STATUS_BUFFER_TOO_SMALL; 3381 } 3382 else 3383 { 3384 PDISK_CACHE_SETTING cacheSetting = (PDISK_CACHE_SETTING)Irp->AssociatedIrp.SystemBuffer; 3385 3386 cacheSetting->Version = sizeof(DISK_CACHE_SETTING); 3387 cacheSetting->State = DiskCacheNormal; 3388 3389 // 3390 // Determine whether it is safe to turn on the cache 3391 // 3392 if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_FUA_NOT_SUPPORTED)) 3393 { 3394 cacheSetting->State = DiskCacheWriteThroughNotSupported; 3395 } 3396 3397 // 3398 // Determine whether it is possible to modify the cache setting 3399 // 3400 if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_MODIFY_CACHE_UNSUCCESSFUL)) 3401 { 3402 cacheSetting->State = DiskCacheModifyUnsuccessful; 3403 } 3404 3405 cacheSetting->IsPowerProtected = TEST_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED); 3406 3407 Irp->IoStatus.Information = sizeof(DISK_CACHE_SETTING); 3408 } 3409 3410 return status; 3411 } 3412 3413 3414 NTSTATUS 3415 DiskIoctlSetCacheSetting( 3416 IN PDEVICE_OBJECT DeviceObject, 3417 IN PIRP Irp 3418 ) 3419 3420 /*++ 3421 3422 Routine description: 3423 3424 This routine services IOCTL_DISK_SET_CACHE_SETTING. It allows 3425 the user to specify whether the disk cache is power-protected 3426 or not 3427 3428 This function must be called at IRQL < DISPATCH_LEVEL. 3429 3430 Arguments: 3431 3432 Fdo - The functional device object processing the request 3433 Irp - The ioctl to be processed 3434 3435 Return Value: 3436 3437 STATUS_SUCCESS if successful, an error code otherwise 3438 3439 --*/ 3440 3441 { 3442 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 3443 PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); 3444 NTSTATUS status = STATUS_SUCCESS; 3445 3446 // 3447 // This function must be called at less than dispatch level. 3448 // Fail if IRQL >= DISPATCH_LEVEL. 3449 // 3450 PAGED_CODE(); 3451 CHECK_IRQL(); 3452 3453 if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(DISK_CACHE_SETTING)) 3454 { 3455 status = STATUS_INFO_LENGTH_MISMATCH; 3456 } 3457 else 3458 { 3459 PDISK_CACHE_SETTING cacheSetting = (PDISK_CACHE_SETTING)Irp->AssociatedIrp.SystemBuffer; 3460 3461 if (cacheSetting->Version == sizeof(DISK_CACHE_SETTING)) 3462 { 3463 ULONG isPowerProtected; 3464 3465 // 3466 // Save away the user-defined override in our extension and the registry 3467 // 3468 if (cacheSetting->IsPowerProtected) 3469 { 3470 SET_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED); 3471 isPowerProtected = 1; 3472 } 3473 else 3474 { 3475 CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED); 3476 isPowerProtected = 0; 3477 } 3478 ADJUST_FUA_FLAG(fdoExtension); 3479 3480 ClassSetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey, DiskDeviceCacheIsPowerProtected, isPowerProtected); 3481 } 3482 else 3483 { 3484 status = STATUS_INVALID_PARAMETER; 3485 } 3486 } 3487 3488 return status; 3489 } 3490 3491 NTSTATUS 3492 DiskIoctlGetLengthInfo( 3493 IN OUT PDEVICE_OBJECT DeviceObject, 3494 IN OUT PIRP Irp 3495 ) 3496 3497 /*++ 3498 3499 Routine Description: 3500 3501 This routine services IOCTL_DISK_GET_LENGTH_INFO. It returns 3502 the disk geometry to the caller. 3503 3504 This function must be called at IRQL < DISPATCH_LEVEL. 3505 3506 Arguments: 3507 3508 DeviceObject - Supplies the device object associated with this request. 3509 3510 Irp - The IRP to be processed 3511 3512 Return Value: 3513 3514 NTSTATUS code 3515 3516 --*/ 3517 3518 { 3519 NTSTATUS status; 3520 PIO_STACK_LOCATION irpStack; 3521 PGET_LENGTH_INFORMATION lengthInfo; 3522 PFUNCTIONAL_DEVICE_EXTENSION p0Extension; 3523 PCOMMON_DEVICE_EXTENSION commonExtension; 3524 PDISK_DATA partitionZeroData; 3525 NTSTATUS oldReadyStatus; 3526 3527 // 3528 // This function must be called at less than dispatch level. 3529 // Fail if IRQL >= DISPATCH_LEVEL. 3530 // 3531 PAGED_CODE(); 3532 CHECK_IRQL(); 3533 3534 // 3535 // Initialization 3536 // 3537 3538 commonExtension = DeviceObject->DeviceExtension; 3539 irpStack = IoGetCurrentIrpStackLocation(Irp); 3540 p0Extension = commonExtension->PartitionZeroExtension; 3541 partitionZeroData = ((PDISK_DATA) p0Extension->CommonExtension.DriverData); 3542 3543 // 3544 // Check that the buffer is large enough. 3545 // 3546 3547 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_LENGTH_INFORMATION)) { 3548 return STATUS_BUFFER_TOO_SMALL; 3549 } 3550 3551 // 3552 // Update the geometry in case it has changed 3553 // 3554 3555 status = DiskReadDriveCapacity(p0Extension->DeviceObject); 3556 3557 // 3558 // Note whether the drive is ready. If the status has changed then 3559 // notify pnp. 3560 // 3561 3562 oldReadyStatus = InterlockedExchange(&(partitionZeroData->ReadyStatus), status); 3563 3564 if(partitionZeroData->ReadyStatus != oldReadyStatus) { 3565 IoInvalidateDeviceRelations(p0Extension->LowerPdo, BusRelations); 3566 } 3567 3568 if(!NT_SUCCESS(status)) { 3569 return status; 3570 } 3571 lengthInfo = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer; 3572 3573 lengthInfo->Length = commonExtension->PartitionLength; 3574 3575 status = STATUS_SUCCESS; 3576 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION); 3577 3578 return status; 3579 } 3580 3581 NTSTATUS 3582 DiskIoctlGetDriveGeometry( 3583 IN PDEVICE_OBJECT DeviceObject, 3584 IN OUT PIRP Irp 3585 ) 3586 3587 /*++ 3588 3589 Routine Description: 3590 3591 This routine services IOCTL_DISK_GET_DRIVE_GEOMETRY. It returns 3592 the disk geometry to the caller. 3593 3594 This function must be called at IRQL < DISPATCH_LEVEL. 3595 3596 Arguments: 3597 3598 DeviceObject - Supplies the device object associated with this request. 3599 3600 Irp - IRP with a return buffer large enough to receive the 3601 extended geometry information. 3602 3603 Return Value: 3604 3605 NTSTATUS code 3606 3607 --*/ 3608 3609 { 3610 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 3611 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 3612 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); 3613 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 3614 NTSTATUS status; 3615 3616 // 3617 // This function must be called at less than dispatch level. 3618 // Fail if IRQL >= DISPATCH_LEVEL. 3619 // 3620 PAGED_CODE(); 3621 CHECK_IRQL(); 3622 3623 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) { 3624 3625 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetDriveGeometry: Output buffer too small.\n")); 3626 return STATUS_BUFFER_TOO_SMALL; 3627 } 3628 3629 if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) { 3630 3631 // 3632 // Issue ReadCapacity to update device extension 3633 // with information for current media. 3634 // 3635 3636 status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject); 3637 3638 // 3639 // Note whether the drive is ready. 3640 // 3641 3642 diskData->ReadyStatus = status; 3643 3644 if (!NT_SUCCESS(status)) { 3645 return status; 3646 } 3647 } 3648 3649 // 3650 // Copy drive geometry information from device extension. 3651 // 3652 3653 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, 3654 &(fdoExtension->DiskGeometry), 3655 sizeof(DISK_GEOMETRY)); 3656 3657 if (((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector == 0) { 3658 ((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector = 512; 3659 } 3660 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY); 3661 return STATUS_SUCCESS; 3662 } 3663 3664 typedef struct _DISK_GEOMETRY_EX_INTERNAL { 3665 DISK_GEOMETRY Geometry; 3666 LARGE_INTEGER DiskSize; 3667 DISK_PARTITION_INFO Partition; 3668 DISK_DETECTION_INFO Detection; 3669 } DISK_GEOMETRY_EX_INTERNAL, *PDISK_GEOMETRY_EX_INTERNAL; 3670 3671 NTSTATUS 3672 DiskIoctlGetDriveGeometryEx( 3673 IN PDEVICE_OBJECT DeviceObject, 3674 IN OUT PIRP Irp 3675 ) 3676 3677 /*++ 3678 3679 Routine Description: 3680 3681 This routine services IOCTL_DISK_GET_DRIVE_GEOMETRY_EX. It returns 3682 the extended disk geometry to the caller. 3683 3684 This function must be called at IRQL < DISPATCH_LEVEL. 3685 3686 Arguments: 3687 3688 DeviceObject - The device object to obtain the geometry for. 3689 3690 Irp - IRP with a return buffer large enough to receive the 3691 extended geometry information. 3692 3693 Return Value: 3694 3695 NTSTATUS code 3696 3697 --*/ 3698 3699 { 3700 NTSTATUS status; 3701 PIO_STACK_LOCATION irpStack; 3702 PCOMMON_DEVICE_EXTENSION commonExtension; 3703 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 3704 PDISK_DATA diskData; 3705 PDISK_GEOMETRY_EX_INTERNAL geometryEx; 3706 ULONG OutputBufferLength; 3707 3708 // 3709 // This function must be called at less than dispatch level. 3710 // Fail if IRQL >= DISPATCH_LEVEL. 3711 // 3712 PAGED_CODE(); 3713 CHECK_IRQL(); 3714 3715 // 3716 // Setup parameters 3717 // 3718 3719 commonExtension = DeviceObject->DeviceExtension; 3720 fdoExtension = DeviceObject->DeviceExtension; 3721 diskData = (PDISK_DATA)(commonExtension->DriverData); 3722 irpStack = IoGetCurrentIrpStackLocation ( Irp ); 3723 geometryEx = NULL; 3724 OutputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; 3725 3726 // 3727 // Check that the buffer is large enough. It must be large enough 3728 // to hold at lest the Geometry and DiskSize fields of of the 3729 // DISK_GEOMETRY_EX structure. 3730 // 3731 3732 if ( (LONG)OutputBufferLength < FIELD_OFFSET (DISK_GEOMETRY_EX, Data) ) { 3733 3734 // 3735 // Buffer too small. Bail out, telling the caller the required 3736 // size. 3737 // 3738 3739 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetDriveGeometryEx: Output buffer too small.\n")); 3740 status = STATUS_BUFFER_TOO_SMALL; 3741 return status; 3742 } 3743 3744 if (TEST_FLAG (DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) { 3745 3746 // 3747 // Issue a ReadCapacity to update device extension 3748 // with information for the current media. 3749 // 3750 3751 status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject); 3752 3753 diskData->ReadyStatus = status; 3754 3755 if (!NT_SUCCESS (status)) { 3756 return status; 3757 } 3758 } 3759 3760 // 3761 // Copy drive geometry. 3762 // 3763 3764 geometryEx = (PDISK_GEOMETRY_EX_INTERNAL)Irp->AssociatedIrp.SystemBuffer; 3765 geometryEx->Geometry = fdoExtension->DiskGeometry; 3766 if (geometryEx->Geometry.BytesPerSector == 0) { 3767 geometryEx->Geometry.BytesPerSector = 512; 3768 } 3769 geometryEx->DiskSize = commonExtension->PartitionZeroExtension->CommonExtension.PartitionLength; 3770 3771 // 3772 // If the user buffer is large enough to hold the partition information 3773 // then add that as well. 3774 // 3775 3776 if ((LONG)OutputBufferLength >= FIELD_OFFSET (DISK_GEOMETRY_EX_INTERNAL, Detection)) { 3777 3778 geometryEx->Partition.SizeOfPartitionInfo = sizeof (geometryEx->Partition); 3779 geometryEx->Partition.PartitionStyle = diskData->PartitionStyle; 3780 3781 switch ( diskData->PartitionStyle ) { 3782 3783 case PARTITION_STYLE_GPT: 3784 3785 // 3786 // Copy GPT signature. 3787 // 3788 3789 geometryEx->Partition.Gpt.DiskId = diskData->Efi.DiskId; 3790 break; 3791 3792 case PARTITION_STYLE_MBR: 3793 3794 // 3795 // Copy MBR signature and checksum. 3796 // 3797 3798 geometryEx->Partition.Mbr.Signature = diskData->Mbr.Signature; 3799 geometryEx->Partition.Mbr.CheckSum = diskData->Mbr.MbrCheckSum; 3800 break; 3801 3802 default: 3803 3804 // 3805 // This is a raw disk. Zero out the signature area so 3806 // nobody gets confused. 3807 // 3808 3809 RtlZeroMemory(&geometryEx->Partition, sizeof (geometryEx->Partition)); 3810 } 3811 } 3812 3813 // 3814 // If the buffer is large enough to hold the detection information, 3815 // then also add that. 3816 // 3817 3818 if (OutputBufferLength >= sizeof (DISK_GEOMETRY_EX_INTERNAL)) { 3819 3820 geometryEx->Detection.SizeOfDetectInfo = sizeof (geometryEx->Detection); 3821 3822 status = DiskGetDetectInfo(fdoExtension, &geometryEx->Detection); 3823 3824 // 3825 // Failed to obtain detection information, set to none. 3826 // 3827 3828 if (!NT_SUCCESS (status)) { 3829 geometryEx->Detection.DetectionType = DetectNone; 3830 } 3831 } 3832 3833 status = STATUS_SUCCESS; 3834 Irp->IoStatus.Information = min (OutputBufferLength, sizeof (DISK_GEOMETRY_EX_INTERNAL)); 3835 3836 return status; 3837 } 3838 3839 NTSTATUS 3840 DiskIoctlGetCacheInformation( 3841 IN PDEVICE_OBJECT DeviceObject, 3842 IN OUT PIRP Irp 3843 ) 3844 3845 /*++ 3846 3847 Routine Description: 3848 3849 This routine services IOCTL_DISK_GET_CACHE_INFORMATION. It reads 3850 the caching mode page from the device and returns information to 3851 the caller. After validating the user parameter it calls the 3852 DiskGetCacheInformation() function to get the mode page. 3853 3854 This function must be called at IRQL < DISPATCH_LEVEL. 3855 3856 Arguments: 3857 3858 DeviceObject - Supplies the device object associated with this request. 3859 3860 Irp - The IRP to be processed 3861 3862 Return Value: 3863 3864 NTSTATUS code 3865 3866 --*/ 3867 3868 { 3869 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 3870 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 3871 PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer; 3872 NTSTATUS status; 3873 3874 // 3875 // This function must be called at less than dispatch level. 3876 // Fail if IRQL >= DISPATCH_LEVEL. 3877 // 3878 PAGED_CODE(); 3879 CHECK_IRQL(); 3880 3881 // 3882 // Validate the request. 3883 // 3884 3885 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetCacheInformation: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 3886 3887 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_CACHE_INFORMATION)) { 3888 3889 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetCacheInformation: Output buffer too small.\n")); 3890 return STATUS_BUFFER_TOO_SMALL; 3891 } 3892 3893 status = DiskGetCacheInformation(fdoExtension, cacheInfo); 3894 3895 if (NT_SUCCESS(status)) { 3896 Irp->IoStatus.Information = sizeof(DISK_CACHE_INFORMATION); 3897 3898 // 3899 // Make sure write cache setting is reflected in device extension 3900 // 3901 if (cacheInfo->WriteCacheEnabled) 3902 { 3903 SET_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE); 3904 } 3905 else 3906 { 3907 CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE); 3908 } 3909 ADJUST_FUA_FLAG(fdoExtension); 3910 3911 } 3912 return status; 3913 } 3914 3915 3916 NTSTATUS 3917 DiskIoctlSetCacheInformation( 3918 IN PDEVICE_OBJECT DeviceObject, 3919 IN OUT PIRP Irp 3920 ) 3921 3922 /*++ 3923 3924 Routine Description: 3925 3926 This routine services IOCTL_DISK_SET_CACHE_INFORMATION. It allows 3927 the caller to set the caching mode page on the device. This function 3928 validates the user parameter and calls the DiskSetCacheInformation() 3929 function to set the mode page. It also stores the cache value in the 3930 device extension and registry. 3931 3932 This function must be called at IRQL < DISPATCH_LEVEL. 3933 3934 Arguments: 3935 3936 DeviceObject - Supplies the device object associated with this request. 3937 3938 Irp - The IRP to be processed 3939 3940 Return Value: 3941 3942 NTSTATUS code 3943 3944 --*/ 3945 3946 { 3947 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 3948 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 3949 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); 3950 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 3951 PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer; 3952 NTSTATUS status; 3953 3954 // 3955 // This function must be called at less than dispatch level. 3956 // Fail if IRQL is equal or above DISPATCH_LEVEL. 3957 // 3958 3959 PAGED_CODE(); 3960 CHECK_IRQL(); 3961 3962 // 3963 // Validate the request. 3964 // 3965 3966 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSetCacheInformation: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 3967 3968 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(DISK_CACHE_INFORMATION)) { 3969 3970 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSetCacheInformation: Input buffer length mismatch.\n")); 3971 return STATUS_INFO_LENGTH_MISMATCH; 3972 } 3973 3974 status = DiskSetCacheInformation(fdoExtension, cacheInfo); 3975 3976 // 3977 // Save away the user-defined override in our extension and the registry 3978 // 3979 if (cacheInfo->WriteCacheEnabled) { 3980 diskData->WriteCacheOverride = DiskWriteCacheEnable; 3981 } else { 3982 diskData->WriteCacheOverride = DiskWriteCacheDisable; 3983 } 3984 3985 ClassSetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey, 3986 DiskDeviceUserWriteCacheSetting, diskData->WriteCacheOverride); 3987 3988 DiskLogCacheInformation(fdoExtension, cacheInfo, status); 3989 3990 return status; 3991 } 3992 3993 NTSTATUS 3994 DiskIoctlGetMediaTypesEx( 3995 IN PDEVICE_OBJECT DeviceObject, 3996 IN OUT PIRP Irp 3997 ) 3998 3999 /*++ 4000 4001 Routine Description: 4002 4003 This routine services IOCTL_STORAGE_GET_MEDIA_TYPES_EX. It returns 4004 the media type information to the caller. After validating the user 4005 parameter it calls DiskDetermineMediaTypes() to get the media type. 4006 4007 This function must be called at IRQL < DISPATCH_LEVEL. 4008 4009 Arguments: 4010 4011 DeviceObject - Supplies the device object associated with this request. 4012 4013 Irp - The IRP to be processed 4014 4015 Return Value: 4016 4017 NTSTATUS code 4018 4019 --*/ 4020 4021 { 4022 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 4023 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 4024 NTSTATUS status; 4025 4026 PMODE_PARAMETER_HEADER modeData; 4027 PMODE_PARAMETER_BLOCK blockDescriptor; 4028 PSCSI_REQUEST_BLOCK srb; 4029 PCDB cdb; 4030 ULONG modeLength; 4031 ULONG retries = 4; 4032 UCHAR densityCode = 0; 4033 BOOLEAN writable = TRUE; 4034 BOOLEAN mediaPresent = FALSE; 4035 ULONG srbSize; 4036 PSTORAGE_REQUEST_BLOCK srbEx = NULL; 4037 PSTOR_ADDR_BTL8 storAddrBtl8 = NULL; 4038 PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL; 4039 4040 // 4041 // This function must be called at less than dispatch level. 4042 // Fail if IRQL >= DISPATCH_LEVEL. 4043 // 4044 PAGED_CODE(); 4045 CHECK_IRQL(); 4046 4047 // 4048 // Validate the request. 4049 // 4050 4051 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 4052 4053 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_MEDIA_TYPES)) { 4054 4055 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Output buffer too small.\n")); 4056 return STATUS_BUFFER_TOO_SMALL; 4057 } 4058 4059 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 4060 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; 4061 } else { 4062 srbSize = SCSI_REQUEST_BLOCK_SIZE; 4063 } 4064 4065 srb = ExAllocatePoolWithTag(NonPagedPoolNx, 4066 srbSize, 4067 DISK_TAG_SRB); 4068 4069 if (srb == NULL) { 4070 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Unable to allocate memory.\n")); 4071 return STATUS_INSUFFICIENT_RESOURCES; 4072 } 4073 4074 RtlZeroMemory(srb, srbSize); 4075 4076 // 4077 // Send a TUR to determine if media is present. 4078 // 4079 4080 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 4081 srbEx = (PSTORAGE_REQUEST_BLOCK)srb; 4082 4083 // 4084 // Set up STORAGE_REQUEST_BLOCK fields 4085 // 4086 4087 srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); 4088 srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; 4089 srbEx->Signature = SRB_SIGNATURE; 4090 srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; 4091 srbEx->SrbLength = srbSize; 4092 srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 4093 srbEx->RequestPriority = IoGetIoPriorityHint(Irp); 4094 srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); 4095 srbEx->NumSrbExData = 1; 4096 4097 // Set timeout value. 4098 srbEx->TimeOutValue = fdoExtension->TimeOutValue; 4099 4100 // 4101 // Set up address fields 4102 // 4103 4104 storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); 4105 storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; 4106 storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; 4107 4108 // 4109 // Set up SCSI SRB extended data fields 4110 // 4111 4112 srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + 4113 sizeof(STOR_ADDR_BTL8); 4114 if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { 4115 srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); 4116 srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; 4117 srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; 4118 srbExDataCdb16->CdbLength = 6; 4119 4120 cdb = (PCDB)srbExDataCdb16->Cdb; 4121 } else { 4122 // Should not happen 4123 NT_ASSERT(FALSE); 4124 4125 FREE_POOL(srb); 4126 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Insufficient extended SRB size.\n")); 4127 return STATUS_INTERNAL_ERROR; 4128 } 4129 4130 } else { 4131 4132 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 4133 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 4134 srb->CdbLength = 6; 4135 cdb = (PCDB)srb->Cdb; 4136 4137 // 4138 // Set timeout value. 4139 // 4140 4141 srb->TimeOutValue = fdoExtension->TimeOutValue; 4142 4143 } 4144 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; 4145 4146 status = ClassSendSrbSynchronous(DeviceObject, 4147 srb, 4148 NULL, 4149 0, 4150 FALSE); 4151 4152 if (NT_SUCCESS(status)) { 4153 mediaPresent = TRUE; 4154 } 4155 4156 modeLength = MODE_DATA_SIZE; 4157 modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, 4158 modeLength, 4159 DISK_TAG_MODE_DATA); 4160 4161 if (modeData == NULL) { 4162 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Unable to allocate memory.\n")); 4163 FREE_POOL(srb); 4164 return STATUS_INSUFFICIENT_RESOURCES; 4165 } 4166 4167 RtlZeroMemory(modeData, modeLength); 4168 4169 // 4170 // Build the MODE SENSE CDB using previous SRB. 4171 // 4172 4173 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 4174 srbEx->SrbStatus = 0; 4175 srbExDataCdb16->ScsiStatus = 0; 4176 srbExDataCdb16->CdbLength = 6; 4177 4178 // 4179 // Set timeout value from device extension. 4180 // 4181 4182 srbEx->TimeOutValue = fdoExtension->TimeOutValue; 4183 } else { 4184 srb->SrbStatus = 0; 4185 srb->ScsiStatus = 0; 4186 srb->CdbLength = 6; 4187 4188 // 4189 // Set timeout value from device extension. 4190 // 4191 4192 srb->TimeOutValue = fdoExtension->TimeOutValue; 4193 } 4194 4195 // 4196 // Page code of 0x3F will return all pages. 4197 // This command could fail if the data to be returned is 4198 // more than 256 bytes. In which case, we should get only 4199 // the caching page since we only need the block descriptor. 4200 // DiskFdoProcessError will change the page code to 4201 // MODE_PAGE_CACHING if there is an error. 4202 // 4203 4204 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; 4205 cdb->MODE_SENSE.PageCode = MODE_SENSE_RETURN_ALL; 4206 cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength; 4207 4208 Retry: 4209 status = ClassSendSrbSynchronous(DeviceObject, 4210 srb, 4211 modeData, 4212 modeLength, 4213 FALSE); 4214 4215 if (status == STATUS_VERIFY_REQUIRED) { 4216 4217 if (retries--) { 4218 4219 // 4220 // Retry request. 4221 // 4222 4223 goto Retry; 4224 } 4225 } else if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) { 4226 status = STATUS_SUCCESS; 4227 } 4228 4229 if (NT_SUCCESS(status) || (status == STATUS_NO_MEDIA_IN_DEVICE)) { 4230 4231 // 4232 // Get the block descriptor. 4233 // 4234 4235 if (modeData->BlockDescriptorLength != 0) { 4236 4237 blockDescriptor = (PMODE_PARAMETER_BLOCK)((ULONG_PTR)modeData + sizeof(MODE_PARAMETER_HEADER)); 4238 densityCode = blockDescriptor->DensityCode; 4239 } 4240 4241 if (TEST_FLAG(modeData->DeviceSpecificParameter, 4242 MODE_DSP_WRITE_PROTECT)) { 4243 4244 writable = FALSE; 4245 } 4246 4247 status = DiskDetermineMediaTypes(DeviceObject, 4248 Irp, 4249 modeData->MediumType, 4250 densityCode, 4251 mediaPresent, 4252 writable); 4253 // 4254 // If the buffer was too small, DetermineMediaTypes updated the status and information and the request will fail. 4255 // 4256 4257 } else { 4258 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Mode sense for header/bd failed. %lx\n", status)); 4259 } 4260 4261 FREE_POOL(srb); 4262 FREE_POOL(modeData); 4263 4264 return status; 4265 } 4266 4267 NTSTATUS 4268 DiskIoctlPredictFailure( 4269 IN PDEVICE_OBJECT DeviceObject, 4270 IN OUT PIRP Irp 4271 ) 4272 4273 /*++ 4274 4275 Routine Description: 4276 4277 This routine services IOCTL_STORAGE_PREDICT_FAILURE. If the device 4278 supports SMART then it returns any available failure data. 4279 4280 This function must be called at IRQL < DISPATCH_LEVEL. 4281 4282 Arguments: 4283 4284 DeviceObject - Supplies the device object associated with this request. 4285 4286 Irp - The IRP to be processed 4287 4288 Return Value: 4289 4290 NTSTATUS code 4291 4292 --*/ 4293 4294 { 4295 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 4296 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 4297 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); 4298 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 4299 NTSTATUS status = STATUS_SUCCESS; 4300 4301 PSTORAGE_PREDICT_FAILURE checkFailure; 4302 STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus; 4303 IO_STATUS_BLOCK ioStatus = { 0 }; 4304 KEVENT event; 4305 4306 // 4307 // This function must be called at less than dispatch level. 4308 // Fail if IRQL >= DISPATCH_LEVEL. 4309 // 4310 PAGED_CODE(); 4311 CHECK_IRQL(); 4312 4313 // 4314 // Validate the request. 4315 // 4316 4317 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlPredictFailure: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 4318 4319 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_PREDICT_FAILURE)) { 4320 4321 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlPredictFailure: Output buffer too small.\n")); 4322 return STATUS_BUFFER_TOO_SMALL; 4323 } 4324 4325 // 4326 // See if the disk is predicting failure 4327 // 4328 4329 checkFailure = (PSTORAGE_PREDICT_FAILURE)Irp->AssociatedIrp.SystemBuffer; 4330 4331 if (diskData->FailurePredictionCapability == FailurePredictionSense) { 4332 ULONG readBufferSize; 4333 PUCHAR readBuffer; 4334 PIRP readIrp; 4335 PDEVICE_OBJECT topOfStack; 4336 4337 checkFailure->PredictFailure = 0; 4338 4339 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 4340 4341 topOfStack = IoGetAttachedDeviceReference(DeviceObject); 4342 4343 // 4344 // SCSI disks need to have a read sent down to provoke any 4345 // failures to be reported. 4346 // 4347 // Issue a normal read operation. The error-handling code in 4348 // classpnp will take care of a failure prediction by logging the 4349 // correct event. 4350 // 4351 4352 readBufferSize = fdoExtension->DiskGeometry.BytesPerSector; 4353 readBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, 4354 readBufferSize, 4355 DISK_TAG_SMART); 4356 4357 if (readBuffer != NULL) { 4358 LARGE_INTEGER offset; 4359 4360 offset.QuadPart = 0; 4361 readIrp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 4362 topOfStack, 4363 readBuffer, 4364 readBufferSize, 4365 &offset, 4366 &event, 4367 &ioStatus); 4368 4369 if (readIrp != NULL) { 4370 4371 status = IoCallDriver(topOfStack, readIrp); 4372 if (status == STATUS_PENDING) { 4373 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 4374 status = ioStatus.Status; 4375 } 4376 4377 4378 } else { 4379 status = STATUS_INSUFFICIENT_RESOURCES; 4380 } 4381 4382 FREE_POOL(readBuffer); 4383 } else { 4384 status = STATUS_INSUFFICIENT_RESOURCES; 4385 } 4386 4387 ObDereferenceObject(topOfStack); 4388 } 4389 4390 if (status != STATUS_INSUFFICIENT_RESOURCES) 4391 { 4392 if ((diskData->FailurePredictionCapability == FailurePredictionSmart) || 4393 (diskData->FailurePredictionCapability == FailurePredictionSense)) { 4394 4395 status = DiskReadFailurePredictStatus(fdoExtension, &diskSmartStatus); 4396 4397 if (NT_SUCCESS(status)) { 4398 4399 status = DiskReadFailurePredictData(fdoExtension, 4400 Irp->AssociatedIrp.SystemBuffer); 4401 4402 if (diskSmartStatus.PredictFailure) { 4403 checkFailure->PredictFailure = 1; 4404 } else { 4405 checkFailure->PredictFailure = 0; 4406 } 4407 4408 Irp->IoStatus.Information = sizeof(STORAGE_PREDICT_FAILURE); 4409 } 4410 } else { 4411 status = STATUS_INVALID_DEVICE_REQUEST; 4412 } 4413 } 4414 return status; 4415 } 4416 4417 #if (NTDDI_VERSION >= NTDDI_WINBLUE) 4418 NTSTATUS 4419 DiskIoctlEnableFailurePrediction( 4420 IN PDEVICE_OBJECT DeviceObject, 4421 IN OUT PIRP Irp 4422 ) 4423 4424 /*++ 4425 4426 Routine Description: 4427 4428 This routine services IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG. If the device 4429 supports SMART then it returns any available failure data. 4430 4431 This function must be called at IRQL < DISPATCH_LEVEL. 4432 4433 Arguments: 4434 4435 DeviceObject - Supplies the device object associated with this request. 4436 4437 Irp - The IRP to be processed 4438 4439 Return Value: 4440 4441 NTSTATUS code 4442 4443 --*/ 4444 4445 { 4446 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 4447 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 4448 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); 4449 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 4450 NTSTATUS status = STATUS_SUCCESS; 4451 PSTORAGE_FAILURE_PREDICTION_CONFIG enablePrediction; 4452 4453 // 4454 // This function must be called at less than dispatch level. 4455 // Fail if IRQL >= DISPATCH_LEVEL. 4456 // 4457 PAGED_CODE(); 4458 CHECK_IRQL(); 4459 4460 // 4461 // Validate the request. 4462 // 4463 4464 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 4465 4466 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG) || 4467 irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG)) { 4468 4469 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Buffer too small.\n")); 4470 return STATUS_BUFFER_TOO_SMALL; 4471 } 4472 4473 enablePrediction = (PSTORAGE_FAILURE_PREDICTION_CONFIG)Irp->AssociatedIrp.SystemBuffer; 4474 4475 if (enablePrediction->Version != STORAGE_FAILURE_PREDICTION_CONFIG_V1 || 4476 enablePrediction->Size < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG)) { 4477 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Buffer version or size is incorrect.\n")); 4478 status = STATUS_INVALID_PARAMETER; 4479 } 4480 4481 if (enablePrediction->Reserved != 0) { 4482 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Reserved bytes are not zero!\n")); 4483 status = STATUS_INVALID_PARAMETER; 4484 } 4485 4486 // 4487 // Default to success. This might get overwritten on failure below. 4488 // 4489 status = STATUS_SUCCESS; 4490 4491 // 4492 // If this is a "set" and the current state (enabled/disabled) is 4493 // different from the sender's desired state, 4494 // 4495 if (enablePrediction->Set && enablePrediction->Enabled != diskData->FailurePredictionEnabled) { 4496 if (diskData->FailurePredictionCapability == FailurePredictionSmart || 4497 diskData->FailurePredictionCapability == FailurePredictionIoctl) { 4498 // 4499 // SMART or IOCTL based failure prediction is being used so call 4500 // the generic function that is normally called in the WMI path. 4501 // 4502 status = DiskEnableDisableFailurePrediction(fdoExtension, enablePrediction->Enabled); 4503 } else if (diskData->ScsiInfoExceptionsSupported) { 4504 // 4505 // If we know that the device supports the Informational Exceptions 4506 // mode page, try to enable/disable failure prediction that way. 4507 // 4508 status = DiskEnableInfoExceptions(fdoExtension, enablePrediction->Enabled); 4509 } 4510 } 4511 4512 // 4513 // Return the current state regardless if this was a "set" or a "get". 4514 // 4515 enablePrediction->Enabled = diskData->FailurePredictionEnabled; 4516 4517 if (NT_SUCCESS(status)) { 4518 Irp->IoStatus.Information = sizeof(STORAGE_FAILURE_PREDICTION_CONFIG); 4519 } 4520 4521 return status; 4522 } 4523 #endif //(NTDDI_VERSION >= NTDDI_WINBLUE) 4524 4525 NTSTATUS 4526 DiskIoctlVerify( 4527 IN PDEVICE_OBJECT DeviceObject, 4528 IN OUT PIRP Irp 4529 ) 4530 4531 /*++ 4532 4533 Routine Description: 4534 4535 This routine services IOCTL_DISK_VERIFY. After verifying 4536 user input, it starts the worker thread DiskIoctlVerifyThread() 4537 to verify the device. 4538 4539 Arguments: 4540 4541 DeviceObject - Supplies the device object associated with this request. 4542 4543 Irp - The IRP to be processed 4544 4545 Return Value: 4546 4547 NTSTATUS code 4548 4549 --*/ 4550 4551 { 4552 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 4553 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 4554 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 4555 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer; 4556 PDISK_VERIFY_WORKITEM_CONTEXT Context = NULL; 4557 PSCSI_REQUEST_BLOCK srb; 4558 LARGE_INTEGER byteOffset; 4559 ULONG srbSize; 4560 4561 // 4562 // Validate the request. 4563 // 4564 4565 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 4566 4567 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(VERIFY_INFORMATION)) { 4568 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Input buffer length mismatch.\n")); 4569 return STATUS_INFO_LENGTH_MISMATCH; 4570 } 4571 4572 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 4573 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; 4574 } else { 4575 srbSize = SCSI_REQUEST_BLOCK_SIZE; 4576 } 4577 srb = ExAllocatePoolWithTag(NonPagedPoolNx, 4578 srbSize, 4579 DISK_TAG_SRB); 4580 4581 if (srb == NULL) { 4582 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Unable to allocate memory.\n")); 4583 return STATUS_INSUFFICIENT_RESOURCES; 4584 } 4585 4586 RtlZeroMemory(srb, srbSize); 4587 4588 // 4589 // Add disk offset to starting sector. 4590 // 4591 4592 byteOffset.QuadPart = commonExtension->StartingOffset.QuadPart + 4593 verifyInfo->StartingOffset.QuadPart; 4594 4595 // 4596 // Perform a bounds check on the sector range 4597 // 4598 4599 if ((verifyInfo->StartingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) || 4600 (verifyInfo->StartingOffset.QuadPart < 0)) { 4601 4602 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Verify request to invalid sector.\n")); 4603 FREE_POOL(srb) 4604 return STATUS_NONEXISTENT_SECTOR; 4605 } else { 4606 4607 ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - verifyInfo->StartingOffset.QuadPart; 4608 4609 if ((ULONGLONG)verifyInfo->Length > bytesRemaining) { 4610 4611 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Verify request to invalid sector.\n")); 4612 FREE_POOL(srb) 4613 return STATUS_NONEXISTENT_SECTOR; 4614 } 4615 } 4616 4617 Context = ExAllocatePoolWithTag(NonPagedPoolNx, 4618 sizeof(DISK_VERIFY_WORKITEM_CONTEXT), 4619 DISK_TAG_WI_CONTEXT); 4620 if (Context) { 4621 4622 Context->Irp = Irp; 4623 Context->Srb = srb; 4624 Context->WorkItem = IoAllocateWorkItem(DeviceObject); 4625 4626 if (Context->WorkItem) { 4627 4628 // 4629 // Queue the work item and return. 4630 // 4631 4632 IoMarkIrpPending(Irp); 4633 4634 IoQueueWorkItem(Context->WorkItem, 4635 DiskIoctlVerifyThread, 4636 DelayedWorkQueue, 4637 Context); 4638 4639 return STATUS_PENDING; 4640 } 4641 FREE_POOL(Context); 4642 } 4643 FREE_POOL(srb) 4644 return STATUS_INSUFFICIENT_RESOURCES; 4645 } 4646 4647 NTSTATUS 4648 DiskIoctlReassignBlocks( 4649 IN PDEVICE_OBJECT DeviceObject, 4650 IN OUT PIRP Irp 4651 ) 4652 4653 /*++ 4654 4655 Routine Description: 4656 4657 This routine services IOCTL_DISK_REASSIGN_BLOCKS. This IOCTL 4658 allows the caller to remap the defective blocks to a new 4659 location on the disk. 4660 4661 This function must be called at IRQL < DISPATCH_LEVEL. 4662 4663 Arguments: 4664 4665 DeviceObject - Supplies the device object associated with this request. 4666 4667 Irp - The IRP to be processed 4668 4669 Return Value: 4670 4671 NTSTATUS code 4672 4673 --*/ 4674 4675 { 4676 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 4677 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 4678 NTSTATUS status; 4679 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer; 4680 PSCSI_REQUEST_BLOCK srb; 4681 PCDB cdb; 4682 ULONG bufferSize; 4683 ULONG blockNumber; 4684 ULONG blockCount; 4685 ULONG srbSize; 4686 PSTORAGE_REQUEST_BLOCK srbEx; 4687 PSTOR_ADDR_BTL8 storAddrBtl8; 4688 PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16; 4689 4690 // 4691 // This function must be called at less than dispatch level. 4692 // Fail if IRQL >= DISPATCH_LEVEL. 4693 // 4694 PAGED_CODE(); 4695 CHECK_IRQL(); 4696 4697 // 4698 // Validate the request. 4699 // 4700 4701 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 4702 4703 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(REASSIGN_BLOCKS)) { 4704 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Input buffer length mismatch.\n")); 4705 return STATUS_INFO_LENGTH_MISMATCH; 4706 } 4707 4708 // 4709 // Make sure we have some data in the input buffer. 4710 // 4711 4712 if (badBlocks->Count == 0) { 4713 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Invalid block count\n")); 4714 return STATUS_INVALID_PARAMETER; 4715 } 4716 4717 bufferSize = sizeof(REASSIGN_BLOCKS) + ((badBlocks->Count - 1) * sizeof(ULONG)); 4718 4719 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < bufferSize) { 4720 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Input buffer length mismatch for bad blocks.\n")); 4721 return STATUS_INFO_LENGTH_MISMATCH; 4722 } 4723 4724 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 4725 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; 4726 } else { 4727 srbSize = SCSI_REQUEST_BLOCK_SIZE; 4728 } 4729 srb = ExAllocatePoolWithTag(NonPagedPoolNx, 4730 srbSize, 4731 DISK_TAG_SRB); 4732 4733 if (srb == NULL) { 4734 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Unable to allocate memory.\n")); 4735 return STATUS_INSUFFICIENT_RESOURCES; 4736 } 4737 4738 RtlZeroMemory(srb, srbSize); 4739 4740 // 4741 // Build the data buffer to be transferred in the input buffer. 4742 // The format of the data to the device is: 4743 // 4744 // 2 bytes Reserved 4745 // 2 bytes Length 4746 // x * 4 btyes Block Address 4747 // 4748 // All values are big endian. 4749 // 4750 4751 badBlocks->Reserved = 0; 4752 blockCount = badBlocks->Count; 4753 4754 // 4755 // Convert # of entries to # of bytes. 4756 // 4757 4758 blockCount *= 4; 4759 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF); 4760 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00); 4761 4762 // 4763 // Convert back to number of entries. 4764 // 4765 4766 blockCount /= 4; 4767 4768 for (; blockCount > 0; blockCount--) { 4769 4770 blockNumber = badBlocks->BlockNumber[blockCount-1]; 4771 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1], (PFOUR_BYTE) &blockNumber); 4772 } 4773 4774 // 4775 // Build a SCSI SRB containing a SCSIOP_REASSIGN_BLOCKS cdb 4776 // 4777 4778 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 4779 srbEx = (PSTORAGE_REQUEST_BLOCK)srb; 4780 4781 // 4782 // Set up STORAGE_REQUEST_BLOCK fields 4783 // 4784 4785 srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); 4786 srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; 4787 srbEx->Signature = SRB_SIGNATURE; 4788 srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; 4789 srbEx->SrbLength = srbSize; 4790 srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 4791 srbEx->RequestPriority = IoGetIoPriorityHint(Irp); 4792 srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); 4793 srbEx->NumSrbExData = 1; 4794 4795 // Set timeout value. 4796 srbEx->TimeOutValue = fdoExtension->TimeOutValue; 4797 4798 // 4799 // Set up address fields 4800 // 4801 4802 storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); 4803 storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; 4804 storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; 4805 4806 // 4807 // Set up SCSI SRB extended data fields 4808 // 4809 4810 srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + 4811 sizeof(STOR_ADDR_BTL8); 4812 if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { 4813 srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); 4814 srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; 4815 srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; 4816 srbExDataCdb16->CdbLength = 6; 4817 4818 cdb = (PCDB)srbExDataCdb16->Cdb; 4819 } else { 4820 // Should not happen 4821 NT_ASSERT(FALSE); 4822 4823 FREE_POOL(srb); 4824 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Insufficient extended SRB size.\n")); 4825 return STATUS_INTERNAL_ERROR; 4826 } 4827 4828 } else { 4829 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 4830 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 4831 srb->CdbLength = 6; 4832 4833 // 4834 // Set timeout value. 4835 // 4836 4837 srb->TimeOutValue = fdoExtension->TimeOutValue; 4838 4839 cdb = (PCDB)srb->Cdb; 4840 } 4841 4842 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS; 4843 4844 status = ClassSendSrbSynchronous(DeviceObject, 4845 srb, 4846 badBlocks, 4847 bufferSize, 4848 TRUE); 4849 4850 FREE_POOL(srb); 4851 return status; 4852 } 4853 4854 NTSTATUS 4855 DiskIoctlReassignBlocksEx( 4856 IN PDEVICE_OBJECT DeviceObject, 4857 IN OUT PIRP Irp 4858 ) 4859 4860 /*++ 4861 4862 Routine Description: 4863 4864 This routine services IOCTL_DISK_REASSIGN_BLOCKS_EX. This IOCTL 4865 allows the caller to remap the defective blocks to a new 4866 location on the disk. The input buffer contains 8-byte LBAs. 4867 4868 This function must be called at IRQL < DISPATCH_LEVEL. 4869 4870 Arguments: 4871 4872 DeviceObject - Supplies the device object associated with this request. 4873 4874 Irp - The IRP to be processed 4875 4876 Return Value: 4877 4878 NTSTATUS code 4879 4880 --*/ 4881 4882 { 4883 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 4884 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 4885 NTSTATUS status; 4886 PREASSIGN_BLOCKS_EX badBlocks = Irp->AssociatedIrp.SystemBuffer; 4887 PSCSI_REQUEST_BLOCK srb; 4888 PCDB cdb; 4889 LARGE_INTEGER blockNumber; 4890 ULONG bufferSize; 4891 ULONG blockCount; 4892 ULONG srbSize; 4893 PSTORAGE_REQUEST_BLOCK srbEx; 4894 PSTOR_ADDR_BTL8 storAddrBtl8; 4895 PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16; 4896 4897 // 4898 // This function must be called at less than dispatch level. 4899 // Fail if IRQL >= DISPATCH_LEVEL. 4900 // 4901 PAGED_CODE(); 4902 CHECK_IRQL(); 4903 4904 // 4905 // Validate the request. 4906 // 4907 4908 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 4909 4910 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(REASSIGN_BLOCKS_EX)) { 4911 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Input buffer length mismatch.\n")); 4912 return STATUS_INFO_LENGTH_MISMATCH; 4913 } 4914 4915 // 4916 // Make sure we have some data in the input buffer. 4917 // 4918 4919 if (badBlocks->Count == 0) { 4920 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Invalid block count\n")); 4921 return STATUS_INVALID_PARAMETER; 4922 } 4923 4924 bufferSize = sizeof(REASSIGN_BLOCKS_EX) + ((badBlocks->Count - 1) * sizeof(LARGE_INTEGER)); 4925 4926 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < bufferSize) { 4927 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Input buffer length mismatch for bad blocks.\n")); 4928 return STATUS_INFO_LENGTH_MISMATCH; 4929 } 4930 4931 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 4932 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; 4933 } else { 4934 srbSize = SCSI_REQUEST_BLOCK_SIZE; 4935 } 4936 srb = ExAllocatePoolWithTag(NonPagedPoolNx, 4937 srbSize, 4938 DISK_TAG_SRB); 4939 4940 if (srb == NULL) { 4941 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Unable to allocate memory.\n")); 4942 return STATUS_INSUFFICIENT_RESOURCES; 4943 } 4944 4945 RtlZeroMemory(srb, srbSize); 4946 4947 // 4948 // Build the data buffer to be transferred in the input buffer. 4949 // The format of the data to the device is: 4950 // 4951 // 2 bytes Reserved 4952 // 2 bytes Length 4953 // x * 8 btyes Block Address 4954 // 4955 // All values are big endian. 4956 // 4957 4958 badBlocks->Reserved = 0; 4959 blockCount = badBlocks->Count; 4960 4961 // 4962 // Convert # of entries to # of bytes. 4963 // 4964 4965 blockCount *= 8; 4966 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF); 4967 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00); 4968 4969 // 4970 // Convert back to number of entries. 4971 // 4972 4973 blockCount /= 8; 4974 4975 for (; blockCount > 0; blockCount--) { 4976 4977 blockNumber = badBlocks->BlockNumber[blockCount-1]; 4978 REVERSE_BYTES_QUAD(&badBlocks->BlockNumber[blockCount-1], &blockNumber); 4979 } 4980 4981 // 4982 // Build a SCSI SRB containing a SCSIOP_REASSIGN_BLOCKS cdb 4983 // 4984 4985 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 4986 srbEx = (PSTORAGE_REQUEST_BLOCK)srb; 4987 4988 // 4989 // Set up STORAGE_REQUEST_BLOCK fields 4990 // 4991 4992 srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); 4993 srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; 4994 srbEx->Signature = SRB_SIGNATURE; 4995 srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; 4996 srbEx->SrbLength = srbSize; 4997 srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 4998 srbEx->RequestPriority = IoGetIoPriorityHint(Irp); 4999 srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); 5000 srbEx->NumSrbExData = 1; 5001 5002 // Set timeout value. 5003 srbEx->TimeOutValue = fdoExtension->TimeOutValue; 5004 5005 // 5006 // Set up address fields 5007 // 5008 5009 storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); 5010 storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; 5011 storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; 5012 5013 // 5014 // Set up SCSI SRB extended data fields 5015 // 5016 5017 srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + 5018 sizeof(STOR_ADDR_BTL8); 5019 if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { 5020 srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); 5021 srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; 5022 srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; 5023 srbExDataCdb16->CdbLength = 6; 5024 5025 cdb = (PCDB)srbExDataCdb16->Cdb; 5026 } else { 5027 // Should not happen 5028 NT_ASSERT(FALSE); 5029 5030 FREE_POOL(srb); 5031 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Insufficient extended SRB size.\n")); 5032 return STATUS_INTERNAL_ERROR; 5033 } 5034 5035 } else { 5036 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 5037 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 5038 srb->CdbLength = 6; 5039 5040 // 5041 // Set timeout value. 5042 // 5043 5044 srb->TimeOutValue = fdoExtension->TimeOutValue; 5045 5046 cdb = (PCDB)srb->Cdb; 5047 } 5048 5049 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS; 5050 cdb->CDB6GENERIC.CommandUniqueBits = 1; // LONGLBA 5051 5052 status = ClassSendSrbSynchronous(DeviceObject, 5053 srb, 5054 badBlocks, 5055 bufferSize, 5056 TRUE); 5057 5058 FREE_POOL(srb); 5059 return status; 5060 } 5061 5062 NTSTATUS 5063 DiskIoctlIsWritable( 5064 IN PDEVICE_OBJECT DeviceObject, 5065 IN OUT PIRP Irp 5066 ) 5067 5068 /*++ 5069 5070 Routine Description: 5071 5072 This routine services IOCTL_DISK_IS_WRITABLE. This function 5073 returns whether the disk is writable. If the device is not 5074 writable then STATUS_MEDIA_WRITE_PROTECTED will be returned. 5075 5076 This function must be called at IRQL < DISPATCH_LEVEL. 5077 5078 Arguments: 5079 5080 DeviceObject - Supplies the device object associated with this request. 5081 5082 Irp - The IRP to be processed 5083 5084 Return Value: 5085 5086 NTSTATUS code 5087 5088 --*/ 5089 5090 { 5091 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 5092 NTSTATUS status = STATUS_SUCCESS; 5093 5094 PMODE_PARAMETER_HEADER modeData; 5095 PSCSI_REQUEST_BLOCK srb; 5096 PCDB cdb = NULL; 5097 ULONG modeLength; 5098 ULONG retries = 4; 5099 ULONG srbSize; 5100 PSTORAGE_REQUEST_BLOCK srbEx; 5101 PSTOR_ADDR_BTL8 storAddrBtl8; 5102 PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16; 5103 5104 // 5105 // This function must be called at less than dispatch level. 5106 // Fail if IRQL >= DISPATCH_LEVEL. 5107 // 5108 PAGED_CODE(); 5109 CHECK_IRQL(); 5110 5111 // 5112 // Validate the request. 5113 // 5114 5115 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 5116 5117 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 5118 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; 5119 } else { 5120 srbSize = SCSI_REQUEST_BLOCK_SIZE; 5121 } 5122 srb = ExAllocatePoolWithTag(NonPagedPoolNx, 5123 srbSize, 5124 DISK_TAG_SRB); 5125 5126 if (srb == NULL) { 5127 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: Unable to allocate memory.\n")); 5128 return STATUS_INSUFFICIENT_RESOURCES; 5129 } 5130 5131 RtlZeroMemory(srb, srbSize); 5132 5133 // 5134 // Allocate memory for a mode header and then some 5135 // for port drivers that need to convert to MODE10 5136 // or always return the MODE_PARAMETER_BLOCK (even 5137 // when memory was not allocated for this purpose) 5138 // 5139 5140 modeLength = MODE_DATA_SIZE; 5141 modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, 5142 modeLength, 5143 DISK_TAG_MODE_DATA); 5144 5145 if (modeData == NULL) { 5146 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: Unable to allocate memory.\n")); 5147 FREE_POOL(srb); 5148 return STATUS_INSUFFICIENT_RESOURCES; 5149 } 5150 5151 RtlZeroMemory(modeData, modeLength); 5152 5153 // 5154 // Build the MODE SENSE CDB 5155 // 5156 5157 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 5158 srbEx = (PSTORAGE_REQUEST_BLOCK)srb; 5159 5160 // 5161 // Set up STORAGE_REQUEST_BLOCK fields 5162 // 5163 5164 srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); 5165 srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; 5166 srbEx->Signature = SRB_SIGNATURE; 5167 srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1; 5168 srbEx->SrbLength = srbSize; 5169 srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 5170 srbEx->RequestPriority = IoGetIoPriorityHint(Irp); 5171 srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK); 5172 srbEx->NumSrbExData = 1; 5173 5174 // Set timeout value. 5175 srbEx->TimeOutValue = fdoExtension->TimeOutValue; 5176 5177 // 5178 // Set up address fields 5179 // 5180 5181 storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset); 5182 storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8; 5183 storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; 5184 5185 // 5186 // Set up SCSI SRB extended data fields 5187 // 5188 5189 srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) + 5190 sizeof(STOR_ADDR_BTL8); 5191 if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) { 5192 srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]); 5193 srbExDataCdb16->Type = SrbExDataTypeScsiCdb16; 5194 srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH; 5195 srbExDataCdb16->CdbLength = 6; 5196 5197 cdb = (PCDB)srbExDataCdb16->Cdb; 5198 } else { 5199 // Should not happen 5200 NT_ASSERT(FALSE); 5201 5202 FREE_POOL(srb); 5203 FREE_POOL(modeData); 5204 return STATUS_INTERNAL_ERROR; 5205 } 5206 5207 } else { 5208 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 5209 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 5210 srb->CdbLength = 6; 5211 5212 // 5213 // Set timeout value. 5214 // 5215 5216 srb->TimeOutValue = fdoExtension->TimeOutValue; 5217 5218 cdb = (PCDB)srb->Cdb; 5219 } 5220 5221 // 5222 // Page code of 0x3F will return all pages. 5223 // This command could fail if the data to be returned is 5224 // more than 256 bytes. In which case, we should get only 5225 // the caching page since we only need the block descriptor. 5226 // DiskFdoProcessError will change the page code to 5227 // MODE_PAGE_CACHING if there is an error. 5228 // 5229 5230 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; 5231 cdb->MODE_SENSE.PageCode = MODE_SENSE_RETURN_ALL; 5232 cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength; 5233 5234 while (retries != 0) { 5235 5236 status = ClassSendSrbSynchronous(DeviceObject, 5237 srb, 5238 modeData, 5239 modeLength, 5240 FALSE); 5241 5242 if (status != STATUS_VERIFY_REQUIRED) { 5243 if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) { 5244 status = STATUS_SUCCESS; 5245 } 5246 break; 5247 } 5248 retries--; 5249 } 5250 5251 if (NT_SUCCESS(status)) { 5252 5253 if (TEST_FLAG(modeData->DeviceSpecificParameter, MODE_DSP_WRITE_PROTECT)) { 5254 status = STATUS_MEDIA_WRITE_PROTECTED; 5255 } 5256 } 5257 5258 FREE_POOL(srb); 5259 FREE_POOL(modeData); 5260 return status; 5261 } 5262 5263 NTSTATUS 5264 DiskIoctlSetVerify( 5265 IN PDEVICE_OBJECT DeviceObject, 5266 IN OUT PIRP Irp 5267 ) 5268 5269 /*++ 5270 5271 Routine Description: 5272 5273 This routine services IOCTL_DISK_INTERNAL_SET_VERIFY. 5274 This is an internal function used to set the DO_VERIFY_VOLUME 5275 device object flag. Only a kernel mode component can send this 5276 IOCTL. 5277 5278 Arguments: 5279 5280 DeviceObject - Supplies the device object associated with this request. 5281 5282 Irp - The IRP to be processed 5283 5284 Return Value: 5285 5286 NTSTATUS code 5287 5288 --*/ 5289 5290 { 5291 NTSTATUS status = STATUS_NOT_SUPPORTED; 5292 5293 // 5294 // Validate the request. 5295 // 5296 5297 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSetVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 5298 5299 // 5300 // If the caller is kernel mode, set the verify bit. 5301 // 5302 5303 if (Irp->RequestorMode == KernelMode) { 5304 5305 SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME); 5306 status = STATUS_SUCCESS; 5307 5308 } 5309 return status; 5310 } 5311 5312 NTSTATUS 5313 DiskIoctlClearVerify( 5314 IN PDEVICE_OBJECT DeviceObject, 5315 IN OUT PIRP Irp 5316 ) 5317 5318 /*++ 5319 5320 Routine Description: 5321 5322 This routine services IOCTL_DISK_INTERNAL_CLEAR_VERIFY. 5323 This is an internal function used to clear the DO_VERIFY_VOLUME 5324 device object flag. Only a kernel mode component can send this 5325 IOCTL. 5326 5327 Arguments: 5328 5329 DeviceObject - Supplies the device object associated with this request. 5330 5331 Irp - The IRP to be processed 5332 5333 Return Value: 5334 5335 NTSTATUS code 5336 5337 --*/ 5338 5339 { 5340 NTSTATUS status = STATUS_NOT_SUPPORTED; 5341 5342 // 5343 // Validate the request. 5344 // 5345 5346 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlClearVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 5347 5348 // 5349 // If the caller is kernel mode, set the verify bit. 5350 // 5351 5352 if (Irp->RequestorMode == KernelMode) { 5353 5354 CLEAR_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME); 5355 status = STATUS_SUCCESS; 5356 5357 } 5358 return status; 5359 } 5360 5361 NTSTATUS 5362 DiskIoctlUpdateDriveSize( 5363 IN PDEVICE_OBJECT DeviceObject, 5364 IN OUT PIRP Irp 5365 ) 5366 5367 /*++ 5368 5369 Routine Description: 5370 5371 This routine services IOCTL_DISK_UPDATE_DRIVE_SIZE. 5372 This function is used to inform the disk driver to update 5373 the device geometry information cached in the device extension 5374 This is normally initiated from the drivers layers above disk 5375 driver. 5376 5377 This function must be called at IRQL < DISPATCH_LEVEL. 5378 5379 Arguments: 5380 5381 DeviceObject - Supplies the device object associated with this request. 5382 5383 Irp - The IRP to be processed 5384 5385 Return Value: 5386 5387 NTSTATUS code 5388 5389 --*/ 5390 5391 { 5392 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 5393 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 5394 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); 5395 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 5396 TARGET_DEVICE_CUSTOM_NOTIFICATION Notification = {0}; 5397 NTSTATUS status; 5398 5399 // 5400 // This function must be called at less than dispatch level. 5401 // Fail if IRQL >= DISPATCH_LEVEL. 5402 // 5403 PAGED_CODE(); 5404 CHECK_IRQL(); 5405 5406 // 5407 // Validate the request. 5408 // 5409 5410 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlUpdateDriveSize: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 5411 5412 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) { 5413 5414 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlUpdateDriveSize: Output buffer too small.\n")); 5415 return STATUS_BUFFER_TOO_SMALL; 5416 } 5417 5418 status = DiskReadDriveCapacity(DeviceObject); 5419 5420 // 5421 // Note whether the drive is ready. 5422 // 5423 5424 diskData->ReadyStatus = status; 5425 5426 if (NT_SUCCESS(status)) { 5427 5428 // 5429 // Copy drive geometry information from the device extension. 5430 // 5431 5432 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, 5433 &(fdoExtension->DiskGeometry), 5434 sizeof(DISK_GEOMETRY)); 5435 5436 if (((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector == 0) { 5437 ((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector = 512; 5438 } 5439 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY); 5440 status = STATUS_SUCCESS; 5441 5442 // 5443 // Notify everyone that the disk layout may have changed 5444 // 5445 5446 Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE; 5447 Notification.Version = 1; 5448 Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer); 5449 Notification.FileObject = NULL; 5450 Notification.NameBufferOffset = -1; 5451 5452 IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo, 5453 &Notification, 5454 NULL, 5455 NULL); 5456 } 5457 return status; 5458 } 5459 5460 NTSTATUS 5461 DiskIoctlGetVolumeDiskExtents( 5462 IN PDEVICE_OBJECT DeviceObject, 5463 IN OUT PIRP Irp 5464 ) 5465 5466 /*++ 5467 5468 Routine Description: 5469 5470 This routine services IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 5471 and IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN. This function 5472 returns the physical location of a volume. 5473 5474 This function must be called at IRQL < DISPATCH_LEVEL. 5475 5476 Arguments: 5477 5478 DeviceObject - Supplies the device object associated with this request. 5479 5480 Irp - The IRP to be processed 5481 5482 Return Value: 5483 5484 NTSTATUS code 5485 5486 --*/ 5487 5488 { 5489 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 5490 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); 5491 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 5492 NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; 5493 5494 // 5495 // This function must be called at less than dispatch level. 5496 // Fail if IRQL >= DISPATCH_LEVEL. 5497 // 5498 PAGED_CODE(); 5499 CHECK_IRQL(); 5500 5501 // 5502 // Validate the request. 5503 // 5504 5505 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetVolumeDiskExtents: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 5506 5507 5508 if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) { 5509 5510 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(VOLUME_DISK_EXTENTS)) { 5511 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetVolumeDiskExtents: Output buffer too small.\n")); 5512 return STATUS_BUFFER_TOO_SMALL; 5513 } 5514 5515 status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject); 5516 5517 // 5518 // Note whether the drive is ready. 5519 // 5520 5521 diskData->ReadyStatus = status; 5522 5523 if (NT_SUCCESS(status)) { 5524 5525 PVOLUME_DISK_EXTENTS pVolExt = (PVOLUME_DISK_EXTENTS)Irp->AssociatedIrp.SystemBuffer; 5526 5527 pVolExt->NumberOfDiskExtents = 1; 5528 pVolExt->Extents[0].DiskNumber = commonExtension->PartitionZeroExtension->DeviceNumber; 5529 pVolExt->Extents[0].StartingOffset = commonExtension->StartingOffset; 5530 pVolExt->Extents[0].ExtentLength = commonExtension->PartitionLength; 5531 5532 Irp->IoStatus.Information = sizeof(VOLUME_DISK_EXTENTS); 5533 } 5534 } 5535 5536 return status; 5537 } 5538 5539 NTSTATUS 5540 DiskIoctlSmartGetVersion( 5541 IN PDEVICE_OBJECT DeviceObject, 5542 IN OUT PIRP Irp 5543 ) 5544 5545 /*++ 5546 5547 Routine Description: 5548 5549 This routine services SMART_GET_VERSION. It returns the 5550 SMART version information. 5551 5552 This function must be called at IRQL < DISPATCH_LEVEL. 5553 5554 Arguments: 5555 5556 DeviceObject - Supplies the device object associated with this request. 5557 5558 Irp - The IRP to be processed 5559 5560 Return Value: 5561 5562 NTSTATUS code 5563 5564 --*/ 5565 5566 { 5567 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 5568 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 5569 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); 5570 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 5571 NTSTATUS status; 5572 5573 PGETVERSIONINPARAMS versionParams; 5574 PSRB_IO_CONTROL srbControl; 5575 IO_STATUS_BLOCK ioStatus = { 0 }; 5576 PUCHAR buffer; 5577 5578 // 5579 // This function must be called at less than dispatch level. 5580 // Fail if IRQL >= DISPATCH_LEVEL. 5581 // 5582 PAGED_CODE(); 5583 CHECK_IRQL(); 5584 5585 // 5586 // Validate the request. 5587 // 5588 5589 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSmartGetVersion: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 5590 5591 5592 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GETVERSIONINPARAMS)) { 5593 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartGetVersion: Output buffer too small.\n")); 5594 return STATUS_BUFFER_TOO_SMALL; 5595 } 5596 5597 srbControl = ExAllocatePoolWithTag(NonPagedPoolNx, 5598 sizeof(SRB_IO_CONTROL) + 5599 sizeof(GETVERSIONINPARAMS), 5600 DISK_TAG_SMART); 5601 5602 if (srbControl == NULL) { 5603 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartGetVersion: Unable to allocate memory.\n")); 5604 return STATUS_INSUFFICIENT_RESOURCES; 5605 } 5606 5607 RtlZeroMemory(srbControl, sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS)); 5608 5609 // 5610 // fill in srbControl fields 5611 // 5612 5613 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); 5614 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); 5615 srbControl->Timeout = fdoExtension->TimeOutValue; 5616 srbControl->Length = sizeof(GETVERSIONINPARAMS); 5617 srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION; 5618 5619 // 5620 // Point to the 'buffer' portion of the SRB_CONTROL 5621 // 5622 5623 buffer = (PUCHAR)srbControl + srbControl->HeaderLength; 5624 5625 // 5626 // Ensure correct target is set in the cmd parameters. 5627 // 5628 5629 versionParams = (PGETVERSIONINPARAMS)buffer; 5630 versionParams->bIDEDeviceMap = diskData->ScsiAddress.TargetId; 5631 5632 ClassSendDeviceIoControlSynchronous( 5633 IOCTL_SCSI_MINIPORT, 5634 commonExtension->LowerDeviceObject, 5635 srbControl, 5636 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS), 5637 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS), 5638 FALSE, 5639 &ioStatus); 5640 5641 status = ioStatus.Status; 5642 5643 // 5644 // If successful, copy the data received into the output buffer. 5645 // This should only fail in the event that the IDE driver is older 5646 // than this driver. 5647 // 5648 5649 if (NT_SUCCESS(status)) { 5650 5651 buffer = (PUCHAR)srbControl + srbControl->HeaderLength; 5652 5653 RtlMoveMemory (Irp->AssociatedIrp.SystemBuffer, buffer, sizeof(GETVERSIONINPARAMS)); 5654 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS); 5655 } 5656 5657 FREE_POOL(srbControl); 5658 5659 return status; 5660 } 5661 5662 NTSTATUS 5663 DiskIoctlSmartReceiveDriveData( 5664 IN PDEVICE_OBJECT DeviceObject, 5665 IN OUT PIRP Irp 5666 ) 5667 5668 /*++ 5669 5670 Routine Description: 5671 5672 This routine services SMART_RCV_DRIVE_DATA. This function 5673 allows the caller to read SMART information from the device. 5674 5675 This function must be called at IRQL < DISPATCH_LEVEL. 5676 5677 Arguments: 5678 5679 DeviceObject - Supplies the device object associated with this request. 5680 5681 Irp - The IRP to be processed 5682 5683 Return Value: 5684 5685 NTSTATUS code 5686 5687 --*/ 5688 5689 { 5690 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 5691 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 5692 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); 5693 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 5694 NTSTATUS status = STATUS_INVALID_PARAMETER; 5695 5696 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer); 5697 PSRB_IO_CONTROL srbControl; 5698 IO_STATUS_BLOCK ioStatus = { 0 }; 5699 ULONG controlCode = 0; 5700 PUCHAR buffer; 5701 PIRP irp2; 5702 KEVENT event; 5703 ULONG length = 0; 5704 5705 // 5706 // This function must be called at less than dispatch level. 5707 // Fail if IRQL >= DISPATCH_LEVEL. 5708 // 5709 PAGED_CODE(); 5710 CHECK_IRQL(); 5711 5712 // 5713 // Validate the request. 5714 // 5715 5716 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 5717 5718 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < (sizeof(SENDCMDINPARAMS) - 1)) { 5719 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Input buffer length invalid.\n")); 5720 return STATUS_INVALID_PARAMETER; 5721 } 5722 5723 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) { 5724 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Output buffer too small.\n")); 5725 return STATUS_BUFFER_TOO_SMALL; 5726 } 5727 5728 // 5729 // Create notification event object to be used to signal the 5730 // request completion. 5731 // 5732 5733 KeInitializeEvent(&event, NotificationEvent, FALSE); 5734 5735 // 5736 // use controlCode as a sort of 'STATUS_SUCCESS' to see if it's 5737 // a valid request type 5738 // 5739 5740 if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) { 5741 5742 length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); 5743 controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY; 5744 5745 } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) { 5746 5747 switch (cmdInParameters->irDriveRegs.bFeaturesReg) { 5748 5749 case READ_ATTRIBUTES: 5750 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; 5751 length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); 5752 break; 5753 5754 case READ_THRESHOLDS: 5755 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; 5756 length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); 5757 break; 5758 5759 case SMART_READ_LOG: { 5760 5761 if (diskData->FailurePredictionCapability != FailurePredictionSmart) { 5762 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: SMART failure prediction not supported.\n")); 5763 return STATUS_INVALID_DEVICE_REQUEST; 5764 } 5765 5766 // 5767 // Calculate additional length based on number of sectors to be read. 5768 // Then verify the output buffer is large enough. 5769 // 5770 5771 length = cmdInParameters->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE; 5772 5773 // 5774 // Ensure at least 1 sector is going to be read 5775 // 5776 if (length == 0) { 5777 return STATUS_INVALID_PARAMETER; 5778 } 5779 5780 length += max(sizeof(SENDCMDOUTPARAMS), sizeof(SENDCMDINPARAMS)); 5781 5782 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < length - 1) { 5783 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Output buffer too small for SMART_READ_LOG.\n")); 5784 return STATUS_BUFFER_TOO_SMALL; 5785 } 5786 5787 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_LOG; 5788 break; 5789 } 5790 } 5791 } 5792 5793 if (controlCode == 0) { 5794 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Invalid request.\n")); 5795 return STATUS_INVALID_PARAMETER; 5796 } 5797 5798 srbControl = ExAllocatePoolWithTag(NonPagedPoolNx, 5799 sizeof(SRB_IO_CONTROL) + length, 5800 DISK_TAG_SMART); 5801 5802 if (srbControl == NULL) { 5803 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Unable to allocate memory.\n")); 5804 return STATUS_INSUFFICIENT_RESOURCES; 5805 } 5806 5807 // 5808 // fill in srbControl fields 5809 // 5810 5811 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); 5812 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); 5813 srbControl->Timeout = fdoExtension->TimeOutValue; 5814 srbControl->Length = length; 5815 srbControl->ControlCode = controlCode; 5816 5817 // 5818 // Point to the 'buffer' portion of the SRB_CONTROL 5819 // 5820 5821 buffer = (PUCHAR)srbControl + srbControl->HeaderLength; 5822 5823 // 5824 // Ensure correct target is set in the cmd parameters. 5825 // 5826 5827 cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId; 5828 5829 // 5830 // Copy the IOCTL parameters to the srb control buffer area. 5831 // 5832 5833 RtlMoveMemory(buffer, 5834 Irp->AssociatedIrp.SystemBuffer, 5835 sizeof(SENDCMDINPARAMS) - 1); 5836 5837 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT, 5838 commonExtension->LowerDeviceObject, 5839 srbControl, 5840 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1, 5841 srbControl, 5842 sizeof(SRB_IO_CONTROL) + length, 5843 FALSE, 5844 &event, 5845 &ioStatus); 5846 5847 if (irp2 == NULL) { 5848 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Unable to allocate IRP.\n")); 5849 FREE_POOL(srbControl); 5850 return STATUS_INSUFFICIENT_RESOURCES; 5851 } 5852 5853 // 5854 // Call the port driver with the request and wait for it to complete. 5855 // 5856 5857 status = IoCallDriver(commonExtension->LowerDeviceObject, irp2); 5858 5859 if (status == STATUS_PENDING) { 5860 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 5861 status = ioStatus.Status; 5862 } 5863 5864 // 5865 // Copy the data received into the output buffer. Since the status buffer 5866 // contains error information also, always perform this copy. IO will 5867 // either pass this back to the app, or zero it, in case of error. 5868 // 5869 5870 buffer = (PUCHAR)srbControl + srbControl->HeaderLength; 5871 5872 if (NT_SUCCESS(status)) { 5873 5874 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length - 1); 5875 Irp->IoStatus.Information = length - 1; 5876 5877 } else { 5878 5879 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, (sizeof(SENDCMDOUTPARAMS) - 1)); 5880 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1; 5881 5882 } 5883 5884 FREE_POOL(srbControl); 5885 5886 return status; 5887 } 5888 5889 NTSTATUS 5890 DiskIoctlSmartSendDriveCommand( 5891 IN PDEVICE_OBJECT DeviceObject, 5892 IN OUT PIRP Irp 5893 ) 5894 5895 /*++ 5896 5897 Routine Description: 5898 5899 This routine services SMART_SEND_DRIVE_COMMAND. This function 5900 allows the caller to send SMART commands to the device. 5901 5902 This function must be called at IRQL < DISPATCH_LEVEL. 5903 5904 Arguments: 5905 5906 DeviceObject - Supplies the device object associated with this request. 5907 5908 Irp - The IRP to be processed 5909 5910 Return Value: 5911 5912 NTSTATUS code 5913 5914 --*/ 5915 5916 { 5917 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 5918 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 5919 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); 5920 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); 5921 NTSTATUS status = STATUS_INVALID_PARAMETER; 5922 5923 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer); 5924 PSRB_IO_CONTROL srbControl; 5925 IO_STATUS_BLOCK ioStatus = { 0 }; 5926 ULONG controlCode = 0; 5927 PUCHAR buffer; 5928 PIRP irp2; 5929 KEVENT event; 5930 ULONG length = 0; 5931 5932 // 5933 // This function must be called at less than dispatch level. 5934 // Fail if IRQL >= DISPATCH_LEVEL. 5935 // 5936 PAGED_CODE(); 5937 CHECK_IRQL(); 5938 5939 // 5940 // Validate the request. 5941 // 5942 5943 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: DeviceObject %p Irp %p\n", DeviceObject, Irp)); 5944 5945 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < (sizeof(SENDCMDINPARAMS) - 1)) { 5946 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Input buffer size invalid.\n")); 5947 return STATUS_INVALID_PARAMETER; 5948 } 5949 5950 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(SENDCMDOUTPARAMS) - 1)) { 5951 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Output buffer too small.\n")); 5952 return STATUS_BUFFER_TOO_SMALL; 5953 } 5954 5955 // 5956 // Create notification event object to be used to signal the 5957 // request completion. 5958 // 5959 5960 KeInitializeEvent(&event, NotificationEvent, FALSE); 5961 5962 if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) { 5963 5964 switch (cmdInParameters->irDriveRegs.bFeaturesReg) { 5965 5966 case SMART_WRITE_LOG: { 5967 5968 if (diskData->FailurePredictionCapability != FailurePredictionSmart) { 5969 5970 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: SMART failure prediction not supported.\n")); 5971 return STATUS_INVALID_DEVICE_REQUEST; 5972 } 5973 5974 // 5975 // Calculate additional length based on number of sectors to be written. 5976 // Then verify the input buffer is large enough. 5977 // 5978 5979 length = cmdInParameters->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE; 5980 5981 // 5982 // Ensure at least 1 sector is going to be written 5983 // 5984 5985 if (length == 0) { 5986 return STATUS_INVALID_PARAMETER; 5987 } 5988 5989 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 5990 (sizeof(SENDCMDINPARAMS) - 1) + length) { 5991 5992 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Input buffer too small for SMART_WRITE_LOG.\n")); 5993 return STATUS_BUFFER_TOO_SMALL; 5994 } 5995 5996 controlCode = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG; 5997 break; 5998 } 5999 6000 case ENABLE_SMART: 6001 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART; 6002 break; 6003 6004 case DISABLE_SMART: 6005 controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART; 6006 break; 6007 6008 case RETURN_SMART_STATUS: 6009 6010 // 6011 // Ensure bBuffer is at least 2 bytes (to hold the values of 6012 // cylinderLow and cylinderHigh). 6013 // 6014 6015 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 6016 (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) { 6017 6018 return STATUS_BUFFER_TOO_SMALL; 6019 break; 6020 } 6021 6022 controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS; 6023 length = sizeof(IDEREGS); 6024 break; 6025 6026 case ENABLE_DISABLE_AUTOSAVE: 6027 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; 6028 break; 6029 6030 case SAVE_ATTRIBUTE_VALUES: 6031 controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; 6032 break; 6033 6034 case EXECUTE_OFFLINE_DIAGS: 6035 // 6036 // Validate that this is an ok self test command 6037 // 6038 if (DiskIsValidSmartSelfTest(cmdInParameters->irDriveRegs.bSectorNumberReg)) { 6039 6040 controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; 6041 } 6042 break; 6043 6044 case ENABLE_DISABLE_AUTO_OFFLINE: 6045 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE; 6046 break; 6047 } 6048 } 6049 6050 if (controlCode == 0) { 6051 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Invalid request.\n")); 6052 return STATUS_INVALID_PARAMETER; 6053 } 6054 6055 length += max(sizeof(SENDCMDOUTPARAMS), sizeof(SENDCMDINPARAMS)); 6056 srbControl = ExAllocatePoolWithTag(NonPagedPoolNx, 6057 sizeof(SRB_IO_CONTROL) + length, 6058 DISK_TAG_SMART); 6059 6060 if (srbControl == NULL) { 6061 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Unable to allocate memory.\n")); 6062 return STATUS_INSUFFICIENT_RESOURCES; 6063 } 6064 6065 // 6066 // fill in srbControl fields 6067 // 6068 6069 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); 6070 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); 6071 srbControl->Timeout = fdoExtension->TimeOutValue; 6072 srbControl->Length = length; 6073 srbControl->ControlCode = controlCode; 6074 6075 // 6076 // Point to the 'buffer' portion of the SRB_CONTROL 6077 // 6078 6079 buffer = (PUCHAR)srbControl + srbControl->HeaderLength; 6080 6081 // 6082 // Ensure correct target is set in the cmd parameters. 6083 // 6084 6085 cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId; 6086 6087 // 6088 // Copy the IOCTL parameters to the srb control buffer area. 6089 // 6090 6091 if (cmdInParameters->irDriveRegs.bFeaturesReg == SMART_WRITE_LOG) { 6092 RtlMoveMemory(buffer, 6093 Irp->AssociatedIrp.SystemBuffer, 6094 sizeof(SENDCMDINPARAMS) - 1 + 6095 cmdInParameters->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE); 6096 } else { 6097 RtlMoveMemory(buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1); 6098 } 6099 6100 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT, 6101 commonExtension->LowerDeviceObject, 6102 srbControl, 6103 sizeof(SRB_IO_CONTROL) + length, 6104 srbControl, 6105 sizeof(SRB_IO_CONTROL) + length, 6106 FALSE, 6107 &event, 6108 &ioStatus); 6109 6110 if (irp2 == NULL) { 6111 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Unable to allocate IRP.\n")); 6112 FREE_POOL(srbControl); 6113 return STATUS_INSUFFICIENT_RESOURCES; 6114 } 6115 6116 // 6117 // Call the port driver with the request and wait for it to complete. 6118 // 6119 6120 status = IoCallDriver(commonExtension->LowerDeviceObject, irp2); 6121 6122 if (status == STATUS_PENDING) { 6123 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 6124 status = ioStatus.Status; 6125 } 6126 6127 // 6128 // Copy the data received into the output buffer. Since the status buffer 6129 // contains error information also, always perform this copy. IO will 6130 // either pass this back to the app, or zero it, in case of error. 6131 // 6132 6133 buffer = (PUCHAR)srbControl + srbControl->HeaderLength; 6134 6135 // 6136 // Update the return buffer size based on the sub-command. 6137 // 6138 6139 if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) { 6140 length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS); 6141 } else { 6142 length = sizeof(SENDCMDOUTPARAMS) - 1; 6143 } 6144 6145 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length); 6146 Irp->IoStatus.Information = length; 6147 6148 FREE_POOL(srbControl); 6149 6150 return status; 6151 } 6152 6153 6154 VOID 6155 DiskEtwEnableCallback ( 6156 _In_ LPCGUID SourceId, 6157 _In_ ULONG IsEnabled, 6158 _In_ UCHAR Level, 6159 _In_ ULONGLONG MatchAnyKeyword, 6160 _In_ ULONGLONG MatchAllKeyword, 6161 _In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData, 6162 _In_opt_ PVOID CallbackContext 6163 ) 6164 /*+++ 6165 6166 Routine Description: 6167 6168 This routine is the enable callback routine for ETW. It gets called when 6169 tracing is enabled or disabled for our provider. 6170 6171 Arguments: 6172 6173 As per the ETW callback. 6174 6175 Return Value: 6176 6177 None. 6178 --*/ 6179 6180 { 6181 // 6182 // Initialize locals. 6183 // 6184 UNREFERENCED_PARAMETER(SourceId); 6185 UNREFERENCED_PARAMETER(Level); 6186 UNREFERENCED_PARAMETER(MatchAnyKeyword); 6187 UNREFERENCED_PARAMETER(MatchAllKeyword); 6188 UNREFERENCED_PARAMETER(FilterData); 6189 UNREFERENCED_PARAMETER(CallbackContext); 6190 6191 // 6192 // Set the ETW tracing enable state. 6193 // 6194 DiskETWEnabled = IsEnabled ? TRUE : FALSE; 6195 6196 return; 6197 } 6198 6199 6200