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 NTSTATUS 1072 NTAPI 1073 CreatePartitionDeviceObjects( 1074 IN PDEVICE_OBJECT PhysicalDeviceObject, 1075 IN PUNICODE_STRING RegistryPath 1076 ) 1077 { 1078 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH]; 1079 ULONG partitionNumber = 0; 1080 NTSTATUS status; 1081 PDEVICE_OBJECT deviceObject = NULL; 1082 PDISK_GEOMETRY_EX diskGeometry = NULL; 1083 PDRIVE_LAYOUT_INFORMATION partitionList = NULL; 1084 PDEVICE_EXTENSION deviceExtension; 1085 PDEVICE_EXTENSION physicalDeviceExtension; 1086 PCLASS_INIT_DATA initData = NULL; 1087 PDISK_DATA diskData; 1088 PDISK_DATA physicalDiskData; 1089 ULONG bytesPerSector; 1090 UCHAR sectorShift; 1091 ULONG srbFlags; 1092 ULONG dmByteSkew = 0; 1093 PULONG dmSkew; 1094 BOOLEAN dmActive = FALSE; 1095 ULONG numberListElements = 0; 1096 1097 1098 // 1099 // Get physical device geometry information for partition table reads. 1100 // 1101 1102 physicalDeviceExtension = PhysicalDeviceObject->DeviceExtension; 1103 diskGeometry = physicalDeviceExtension->DiskGeometry; 1104 bytesPerSector = diskGeometry->Geometry.BytesPerSector; 1105 1106 // 1107 // Make sure sector size is not zero. 1108 // 1109 1110 if (bytesPerSector == 0) { 1111 1112 // 1113 // Default sector size for disk is 512. 1114 // 1115 1116 bytesPerSector = diskGeometry->Geometry.BytesPerSector = 512; 1117 } 1118 1119 sectorShift = physicalDeviceExtension->SectorShift; 1120 1121 // 1122 // Set pointer to disk data area that follows device extension. 1123 // 1124 1125 diskData = (PDISK_DATA)(physicalDeviceExtension + 1); 1126 diskData->PartitionListState = Initializing; 1127 1128 // 1129 // Determine is DM Driver is loaded on an IDE drive that is 1130 // under control of Atapi - this could be either a crashdump or 1131 // an Atapi device is sharing the controller with an IDE disk. 1132 // 1133 1134 HalExamineMBR(PhysicalDeviceObject, 1135 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector, 1136 (ULONG)0x54, 1137 (PVOID)&dmSkew); 1138 1139 if (dmSkew) { 1140 1141 // 1142 // Update the device extension, so that the call to IoReadPartitionTable 1143 // will get the correct information. Any I/O to this disk will have 1144 // to be skewed by *dmSkew sectors aka DMByteSkew. 1145 // 1146 1147 physicalDeviceExtension->DMSkew = *dmSkew; 1148 physicalDeviceExtension->DMActive = TRUE; 1149 physicalDeviceExtension->DMByteSkew = physicalDeviceExtension->DMSkew * bytesPerSector; 1150 1151 // 1152 // Save away the information that we need, since this deviceExtension will soon be 1153 // blown away. 1154 // 1155 1156 dmActive = TRUE; 1157 dmByteSkew = physicalDeviceExtension->DMByteSkew; 1158 1159 } 1160 1161 #ifdef __REACTOS__ 1162 // 1163 // HACK so that we can use NT5+ NTOS functions with this NT4 driver 1164 // for removable devices and avoid an infinite recursive loop between 1165 // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable(). 1166 // 1167 diskData->UpdateRemovableGeometryCount = 0; 1168 #endif 1169 1170 // 1171 // Create objects for all the partitions on the device. 1172 // 1173 1174 status = IoReadPartitionTable(PhysicalDeviceObject, 1175 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector, 1176 TRUE, 1177 (PVOID)&partitionList); 1178 1179 // 1180 // If the I/O read partition table failed and this is a removable device, 1181 // then fix up the partition list to make it look like there is one 1182 // zero length partition. 1183 // 1184 DPRINT("IoReadPartitionTable() status: 0x%08X\n", status); 1185 if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) && 1186 PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 1187 1188 if (!NT_SUCCESS(status)) { 1189 1190 // 1191 // Remember this disk is not ready. 1192 // 1193 1194 diskData->DriveNotReady = TRUE; 1195 1196 } else { 1197 1198 // 1199 // Free the partition list allocated by IoReadPartitionTable. 1200 // 1201 1202 ExFreePool(partitionList); 1203 } 1204 1205 // 1206 // Allocate and zero a partition list. 1207 // 1208 1209 partitionList = ExAllocatePool(NonPagedPool, sizeof(*partitionList)); 1210 1211 1212 if (partitionList != NULL) { 1213 1214 RtlZeroMemory( partitionList, sizeof( *partitionList )); 1215 1216 // 1217 // Set the partition count to one and the status to success 1218 // so one device object will be created. Set the partition type 1219 // to a bogus value. 1220 // 1221 1222 partitionList->PartitionCount = 1; 1223 1224 status = STATUS_SUCCESS; 1225 } 1226 } 1227 1228 if (NT_SUCCESS(status)) { 1229 1230 // 1231 // Record disk signature. 1232 // 1233 1234 diskData->Signature = partitionList->Signature; 1235 1236 // 1237 // If disk signature is zero, then calculate the MBR checksum. 1238 // 1239 1240 if (!diskData->Signature) { 1241 1242 if (!CalculateMbrCheckSum(physicalDeviceExtension, 1243 &diskData->MbrCheckSum)) { 1244 1245 DebugPrint((1, 1246 "SCSIDISK: Can't calculate MBR checksum for disk %x\n", 1247 physicalDeviceExtension->DeviceNumber)); 1248 } else { 1249 1250 DebugPrint((2, 1251 "SCSIDISK: MBR checksum for disk %x is %x\n", 1252 physicalDeviceExtension->DeviceNumber, 1253 diskData->MbrCheckSum)); 1254 } 1255 } 1256 1257 // 1258 // Check the registry and determine if the BIOS knew about this drive. If 1259 // it did then update the geometry with the BIOS information. 1260 // 1261 1262 UpdateGeometry(physicalDeviceExtension); 1263 1264 srbFlags = physicalDeviceExtension->SrbFlags; 1265 1266 initData = ExAllocatePool(NonPagedPool, sizeof(CLASS_INIT_DATA)); 1267 if (!initData) 1268 { 1269 DebugPrint((1, 1270 "Disk.CreatePartitionDeviceObjects - Allocation of initData failed\n")); 1271 1272 status = STATUS_INSUFFICIENT_RESOURCES; 1273 goto CreatePartitionDeviceObjectsExit; 1274 } 1275 1276 RtlZeroMemory(initData, sizeof(CLASS_INIT_DATA)); 1277 1278 initData->InitializationDataSize = sizeof(CLASS_INIT_DATA); 1279 initData->DeviceExtensionSize = DEVICE_EXTENSION_SIZE; 1280 initData->DeviceType = FILE_DEVICE_DISK; 1281 initData->DeviceCharacteristics = PhysicalDeviceObject->Characteristics; 1282 initData->ClassError = physicalDeviceExtension->ClassError; 1283 initData->ClassReadWriteVerification = physicalDeviceExtension->ClassReadWriteVerification; 1284 initData->ClassFindDevices = physicalDeviceExtension->ClassFindDevices; 1285 initData->ClassDeviceControl = physicalDeviceExtension->ClassDeviceControl; 1286 initData->ClassShutdownFlush = physicalDeviceExtension->ClassShutdownFlush; 1287 initData->ClassCreateClose = physicalDeviceExtension->ClassCreateClose; 1288 initData->ClassStartIo = physicalDeviceExtension->ClassStartIo; 1289 1290 // 1291 // Create device objects for the device partitions (if any). 1292 // PartitionCount includes physical device partition 0, 1293 // so only one partition means no objects to create. 1294 // 1295 1296 DebugPrint((2, 1297 "CreateDiskDeviceObjects: Number of partitions is %d\n", 1298 partitionList->PartitionCount)); 1299 1300 for (partitionNumber = 0; partitionNumber < 1301 partitionList->PartitionCount; partitionNumber++) { 1302 1303 // 1304 // Create partition object and set up partition parameters. 1305 // 1306 1307 sprintf(ntNameBuffer, 1308 "\\Device\\Harddisk%lu\\Partition%lu", 1309 physicalDeviceExtension->DeviceNumber, 1310 partitionNumber + 1); 1311 1312 DebugPrint((2, 1313 "CreateDiskDeviceObjects: Create device object %s\n", 1314 ntNameBuffer)); 1315 1316 status = ScsiClassCreateDeviceObject(PhysicalDeviceObject->DriverObject, 1317 ntNameBuffer, 1318 PhysicalDeviceObject, 1319 &deviceObject, 1320 initData); 1321 1322 if (!NT_SUCCESS(status)) { 1323 1324 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer)); 1325 1326 break; 1327 } 1328 1329 // 1330 // Set up device object fields. 1331 // 1332 1333 deviceObject->Flags |= DO_DIRECT_IO; 1334 1335 // 1336 // Check if this is during initialization. If not indicate that 1337 // system initialization already took place and this disk is ready 1338 // to be accessed. 1339 // 1340 1341 if (!RegistryPath) { 1342 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 1343 } 1344 1345 deviceObject->StackSize = (CCHAR)physicalDeviceExtension->PortDeviceObject->StackSize + 1; 1346 1347 // 1348 // Set up device extension fields. 1349 // 1350 1351 deviceExtension = deviceObject->DeviceExtension; 1352 1353 if (dmActive) { 1354 1355 // 1356 // Restore any saved DM values. 1357 // 1358 1359 deviceExtension->DMByteSkew = dmByteSkew; 1360 deviceExtension->DMSkew = *dmSkew; 1361 deviceExtension->DMActive = TRUE; 1362 1363 } 1364 1365 // 1366 // Link new device extension to previous disk data 1367 // to support dynamic partitioning. 1368 // 1369 1370 diskData->NextPartition = deviceExtension; 1371 1372 // 1373 // Get pointer to new disk data. 1374 // 1375 1376 diskData = (PDISK_DATA)(deviceExtension + 1); 1377 1378 // 1379 // Set next partition pointer to NULL in case this is the 1380 // last partition. 1381 // 1382 1383 diskData->NextPartition = NULL; 1384 1385 // 1386 // Allocate spinlock for zoning for split-request completion. 1387 // 1388 1389 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock); 1390 1391 // 1392 // Copy port device object pointer to device extension. 1393 // 1394 1395 deviceExtension->PortDeviceObject = physicalDeviceExtension->PortDeviceObject; 1396 1397 // 1398 // Set the alignment requirements for the device based on the 1399 // host adapter requirements 1400 // 1401 1402 if (physicalDeviceExtension->PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) { 1403 deviceObject->AlignmentRequirement = physicalDeviceExtension->PortDeviceObject->AlignmentRequirement; 1404 } 1405 1406 1407 if (srbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) { 1408 numberListElements = 30; 1409 } else { 1410 numberListElements = 8; 1411 } 1412 1413 // 1414 // Build the lookaside list for srb's for this partition based on 1415 // whether the adapter and disk can do tagged queueing. 1416 // 1417 1418 ScsiClassInitializeSrbLookasideList(deviceExtension, 1419 numberListElements); 1420 1421 deviceExtension->SrbFlags = srbFlags; 1422 1423 // 1424 // Set the sense-data pointer in the device extension. 1425 // 1426 1427 deviceExtension->SenseData = physicalDeviceExtension->SenseData; 1428 deviceExtension->PortCapabilities = physicalDeviceExtension->PortCapabilities; 1429 deviceExtension->DiskGeometry = diskGeometry; 1430 diskData->PartitionOrdinal = diskData->PartitionNumber = partitionNumber + 1; 1431 diskData->PartitionType = partitionList->PartitionEntry[partitionNumber].PartitionType; 1432 diskData->BootIndicator = partitionList->PartitionEntry[partitionNumber].BootIndicator; 1433 1434 DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n", 1435 diskData->PartitionType)); 1436 1437 deviceExtension->StartingOffset = partitionList->PartitionEntry[partitionNumber].StartingOffset; 1438 deviceExtension->PartitionLength = partitionList->PartitionEntry[partitionNumber].PartitionLength; 1439 diskData->HiddenSectors = partitionList->PartitionEntry[partitionNumber].HiddenSectors; 1440 deviceExtension->PortNumber = physicalDeviceExtension->PortNumber; 1441 deviceExtension->PathId = physicalDeviceExtension->PathId; 1442 deviceExtension->TargetId = physicalDeviceExtension->TargetId; 1443 deviceExtension->Lun = physicalDeviceExtension->Lun; 1444 1445 // 1446 // Check for removable media support. 1447 // 1448 1449 if (PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 1450 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA; 1451 } 1452 1453 // 1454 // Set timeout value in seconds. 1455 // 1456 1457 deviceExtension->TimeOutValue = physicalDeviceExtension->TimeOutValue; 1458 deviceExtension->DiskGeometry->Geometry.BytesPerSector = bytesPerSector; 1459 deviceExtension->SectorShift = sectorShift; 1460 deviceExtension->DeviceObject = deviceObject; 1461 deviceExtension->DeviceFlags |= physicalDeviceExtension->DeviceFlags; 1462 1463 } // end for (partitionNumber) ... 1464 1465 // 1466 // Free the buffer allocated by reading the 1467 // partition table. 1468 // 1469 1470 ExFreePool(partitionList); 1471 1472 if (dmSkew) { 1473 ExFreePool(dmSkew); 1474 } 1475 1476 } else { 1477 1478 CreatePartitionDeviceObjectsExit: 1479 1480 if (partitionList) { 1481 ExFreePool(partitionList); 1482 } 1483 if (initData) { 1484 ExFreePool(initData); 1485 } 1486 1487 if (dmSkew) { 1488 ExFreePool(dmSkew); 1489 } 1490 1491 return status; 1492 1493 } // end if...else 1494 1495 1496 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1); 1497 physicalDiskData->PartitionListState = Initialized; 1498 1499 return(STATUS_SUCCESS); 1500 1501 1502 } // end CreatePartitionDeviceObjects() 1503 1504 1505 NTSTATUS 1506 NTAPI 1507 ScsiDiskReadWriteVerification( 1508 IN PDEVICE_OBJECT DeviceObject, 1509 IN PIRP Irp 1510 ) 1511 1512 /*++ 1513 1514 Routine Description: 1515 1516 I/O System entry for read and write requests to SCSI disks. 1517 1518 Arguments: 1519 1520 DeviceObject - Pointer to driver object created by system. 1521 Irp - IRP involved. 1522 1523 Return Value: 1524 1525 NT Status 1526 1527 --*/ 1528 1529 { 1530 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 1531 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 1532 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; 1533 LARGE_INTEGER startingOffset; 1534 1535 // 1536 // HACK: How can we end here with null sector size?! 1537 // 1538 1539 if (deviceExtension->DiskGeometry->Geometry.BytesPerSector == 0) { 1540 DPRINT1("Hack! Received invalid sector size\n"); 1541 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 512; 1542 } 1543 1544 // 1545 // Verify parameters of this request. 1546 // Check that ending sector is within partition and 1547 // that number of bytes to transfer is a multiple of 1548 // the sector size. 1549 // 1550 1551 startingOffset.QuadPart = (currentIrpStack->Parameters.Read.ByteOffset.QuadPart + 1552 transferByteCount); 1553 1554 if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) || 1555 (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) { 1556 1557 // 1558 // This error maybe caused by the fact that the drive is not ready. 1559 // 1560 1561 if (((PDISK_DATA)(deviceExtension + 1))->DriveNotReady) { 1562 1563 // 1564 // Flag this as a user error so that a popup is generated. 1565 // 1566 1567 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY; 1568 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 1569 1570 } else { 1571 1572 // 1573 // Note fastfat depends on this parameter to determine when to 1574 // remount do to a sector size change. 1575 // 1576 1577 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 1578 } 1579 1580 if (startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) { 1581 DPRINT1("Reading beyond partition end! startingOffset: %I64d, PartitionLength: %I64d\n", startingOffset.QuadPart, deviceExtension->PartitionLength.QuadPart); 1582 } 1583 1584 if (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1)) { 1585 DPRINT1("Not reading sectors! TransferByteCount: %lu, BytesPerSector: %lu\n", transferByteCount, deviceExtension->DiskGeometry->Geometry.BytesPerSector); 1586 } 1587 1588 if (Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) { 1589 DPRINT1("Failing due to device not ready!\n"); 1590 } 1591 1592 return STATUS_INVALID_PARAMETER; 1593 } 1594 1595 return STATUS_SUCCESS; 1596 1597 } // end ScsiDiskReadWrite() 1598 1599 1600 NTSTATUS 1601 NTAPI 1602 ScsiDiskDeviceControl( 1603 PDEVICE_OBJECT DeviceObject, 1604 PIRP Irp 1605 ) 1606 1607 /*++ 1608 1609 Routine Description: 1610 1611 I/O system entry for device controls to SCSI disks. 1612 1613 Arguments: 1614 1615 DeviceObject - Pointer to driver object created by system. 1616 Irp - IRP involved. 1617 1618 Return Value: 1619 1620 Status is returned. 1621 1622 --*/ 1623 1624 { 1625 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 1626 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 1627 PDISK_DATA diskData = (PDISK_DATA)(deviceExtension + 1); 1628 PSCSI_REQUEST_BLOCK srb; 1629 PCDB cdb; 1630 PMODE_PARAMETER_HEADER modeData; 1631 PIRP irp2; 1632 ULONG length; 1633 NTSTATUS status; 1634 KEVENT event; 1635 IO_STATUS_BLOCK ioStatus; 1636 1637 PAGED_CODE(); 1638 1639 srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE); 1640 1641 if (srb == NULL) { 1642 1643 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 1644 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1645 return(STATUS_INSUFFICIENT_RESOURCES); 1646 } 1647 1648 // 1649 // Write zeros to Srb. 1650 // 1651 1652 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 1653 1654 cdb = (PCDB)srb->Cdb; 1655 1656 switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { 1657 1658 case SMART_GET_VERSION: { 1659 1660 ULONG_PTR buffer; 1661 PSRB_IO_CONTROL srbControl; 1662 PGETVERSIONINPARAMS versionParams; 1663 1664 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 1665 sizeof(GETVERSIONINPARAMS)) { 1666 status = STATUS_INVALID_PARAMETER; 1667 break; 1668 } 1669 1670 // 1671 // Create notification event object to be used to signal the 1672 // request completion. 1673 // 1674 1675 KeInitializeEvent(&event, NotificationEvent, FALSE); 1676 1677 srbControl = ExAllocatePool(NonPagedPool, 1678 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS)); 1679 1680 if (!srbControl) { 1681 status = STATUS_INSUFFICIENT_RESOURCES; 1682 break; 1683 } 1684 1685 // 1686 // fill in srbControl fields 1687 // 1688 1689 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); 1690 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); 1691 srbControl->Timeout = deviceExtension->TimeOutValue; 1692 srbControl->Length = sizeof(GETVERSIONINPARAMS); 1693 srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION; 1694 1695 // 1696 // Point to the 'buffer' portion of the SRB_CONTROL 1697 // 1698 1699 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 1700 1701 // 1702 // Ensure correct target is set in the cmd parameters. 1703 // 1704 1705 versionParams = (PGETVERSIONINPARAMS)buffer; 1706 versionParams->bIDEDeviceMap = deviceExtension->TargetId; 1707 1708 // 1709 // Copy the IOCTL parameters to the srb control buffer area. 1710 // 1711 1712 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(GETVERSIONINPARAMS)); 1713 1714 1715 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT, 1716 deviceExtension->PortDeviceObject, 1717 srbControl, 1718 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS), 1719 srbControl, 1720 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS), 1721 FALSE, 1722 &event, 1723 &ioStatus); 1724 1725 if (irp2 == NULL) { 1726 status = STATUS_INSUFFICIENT_RESOURCES; 1727 break; 1728 } 1729 1730 // 1731 // Call the port driver with the request and wait for it to complete. 1732 // 1733 1734 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2); 1735 1736 if (status == STATUS_PENDING) { 1737 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 1738 status = ioStatus.Status; 1739 } 1740 1741 // 1742 // If successful, copy the data received into the output buffer. 1743 // This should only fail in the event that the IDE driver is older than this driver. 1744 // 1745 1746 if (NT_SUCCESS(status)) { 1747 1748 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 1749 1750 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, sizeof(GETVERSIONINPARAMS)); 1751 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS); 1752 } 1753 1754 ExFreePool(srbControl); 1755 break; 1756 } 1757 1758 case SMART_RCV_DRIVE_DATA: { 1759 1760 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer); 1761 ULONG controlCode = 0; 1762 PSRB_IO_CONTROL srbControl; 1763 ULONG_PTR buffer; 1764 1765 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 1766 (sizeof(SENDCMDINPARAMS) - 1)) { 1767 status = STATUS_INVALID_PARAMETER; 1768 break; 1769 1770 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 1771 (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) { 1772 status = STATUS_INVALID_PARAMETER; 1773 break; 1774 } 1775 1776 // 1777 // Create notification event object to be used to signal the 1778 // request completion. 1779 // 1780 1781 KeInitializeEvent(&event, NotificationEvent, FALSE); 1782 1783 if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) { 1784 1785 length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); 1786 controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY; 1787 1788 } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) { 1789 switch (cmdInParameters->irDriveRegs.bFeaturesReg) { 1790 case READ_ATTRIBUTES: 1791 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; 1792 length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); 1793 break; 1794 case READ_THRESHOLDS: 1795 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; 1796 length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); 1797 break; 1798 default: 1799 status = STATUS_INVALID_PARAMETER; 1800 break; 1801 } 1802 } else { 1803 1804 status = STATUS_INVALID_PARAMETER; 1805 } 1806 1807 if (controlCode == 0) { 1808 status = STATUS_INVALID_PARAMETER; 1809 break; 1810 } 1811 1812 srbControl = ExAllocatePool(NonPagedPool, 1813 sizeof(SRB_IO_CONTROL) + length); 1814 1815 if (!srbControl) { 1816 status = STATUS_INSUFFICIENT_RESOURCES; 1817 break; 1818 } 1819 1820 // 1821 // fill in srbControl fields 1822 // 1823 1824 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); 1825 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); 1826 srbControl->Timeout = deviceExtension->TimeOutValue; 1827 srbControl->Length = length; 1828 srbControl->ControlCode = controlCode; 1829 1830 // 1831 // Point to the 'buffer' portion of the SRB_CONTROL 1832 // 1833 1834 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 1835 1836 // 1837 // Ensure correct target is set in the cmd parameters. 1838 // 1839 1840 cmdInParameters->bDriveNumber = deviceExtension->TargetId; 1841 1842 // 1843 // Copy the IOCTL parameters to the srb control buffer area. 1844 // 1845 1846 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1); 1847 1848 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT, 1849 deviceExtension->PortDeviceObject, 1850 srbControl, 1851 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1, 1852 srbControl, 1853 sizeof(SRB_IO_CONTROL) + length, 1854 FALSE, 1855 &event, 1856 &ioStatus); 1857 1858 if (irp2 == NULL) { 1859 status = STATUS_INSUFFICIENT_RESOURCES; 1860 break; 1861 } 1862 1863 // 1864 // Call the port driver with the request and wait for it to complete. 1865 // 1866 1867 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2); 1868 1869 if (status == STATUS_PENDING) { 1870 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 1871 status = ioStatus.Status; 1872 } 1873 1874 // 1875 // If successful, copy the data received into the output buffer 1876 // 1877 1878 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 1879 1880 if (NT_SUCCESS(status)) { 1881 1882 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length - 1); 1883 Irp->IoStatus.Information = length - 1; 1884 1885 } else { 1886 1887 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, (sizeof(SENDCMDOUTPARAMS) - 1)); 1888 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1; 1889 1890 } 1891 1892 ExFreePool(srbControl); 1893 break; 1894 1895 } 1896 1897 case SMART_SEND_DRIVE_COMMAND: { 1898 1899 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer); 1900 PSRB_IO_CONTROL srbControl; 1901 ULONG controlCode = 0; 1902 ULONG_PTR buffer; 1903 1904 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 1905 (sizeof(SENDCMDINPARAMS) - 1)) { 1906 status = STATUS_INVALID_PARAMETER; 1907 break; 1908 1909 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 1910 (sizeof(SENDCMDOUTPARAMS) - 1)) { 1911 status = STATUS_INVALID_PARAMETER; 1912 break; 1913 } 1914 1915 // 1916 // Create notification event object to be used to signal the 1917 // request completion. 1918 // 1919 1920 KeInitializeEvent(&event, NotificationEvent, FALSE); 1921 1922 length = 0; 1923 1924 if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) { 1925 switch (cmdInParameters->irDriveRegs.bFeaturesReg) { 1926 1927 case ENABLE_SMART: 1928 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART; 1929 break; 1930 1931 case DISABLE_SMART: 1932 controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART; 1933 break; 1934 1935 case RETURN_SMART_STATUS: 1936 1937 // 1938 // Ensure bBuffer is at least 2 bytes (to hold the values of 1939 // cylinderLow and cylinderHigh). 1940 // 1941 1942 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 1943 (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) { 1944 1945 status = STATUS_INVALID_PARAMETER; 1946 break; 1947 } 1948 1949 controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS; 1950 length = sizeof(IDEREGS); 1951 break; 1952 1953 case ENABLE_DISABLE_AUTOSAVE: 1954 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; 1955 break; 1956 1957 case SAVE_ATTRIBUTE_VALUES: 1958 controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; 1959 break; 1960 1961 case EXECUTE_OFFLINE_DIAGS: 1962 controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; 1963 break; 1964 1965 default: 1966 status = STATUS_INVALID_PARAMETER; 1967 break; 1968 } 1969 } else { 1970 1971 status = STATUS_INVALID_PARAMETER; 1972 } 1973 1974 if (controlCode == 0) { 1975 status = STATUS_INVALID_PARAMETER; 1976 break; 1977 } 1978 1979 length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS); 1980 srbControl = ExAllocatePool(NonPagedPool, 1981 sizeof(SRB_IO_CONTROL) + length); 1982 1983 if (!srbControl) { 1984 status = STATUS_INSUFFICIENT_RESOURCES; 1985 break; 1986 } 1987 1988 // 1989 // fill in srbControl fields 1990 // 1991 1992 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); 1993 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); 1994 srbControl->Timeout = deviceExtension->TimeOutValue; 1995 srbControl->Length = length; 1996 1997 // 1998 // Point to the 'buffer' portion of the SRB_CONTROL 1999 // 2000 2001 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 2002 2003 // 2004 // Ensure correct target is set in the cmd parameters. 2005 // 2006 2007 cmdInParameters->bDriveNumber = deviceExtension->TargetId; 2008 2009 // 2010 // Copy the IOCTL parameters to the srb control buffer area. 2011 // 2012 2013 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1); 2014 2015 srbControl->ControlCode = controlCode; 2016 2017 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT, 2018 deviceExtension->PortDeviceObject, 2019 srbControl, 2020 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1, 2021 srbControl, 2022 sizeof(SRB_IO_CONTROL) + length, 2023 FALSE, 2024 &event, 2025 &ioStatus); 2026 2027 if (irp2 == NULL) { 2028 status = STATUS_INSUFFICIENT_RESOURCES; 2029 break; 2030 } 2031 2032 // 2033 // Call the port driver with the request and wait for it to complete. 2034 // 2035 2036 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2); 2037 2038 if (status == STATUS_PENDING) { 2039 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 2040 status = ioStatus.Status; 2041 } 2042 2043 // 2044 // Copy the data received into the output buffer. Since the status buffer 2045 // contains error information also, always perform this copy. IO will will 2046 // either pass this back to the app, or zero it, in case of error. 2047 // 2048 2049 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 2050 2051 // 2052 // Update the return buffer size based on the sub-command. 2053 // 2054 2055 if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) { 2056 length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS); 2057 } else { 2058 length = sizeof(SENDCMDOUTPARAMS) - 1; 2059 } 2060 2061 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length); 2062 Irp->IoStatus.Information = length; 2063 2064 ExFreePool(srbControl); 2065 break; 2066 2067 } 2068 2069 case IOCTL_DISK_GET_DRIVE_GEOMETRY: 2070 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: 2071 { 2072 2073 PDEVICE_EXTENSION physicalDeviceExtension; 2074 PDISK_DATA physicalDiskData; 2075 BOOLEAN removable = FALSE; 2076 BOOLEAN listInitialized = FALSE; 2077 ULONG copyLength; 2078 2079 if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) { 2080 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) { 2081 status = STATUS_BUFFER_TOO_SMALL; 2082 break; 2083 } 2084 2085 copyLength = sizeof(DISK_GEOMETRY); 2086 } else { 2087 ASSERT(irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX); 2088 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(DISK_GEOMETRY_EX, Data)) { 2089 status = STATUS_BUFFER_TOO_SMALL; 2090 break; 2091 } 2092 2093 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(DISK_GEOMETRY_EX)) { 2094 copyLength = sizeof(DISK_GEOMETRY_EX); 2095 } else { 2096 copyLength = FIELD_OFFSET(DISK_GEOMETRY_EX, Data); 2097 } 2098 } 2099 2100 status = STATUS_SUCCESS; 2101 2102 physicalDeviceExtension = deviceExtension->PhysicalDevice->DeviceExtension; 2103 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1); 2104 2105 removable = (BOOLEAN)DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA; 2106 listInitialized = (physicalDiskData->PartitionListState == Initialized); 2107 2108 if (removable || (!listInitialized)) 2109 { 2110 // 2111 // Issue ReadCapacity to update device extension 2112 // with information for current media. 2113 // 2114 2115 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice); 2116 2117 } 2118 2119 if (removable) { 2120 2121 if (!NT_SUCCESS(status)) { 2122 2123 // 2124 // Note the drive is not ready. 2125 // 2126 2127 diskData->DriveNotReady = TRUE; 2128 2129 break; 2130 } 2131 2132 // 2133 // Note the drive is now ready. 2134 // 2135 2136 diskData->DriveNotReady = FALSE; 2137 2138 } else if (NT_SUCCESS(status)) { 2139 2140 // ReadDriveCapacity was alright, create Partition Objects 2141 2142 if (physicalDiskData->PartitionListState == NotInitialized) { 2143 status = CreatePartitionDeviceObjects(deviceExtension->PhysicalDevice, NULL); 2144 } 2145 } 2146 2147 if (NT_SUCCESS(status)) { 2148 2149 // 2150 // Copy drive geometry information from device extension. 2151 // 2152 2153 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, 2154 deviceExtension->DiskGeometry, 2155 copyLength); 2156 2157 status = STATUS_SUCCESS; 2158 Irp->IoStatus.Information = copyLength; 2159 } 2160 2161 break; 2162 2163 } 2164 2165 case IOCTL_DISK_VERIFY: 2166 2167 { 2168 2169 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer; 2170 LARGE_INTEGER byteOffset; 2171 ULONG sectorOffset; 2172 USHORT sectorCount; 2173 2174 // 2175 // Validate buffer length. 2176 // 2177 2178 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2179 sizeof(VERIFY_INFORMATION)) { 2180 2181 status = STATUS_INFO_LENGTH_MISMATCH; 2182 break; 2183 } 2184 2185 // 2186 // Verify sectors 2187 // 2188 2189 srb->CdbLength = 10; 2190 2191 cdb->CDB10.OperationCode = SCSIOP_VERIFY; 2192 2193 // 2194 // Add disk offset to starting sector. 2195 // 2196 2197 byteOffset.QuadPart = deviceExtension->StartingOffset.QuadPart + 2198 verifyInfo->StartingOffset.QuadPart; 2199 2200 // 2201 // Convert byte offset to sector offset. 2202 // 2203 2204 sectorOffset = (ULONG)(byteOffset.QuadPart >> deviceExtension->SectorShift); 2205 2206 // 2207 // Convert ULONG byte count to USHORT sector count. 2208 // 2209 2210 sectorCount = (USHORT)(verifyInfo->Length >> deviceExtension->SectorShift); 2211 2212 // 2213 // Move little endian values into CDB in big endian format. 2214 // 2215 2216 cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)§orOffset)->Byte3; 2217 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)§orOffset)->Byte2; 2218 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)§orOffset)->Byte1; 2219 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)§orOffset)->Byte0; 2220 2221 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)§orCount)->Byte1; 2222 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)§orCount)->Byte0; 2223 2224 // 2225 // The verify command is used by the NT FORMAT utility and 2226 // requests are sent down for 5% of the volume size. The 2227 // request timeout value is calculated based on the number of 2228 // sectors verified. 2229 // 2230 2231 srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) * 2232 deviceExtension->TimeOutValue; 2233 2234 status = ScsiClassSendSrbAsynchronous(DeviceObject, 2235 srb, 2236 Irp, 2237 NULL, 2238 0, 2239 FALSE); 2240 2241 return(status); 2242 2243 } 2244 2245 case IOCTL_DISK_GET_PARTITION_INFO: 2246 2247 // 2248 // Return the information about the partition specified by the device 2249 // object. Note that no information is ever returned about the size 2250 // or partition type of the physical disk, as this doesn't make any 2251 // sense. 2252 // 2253 2254 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 2255 sizeof(PARTITION_INFORMATION)) { 2256 2257 status = STATUS_INFO_LENGTH_MISMATCH; 2258 break; 2259 } 2260 2261 // 2262 // Update the geometry in case it has changed. 2263 // 2264 2265 status = UpdateRemovableGeometry (DeviceObject, Irp); 2266 2267 if (!NT_SUCCESS(status)) { 2268 2269 // 2270 // Note the drive is not ready. 2271 // 2272 2273 diskData->DriveNotReady = TRUE; 2274 break; 2275 } 2276 2277 // 2278 // Note the drive is now ready. 2279 // 2280 2281 diskData->DriveNotReady = FALSE; 2282 2283 // 2284 // Handle the case were we query the whole disk 2285 // 2286 2287 if (diskData->PartitionNumber == 0) { 2288 2289 PPARTITION_INFORMATION outputBuffer; 2290 2291 outputBuffer = 2292 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 2293 2294 outputBuffer->PartitionType = PARTITION_ENTRY_UNUSED; 2295 outputBuffer->StartingOffset = deviceExtension->StartingOffset; 2296 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart; 2297 outputBuffer->HiddenSectors = 0; 2298 outputBuffer->PartitionNumber = diskData->PartitionNumber; 2299 outputBuffer->BootIndicator = FALSE; 2300 outputBuffer->RewritePartition = FALSE; 2301 outputBuffer->RecognizedPartition = FALSE; 2302 2303 status = STATUS_SUCCESS; 2304 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION); 2305 2306 } else { 2307 2308 PPARTITION_INFORMATION outputBuffer; 2309 2310 // 2311 // We query a single partition here 2312 // FIXME: this can only work for MBR-based disks, check for this! 2313 // 2314 2315 outputBuffer = 2316 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 2317 2318 outputBuffer->PartitionType = diskData->PartitionType; 2319 outputBuffer->StartingOffset = deviceExtension->StartingOffset; 2320 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart; 2321 outputBuffer->HiddenSectors = diskData->HiddenSectors; 2322 outputBuffer->PartitionNumber = diskData->PartitionNumber; 2323 outputBuffer->BootIndicator = diskData->BootIndicator; 2324 outputBuffer->RewritePartition = FALSE; 2325 outputBuffer->RecognizedPartition = 2326 IsRecognizedPartition(diskData->PartitionType); 2327 2328 status = STATUS_SUCCESS; 2329 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION); 2330 } 2331 2332 break; 2333 2334 case IOCTL_DISK_GET_PARTITION_INFO_EX: 2335 2336 // 2337 // Return the information about the partition specified by the device 2338 // object. Note that no information is ever returned about the size 2339 // or partition type of the physical disk, as this doesn't make any 2340 // sense. 2341 // 2342 2343 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 2344 sizeof(PARTITION_INFORMATION_EX)) { 2345 2346 status = STATUS_INFO_LENGTH_MISMATCH; 2347 2348 } 2349 #if 0 // HACK: ReactOS partition numbers must be wrong 2350 else if (diskData->PartitionNumber == 0) { 2351 2352 // 2353 // Partition zero is not a partition so this is not a 2354 // reasonable request. 2355 // 2356 2357 status = STATUS_INVALID_DEVICE_REQUEST; 2358 2359 } 2360 #endif 2361 else { 2362 2363 PPARTITION_INFORMATION_EX outputBuffer; 2364 2365 if (diskData->PartitionNumber == 0) { 2366 DPRINT1("HACK: Handling partition 0 request!\n"); 2367 //ASSERT(FALSE); 2368 } 2369 2370 // 2371 // Update the geometry in case it has changed. 2372 // 2373 2374 status = UpdateRemovableGeometry (DeviceObject, Irp); 2375 2376 if (!NT_SUCCESS(status)) { 2377 2378 // 2379 // Note the drive is not ready. 2380 // 2381 2382 diskData->DriveNotReady = TRUE; 2383 break; 2384 } 2385 2386 // 2387 // Note the drive is now ready. 2388 // 2389 2390 diskData->DriveNotReady = FALSE; 2391 2392 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) { 2393 2394 status = STATUS_INVALID_DEVICE_REQUEST; 2395 break; 2396 } 2397 2398 outputBuffer = 2399 (PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer; 2400 2401 // 2402 // FIXME: hack of the year, assume that partition is MBR 2403 // Thing that can obviously be wrong... 2404 // 2405 2406 outputBuffer->PartitionStyle = PARTITION_STYLE_MBR; 2407 outputBuffer->Mbr.PartitionType = diskData->PartitionType; 2408 outputBuffer->StartingOffset = deviceExtension->StartingOffset; 2409 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart; 2410 outputBuffer->Mbr.HiddenSectors = diskData->HiddenSectors; 2411 outputBuffer->PartitionNumber = diskData->PartitionNumber; 2412 outputBuffer->Mbr.BootIndicator = diskData->BootIndicator; 2413 outputBuffer->RewritePartition = FALSE; 2414 outputBuffer->Mbr.RecognizedPartition = 2415 IsRecognizedPartition(diskData->PartitionType); 2416 2417 status = STATUS_SUCCESS; 2418 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX); 2419 } 2420 2421 break; 2422 2423 case IOCTL_DISK_SET_PARTITION_INFO: 2424 2425 if (diskData->PartitionNumber == 0) { 2426 2427 status = STATUS_UNSUCCESSFUL; 2428 2429 } else { 2430 2431 PSET_PARTITION_INFORMATION inputBuffer = 2432 (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 2433 2434 // 2435 // Validate buffer length. 2436 // 2437 2438 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2439 sizeof(SET_PARTITION_INFORMATION)) { 2440 2441 status = STATUS_INFO_LENGTH_MISMATCH; 2442 break; 2443 } 2444 2445 // 2446 // The HAL routines IoGet- and IoSetPartitionInformation were 2447 // developed before support of dynamic partitioning and therefore 2448 // don't distinguish between partition ordinal (that is the order 2449 // of a partition on a disk) and the partition number. (The 2450 // partition number is assigned to a partition to identify it to 2451 // the system.) Use partition ordinals for these legacy calls. 2452 // 2453 2454 status = IoSetPartitionInformation( 2455 deviceExtension->PhysicalDevice, 2456 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 2457 diskData->PartitionOrdinal, 2458 inputBuffer->PartitionType); 2459 2460 if (NT_SUCCESS(status)) { 2461 2462 diskData->PartitionType = inputBuffer->PartitionType; 2463 } 2464 } 2465 2466 break; 2467 2468 case IOCTL_DISK_GET_DRIVE_LAYOUT: 2469 2470 // 2471 // Return the partition layout for the physical drive. Note that 2472 // the layout is returned for the actual physical drive, regardless 2473 // of which partition was specified for the request. 2474 // 2475 2476 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 2477 sizeof(DRIVE_LAYOUT_INFORMATION)) { 2478 status = STATUS_INFO_LENGTH_MISMATCH; 2479 2480 } else { 2481 2482 PDRIVE_LAYOUT_INFORMATION partitionList; 2483 PDEVICE_EXTENSION physicalExtension = deviceExtension; 2484 PPARTITION_INFORMATION partitionEntry; 2485 PDISK_DATA diskData; 2486 ULONG tempSize; 2487 ULONG i; 2488 2489 // 2490 // Read partition information. 2491 // 2492 2493 status = IoReadPartitionTable(deviceExtension->PhysicalDevice, 2494 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 2495 FALSE, 2496 &partitionList); 2497 2498 if (!NT_SUCCESS(status)) { 2499 break; 2500 } 2501 2502 // 2503 // The disk layout has been returned in the partitionList 2504 // buffer. Determine its size and, if the data will fit 2505 // into the intermediary buffer, return it. 2506 // 2507 2508 tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]); 2509 tempSize += partitionList->PartitionCount * 2510 sizeof(PARTITION_INFORMATION); 2511 2512 if (tempSize > 2513 irpStack->Parameters.DeviceIoControl.OutputBufferLength) { 2514 2515 status = STATUS_BUFFER_TOO_SMALL; 2516 ExFreePool(partitionList); 2517 break; 2518 } 2519 2520 // 2521 // Walk partition list to associate partition numbers with 2522 // partition entries. 2523 // 2524 2525 for (i = 0; i < partitionList->PartitionCount; i++) { 2526 2527 // 2528 // Walk partition chain anchored at physical disk extension. 2529 // 2530 2531 deviceExtension = physicalExtension; 2532 diskData = (PDISK_DATA)(deviceExtension + 1); 2533 2534 do { 2535 2536 deviceExtension = diskData->NextPartition; 2537 2538 // 2539 // Check if this is the last partition in the chain. 2540 // 2541 2542 if (!deviceExtension) { 2543 break; 2544 } 2545 2546 // 2547 // Get the partition device extension from disk data. 2548 // 2549 2550 diskData = (PDISK_DATA)(deviceExtension + 1); 2551 2552 // 2553 // Check if this partition is not currently being used. 2554 // 2555 2556 if (!deviceExtension->PartitionLength.QuadPart) { 2557 continue; 2558 } 2559 2560 partitionEntry = &partitionList->PartitionEntry[i]; 2561 2562 // 2563 // Check if empty, or describes extended partition or hasn't changed. 2564 // 2565 2566 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED || 2567 IsContainerPartition(partitionEntry->PartitionType)) { 2568 continue; 2569 } 2570 2571 // 2572 // Check if new partition starts where this partition starts. 2573 // 2574 2575 if (partitionEntry->StartingOffset.QuadPart != 2576 deviceExtension->StartingOffset.QuadPart) { 2577 continue; 2578 } 2579 2580 // 2581 // Check if partition length is the same. 2582 // 2583 2584 if (partitionEntry->PartitionLength.QuadPart == 2585 deviceExtension->PartitionLength.QuadPart) { 2586 2587 // 2588 // Partitions match. Update partition number. 2589 // 2590 2591 partitionEntry->PartitionNumber = 2592 diskData->PartitionNumber; 2593 break; 2594 } 2595 2596 } while (TRUE); 2597 } 2598 2599 // 2600 // Copy partition information to system buffer. 2601 // 2602 2603 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, 2604 partitionList, 2605 tempSize); 2606 status = STATUS_SUCCESS; 2607 Irp->IoStatus.Information = tempSize; 2608 2609 // 2610 // Finally, free the buffer allocated by reading the 2611 // partition table. 2612 // 2613 2614 ExFreePool(partitionList); 2615 } 2616 2617 break; 2618 2619 case IOCTL_DISK_SET_DRIVE_LAYOUT: 2620 2621 { 2622 2623 // 2624 // Update the disk with new partition information. 2625 // 2626 2627 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer; 2628 2629 // 2630 // Validate buffer length. 2631 // 2632 2633 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2634 sizeof(DRIVE_LAYOUT_INFORMATION)) { 2635 2636 status = STATUS_INFO_LENGTH_MISMATCH; 2637 break; 2638 } 2639 2640 length = sizeof(DRIVE_LAYOUT_INFORMATION) + 2641 (partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION); 2642 2643 2644 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2645 length) { 2646 2647 status = STATUS_BUFFER_TOO_SMALL; 2648 break; 2649 } 2650 2651 // 2652 // Verify that device object is for physical disk. 2653 // 2654 2655 if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) { 2656 status = STATUS_INVALID_PARAMETER; 2657 break; 2658 } 2659 2660 // 2661 // Walk through partition table comparing partitions to 2662 // existing partitions to create, delete and change 2663 // device objects as necessary. 2664 // 2665 2666 UpdateDeviceObjects(DeviceObject, 2667 Irp); 2668 2669 // 2670 // Write changes to disk. 2671 // 2672 2673 status = IoWritePartitionTable( 2674 deviceExtension->DeviceObject, 2675 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 2676 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack, 2677 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder, 2678 partitionList); 2679 } 2680 2681 // 2682 // Update IRP with bytes returned. 2683 // 2684 2685 if (NT_SUCCESS(status)) { 2686 Irp->IoStatus.Information = length; 2687 } 2688 2689 break; 2690 2691 case IOCTL_DISK_REASSIGN_BLOCKS: 2692 2693 // 2694 // Map defective blocks to new location on disk. 2695 // 2696 2697 { 2698 2699 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer; 2700 ULONG bufferSize; 2701 ULONG blockNumber; 2702 ULONG blockCount; 2703 2704 // 2705 // Validate buffer length. 2706 // 2707 2708 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2709 sizeof(REASSIGN_BLOCKS)) { 2710 2711 status = STATUS_INFO_LENGTH_MISMATCH; 2712 break; 2713 } 2714 2715 bufferSize = sizeof(REASSIGN_BLOCKS) + 2716 (badBlocks->Count - 1) * sizeof(ULONG); 2717 2718 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2719 bufferSize) { 2720 2721 status = STATUS_INFO_LENGTH_MISMATCH; 2722 break; 2723 } 2724 2725 // 2726 // Build the data buffer to be transferred in the input buffer. 2727 // The format of the data to the device is: 2728 // 2729 // 2 bytes Reserved 2730 // 2 bytes Length 2731 // x * 4 btyes Block Address 2732 // 2733 // All values are big endian. 2734 // 2735 2736 badBlocks->Reserved = 0; 2737 blockCount = badBlocks->Count; 2738 2739 // 2740 // Convert # of entries to # of bytes. 2741 // 2742 2743 blockCount *= 4; 2744 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF); 2745 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00); 2746 2747 // 2748 // Convert back to number of entries. 2749 // 2750 2751 blockCount /= 4; 2752 2753 for (; blockCount > 0; blockCount--) { 2754 2755 blockNumber = badBlocks->BlockNumber[blockCount-1]; 2756 2757 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1], 2758 (PFOUR_BYTE) &blockNumber); 2759 } 2760 2761 srb->CdbLength = 6; 2762 2763 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS; 2764 2765 // 2766 // Set timeout value. 2767 // 2768 2769 srb->TimeOutValue = deviceExtension->TimeOutValue; 2770 2771 status = ScsiClassSendSrbSynchronous(DeviceObject, 2772 srb, 2773 badBlocks, 2774 bufferSize, 2775 TRUE); 2776 2777 Irp->IoStatus.Status = status; 2778 Irp->IoStatus.Information = 0; 2779 ExFreePool(srb); 2780 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2781 } 2782 2783 return(status); 2784 2785 case IOCTL_DISK_IS_WRITABLE: 2786 2787 // 2788 // Determine if the device is writable. 2789 // 2790 2791 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE); 2792 2793 if (modeData == NULL) { 2794 status = STATUS_INSUFFICIENT_RESOURCES; 2795 break; 2796 } 2797 2798 RtlZeroMemory(modeData, MODE_DATA_SIZE); 2799 2800 length = ScsiClassModeSense(DeviceObject, 2801 (PCHAR) modeData, 2802 MODE_DATA_SIZE, 2803 MODE_SENSE_RETURN_ALL); 2804 2805 if (length < sizeof(MODE_PARAMETER_HEADER)) { 2806 2807 // 2808 // Retry the request in case of a check condition. 2809 // 2810 2811 length = ScsiClassModeSense(DeviceObject, 2812 (PCHAR) modeData, 2813 MODE_DATA_SIZE, 2814 MODE_SENSE_RETURN_ALL); 2815 2816 if (length < sizeof(MODE_PARAMETER_HEADER)) { 2817 status = STATUS_IO_DEVICE_ERROR; 2818 ExFreePool(modeData); 2819 break; 2820 } 2821 } 2822 2823 if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) { 2824 status = STATUS_MEDIA_WRITE_PROTECTED; 2825 } else { 2826 status = STATUS_SUCCESS; 2827 } 2828 2829 ExFreePool(modeData); 2830 break; 2831 2832 case IOCTL_DISK_INTERNAL_SET_VERIFY: 2833 2834 // 2835 // If the caller is kernel mode, set the verify bit. 2836 // 2837 2838 if (Irp->RequestorMode == KernelMode) { 2839 DeviceObject->Flags |= DO_VERIFY_VOLUME; 2840 } 2841 status = STATUS_SUCCESS; 2842 break; 2843 2844 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY: 2845 2846 // 2847 // If the caller is kernel mode, clear the verify bit. 2848 // 2849 2850 if (Irp->RequestorMode == KernelMode) { 2851 DeviceObject->Flags &= ~DO_VERIFY_VOLUME; 2852 } 2853 status = STATUS_SUCCESS; 2854 break; 2855 2856 case IOCTL_DISK_FIND_NEW_DEVICES: 2857 2858 // 2859 // Search for devices that have been powered on since the last 2860 // device search or system initialization. 2861 // 2862 2863 DebugPrint((3,"CdRomDeviceControl: Find devices\n")); 2864 status = DriverEntry(DeviceObject->DriverObject, 2865 NULL); 2866 2867 Irp->IoStatus.Status = status; 2868 ExFreePool(srb); 2869 IoCompleteRequest(Irp, IO_NO_INCREMENT); 2870 return status; 2871 2872 case IOCTL_DISK_MEDIA_REMOVAL: 2873 2874 // 2875 // If the disk is not removable then don't allow this command. 2876 // 2877 2878 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) { 2879 status = STATUS_INVALID_DEVICE_REQUEST; 2880 break; 2881 } 2882 2883 // 2884 // Fall through and let the class driver process the request. 2885 // 2886 2887 case IOCTL_DISK_GET_LENGTH_INFO: 2888 2889 // 2890 // Validate buffer length. 2891 // 2892 2893 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 2894 sizeof(GET_LENGTH_INFORMATION)) { 2895 status = STATUS_BUFFER_TOO_SMALL; 2896 2897 } else { 2898 2899 PGET_LENGTH_INFORMATION lengthInformation = Irp->AssociatedIrp.SystemBuffer; 2900 2901 // 2902 // Update the geometry in case it has changed. 2903 // 2904 2905 status = UpdateRemovableGeometry (DeviceObject, Irp); 2906 2907 if (!NT_SUCCESS(status)) { 2908 2909 // 2910 // Note the drive is not ready. 2911 // 2912 2913 diskData->DriveNotReady = TRUE; 2914 break; 2915 } 2916 2917 // 2918 // Note the drive is now ready. 2919 // 2920 2921 diskData->DriveNotReady = FALSE; 2922 2923 // 2924 // Output data, and return 2925 // 2926 2927 lengthInformation->Length.QuadPart = deviceExtension->PartitionLength.QuadPart; 2928 status = STATUS_SUCCESS; 2929 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION); 2930 } 2931 2932 break; 2933 2934 default: 2935 2936 // 2937 // Free the Srb, since it is not needed. 2938 // 2939 2940 ExFreePool(srb); 2941 2942 // 2943 // Pass the request to the common device control routine. 2944 // 2945 2946 return(ScsiClassDeviceControl(DeviceObject, Irp)); 2947 2948 break; 2949 2950 } // end switch( ... 2951 2952 Irp->IoStatus.Status = status; 2953 2954 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) { 2955 2956 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 2957 } 2958 2959 IoCompleteRequest(Irp, IO_NO_INCREMENT); 2960 ExFreePool(srb); 2961 return(status); 2962 2963 } // end ScsiDiskDeviceControl() 2964 2965 NTSTATUS 2966 NTAPI 2967 ScsiDiskShutdownFlush ( 2968 IN PDEVICE_OBJECT DeviceObject, 2969 IN PIRP Irp 2970 ) 2971 2972 /*++ 2973 2974 Routine Description: 2975 2976 This routine is called for a shutdown and flush IRPs. These are sent by the 2977 system before it actually shuts down or when the file system does a flush. 2978 A synchronize cache command is sent to the device if it is write caching. 2979 If the device is removable an unlock command will be sent. This routine 2980 will sent a shutdown or flush Srb to the port driver. 2981 2982 Arguments: 2983 2984 DriverObject - Pointer to device object to being shutdown by system. 2985 2986 Irp - IRP involved. 2987 2988 Return Value: 2989 2990 NT Status 2991 2992 --*/ 2993 2994 { 2995 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 2996 PIO_STACK_LOCATION irpStack; 2997 PSCSI_REQUEST_BLOCK srb; 2998 NTSTATUS status; 2999 PCDB cdb; 3000 3001 // 3002 // Allocate SCSI request block. 3003 // 3004 3005 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK)); 3006 3007 if (srb == NULL) { 3008 3009 // 3010 // Set the status and complete the request. 3011 // 3012 3013 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 3014 IoCompleteRequest(Irp, IO_NO_INCREMENT); 3015 return(STATUS_INSUFFICIENT_RESOURCES); 3016 } 3017 3018 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 3019 3020 // 3021 // Write length to SRB. 3022 // 3023 3024 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 3025 3026 // 3027 // Set SCSI bus address. 3028 // 3029 3030 srb->PathId = deviceExtension->PathId; 3031 srb->TargetId = deviceExtension->TargetId; 3032 srb->Lun = deviceExtension->Lun; 3033 3034 // 3035 // Set timeout value and mark the request as not being a tagged request. 3036 // 3037 3038 srb->TimeOutValue = deviceExtension->TimeOutValue * 4; 3039 srb->QueueTag = SP_UNTAGGED; 3040 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 3041 srb->SrbFlags = deviceExtension->SrbFlags; 3042 3043 // 3044 // If the write cache is enabled then send a synchronize cache request. 3045 // 3046 3047 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) { 3048 3049 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 3050 srb->CdbLength = 10; 3051 3052 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE; 3053 3054 status = ScsiClassSendSrbSynchronous(DeviceObject, 3055 srb, 3056 NULL, 3057 0, 3058 TRUE); 3059 3060 DebugPrint((1, "ScsiDiskShutdownFlush: Synchronize cache sent. Status = %lx\n", status )); 3061 } 3062 3063 // 3064 // Unlock the device if it is removable and this is a shutdown. 3065 // 3066 3067 irpStack = IoGetCurrentIrpStackLocation(Irp); 3068 3069 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA && 3070 irpStack->MajorFunction == IRP_MJ_SHUTDOWN) { 3071 3072 srb->CdbLength = 6; 3073 cdb = (PVOID) srb->Cdb; 3074 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; 3075 cdb->MEDIA_REMOVAL.Prevent = FALSE; 3076 3077 // 3078 // Set timeout value. 3079 // 3080 3081 srb->TimeOutValue = deviceExtension->TimeOutValue; 3082 status = ScsiClassSendSrbSynchronous(DeviceObject, 3083 srb, 3084 NULL, 3085 0, 3086 TRUE); 3087 3088 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status )); 3089 } 3090 3091 srb->CdbLength = 0; 3092 3093 // 3094 // Save a few parameters in the current stack location. 3095 // 3096 3097 srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ? 3098 SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH; 3099 3100 // 3101 // Set the retry count to zero. 3102 // 3103 3104 irpStack->Parameters.Others.Argument4 = (PVOID) 0; 3105 3106 // 3107 // Set up IoCompletion routine address. 3108 // 3109 3110 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE); 3111 3112 // 3113 // Get next stack location and 3114 // set major function code. 3115 // 3116 3117 irpStack = IoGetNextIrpStackLocation(Irp); 3118 3119 irpStack->MajorFunction = IRP_MJ_SCSI; 3120 3121 // 3122 // Set up SRB for execute scsi request. 3123 // Save SRB address in next stack for port driver. 3124 // 3125 3126 irpStack->Parameters.Scsi.Srb = srb; 3127 3128 // 3129 // Set up Irp Address. 3130 // 3131 3132 srb->OriginalRequest = Irp; 3133 3134 // 3135 // Call the port driver to process the request. 3136 // 3137 3138 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp)); 3139 3140 } // end ScsiDiskShutdown() 3141 3142 3143 BOOLEAN 3144 NTAPI 3145 IsFloppyDevice( 3146 PDEVICE_OBJECT DeviceObject 3147 ) 3148 /*++ 3149 3150 Routine Description: 3151 3152 The routine performs the necessary functions to determine if a device is 3153 really a floppy rather than a harddisk. This is done by a mode sense 3154 command. First, a check is made to see if the media type is set. Second 3155 a check is made for the flexible parameters mode page. Also a check is 3156 made to see if the write cache is enabled. 3157 3158 Arguments: 3159 3160 DeviceObject - Supplies the device object to be tested. 3161 3162 Return Value: 3163 3164 Return TRUE if the indicated device is a floppy. 3165 3166 --*/ 3167 { 3168 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 3169 PVOID modeData; 3170 PUCHAR pageData; 3171 ULONG length; 3172 3173 PAGED_CODE(); 3174 3175 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE); 3176 3177 if (modeData == NULL) { 3178 return(FALSE); 3179 } 3180 3181 RtlZeroMemory(modeData, MODE_DATA_SIZE); 3182 3183 length = ScsiClassModeSense(DeviceObject, 3184 modeData, 3185 MODE_DATA_SIZE, 3186 MODE_SENSE_RETURN_ALL); 3187 3188 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3189 3190 // 3191 // Retry the request in case of a check condition. 3192 // 3193 3194 length = ScsiClassModeSense(DeviceObject, 3195 modeData, 3196 MODE_DATA_SIZE, 3197 MODE_SENSE_RETURN_ALL); 3198 3199 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3200 3201 ExFreePool(modeData); 3202 return(FALSE); 3203 3204 } 3205 } 3206 3207 // 3208 // If the length is greater than length indicated by the mode data reset 3209 // the data to the mode data. 3210 // 3211 3212 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) { 3213 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1; 3214 } 3215 3216 // 3217 // Look for the flexible disk mode page. 3218 // 3219 3220 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE); 3221 3222 if (pageData != NULL) { 3223 3224 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n")); 3225 ExFreePool(modeData); 3226 return(TRUE); 3227 } 3228 3229 // 3230 // Check to see if the write cache is enabled. 3231 // 3232 3233 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE); 3234 3235 // 3236 // Assume that write cache is disabled or not supported. 3237 // 3238 3239 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 3240 3241 // 3242 // Check if valid caching page exists. 3243 // 3244 3245 if (pageData != NULL) { 3246 3247 // 3248 // Check if write cache is disabled. 3249 // 3250 3251 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) { 3252 3253 DebugPrint((1, 3254 "SCSIDISK: Disk write cache enabled\n")); 3255 3256 // 3257 // Check if forced unit access (FUA) is supported. 3258 // 3259 3260 if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) { 3261 3262 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE; 3263 3264 } else { 3265 3266 DebugPrint((1, 3267 "SCSIDISK: Disk does not support FUA or DPO\n")); 3268 3269 // 3270 // TODO: Log this. 3271 // 3272 3273 } 3274 } 3275 } 3276 3277 ExFreePool(modeData); 3278 return(FALSE); 3279 3280 } // end IsFloppyDevice() 3281 3282 3283 BOOLEAN 3284 NTAPI 3285 ScsiDiskModeSelect( 3286 IN PDEVICE_OBJECT DeviceObject, 3287 IN PCHAR ModeSelectBuffer, 3288 IN ULONG Length, 3289 IN BOOLEAN SavePage 3290 ) 3291 3292 /*++ 3293 3294 Routine Description: 3295 3296 This routine sends a mode select command. 3297 3298 Arguments: 3299 3300 DeviceObject - Supplies the device object associated with this request. 3301 3302 ModeSelectBuffer - Supplies a buffer containing the page data. 3303 3304 Length - Supplies the length in bytes of the mode select buffer. 3305 3306 SavePage - Indicates that parameters should be written to disk. 3307 3308 Return Value: 3309 3310 Length of the transferred data is returned. 3311 3312 --*/ 3313 { 3314 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 3315 PCDB cdb; 3316 SCSI_REQUEST_BLOCK srb; 3317 ULONG retries = 1; 3318 ULONG length2; 3319 NTSTATUS status; 3320 ULONG_PTR buffer; 3321 PMODE_PARAMETER_BLOCK blockDescriptor; 3322 3323 PAGED_CODE(); 3324 3325 length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK); 3326 3327 // 3328 // Allocate buffer for mode select header, block descriptor, and mode page. 3329 // 3330 3331 buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2); 3332 3333 RtlZeroMemory((PVOID)buffer, length2); 3334 3335 // 3336 // Set length in header to size of mode page. 3337 // 3338 3339 ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK); 3340 3341 blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1); 3342 3343 // 3344 // Set size 3345 // 3346 3347 blockDescriptor->BlockLength[1]=0x02; 3348 3349 // 3350 // Copy mode page to buffer. 3351 // 3352 3353 RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length); 3354 3355 // 3356 // Zero SRB. 3357 // 3358 3359 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 3360 3361 // 3362 // Build the MODE SELECT CDB. 3363 // 3364 3365 srb.CdbLength = 6; 3366 cdb = (PCDB)srb.Cdb; 3367 3368 // 3369 // Set timeout value from device extension. 3370 // 3371 3372 srb.TimeOutValue = deviceExtension->TimeOutValue * 2; 3373 3374 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; 3375 cdb->MODE_SELECT.SPBit = SavePage; 3376 cdb->MODE_SELECT.PFBit = 1; 3377 cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2); 3378 3379 Retry: 3380 3381 status = ScsiClassSendSrbSynchronous(DeviceObject, 3382 &srb, 3383 (PVOID)buffer, 3384 length2, 3385 TRUE); 3386 3387 3388 if (status == STATUS_VERIFY_REQUIRED) { 3389 3390 // 3391 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with 3392 // this status. 3393 // 3394 3395 if (retries--) { 3396 3397 // 3398 // Retry request. 3399 // 3400 3401 goto Retry; 3402 } 3403 3404 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) { 3405 status = STATUS_SUCCESS; 3406 } 3407 3408 ExFreePool((PVOID)buffer); 3409 3410 if (NT_SUCCESS(status)) { 3411 return(TRUE); 3412 } else { 3413 return(FALSE); 3414 } 3415 3416 } // end SciDiskModeSelect() 3417 3418 3419 VOID 3420 NTAPI 3421 DisableWriteCache( 3422 IN PDEVICE_OBJECT DeviceObject, 3423 IN PSCSI_INQUIRY_DATA LunInfo 3424 ) 3425 3426 { 3427 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 3428 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData; 3429 BAD_CONTROLLER_INFORMATION const *controller; 3430 ULONG j,length; 3431 PVOID modeData; 3432 PUCHAR pageData; 3433 3434 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) { 3435 3436 controller = &ScsiDiskBadControllers[j]; 3437 3438 if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) { 3439 continue; 3440 } 3441 3442 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString)); 3443 3444 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE); 3445 3446 if (modeData == NULL) { 3447 3448 DebugPrint((1, 3449 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n")); 3450 return; 3451 } 3452 3453 RtlZeroMemory(modeData, MODE_DATA_SIZE); 3454 3455 length = ScsiClassModeSense(DeviceObject, 3456 modeData, 3457 MODE_DATA_SIZE, 3458 MODE_SENSE_RETURN_ALL); 3459 3460 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3461 3462 // 3463 // Retry the request in case of a check condition. 3464 // 3465 3466 length = ScsiClassModeSense(DeviceObject, 3467 modeData, 3468 MODE_DATA_SIZE, 3469 MODE_SENSE_RETURN_ALL); 3470 3471 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3472 3473 3474 DebugPrint((1, 3475 "ScsiDisk.DisableWriteCache: Mode Sense failed\n")); 3476 3477 ExFreePool(modeData); 3478 return; 3479 3480 } 3481 } 3482 3483 // 3484 // If the length is greater than length indicated by the mode data reset 3485 // the data to the mode data. 3486 // 3487 3488 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) { 3489 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1; 3490 } 3491 3492 // 3493 // Check to see if the write cache is enabled. 3494 // 3495 3496 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE); 3497 3498 // 3499 // Assume that write cache is disabled or not supported. 3500 // 3501 3502 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 3503 3504 // 3505 // Check if valid caching page exists. 3506 // 3507 3508 if (pageData != NULL) { 3509 3510 BOOLEAN savePage = FALSE; 3511 3512 savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable); 3513 3514 // 3515 // Check if write cache is disabled. 3516 // 3517 3518 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) { 3519 3520 PIO_ERROR_LOG_PACKET errorLogEntry; 3521 LONG errorCode; 3522 3523 3524 // 3525 // Disable write cache and ensure necessary fields are zeroed. 3526 // 3527 3528 ((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE; 3529 ((PMODE_CACHING_PAGE)pageData)->Reserved = 0; 3530 ((PMODE_CACHING_PAGE)pageData)->PageSavable = 0; 3531 ((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0; 3532 3533 // 3534 // Extract length from caching page. 3535 // 3536 3537 length = ((PMODE_CACHING_PAGE)pageData)->PageLength; 3538 3539 // 3540 // Compensate for page code and page length. 3541 // 3542 3543 length += 2; 3544 3545 // 3546 // Issue mode select to set the parameter. 3547 // 3548 3549 if (ScsiDiskModeSelect(DeviceObject, 3550 (PCHAR)pageData, 3551 length, 3552 savePage)) { 3553 3554 DebugPrint((1, 3555 "SCSIDISK: Disk write cache disabled\n")); 3556 3557 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 3558 errorCode = IO_WRITE_CACHE_DISABLED; 3559 3560 } else { 3561 if (ScsiDiskModeSelect(DeviceObject, 3562 (PCHAR)pageData, 3563 length, 3564 savePage)) { 3565 3566 DebugPrint((1, 3567 "SCSIDISK: Disk write cache disabled\n")); 3568 3569 3570 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 3571 errorCode = IO_WRITE_CACHE_DISABLED; 3572 3573 } else { 3574 3575 DebugPrint((1, 3576 "SCSIDISK: Mode select to disable write cache failed\n")); 3577 3578 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE; 3579 errorCode = IO_WRITE_CACHE_ENABLED; 3580 } 3581 } 3582 3583 // 3584 // Log the appropriate informational or error entry. 3585 // 3586 3587 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( 3588 DeviceObject, 3589 sizeof(IO_ERROR_LOG_PACKET) + 3 3590 * sizeof(ULONG)); 3591 3592 if (errorLogEntry != NULL) { 3593 3594 errorLogEntry->FinalStatus = STATUS_SUCCESS; 3595 errorLogEntry->ErrorCode = errorCode; 3596 errorLogEntry->SequenceNumber = 0; 3597 errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI; 3598 errorLogEntry->IoControlCode = 0; 3599 errorLogEntry->RetryCount = 0; 3600 errorLogEntry->UniqueErrorValue = 0x1; 3601 errorLogEntry->DumpDataSize = 3 * sizeof(ULONG); 3602 errorLogEntry->DumpData[0] = LunInfo->PathId; 3603 errorLogEntry->DumpData[1] = LunInfo->TargetId; 3604 errorLogEntry->DumpData[2] = LunInfo->Lun; 3605 3606 // 3607 // Write the error log packet. 3608 // 3609 3610 IoWriteErrorLogEntry(errorLogEntry); 3611 } 3612 } 3613 } 3614 3615 // 3616 // Found device so exit the loop and return. 3617 // 3618 3619 break; 3620 } 3621 3622 return; 3623 } 3624 3625 3626 BOOLEAN 3627 NTAPI 3628 CalculateMbrCheckSum( 3629 IN PDEVICE_EXTENSION DeviceExtension, 3630 OUT PULONG Checksum 3631 ) 3632 3633 /*++ 3634 3635 Routine Description: 3636 3637 Read MBR and calculate checksum. 3638 3639 Arguments: 3640 3641 DeviceExtension - Supplies a pointer to the device information for disk. 3642 Checksum - Memory location to return MBR checksum. 3643 3644 Return Value: 3645 3646 Returns TRUE if checksum is valid. 3647 3648 --*/ 3649 { 3650 LARGE_INTEGER sectorZero; 3651 PIRP irp; 3652 IO_STATUS_BLOCK ioStatus; 3653 KEVENT event; 3654 NTSTATUS status; 3655 ULONG sectorSize; 3656 PULONG mbr; 3657 ULONG i; 3658 3659 PAGED_CODE(); 3660 sectorZero.QuadPart = (LONGLONG) 0; 3661 3662 // 3663 // Create notification event object to be used to signal the inquiry 3664 // request completion. 3665 // 3666 3667 KeInitializeEvent(&event, NotificationEvent, FALSE); 3668 3669 // 3670 // Get sector size. 3671 // 3672 3673 sectorSize = DeviceExtension->DiskGeometry->Geometry.BytesPerSector; 3674 3675 // 3676 // Make sure sector size is at least 512 bytes. 3677 // 3678 3679 if (sectorSize < 512) { 3680 sectorSize = 512; 3681 } 3682 3683 // 3684 // Allocate buffer for sector read. 3685 // 3686 3687 mbr = ExAllocatePool(NonPagedPoolCacheAligned, sectorSize); 3688 3689 if (!mbr) { 3690 return FALSE; 3691 } 3692 3693 // 3694 // Build IRP to read MBR. 3695 // 3696 3697 irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 3698 DeviceExtension->DeviceObject, 3699 mbr, 3700 sectorSize, 3701 §orZero, 3702 &event, 3703 &ioStatus ); 3704 3705 if (!irp) { 3706 ExFreePool(mbr); 3707 return FALSE; 3708 } 3709 3710 // 3711 // Pass request to port driver and wait for request to complete. 3712 // 3713 3714 status = IoCallDriver(DeviceExtension->DeviceObject, 3715 irp); 3716 3717 if (status == STATUS_PENDING) { 3718 KeWaitForSingleObject(&event, 3719 Suspended, 3720 KernelMode, 3721 FALSE, 3722 NULL); 3723 status = ioStatus.Status; 3724 } 3725 3726 if (!NT_SUCCESS(status)) { 3727 ExFreePool(mbr); 3728 return FALSE; 3729 } 3730 3731 // 3732 // Calculate MBR checksum. 3733 // 3734 3735 *Checksum = 0; 3736 3737 for (i = 0; i < 128; i++) { 3738 *Checksum += mbr[i]; 3739 } 3740 3741 *Checksum = ~*Checksum + 1; 3742 3743 ExFreePool(mbr); 3744 return TRUE; 3745 } 3746 3747 3748 BOOLEAN 3749 NTAPI 3750 EnumerateBusKey( 3751 IN PDEVICE_EXTENSION DeviceExtension, 3752 HANDLE BusKey, 3753 PULONG DiskNumber 3754 ) 3755 3756 /*++ 3757 3758 Routine Description: 3759 3760 The routine queries the registry to determine if this disk is visible to 3761 the BIOS. If the disk is visible to the BIOS, then the geometry information 3762 is updated. 3763 3764 Arguments: 3765 3766 DeviceExtension - Supplies a pointer to the device information for disk. 3767 Signature - Unique identifier recorded in MBR. 3768 BusKey - Handle of bus key. 3769 DiskNumber - Returns ordinal of disk as BIOS sees it. 3770 3771 Return Value: 3772 3773 TRUE is disk signature matched. 3774 3775 --*/ 3776 { 3777 PDISK_DATA diskData = (PDISK_DATA)(DeviceExtension + 1); 3778 BOOLEAN diskFound = FALSE; 3779 OBJECT_ATTRIBUTES objectAttributes; 3780 UNICODE_STRING unicodeString; 3781 UNICODE_STRING identifier; 3782 ULONG busNumber; 3783 ULONG adapterNumber; 3784 ULONG diskNumber; 3785 HANDLE adapterKey; 3786 HANDLE spareKey; 3787 HANDLE diskKey; 3788 HANDLE targetKey; 3789 NTSTATUS status; 3790 STRING string; 3791 STRING anotherString; 3792 ULONG length; 3793 UCHAR buffer[20]; 3794 PKEY_VALUE_FULL_INFORMATION keyData; 3795 3796 PAGED_CODE(); 3797 3798 for (busNumber = 0; ; busNumber++) { 3799 3800 // 3801 // Open controller name key. 3802 // 3803 3804 sprintf((PCHAR)buffer, 3805 "%lu", 3806 busNumber); 3807 3808 RtlInitString(&string, 3809 (PCSZ)buffer); 3810 3811 status = RtlAnsiStringToUnicodeString(&unicodeString, 3812 &string, 3813 TRUE); 3814 3815 if (!NT_SUCCESS(status)){ 3816 break; 3817 } 3818 3819 InitializeObjectAttributes(&objectAttributes, 3820 &unicodeString, 3821 OBJ_CASE_INSENSITIVE, 3822 BusKey, 3823 (PSECURITY_DESCRIPTOR)NULL); 3824 3825 status = ZwOpenKey(&spareKey, 3826 KEY_READ, 3827 &objectAttributes); 3828 3829 RtlFreeUnicodeString(&unicodeString); 3830 3831 if (!NT_SUCCESS(status)) { 3832 break; 3833 } 3834 3835 // 3836 // Open up controller ordinal key. 3837 // 3838 3839 RtlInitUnicodeString(&unicodeString, L"DiskController"); 3840 InitializeObjectAttributes(&objectAttributes, 3841 &unicodeString, 3842 OBJ_CASE_INSENSITIVE, 3843 spareKey, 3844 (PSECURITY_DESCRIPTOR)NULL); 3845 3846 status = ZwOpenKey(&adapterKey, 3847 KEY_READ, 3848 &objectAttributes); 3849 3850 // 3851 // This could fail even with additional adapters of this type 3852 // to search. 3853 // 3854 3855 if (!NT_SUCCESS(status)) { 3856 continue; 3857 } 3858 3859 for (adapterNumber = 0; ; adapterNumber++) { 3860 3861 // 3862 // Open disk key. 3863 // 3864 3865 sprintf((PCHAR)buffer, 3866 "%lu\\DiskPeripheral", 3867 adapterNumber); 3868 3869 RtlInitString(&string, 3870 (PCSZ)buffer); 3871 3872 status = RtlAnsiStringToUnicodeString(&unicodeString, 3873 &string, 3874 TRUE); 3875 3876 if (!NT_SUCCESS(status)){ 3877 break; 3878 } 3879 3880 InitializeObjectAttributes(&objectAttributes, 3881 &unicodeString, 3882 OBJ_CASE_INSENSITIVE, 3883 adapterKey, 3884 (PSECURITY_DESCRIPTOR)NULL); 3885 3886 status = ZwOpenKey(&diskKey, 3887 KEY_READ, 3888 &objectAttributes); 3889 3890 RtlFreeUnicodeString(&unicodeString); 3891 3892 if (!NT_SUCCESS(status)) { 3893 break; 3894 } 3895 3896 for (diskNumber = 0; ; diskNumber++) { 3897 3898 sprintf((PCHAR)buffer, 3899 "%lu", 3900 diskNumber); 3901 3902 RtlInitString(&string, 3903 (PCSZ)buffer); 3904 3905 status = RtlAnsiStringToUnicodeString(&unicodeString, 3906 &string, 3907 TRUE); 3908 3909 if (!NT_SUCCESS(status)){ 3910 break; 3911 } 3912 3913 InitializeObjectAttributes(&objectAttributes, 3914 &unicodeString, 3915 OBJ_CASE_INSENSITIVE, 3916 diskKey, 3917 (PSECURITY_DESCRIPTOR)NULL); 3918 3919 status = ZwOpenKey(&targetKey, 3920 KEY_READ, 3921 &objectAttributes); 3922 3923 RtlFreeUnicodeString(&unicodeString); 3924 3925 if (!NT_SUCCESS(status)) { 3926 break; 3927 } 3928 3929 // 3930 // Allocate buffer for registry query. 3931 // 3932 3933 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE); 3934 3935 if (keyData == NULL) { 3936 ZwClose(targetKey); 3937 continue; 3938 } 3939 3940 // 3941 // Get disk peripheral identifier. 3942 // 3943 3944 RtlInitUnicodeString(&unicodeString, L"Identifier"); 3945 status = ZwQueryValueKey(targetKey, 3946 &unicodeString, 3947 KeyValueFullInformation, 3948 keyData, 3949 VALUE_BUFFER_SIZE, 3950 &length); 3951 3952 ZwClose(targetKey); 3953 3954 if (!NT_SUCCESS(status)) { 3955 ExFreePool(keyData); 3956 continue; 3957 } 3958 3959 if (keyData->DataLength < 9*sizeof(WCHAR)) { 3960 // 3961 // the data is too short to use (we subtract 9 chars in normal path) 3962 // 3963 DebugPrint((1, "EnumerateBusKey: Saved data was invalid, " 3964 "not enough data in registry!\n")); 3965 ExFreePool(keyData); 3966 continue; 3967 } 3968 3969 // 3970 // Complete unicode string. 3971 // 3972 3973 identifier.Buffer = 3974 (PWSTR)((PUCHAR)keyData + keyData->DataOffset); 3975 identifier.Length = (USHORT)keyData->DataLength; 3976 identifier.MaximumLength = (USHORT)keyData->DataLength; 3977 3978 // 3979 // Convert unicode identifier to ansi string. 3980 // 3981 3982 status = 3983 RtlUnicodeStringToAnsiString(&anotherString, 3984 &identifier, 3985 TRUE); 3986 3987 if (!NT_SUCCESS(status)) { 3988 ExFreePool(keyData); 3989 continue; 3990 } 3991 3992 // 3993 // If checksum is zero, then the MBR is valid and 3994 // the signature is meaningful. 3995 // 3996 3997 if (diskData->MbrCheckSum) { 3998 3999 // 4000 // Convert checksum to ansi string. 4001 // 4002 4003 sprintf((PCHAR)buffer, "%08lx", diskData->MbrCheckSum); 4004 4005 } else { 4006 4007 // 4008 // Convert signature to ansi string. 4009 // 4010 4011 sprintf((PCHAR)buffer, "%08lx", diskData->Signature); 4012 4013 // 4014 // Make string point at signature. Can't use scan 4015 // functions because they are not exported for driver use. 4016 // 4017 4018 anotherString.Buffer+=9; 4019 } 4020 4021 // 4022 // Convert to ansi string. 4023 // 4024 4025 RtlInitString(&string, 4026 (PCSZ)buffer); 4027 4028 4029 // 4030 // Make string lengths equal. 4031 // 4032 4033 anotherString.Length = string.Length; 4034 4035 // 4036 // Check if strings match. 4037 // 4038 4039 if (RtlCompareString(&string, 4040 &anotherString, 4041 TRUE) == 0) { 4042 4043 diskFound = TRUE; 4044 *DiskNumber = diskNumber; 4045 } 4046 4047 ExFreePool(keyData); 4048 4049 // 4050 // Readjust identifier string if necessary. 4051 // 4052 4053 if (!diskData->MbrCheckSum) { 4054 anotherString.Buffer-=9; 4055 } 4056 4057 RtlFreeAnsiString(&anotherString); 4058 4059 if (diskFound) { 4060 break; 4061 } 4062 } 4063 4064 ZwClose(diskKey); 4065 } 4066 4067 ZwClose(adapterKey); 4068 } 4069 4070 ZwClose(BusKey); 4071 return diskFound; 4072 4073 } // end EnumerateBusKey() 4074 4075 4076 VOID 4077 NTAPI 4078 UpdateGeometry( 4079 IN PDEVICE_EXTENSION DeviceExtension 4080 ) 4081 /*++ 4082 4083 Routine Description: 4084 4085 The routine queries the registry to determine if this disk is visible to 4086 the BIOS. If the disk is visible to the BIOS, then the geometry information 4087 is updated. 4088 4089 Arguments: 4090 4091 DeviceExtension - Supplies a pointer to the device information for disk. 4092 4093 Return Value: 4094 4095 None. 4096 4097 --*/ 4098 4099 { 4100 OBJECT_ATTRIBUTES objectAttributes; 4101 UNICODE_STRING unicodeString; 4102 NTSTATUS status; 4103 HANDLE hardwareKey; 4104 HANDLE busKey; 4105 PCM_INT13_DRIVE_PARAMETER driveParameters; 4106 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor; 4107 PKEY_VALUE_FULL_INFORMATION keyData; 4108 ULONG diskNumber; 4109 PUCHAR buffer; 4110 ULONG length; 4111 ULONG numberOfDrives; 4112 ULONG cylinders; 4113 ULONG sectors; 4114 ULONG sectorsPerTrack; 4115 ULONG tracksPerCylinder; 4116 BOOLEAN foundEZHooker; 4117 PVOID tmpPtr; 4118 4119 PAGED_CODE(); 4120 4121 // 4122 // Initialize the object for the key. 4123 // 4124 4125 InitializeObjectAttributes(&objectAttributes, 4126 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase, 4127 OBJ_CASE_INSENSITIVE, 4128 NULL, 4129 (PSECURITY_DESCRIPTOR) NULL); 4130 4131 // 4132 // Create the hardware base key. 4133 // 4134 4135 status = ZwOpenKey(&hardwareKey, 4136 KEY_READ, 4137 &objectAttributes); 4138 4139 4140 if (!NT_SUCCESS(status)) { 4141 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension->DeviceObject->DriverObject->HardwareDatabase)); 4142 return; 4143 } 4144 4145 4146 // 4147 // Get disk BIOS geometry information. 4148 // 4149 4150 RtlInitUnicodeString(&unicodeString, L"Configuration Data"); 4151 4152 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE); 4153 4154 if (keyData == NULL) { 4155 ZwClose(hardwareKey); 4156 return; 4157 } 4158 4159 status = ZwQueryValueKey(hardwareKey, 4160 &unicodeString, 4161 KeyValueFullInformation, 4162 keyData, 4163 VALUE_BUFFER_SIZE, 4164 &length); 4165 4166 if (!NT_SUCCESS(status)) { 4167 DebugPrint((1, 4168 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n", 4169 status)); 4170 ZwClose(hardwareKey); 4171 ExFreePool(keyData); 4172 return; 4173 } 4174 4175 // 4176 // Open EISA bus key. 4177 // 4178 4179 RtlInitUnicodeString(&unicodeString, L"EisaAdapter"); 4180 4181 InitializeObjectAttributes(&objectAttributes, 4182 &unicodeString, 4183 OBJ_CASE_INSENSITIVE, 4184 hardwareKey, 4185 (PSECURITY_DESCRIPTOR)NULL); 4186 4187 status = ZwOpenKey(&busKey, 4188 KEY_READ, 4189 &objectAttributes); 4190 4191 if (!NT_SUCCESS(status)) { 4192 goto openMultiKey; 4193 } 4194 4195 DebugPrint((3, 4196 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n")); 4197 if (EnumerateBusKey(DeviceExtension, 4198 busKey, 4199 &diskNumber)) { 4200 4201 ZwClose(hardwareKey); 4202 goto diskMatched; 4203 } 4204 4205 openMultiKey: 4206 4207 // 4208 // Open Multifunction bus key. 4209 // 4210 4211 RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter"); 4212 4213 InitializeObjectAttributes(&objectAttributes, 4214 &unicodeString, 4215 OBJ_CASE_INSENSITIVE, 4216 hardwareKey, 4217 (PSECURITY_DESCRIPTOR)NULL); 4218 4219 status = ZwOpenKey(&busKey, 4220 KEY_READ, 4221 &objectAttributes); 4222 4223 ZwClose(hardwareKey); 4224 if (NT_SUCCESS(status)) { 4225 DebugPrint((3, 4226 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n")); 4227 if (EnumerateBusKey(DeviceExtension, 4228 busKey, 4229 &diskNumber)) { 4230 4231 goto diskMatched; 4232 } 4233 } 4234 4235 ExFreePool(keyData); 4236 return; 4237 4238 diskMatched: 4239 4240 resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)keyData + 4241 keyData->DataOffset); 4242 4243 // 4244 // Check that the data is long enough to hold a full resource descriptor, 4245 // and that the last resource list is device-specific and long enough. 4246 // 4247 4248 if (keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR) || 4249 resourceDescriptor->PartialResourceList.Count == 0 || 4250 resourceDescriptor->PartialResourceList.PartialDescriptors[0].Type != 4251 CmResourceTypeDeviceSpecific || 4252 resourceDescriptor->PartialResourceList.PartialDescriptors[0] 4253 .u.DeviceSpecificData.DataSize < sizeof(ULONG)) { 4254 4255 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n")); 4256 ExFreePool(keyData); 4257 return; 4258 } 4259 4260 length = 4261 resourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize; 4262 4263 // 4264 // Point to the BIOS data. The BIOS data is located after the first 4265 // partial Resource list which should be device specific data. 4266 // 4267 4268 buffer = (PUCHAR) keyData + keyData->DataOffset + 4269 sizeof(CM_FULL_RESOURCE_DESCRIPTOR); 4270 4271 4272 numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER); 4273 4274 // 4275 // Use the defaults if the drive number is greater than the 4276 // number of drives detected by the BIOS. 4277 // 4278 4279 if (numberOfDrives <= diskNumber) { 4280 ExFreePool(keyData); 4281 return; 4282 } 4283 4284 // 4285 // Point to the array of drive parameters. 4286 // 4287 4288 driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer + diskNumber; 4289 cylinders = driveParameters->MaxCylinders + 1; 4290 sectorsPerTrack = driveParameters->SectorsPerTrack; 4291 tracksPerCylinder = driveParameters->MaxHeads +1; 4292 4293 // 4294 // Calculate the actual number of sectors. 4295 // 4296 4297 sectors = (ULONG)(DeviceExtension->PartitionLength.QuadPart >> 4298 DeviceExtension->SectorShift); 4299 4300 #if DBG 4301 if (sectors >= cylinders * tracksPerCylinder * sectorsPerTrack) { 4302 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n" 4303 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n", 4304 sectors, cylinders, tracksPerCylinder, sectorsPerTrack)); 4305 } 4306 #endif 4307 4308 // 4309 // Since the BIOS may not report the full drive, recalculate the drive 4310 // size based on the volume size and the BIOS values for tracks per 4311 // cylinder and sectors per track.. 4312 // 4313 4314 length = tracksPerCylinder * sectorsPerTrack; 4315 4316 if (length == 0) { 4317 4318 // 4319 // The BIOS information is bogus. 4320 // 4321 4322 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n")); 4323 ExFreePool(keyData); 4324 return; 4325 } 4326 4327 cylinders = sectors / length; 4328 4329 // 4330 // Update the actual geometry information. 4331 // 4332 4333 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack = sectorsPerTrack; 4334 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder; 4335 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)cylinders; 4336 DeviceExtension->DiskGeometry->DiskSize.QuadPart = (LONGLONG)cylinders * tracksPerCylinder * sectorsPerTrack * 4337 DeviceExtension->DiskGeometry->Geometry.BytesPerSector; 4338 4339 DebugPrint((3, 4340 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n", 4341 sectorsPerTrack, 4342 tracksPerCylinder, 4343 cylinders)); 4344 4345 ExFreePool(keyData); 4346 4347 foundEZHooker = FALSE; 4348 4349 if (!DeviceExtension->DMActive) { 4350 4351 HalExamineMBR(DeviceExtension->DeviceObject, 4352 DeviceExtension->DiskGeometry->Geometry.BytesPerSector, 4353 (ULONG)0x55, 4354 &tmpPtr 4355 ); 4356 4357 if (tmpPtr) { 4358 4359 ExFreePool(tmpPtr); 4360 foundEZHooker = TRUE; 4361 4362 } 4363 4364 } 4365 4366 if (DeviceExtension->DMActive || foundEZHooker) { 4367 4368 while (cylinders > 1024) { 4369 4370 tracksPerCylinder = tracksPerCylinder*2; 4371 cylinders = cylinders/2; 4372 4373 } 4374 4375 // 4376 // int 13 values are always 1 less. 4377 // 4378 4379 tracksPerCylinder -= 1; 4380 cylinders -= 1; 4381 4382 // 4383 // DM reserves the CE cylinder 4384 // 4385 4386 cylinders -= 1; 4387 4388 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = cylinders + 1; 4389 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder + 1; 4390 4391 DeviceExtension->PartitionLength.QuadPart = 4392 DeviceExtension->DiskGeometry->DiskSize.QuadPart = 4393 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart * 4394 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack * 4395 DeviceExtension->DiskGeometry->Geometry.BytesPerSector * 4396 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder; 4397 4398 if (DeviceExtension->DMActive) { 4399 4400 DeviceExtension->DMByteSkew = DeviceExtension->DMSkew * DeviceExtension->DiskGeometry->Geometry.BytesPerSector; 4401 4402 } 4403 4404 } else { 4405 4406 DeviceExtension->DMByteSkew = 0; 4407 4408 } 4409 4410 return; 4411 4412 } // end UpdateGeometry() 4413 4414 4415 4416 NTSTATUS 4417 NTAPI 4418 UpdateRemovableGeometry ( 4419 IN PDEVICE_OBJECT DeviceObject, 4420 IN PIRP Irp 4421 ) 4422 4423 /*++ 4424 4425 Routine Description: 4426 4427 This routines updates the size and starting offset of the device. This is 4428 used when the media on the device may have changed thereby changing the 4429 size of the device. If this is the physical device then a 4430 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done. 4431 4432 Arguments: 4433 4434 DeviceObject - Supplies the device object whos size needs to be updated. 4435 4436 Irp - Supplies a reference where the status can be updated. 4437 4438 Return Value: 4439 4440 Returns the status of the operation. 4441 4442 --*/ 4443 { 4444 4445 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 4446 PDRIVE_LAYOUT_INFORMATION partitionList; 4447 NTSTATUS status; 4448 PDISK_DATA diskData; 4449 ULONG partitionNumber; 4450 4451 // 4452 // Determine if the size of the partition may have changed because 4453 // the media has changed. 4454 // 4455 4456 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) { 4457 4458 return(STATUS_SUCCESS); 4459 4460 } 4461 4462 // 4463 // If this request is for partition zero then do a read drive 4464 // capacity otherwise do a I/O read partition table. 4465 // 4466 4467 diskData = (PDISK_DATA) (deviceExtension + 1); 4468 4469 // 4470 // Read the drive capacity. If that fails, give up. 4471 // 4472 4473 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice); 4474 4475 if (!NT_SUCCESS(status)) { 4476 return(status); 4477 } 4478 4479 #ifdef __REACTOS__ 4480 // 4481 // HACK so that we can use NT5+ NTOS functions with this NT4 driver 4482 // for removable devices and avoid an infinite recursive loop between 4483 // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable(). 4484 // 4485 // Check whether the update-count is greater or equal than one 4486 // (and increase it) and if so, reset it and return success. 4487 if (diskData->UpdateRemovableGeometryCount++ >= 1) 4488 { 4489 diskData->UpdateRemovableGeometryCount = 0; 4490 return(STATUS_SUCCESS); 4491 } 4492 #endif 4493 4494 // 4495 // Read the partition table again. 4496 // 4497 4498 status = IoReadPartitionTable(deviceExtension->PhysicalDevice, 4499 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 4500 TRUE, 4501 &partitionList); 4502 4503 #ifdef __REACTOS__ 4504 // 4505 // HACK so that we can use NT5+ NTOS functions with this NT4 driver 4506 // for removable devices and avoid an infinite recursive loop between 4507 // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable(). 4508 // 4509 // Inconditionally reset the update-count. 4510 diskData->UpdateRemovableGeometryCount = 0; 4511 #endif 4512 4513 if (!NT_SUCCESS(status)) { 4514 4515 // 4516 // Fail the request. 4517 // 4518 4519 return(status); 4520 } 4521 4522 if (diskData->PartitionNumber != 0 && 4523 diskData->PartitionNumber <= partitionList->PartitionCount ) { 4524 4525 partitionNumber = diskData->PartitionNumber - 1; 4526 4527 // 4528 // Update the partition information for this partition. 4529 // 4530 4531 diskData->PartitionType = 4532 partitionList->PartitionEntry[partitionNumber].PartitionType; 4533 4534 diskData->BootIndicator = 4535 partitionList->PartitionEntry[partitionNumber].BootIndicator; 4536 4537 deviceExtension->StartingOffset = 4538 partitionList->PartitionEntry[partitionNumber].StartingOffset; 4539 4540 deviceExtension->PartitionLength = 4541 partitionList->PartitionEntry[partitionNumber].PartitionLength; 4542 4543 diskData->HiddenSectors = 4544 partitionList->PartitionEntry[partitionNumber].HiddenSectors; 4545 4546 deviceExtension->SectorShift = ((PDEVICE_EXTENSION) 4547 deviceExtension->PhysicalDevice->DeviceExtension)->SectorShift; 4548 4549 } else if (diskData->PartitionNumber != 0) { 4550 4551 // 4552 // The partition does not exist. Zero all the data. 4553 // 4554 4555 diskData->PartitionType = 0; 4556 diskData->BootIndicator = 0; 4557 diskData->HiddenSectors = 0; 4558 deviceExtension->StartingOffset.QuadPart = (LONGLONG)0; 4559 deviceExtension->PartitionLength.QuadPart = (LONGLONG)0; 4560 } 4561 4562 // 4563 // Free the partition list allocate by I/O read partition table. 4564 // 4565 4566 ExFreePool(partitionList); 4567 4568 4569 return(STATUS_SUCCESS); 4570 } 4571 4572 4573 VOID 4574 NTAPI 4575 ScsiDiskProcessError( 4576 PDEVICE_OBJECT DeviceObject, 4577 PSCSI_REQUEST_BLOCK Srb, 4578 NTSTATUS *Status, 4579 BOOLEAN *Retry 4580 ) 4581 /*++ 4582 4583 Routine Description: 4584 4585 This routine checks the type of error. If the error indicates an underrun 4586 then indicate the request should be retried. 4587 4588 Arguments: 4589 4590 DeviceObject - Supplies a pointer to the device object. 4591 4592 Srb - Supplies a pointer to the failing Srb. 4593 4594 Status - Status with which the IRP will be completed. 4595 4596 Retry - Indication of whether the request will be retried. 4597 4598 Return Value: 4599 4600 None. 4601 4602 --*/ 4603 4604 { 4605 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 4606 4607 if (*Status == STATUS_DATA_OVERRUN && 4608 ( Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_READ)) { 4609 4610 *Retry = TRUE; 4611 4612 // 4613 // Update the error count for the device. 4614 // 4615 4616 deviceExtension->ErrorCount++; 4617 } 4618 4619 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR && 4620 Srb->ScsiStatus == SCSISTAT_BUSY) { 4621 4622 // 4623 // The disk drive should never be busy this long. Reset the scsi bus 4624 // maybe this will clear the condition. 4625 // 4626 4627 ResetScsiBus(DeviceObject); 4628 4629 // 4630 // Update the error count for the device. 4631 // 4632 4633 deviceExtension->ErrorCount++; 4634 } 4635 } 4636 4637 VOID 4638 NTAPI 4639 ScanForSpecial( 4640 PDEVICE_OBJECT DeviceObject, 4641 PSCSI_INQUIRY_DATA LunInfo, 4642 PIO_SCSI_CAPABILITIES PortCapabilities 4643 ) 4644 4645 /*++ 4646 4647 Routine Description: 4648 4649 This function checks to see if an SCSI logical unit requires special 4650 flags to be set. 4651 4652 Arguments: 4653 4654 DeviceObject - Supplies the device object to be tested. 4655 4656 InquiryData - Supplies the inquiry data returned by the device of interest. 4657 4658 PortCapabilities - Supplies the capabilities of the device object. 4659 4660 Return Value: 4661 4662 None. 4663 4664 --*/ 4665 4666 { 4667 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 4668 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData; 4669 BAD_CONTROLLER_INFORMATION const *controller; 4670 ULONG j; 4671 4672 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) { 4673 4674 controller = &ScsiDiskBadControllers[j]; 4675 4676 if (strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) { 4677 continue; 4678 } 4679 4680 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller->InquiryString)); 4681 4682 // 4683 // Found a listed controller. Determine what must be done. 4684 // 4685 4686 if (controller->DisableTaggedQueuing) { 4687 4688 // 4689 // Disable tagged queuing. 4690 // 4691 4692 deviceExtension->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE; 4693 } 4694 4695 if (controller->DisableSynchronousTransfers) { 4696 4697 // 4698 // Disable synchronous data transfers. 4699 // 4700 4701 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 4702 4703 } 4704 4705 if (controller->DisableDisconnects) { 4706 4707 // 4708 // Disable disconnects. 4709 // 4710 4711 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT; 4712 4713 } 4714 4715 // 4716 // Found device so exit the loop and return. 4717 // 4718 4719 break; 4720 } 4721 4722 // 4723 // Set the StartUnit flag appropriately. 4724 // 4725 4726 if (DeviceObject->DeviceType == FILE_DEVICE_DISK) { 4727 deviceExtension->DeviceFlags |= DEV_SAFE_START_UNIT; 4728 4729 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 4730 if (_strnicmp((PCCHAR)InquiryData->VendorId, "iomega", strlen("iomega"))) { 4731 deviceExtension->DeviceFlags &= ~DEV_SAFE_START_UNIT; 4732 } 4733 } 4734 } 4735 4736 return; 4737 } 4738 4739 VOID 4740 NTAPI 4741 ResetScsiBus( 4742 IN PDEVICE_OBJECT DeviceObject 4743 ) 4744 4745 /*++ 4746 4747 Routine Description: 4748 4749 This command sends a reset bus command to the SCSI port driver. 4750 4751 Arguments: 4752 4753 DeviceObject - The device object for the logical unit with 4754 hardware problem. 4755 4756 Return Value: 4757 4758 None. 4759 4760 --*/ 4761 { 4762 PIO_STACK_LOCATION irpStack; 4763 PIRP irp; 4764 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 4765 PSCSI_REQUEST_BLOCK srb; 4766 PCOMPLETION_CONTEXT context; 4767 4768 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n")); 4769 4770 // 4771 // Allocate Srb from nonpaged pool. 4772 // 4773 4774 context = ExAllocatePool(NonPagedPoolMustSucceed, 4775 sizeof(COMPLETION_CONTEXT)); 4776 4777 // 4778 // Save the device object in the context for use by the completion 4779 // routine. 4780 // 4781 4782 context->DeviceObject = DeviceObject; 4783 srb = &context->Srb; 4784 4785 // 4786 // Zero out srb. 4787 // 4788 4789 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 4790 4791 // 4792 // Write length to SRB. 4793 // 4794 4795 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 4796 4797 // 4798 // Set up SCSI bus address. 4799 // 4800 4801 srb->PathId = deviceExtension->PathId; 4802 srb->TargetId = deviceExtension->TargetId; 4803 srb->Lun = deviceExtension->Lun; 4804 4805 srb->Function = SRB_FUNCTION_RESET_BUS; 4806 4807 // 4808 // Build the asynchronous request to be sent to the port driver. 4809 // Since this routine is called from a DPC the IRP should always be 4810 // available. 4811 // 4812 4813 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 4814 4815 IoSetCompletionRoutine(irp, 4816 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion, 4817 context, 4818 TRUE, 4819 TRUE, 4820 TRUE); 4821 4822 irpStack = IoGetNextIrpStackLocation(irp); 4823 4824 irpStack->MajorFunction = IRP_MJ_SCSI; 4825 4826 srb->OriginalRequest = irp; 4827 4828 // 4829 // Store the SRB address in next stack for port driver. 4830 // 4831 4832 irpStack->Parameters.Scsi.Srb = srb; 4833 4834 // 4835 // Call the port driver with the IRP. 4836 // 4837 4838 IoCallDriver(deviceExtension->PortDeviceObject, irp); 4839 4840 return; 4841 4842 } // end ResetScsiBus() 4843 4844 4845 VOID 4846 NTAPI 4847 UpdateDeviceObjects( 4848 IN PDEVICE_OBJECT PhysicalDisk, 4849 IN PIRP Irp 4850 ) 4851 4852 /*++ 4853 4854 Routine Description: 4855 4856 This routine creates, deletes and changes device objects when 4857 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates 4858 the drive layout information for the user. It is possible to 4859 call this routine even in the GET_LAYOUT case because RewritePartition 4860 will be false. 4861 4862 Arguments: 4863 4864 DeviceObject - Device object for physical disk. 4865 Irp - IO Request Packet (IRP). 4866 4867 Return Value: 4868 4869 None. 4870 4871 --*/ 4872 { 4873 PDEVICE_EXTENSION physicalExtension = PhysicalDisk->DeviceExtension; 4874 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer; 4875 ULONG partition; 4876 ULONG partitionNumber; 4877 ULONG partitionCount; 4878 ULONG lastPartition; 4879 ULONG partitionOrdinal; 4880 PPARTITION_INFORMATION partitionEntry; 4881 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH]; 4882 STRING ntNameString; 4883 UNICODE_STRING ntUnicodeString; 4884 PDEVICE_OBJECT deviceObject; 4885 PDEVICE_EXTENSION deviceExtension; 4886 PDISK_DATA diskData; 4887 NTSTATUS status; 4888 ULONG numberListElements; 4889 BOOLEAN found; 4890 4891 partitionCount = ((partitionList->PartitionCount + 3) / 4) * 4; 4892 4893 // 4894 // Zero all of the partition numbers. 4895 // 4896 4897 for (partition = 0; partition < partitionCount; partition++) { 4898 partitionEntry = &partitionList->PartitionEntry[partition]; 4899 partitionEntry->PartitionNumber = 0; 4900 } 4901 4902 // 4903 // Walk through chain of partitions for this disk to determine 4904 // which existing partitions have no match. 4905 // 4906 4907 deviceExtension = physicalExtension; 4908 diskData = (PDISK_DATA)(deviceExtension + 1); 4909 lastPartition = 0; 4910 4911 do { 4912 4913 deviceExtension = diskData->NextPartition; 4914 4915 // 4916 // Check if this is the last partition in the chain. 4917 // 4918 4919 if (!deviceExtension) { 4920 break; 4921 } 4922 4923 // 4924 // Get the partition device extension from disk data. 4925 // 4926 4927 diskData = (PDISK_DATA)(deviceExtension + 1); 4928 4929 // 4930 // Check for highest partition number this far. 4931 // 4932 4933 if (diskData->PartitionNumber > lastPartition) { 4934 lastPartition = diskData->PartitionNumber; 4935 } 4936 4937 // 4938 // Check if this partition is not currently being used. 4939 // 4940 4941 if (!deviceExtension->PartitionLength.QuadPart) { 4942 continue; 4943 } 4944 4945 // 4946 // Loop through partition information to look for match. 4947 // 4948 4949 found = FALSE; 4950 partitionOrdinal = 0; 4951 4952 for (partition = 0; partition < partitionCount; partition++) { 4953 4954 // 4955 // Get partition descriptor. 4956 // 4957 4958 partitionEntry = &partitionList->PartitionEntry[partition]; 4959 4960 // 4961 // Check if empty, or describes extended partition or hasn't changed. 4962 // 4963 4964 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED || 4965 IsContainerPartition(partitionEntry->PartitionType)) { 4966 continue; 4967 } 4968 4969 // 4970 // Advance partition ordinal. 4971 // 4972 4973 partitionOrdinal++; 4974 4975 // 4976 // Check if new partition starts where this partition starts. 4977 // 4978 4979 if (partitionEntry->StartingOffset.QuadPart != 4980 deviceExtension->StartingOffset.QuadPart) { 4981 continue; 4982 } 4983 4984 // 4985 // Check if partition length is the same. 4986 // 4987 4988 if (partitionEntry->PartitionLength.QuadPart == 4989 deviceExtension->PartitionLength.QuadPart) { 4990 4991 DebugPrint((3, 4992 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n", 4993 physicalExtension->DeviceNumber, 4994 diskData->PartitionNumber)); 4995 4996 // 4997 // Indicate match is found and set partition number 4998 // in user buffer. 4999 // 5000 5001 found = TRUE; 5002 partitionEntry->PartitionNumber = diskData->PartitionNumber; 5003 break; 5004 } 5005 } 5006 5007 if (found) { 5008 5009 // 5010 // A match is found. 5011 // 5012 5013 diskData = (PDISK_DATA)(deviceExtension + 1); 5014 5015 // 5016 // If this partition is marked for update then update partition type. 5017 // 5018 5019 if (partitionEntry->RewritePartition) { 5020 diskData->PartitionType = partitionEntry->PartitionType; 5021 } 5022 5023 // 5024 // Update partitional ordinal for calls to HAL routine 5025 // IoSetPartitionInformation. 5026 // 5027 5028 diskData->PartitionOrdinal = partitionOrdinal; 5029 5030 DebugPrint((1, 5031 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n", 5032 physicalExtension->DeviceNumber, 5033 diskData->PartitionOrdinal, 5034 diskData->PartitionNumber)); 5035 5036 } else { 5037 5038 // 5039 // no match was found, indicate this partition is gone. 5040 // 5041 5042 DebugPrint((1, 5043 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n", 5044 physicalExtension->DeviceNumber, 5045 diskData->PartitionNumber)); 5046 5047 deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0; 5048 } 5049 5050 } while (TRUE); 5051 5052 // 5053 // Walk through partition loop to find new partitions and set up 5054 // device extensions to describe them. In some cases new device 5055 // objects will be created. 5056 // 5057 5058 partitionOrdinal = 0; 5059 5060 for (partition = 0; 5061 partition < partitionCount; 5062 partition++) { 5063 5064 // 5065 // Get partition descriptor. 5066 // 5067 5068 partitionEntry = &partitionList->PartitionEntry[partition]; 5069 5070 // 5071 // Check if empty, or describes an extended partition. 5072 // 5073 5074 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED || 5075 IsContainerPartition(partitionEntry->PartitionType)) { 5076 continue; 5077 } 5078 5079 // 5080 // Keep track of position on the disk for calls to IoSetPartitionInformation. 5081 // 5082 5083 partitionOrdinal++; 5084 5085 // 5086 // Check if this entry should be rewritten. 5087 // 5088 5089 if (!partitionEntry->RewritePartition) { 5090 continue; 5091 } 5092 5093 if (partitionEntry->PartitionNumber) { 5094 5095 // 5096 // Partition is an exact match with an existing partition, but is 5097 // being written anyway. 5098 // 5099 5100 continue; 5101 } 5102 5103 // 5104 // Check first if existing device object is available by 5105 // walking partition extension list. 5106 // 5107 5108 partitionNumber = 0; 5109 deviceExtension = physicalExtension; 5110 diskData = (PDISK_DATA)(deviceExtension + 1); 5111 5112 do { 5113 5114 // 5115 // Get next partition device extension from disk data. 5116 // 5117 5118 deviceExtension = diskData->NextPartition; 5119 5120 if (!deviceExtension) { 5121 break; 5122 } 5123 5124 diskData = (PDISK_DATA)(deviceExtension + 1); 5125 5126 // 5127 // A device object is free if the partition length is set to zero. 5128 // 5129 5130 if (!deviceExtension->PartitionLength.QuadPart) { 5131 partitionNumber = diskData->PartitionNumber; 5132 break; 5133 } 5134 5135 } while (TRUE); 5136 5137 // 5138 // If partition number is still zero then a new device object 5139 // must be created. 5140 // 5141 5142 if (partitionNumber == 0) { 5143 5144 lastPartition++; 5145 partitionNumber = lastPartition; 5146 5147 // 5148 // Get or create partition object and set up partition parameters. 5149 // 5150 5151 sprintf(ntNameBuffer, 5152 "\\Device\\Harddisk%lu\\Partition%lu", 5153 physicalExtension->DeviceNumber, 5154 partitionNumber); 5155 5156 RtlInitString(&ntNameString, 5157 ntNameBuffer); 5158 5159 status = RtlAnsiStringToUnicodeString(&ntUnicodeString, 5160 &ntNameString, 5161 TRUE); 5162 5163 if (!NT_SUCCESS(status)) { 5164 continue; 5165 } 5166 5167 DebugPrint((3, 5168 "UpdateDeviceObjects: Create device object %s\n", 5169 ntNameBuffer)); 5170 5171 // 5172 // This is a new name. Create the device object to represent it. 5173 // 5174 5175 status = IoCreateDevice(PhysicalDisk->DriverObject, 5176 DEVICE_EXTENSION_SIZE, 5177 &ntUnicodeString, 5178 FILE_DEVICE_DISK, 5179 0, 5180 FALSE, 5181 &deviceObject); 5182 5183 if (!NT_SUCCESS(status)) { 5184 DebugPrint((1, 5185 "UpdateDeviceObjects: Can't create device %s\n", 5186 ntNameBuffer)); 5187 RtlFreeUnicodeString(&ntUnicodeString); 5188 continue; 5189 } 5190 5191 // 5192 // Set up device object fields. 5193 // 5194 5195 deviceObject->Flags |= DO_DIRECT_IO; 5196 deviceObject->StackSize = PhysicalDisk->StackSize; 5197 5198 // 5199 // Set up device extension fields. 5200 // 5201 5202 deviceExtension = deviceObject->DeviceExtension; 5203 5204 // 5205 // Copy physical disk extension to partition extension. 5206 // 5207 5208 RtlMoveMemory(deviceExtension, 5209 physicalExtension, 5210 sizeof(DEVICE_EXTENSION)); 5211 5212 // 5213 // Initialize the new S-List. 5214 // 5215 5216 if (deviceExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) { 5217 numberListElements = 30; 5218 } else { 5219 numberListElements = 8; 5220 } 5221 5222 // 5223 // Build the lookaside list for srb's for this partition based on 5224 // whether the adapter and disk can do tagged queueing. 5225 // 5226 5227 ScsiClassInitializeSrbLookasideList(deviceExtension, 5228 numberListElements); 5229 5230 // 5231 // Allocate spinlock for zoning for split-request completion. 5232 // 5233 5234 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock); 5235 5236 // 5237 // Write back partition number used in creating object name. 5238 // 5239 5240 partitionEntry->PartitionNumber = partitionNumber; 5241 5242 // 5243 // Clear flags initializing bit. 5244 // 5245 5246 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 5247 5248 // 5249 // Point back at device object. 5250 // 5251 5252 deviceExtension->DeviceObject = deviceObject; 5253 5254 RtlFreeUnicodeString(&ntUnicodeString); 5255 5256 // 5257 // Link to end of partition chain using previous disk data. 5258 // 5259 5260 diskData->NextPartition = deviceExtension; 5261 5262 // 5263 // Get new disk data and zero next partition pointer. 5264 // 5265 5266 diskData = (PDISK_DATA)(deviceExtension + 1); 5267 diskData->NextPartition = NULL; 5268 5269 } else { 5270 5271 // 5272 // Set pointer to disk data area that follows device extension. 5273 // 5274 5275 diskData = (PDISK_DATA)(deviceExtension + 1); 5276 5277 DebugPrint((1, 5278 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n", 5279 physicalExtension->DeviceNumber, 5280 partitionNumber)); 5281 } 5282 5283 // 5284 // Update partition information in partition device extension. 5285 // 5286 5287 diskData->PartitionNumber = partitionNumber; 5288 diskData->PartitionType = partitionEntry->PartitionType; 5289 diskData->BootIndicator = partitionEntry->BootIndicator; 5290 deviceExtension->StartingOffset = partitionEntry->StartingOffset; 5291 deviceExtension->PartitionLength = partitionEntry->PartitionLength; 5292 diskData->HiddenSectors = partitionEntry->HiddenSectors; 5293 diskData->PartitionOrdinal = partitionOrdinal; 5294 5295 DebugPrint((1, 5296 "UpdateDeviceObjects: Ordinal %d is partition %d\n", 5297 diskData->PartitionOrdinal, 5298 diskData->PartitionNumber)); 5299 5300 // 5301 // Update partition number passed in to indicate the 5302 // device name for this partition. 5303 // 5304 5305 partitionEntry->PartitionNumber = partitionNumber; 5306 } 5307 5308 } // end UpdateDeviceObjects() 5309 5310