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