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