1 /* 2 * PROJECT: ReactOS Storage Stack 3 * LICENSE: DDK - see license.txt in the root dir 4 * FILE: drivers/storage/disk/disk.c 5 * PURPOSE: Disk class driver 6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK 7 */ 8 9 #include <ntddk.h> 10 #include <ntdddisk.h> 11 #include <scsi.h> 12 #include <ntddscsi.h> 13 #include <mountdev.h> 14 #include <mountmgr.h> 15 #include <ntiologc.h> 16 #include <include/class2.h> 17 #include <stdio.h> 18 19 #define NDEBUG 20 #include <debug.h> 21 22 23 #ifdef POOL_TAGGING 24 #ifdef ExAllocatePool 25 #undef ExAllocatePool 26 #endif 27 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'DscS') 28 #endif 29 30 typedef enum { 31 NotInitialized, 32 Initializing, 33 Initialized 34 } PARTITION_LIST_STATE; 35 36 // 37 // Disk device data 38 // 39 40 typedef struct _DISK_DATA { 41 42 // 43 // Partition chain 44 // 45 46 PDEVICE_EXTENSION NextPartition; 47 48 // 49 // Disk signature (from MBR) 50 // 51 52 ULONG Signature; 53 54 // 55 // MBR checksum 56 // 57 58 ULONG MbrCheckSum; 59 60 // 61 // Number of hidden sectors for BPB. 62 // 63 64 ULONG HiddenSectors; 65 66 // 67 // Partition number of this device object 68 // 69 // This field is set during driver initialization or when the partition 70 // is created to identify a partition to the system. 71 // 72 73 ULONG PartitionNumber; 74 75 // 76 // This field is the ordinal of a partition as it appears on a disk. 77 // 78 79 ULONG PartitionOrdinal; 80 81 // 82 // Partition type of this device object 83 // 84 // This field is set by: 85 // 86 // 1) Initially set according to the partition list entry partition 87 // type returned by IoReadPartitionTable. 88 // 89 // 2) Subsequently set by the IOCTL_DISK_SET_PARTITION_INFORMATION 90 // I/O control function when IoSetPartitionInformation function 91 // successfully updates the partition type on the disk. 92 // 93 94 UCHAR PartitionType; 95 96 // 97 // Boot indicator - indicates whether this partition is a bootable (active) 98 // partition for this device 99 // 100 // This field is set according to the partition list entry boot indicator 101 // returned by IoReadPartitionTable. 102 // 103 104 BOOLEAN BootIndicator; 105 106 // 107 // DriveNotReady - indicates that the this device is currently not ready 108 // because there is no media in the device. 109 // 110 111 BOOLEAN DriveNotReady; 112 113 // 114 // State of PartitionList initialization 115 // 116 117 PARTITION_LIST_STATE PartitionListState; 118 119 #ifdef __REACTOS__ 120 // 121 // HACK so that we can use NT5+ NTOS functions with this NT4 driver 122 // for removable devices and avoid an infinite recursive loop between 123 // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable(). 124 // 125 ULONG UpdateRemovableGeometryCount; 126 #endif 127 128 } DISK_DATA, *PDISK_DATA; 129 130 // 131 // Define a general structure of identifying disk controllers with bad 132 // hardware. 133 // 134 135 typedef struct _BAD_CONTROLLER_INFORMATION { 136 PCHAR InquiryString; 137 BOOLEAN DisableTaggedQueuing; 138 BOOLEAN DisableSynchronousTransfers; 139 BOOLEAN DisableDisconnects; 140 BOOLEAN DisableWriteCache; 141 }BAD_CONTROLLER_INFORMATION, *PBAD_CONTROLLER_INFORMATION; 142 143 BAD_CONTROLLER_INFORMATION const ScsiDiskBadControllers[] = { 144 { "TOSHIBA MK538FB 60", TRUE, FALSE, FALSE, FALSE }, 145 { "CONNER CP3500", FALSE, TRUE, FALSE, FALSE }, 146 { "OLIVETTICP3500", FALSE, TRUE, FALSE, FALSE }, 147 { "SyQuest SQ5110 CHC", TRUE, TRUE, FALSE, FALSE }, 148 { "SEAGATE ST41601N 0102", FALSE, TRUE, FALSE, FALSE }, 149 { "SEAGATE ST3655N", FALSE, FALSE, FALSE, TRUE }, 150 { "SEAGATE ST3390N", FALSE, FALSE, FALSE, TRUE }, 151 { "SEAGATE ST12550N", FALSE, FALSE, FALSE, TRUE }, 152 { "SEAGATE ST32430N", FALSE, FALSE, FALSE, TRUE }, 153 { "SEAGATE ST31230N", FALSE, FALSE, FALSE, TRUE }, 154 { "SEAGATE ST15230N", FALSE, FALSE, FALSE, TRUE }, 155 { "FUJITSU M2652S-512", TRUE, FALSE, FALSE, FALSE }, 156 { "MAXTOR MXT-540SL I1.2", TRUE, FALSE, FALSE, FALSE }, 157 { "COMPAQ PD-1", FALSE, TRUE, FALSE, FALSE } 158 }; 159 160 161 #define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION)) 162 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA) 163 164 #define MODE_DATA_SIZE 192 165 #define VALUE_BUFFER_SIZE 2048 166 #define SCSI_DISK_TIMEOUT 10 167 #define PARTITION0_LIST_SIZE 4 168 169 170 NTSTATUS 171 NTAPI 172 DriverEntry( 173 IN PDRIVER_OBJECT DriverObject, 174 IN PUNICODE_STRING RegistryPath 175 ); 176 177 BOOLEAN 178 NTAPI 179 ScsiDiskDeviceVerification( 180 IN PINQUIRYDATA InquiryData 181 ); 182 183 BOOLEAN 184 NTAPI 185 FindScsiDisks( 186 IN PDRIVER_OBJECT DriveObject, 187 IN PUNICODE_STRING RegistryPath, 188 IN PCLASS_INIT_DATA InitializationData, 189 IN PDEVICE_OBJECT PortDeviceObject, 190 IN ULONG PortNumber 191 ); 192 193 NTSTATUS 194 NTAPI 195 ScsiDiskCreateClose ( 196 IN PDEVICE_OBJECT DeviceObject, 197 IN PIRP Irp 198 ); 199 200 NTSTATUS 201 NTAPI 202 ScsiDiskReadWriteVerification( 203 IN PDEVICE_OBJECT DeviceObject, 204 IN PIRP Irp 205 ); 206 207 NTSTATUS 208 NTAPI 209 ScsiDiskDeviceControl( 210 IN PDEVICE_OBJECT DeviceObject, 211 IN PIRP Irp 212 ); 213 214 VOID 215 NTAPI 216 ScsiDiskProcessError( 217 PDEVICE_OBJECT DeviceObject, 218 PSCSI_REQUEST_BLOCK Srb, 219 NTSTATUS *Status, 220 BOOLEAN *Retry 221 ); 222 223 NTSTATUS 224 NTAPI 225 ScsiDiskShutdownFlush( 226 IN PDEVICE_OBJECT DeviceObject, 227 IN PIRP Irp 228 ); 229 230 VOID 231 NTAPI 232 DisableWriteCache( 233 IN PDEVICE_OBJECT DeviceObject, 234 IN PSCSI_INQUIRY_DATA LunInfo 235 ); 236 237 BOOLEAN 238 NTAPI 239 ScsiDiskModeSelect( 240 IN PDEVICE_OBJECT DeviceObject, 241 IN PCHAR ModeSelectBuffer, 242 IN ULONG Length, 243 IN BOOLEAN SavePage 244 ); 245 246 BOOLEAN 247 NTAPI 248 IsFloppyDevice( 249 IN PDEVICE_OBJECT DeviceObject 250 ); 251 252 BOOLEAN 253 NTAPI 254 CalculateMbrCheckSum( 255 IN PDEVICE_EXTENSION DeviceExtension, 256 OUT PULONG Checksum 257 ); 258 259 BOOLEAN 260 NTAPI 261 EnumerateBusKey( 262 IN PDEVICE_EXTENSION DeviceExtension, 263 HANDLE BusKey, 264 PULONG DiskNumber 265 ); 266 267 VOID 268 NTAPI 269 UpdateGeometry( 270 IN PDEVICE_EXTENSION DeviceExtension 271 ); 272 273 NTSTATUS 274 NTAPI 275 UpdateRemovableGeometry ( 276 IN PDEVICE_OBJECT DeviceObject, 277 IN PIRP Irp 278 ); 279 280 NTSTATUS 281 NTAPI 282 CreateDiskDeviceObject( 283 IN PDRIVER_OBJECT DriverObject, 284 IN PUNICODE_STRING RegistryPath, 285 IN PDEVICE_OBJECT PortDeviceObject, 286 IN ULONG PortNumber, 287 IN PULONG DeviceCount, 288 IN PIO_SCSI_CAPABILITIES PortCapabilities, 289 IN PSCSI_INQUIRY_DATA LunInfo, 290 IN PCLASS_INIT_DATA InitData 291 ); 292 293 NTSTATUS 294 NTAPI 295 CreatePartitionDeviceObjects( 296 IN PDEVICE_OBJECT PhysicalDeviceObject, 297 IN PUNICODE_STRING RegistryPath 298 ); 299 300 VOID 301 NTAPI 302 UpdateDeviceObjects( 303 IN PDEVICE_OBJECT DeviceObject, 304 IN PIRP Irp 305 ); 306 307 VOID 308 NTAPI 309 ScanForSpecial( 310 PDEVICE_OBJECT DeviceObject, 311 PSCSI_INQUIRY_DATA LunInfo, 312 PIO_SCSI_CAPABILITIES PortCapabilities 313 ); 314 315 VOID 316 NTAPI 317 ResetScsiBus( 318 IN PDEVICE_OBJECT DeviceObject 319 ); 320 321 NTSTATUS 322 NTAPI 323 ScsiDiskFileSystemControl(PDEVICE_OBJECT DeviceObject, 324 PIRP Irp); 325 326 #ifdef ALLOC_PRAGMA 327 #pragma alloc_text(PAGE, DriverEntry) 328 #pragma alloc_text(PAGE, FindScsiDisks) 329 #pragma alloc_text(PAGE, CreateDiskDeviceObject) 330 #pragma alloc_text(PAGE, CalculateMbrCheckSum) 331 #pragma alloc_text(PAGE, EnumerateBusKey) 332 #pragma alloc_text(PAGE, UpdateGeometry) 333 #pragma alloc_text(PAGE, IsFloppyDevice) 334 #pragma alloc_text(PAGE, ScanForSpecial) 335 #pragma alloc_text(PAGE, ScsiDiskDeviceControl) 336 #pragma alloc_text(PAGE, ScsiDiskModeSelect) 337 #endif 338 339 340 NTSTATUS 341 NTAPI 342 DriverEntry( 343 IN PDRIVER_OBJECT DriverObject, 344 IN PUNICODE_STRING RegistryPath 345 ) 346 347 /*++ 348 349 Routine Description: 350 351 This routine initializes the SCSI hard disk class driver. 352 353 Arguments: 354 355 DriverObject - Pointer to driver object created by system. 356 357 RegistryPath - Pointer to the name of the services node for this driver. 358 359 Return Value: 360 361 The function value is the final status from the initialization operation. 362 363 --*/ 364 365 { 366 CLASS_INIT_DATA InitializationData; 367 368 // 369 // Zero InitData 370 // 371 372 RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA)); 373 374 // 375 // Set sizes 376 // 377 378 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA); 379 InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE; 380 381 InitializationData.DeviceType = FILE_DEVICE_DISK; 382 InitializationData.DeviceCharacteristics = 0; 383 384 // 385 // Set entry points 386 // 387 388 InitializationData.ClassError = ScsiDiskProcessError; 389 InitializationData.ClassReadWriteVerification = ScsiDiskReadWriteVerification; 390 InitializationData.ClassFindDevices = FindScsiDisks; 391 InitializationData.ClassFindDeviceCallBack = ScsiDiskDeviceVerification; 392 InitializationData.ClassDeviceControl = ScsiDiskDeviceControl; 393 InitializationData.ClassShutdownFlush = ScsiDiskShutdownFlush; 394 InitializationData.ClassCreateClose = NULL; 395 396 // 397 // Call the class init routine 398 // 399 400 return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData); 401 402 } // end DriverEntry() 403 404 405 406 BOOLEAN 407 NTAPI 408 ScsiDiskDeviceVerification( 409 IN PINQUIRYDATA InquiryData 410 ) 411 412 /*++ 413 414 Routine Description: 415 416 This routine checks InquiryData for the correct device type and qualifier. 417 418 Arguments: 419 420 InquiryData - Pointer to the inquiry data for the device in question. 421 422 Return Value: 423 424 True is returned if the correct device type is found. 425 426 --*/ 427 { 428 429 if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) || 430 (InquiryData->DeviceType == OPTICAL_DEVICE)) && 431 InquiryData->DeviceTypeQualifier == 0) { 432 433 return TRUE; 434 435 } else { 436 return FALSE; 437 } 438 } 439 440 441 BOOLEAN 442 NTAPI 443 FindScsiDisks( 444 IN PDRIVER_OBJECT DriverObject, 445 IN PUNICODE_STRING RegistryPath, 446 IN PCLASS_INIT_DATA InitializationData, 447 IN PDEVICE_OBJECT PortDeviceObject, 448 IN ULONG PortNumber 449 ) 450 451 /*++ 452 453 Routine Description: 454 455 This routine gets a port drivers capabilities, obtains the 456 inquiry data, searches the SCSI bus for the port driver and creates 457 the device objects for the disks found. 458 459 Arguments: 460 461 DriverObject - Pointer to driver object created by system. 462 463 PortDeviceObject - Device object use to send requests to port driver. 464 465 PortNumber - Number for port driver. Used to pass on to 466 CreateDiskDeviceObjects() and create device objects. 467 468 Return Value: 469 470 True is returned if one disk was found and successfully created. 471 472 --*/ 473 474 { 475 PIO_SCSI_CAPABILITIES portCapabilities; 476 PULONG diskCount; 477 PCONFIGURATION_INFORMATION configurationInformation; 478 PCHAR buffer; 479 PSCSI_INQUIRY_DATA lunInfo; 480 PSCSI_ADAPTER_BUS_INFO adapterInfo; 481 PINQUIRYDATA inquiryData; 482 ULONG scsiBus; 483 ULONG adapterDisk; 484 NTSTATUS status; 485 BOOLEAN foundOne = FALSE; 486 487 PAGED_CODE(); 488 489 // 490 // Call port driver to get adapter capabilities. 491 // 492 493 status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities); 494 495 if (!NT_SUCCESS(status)) { 496 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n")); 497 return(FALSE); 498 } 499 500 // 501 // Call port driver to get inquiry information to find disks. 502 // 503 504 status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer); 505 506 if (!NT_SUCCESS(status)) { 507 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n")); 508 return(FALSE); 509 } 510 511 // 512 // Do a quick scan of the devices on this adapter to determine how many 513 // disks are on this adapter. This is used to determine the number of 514 // SRB zone elements to allocate. 515 // 516 517 adapterInfo = (PVOID) buffer; 518 519 adapterDisk = ScsiClassFindUnclaimedDevices(InitializationData, adapterInfo); 520 521 // 522 // Allocate a zone of SRB for disks on this adapter. 523 // 524 525 if (adapterDisk == 0) { 526 527 // 528 // No free disks were found. 529 // 530 531 return(FALSE); 532 } 533 534 // 535 // Get the number of disks already initialized. 536 // 537 538 configurationInformation = IoGetConfigurationInformation(); 539 diskCount = &configurationInformation->DiskCount; 540 541 // 542 // For each SCSI bus this adapter supports ... 543 // 544 545 for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) { 546 547 // 548 // Get the SCSI bus scan data for this bus. 549 // 550 551 lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset); 552 553 // 554 // Search list for unclaimed disk devices. 555 // 556 557 while (adapterInfo->BusData[scsiBus].InquiryDataOffset) { 558 559 inquiryData = (PVOID)lunInfo->InquiryData; 560 561 if (((inquiryData->DeviceType == DIRECT_ACCESS_DEVICE) || 562 (inquiryData->DeviceType == OPTICAL_DEVICE)) && 563 inquiryData->DeviceTypeQualifier == 0 && 564 (!lunInfo->DeviceClaimed)) { 565 566 DebugPrint((1, 567 "FindScsiDevices: Vendor string is %.24s\n", 568 inquiryData->VendorId)); 569 570 // 571 // Create device objects for disk 572 // 573 574 status = CreateDiskDeviceObject(DriverObject, 575 RegistryPath, 576 PortDeviceObject, 577 PortNumber, 578 diskCount, 579 portCapabilities, 580 lunInfo, 581 InitializationData); 582 583 if (NT_SUCCESS(status)) { 584 585 // 586 // Increment system disk device count. 587 // 588 589 (*diskCount)++; 590 foundOne = TRUE; 591 592 } 593 } 594 595 // 596 // Get next LunInfo. 597 // 598 599 if (lunInfo->NextInquiryDataOffset == 0) { 600 break; 601 } 602 603 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset); 604 605 } 606 } 607 608 // 609 // Buffer is allocated by ScsiClassGetInquiryData and must be free returning. 610 // 611 612 ExFreePool(buffer); 613 614 return(foundOne); 615 616 } // end FindScsiDisks() 617 618 619 NTSTATUS 620 NTAPI 621 CreateDiskDeviceObject( 622 IN PDRIVER_OBJECT DriverObject, 623 IN PUNICODE_STRING RegistryPath, 624 IN PDEVICE_OBJECT PortDeviceObject, 625 IN ULONG PortNumber, 626 IN PULONG DeviceCount, 627 IN PIO_SCSI_CAPABILITIES PortCapabilities, 628 IN PSCSI_INQUIRY_DATA LunInfo, 629 IN PCLASS_INIT_DATA InitData 630 ) 631 632 /*++ 633 634 Routine Description: 635 636 This routine creates an object for the physical device and then searches 637 the device for partitions and creates an object for each partition. 638 639 Arguments: 640 641 DriverObject - Pointer to driver object created by system. 642 643 PortDeviceObject - Miniport device object. 644 645 PortNumber - port number. Used in creating disk objects. 646 647 DeviceCount - Number of previously installed devices. 648 649 PortCapabilities - Capabilities of this SCSI port. 650 651 LunInfo - LUN specific information. 652 653 Return Value: 654 655 NTSTATUS 656 657 --*/ 658 { 659 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH]; 660 STRING ntNameString; 661 UNICODE_STRING ntUnicodeString; 662 OBJECT_ATTRIBUTES objectAttributes; 663 HANDLE handle; 664 NTSTATUS status; 665 PDEVICE_OBJECT deviceObject = NULL; 666 //PDEVICE_OBJECT physicalDevice; 667 PDISK_GEOMETRY_EX diskGeometry = NULL; 668 PDEVICE_EXTENSION deviceExtension = NULL; 669 //PDEVICE_EXTENSION physicalDeviceExtension; 670 UCHAR pathId = LunInfo->PathId; 671 UCHAR targetId = LunInfo->TargetId; 672 UCHAR lun = LunInfo->Lun; 673 //BOOLEAN writeCache; 674 PVOID senseData = NULL; 675 //ULONG srbFlags; 676 ULONG timeOut = 0; 677 BOOLEAN srbListInitialized = FALSE; 678 679 680 PAGED_CODE(); 681 682 // 683 // Set up an object directory to contain the objects for this 684 // device and all its partitions. 685 // 686 687 sprintf(ntNameBuffer, 688 "\\Device\\Harddisk%lu", 689 *DeviceCount); 690 691 RtlInitString(&ntNameString, 692 ntNameBuffer); 693 694 status = RtlAnsiStringToUnicodeString(&ntUnicodeString, 695 &ntNameString, 696 TRUE); 697 698 if (!NT_SUCCESS(status)) { 699 return(status); 700 } 701 702 InitializeObjectAttributes(&objectAttributes, 703 &ntUnicodeString, 704 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, 705 NULL, 706 NULL); 707 708 status = ZwCreateDirectoryObject(&handle, 709 DIRECTORY_ALL_ACCESS, 710 &objectAttributes); 711 712 RtlFreeUnicodeString(&ntUnicodeString); 713 714 if (!NT_SUCCESS(status)) { 715 716 DebugPrint((1, 717 "CreateDiskDeviceObjects: Could not create directory %s\n", 718 ntNameBuffer)); 719 720 return(status); 721 } 722 723 // 724 // Claim the device. 725 // 726 727 status = ScsiClassClaimDevice(PortDeviceObject, 728 LunInfo, 729 FALSE, 730 &PortDeviceObject); 731 732 if (!NT_SUCCESS(status)) { 733 ZwMakeTemporaryObject(handle); 734 ZwClose(handle); 735 return status; 736 } 737 738 // 739 // Create a device object for this device. Each physical disk will 740 // have at least one device object. The required device object 741 // describes the entire device. Its directory path is 742 // \Device\HarddiskN\Partition0, where N = device number. 743 // 744 745 sprintf(ntNameBuffer, 746 "\\Device\\Harddisk%lu\\Partition0", 747 *DeviceCount); 748 749 750 status = ScsiClassCreateDeviceObject(DriverObject, 751 ntNameBuffer, 752 NULL, 753 &deviceObject, 754 InitData); 755 756 if (!NT_SUCCESS(status)) { 757 758 DebugPrint((1, 759 "CreateDiskDeviceObjects: Can not create device object %s\n", 760 ntNameBuffer)); 761 762 goto CreateDiskDeviceObjectsExit; 763 } 764 765 // 766 // Indicate that IRPs should include MDLs for data transfers. 767 // 768 769 deviceObject->Flags |= DO_DIRECT_IO; 770 771 // 772 // Check if this is during initialization. If not indicate that 773 // system initialization already took place and this disk is ready 774 // to be accessed. 775 // 776 777 if (!RegistryPath) { 778 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 779 } 780 781 // 782 // Check for removable media support. 783 // 784 785 if (((PINQUIRYDATA)LunInfo->InquiryData)->RemovableMedia) { 786 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA; 787 } 788 789 // 790 // Set up required stack size in device object. 791 // 792 793 deviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1; 794 795 deviceExtension = deviceObject->DeviceExtension; 796 797 // 798 // Allocate spinlock for split request completion. 799 // 800 801 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock); 802 803 // 804 // Initialize lock count to zero. The lock count is used to 805 // disable the ejection mechanism on devices that support 806 // removable media. Only the lock count in the physical 807 // device extension is used. 808 // 809 810 deviceExtension->LockCount = 0; 811 812 // 813 // Save system disk number. 814 // 815 816 deviceExtension->DeviceNumber = *DeviceCount; 817 818 // 819 // Copy port device object pointer to the device extension. 820 // 821 822 deviceExtension->PortDeviceObject = PortDeviceObject; 823 824 // 825 // Set the alignment requirements for the device based on the 826 // host adapter requirements 827 // 828 829 if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) { 830 deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement; 831 } 832 833 // 834 // This is the physical device object. 835 // 836 837 //physicalDevice = deviceObject; 838 //physicalDeviceExtension = deviceExtension; 839 840 // 841 // Save address of port driver capabilities. 842 // 843 844 deviceExtension->PortCapabilities = PortCapabilities; 845 846 // 847 // Build the lookaside list for srb's for the physical disk. Should only 848 // need a couple. 849 // 850 851 ScsiClassInitializeSrbLookasideList(deviceExtension, 852 PARTITION0_LIST_SIZE); 853 854 srbListInitialized = TRUE; 855 856 // 857 // Initialize the srb flags. 858 // 859 860 if (((PINQUIRYDATA)LunInfo->InquiryData)->CommandQueue && 861 PortCapabilities->TaggedQueuing) { 862 863 deviceExtension->SrbFlags = SRB_FLAGS_QUEUE_ACTION_ENABLE; 864 865 } else { 866 867 deviceExtension->SrbFlags = 0; 868 869 } 870 871 // 872 // Allow queued requests if this is not removable media. 873 // 874 875 if (!(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) { 876 877 deviceExtension->SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE; 878 879 } 880 881 // 882 // Look for controller that require special flags. 883 // 884 885 ScanForSpecial(deviceObject, 886 LunInfo, 887 PortCapabilities); 888 889 //srbFlags = deviceExtension->SrbFlags; 890 891 // 892 // Allocate buffer for drive geometry. 893 // 894 895 diskGeometry = ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY_EX)); 896 897 if (diskGeometry == NULL) { 898 899 DebugPrint((1, 900 "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n")); 901 status = STATUS_INSUFFICIENT_RESOURCES; 902 goto CreateDiskDeviceObjectsExit; 903 } 904 905 deviceExtension->DiskGeometry = diskGeometry; 906 907 // 908 // Allocate request sense buffer. 909 // 910 911 senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE); 912 913 if (senseData == NULL) { 914 915 // 916 // The buffer can not be allocated. 917 // 918 919 DebugPrint((1, 920 "CreateDiskDeviceObjects: Can not allocate request sense buffer\n")); 921 922 status = STATUS_INSUFFICIENT_RESOURCES; 923 goto CreateDiskDeviceObjectsExit; 924 } 925 926 // 927 // Set the sense data pointer in the device extension. 928 // 929 930 deviceExtension->SenseData = senseData; 931 932 // 933 // Physical device object will describe the entire 934 // device, starting at byte offset 0. 935 // 936 937 deviceExtension->StartingOffset.QuadPart = (LONGLONG)(0); 938 939 // 940 // TargetId/LUN describes a device location on the SCSI bus. 941 // This information comes from the inquiry buffer. 942 // 943 944 deviceExtension->PortNumber = (UCHAR)PortNumber; 945 deviceExtension->PathId = pathId; 946 deviceExtension->TargetId = targetId; 947 deviceExtension->Lun = lun; 948 949 // 950 // Set timeout value in seconds. 951 // 952 953 timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath); 954 if (timeOut) { 955 deviceExtension->TimeOutValue = timeOut; 956 } else { 957 deviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT; 958 } 959 960 // 961 // Back pointer to device object. 962 // 963 964 deviceExtension->DeviceObject = deviceObject; 965 966 // 967 // If this is a removable device, then make sure it is not a floppy. 968 // Perform a mode sense command to determine the media type. Note 969 // IsFloppyDevice also checks for write cache enabled. 970 // 971 972 #if 0 973 if (IsFloppyDevice(deviceObject) && deviceObject->Characteristics & FILE_REMOVABLE_MEDIA && 974 (((PINQUIRYDATA)LunInfo->InquiryData)->DeviceType == DIRECT_ACCESS_DEVICE)) { 975 976 status = STATUS_NO_SUCH_DEVICE; 977 goto CreateDiskDeviceObjectsExit; 978 } 979 #endif 980 981 DisableWriteCache(deviceObject,LunInfo); 982 983 //writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE; 984 985 // 986 // NOTE: At this point one device object has been successfully created. 987 // from here on out return success. 988 // 989 990 // 991 // Do READ CAPACITY. This SCSI command 992 // returns the number of bytes on a device. 993 // Device extension is updated with device size. 994 // 995 996 status = ScsiClassReadDriveCapacity(deviceObject); 997 998 // 999 // If the read capacity failed then just return, unless this is a 1000 // removable disk where a device object partition needs to be created. 1001 // 1002 1003 if (!NT_SUCCESS(status) && 1004 !(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) { 1005 1006 DebugPrint((1, 1007 "CreateDiskDeviceObjects: Can't read capacity for device %s\n", 1008 ntNameBuffer)); 1009 1010 return(STATUS_SUCCESS); 1011 1012 } else { 1013 1014 // 1015 // Make sure the volume verification bit is off so that 1016 // IoReadPartitionTable will work. 1017 // 1018 1019 deviceObject->Flags &= ~DO_VERIFY_VOLUME; 1020 } 1021 1022 status = CreatePartitionDeviceObjects(deviceObject, RegistryPath); 1023 1024 if (NT_SUCCESS(status)) 1025 return STATUS_SUCCESS; 1026 1027 1028 CreateDiskDeviceObjectsExit: 1029 1030 // 1031 // Release the device since an error occurred. 1032 // 1033 1034 ScsiClassClaimDevice(PortDeviceObject, 1035 LunInfo, 1036 TRUE, 1037 NULL); 1038 1039 if (diskGeometry != NULL) { 1040 ExFreePool(diskGeometry); 1041 } 1042 1043 if (senseData != NULL) { 1044 ExFreePool(senseData); 1045 } 1046 1047 if (deviceObject != NULL) { 1048 1049 if (srbListInitialized) { 1050 ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead); 1051 } 1052 1053 IoDeleteDevice(deviceObject); 1054 } 1055 1056 // 1057 // Delete directory and return. 1058 // 1059 1060 if (!NT_SUCCESS(status)) { 1061 ZwMakeTemporaryObject(handle); 1062 } 1063 1064 ZwClose(handle); 1065 1066 return(status); 1067 1068 } // end CreateDiskDeviceObjects() 1069 1070 1071 VOID 1072 NTAPI 1073 ReportToMountMgr( 1074 IN PDEVICE_OBJECT DiskDeviceObject 1075 ) 1076 1077 /*++ 1078 1079 Routine Description: 1080 1081 This routine reports the creation of a disk device object to the 1082 MountMgr to fake PnP. 1083 1084 Arguments: 1085 1086 DiskDeviceObject - Pointer to the created disk device. 1087 1088 Return Value: 1089 1090 VOID 1091 1092 --*/ 1093 { 1094 NTSTATUS status; 1095 UNICODE_STRING mountMgrDevice; 1096 PDEVICE_OBJECT deviceObject; 1097 PFILE_OBJECT fileObject; 1098 PMOUNTMGR_TARGET_NAME mountTarget; 1099 ULONG diskLen; 1100 PDEVICE_EXTENSION deviceExtension; 1101 PIRP irp; 1102 KEVENT event; 1103 IO_STATUS_BLOCK ioStatus; 1104 1105 // 1106 // First, get MountMgr DeviceObject. 1107 // 1108 1109 RtlInitUnicodeString(&mountMgrDevice, MOUNTMGR_DEVICE_NAME); 1110 status = IoGetDeviceObjectPointer(&mountMgrDevice, FILE_READ_ATTRIBUTES, 1111 &fileObject, &deviceObject); 1112 1113 if (!NT_SUCCESS(status)) { 1114 1115 DebugPrint((1, 1116 "ReportToMountMgr: Can't get MountMgr pointers %lx\n", 1117 status)); 1118 1119 return; 1120 } 1121 1122 deviceExtension = DiskDeviceObject->DeviceExtension; 1123 diskLen = deviceExtension->DeviceName.Length; 1124 1125 // 1126 // Allocate input buffer to report our partition device. 1127 // 1128 1129 mountTarget = ExAllocatePool(NonPagedPool, 1130 sizeof(MOUNTMGR_TARGET_NAME) + diskLen); 1131 1132 if (!mountTarget) { 1133 1134 DebugPrint((1, 1135 "ReportToMountMgr: Allocation of mountTarget failed\n")); 1136 1137 ObDereferenceObject(fileObject); 1138 return; 1139 } 1140 1141 mountTarget->DeviceNameLength = diskLen; 1142 RtlCopyMemory(mountTarget->DeviceName, deviceExtension->DeviceName.Buffer, diskLen); 1143 1144 KeInitializeEvent(&event, NotificationEvent, FALSE); 1145 1146 // 1147 // Build the IRP used to communicate with the MountMgr. 1148 // 1149 1150 irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, 1151 deviceObject, 1152 mountTarget, 1153 sizeof(MOUNTMGR_TARGET_NAME) + diskLen, 1154 NULL, 1155 0, 1156 FALSE, 1157 &event, 1158 &ioStatus); 1159 1160 if (!irp) { 1161 1162 DebugPrint((1, 1163 "ReportToMountMgr: Allocation of irp failed\n")); 1164 1165 ExFreePool(mountTarget); 1166 ObDereferenceObject(fileObject); 1167 return; 1168 } 1169 1170 // 1171 // Call the MountMgr. 1172 // 1173 1174 status = IoCallDriver(deviceObject, irp); 1175 1176 if (status == STATUS_PENDING) { 1177 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 1178 status = ioStatus.Status; 1179 } 1180 1181 // 1182 // We're done. 1183 // 1184 1185 DPRINT1("Reported to the MountMgr: %lx\n", status); 1186 1187 ExFreePool(mountTarget); 1188 ObDereferenceObject(fileObject); 1189 1190 return; 1191 } 1192 1193 1194 NTSTATUS 1195 NTAPI 1196 CreatePartitionDeviceObjects( 1197 IN PDEVICE_OBJECT PhysicalDeviceObject, 1198 IN PUNICODE_STRING RegistryPath 1199 ) 1200 { 1201 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH]; 1202 ULONG partitionNumber = 0; 1203 NTSTATUS status; 1204 PDEVICE_OBJECT deviceObject = NULL; 1205 PDISK_GEOMETRY_EX diskGeometry = NULL; 1206 PDRIVE_LAYOUT_INFORMATION partitionList = NULL; 1207 PDEVICE_EXTENSION deviceExtension; 1208 PDEVICE_EXTENSION physicalDeviceExtension; 1209 PCLASS_INIT_DATA initData = NULL; 1210 PDISK_DATA diskData; 1211 PDISK_DATA physicalDiskData; 1212 ULONG bytesPerSector; 1213 UCHAR sectorShift; 1214 ULONG srbFlags; 1215 ULONG dmByteSkew = 0; 1216 PULONG dmSkew; 1217 BOOLEAN dmActive = FALSE; 1218 ULONG numberListElements = 0; 1219 1220 1221 // 1222 // Get physical device geometry information for partition table reads. 1223 // 1224 1225 physicalDeviceExtension = PhysicalDeviceObject->DeviceExtension; 1226 diskGeometry = physicalDeviceExtension->DiskGeometry; 1227 bytesPerSector = diskGeometry->Geometry.BytesPerSector; 1228 1229 // 1230 // Make sure sector size is not zero. 1231 // 1232 1233 if (bytesPerSector == 0) { 1234 1235 // 1236 // Default sector size for disk is 512. 1237 // 1238 1239 bytesPerSector = diskGeometry->Geometry.BytesPerSector = 512; 1240 } 1241 1242 sectorShift = physicalDeviceExtension->SectorShift; 1243 1244 // 1245 // Set pointer to disk data area that follows device extension. 1246 // 1247 1248 diskData = (PDISK_DATA)(physicalDeviceExtension + 1); 1249 diskData->PartitionListState = Initializing; 1250 1251 // 1252 // Determine is DM Driver is loaded on an IDE drive that is 1253 // under control of Atapi - this could be either a crashdump or 1254 // an Atapi device is sharing the controller with an IDE disk. 1255 // 1256 1257 HalExamineMBR(PhysicalDeviceObject, 1258 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector, 1259 (ULONG)0x54, 1260 (PVOID)&dmSkew); 1261 1262 if (dmSkew) { 1263 1264 // 1265 // Update the device extension, so that the call to IoReadPartitionTable 1266 // will get the correct information. Any I/O to this disk will have 1267 // to be skewed by *dmSkew sectors aka DMByteSkew. 1268 // 1269 1270 physicalDeviceExtension->DMSkew = *dmSkew; 1271 physicalDeviceExtension->DMActive = TRUE; 1272 physicalDeviceExtension->DMByteSkew = physicalDeviceExtension->DMSkew * bytesPerSector; 1273 1274 // 1275 // Save away the information that we need, since this deviceExtension will soon be 1276 // blown away. 1277 // 1278 1279 dmActive = TRUE; 1280 dmByteSkew = physicalDeviceExtension->DMByteSkew; 1281 1282 } 1283 1284 #ifdef __REACTOS__ 1285 // 1286 // HACK so that we can use NT5+ NTOS functions with this NT4 driver 1287 // for removable devices and avoid an infinite recursive loop between 1288 // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable(). 1289 // 1290 diskData->UpdateRemovableGeometryCount = 0; 1291 #endif 1292 1293 // 1294 // Create objects for all the partitions on the device. 1295 // 1296 1297 status = IoReadPartitionTable(PhysicalDeviceObject, 1298 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector, 1299 TRUE, 1300 (PVOID)&partitionList); 1301 1302 // 1303 // If the I/O read partition table failed and this is a removable device, 1304 // then fix up the partition list to make it look like there is one 1305 // zero length partition. 1306 // 1307 DPRINT("IoReadPartitionTable() status: 0x%08X\n", status); 1308 if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) && 1309 PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 1310 1311 if (!NT_SUCCESS(status)) { 1312 1313 // 1314 // Remember this disk is not ready. 1315 // 1316 1317 diskData->DriveNotReady = TRUE; 1318 1319 } else { 1320 1321 // 1322 // Free the partition list allocated by IoReadPartitionTable. 1323 // 1324 1325 ExFreePool(partitionList); 1326 } 1327 1328 // 1329 // Allocate and zero a partition list. 1330 // 1331 1332 partitionList = ExAllocatePool(NonPagedPool, sizeof(*partitionList)); 1333 1334 1335 if (partitionList != NULL) { 1336 1337 RtlZeroMemory( partitionList, sizeof( *partitionList )); 1338 1339 // 1340 // Set the partition count to one and the status to success 1341 // so one device object will be created. Set the partition type 1342 // to a bogus value. 1343 // 1344 1345 partitionList->PartitionCount = 1; 1346 1347 status = STATUS_SUCCESS; 1348 } 1349 } 1350 1351 if (NT_SUCCESS(status)) { 1352 1353 // 1354 // Record disk signature. 1355 // 1356 1357 diskData->Signature = partitionList->Signature; 1358 1359 // 1360 // If disk signature is zero, then calculate the MBR checksum. 1361 // 1362 1363 if (!diskData->Signature) { 1364 1365 if (!CalculateMbrCheckSum(physicalDeviceExtension, 1366 &diskData->MbrCheckSum)) { 1367 1368 DebugPrint((1, 1369 "SCSIDISK: Can't calculate MBR checksum for disk %x\n", 1370 physicalDeviceExtension->DeviceNumber)); 1371 } else { 1372 1373 DebugPrint((2, 1374 "SCSIDISK: MBR checksum for disk %x is %x\n", 1375 physicalDeviceExtension->DeviceNumber, 1376 diskData->MbrCheckSum)); 1377 } 1378 } 1379 1380 // 1381 // Check the registry and determine if the BIOS knew about this drive. If 1382 // it did then update the geometry with the BIOS information. 1383 // 1384 1385 UpdateGeometry(physicalDeviceExtension); 1386 1387 srbFlags = physicalDeviceExtension->SrbFlags; 1388 1389 initData = ExAllocatePool(NonPagedPool, sizeof(CLASS_INIT_DATA)); 1390 if (!initData) 1391 { 1392 DebugPrint((1, 1393 "Disk.CreatePartitionDeviceObjects - Allocation of initData failed\n")); 1394 1395 status = STATUS_INSUFFICIENT_RESOURCES; 1396 goto CreatePartitionDeviceObjectsExit; 1397 } 1398 1399 RtlZeroMemory(initData, sizeof(CLASS_INIT_DATA)); 1400 1401 initData->InitializationDataSize = sizeof(CLASS_INIT_DATA); 1402 initData->DeviceExtensionSize = DEVICE_EXTENSION_SIZE; 1403 initData->DeviceType = FILE_DEVICE_DISK; 1404 initData->DeviceCharacteristics = PhysicalDeviceObject->Characteristics; 1405 initData->ClassError = physicalDeviceExtension->ClassError; 1406 initData->ClassReadWriteVerification = physicalDeviceExtension->ClassReadWriteVerification; 1407 initData->ClassFindDevices = physicalDeviceExtension->ClassFindDevices; 1408 initData->ClassDeviceControl = physicalDeviceExtension->ClassDeviceControl; 1409 initData->ClassShutdownFlush = physicalDeviceExtension->ClassShutdownFlush; 1410 initData->ClassCreateClose = physicalDeviceExtension->ClassCreateClose; 1411 initData->ClassStartIo = physicalDeviceExtension->ClassStartIo; 1412 1413 // 1414 // Create device objects for the device partitions (if any). 1415 // PartitionCount includes physical device partition 0, 1416 // so only one partition means no objects to create. 1417 // 1418 1419 DebugPrint((2, 1420 "CreateDiskDeviceObjects: Number of partitions is %d\n", 1421 partitionList->PartitionCount)); 1422 1423 for (partitionNumber = 0; partitionNumber < 1424 partitionList->PartitionCount; partitionNumber++) { 1425 1426 // 1427 // Create partition object and set up partition parameters. 1428 // 1429 1430 sprintf(ntNameBuffer, 1431 "\\Device\\Harddisk%lu\\Partition%lu", 1432 physicalDeviceExtension->DeviceNumber, 1433 partitionNumber + 1); 1434 1435 DebugPrint((2, 1436 "CreateDiskDeviceObjects: Create device object %s\n", 1437 ntNameBuffer)); 1438 1439 status = ScsiClassCreateDeviceObject(PhysicalDeviceObject->DriverObject, 1440 ntNameBuffer, 1441 PhysicalDeviceObject, 1442 &deviceObject, 1443 initData); 1444 1445 if (!NT_SUCCESS(status)) { 1446 1447 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer)); 1448 1449 break; 1450 } 1451 1452 // 1453 // Set up device object fields. 1454 // 1455 1456 deviceObject->Flags |= DO_DIRECT_IO; 1457 1458 // 1459 // Check if this is during initialization. If not indicate that 1460 // system initialization already took place and this disk is ready 1461 // to be accessed. 1462 // 1463 1464 if (!RegistryPath) { 1465 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 1466 } 1467 1468 deviceObject->StackSize = (CCHAR)physicalDeviceExtension->PortDeviceObject->StackSize + 1; 1469 1470 // 1471 // Set up device extension fields. 1472 // 1473 1474 deviceExtension = deviceObject->DeviceExtension; 1475 1476 if (dmActive) { 1477 1478 // 1479 // Restore any saved DM values. 1480 // 1481 1482 deviceExtension->DMByteSkew = dmByteSkew; 1483 deviceExtension->DMSkew = *dmSkew; 1484 deviceExtension->DMActive = TRUE; 1485 1486 } 1487 1488 // 1489 // Link new device extension to previous disk data 1490 // to support dynamic partitioning. 1491 // 1492 1493 diskData->NextPartition = deviceExtension; 1494 1495 // 1496 // Get pointer to new disk data. 1497 // 1498 1499 diskData = (PDISK_DATA)(deviceExtension + 1); 1500 1501 // 1502 // Set next partition pointer to NULL in case this is the 1503 // last partition. 1504 // 1505 1506 diskData->NextPartition = NULL; 1507 1508 // 1509 // Allocate spinlock for zoning for split-request completion. 1510 // 1511 1512 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock); 1513 1514 // 1515 // Copy port device object pointer to device extension. 1516 // 1517 1518 deviceExtension->PortDeviceObject = physicalDeviceExtension->PortDeviceObject; 1519 1520 // 1521 // Set the alignment requirements for the device based on the 1522 // host adapter requirements 1523 // 1524 1525 if (physicalDeviceExtension->PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) { 1526 deviceObject->AlignmentRequirement = physicalDeviceExtension->PortDeviceObject->AlignmentRequirement; 1527 } 1528 1529 1530 if (srbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) { 1531 numberListElements = 30; 1532 } else { 1533 numberListElements = 8; 1534 } 1535 1536 // 1537 // Build the lookaside list for srb's for this partition based on 1538 // whether the adapter and disk can do tagged queueing. 1539 // 1540 1541 ScsiClassInitializeSrbLookasideList(deviceExtension, 1542 numberListElements); 1543 1544 deviceExtension->SrbFlags = srbFlags; 1545 1546 // 1547 // Set the sense-data pointer in the device extension. 1548 // 1549 1550 deviceExtension->SenseData = physicalDeviceExtension->SenseData; 1551 deviceExtension->PortCapabilities = physicalDeviceExtension->PortCapabilities; 1552 deviceExtension->DiskGeometry = diskGeometry; 1553 diskData->PartitionOrdinal = diskData->PartitionNumber = partitionNumber + 1; 1554 diskData->PartitionType = partitionList->PartitionEntry[partitionNumber].PartitionType; 1555 diskData->BootIndicator = partitionList->PartitionEntry[partitionNumber].BootIndicator; 1556 1557 DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n", 1558 diskData->PartitionType)); 1559 1560 deviceExtension->StartingOffset = partitionList->PartitionEntry[partitionNumber].StartingOffset; 1561 deviceExtension->PartitionLength = partitionList->PartitionEntry[partitionNumber].PartitionLength; 1562 diskData->HiddenSectors = partitionList->PartitionEntry[partitionNumber].HiddenSectors; 1563 deviceExtension->PortNumber = physicalDeviceExtension->PortNumber; 1564 deviceExtension->PathId = physicalDeviceExtension->PathId; 1565 deviceExtension->TargetId = physicalDeviceExtension->TargetId; 1566 deviceExtension->Lun = physicalDeviceExtension->Lun; 1567 1568 // 1569 // Check for removable media support. 1570 // 1571 1572 if (PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 1573 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA; 1574 } 1575 1576 // 1577 // Set timeout value in seconds. 1578 // 1579 1580 deviceExtension->TimeOutValue = physicalDeviceExtension->TimeOutValue; 1581 deviceExtension->DiskGeometry->Geometry.BytesPerSector = bytesPerSector; 1582 deviceExtension->SectorShift = sectorShift; 1583 deviceExtension->DeviceObject = deviceObject; 1584 deviceExtension->DeviceFlags |= physicalDeviceExtension->DeviceFlags; 1585 1586 // 1587 // Now we're done, report to the MountMgr. 1588 // This is a HACK required to have the driver 1589 // handle the associated DosDevices. 1590 // 1591 1592 ReportToMountMgr(deviceObject); 1593 1594 } // end for (partitionNumber) ... 1595 1596 // 1597 // Free the buffer allocated by reading the 1598 // partition table. 1599 // 1600 1601 ExFreePool(partitionList); 1602 1603 if (dmSkew) { 1604 ExFreePool(dmSkew); 1605 } 1606 1607 } else { 1608 1609 CreatePartitionDeviceObjectsExit: 1610 1611 if (partitionList) { 1612 ExFreePool(partitionList); 1613 } 1614 if (initData) { 1615 ExFreePool(initData); 1616 } 1617 1618 if (dmSkew) { 1619 ExFreePool(dmSkew); 1620 } 1621 1622 return status; 1623 1624 } // end if...else 1625 1626 1627 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1); 1628 physicalDiskData->PartitionListState = Initialized; 1629 1630 return(STATUS_SUCCESS); 1631 1632 1633 } // end CreatePartitionDeviceObjects() 1634 1635 1636 NTSTATUS 1637 NTAPI 1638 ScsiDiskReadWriteVerification( 1639 IN PDEVICE_OBJECT DeviceObject, 1640 IN PIRP Irp 1641 ) 1642 1643 /*++ 1644 1645 Routine Description: 1646 1647 I/O System entry for read and write requests to SCSI disks. 1648 1649 Arguments: 1650 1651 DeviceObject - Pointer to driver object created by system. 1652 Irp - IRP involved. 1653 1654 Return Value: 1655 1656 NT Status 1657 1658 --*/ 1659 1660 { 1661 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 1662 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 1663 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; 1664 LARGE_INTEGER startingOffset; 1665 1666 // 1667 // HACK: How can we end here with null sector size?! 1668 // 1669 1670 if (deviceExtension->DiskGeometry->Geometry.BytesPerSector == 0) { 1671 DPRINT1("Hack! Received invalid sector size\n"); 1672 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 512; 1673 } 1674 1675 // 1676 // Verify parameters of this request. 1677 // Check that ending sector is within partition and 1678 // that number of bytes to transfer is a multiple of 1679 // the sector size. 1680 // 1681 1682 startingOffset.QuadPart = (currentIrpStack->Parameters.Read.ByteOffset.QuadPart + 1683 transferByteCount); 1684 1685 if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) || 1686 (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) { 1687 1688 // 1689 // This error maybe caused by the fact that the drive is not ready. 1690 // 1691 1692 if (((PDISK_DATA)(deviceExtension + 1))->DriveNotReady) { 1693 1694 // 1695 // Flag this as a user error so that a popup is generated. 1696 // 1697 1698 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY; 1699 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 1700 1701 } else { 1702 1703 // 1704 // Note fastfat depends on this parameter to determine when to 1705 // remount do to a sector size change. 1706 // 1707 1708 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 1709 } 1710 1711 if (startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) { 1712 DPRINT1("Reading beyond partition end! startingOffset: %I64d, PartitionLength: %I64d\n", startingOffset.QuadPart, deviceExtension->PartitionLength.QuadPart); 1713 } 1714 1715 if (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1)) { 1716 DPRINT1("Not reading sectors! TransferByteCount: %lu, BytesPerSector: %lu\n", transferByteCount, deviceExtension->DiskGeometry->Geometry.BytesPerSector); 1717 } 1718 1719 if (Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) { 1720 DPRINT1("Failing due to device not ready!\n"); 1721 } 1722 1723 return STATUS_INVALID_PARAMETER; 1724 } 1725 1726 return STATUS_SUCCESS; 1727 1728 } // end ScsiDiskReadWrite() 1729 1730 1731 NTSTATUS 1732 NTAPI 1733 ScsiDiskDeviceControl( 1734 PDEVICE_OBJECT DeviceObject, 1735 PIRP Irp 1736 ) 1737 1738 /*++ 1739 1740 Routine Description: 1741 1742 I/O system entry for device controls to SCSI disks. 1743 1744 Arguments: 1745 1746 DeviceObject - Pointer to driver object created by system. 1747 Irp - IRP involved. 1748 1749 Return Value: 1750 1751 Status is returned. 1752 1753 --*/ 1754 1755 { 1756 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 1757 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 1758 PDISK_DATA diskData = (PDISK_DATA)(deviceExtension + 1); 1759 PSCSI_REQUEST_BLOCK srb; 1760 PCDB cdb; 1761 PMODE_PARAMETER_HEADER modeData; 1762 PIRP irp2; 1763 ULONG length; 1764 NTSTATUS status; 1765 KEVENT event; 1766 IO_STATUS_BLOCK ioStatus; 1767 1768 PAGED_CODE(); 1769 1770 srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE); 1771 1772 if (srb == NULL) { 1773 1774 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 1775 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1776 return(STATUS_INSUFFICIENT_RESOURCES); 1777 } 1778 1779 // 1780 // Write zeros to Srb. 1781 // 1782 1783 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 1784 1785 cdb = (PCDB)srb->Cdb; 1786 1787 switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { 1788 1789 case SMART_GET_VERSION: { 1790 1791 ULONG_PTR buffer; 1792 PSRB_IO_CONTROL srbControl; 1793 PGETVERSIONINPARAMS versionParams; 1794 1795 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 1796 sizeof(GETVERSIONINPARAMS)) { 1797 status = STATUS_INVALID_PARAMETER; 1798 break; 1799 } 1800 1801 // 1802 // Create notification event object to be used to signal the 1803 // request completion. 1804 // 1805 1806 KeInitializeEvent(&event, NotificationEvent, FALSE); 1807 1808 srbControl = ExAllocatePool(NonPagedPool, 1809 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS)); 1810 1811 if (!srbControl) { 1812 status = STATUS_INSUFFICIENT_RESOURCES; 1813 break; 1814 } 1815 1816 // 1817 // fill in srbControl fields 1818 // 1819 1820 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); 1821 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); 1822 srbControl->Timeout = deviceExtension->TimeOutValue; 1823 srbControl->Length = sizeof(GETVERSIONINPARAMS); 1824 srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION; 1825 1826 // 1827 // Point to the 'buffer' portion of the SRB_CONTROL 1828 // 1829 1830 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 1831 1832 // 1833 // Ensure correct target is set in the cmd parameters. 1834 // 1835 1836 versionParams = (PGETVERSIONINPARAMS)buffer; 1837 versionParams->bIDEDeviceMap = deviceExtension->TargetId; 1838 1839 // 1840 // Copy the IOCTL parameters to the srb control buffer area. 1841 // 1842 1843 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(GETVERSIONINPARAMS)); 1844 1845 1846 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT, 1847 deviceExtension->PortDeviceObject, 1848 srbControl, 1849 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS), 1850 srbControl, 1851 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS), 1852 FALSE, 1853 &event, 1854 &ioStatus); 1855 1856 if (irp2 == NULL) { 1857 status = STATUS_INSUFFICIENT_RESOURCES; 1858 break; 1859 } 1860 1861 // 1862 // Call the port driver with the request and wait for it to complete. 1863 // 1864 1865 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2); 1866 1867 if (status == STATUS_PENDING) { 1868 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 1869 status = ioStatus.Status; 1870 } 1871 1872 // 1873 // If successful, copy the data received into the output buffer. 1874 // This should only fail in the event that the IDE driver is older than this driver. 1875 // 1876 1877 if (NT_SUCCESS(status)) { 1878 1879 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 1880 1881 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, sizeof(GETVERSIONINPARAMS)); 1882 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS); 1883 } 1884 1885 ExFreePool(srbControl); 1886 break; 1887 } 1888 1889 case SMART_RCV_DRIVE_DATA: { 1890 1891 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer); 1892 ULONG controlCode = 0; 1893 PSRB_IO_CONTROL srbControl; 1894 ULONG_PTR buffer; 1895 1896 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 1897 (sizeof(SENDCMDINPARAMS) - 1)) { 1898 status = STATUS_INVALID_PARAMETER; 1899 break; 1900 1901 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 1902 (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) { 1903 status = STATUS_INVALID_PARAMETER; 1904 break; 1905 } 1906 1907 // 1908 // Create notification event object to be used to signal the 1909 // request completion. 1910 // 1911 1912 KeInitializeEvent(&event, NotificationEvent, FALSE); 1913 1914 if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) { 1915 1916 length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); 1917 controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY; 1918 1919 } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) { 1920 switch (cmdInParameters->irDriveRegs.bFeaturesReg) { 1921 case READ_ATTRIBUTES: 1922 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; 1923 length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); 1924 break; 1925 case READ_THRESHOLDS: 1926 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; 1927 length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); 1928 break; 1929 default: 1930 status = STATUS_INVALID_PARAMETER; 1931 break; 1932 } 1933 } else { 1934 1935 status = STATUS_INVALID_PARAMETER; 1936 } 1937 1938 if (controlCode == 0) { 1939 status = STATUS_INVALID_PARAMETER; 1940 break; 1941 } 1942 1943 srbControl = ExAllocatePool(NonPagedPool, 1944 sizeof(SRB_IO_CONTROL) + length); 1945 1946 if (!srbControl) { 1947 status = STATUS_INSUFFICIENT_RESOURCES; 1948 break; 1949 } 1950 1951 // 1952 // fill in srbControl fields 1953 // 1954 1955 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); 1956 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); 1957 srbControl->Timeout = deviceExtension->TimeOutValue; 1958 srbControl->Length = length; 1959 srbControl->ControlCode = controlCode; 1960 1961 // 1962 // Point to the 'buffer' portion of the SRB_CONTROL 1963 // 1964 1965 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 1966 1967 // 1968 // Ensure correct target is set in the cmd parameters. 1969 // 1970 1971 cmdInParameters->bDriveNumber = deviceExtension->TargetId; 1972 1973 // 1974 // Copy the IOCTL parameters to the srb control buffer area. 1975 // 1976 1977 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1); 1978 1979 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT, 1980 deviceExtension->PortDeviceObject, 1981 srbControl, 1982 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1, 1983 srbControl, 1984 sizeof(SRB_IO_CONTROL) + length, 1985 FALSE, 1986 &event, 1987 &ioStatus); 1988 1989 if (irp2 == NULL) { 1990 status = STATUS_INSUFFICIENT_RESOURCES; 1991 break; 1992 } 1993 1994 // 1995 // Call the port driver with the request and wait for it to complete. 1996 // 1997 1998 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2); 1999 2000 if (status == STATUS_PENDING) { 2001 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 2002 status = ioStatus.Status; 2003 } 2004 2005 // 2006 // If successful, copy the data received into the output buffer 2007 // 2008 2009 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 2010 2011 if (NT_SUCCESS(status)) { 2012 2013 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length - 1); 2014 Irp->IoStatus.Information = length - 1; 2015 2016 } else { 2017 2018 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, (sizeof(SENDCMDOUTPARAMS) - 1)); 2019 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1; 2020 2021 } 2022 2023 ExFreePool(srbControl); 2024 break; 2025 2026 } 2027 2028 case SMART_SEND_DRIVE_COMMAND: { 2029 2030 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer); 2031 PSRB_IO_CONTROL srbControl; 2032 ULONG controlCode = 0; 2033 ULONG_PTR buffer; 2034 2035 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2036 (sizeof(SENDCMDINPARAMS) - 1)) { 2037 status = STATUS_INVALID_PARAMETER; 2038 break; 2039 2040 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 2041 (sizeof(SENDCMDOUTPARAMS) - 1)) { 2042 status = STATUS_INVALID_PARAMETER; 2043 break; 2044 } 2045 2046 // 2047 // Create notification event object to be used to signal the 2048 // request completion. 2049 // 2050 2051 KeInitializeEvent(&event, NotificationEvent, FALSE); 2052 2053 length = 0; 2054 2055 if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) { 2056 switch (cmdInParameters->irDriveRegs.bFeaturesReg) { 2057 2058 case ENABLE_SMART: 2059 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART; 2060 break; 2061 2062 case DISABLE_SMART: 2063 controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART; 2064 break; 2065 2066 case RETURN_SMART_STATUS: 2067 2068 // 2069 // Ensure bBuffer is at least 2 bytes (to hold the values of 2070 // cylinderLow and cylinderHigh). 2071 // 2072 2073 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 2074 (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) { 2075 2076 status = STATUS_INVALID_PARAMETER; 2077 break; 2078 } 2079 2080 controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS; 2081 length = sizeof(IDEREGS); 2082 break; 2083 2084 case ENABLE_DISABLE_AUTOSAVE: 2085 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; 2086 break; 2087 2088 case SAVE_ATTRIBUTE_VALUES: 2089 controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; 2090 break; 2091 2092 case EXECUTE_OFFLINE_DIAGS: 2093 controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; 2094 break; 2095 2096 default: 2097 status = STATUS_INVALID_PARAMETER; 2098 break; 2099 } 2100 } else { 2101 2102 status = STATUS_INVALID_PARAMETER; 2103 } 2104 2105 if (controlCode == 0) { 2106 status = STATUS_INVALID_PARAMETER; 2107 break; 2108 } 2109 2110 length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS); 2111 srbControl = ExAllocatePool(NonPagedPool, 2112 sizeof(SRB_IO_CONTROL) + length); 2113 2114 if (!srbControl) { 2115 status = STATUS_INSUFFICIENT_RESOURCES; 2116 break; 2117 } 2118 2119 // 2120 // fill in srbControl fields 2121 // 2122 2123 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); 2124 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); 2125 srbControl->Timeout = deviceExtension->TimeOutValue; 2126 srbControl->Length = length; 2127 2128 // 2129 // Point to the 'buffer' portion of the SRB_CONTROL 2130 // 2131 2132 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 2133 2134 // 2135 // Ensure correct target is set in the cmd parameters. 2136 // 2137 2138 cmdInParameters->bDriveNumber = deviceExtension->TargetId; 2139 2140 // 2141 // Copy the IOCTL parameters to the srb control buffer area. 2142 // 2143 2144 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1); 2145 2146 srbControl->ControlCode = controlCode; 2147 2148 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT, 2149 deviceExtension->PortDeviceObject, 2150 srbControl, 2151 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1, 2152 srbControl, 2153 sizeof(SRB_IO_CONTROL) + length, 2154 FALSE, 2155 &event, 2156 &ioStatus); 2157 2158 if (irp2 == NULL) { 2159 status = STATUS_INSUFFICIENT_RESOURCES; 2160 break; 2161 } 2162 2163 // 2164 // Call the port driver with the request and wait for it to complete. 2165 // 2166 2167 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2); 2168 2169 if (status == STATUS_PENDING) { 2170 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 2171 status = ioStatus.Status; 2172 } 2173 2174 // 2175 // Copy the data received into the output buffer. Since the status buffer 2176 // contains error information also, always perform this copy. IO will will 2177 // either pass this back to the app, or zero it, in case of error. 2178 // 2179 2180 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 2181 2182 // 2183 // Update the return buffer size based on the sub-command. 2184 // 2185 2186 if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) { 2187 length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS); 2188 } else { 2189 length = sizeof(SENDCMDOUTPARAMS) - 1; 2190 } 2191 2192 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length); 2193 Irp->IoStatus.Information = length; 2194 2195 ExFreePool(srbControl); 2196 break; 2197 2198 } 2199 2200 case IOCTL_DISK_GET_DRIVE_GEOMETRY: 2201 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: 2202 { 2203 2204 PDEVICE_EXTENSION physicalDeviceExtension; 2205 PDISK_DATA physicalDiskData; 2206 BOOLEAN removable = FALSE; 2207 BOOLEAN listInitialized = FALSE; 2208 ULONG copyLength; 2209 2210 if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) { 2211 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) { 2212 status = STATUS_BUFFER_TOO_SMALL; 2213 break; 2214 } 2215 2216 copyLength = sizeof(DISK_GEOMETRY); 2217 } else { 2218 ASSERT(irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX); 2219 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(DISK_GEOMETRY_EX, Data)) { 2220 status = STATUS_BUFFER_TOO_SMALL; 2221 break; 2222 } 2223 2224 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(DISK_GEOMETRY_EX)) { 2225 copyLength = sizeof(DISK_GEOMETRY_EX); 2226 } else { 2227 copyLength = FIELD_OFFSET(DISK_GEOMETRY_EX, Data); 2228 } 2229 } 2230 2231 status = STATUS_SUCCESS; 2232 2233 physicalDeviceExtension = deviceExtension->PhysicalDevice->DeviceExtension; 2234 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1); 2235 2236 removable = (BOOLEAN)DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA; 2237 listInitialized = (physicalDiskData->PartitionListState == Initialized); 2238 2239 if (removable || (!listInitialized)) 2240 { 2241 // 2242 // Issue ReadCapacity to update device extension 2243 // with information for current media. 2244 // 2245 2246 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice); 2247 2248 } 2249 2250 if (removable) { 2251 2252 if (!NT_SUCCESS(status)) { 2253 2254 // 2255 // Note the drive is not ready. 2256 // 2257 2258 diskData->DriveNotReady = TRUE; 2259 2260 break; 2261 } 2262 2263 // 2264 // Note the drive is now ready. 2265 // 2266 2267 diskData->DriveNotReady = FALSE; 2268 2269 } else if (NT_SUCCESS(status)) { 2270 2271 // ReadDriveCapacity was alright, create Partition Objects 2272 2273 if (physicalDiskData->PartitionListState == NotInitialized) { 2274 status = CreatePartitionDeviceObjects(deviceExtension->PhysicalDevice, NULL); 2275 } 2276 } 2277 2278 if (NT_SUCCESS(status)) { 2279 2280 // 2281 // Copy drive geometry information from device extension. 2282 // 2283 2284 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, 2285 deviceExtension->DiskGeometry, 2286 copyLength); 2287 2288 status = STATUS_SUCCESS; 2289 Irp->IoStatus.Information = copyLength; 2290 } 2291 2292 break; 2293 2294 } 2295 2296 case IOCTL_DISK_VERIFY: 2297 2298 { 2299 2300 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer; 2301 LARGE_INTEGER byteOffset; 2302 ULONG sectorOffset; 2303 USHORT sectorCount; 2304 2305 // 2306 // Validate buffer length. 2307 // 2308 2309 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2310 sizeof(VERIFY_INFORMATION)) { 2311 2312 status = STATUS_INFO_LENGTH_MISMATCH; 2313 break; 2314 } 2315 2316 // 2317 // Verify sectors 2318 // 2319 2320 srb->CdbLength = 10; 2321 2322 cdb->CDB10.OperationCode = SCSIOP_VERIFY; 2323 2324 // 2325 // Add disk offset to starting sector. 2326 // 2327 2328 byteOffset.QuadPart = deviceExtension->StartingOffset.QuadPart + 2329 verifyInfo->StartingOffset.QuadPart; 2330 2331 // 2332 // Convert byte offset to sector offset. 2333 // 2334 2335 sectorOffset = (ULONG)(byteOffset.QuadPart >> deviceExtension->SectorShift); 2336 2337 // 2338 // Convert ULONG byte count to USHORT sector count. 2339 // 2340 2341 sectorCount = (USHORT)(verifyInfo->Length >> deviceExtension->SectorShift); 2342 2343 // 2344 // Move little endian values into CDB in big endian format. 2345 // 2346 2347 cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)§orOffset)->Byte3; 2348 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)§orOffset)->Byte2; 2349 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)§orOffset)->Byte1; 2350 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)§orOffset)->Byte0; 2351 2352 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)§orCount)->Byte1; 2353 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)§orCount)->Byte0; 2354 2355 // 2356 // The verify command is used by the NT FORMAT utility and 2357 // requests are sent down for 5% of the volume size. The 2358 // request timeout value is calculated based on the number of 2359 // sectors verified. 2360 // 2361 2362 srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) * 2363 deviceExtension->TimeOutValue; 2364 2365 status = ScsiClassSendSrbAsynchronous(DeviceObject, 2366 srb, 2367 Irp, 2368 NULL, 2369 0, 2370 FALSE); 2371 2372 return(status); 2373 2374 } 2375 2376 case IOCTL_DISK_GET_PARTITION_INFO: 2377 2378 // 2379 // Return the information about the partition specified by the device 2380 // object. Note that no information is ever returned about the size 2381 // or partition type of the physical disk, as this doesn't make any 2382 // sense. 2383 // 2384 2385 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 2386 sizeof(PARTITION_INFORMATION)) { 2387 2388 status = STATUS_INFO_LENGTH_MISMATCH; 2389 break; 2390 } 2391 2392 // 2393 // Update the geometry in case it has changed. 2394 // 2395 2396 status = UpdateRemovableGeometry (DeviceObject, Irp); 2397 2398 if (!NT_SUCCESS(status)) { 2399 2400 // 2401 // Note the drive is not ready. 2402 // 2403 2404 diskData->DriveNotReady = TRUE; 2405 break; 2406 } 2407 2408 // 2409 // Note the drive is now ready. 2410 // 2411 2412 diskData->DriveNotReady = FALSE; 2413 2414 // 2415 // Handle the case were we query the whole disk 2416 // 2417 2418 if (diskData->PartitionNumber == 0) { 2419 2420 PPARTITION_INFORMATION outputBuffer; 2421 2422 outputBuffer = 2423 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 2424 2425 outputBuffer->PartitionType = PARTITION_ENTRY_UNUSED; 2426 outputBuffer->StartingOffset = deviceExtension->StartingOffset; 2427 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart; 2428 outputBuffer->HiddenSectors = 0; 2429 outputBuffer->PartitionNumber = diskData->PartitionNumber; 2430 outputBuffer->BootIndicator = FALSE; 2431 outputBuffer->RewritePartition = FALSE; 2432 outputBuffer->RecognizedPartition = FALSE; 2433 2434 status = STATUS_SUCCESS; 2435 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION); 2436 2437 } else { 2438 2439 PPARTITION_INFORMATION outputBuffer; 2440 2441 // 2442 // We query a single partition here 2443 // FIXME: this can only work for MBR-based disks, check for this! 2444 // 2445 2446 outputBuffer = 2447 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 2448 2449 outputBuffer->PartitionType = diskData->PartitionType; 2450 outputBuffer->StartingOffset = deviceExtension->StartingOffset; 2451 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart; 2452 outputBuffer->HiddenSectors = diskData->HiddenSectors; 2453 outputBuffer->PartitionNumber = diskData->PartitionNumber; 2454 outputBuffer->BootIndicator = diskData->BootIndicator; 2455 outputBuffer->RewritePartition = FALSE; 2456 outputBuffer->RecognizedPartition = 2457 IsRecognizedPartition(diskData->PartitionType); 2458 2459 status = STATUS_SUCCESS; 2460 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION); 2461 } 2462 2463 break; 2464 2465 case IOCTL_DISK_GET_PARTITION_INFO_EX: 2466 2467 // 2468 // Return the information about the partition specified by the device 2469 // object. Note that no information is ever returned about the size 2470 // or partition type of the physical disk, as this doesn't make any 2471 // sense. 2472 // 2473 2474 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 2475 sizeof(PARTITION_INFORMATION_EX)) { 2476 2477 status = STATUS_INFO_LENGTH_MISMATCH; 2478 2479 } 2480 #if 0 // HACK: ReactOS partition numbers must be wrong 2481 else if (diskData->PartitionNumber == 0) { 2482 2483 // 2484 // Partition zero is not a partition so this is not a 2485 // reasonable request. 2486 // 2487 2488 status = STATUS_INVALID_DEVICE_REQUEST; 2489 2490 } 2491 #endif 2492 else { 2493 2494 PPARTITION_INFORMATION_EX outputBuffer; 2495 2496 if (diskData->PartitionNumber == 0) { 2497 DPRINT1("HACK: Handling partition 0 request!\n"); 2498 //ASSERT(FALSE); 2499 } 2500 2501 // 2502 // Update the geometry in case it has changed. 2503 // 2504 2505 status = UpdateRemovableGeometry (DeviceObject, Irp); 2506 2507 if (!NT_SUCCESS(status)) { 2508 2509 // 2510 // Note the drive is not ready. 2511 // 2512 2513 diskData->DriveNotReady = TRUE; 2514 break; 2515 } 2516 2517 // 2518 // Note the drive is now ready. 2519 // 2520 2521 diskData->DriveNotReady = FALSE; 2522 2523 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) { 2524 2525 status = STATUS_INVALID_DEVICE_REQUEST; 2526 break; 2527 } 2528 2529 outputBuffer = 2530 (PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer; 2531 2532 // 2533 // FIXME: hack of the year, assume that partition is MBR 2534 // Thing that can obviously be wrong... 2535 // 2536 2537 outputBuffer->PartitionStyle = PARTITION_STYLE_MBR; 2538 outputBuffer->Mbr.PartitionType = diskData->PartitionType; 2539 outputBuffer->StartingOffset = deviceExtension->StartingOffset; 2540 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart; 2541 outputBuffer->Mbr.HiddenSectors = diskData->HiddenSectors; 2542 outputBuffer->PartitionNumber = diskData->PartitionNumber; 2543 outputBuffer->Mbr.BootIndicator = diskData->BootIndicator; 2544 outputBuffer->RewritePartition = FALSE; 2545 outputBuffer->Mbr.RecognizedPartition = 2546 IsRecognizedPartition(diskData->PartitionType); 2547 2548 status = STATUS_SUCCESS; 2549 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX); 2550 } 2551 2552 break; 2553 2554 case IOCTL_DISK_SET_PARTITION_INFO: 2555 2556 if (diskData->PartitionNumber == 0) { 2557 2558 status = STATUS_UNSUCCESSFUL; 2559 2560 } else { 2561 2562 PSET_PARTITION_INFORMATION inputBuffer = 2563 (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 2564 2565 // 2566 // Validate buffer length. 2567 // 2568 2569 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2570 sizeof(SET_PARTITION_INFORMATION)) { 2571 2572 status = STATUS_INFO_LENGTH_MISMATCH; 2573 break; 2574 } 2575 2576 // 2577 // The HAL routines IoGet- and IoSetPartitionInformation were 2578 // developed before support of dynamic partitioning and therefore 2579 // don't distinguish between partition ordinal (that is the order 2580 // of a partition on a disk) and the partition number. (The 2581 // partition number is assigned to a partition to identify it to 2582 // the system.) Use partition ordinals for these legacy calls. 2583 // 2584 2585 status = IoSetPartitionInformation( 2586 deviceExtension->PhysicalDevice, 2587 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 2588 diskData->PartitionOrdinal, 2589 inputBuffer->PartitionType); 2590 2591 if (NT_SUCCESS(status)) { 2592 2593 diskData->PartitionType = inputBuffer->PartitionType; 2594 } 2595 } 2596 2597 break; 2598 2599 case IOCTL_DISK_GET_DRIVE_LAYOUT: 2600 2601 // 2602 // Return the partition layout for the physical drive. Note that 2603 // the layout is returned for the actual physical drive, regardless 2604 // of which partition was specified for the request. 2605 // 2606 2607 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 2608 sizeof(DRIVE_LAYOUT_INFORMATION)) { 2609 status = STATUS_INFO_LENGTH_MISMATCH; 2610 2611 } else { 2612 2613 PDRIVE_LAYOUT_INFORMATION partitionList; 2614 PDEVICE_EXTENSION physicalExtension = deviceExtension; 2615 PPARTITION_INFORMATION partitionEntry; 2616 PDISK_DATA diskData; 2617 ULONG tempSize; 2618 ULONG i; 2619 2620 // 2621 // Read partition information. 2622 // 2623 2624 status = IoReadPartitionTable(deviceExtension->PhysicalDevice, 2625 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 2626 FALSE, 2627 &partitionList); 2628 2629 if (!NT_SUCCESS(status)) { 2630 break; 2631 } 2632 2633 // 2634 // The disk layout has been returned in the partitionList 2635 // buffer. Determine its size and, if the data will fit 2636 // into the intermediary buffer, return it. 2637 // 2638 2639 tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]); 2640 tempSize += partitionList->PartitionCount * 2641 sizeof(PARTITION_INFORMATION); 2642 2643 if (tempSize > 2644 irpStack->Parameters.DeviceIoControl.OutputBufferLength) { 2645 2646 status = STATUS_BUFFER_TOO_SMALL; 2647 ExFreePool(partitionList); 2648 break; 2649 } 2650 2651 // 2652 // Walk partition list to associate partition numbers with 2653 // partition entries. 2654 // 2655 2656 for (i = 0; i < partitionList->PartitionCount; i++) { 2657 2658 // 2659 // Walk partition chain anchored at physical disk extension. 2660 // 2661 2662 deviceExtension = physicalExtension; 2663 diskData = (PDISK_DATA)(deviceExtension + 1); 2664 2665 do { 2666 2667 deviceExtension = diskData->NextPartition; 2668 2669 // 2670 // Check if this is the last partition in the chain. 2671 // 2672 2673 if (!deviceExtension) { 2674 break; 2675 } 2676 2677 // 2678 // Get the partition device extension from disk data. 2679 // 2680 2681 diskData = (PDISK_DATA)(deviceExtension + 1); 2682 2683 // 2684 // Check if this partition is not currently being used. 2685 // 2686 2687 if (!deviceExtension->PartitionLength.QuadPart) { 2688 continue; 2689 } 2690 2691 partitionEntry = &partitionList->PartitionEntry[i]; 2692 2693 // 2694 // Check if empty, or describes extended partition or hasn't changed. 2695 // 2696 2697 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED || 2698 IsContainerPartition(partitionEntry->PartitionType)) { 2699 continue; 2700 } 2701 2702 // 2703 // Check if new partition starts where this partition starts. 2704 // 2705 2706 if (partitionEntry->StartingOffset.QuadPart != 2707 deviceExtension->StartingOffset.QuadPart) { 2708 continue; 2709 } 2710 2711 // 2712 // Check if partition length is the same. 2713 // 2714 2715 if (partitionEntry->PartitionLength.QuadPart == 2716 deviceExtension->PartitionLength.QuadPart) { 2717 2718 // 2719 // Partitions match. Update partition number. 2720 // 2721 2722 partitionEntry->PartitionNumber = 2723 diskData->PartitionNumber; 2724 break; 2725 } 2726 2727 } while (TRUE); 2728 } 2729 2730 // 2731 // Copy partition information to system buffer. 2732 // 2733 2734 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, 2735 partitionList, 2736 tempSize); 2737 status = STATUS_SUCCESS; 2738 Irp->IoStatus.Information = tempSize; 2739 2740 // 2741 // Finally, free the buffer allocated by reading the 2742 // partition table. 2743 // 2744 2745 ExFreePool(partitionList); 2746 } 2747 2748 break; 2749 2750 case IOCTL_DISK_SET_DRIVE_LAYOUT: 2751 2752 { 2753 2754 // 2755 // Update the disk with new partition information. 2756 // 2757 2758 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer; 2759 2760 // 2761 // Validate buffer length. 2762 // 2763 2764 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2765 sizeof(DRIVE_LAYOUT_INFORMATION)) { 2766 2767 status = STATUS_INFO_LENGTH_MISMATCH; 2768 break; 2769 } 2770 2771 length = sizeof(DRIVE_LAYOUT_INFORMATION) + 2772 (partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION); 2773 2774 2775 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2776 length) { 2777 2778 status = STATUS_BUFFER_TOO_SMALL; 2779 break; 2780 } 2781 2782 // 2783 // Verify that device object is for physical disk. 2784 // 2785 2786 if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) { 2787 status = STATUS_INVALID_PARAMETER; 2788 break; 2789 } 2790 2791 // 2792 // Walk through partition table comparing partitions to 2793 // existing partitions to create, delete and change 2794 // device objects as necessary. 2795 // 2796 2797 UpdateDeviceObjects(DeviceObject, 2798 Irp); 2799 2800 // 2801 // Write changes to disk. 2802 // 2803 2804 status = IoWritePartitionTable( 2805 deviceExtension->DeviceObject, 2806 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 2807 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack, 2808 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder, 2809 partitionList); 2810 } 2811 2812 // 2813 // Update IRP with bytes returned. 2814 // 2815 2816 if (NT_SUCCESS(status)) { 2817 Irp->IoStatus.Information = length; 2818 } 2819 2820 break; 2821 2822 case IOCTL_DISK_REASSIGN_BLOCKS: 2823 2824 // 2825 // Map defective blocks to new location on disk. 2826 // 2827 2828 { 2829 2830 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer; 2831 ULONG bufferSize; 2832 ULONG blockNumber; 2833 ULONG blockCount; 2834 2835 // 2836 // Validate buffer length. 2837 // 2838 2839 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2840 sizeof(REASSIGN_BLOCKS)) { 2841 2842 status = STATUS_INFO_LENGTH_MISMATCH; 2843 break; 2844 } 2845 2846 bufferSize = sizeof(REASSIGN_BLOCKS) + 2847 (badBlocks->Count - 1) * sizeof(ULONG); 2848 2849 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2850 bufferSize) { 2851 2852 status = STATUS_INFO_LENGTH_MISMATCH; 2853 break; 2854 } 2855 2856 // 2857 // Build the data buffer to be transferred in the input buffer. 2858 // The format of the data to the device is: 2859 // 2860 // 2 bytes Reserved 2861 // 2 bytes Length 2862 // x * 4 btyes Block Address 2863 // 2864 // All values are big endian. 2865 // 2866 2867 badBlocks->Reserved = 0; 2868 blockCount = badBlocks->Count; 2869 2870 // 2871 // Convert # of entries to # of bytes. 2872 // 2873 2874 blockCount *= 4; 2875 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF); 2876 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00); 2877 2878 // 2879 // Convert back to number of entries. 2880 // 2881 2882 blockCount /= 4; 2883 2884 for (; blockCount > 0; blockCount--) { 2885 2886 blockNumber = badBlocks->BlockNumber[blockCount-1]; 2887 2888 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1], 2889 (PFOUR_BYTE) &blockNumber); 2890 } 2891 2892 srb->CdbLength = 6; 2893 2894 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS; 2895 2896 // 2897 // Set timeout value. 2898 // 2899 2900 srb->TimeOutValue = deviceExtension->TimeOutValue; 2901 2902 status = ScsiClassSendSrbSynchronous(DeviceObject, 2903 srb, 2904 badBlocks, 2905 bufferSize, 2906 TRUE); 2907 2908 Irp->IoStatus.Status = status; 2909 Irp->IoStatus.Information = 0; 2910 ExFreePool(srb); 2911 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2912 } 2913 2914 return(status); 2915 2916 case IOCTL_DISK_IS_WRITABLE: 2917 2918 // 2919 // Determine if the device is writable. 2920 // 2921 2922 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE); 2923 2924 if (modeData == NULL) { 2925 status = STATUS_INSUFFICIENT_RESOURCES; 2926 break; 2927 } 2928 2929 RtlZeroMemory(modeData, MODE_DATA_SIZE); 2930 2931 length = ScsiClassModeSense(DeviceObject, 2932 (PCHAR) modeData, 2933 MODE_DATA_SIZE, 2934 MODE_SENSE_RETURN_ALL); 2935 2936 if (length < sizeof(MODE_PARAMETER_HEADER)) { 2937 2938 // 2939 // Retry the request in case of a check condition. 2940 // 2941 2942 length = ScsiClassModeSense(DeviceObject, 2943 (PCHAR) modeData, 2944 MODE_DATA_SIZE, 2945 MODE_SENSE_RETURN_ALL); 2946 2947 if (length < sizeof(MODE_PARAMETER_HEADER)) { 2948 status = STATUS_IO_DEVICE_ERROR; 2949 ExFreePool(modeData); 2950 break; 2951 } 2952 } 2953 2954 if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) { 2955 status = STATUS_MEDIA_WRITE_PROTECTED; 2956 } else { 2957 status = STATUS_SUCCESS; 2958 } 2959 2960 ExFreePool(modeData); 2961 break; 2962 2963 case IOCTL_DISK_INTERNAL_SET_VERIFY: 2964 2965 // 2966 // If the caller is kernel mode, set the verify bit. 2967 // 2968 2969 if (Irp->RequestorMode == KernelMode) { 2970 DeviceObject->Flags |= DO_VERIFY_VOLUME; 2971 } 2972 status = STATUS_SUCCESS; 2973 break; 2974 2975 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY: 2976 2977 // 2978 // If the caller is kernel mode, clear the verify bit. 2979 // 2980 2981 if (Irp->RequestorMode == KernelMode) { 2982 DeviceObject->Flags &= ~DO_VERIFY_VOLUME; 2983 } 2984 status = STATUS_SUCCESS; 2985 break; 2986 2987 case IOCTL_DISK_FIND_NEW_DEVICES: 2988 2989 // 2990 // Search for devices that have been powered on since the last 2991 // device search or system initialization. 2992 // 2993 2994 DebugPrint((3,"CdRomDeviceControl: Find devices\n")); 2995 status = DriverEntry(DeviceObject->DriverObject, 2996 NULL); 2997 2998 Irp->IoStatus.Status = status; 2999 ExFreePool(srb); 3000 IoCompleteRequest(Irp, IO_NO_INCREMENT); 3001 return status; 3002 3003 case IOCTL_DISK_MEDIA_REMOVAL: 3004 3005 // 3006 // If the disk is not removable then don't allow this command. 3007 // 3008 3009 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) { 3010 status = STATUS_INVALID_DEVICE_REQUEST; 3011 break; 3012 } 3013 3014 // 3015 // Fall through and let the class driver process the request. 3016 // 3017 3018 case IOCTL_DISK_GET_LENGTH_INFO: 3019 3020 // 3021 // Validate buffer length. 3022 // 3023 3024 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 3025 sizeof(GET_LENGTH_INFORMATION)) { 3026 status = STATUS_BUFFER_TOO_SMALL; 3027 3028 } else { 3029 3030 PGET_LENGTH_INFORMATION lengthInformation = Irp->AssociatedIrp.SystemBuffer; 3031 3032 // 3033 // Update the geometry in case it has changed. 3034 // 3035 3036 status = UpdateRemovableGeometry (DeviceObject, Irp); 3037 3038 if (!NT_SUCCESS(status)) { 3039 3040 // 3041 // Note the drive is not ready. 3042 // 3043 3044 diskData->DriveNotReady = TRUE; 3045 break; 3046 } 3047 3048 // 3049 // Note the drive is now ready. 3050 // 3051 3052 diskData->DriveNotReady = FALSE; 3053 3054 // 3055 // Output data, and return 3056 // 3057 3058 lengthInformation->Length.QuadPart = deviceExtension->PartitionLength.QuadPart; 3059 status = STATUS_SUCCESS; 3060 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION); 3061 } 3062 3063 break; 3064 3065 default: 3066 3067 // 3068 // Free the Srb, since it is not needed. 3069 // 3070 3071 ExFreePool(srb); 3072 3073 // 3074 // Pass the request to the common device control routine. 3075 // 3076 3077 return(ScsiClassDeviceControl(DeviceObject, Irp)); 3078 3079 break; 3080 3081 } // end switch( ... 3082 3083 Irp->IoStatus.Status = status; 3084 3085 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) { 3086 3087 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 3088 } 3089 3090 IoCompleteRequest(Irp, IO_NO_INCREMENT); 3091 ExFreePool(srb); 3092 return(status); 3093 3094 } // end ScsiDiskDeviceControl() 3095 3096 NTSTATUS 3097 NTAPI 3098 ScsiDiskShutdownFlush ( 3099 IN PDEVICE_OBJECT DeviceObject, 3100 IN PIRP Irp 3101 ) 3102 3103 /*++ 3104 3105 Routine Description: 3106 3107 This routine is called for a shutdown and flush IRPs. These are sent by the 3108 system before it actually shuts down or when the file system does a flush. 3109 A synchronize cache command is sent to the device if it is write caching. 3110 If the device is removable an unlock command will be sent. This routine 3111 will sent a shutdown or flush Srb to the port driver. 3112 3113 Arguments: 3114 3115 DriverObject - Pointer to device object to being shutdown by system. 3116 3117 Irp - IRP involved. 3118 3119 Return Value: 3120 3121 NT Status 3122 3123 --*/ 3124 3125 { 3126 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 3127 PIO_STACK_LOCATION irpStack; 3128 PSCSI_REQUEST_BLOCK srb; 3129 NTSTATUS status; 3130 PCDB cdb; 3131 3132 // 3133 // Allocate SCSI request block. 3134 // 3135 3136 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK)); 3137 3138 if (srb == NULL) { 3139 3140 // 3141 // Set the status and complete the request. 3142 // 3143 3144 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 3145 IoCompleteRequest(Irp, IO_NO_INCREMENT); 3146 return(STATUS_INSUFFICIENT_RESOURCES); 3147 } 3148 3149 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 3150 3151 // 3152 // Write length to SRB. 3153 // 3154 3155 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 3156 3157 // 3158 // Set SCSI bus address. 3159 // 3160 3161 srb->PathId = deviceExtension->PathId; 3162 srb->TargetId = deviceExtension->TargetId; 3163 srb->Lun = deviceExtension->Lun; 3164 3165 // 3166 // Set timeout value and mark the request as not being a tagged request. 3167 // 3168 3169 srb->TimeOutValue = deviceExtension->TimeOutValue * 4; 3170 srb->QueueTag = SP_UNTAGGED; 3171 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 3172 srb->SrbFlags = deviceExtension->SrbFlags; 3173 3174 // 3175 // If the write cache is enabled then send a synchronize cache request. 3176 // 3177 3178 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) { 3179 3180 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 3181 srb->CdbLength = 10; 3182 3183 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE; 3184 3185 status = ScsiClassSendSrbSynchronous(DeviceObject, 3186 srb, 3187 NULL, 3188 0, 3189 TRUE); 3190 3191 DebugPrint((1, "ScsiDiskShutdownFlush: Synchronize cache sent. Status = %lx\n", status )); 3192 } 3193 3194 // 3195 // Unlock the device if it is removable and this is a shutdown. 3196 // 3197 3198 irpStack = IoGetCurrentIrpStackLocation(Irp); 3199 3200 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA && 3201 irpStack->MajorFunction == IRP_MJ_SHUTDOWN) { 3202 3203 srb->CdbLength = 6; 3204 cdb = (PVOID) srb->Cdb; 3205 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; 3206 cdb->MEDIA_REMOVAL.Prevent = FALSE; 3207 3208 // 3209 // Set timeout value. 3210 // 3211 3212 srb->TimeOutValue = deviceExtension->TimeOutValue; 3213 status = ScsiClassSendSrbSynchronous(DeviceObject, 3214 srb, 3215 NULL, 3216 0, 3217 TRUE); 3218 3219 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status )); 3220 } 3221 3222 srb->CdbLength = 0; 3223 3224 // 3225 // Save a few parameters in the current stack location. 3226 // 3227 3228 srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ? 3229 SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH; 3230 3231 // 3232 // Set the retry count to zero. 3233 // 3234 3235 irpStack->Parameters.Others.Argument4 = (PVOID) 0; 3236 3237 // 3238 // Set up IoCompletion routine address. 3239 // 3240 3241 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE); 3242 3243 // 3244 // Get next stack location and 3245 // set major function code. 3246 // 3247 3248 irpStack = IoGetNextIrpStackLocation(Irp); 3249 3250 irpStack->MajorFunction = IRP_MJ_SCSI; 3251 3252 // 3253 // Set up SRB for execute scsi request. 3254 // Save SRB address in next stack for port driver. 3255 // 3256 3257 irpStack->Parameters.Scsi.Srb = srb; 3258 3259 // 3260 // Set up Irp Address. 3261 // 3262 3263 srb->OriginalRequest = Irp; 3264 3265 // 3266 // Call the port driver to process the request. 3267 // 3268 3269 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp)); 3270 3271 } // end ScsiDiskShutdown() 3272 3273 3274 BOOLEAN 3275 NTAPI 3276 IsFloppyDevice( 3277 PDEVICE_OBJECT DeviceObject 3278 ) 3279 /*++ 3280 3281 Routine Description: 3282 3283 The routine performs the necessary functions to determine if a device is 3284 really a floppy rather than a harddisk. This is done by a mode sense 3285 command. First, a check is made to see if the media type is set. Second 3286 a check is made for the flexible parameters mode page. Also a check is 3287 made to see if the write cache is enabled. 3288 3289 Arguments: 3290 3291 DeviceObject - Supplies the device object to be tested. 3292 3293 Return Value: 3294 3295 Return TRUE if the indicated device is a floppy. 3296 3297 --*/ 3298 { 3299 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 3300 PVOID modeData; 3301 PUCHAR pageData; 3302 ULONG length; 3303 3304 PAGED_CODE(); 3305 3306 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE); 3307 3308 if (modeData == NULL) { 3309 return(FALSE); 3310 } 3311 3312 RtlZeroMemory(modeData, MODE_DATA_SIZE); 3313 3314 length = ScsiClassModeSense(DeviceObject, 3315 modeData, 3316 MODE_DATA_SIZE, 3317 MODE_SENSE_RETURN_ALL); 3318 3319 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3320 3321 // 3322 // Retry the request in case of a check condition. 3323 // 3324 3325 length = ScsiClassModeSense(DeviceObject, 3326 modeData, 3327 MODE_DATA_SIZE, 3328 MODE_SENSE_RETURN_ALL); 3329 3330 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3331 3332 ExFreePool(modeData); 3333 return(FALSE); 3334 3335 } 3336 } 3337 3338 // 3339 // If the length is greater than length indicated by the mode data reset 3340 // the data to the mode data. 3341 // 3342 3343 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) { 3344 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1; 3345 } 3346 3347 // 3348 // Look for the flexible disk mode page. 3349 // 3350 3351 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE); 3352 3353 if (pageData != NULL) { 3354 3355 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n")); 3356 ExFreePool(modeData); 3357 return(TRUE); 3358 } 3359 3360 // 3361 // Check to see if the write cache is enabled. 3362 // 3363 3364 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE); 3365 3366 // 3367 // Assume that write cache is disabled or not supported. 3368 // 3369 3370 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 3371 3372 // 3373 // Check if valid caching page exists. 3374 // 3375 3376 if (pageData != NULL) { 3377 3378 // 3379 // Check if write cache is disabled. 3380 // 3381 3382 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) { 3383 3384 DebugPrint((1, 3385 "SCSIDISK: Disk write cache enabled\n")); 3386 3387 // 3388 // Check if forced unit access (FUA) is supported. 3389 // 3390 3391 if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) { 3392 3393 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE; 3394 3395 } else { 3396 3397 DebugPrint((1, 3398 "SCSIDISK: Disk does not support FUA or DPO\n")); 3399 3400 // 3401 // TODO: Log this. 3402 // 3403 3404 } 3405 } 3406 } 3407 3408 ExFreePool(modeData); 3409 return(FALSE); 3410 3411 } // end IsFloppyDevice() 3412 3413 3414 BOOLEAN 3415 NTAPI 3416 ScsiDiskModeSelect( 3417 IN PDEVICE_OBJECT DeviceObject, 3418 IN PCHAR ModeSelectBuffer, 3419 IN ULONG Length, 3420 IN BOOLEAN SavePage 3421 ) 3422 3423 /*++ 3424 3425 Routine Description: 3426 3427 This routine sends a mode select command. 3428 3429 Arguments: 3430 3431 DeviceObject - Supplies the device object associated with this request. 3432 3433 ModeSelectBuffer - Supplies a buffer containing the page data. 3434 3435 Length - Supplies the length in bytes of the mode select buffer. 3436 3437 SavePage - Indicates that parameters should be written to disk. 3438 3439 Return Value: 3440 3441 Length of the transferred data is returned. 3442 3443 --*/ 3444 { 3445 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 3446 PCDB cdb; 3447 SCSI_REQUEST_BLOCK srb; 3448 ULONG retries = 1; 3449 ULONG length2; 3450 NTSTATUS status; 3451 ULONG_PTR buffer; 3452 PMODE_PARAMETER_BLOCK blockDescriptor; 3453 3454 PAGED_CODE(); 3455 3456 length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK); 3457 3458 // 3459 // Allocate buffer for mode select header, block descriptor, and mode page. 3460 // 3461 3462 buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2); 3463 3464 RtlZeroMemory((PVOID)buffer, length2); 3465 3466 // 3467 // Set length in header to size of mode page. 3468 // 3469 3470 ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK); 3471 3472 blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1); 3473 3474 // 3475 // Set size 3476 // 3477 3478 blockDescriptor->BlockLength[1]=0x02; 3479 3480 // 3481 // Copy mode page to buffer. 3482 // 3483 3484 RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length); 3485 3486 // 3487 // Zero SRB. 3488 // 3489 3490 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 3491 3492 // 3493 // Build the MODE SELECT CDB. 3494 // 3495 3496 srb.CdbLength = 6; 3497 cdb = (PCDB)srb.Cdb; 3498 3499 // 3500 // Set timeout value from device extension. 3501 // 3502 3503 srb.TimeOutValue = deviceExtension->TimeOutValue * 2; 3504 3505 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; 3506 cdb->MODE_SELECT.SPBit = SavePage; 3507 cdb->MODE_SELECT.PFBit = 1; 3508 cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2); 3509 3510 Retry: 3511 3512 status = ScsiClassSendSrbSynchronous(DeviceObject, 3513 &srb, 3514 (PVOID)buffer, 3515 length2, 3516 TRUE); 3517 3518 3519 if (status == STATUS_VERIFY_REQUIRED) { 3520 3521 // 3522 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with 3523 // this status. 3524 // 3525 3526 if (retries--) { 3527 3528 // 3529 // Retry request. 3530 // 3531 3532 goto Retry; 3533 } 3534 3535 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) { 3536 status = STATUS_SUCCESS; 3537 } 3538 3539 ExFreePool((PVOID)buffer); 3540 3541 if (NT_SUCCESS(status)) { 3542 return(TRUE); 3543 } else { 3544 return(FALSE); 3545 } 3546 3547 } // end SciDiskModeSelect() 3548 3549 3550 VOID 3551 NTAPI 3552 DisableWriteCache( 3553 IN PDEVICE_OBJECT DeviceObject, 3554 IN PSCSI_INQUIRY_DATA LunInfo 3555 ) 3556 3557 { 3558 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 3559 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData; 3560 BAD_CONTROLLER_INFORMATION const *controller; 3561 ULONG j,length; 3562 PVOID modeData; 3563 PUCHAR pageData; 3564 3565 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) { 3566 3567 controller = &ScsiDiskBadControllers[j]; 3568 3569 if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) { 3570 continue; 3571 } 3572 3573 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString)); 3574 3575 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE); 3576 3577 if (modeData == NULL) { 3578 3579 DebugPrint((1, 3580 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n")); 3581 return; 3582 } 3583 3584 RtlZeroMemory(modeData, MODE_DATA_SIZE); 3585 3586 length = ScsiClassModeSense(DeviceObject, 3587 modeData, 3588 MODE_DATA_SIZE, 3589 MODE_SENSE_RETURN_ALL); 3590 3591 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3592 3593 // 3594 // Retry the request in case of a check condition. 3595 // 3596 3597 length = ScsiClassModeSense(DeviceObject, 3598 modeData, 3599 MODE_DATA_SIZE, 3600 MODE_SENSE_RETURN_ALL); 3601 3602 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3603 3604 3605 DebugPrint((1, 3606 "ScsiDisk.DisableWriteCache: Mode Sense failed\n")); 3607 3608 ExFreePool(modeData); 3609 return; 3610 3611 } 3612 } 3613 3614 // 3615 // If the length is greater than length indicated by the mode data reset 3616 // the data to the mode data. 3617 // 3618 3619 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) { 3620 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1; 3621 } 3622 3623 // 3624 // Check to see if the write cache is enabled. 3625 // 3626 3627 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE); 3628 3629 // 3630 // Assume that write cache is disabled or not supported. 3631 // 3632 3633 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 3634 3635 // 3636 // Check if valid caching page exists. 3637 // 3638 3639 if (pageData != NULL) { 3640 3641 BOOLEAN savePage = FALSE; 3642 3643 savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable); 3644 3645 // 3646 // Check if write cache is disabled. 3647 // 3648 3649 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) { 3650 3651 PIO_ERROR_LOG_PACKET errorLogEntry; 3652 LONG errorCode; 3653 3654 3655 // 3656 // Disable write cache and ensure necessary fields are zeroed. 3657 // 3658 3659 ((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE; 3660 ((PMODE_CACHING_PAGE)pageData)->Reserved = 0; 3661 ((PMODE_CACHING_PAGE)pageData)->PageSavable = 0; 3662 ((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0; 3663 3664 // 3665 // Extract length from caching page. 3666 // 3667 3668 length = ((PMODE_CACHING_PAGE)pageData)->PageLength; 3669 3670 // 3671 // Compensate for page code and page length. 3672 // 3673 3674 length += 2; 3675 3676 // 3677 // Issue mode select to set the parameter. 3678 // 3679 3680 if (ScsiDiskModeSelect(DeviceObject, 3681 (PCHAR)pageData, 3682 length, 3683 savePage)) { 3684 3685 DebugPrint((1, 3686 "SCSIDISK: Disk write cache disabled\n")); 3687 3688 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 3689 errorCode = IO_WRITE_CACHE_DISABLED; 3690 3691 } else { 3692 if (ScsiDiskModeSelect(DeviceObject, 3693 (PCHAR)pageData, 3694 length, 3695 savePage)) { 3696 3697 DebugPrint((1, 3698 "SCSIDISK: Disk write cache disabled\n")); 3699 3700 3701 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 3702 errorCode = IO_WRITE_CACHE_DISABLED; 3703 3704 } else { 3705 3706 DebugPrint((1, 3707 "SCSIDISK: Mode select to disable write cache failed\n")); 3708 3709 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE; 3710 errorCode = IO_WRITE_CACHE_ENABLED; 3711 } 3712 } 3713 3714 // 3715 // Log the appropriate informational or error entry. 3716 // 3717 3718 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( 3719 DeviceObject, 3720 sizeof(IO_ERROR_LOG_PACKET) + 3 3721 * sizeof(ULONG)); 3722 3723 if (errorLogEntry != NULL) { 3724 3725 errorLogEntry->FinalStatus = STATUS_SUCCESS; 3726 errorLogEntry->ErrorCode = errorCode; 3727 errorLogEntry->SequenceNumber = 0; 3728 errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI; 3729 errorLogEntry->IoControlCode = 0; 3730 errorLogEntry->RetryCount = 0; 3731 errorLogEntry->UniqueErrorValue = 0x1; 3732 errorLogEntry->DumpDataSize = 3 * sizeof(ULONG); 3733 errorLogEntry->DumpData[0] = LunInfo->PathId; 3734 errorLogEntry->DumpData[1] = LunInfo->TargetId; 3735 errorLogEntry->DumpData[2] = LunInfo->Lun; 3736 3737 // 3738 // Write the error log packet. 3739 // 3740 3741 IoWriteErrorLogEntry(errorLogEntry); 3742 } 3743 } 3744 } 3745 3746 // 3747 // Found device so exit the loop and return. 3748 // 3749 3750 break; 3751 } 3752 3753 return; 3754 } 3755 3756 3757 BOOLEAN 3758 NTAPI 3759 CalculateMbrCheckSum( 3760 IN PDEVICE_EXTENSION DeviceExtension, 3761 OUT PULONG Checksum 3762 ) 3763 3764 /*++ 3765 3766 Routine Description: 3767 3768 Read MBR and calculate checksum. 3769 3770 Arguments: 3771 3772 DeviceExtension - Supplies a pointer to the device information for disk. 3773 Checksum - Memory location to return MBR checksum. 3774 3775 Return Value: 3776 3777 Returns TRUE if checksum is valid. 3778 3779 --*/ 3780 { 3781 LARGE_INTEGER sectorZero; 3782 PIRP irp; 3783 IO_STATUS_BLOCK ioStatus; 3784 KEVENT event; 3785 NTSTATUS status; 3786 ULONG sectorSize; 3787 PULONG mbr; 3788 ULONG i; 3789 3790 PAGED_CODE(); 3791 sectorZero.QuadPart = (LONGLONG) 0; 3792 3793 // 3794 // Create notification event object to be used to signal the inquiry 3795 // request completion. 3796 // 3797 3798 KeInitializeEvent(&event, NotificationEvent, FALSE); 3799 3800 // 3801 // Get sector size. 3802 // 3803 3804 sectorSize = DeviceExtension->DiskGeometry->Geometry.BytesPerSector; 3805 3806 // 3807 // Make sure sector size is at least 512 bytes. 3808 // 3809 3810 if (sectorSize < 512) { 3811 sectorSize = 512; 3812 } 3813 3814 // 3815 // Allocate buffer for sector read. 3816 // 3817 3818 mbr = ExAllocatePool(NonPagedPoolCacheAligned, sectorSize); 3819 3820 if (!mbr) { 3821 return FALSE; 3822 } 3823 3824 // 3825 // Build IRP to read MBR. 3826 // 3827 3828 irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 3829 DeviceExtension->DeviceObject, 3830 mbr, 3831 sectorSize, 3832 §orZero, 3833 &event, 3834 &ioStatus ); 3835 3836 if (!irp) { 3837 ExFreePool(mbr); 3838 return FALSE; 3839 } 3840 3841 // 3842 // Pass request to port driver and wait for request to complete. 3843 // 3844 3845 status = IoCallDriver(DeviceExtension->DeviceObject, 3846 irp); 3847 3848 if (status == STATUS_PENDING) { 3849 KeWaitForSingleObject(&event, 3850 Suspended, 3851 KernelMode, 3852 FALSE, 3853 NULL); 3854 status = ioStatus.Status; 3855 } 3856 3857 if (!NT_SUCCESS(status)) { 3858 ExFreePool(mbr); 3859 return FALSE; 3860 } 3861 3862 // 3863 // Calculate MBR checksum. 3864 // 3865 3866 *Checksum = 0; 3867 3868 for (i = 0; i < 128; i++) { 3869 *Checksum += mbr[i]; 3870 } 3871 3872 *Checksum = ~*Checksum + 1; 3873 3874 ExFreePool(mbr); 3875 return TRUE; 3876 } 3877 3878 3879 BOOLEAN 3880 NTAPI 3881 EnumerateBusKey( 3882 IN PDEVICE_EXTENSION DeviceExtension, 3883 HANDLE BusKey, 3884 PULONG DiskNumber 3885 ) 3886 3887 /*++ 3888 3889 Routine Description: 3890 3891 The routine queries the registry to determine if this disk is visible to 3892 the BIOS. If the disk is visible to the BIOS, then the geometry information 3893 is updated. 3894 3895 Arguments: 3896 3897 DeviceExtension - Supplies a pointer to the device information for disk. 3898 Signature - Unique identifier recorded in MBR. 3899 BusKey - Handle of bus key. 3900 DiskNumber - Returns ordinal of disk as BIOS sees it. 3901 3902 Return Value: 3903 3904 TRUE is disk signature matched. 3905 3906 --*/ 3907 { 3908 PDISK_DATA diskData = (PDISK_DATA)(DeviceExtension + 1); 3909 BOOLEAN diskFound = FALSE; 3910 OBJECT_ATTRIBUTES objectAttributes; 3911 UNICODE_STRING unicodeString; 3912 UNICODE_STRING identifier; 3913 ULONG busNumber; 3914 ULONG adapterNumber; 3915 ULONG diskNumber; 3916 HANDLE adapterKey; 3917 HANDLE spareKey; 3918 HANDLE diskKey; 3919 HANDLE targetKey; 3920 NTSTATUS status; 3921 STRING string; 3922 STRING anotherString; 3923 ULONG length; 3924 UCHAR buffer[20]; 3925 PKEY_VALUE_FULL_INFORMATION keyData; 3926 3927 PAGED_CODE(); 3928 3929 for (busNumber = 0; ; busNumber++) { 3930 3931 // 3932 // Open controller name key. 3933 // 3934 3935 sprintf((PCHAR)buffer, 3936 "%lu", 3937 busNumber); 3938 3939 RtlInitString(&string, 3940 (PCSZ)buffer); 3941 3942 status = RtlAnsiStringToUnicodeString(&unicodeString, 3943 &string, 3944 TRUE); 3945 3946 if (!NT_SUCCESS(status)){ 3947 break; 3948 } 3949 3950 InitializeObjectAttributes(&objectAttributes, 3951 &unicodeString, 3952 OBJ_CASE_INSENSITIVE, 3953 BusKey, 3954 (PSECURITY_DESCRIPTOR)NULL); 3955 3956 status = ZwOpenKey(&spareKey, 3957 KEY_READ, 3958 &objectAttributes); 3959 3960 RtlFreeUnicodeString(&unicodeString); 3961 3962 if (!NT_SUCCESS(status)) { 3963 break; 3964 } 3965 3966 // 3967 // Open up controller ordinal key. 3968 // 3969 3970 RtlInitUnicodeString(&unicodeString, L"DiskController"); 3971 InitializeObjectAttributes(&objectAttributes, 3972 &unicodeString, 3973 OBJ_CASE_INSENSITIVE, 3974 spareKey, 3975 (PSECURITY_DESCRIPTOR)NULL); 3976 3977 status = ZwOpenKey(&adapterKey, 3978 KEY_READ, 3979 &objectAttributes); 3980 3981 // 3982 // This could fail even with additional adapters of this type 3983 // to search. 3984 // 3985 3986 if (!NT_SUCCESS(status)) { 3987 continue; 3988 } 3989 3990 for (adapterNumber = 0; ; adapterNumber++) { 3991 3992 // 3993 // Open disk key. 3994 // 3995 3996 sprintf((PCHAR)buffer, 3997 "%lu\\DiskPeripheral", 3998 adapterNumber); 3999 4000 RtlInitString(&string, 4001 (PCSZ)buffer); 4002 4003 status = RtlAnsiStringToUnicodeString(&unicodeString, 4004 &string, 4005 TRUE); 4006 4007 if (!NT_SUCCESS(status)){ 4008 break; 4009 } 4010 4011 InitializeObjectAttributes(&objectAttributes, 4012 &unicodeString, 4013 OBJ_CASE_INSENSITIVE, 4014 adapterKey, 4015 (PSECURITY_DESCRIPTOR)NULL); 4016 4017 status = ZwOpenKey(&diskKey, 4018 KEY_READ, 4019 &objectAttributes); 4020 4021 RtlFreeUnicodeString(&unicodeString); 4022 4023 if (!NT_SUCCESS(status)) { 4024 break; 4025 } 4026 4027 for (diskNumber = 0; ; diskNumber++) { 4028 4029 sprintf((PCHAR)buffer, 4030 "%lu", 4031 diskNumber); 4032 4033 RtlInitString(&string, 4034 (PCSZ)buffer); 4035 4036 status = RtlAnsiStringToUnicodeString(&unicodeString, 4037 &string, 4038 TRUE); 4039 4040 if (!NT_SUCCESS(status)){ 4041 break; 4042 } 4043 4044 InitializeObjectAttributes(&objectAttributes, 4045 &unicodeString, 4046 OBJ_CASE_INSENSITIVE, 4047 diskKey, 4048 (PSECURITY_DESCRIPTOR)NULL); 4049 4050 status = ZwOpenKey(&targetKey, 4051 KEY_READ, 4052 &objectAttributes); 4053 4054 RtlFreeUnicodeString(&unicodeString); 4055 4056 if (!NT_SUCCESS(status)) { 4057 break; 4058 } 4059 4060 // 4061 // Allocate buffer for registry query. 4062 // 4063 4064 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE); 4065 4066 if (keyData == NULL) { 4067 ZwClose(targetKey); 4068 continue; 4069 } 4070 4071 // 4072 // Get disk peripheral identifier. 4073 // 4074 4075 RtlInitUnicodeString(&unicodeString, L"Identifier"); 4076 status = ZwQueryValueKey(targetKey, 4077 &unicodeString, 4078 KeyValueFullInformation, 4079 keyData, 4080 VALUE_BUFFER_SIZE, 4081 &length); 4082 4083 ZwClose(targetKey); 4084 4085 if (!NT_SUCCESS(status)) { 4086 ExFreePool(keyData); 4087 continue; 4088 } 4089 4090 if (keyData->DataLength < 9*sizeof(WCHAR)) { 4091 // 4092 // the data is too short to use (we subtract 9 chars in normal path) 4093 // 4094 DebugPrint((1, "EnumerateBusKey: Saved data was invalid, " 4095 "not enough data in registry!\n")); 4096 ExFreePool(keyData); 4097 continue; 4098 } 4099 4100 // 4101 // Complete unicode string. 4102 // 4103 4104 identifier.Buffer = 4105 (PWSTR)((PUCHAR)keyData + keyData->DataOffset); 4106 identifier.Length = (USHORT)keyData->DataLength; 4107 identifier.MaximumLength = (USHORT)keyData->DataLength; 4108 4109 // 4110 // Convert unicode identifier to ansi string. 4111 // 4112 4113 status = 4114 RtlUnicodeStringToAnsiString(&anotherString, 4115 &identifier, 4116 TRUE); 4117 4118 if (!NT_SUCCESS(status)) { 4119 ExFreePool(keyData); 4120 continue; 4121 } 4122 4123 // 4124 // If checksum is zero, then the MBR is valid and 4125 // the signature is meaningful. 4126 // 4127 4128 if (diskData->MbrCheckSum) { 4129 4130 // 4131 // Convert checksum to ansi string. 4132 // 4133 4134 sprintf((PCHAR)buffer, "%08lx", diskData->MbrCheckSum); 4135 4136 } else { 4137 4138 // 4139 // Convert signature to ansi string. 4140 // 4141 4142 sprintf((PCHAR)buffer, "%08lx", diskData->Signature); 4143 4144 // 4145 // Make string point at signature. Can't use scan 4146 // functions because they are not exported for driver use. 4147 // 4148 4149 anotherString.Buffer+=9; 4150 } 4151 4152 // 4153 // Convert to ansi string. 4154 // 4155 4156 RtlInitString(&string, 4157 (PCSZ)buffer); 4158 4159 4160 // 4161 // Make string lengths equal. 4162 // 4163 4164 anotherString.Length = string.Length; 4165 4166 // 4167 // Check if strings match. 4168 // 4169 4170 if (RtlCompareString(&string, 4171 &anotherString, 4172 TRUE) == 0) { 4173 4174 diskFound = TRUE; 4175 *DiskNumber = diskNumber; 4176 } 4177 4178 ExFreePool(keyData); 4179 4180 // 4181 // Readjust identifier string if necessary. 4182 // 4183 4184 if (!diskData->MbrCheckSum) { 4185 anotherString.Buffer-=9; 4186 } 4187 4188 RtlFreeAnsiString(&anotherString); 4189 4190 if (diskFound) { 4191 break; 4192 } 4193 } 4194 4195 ZwClose(diskKey); 4196 } 4197 4198 ZwClose(adapterKey); 4199 } 4200 4201 ZwClose(BusKey); 4202 return diskFound; 4203 4204 } // end EnumerateBusKey() 4205 4206 4207 VOID 4208 NTAPI 4209 UpdateGeometry( 4210 IN PDEVICE_EXTENSION DeviceExtension 4211 ) 4212 /*++ 4213 4214 Routine Description: 4215 4216 The routine queries the registry to determine if this disk is visible to 4217 the BIOS. If the disk is visible to the BIOS, then the geometry information 4218 is updated. 4219 4220 Arguments: 4221 4222 DeviceExtension - Supplies a pointer to the device information for disk. 4223 4224 Return Value: 4225 4226 None. 4227 4228 --*/ 4229 4230 { 4231 OBJECT_ATTRIBUTES objectAttributes; 4232 UNICODE_STRING unicodeString; 4233 NTSTATUS status; 4234 HANDLE hardwareKey; 4235 HANDLE busKey; 4236 PCM_INT13_DRIVE_PARAMETER driveParameters; 4237 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor; 4238 PKEY_VALUE_FULL_INFORMATION keyData; 4239 ULONG diskNumber; 4240 PUCHAR buffer; 4241 ULONG length; 4242 ULONG numberOfDrives; 4243 ULONG cylinders; 4244 ULONG sectors; 4245 ULONG sectorsPerTrack; 4246 ULONG tracksPerCylinder; 4247 BOOLEAN foundEZHooker; 4248 PVOID tmpPtr; 4249 4250 PAGED_CODE(); 4251 4252 // 4253 // Initialize the object for the key. 4254 // 4255 4256 InitializeObjectAttributes(&objectAttributes, 4257 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase, 4258 OBJ_CASE_INSENSITIVE, 4259 NULL, 4260 (PSECURITY_DESCRIPTOR) NULL); 4261 4262 // 4263 // Create the hardware base key. 4264 // 4265 4266 status = ZwOpenKey(&hardwareKey, 4267 KEY_READ, 4268 &objectAttributes); 4269 4270 4271 if (!NT_SUCCESS(status)) { 4272 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension->DeviceObject->DriverObject->HardwareDatabase)); 4273 return; 4274 } 4275 4276 4277 // 4278 // Get disk BIOS geometry information. 4279 // 4280 4281 RtlInitUnicodeString(&unicodeString, L"Configuration Data"); 4282 4283 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE); 4284 4285 if (keyData == NULL) { 4286 ZwClose(hardwareKey); 4287 return; 4288 } 4289 4290 status = ZwQueryValueKey(hardwareKey, 4291 &unicodeString, 4292 KeyValueFullInformation, 4293 keyData, 4294 VALUE_BUFFER_SIZE, 4295 &length); 4296 4297 if (!NT_SUCCESS(status)) { 4298 DebugPrint((1, 4299 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n", 4300 status)); 4301 ZwClose(hardwareKey); 4302 ExFreePool(keyData); 4303 return; 4304 } 4305 4306 // 4307 // Open EISA bus key. 4308 // 4309 4310 RtlInitUnicodeString(&unicodeString, L"EisaAdapter"); 4311 4312 InitializeObjectAttributes(&objectAttributes, 4313 &unicodeString, 4314 OBJ_CASE_INSENSITIVE, 4315 hardwareKey, 4316 (PSECURITY_DESCRIPTOR)NULL); 4317 4318 status = ZwOpenKey(&busKey, 4319 KEY_READ, 4320 &objectAttributes); 4321 4322 if (!NT_SUCCESS(status)) { 4323 goto openMultiKey; 4324 } 4325 4326 DebugPrint((3, 4327 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n")); 4328 if (EnumerateBusKey(DeviceExtension, 4329 busKey, 4330 &diskNumber)) { 4331 4332 ZwClose(hardwareKey); 4333 goto diskMatched; 4334 } 4335 4336 openMultiKey: 4337 4338 // 4339 // Open Multifunction bus key. 4340 // 4341 4342 RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter"); 4343 4344 InitializeObjectAttributes(&objectAttributes, 4345 &unicodeString, 4346 OBJ_CASE_INSENSITIVE, 4347 hardwareKey, 4348 (PSECURITY_DESCRIPTOR)NULL); 4349 4350 status = ZwOpenKey(&busKey, 4351 KEY_READ, 4352 &objectAttributes); 4353 4354 ZwClose(hardwareKey); 4355 if (NT_SUCCESS(status)) { 4356 DebugPrint((3, 4357 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n")); 4358 if (EnumerateBusKey(DeviceExtension, 4359 busKey, 4360 &diskNumber)) { 4361 4362 goto diskMatched; 4363 } 4364 } 4365 4366 ExFreePool(keyData); 4367 return; 4368 4369 diskMatched: 4370 4371 resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)keyData + 4372 keyData->DataOffset); 4373 4374 // 4375 // Check that the data is long enough to hold a full resource descriptor, 4376 // and that the last resource list is device-specific and long enough. 4377 // 4378 4379 if (keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR) || 4380 resourceDescriptor->PartialResourceList.Count == 0 || 4381 resourceDescriptor->PartialResourceList.PartialDescriptors[0].Type != 4382 CmResourceTypeDeviceSpecific || 4383 resourceDescriptor->PartialResourceList.PartialDescriptors[0] 4384 .u.DeviceSpecificData.DataSize < sizeof(ULONG)) { 4385 4386 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n")); 4387 ExFreePool(keyData); 4388 return; 4389 } 4390 4391 length = 4392 resourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize; 4393 4394 // 4395 // Point to the BIOS data. The BIOS data is located after the first 4396 // partial Resource list which should be device specific data. 4397 // 4398 4399 buffer = (PUCHAR) keyData + keyData->DataOffset + 4400 sizeof(CM_FULL_RESOURCE_DESCRIPTOR); 4401 4402 4403 numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER); 4404 4405 // 4406 // Use the defaults if the drive number is greater than the 4407 // number of drives detected by the BIOS. 4408 // 4409 4410 if (numberOfDrives <= diskNumber) { 4411 ExFreePool(keyData); 4412 return; 4413 } 4414 4415 // 4416 // Point to the array of drive parameters. 4417 // 4418 4419 driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer + diskNumber; 4420 cylinders = driveParameters->MaxCylinders + 1; 4421 sectorsPerTrack = driveParameters->SectorsPerTrack; 4422 tracksPerCylinder = driveParameters->MaxHeads +1; 4423 4424 // 4425 // Calculate the actual number of sectors. 4426 // 4427 4428 sectors = (ULONG)(DeviceExtension->PartitionLength.QuadPart >> 4429 DeviceExtension->SectorShift); 4430 4431 #if DBG 4432 if (sectors >= cylinders * tracksPerCylinder * sectorsPerTrack) { 4433 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n" 4434 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n", 4435 sectors, cylinders, tracksPerCylinder, sectorsPerTrack)); 4436 } 4437 #endif 4438 4439 // 4440 // Since the BIOS may not report the full drive, recalculate the drive 4441 // size based on the volume size and the BIOS values for tracks per 4442 // cylinder and sectors per track.. 4443 // 4444 4445 length = tracksPerCylinder * sectorsPerTrack; 4446 4447 if (length == 0) { 4448 4449 // 4450 // The BIOS information is bogus. 4451 // 4452 4453 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n")); 4454 ExFreePool(keyData); 4455 return; 4456 } 4457 4458 cylinders = sectors / length; 4459 4460 // 4461 // Update the actual geometry information. 4462 // 4463 4464 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack = sectorsPerTrack; 4465 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder; 4466 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)cylinders; 4467 DeviceExtension->DiskGeometry->DiskSize.QuadPart = (LONGLONG)cylinders * tracksPerCylinder * sectorsPerTrack * 4468 DeviceExtension->DiskGeometry->Geometry.BytesPerSector; 4469 4470 DebugPrint((3, 4471 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n", 4472 sectorsPerTrack, 4473 tracksPerCylinder, 4474 cylinders)); 4475 4476 ExFreePool(keyData); 4477 4478 foundEZHooker = FALSE; 4479 4480 if (!DeviceExtension->DMActive) { 4481 4482 HalExamineMBR(DeviceExtension->DeviceObject, 4483 DeviceExtension->DiskGeometry->Geometry.BytesPerSector, 4484 (ULONG)0x55, 4485 &tmpPtr 4486 ); 4487 4488 if (tmpPtr) { 4489 4490 ExFreePool(tmpPtr); 4491 foundEZHooker = TRUE; 4492 4493 } 4494 4495 } 4496 4497 if (DeviceExtension->DMActive || foundEZHooker) { 4498 4499 while (cylinders > 1024) { 4500 4501 tracksPerCylinder = tracksPerCylinder*2; 4502 cylinders = cylinders/2; 4503 4504 } 4505 4506 // 4507 // int 13 values are always 1 less. 4508 // 4509 4510 tracksPerCylinder -= 1; 4511 cylinders -= 1; 4512 4513 // 4514 // DM reserves the CE cylinder 4515 // 4516 4517 cylinders -= 1; 4518 4519 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = cylinders + 1; 4520 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder + 1; 4521 4522 DeviceExtension->PartitionLength.QuadPart = 4523 DeviceExtension->DiskGeometry->DiskSize.QuadPart = 4524 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart * 4525 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack * 4526 DeviceExtension->DiskGeometry->Geometry.BytesPerSector * 4527 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder; 4528 4529 if (DeviceExtension->DMActive) { 4530 4531 DeviceExtension->DMByteSkew = DeviceExtension->DMSkew * DeviceExtension->DiskGeometry->Geometry.BytesPerSector; 4532 4533 } 4534 4535 } else { 4536 4537 DeviceExtension->DMByteSkew = 0; 4538 4539 } 4540 4541 return; 4542 4543 } // end UpdateGeometry() 4544 4545 4546 4547 NTSTATUS 4548 NTAPI 4549 UpdateRemovableGeometry ( 4550 IN PDEVICE_OBJECT DeviceObject, 4551 IN PIRP Irp 4552 ) 4553 4554 /*++ 4555 4556 Routine Description: 4557 4558 This routines updates the size and starting offset of the device. This is 4559 used when the media on the device may have changed thereby changing the 4560 size of the device. If this is the physical device then a 4561 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done. 4562 4563 Arguments: 4564 4565 DeviceObject - Supplies the device object whos size needs to be updated. 4566 4567 Irp - Supplies a reference where the status can be updated. 4568 4569 Return Value: 4570 4571 Returns the status of the operation. 4572 4573 --*/ 4574 { 4575 4576 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 4577 PDRIVE_LAYOUT_INFORMATION partitionList; 4578 NTSTATUS status; 4579 PDISK_DATA diskData; 4580 ULONG partitionNumber; 4581 4582 // 4583 // Determine if the size of the partition may have changed because 4584 // the media has changed. 4585 // 4586 4587 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) { 4588 4589 return(STATUS_SUCCESS); 4590 4591 } 4592 4593 // 4594 // If this request is for partition zero then do a read drive 4595 // capacity otherwise do a I/O read partition table. 4596 // 4597 4598 diskData = (PDISK_DATA) (deviceExtension + 1); 4599 4600 // 4601 // Read the drive capacity. If that fails, give up. 4602 // 4603 4604 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice); 4605 4606 if (!NT_SUCCESS(status)) { 4607 return(status); 4608 } 4609 4610 #ifdef __REACTOS__ 4611 // 4612 // HACK so that we can use NT5+ NTOS functions with this NT4 driver 4613 // for removable devices and avoid an infinite recursive loop between 4614 // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable(). 4615 // 4616 // Check whether the update-count is greater or equal than one 4617 // (and increase it) and if so, reset it and return success. 4618 if (diskData->UpdateRemovableGeometryCount++ >= 1) 4619 { 4620 diskData->UpdateRemovableGeometryCount = 0; 4621 return(STATUS_SUCCESS); 4622 } 4623 #endif 4624 4625 // 4626 // Read the partition table again. 4627 // 4628 4629 status = IoReadPartitionTable(deviceExtension->PhysicalDevice, 4630 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 4631 TRUE, 4632 &partitionList); 4633 4634 #ifdef __REACTOS__ 4635 // 4636 // HACK so that we can use NT5+ NTOS functions with this NT4 driver 4637 // for removable devices and avoid an infinite recursive loop between 4638 // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable(). 4639 // 4640 // Inconditionally reset the update-count. 4641 diskData->UpdateRemovableGeometryCount = 0; 4642 #endif 4643 4644 if (!NT_SUCCESS(status)) { 4645 4646 // 4647 // Fail the request. 4648 // 4649 4650 return(status); 4651 } 4652 4653 if (diskData->PartitionNumber != 0 && 4654 diskData->PartitionNumber <= partitionList->PartitionCount ) { 4655 4656 partitionNumber = diskData->PartitionNumber - 1; 4657 4658 // 4659 // Update the partition information for this partition. 4660 // 4661 4662 diskData->PartitionType = 4663 partitionList->PartitionEntry[partitionNumber].PartitionType; 4664 4665 diskData->BootIndicator = 4666 partitionList->PartitionEntry[partitionNumber].BootIndicator; 4667 4668 deviceExtension->StartingOffset = 4669 partitionList->PartitionEntry[partitionNumber].StartingOffset; 4670 4671 deviceExtension->PartitionLength = 4672 partitionList->PartitionEntry[partitionNumber].PartitionLength; 4673 4674 diskData->HiddenSectors = 4675 partitionList->PartitionEntry[partitionNumber].HiddenSectors; 4676 4677 deviceExtension->SectorShift = ((PDEVICE_EXTENSION) 4678 deviceExtension->PhysicalDevice->DeviceExtension)->SectorShift; 4679 4680 } else if (diskData->PartitionNumber != 0) { 4681 4682 // 4683 // The partition does not exist. Zero all the data. 4684 // 4685 4686 diskData->PartitionType = 0; 4687 diskData->BootIndicator = 0; 4688 diskData->HiddenSectors = 0; 4689 deviceExtension->StartingOffset.QuadPart = (LONGLONG)0; 4690 deviceExtension->PartitionLength.QuadPart = (LONGLONG)0; 4691 } 4692 4693 // 4694 // Free the partition list allocate by I/O read partition table. 4695 // 4696 4697 ExFreePool(partitionList); 4698 4699 4700 return(STATUS_SUCCESS); 4701 } 4702 4703 4704 VOID 4705 NTAPI 4706 ScsiDiskProcessError( 4707 PDEVICE_OBJECT DeviceObject, 4708 PSCSI_REQUEST_BLOCK Srb, 4709 NTSTATUS *Status, 4710 BOOLEAN *Retry 4711 ) 4712 /*++ 4713 4714 Routine Description: 4715 4716 This routine checks the type of error. If the error indicates an underrun 4717 then indicate the request should be retried. 4718 4719 Arguments: 4720 4721 DeviceObject - Supplies a pointer to the device object. 4722 4723 Srb - Supplies a pointer to the failing Srb. 4724 4725 Status - Status with which the IRP will be completed. 4726 4727 Retry - Indication of whether the request will be retried. 4728 4729 Return Value: 4730 4731 None. 4732 4733 --*/ 4734 4735 { 4736 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 4737 4738 if (*Status == STATUS_DATA_OVERRUN && 4739 ( Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_READ)) { 4740 4741 *Retry = TRUE; 4742 4743 // 4744 // Update the error count for the device. 4745 // 4746 4747 deviceExtension->ErrorCount++; 4748 } 4749 4750 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR && 4751 Srb->ScsiStatus == SCSISTAT_BUSY) { 4752 4753 // 4754 // The disk drive should never be busy this long. Reset the scsi bus 4755 // maybe this will clear the condition. 4756 // 4757 4758 ResetScsiBus(DeviceObject); 4759 4760 // 4761 // Update the error count for the device. 4762 // 4763 4764 deviceExtension->ErrorCount++; 4765 } 4766 } 4767 4768 VOID 4769 NTAPI 4770 ScanForSpecial( 4771 PDEVICE_OBJECT DeviceObject, 4772 PSCSI_INQUIRY_DATA LunInfo, 4773 PIO_SCSI_CAPABILITIES PortCapabilities 4774 ) 4775 4776 /*++ 4777 4778 Routine Description: 4779 4780 This function checks to see if an SCSI logical unit requires special 4781 flags to be set. 4782 4783 Arguments: 4784 4785 DeviceObject - Supplies the device object to be tested. 4786 4787 InquiryData - Supplies the inquiry data returned by the device of interest. 4788 4789 PortCapabilities - Supplies the capabilities of the device object. 4790 4791 Return Value: 4792 4793 None. 4794 4795 --*/ 4796 4797 { 4798 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 4799 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData; 4800 BAD_CONTROLLER_INFORMATION const *controller; 4801 ULONG j; 4802 4803 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) { 4804 4805 controller = &ScsiDiskBadControllers[j]; 4806 4807 if (strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) { 4808 continue; 4809 } 4810 4811 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller->InquiryString)); 4812 4813 // 4814 // Found a listed controller. Determine what must be done. 4815 // 4816 4817 if (controller->DisableTaggedQueuing) { 4818 4819 // 4820 // Disable tagged queuing. 4821 // 4822 4823 deviceExtension->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE; 4824 } 4825 4826 if (controller->DisableSynchronousTransfers) { 4827 4828 // 4829 // Disable synchronous data transfers. 4830 // 4831 4832 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 4833 4834 } 4835 4836 if (controller->DisableDisconnects) { 4837 4838 // 4839 // Disable disconnects. 4840 // 4841 4842 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT; 4843 4844 } 4845 4846 // 4847 // Found device so exit the loop and return. 4848 // 4849 4850 break; 4851 } 4852 4853 // 4854 // Set the StartUnit flag appropriately. 4855 // 4856 4857 if (DeviceObject->DeviceType == FILE_DEVICE_DISK) { 4858 deviceExtension->DeviceFlags |= DEV_SAFE_START_UNIT; 4859 4860 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 4861 if (_strnicmp((PCCHAR)InquiryData->VendorId, "iomega", strlen("iomega"))) { 4862 deviceExtension->DeviceFlags &= ~DEV_SAFE_START_UNIT; 4863 } 4864 } 4865 } 4866 4867 return; 4868 } 4869 4870 VOID 4871 NTAPI 4872 ResetScsiBus( 4873 IN PDEVICE_OBJECT DeviceObject 4874 ) 4875 4876 /*++ 4877 4878 Routine Description: 4879 4880 This command sends a reset bus command to the SCSI port driver. 4881 4882 Arguments: 4883 4884 DeviceObject - The device object for the logical unit with 4885 hardware problem. 4886 4887 Return Value: 4888 4889 None. 4890 4891 --*/ 4892 { 4893 PIO_STACK_LOCATION irpStack; 4894 PIRP irp; 4895 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 4896 PSCSI_REQUEST_BLOCK srb; 4897 PCOMPLETION_CONTEXT context; 4898 4899 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n")); 4900 4901 // 4902 // Allocate Srb from nonpaged pool. 4903 // 4904 4905 context = ExAllocatePool(NonPagedPoolMustSucceed, 4906 sizeof(COMPLETION_CONTEXT)); 4907 4908 // 4909 // Save the device object in the context for use by the completion 4910 // routine. 4911 // 4912 4913 context->DeviceObject = DeviceObject; 4914 srb = &context->Srb; 4915 4916 // 4917 // Zero out srb. 4918 // 4919 4920 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 4921 4922 // 4923 // Write length to SRB. 4924 // 4925 4926 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 4927 4928 // 4929 // Set up SCSI bus address. 4930 // 4931 4932 srb->PathId = deviceExtension->PathId; 4933 srb->TargetId = deviceExtension->TargetId; 4934 srb->Lun = deviceExtension->Lun; 4935 4936 srb->Function = SRB_FUNCTION_RESET_BUS; 4937 4938 // 4939 // Build the asynchronous request to be sent to the port driver. 4940 // Since this routine is called from a DPC the IRP should always be 4941 // available. 4942 // 4943 4944 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 4945 4946 IoSetCompletionRoutine(irp, 4947 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion, 4948 context, 4949 TRUE, 4950 TRUE, 4951 TRUE); 4952 4953 irpStack = IoGetNextIrpStackLocation(irp); 4954 4955 irpStack->MajorFunction = IRP_MJ_SCSI; 4956 4957 srb->OriginalRequest = irp; 4958 4959 // 4960 // Store the SRB address in next stack for port driver. 4961 // 4962 4963 irpStack->Parameters.Scsi.Srb = srb; 4964 4965 // 4966 // Call the port driver with the IRP. 4967 // 4968 4969 IoCallDriver(deviceExtension->PortDeviceObject, irp); 4970 4971 return; 4972 4973 } // end ResetScsiBus() 4974 4975 4976 VOID 4977 NTAPI 4978 UpdateDeviceObjects( 4979 IN PDEVICE_OBJECT PhysicalDisk, 4980 IN PIRP Irp 4981 ) 4982 4983 /*++ 4984 4985 Routine Description: 4986 4987 This routine creates, deletes and changes device objects when 4988 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates 4989 the drive layout information for the user. It is possible to 4990 call this routine even in the GET_LAYOUT case because RewritePartition 4991 will be false. 4992 4993 Arguments: 4994 4995 DeviceObject - Device object for physical disk. 4996 Irp - IO Request Packet (IRP). 4997 4998 Return Value: 4999 5000 None. 5001 5002 --*/ 5003 { 5004 PDEVICE_EXTENSION physicalExtension = PhysicalDisk->DeviceExtension; 5005 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer; 5006 ULONG partition; 5007 ULONG partitionNumber; 5008 ULONG partitionCount; 5009 ULONG lastPartition; 5010 ULONG partitionOrdinal; 5011 PPARTITION_INFORMATION partitionEntry; 5012 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH]; 5013 STRING ntNameString; 5014 UNICODE_STRING ntUnicodeString; 5015 PDEVICE_OBJECT deviceObject; 5016 PDEVICE_EXTENSION deviceExtension; 5017 PDISK_DATA diskData; 5018 NTSTATUS status; 5019 ULONG numberListElements; 5020 BOOLEAN found; 5021 5022 partitionCount = ((partitionList->PartitionCount + 3) / 4) * 4; 5023 5024 // 5025 // Zero all of the partition numbers. 5026 // 5027 5028 for (partition = 0; partition < partitionCount; partition++) { 5029 partitionEntry = &partitionList->PartitionEntry[partition]; 5030 partitionEntry->PartitionNumber = 0; 5031 } 5032 5033 // 5034 // Walk through chain of partitions for this disk to determine 5035 // which existing partitions have no match. 5036 // 5037 5038 deviceExtension = physicalExtension; 5039 diskData = (PDISK_DATA)(deviceExtension + 1); 5040 lastPartition = 0; 5041 5042 do { 5043 5044 deviceExtension = diskData->NextPartition; 5045 5046 // 5047 // Check if this is the last partition in the chain. 5048 // 5049 5050 if (!deviceExtension) { 5051 break; 5052 } 5053 5054 // 5055 // Get the partition device extension from disk data. 5056 // 5057 5058 diskData = (PDISK_DATA)(deviceExtension + 1); 5059 5060 // 5061 // Check for highest partition number this far. 5062 // 5063 5064 if (diskData->PartitionNumber > lastPartition) { 5065 lastPartition = diskData->PartitionNumber; 5066 } 5067 5068 // 5069 // Check if this partition is not currently being used. 5070 // 5071 5072 if (!deviceExtension->PartitionLength.QuadPart) { 5073 continue; 5074 } 5075 5076 // 5077 // Loop through partition information to look for match. 5078 // 5079 5080 found = FALSE; 5081 partitionOrdinal = 0; 5082 5083 for (partition = 0; partition < partitionCount; partition++) { 5084 5085 // 5086 // Get partition descriptor. 5087 // 5088 5089 partitionEntry = &partitionList->PartitionEntry[partition]; 5090 5091 // 5092 // Check if empty, or describes extended partition or hasn't changed. 5093 // 5094 5095 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED || 5096 IsContainerPartition(partitionEntry->PartitionType)) { 5097 continue; 5098 } 5099 5100 // 5101 // Advance partition ordinal. 5102 // 5103 5104 partitionOrdinal++; 5105 5106 // 5107 // Check if new partition starts where this partition starts. 5108 // 5109 5110 if (partitionEntry->StartingOffset.QuadPart != 5111 deviceExtension->StartingOffset.QuadPart) { 5112 continue; 5113 } 5114 5115 // 5116 // Check if partition length is the same. 5117 // 5118 5119 if (partitionEntry->PartitionLength.QuadPart == 5120 deviceExtension->PartitionLength.QuadPart) { 5121 5122 DebugPrint((3, 5123 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n", 5124 physicalExtension->DeviceNumber, 5125 diskData->PartitionNumber)); 5126 5127 // 5128 // Indicate match is found and set partition number 5129 // in user buffer. 5130 // 5131 5132 found = TRUE; 5133 partitionEntry->PartitionNumber = diskData->PartitionNumber; 5134 break; 5135 } 5136 } 5137 5138 if (found) { 5139 5140 // 5141 // A match is found. 5142 // 5143 5144 diskData = (PDISK_DATA)(deviceExtension + 1); 5145 5146 // 5147 // If this partition is marked for update then update partition type. 5148 // 5149 5150 if (partitionEntry->RewritePartition) { 5151 diskData->PartitionType = partitionEntry->PartitionType; 5152 } 5153 5154 // 5155 // Update partitional ordinal for calls to HAL routine 5156 // IoSetPartitionInformation. 5157 // 5158 5159 diskData->PartitionOrdinal = partitionOrdinal; 5160 5161 DebugPrint((1, 5162 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n", 5163 physicalExtension->DeviceNumber, 5164 diskData->PartitionOrdinal, 5165 diskData->PartitionNumber)); 5166 5167 } else { 5168 5169 // 5170 // no match was found, indicate this partition is gone. 5171 // 5172 5173 DebugPrint((1, 5174 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n", 5175 physicalExtension->DeviceNumber, 5176 diskData->PartitionNumber)); 5177 5178 deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0; 5179 } 5180 5181 } while (TRUE); 5182 5183 // 5184 // Walk through partition loop to find new partitions and set up 5185 // device extensions to describe them. In some cases new device 5186 // objects will be created. 5187 // 5188 5189 partitionOrdinal = 0; 5190 5191 for (partition = 0; 5192 partition < partitionCount; 5193 partition++) { 5194 5195 // 5196 // Get partition descriptor. 5197 // 5198 5199 partitionEntry = &partitionList->PartitionEntry[partition]; 5200 5201 // 5202 // Check if empty, or describes an extended partition. 5203 // 5204 5205 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED || 5206 IsContainerPartition(partitionEntry->PartitionType)) { 5207 continue; 5208 } 5209 5210 // 5211 // Keep track of position on the disk for calls to IoSetPartitionInformation. 5212 // 5213 5214 partitionOrdinal++; 5215 5216 // 5217 // Check if this entry should be rewritten. 5218 // 5219 5220 if (!partitionEntry->RewritePartition) { 5221 continue; 5222 } 5223 5224 if (partitionEntry->PartitionNumber) { 5225 5226 // 5227 // Partition is an exact match with an existing partition, but is 5228 // being written anyway. 5229 // 5230 5231 continue; 5232 } 5233 5234 // 5235 // Check first if existing device object is available by 5236 // walking partition extension list. 5237 // 5238 5239 partitionNumber = 0; 5240 deviceExtension = physicalExtension; 5241 diskData = (PDISK_DATA)(deviceExtension + 1); 5242 5243 do { 5244 5245 // 5246 // Get next partition device extension from disk data. 5247 // 5248 5249 deviceExtension = diskData->NextPartition; 5250 5251 if (!deviceExtension) { 5252 break; 5253 } 5254 5255 diskData = (PDISK_DATA)(deviceExtension + 1); 5256 5257 // 5258 // A device object is free if the partition length is set to zero. 5259 // 5260 5261 if (!deviceExtension->PartitionLength.QuadPart) { 5262 partitionNumber = diskData->PartitionNumber; 5263 break; 5264 } 5265 5266 } while (TRUE); 5267 5268 // 5269 // If partition number is still zero then a new device object 5270 // must be created. 5271 // 5272 5273 if (partitionNumber == 0) { 5274 5275 lastPartition++; 5276 partitionNumber = lastPartition; 5277 5278 // 5279 // Get or create partition object and set up partition parameters. 5280 // 5281 5282 sprintf(ntNameBuffer, 5283 "\\Device\\Harddisk%lu\\Partition%lu", 5284 physicalExtension->DeviceNumber, 5285 partitionNumber); 5286 5287 RtlInitString(&ntNameString, 5288 ntNameBuffer); 5289 5290 status = RtlAnsiStringToUnicodeString(&ntUnicodeString, 5291 &ntNameString, 5292 TRUE); 5293 5294 if (!NT_SUCCESS(status)) { 5295 continue; 5296 } 5297 5298 DebugPrint((3, 5299 "UpdateDeviceObjects: Create device object %s\n", 5300 ntNameBuffer)); 5301 5302 // 5303 // This is a new name. Create the device object to represent it. 5304 // 5305 5306 status = IoCreateDevice(PhysicalDisk->DriverObject, 5307 DEVICE_EXTENSION_SIZE, 5308 &ntUnicodeString, 5309 FILE_DEVICE_DISK, 5310 0, 5311 FALSE, 5312 &deviceObject); 5313 5314 if (!NT_SUCCESS(status)) { 5315 DebugPrint((1, 5316 "UpdateDeviceObjects: Can't create device %s\n", 5317 ntNameBuffer)); 5318 RtlFreeUnicodeString(&ntUnicodeString); 5319 continue; 5320 } 5321 5322 // 5323 // Set up device object fields. 5324 // 5325 5326 deviceObject->Flags |= DO_DIRECT_IO; 5327 deviceObject->StackSize = PhysicalDisk->StackSize; 5328 5329 // 5330 // Set up device extension fields. 5331 // 5332 5333 deviceExtension = deviceObject->DeviceExtension; 5334 5335 // 5336 // Copy physical disk extension to partition extension. 5337 // 5338 5339 RtlMoveMemory(deviceExtension, 5340 physicalExtension, 5341 sizeof(DEVICE_EXTENSION)); 5342 5343 // 5344 // Initialize the new S-List. 5345 // 5346 5347 if (deviceExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) { 5348 numberListElements = 30; 5349 } else { 5350 numberListElements = 8; 5351 } 5352 5353 // 5354 // Build the lookaside list for srb's for this partition based on 5355 // whether the adapter and disk can do tagged queueing. 5356 // 5357 5358 ScsiClassInitializeSrbLookasideList(deviceExtension, 5359 numberListElements); 5360 5361 // 5362 // Allocate spinlock for zoning for split-request completion. 5363 // 5364 5365 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock); 5366 5367 // 5368 // Write back partition number used in creating object name. 5369 // 5370 5371 partitionEntry->PartitionNumber = partitionNumber; 5372 5373 // 5374 // Clear flags initializing bit. 5375 // 5376 5377 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 5378 5379 // 5380 // Point back at device object. 5381 // 5382 5383 deviceExtension->DeviceObject = deviceObject; 5384 5385 RtlFreeUnicodeString(&ntUnicodeString); 5386 5387 // 5388 // Link to end of partition chain using previous disk data. 5389 // 5390 5391 diskData->NextPartition = deviceExtension; 5392 5393 // 5394 // Get new disk data and zero next partition pointer. 5395 // 5396 5397 diskData = (PDISK_DATA)(deviceExtension + 1); 5398 diskData->NextPartition = NULL; 5399 5400 } else { 5401 5402 // 5403 // Set pointer to disk data area that follows device extension. 5404 // 5405 5406 diskData = (PDISK_DATA)(deviceExtension + 1); 5407 5408 DebugPrint((1, 5409 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n", 5410 physicalExtension->DeviceNumber, 5411 partitionNumber)); 5412 } 5413 5414 // 5415 // Update partition information in partition device extension. 5416 // 5417 5418 diskData->PartitionNumber = partitionNumber; 5419 diskData->PartitionType = partitionEntry->PartitionType; 5420 diskData->BootIndicator = partitionEntry->BootIndicator; 5421 deviceExtension->StartingOffset = partitionEntry->StartingOffset; 5422 deviceExtension->PartitionLength = partitionEntry->PartitionLength; 5423 diskData->HiddenSectors = partitionEntry->HiddenSectors; 5424 diskData->PartitionOrdinal = partitionOrdinal; 5425 5426 DebugPrint((1, 5427 "UpdateDeviceObjects: Ordinal %d is partition %d\n", 5428 diskData->PartitionOrdinal, 5429 diskData->PartitionNumber)); 5430 5431 // 5432 // Update partition number passed in to indicate the 5433 // device name for this partition. 5434 // 5435 5436 partitionEntry->PartitionNumber = partitionNumber; 5437 } 5438 5439 } // end UpdateDeviceObjects() 5440 5441