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 break; 2239 } 2240 2241 // 2242 // Update the geometry in case it has changed. 2243 // 2244 2245 status = UpdateRemovableGeometry (DeviceObject, Irp); 2246 2247 if (!NT_SUCCESS(status)) { 2248 2249 // 2250 // Note the drive is not ready. 2251 // 2252 2253 diskData->DriveNotReady = TRUE; 2254 break; 2255 } 2256 2257 // 2258 // Note the drive is now ready. 2259 // 2260 2261 diskData->DriveNotReady = FALSE; 2262 2263 // 2264 // Handle the case were we query the whole disk 2265 // 2266 2267 if (diskData->PartitionNumber == 0) { 2268 2269 PPARTITION_INFORMATION outputBuffer; 2270 2271 outputBuffer = 2272 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 2273 2274 outputBuffer->PartitionType = PARTITION_ENTRY_UNUSED; 2275 outputBuffer->StartingOffset = deviceExtension->StartingOffset; 2276 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart; 2277 outputBuffer->HiddenSectors = 0; 2278 outputBuffer->PartitionNumber = diskData->PartitionNumber; 2279 outputBuffer->BootIndicator = FALSE; 2280 outputBuffer->RewritePartition = FALSE; 2281 outputBuffer->RecognizedPartition = FALSE; 2282 2283 status = STATUS_SUCCESS; 2284 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION); 2285 2286 } else { 2287 2288 PPARTITION_INFORMATION outputBuffer; 2289 2290 // 2291 // We query a single partition here 2292 // FIXME: this can only work for MBR-based disks, check for this! 2293 // 2294 2295 outputBuffer = 2296 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 2297 2298 outputBuffer->PartitionType = diskData->PartitionType; 2299 outputBuffer->StartingOffset = deviceExtension->StartingOffset; 2300 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart; 2301 outputBuffer->HiddenSectors = diskData->HiddenSectors; 2302 outputBuffer->PartitionNumber = diskData->PartitionNumber; 2303 outputBuffer->BootIndicator = diskData->BootIndicator; 2304 outputBuffer->RewritePartition = FALSE; 2305 outputBuffer->RecognizedPartition = 2306 IsRecognizedPartition(diskData->PartitionType); 2307 2308 status = STATUS_SUCCESS; 2309 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION); 2310 } 2311 2312 break; 2313 2314 case IOCTL_DISK_GET_PARTITION_INFO_EX: 2315 2316 // 2317 // Return the information about the partition specified by the device 2318 // object. Note that no information is ever returned about the size 2319 // or partition type of the physical disk, as this doesn't make any 2320 // sense. 2321 // 2322 2323 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 2324 sizeof(PARTITION_INFORMATION_EX)) { 2325 2326 status = STATUS_INFO_LENGTH_MISMATCH; 2327 2328 } 2329 #if 0 // HACK: ReactOS partition numbers must be wrong 2330 else if (diskData->PartitionNumber == 0) { 2331 2332 // 2333 // Partition zero is not a partition so this is not a 2334 // reasonable request. 2335 // 2336 2337 status = STATUS_INVALID_DEVICE_REQUEST; 2338 2339 } 2340 #endif 2341 else { 2342 2343 PPARTITION_INFORMATION_EX outputBuffer; 2344 2345 if (diskData->PartitionNumber == 0) { 2346 DPRINT1("HACK: Handling partition 0 request!\n"); 2347 //ASSERT(FALSE); 2348 } 2349 2350 // 2351 // Update the geometry in case it has changed. 2352 // 2353 2354 status = UpdateRemovableGeometry (DeviceObject, Irp); 2355 2356 if (!NT_SUCCESS(status)) { 2357 2358 // 2359 // Note the drive is not ready. 2360 // 2361 2362 diskData->DriveNotReady = TRUE; 2363 break; 2364 } 2365 2366 // 2367 // Note the drive is now ready. 2368 // 2369 2370 diskData->DriveNotReady = FALSE; 2371 2372 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) { 2373 2374 status = STATUS_INVALID_DEVICE_REQUEST; 2375 break; 2376 } 2377 2378 outputBuffer = 2379 (PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer; 2380 2381 // 2382 // FIXME: hack of the year, assume that partition is MBR 2383 // Thing that can obviously be wrong... 2384 // 2385 2386 outputBuffer->PartitionStyle = PARTITION_STYLE_MBR; 2387 outputBuffer->Mbr.PartitionType = diskData->PartitionType; 2388 outputBuffer->StartingOffset = deviceExtension->StartingOffset; 2389 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart; 2390 outputBuffer->Mbr.HiddenSectors = diskData->HiddenSectors; 2391 outputBuffer->PartitionNumber = diskData->PartitionNumber; 2392 outputBuffer->Mbr.BootIndicator = diskData->BootIndicator; 2393 outputBuffer->RewritePartition = FALSE; 2394 outputBuffer->Mbr.RecognizedPartition = 2395 IsRecognizedPartition(diskData->PartitionType); 2396 2397 status = STATUS_SUCCESS; 2398 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX); 2399 } 2400 2401 break; 2402 2403 case IOCTL_DISK_SET_PARTITION_INFO: 2404 2405 if (diskData->PartitionNumber == 0) { 2406 2407 status = STATUS_UNSUCCESSFUL; 2408 2409 } else { 2410 2411 PSET_PARTITION_INFORMATION inputBuffer = 2412 (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 2413 2414 // 2415 // Validate buffer length. 2416 // 2417 2418 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2419 sizeof(SET_PARTITION_INFORMATION)) { 2420 2421 status = STATUS_INFO_LENGTH_MISMATCH; 2422 break; 2423 } 2424 2425 // 2426 // The HAL routines IoGet- and IoSetPartitionInformation were 2427 // developed before support of dynamic partitioning and therefore 2428 // don't distinguish between partition ordinal (that is the order 2429 // of a partition on a disk) and the partition number. (The 2430 // partition number is assigned to a partition to identify it to 2431 // the system.) Use partition ordinals for these legacy calls. 2432 // 2433 2434 status = IoSetPartitionInformation( 2435 deviceExtension->PhysicalDevice, 2436 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 2437 diskData->PartitionOrdinal, 2438 inputBuffer->PartitionType); 2439 2440 if (NT_SUCCESS(status)) { 2441 2442 diskData->PartitionType = inputBuffer->PartitionType; 2443 } 2444 } 2445 2446 break; 2447 2448 case IOCTL_DISK_GET_DRIVE_LAYOUT: 2449 2450 // 2451 // Return the partition layout for the physical drive. Note that 2452 // the layout is returned for the actual physical drive, regardless 2453 // of which partition was specified for the request. 2454 // 2455 2456 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 2457 sizeof(DRIVE_LAYOUT_INFORMATION)) { 2458 status = STATUS_INFO_LENGTH_MISMATCH; 2459 2460 } else { 2461 2462 PDRIVE_LAYOUT_INFORMATION partitionList; 2463 PDEVICE_EXTENSION physicalExtension = deviceExtension; 2464 PPARTITION_INFORMATION partitionEntry; 2465 PDISK_DATA diskData; 2466 ULONG tempSize; 2467 ULONG i; 2468 2469 // 2470 // Read partition information. 2471 // 2472 2473 status = IoReadPartitionTable(deviceExtension->PhysicalDevice, 2474 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 2475 FALSE, 2476 &partitionList); 2477 2478 if (!NT_SUCCESS(status)) { 2479 break; 2480 } 2481 2482 // 2483 // The disk layout has been returned in the partitionList 2484 // buffer. Determine its size and, if the data will fit 2485 // into the intermediary buffer, return it. 2486 // 2487 2488 tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]); 2489 tempSize += partitionList->PartitionCount * 2490 sizeof(PARTITION_INFORMATION); 2491 2492 if (tempSize > 2493 irpStack->Parameters.DeviceIoControl.OutputBufferLength) { 2494 2495 status = STATUS_BUFFER_TOO_SMALL; 2496 ExFreePool(partitionList); 2497 break; 2498 } 2499 2500 // 2501 // Walk partition list to associate partition numbers with 2502 // partition entries. 2503 // 2504 2505 for (i = 0; i < partitionList->PartitionCount; i++) { 2506 2507 // 2508 // Walk partition chain anchored at physical disk extension. 2509 // 2510 2511 deviceExtension = physicalExtension; 2512 diskData = (PDISK_DATA)(deviceExtension + 1); 2513 2514 do { 2515 2516 deviceExtension = diskData->NextPartition; 2517 2518 // 2519 // Check if this is the last partition in the chain. 2520 // 2521 2522 if (!deviceExtension) { 2523 break; 2524 } 2525 2526 // 2527 // Get the partition device extension from disk data. 2528 // 2529 2530 diskData = (PDISK_DATA)(deviceExtension + 1); 2531 2532 // 2533 // Check if this partition is not currently being used. 2534 // 2535 2536 if (!deviceExtension->PartitionLength.QuadPart) { 2537 continue; 2538 } 2539 2540 partitionEntry = &partitionList->PartitionEntry[i]; 2541 2542 // 2543 // Check if empty, or describes extended partition or hasn't changed. 2544 // 2545 2546 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED || 2547 IsContainerPartition(partitionEntry->PartitionType)) { 2548 continue; 2549 } 2550 2551 // 2552 // Check if new partition starts where this partition starts. 2553 // 2554 2555 if (partitionEntry->StartingOffset.QuadPart != 2556 deviceExtension->StartingOffset.QuadPart) { 2557 continue; 2558 } 2559 2560 // 2561 // Check if partition length is the same. 2562 // 2563 2564 if (partitionEntry->PartitionLength.QuadPart == 2565 deviceExtension->PartitionLength.QuadPart) { 2566 2567 // 2568 // Partitions match. Update partition number. 2569 // 2570 2571 partitionEntry->PartitionNumber = 2572 diskData->PartitionNumber; 2573 break; 2574 } 2575 2576 } while (TRUE); 2577 } 2578 2579 // 2580 // Copy partition information to system buffer. 2581 // 2582 2583 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, 2584 partitionList, 2585 tempSize); 2586 status = STATUS_SUCCESS; 2587 Irp->IoStatus.Information = tempSize; 2588 2589 // 2590 // Finally, free the buffer allocated by reading the 2591 // partition table. 2592 // 2593 2594 ExFreePool(partitionList); 2595 } 2596 2597 break; 2598 2599 case IOCTL_DISK_SET_DRIVE_LAYOUT: 2600 2601 { 2602 2603 // 2604 // Update the disk with new partition information. 2605 // 2606 2607 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer; 2608 2609 // 2610 // Validate buffer length. 2611 // 2612 2613 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2614 sizeof(DRIVE_LAYOUT_INFORMATION)) { 2615 2616 status = STATUS_INFO_LENGTH_MISMATCH; 2617 break; 2618 } 2619 2620 length = sizeof(DRIVE_LAYOUT_INFORMATION) + 2621 (partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION); 2622 2623 2624 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2625 length) { 2626 2627 status = STATUS_BUFFER_TOO_SMALL; 2628 break; 2629 } 2630 2631 // 2632 // Verify that device object is for physical disk. 2633 // 2634 2635 if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) { 2636 status = STATUS_INVALID_PARAMETER; 2637 break; 2638 } 2639 2640 // 2641 // Walk through partition table comparing partitions to 2642 // existing partitions to create, delete and change 2643 // device objects as necessary. 2644 // 2645 2646 UpdateDeviceObjects(DeviceObject, 2647 Irp); 2648 2649 // 2650 // Write changes to disk. 2651 // 2652 2653 status = IoWritePartitionTable( 2654 deviceExtension->DeviceObject, 2655 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 2656 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack, 2657 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder, 2658 partitionList); 2659 } 2660 2661 // 2662 // Update IRP with bytes returned. 2663 // 2664 2665 if (NT_SUCCESS(status)) { 2666 Irp->IoStatus.Information = length; 2667 } 2668 2669 break; 2670 2671 case IOCTL_DISK_REASSIGN_BLOCKS: 2672 2673 // 2674 // Map defective blocks to new location on disk. 2675 // 2676 2677 { 2678 2679 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer; 2680 ULONG bufferSize; 2681 ULONG blockNumber; 2682 ULONG blockCount; 2683 2684 // 2685 // Validate buffer length. 2686 // 2687 2688 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2689 sizeof(REASSIGN_BLOCKS)) { 2690 2691 status = STATUS_INFO_LENGTH_MISMATCH; 2692 break; 2693 } 2694 2695 bufferSize = sizeof(REASSIGN_BLOCKS) + 2696 (badBlocks->Count - 1) * sizeof(ULONG); 2697 2698 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 2699 bufferSize) { 2700 2701 status = STATUS_INFO_LENGTH_MISMATCH; 2702 break; 2703 } 2704 2705 // 2706 // Build the data buffer to be transferred in the input buffer. 2707 // The format of the data to the device is: 2708 // 2709 // 2 bytes Reserved 2710 // 2 bytes Length 2711 // x * 4 btyes Block Address 2712 // 2713 // All values are big endian. 2714 // 2715 2716 badBlocks->Reserved = 0; 2717 blockCount = badBlocks->Count; 2718 2719 // 2720 // Convert # of entries to # of bytes. 2721 // 2722 2723 blockCount *= 4; 2724 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF); 2725 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00); 2726 2727 // 2728 // Convert back to number of entries. 2729 // 2730 2731 blockCount /= 4; 2732 2733 for (; blockCount > 0; blockCount--) { 2734 2735 blockNumber = badBlocks->BlockNumber[blockCount-1]; 2736 2737 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1], 2738 (PFOUR_BYTE) &blockNumber); 2739 } 2740 2741 srb->CdbLength = 6; 2742 2743 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS; 2744 2745 // 2746 // Set timeout value. 2747 // 2748 2749 srb->TimeOutValue = deviceExtension->TimeOutValue; 2750 2751 status = ScsiClassSendSrbSynchronous(DeviceObject, 2752 srb, 2753 badBlocks, 2754 bufferSize, 2755 TRUE); 2756 2757 Irp->IoStatus.Status = status; 2758 Irp->IoStatus.Information = 0; 2759 ExFreePool(srb); 2760 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2761 } 2762 2763 return(status); 2764 2765 case IOCTL_DISK_IS_WRITABLE: 2766 2767 // 2768 // Determine if the device is writable. 2769 // 2770 2771 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE); 2772 2773 if (modeData == NULL) { 2774 status = STATUS_INSUFFICIENT_RESOURCES; 2775 break; 2776 } 2777 2778 RtlZeroMemory(modeData, MODE_DATA_SIZE); 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 2787 // 2788 // Retry the request in case of a check condition. 2789 // 2790 2791 length = ScsiClassModeSense(DeviceObject, 2792 (PCHAR) modeData, 2793 MODE_DATA_SIZE, 2794 MODE_SENSE_RETURN_ALL); 2795 2796 if (length < sizeof(MODE_PARAMETER_HEADER)) { 2797 status = STATUS_IO_DEVICE_ERROR; 2798 ExFreePool(modeData); 2799 break; 2800 } 2801 } 2802 2803 if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) { 2804 status = STATUS_MEDIA_WRITE_PROTECTED; 2805 } else { 2806 status = STATUS_SUCCESS; 2807 } 2808 2809 ExFreePool(modeData); 2810 break; 2811 2812 case IOCTL_DISK_INTERNAL_SET_VERIFY: 2813 2814 // 2815 // If the caller is kernel mode, set the verify bit. 2816 // 2817 2818 if (Irp->RequestorMode == KernelMode) { 2819 DeviceObject->Flags |= DO_VERIFY_VOLUME; 2820 } 2821 status = STATUS_SUCCESS; 2822 break; 2823 2824 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY: 2825 2826 // 2827 // If the caller is kernel mode, clear the verify bit. 2828 // 2829 2830 if (Irp->RequestorMode == KernelMode) { 2831 DeviceObject->Flags &= ~DO_VERIFY_VOLUME; 2832 } 2833 status = STATUS_SUCCESS; 2834 break; 2835 2836 case IOCTL_DISK_FIND_NEW_DEVICES: 2837 2838 // 2839 // Search for devices that have been powered on since the last 2840 // device search or system initialization. 2841 // 2842 2843 DebugPrint((3,"CdRomDeviceControl: Find devices\n")); 2844 status = DriverEntry(DeviceObject->DriverObject, 2845 NULL); 2846 2847 Irp->IoStatus.Status = status; 2848 ExFreePool(srb); 2849 IoCompleteRequest(Irp, IO_NO_INCREMENT); 2850 return status; 2851 2852 case IOCTL_DISK_MEDIA_REMOVAL: 2853 2854 // 2855 // If the disk is not removable then don't allow this command. 2856 // 2857 2858 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) { 2859 status = STATUS_INVALID_DEVICE_REQUEST; 2860 break; 2861 } 2862 2863 // 2864 // Fall through and let the class driver process the request. 2865 // 2866 2867 case IOCTL_DISK_GET_LENGTH_INFO: 2868 2869 // 2870 // Validate buffer length. 2871 // 2872 2873 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 2874 sizeof(GET_LENGTH_INFORMATION)) { 2875 status = STATUS_BUFFER_TOO_SMALL; 2876 2877 } else { 2878 2879 PGET_LENGTH_INFORMATION lengthInformation = Irp->AssociatedIrp.SystemBuffer; 2880 2881 // 2882 // Update the geometry in case it has changed. 2883 // 2884 2885 status = UpdateRemovableGeometry (DeviceObject, Irp); 2886 2887 if (!NT_SUCCESS(status)) { 2888 2889 // 2890 // Note the drive is not ready. 2891 // 2892 2893 diskData->DriveNotReady = TRUE; 2894 break; 2895 } 2896 2897 // 2898 // Note the drive is now ready. 2899 // 2900 2901 diskData->DriveNotReady = FALSE; 2902 2903 // 2904 // Output data, and return 2905 // 2906 2907 lengthInformation->Length.QuadPart = deviceExtension->PartitionLength.QuadPart; 2908 status = STATUS_SUCCESS; 2909 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION); 2910 } 2911 2912 break; 2913 2914 default: 2915 2916 // 2917 // Free the Srb, since it is not needed. 2918 // 2919 2920 ExFreePool(srb); 2921 2922 // 2923 // Pass the request to the common device control routine. 2924 // 2925 2926 return(ScsiClassDeviceControl(DeviceObject, Irp)); 2927 2928 break; 2929 2930 } // end switch( ... 2931 2932 Irp->IoStatus.Status = status; 2933 2934 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) { 2935 2936 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 2937 } 2938 2939 IoCompleteRequest(Irp, IO_NO_INCREMENT); 2940 ExFreePool(srb); 2941 return(status); 2942 2943 } // end ScsiDiskDeviceControl() 2944 2945 NTSTATUS 2946 NTAPI 2947 ScsiDiskShutdownFlush ( 2948 IN PDEVICE_OBJECT DeviceObject, 2949 IN PIRP Irp 2950 ) 2951 2952 /*++ 2953 2954 Routine Description: 2955 2956 This routine is called for a shutdown and flush IRPs. These are sent by the 2957 system before it actually shuts down or when the file system does a flush. 2958 A synchronize cache command is sent to the device if it is write caching. 2959 If the device is removable an unlock command will be sent. This routine 2960 will sent a shutdown or flush Srb to the port driver. 2961 2962 Arguments: 2963 2964 DriverObject - Pointer to device object to being shutdown by system. 2965 2966 Irp - IRP involved. 2967 2968 Return Value: 2969 2970 NT Status 2971 2972 --*/ 2973 2974 { 2975 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 2976 PIO_STACK_LOCATION irpStack; 2977 PSCSI_REQUEST_BLOCK srb; 2978 NTSTATUS status; 2979 PCDB cdb; 2980 2981 // 2982 // Allocate SCSI request block. 2983 // 2984 2985 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK)); 2986 2987 if (srb == NULL) { 2988 2989 // 2990 // Set the status and complete the request. 2991 // 2992 2993 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 2994 IoCompleteRequest(Irp, IO_NO_INCREMENT); 2995 return(STATUS_INSUFFICIENT_RESOURCES); 2996 } 2997 2998 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 2999 3000 // 3001 // Write length to SRB. 3002 // 3003 3004 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 3005 3006 // 3007 // Set SCSI bus address. 3008 // 3009 3010 srb->PathId = deviceExtension->PathId; 3011 srb->TargetId = deviceExtension->TargetId; 3012 srb->Lun = deviceExtension->Lun; 3013 3014 // 3015 // Set timeout value and mark the request as not being a tagged request. 3016 // 3017 3018 srb->TimeOutValue = deviceExtension->TimeOutValue * 4; 3019 srb->QueueTag = SP_UNTAGGED; 3020 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 3021 srb->SrbFlags = deviceExtension->SrbFlags; 3022 3023 // 3024 // If the write cache is enabled then send a synchronize cache request. 3025 // 3026 3027 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) { 3028 3029 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 3030 srb->CdbLength = 10; 3031 3032 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE; 3033 3034 status = ScsiClassSendSrbSynchronous(DeviceObject, 3035 srb, 3036 NULL, 3037 0, 3038 TRUE); 3039 3040 DebugPrint((1, "ScsiDiskShutdownFlush: Synchronize cache sent. Status = %lx\n", status )); 3041 } 3042 3043 // 3044 // Unlock the device if it is removable and this is a shutdown. 3045 // 3046 3047 irpStack = IoGetCurrentIrpStackLocation(Irp); 3048 3049 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA && 3050 irpStack->MajorFunction == IRP_MJ_SHUTDOWN) { 3051 3052 srb->CdbLength = 6; 3053 cdb = (PVOID) srb->Cdb; 3054 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; 3055 cdb->MEDIA_REMOVAL.Prevent = FALSE; 3056 3057 // 3058 // Set timeout value. 3059 // 3060 3061 srb->TimeOutValue = deviceExtension->TimeOutValue; 3062 status = ScsiClassSendSrbSynchronous(DeviceObject, 3063 srb, 3064 NULL, 3065 0, 3066 TRUE); 3067 3068 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status )); 3069 } 3070 3071 srb->CdbLength = 0; 3072 3073 // 3074 // Save a few parameters in the current stack location. 3075 // 3076 3077 srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ? 3078 SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH; 3079 3080 // 3081 // Set the retry count to zero. 3082 // 3083 3084 irpStack->Parameters.Others.Argument4 = (PVOID) 0; 3085 3086 // 3087 // Set up IoCompletion routine address. 3088 // 3089 3090 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE); 3091 3092 // 3093 // Get next stack location and 3094 // set major function code. 3095 // 3096 3097 irpStack = IoGetNextIrpStackLocation(Irp); 3098 3099 irpStack->MajorFunction = IRP_MJ_SCSI; 3100 3101 // 3102 // Set up SRB for execute scsi request. 3103 // Save SRB address in next stack for port driver. 3104 // 3105 3106 irpStack->Parameters.Scsi.Srb = srb; 3107 3108 // 3109 // Set up Irp Address. 3110 // 3111 3112 srb->OriginalRequest = Irp; 3113 3114 // 3115 // Call the port driver to process the request. 3116 // 3117 3118 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp)); 3119 3120 } // end ScsiDiskShutdown() 3121 3122 3123 BOOLEAN 3124 NTAPI 3125 IsFloppyDevice( 3126 PDEVICE_OBJECT DeviceObject 3127 ) 3128 /*++ 3129 3130 Routine Description: 3131 3132 The routine performs the necessary functions to determine if a device is 3133 really a floppy rather than a harddisk. This is done by a mode sense 3134 command. First, a check is made to see if the media type is set. Second 3135 a check is made for the flexible parameters mode page. Also a check is 3136 made to see if the write cache is enabled. 3137 3138 Arguments: 3139 3140 DeviceObject - Supplies the device object to be tested. 3141 3142 Return Value: 3143 3144 Return TRUE if the indicated device is a floppy. 3145 3146 --*/ 3147 { 3148 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 3149 PVOID modeData; 3150 PUCHAR pageData; 3151 ULONG length; 3152 3153 PAGED_CODE(); 3154 3155 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE); 3156 3157 if (modeData == NULL) { 3158 return(FALSE); 3159 } 3160 3161 RtlZeroMemory(modeData, MODE_DATA_SIZE); 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 // 3171 // Retry the request in case of a check condition. 3172 // 3173 3174 length = ScsiClassModeSense(DeviceObject, 3175 modeData, 3176 MODE_DATA_SIZE, 3177 MODE_SENSE_RETURN_ALL); 3178 3179 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3180 3181 ExFreePool(modeData); 3182 return(FALSE); 3183 3184 } 3185 } 3186 3187 // 3188 // If the length is greater than length indicated by the mode data reset 3189 // the data to the mode data. 3190 // 3191 3192 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) { 3193 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1; 3194 } 3195 3196 // 3197 // Look for the flexible disk mode page. 3198 // 3199 3200 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE); 3201 3202 if (pageData != NULL) { 3203 3204 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n")); 3205 ExFreePool(modeData); 3206 return(TRUE); 3207 } 3208 3209 // 3210 // Check to see if the write cache is enabled. 3211 // 3212 3213 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE); 3214 3215 // 3216 // Assume that write cache is disabled or not supported. 3217 // 3218 3219 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 3220 3221 // 3222 // Check if valid caching page exists. 3223 // 3224 3225 if (pageData != NULL) { 3226 3227 // 3228 // Check if write cache is disabled. 3229 // 3230 3231 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) { 3232 3233 DebugPrint((1, 3234 "SCSIDISK: Disk write cache enabled\n")); 3235 3236 // 3237 // Check if forced unit access (FUA) is supported. 3238 // 3239 3240 if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) { 3241 3242 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE; 3243 3244 } else { 3245 3246 DebugPrint((1, 3247 "SCSIDISK: Disk does not support FUA or DPO\n")); 3248 3249 // 3250 // TODO: Log this. 3251 // 3252 3253 } 3254 } 3255 } 3256 3257 ExFreePool(modeData); 3258 return(FALSE); 3259 3260 } // end IsFloppyDevice() 3261 3262 3263 BOOLEAN 3264 NTAPI 3265 ScsiDiskModeSelect( 3266 IN PDEVICE_OBJECT DeviceObject, 3267 IN PCHAR ModeSelectBuffer, 3268 IN ULONG Length, 3269 IN BOOLEAN SavePage 3270 ) 3271 3272 /*++ 3273 3274 Routine Description: 3275 3276 This routine sends a mode select command. 3277 3278 Arguments: 3279 3280 DeviceObject - Supplies the device object associated with this request. 3281 3282 ModeSelectBuffer - Supplies a buffer containing the page data. 3283 3284 Length - Supplies the length in bytes of the mode select buffer. 3285 3286 SavePage - Indicates that parameters should be written to disk. 3287 3288 Return Value: 3289 3290 Length of the transferred data is returned. 3291 3292 --*/ 3293 { 3294 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 3295 PCDB cdb; 3296 SCSI_REQUEST_BLOCK srb; 3297 ULONG retries = 1; 3298 ULONG length2; 3299 NTSTATUS status; 3300 ULONG_PTR buffer; 3301 PMODE_PARAMETER_BLOCK blockDescriptor; 3302 3303 PAGED_CODE(); 3304 3305 length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK); 3306 3307 // 3308 // Allocate buffer for mode select header, block descriptor, and mode page. 3309 // 3310 3311 buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2); 3312 3313 RtlZeroMemory((PVOID)buffer, length2); 3314 3315 // 3316 // Set length in header to size of mode page. 3317 // 3318 3319 ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK); 3320 3321 blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1); 3322 3323 // 3324 // Set size 3325 // 3326 3327 blockDescriptor->BlockLength[1]=0x02; 3328 3329 // 3330 // Copy mode page to buffer. 3331 // 3332 3333 RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length); 3334 3335 // 3336 // Zero SRB. 3337 // 3338 3339 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 3340 3341 // 3342 // Build the MODE SELECT CDB. 3343 // 3344 3345 srb.CdbLength = 6; 3346 cdb = (PCDB)srb.Cdb; 3347 3348 // 3349 // Set timeout value from device extension. 3350 // 3351 3352 srb.TimeOutValue = deviceExtension->TimeOutValue * 2; 3353 3354 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; 3355 cdb->MODE_SELECT.SPBit = SavePage; 3356 cdb->MODE_SELECT.PFBit = 1; 3357 cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2); 3358 3359 Retry: 3360 3361 status = ScsiClassSendSrbSynchronous(DeviceObject, 3362 &srb, 3363 (PVOID)buffer, 3364 length2, 3365 TRUE); 3366 3367 3368 if (status == STATUS_VERIFY_REQUIRED) { 3369 3370 // 3371 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with 3372 // this status. 3373 // 3374 3375 if (retries--) { 3376 3377 // 3378 // Retry request. 3379 // 3380 3381 goto Retry; 3382 } 3383 3384 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) { 3385 status = STATUS_SUCCESS; 3386 } 3387 3388 ExFreePool((PVOID)buffer); 3389 3390 if (NT_SUCCESS(status)) { 3391 return(TRUE); 3392 } else { 3393 return(FALSE); 3394 } 3395 3396 } // end SciDiskModeSelect() 3397 3398 3399 VOID 3400 NTAPI 3401 DisableWriteCache( 3402 IN PDEVICE_OBJECT DeviceObject, 3403 IN PSCSI_INQUIRY_DATA LunInfo 3404 ) 3405 3406 { 3407 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 3408 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData; 3409 BAD_CONTROLLER_INFORMATION const *controller; 3410 ULONG j,length; 3411 PVOID modeData; 3412 PUCHAR pageData; 3413 3414 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) { 3415 3416 controller = &ScsiDiskBadControllers[j]; 3417 3418 if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) { 3419 continue; 3420 } 3421 3422 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString)); 3423 3424 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE); 3425 3426 if (modeData == NULL) { 3427 3428 DebugPrint((1, 3429 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n")); 3430 return; 3431 } 3432 3433 RtlZeroMemory(modeData, MODE_DATA_SIZE); 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 // Retry the request in case of a check condition. 3444 // 3445 3446 length = ScsiClassModeSense(DeviceObject, 3447 modeData, 3448 MODE_DATA_SIZE, 3449 MODE_SENSE_RETURN_ALL); 3450 3451 if (length < sizeof(MODE_PARAMETER_HEADER)) { 3452 3453 3454 DebugPrint((1, 3455 "ScsiDisk.DisableWriteCache: Mode Sense failed\n")); 3456 3457 ExFreePool(modeData); 3458 return; 3459 3460 } 3461 } 3462 3463 // 3464 // If the length is greater than length indicated by the mode data reset 3465 // the data to the mode data. 3466 // 3467 3468 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) { 3469 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1; 3470 } 3471 3472 // 3473 // Check to see if the write cache is enabled. 3474 // 3475 3476 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE); 3477 3478 // 3479 // Assume that write cache is disabled or not supported. 3480 // 3481 3482 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 3483 3484 // 3485 // Check if valid caching page exists. 3486 // 3487 3488 if (pageData != NULL) { 3489 3490 BOOLEAN savePage = FALSE; 3491 3492 savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable); 3493 3494 // 3495 // Check if write cache is disabled. 3496 // 3497 3498 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) { 3499 3500 PIO_ERROR_LOG_PACKET errorLogEntry; 3501 LONG errorCode; 3502 3503 3504 // 3505 // Disable write cache and ensure necessary fields are zeroed. 3506 // 3507 3508 ((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE; 3509 ((PMODE_CACHING_PAGE)pageData)->Reserved = 0; 3510 ((PMODE_CACHING_PAGE)pageData)->PageSavable = 0; 3511 ((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0; 3512 3513 // 3514 // Extract length from caching page. 3515 // 3516 3517 length = ((PMODE_CACHING_PAGE)pageData)->PageLength; 3518 3519 // 3520 // Compensate for page code and page length. 3521 // 3522 3523 length += 2; 3524 3525 // 3526 // Issue mode select to set the parameter. 3527 // 3528 3529 if (ScsiDiskModeSelect(DeviceObject, 3530 (PCHAR)pageData, 3531 length, 3532 savePage)) { 3533 3534 DebugPrint((1, 3535 "SCSIDISK: Disk write cache disabled\n")); 3536 3537 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 3538 errorCode = IO_WRITE_CACHE_DISABLED; 3539 3540 } else { 3541 if (ScsiDiskModeSelect(DeviceObject, 3542 (PCHAR)pageData, 3543 length, 3544 savePage)) { 3545 3546 DebugPrint((1, 3547 "SCSIDISK: Disk write cache disabled\n")); 3548 3549 3550 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 3551 errorCode = IO_WRITE_CACHE_DISABLED; 3552 3553 } else { 3554 3555 DebugPrint((1, 3556 "SCSIDISK: Mode select to disable write cache failed\n")); 3557 3558 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE; 3559 errorCode = IO_WRITE_CACHE_ENABLED; 3560 } 3561 } 3562 3563 // 3564 // Log the appropriate informational or error entry. 3565 // 3566 3567 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( 3568 DeviceObject, 3569 sizeof(IO_ERROR_LOG_PACKET) + 3 3570 * sizeof(ULONG)); 3571 3572 if (errorLogEntry != NULL) { 3573 3574 errorLogEntry->FinalStatus = STATUS_SUCCESS; 3575 errorLogEntry->ErrorCode = errorCode; 3576 errorLogEntry->SequenceNumber = 0; 3577 errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI; 3578 errorLogEntry->IoControlCode = 0; 3579 errorLogEntry->RetryCount = 0; 3580 errorLogEntry->UniqueErrorValue = 0x1; 3581 errorLogEntry->DumpDataSize = 3 * sizeof(ULONG); 3582 errorLogEntry->DumpData[0] = LunInfo->PathId; 3583 errorLogEntry->DumpData[1] = LunInfo->TargetId; 3584 errorLogEntry->DumpData[2] = LunInfo->Lun; 3585 3586 // 3587 // Write the error log packet. 3588 // 3589 3590 IoWriteErrorLogEntry(errorLogEntry); 3591 } 3592 } 3593 } 3594 3595 // 3596 // Found device so exit the loop and return. 3597 // 3598 3599 break; 3600 } 3601 3602 return; 3603 } 3604 3605 3606 BOOLEAN 3607 NTAPI 3608 CalculateMbrCheckSum( 3609 IN PDEVICE_EXTENSION DeviceExtension, 3610 OUT PULONG Checksum 3611 ) 3612 3613 /*++ 3614 3615 Routine Description: 3616 3617 Read MBR and calculate checksum. 3618 3619 Arguments: 3620 3621 DeviceExtension - Supplies a pointer to the device information for disk. 3622 Checksum - Memory location to return MBR checksum. 3623 3624 Return Value: 3625 3626 Returns TRUE if checksum is valid. 3627 3628 --*/ 3629 { 3630 LARGE_INTEGER sectorZero; 3631 PIRP irp; 3632 IO_STATUS_BLOCK ioStatus; 3633 KEVENT event; 3634 NTSTATUS status; 3635 ULONG sectorSize; 3636 PULONG mbr; 3637 ULONG i; 3638 3639 PAGED_CODE(); 3640 sectorZero.QuadPart = (LONGLONG) 0; 3641 3642 // 3643 // Create notification event object to be used to signal the inquiry 3644 // request completion. 3645 // 3646 3647 KeInitializeEvent(&event, NotificationEvent, FALSE); 3648 3649 // 3650 // Get sector size. 3651 // 3652 3653 sectorSize = DeviceExtension->DiskGeometry->Geometry.BytesPerSector; 3654 3655 // 3656 // Make sure sector size is at least 512 bytes. 3657 // 3658 3659 if (sectorSize < 512) { 3660 sectorSize = 512; 3661 } 3662 3663 // 3664 // Allocate buffer for sector read. 3665 // 3666 3667 mbr = ExAllocatePool(NonPagedPoolCacheAligned, sectorSize); 3668 3669 if (!mbr) { 3670 return FALSE; 3671 } 3672 3673 // 3674 // Build IRP to read MBR. 3675 // 3676 3677 irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 3678 DeviceExtension->DeviceObject, 3679 mbr, 3680 sectorSize, 3681 §orZero, 3682 &event, 3683 &ioStatus ); 3684 3685 if (!irp) { 3686 ExFreePool(mbr); 3687 return FALSE; 3688 } 3689 3690 // 3691 // Pass request to port driver and wait for request to complete. 3692 // 3693 3694 status = IoCallDriver(DeviceExtension->DeviceObject, 3695 irp); 3696 3697 if (status == STATUS_PENDING) { 3698 KeWaitForSingleObject(&event, 3699 Suspended, 3700 KernelMode, 3701 FALSE, 3702 NULL); 3703 status = ioStatus.Status; 3704 } 3705 3706 if (!NT_SUCCESS(status)) { 3707 ExFreePool(mbr); 3708 return FALSE; 3709 } 3710 3711 // 3712 // Calculate MBR checksum. 3713 // 3714 3715 *Checksum = 0; 3716 3717 for (i = 0; i < 128; i++) { 3718 *Checksum += mbr[i]; 3719 } 3720 3721 *Checksum = ~*Checksum + 1; 3722 3723 ExFreePool(mbr); 3724 return TRUE; 3725 } 3726 3727 3728 BOOLEAN 3729 NTAPI 3730 EnumerateBusKey( 3731 IN PDEVICE_EXTENSION DeviceExtension, 3732 HANDLE BusKey, 3733 PULONG DiskNumber 3734 ) 3735 3736 /*++ 3737 3738 Routine Description: 3739 3740 The routine queries the registry to determine if this disk is visible to 3741 the BIOS. If the disk is visible to the BIOS, then the geometry information 3742 is updated. 3743 3744 Arguments: 3745 3746 DeviceExtension - Supplies a pointer to the device information for disk. 3747 Signature - Unique identifier recorded in MBR. 3748 BusKey - Handle of bus key. 3749 DiskNumber - Returns ordinal of disk as BIOS sees it. 3750 3751 Return Value: 3752 3753 TRUE is disk signature matched. 3754 3755 --*/ 3756 { 3757 PDISK_DATA diskData = (PDISK_DATA)(DeviceExtension + 1); 3758 BOOLEAN diskFound = FALSE; 3759 OBJECT_ATTRIBUTES objectAttributes; 3760 UNICODE_STRING unicodeString; 3761 UNICODE_STRING identifier; 3762 ULONG busNumber; 3763 ULONG adapterNumber; 3764 ULONG diskNumber; 3765 HANDLE adapterKey; 3766 HANDLE spareKey; 3767 HANDLE diskKey; 3768 HANDLE targetKey; 3769 NTSTATUS status; 3770 STRING string; 3771 STRING anotherString; 3772 ULONG length; 3773 UCHAR buffer[20]; 3774 PKEY_VALUE_FULL_INFORMATION keyData; 3775 3776 PAGED_CODE(); 3777 3778 for (busNumber = 0; ; busNumber++) { 3779 3780 // 3781 // Open controller name key. 3782 // 3783 3784 sprintf((PCHAR)buffer, 3785 "%lu", 3786 busNumber); 3787 3788 RtlInitString(&string, 3789 (PCSZ)buffer); 3790 3791 status = RtlAnsiStringToUnicodeString(&unicodeString, 3792 &string, 3793 TRUE); 3794 3795 if (!NT_SUCCESS(status)){ 3796 break; 3797 } 3798 3799 InitializeObjectAttributes(&objectAttributes, 3800 &unicodeString, 3801 OBJ_CASE_INSENSITIVE, 3802 BusKey, 3803 (PSECURITY_DESCRIPTOR)NULL); 3804 3805 status = ZwOpenKey(&spareKey, 3806 KEY_READ, 3807 &objectAttributes); 3808 3809 RtlFreeUnicodeString(&unicodeString); 3810 3811 if (!NT_SUCCESS(status)) { 3812 break; 3813 } 3814 3815 // 3816 // Open up controller ordinal key. 3817 // 3818 3819 RtlInitUnicodeString(&unicodeString, L"DiskController"); 3820 InitializeObjectAttributes(&objectAttributes, 3821 &unicodeString, 3822 OBJ_CASE_INSENSITIVE, 3823 spareKey, 3824 (PSECURITY_DESCRIPTOR)NULL); 3825 3826 status = ZwOpenKey(&adapterKey, 3827 KEY_READ, 3828 &objectAttributes); 3829 3830 // 3831 // This could fail even with additional adapters of this type 3832 // to search. 3833 // 3834 3835 if (!NT_SUCCESS(status)) { 3836 continue; 3837 } 3838 3839 for (adapterNumber = 0; ; adapterNumber++) { 3840 3841 // 3842 // Open disk key. 3843 // 3844 3845 sprintf((PCHAR)buffer, 3846 "%lu\\DiskPeripheral", 3847 adapterNumber); 3848 3849 RtlInitString(&string, 3850 (PCSZ)buffer); 3851 3852 status = RtlAnsiStringToUnicodeString(&unicodeString, 3853 &string, 3854 TRUE); 3855 3856 if (!NT_SUCCESS(status)){ 3857 break; 3858 } 3859 3860 InitializeObjectAttributes(&objectAttributes, 3861 &unicodeString, 3862 OBJ_CASE_INSENSITIVE, 3863 adapterKey, 3864 (PSECURITY_DESCRIPTOR)NULL); 3865 3866 status = ZwOpenKey(&diskKey, 3867 KEY_READ, 3868 &objectAttributes); 3869 3870 RtlFreeUnicodeString(&unicodeString); 3871 3872 if (!NT_SUCCESS(status)) { 3873 break; 3874 } 3875 3876 for (diskNumber = 0; ; diskNumber++) { 3877 3878 sprintf((PCHAR)buffer, 3879 "%lu", 3880 diskNumber); 3881 3882 RtlInitString(&string, 3883 (PCSZ)buffer); 3884 3885 status = RtlAnsiStringToUnicodeString(&unicodeString, 3886 &string, 3887 TRUE); 3888 3889 if (!NT_SUCCESS(status)){ 3890 break; 3891 } 3892 3893 InitializeObjectAttributes(&objectAttributes, 3894 &unicodeString, 3895 OBJ_CASE_INSENSITIVE, 3896 diskKey, 3897 (PSECURITY_DESCRIPTOR)NULL); 3898 3899 status = ZwOpenKey(&targetKey, 3900 KEY_READ, 3901 &objectAttributes); 3902 3903 RtlFreeUnicodeString(&unicodeString); 3904 3905 if (!NT_SUCCESS(status)) { 3906 break; 3907 } 3908 3909 // 3910 // Allocate buffer for registry query. 3911 // 3912 3913 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE); 3914 3915 if (keyData == NULL) { 3916 ZwClose(targetKey); 3917 continue; 3918 } 3919 3920 // 3921 // Get disk peripheral identifier. 3922 // 3923 3924 RtlInitUnicodeString(&unicodeString, L"Identifier"); 3925 status = ZwQueryValueKey(targetKey, 3926 &unicodeString, 3927 KeyValueFullInformation, 3928 keyData, 3929 VALUE_BUFFER_SIZE, 3930 &length); 3931 3932 ZwClose(targetKey); 3933 3934 if (!NT_SUCCESS(status)) { 3935 ExFreePool(keyData); 3936 continue; 3937 } 3938 3939 if (keyData->DataLength < 9*sizeof(WCHAR)) { 3940 // 3941 // the data is too short to use (we subtract 9 chars in normal path) 3942 // 3943 DebugPrint((1, "EnumerateBusKey: Saved data was invalid, " 3944 "not enough data in registry!\n")); 3945 ExFreePool(keyData); 3946 continue; 3947 } 3948 3949 // 3950 // Complete unicode string. 3951 // 3952 3953 identifier.Buffer = 3954 (PWSTR)((PUCHAR)keyData + keyData->DataOffset); 3955 identifier.Length = (USHORT)keyData->DataLength; 3956 identifier.MaximumLength = (USHORT)keyData->DataLength; 3957 3958 // 3959 // Convert unicode identifier to ansi string. 3960 // 3961 3962 status = 3963 RtlUnicodeStringToAnsiString(&anotherString, 3964 &identifier, 3965 TRUE); 3966 3967 if (!NT_SUCCESS(status)) { 3968 ExFreePool(keyData); 3969 continue; 3970 } 3971 3972 // 3973 // If checksum is zero, then the MBR is valid and 3974 // the signature is meaningful. 3975 // 3976 3977 if (diskData->MbrCheckSum) { 3978 3979 // 3980 // Convert checksum to ansi string. 3981 // 3982 3983 sprintf((PCHAR)buffer, "%08lx", diskData->MbrCheckSum); 3984 3985 } else { 3986 3987 // 3988 // Convert signature to ansi string. 3989 // 3990 3991 sprintf((PCHAR)buffer, "%08lx", diskData->Signature); 3992 3993 // 3994 // Make string point at signature. Can't use scan 3995 // functions because they are not exported for driver use. 3996 // 3997 3998 anotherString.Buffer+=9; 3999 } 4000 4001 // 4002 // Convert to ansi string. 4003 // 4004 4005 RtlInitString(&string, 4006 (PCSZ)buffer); 4007 4008 4009 // 4010 // Make string lengths equal. 4011 // 4012 4013 anotherString.Length = string.Length; 4014 4015 // 4016 // Check if strings match. 4017 // 4018 4019 if (RtlCompareString(&string, 4020 &anotherString, 4021 TRUE) == 0) { 4022 4023 diskFound = TRUE; 4024 *DiskNumber = diskNumber; 4025 } 4026 4027 ExFreePool(keyData); 4028 4029 // 4030 // Readjust identifier string if necessary. 4031 // 4032 4033 if (!diskData->MbrCheckSum) { 4034 anotherString.Buffer-=9; 4035 } 4036 4037 RtlFreeAnsiString(&anotherString); 4038 4039 if (diskFound) { 4040 break; 4041 } 4042 } 4043 4044 ZwClose(diskKey); 4045 } 4046 4047 ZwClose(adapterKey); 4048 } 4049 4050 ZwClose(BusKey); 4051 return diskFound; 4052 4053 } // end EnumerateBusKey() 4054 4055 4056 VOID 4057 NTAPI 4058 UpdateGeometry( 4059 IN PDEVICE_EXTENSION DeviceExtension 4060 ) 4061 /*++ 4062 4063 Routine Description: 4064 4065 The routine queries the registry to determine if this disk is visible to 4066 the BIOS. If the disk is visible to the BIOS, then the geometry information 4067 is updated. 4068 4069 Arguments: 4070 4071 DeviceExtension - Supplies a pointer to the device information for disk. 4072 4073 Return Value: 4074 4075 None. 4076 4077 --*/ 4078 4079 { 4080 OBJECT_ATTRIBUTES objectAttributes; 4081 UNICODE_STRING unicodeString; 4082 NTSTATUS status; 4083 HANDLE hardwareKey; 4084 HANDLE busKey; 4085 PCM_INT13_DRIVE_PARAMETER driveParameters; 4086 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor; 4087 PKEY_VALUE_FULL_INFORMATION keyData; 4088 ULONG diskNumber; 4089 PUCHAR buffer; 4090 ULONG length; 4091 ULONG numberOfDrives; 4092 ULONG cylinders; 4093 ULONG sectors; 4094 ULONG sectorsPerTrack; 4095 ULONG tracksPerCylinder; 4096 BOOLEAN foundEZHooker; 4097 PVOID tmpPtr; 4098 4099 PAGED_CODE(); 4100 4101 // 4102 // Initialize the object for the key. 4103 // 4104 4105 InitializeObjectAttributes(&objectAttributes, 4106 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase, 4107 OBJ_CASE_INSENSITIVE, 4108 NULL, 4109 (PSECURITY_DESCRIPTOR) NULL); 4110 4111 // 4112 // Create the hardware base key. 4113 // 4114 4115 status = ZwOpenKey(&hardwareKey, 4116 KEY_READ, 4117 &objectAttributes); 4118 4119 4120 if (!NT_SUCCESS(status)) { 4121 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension->DeviceObject->DriverObject->HardwareDatabase)); 4122 return; 4123 } 4124 4125 4126 // 4127 // Get disk BIOS geometry information. 4128 // 4129 4130 RtlInitUnicodeString(&unicodeString, L"Configuration Data"); 4131 4132 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE); 4133 4134 if (keyData == NULL) { 4135 ZwClose(hardwareKey); 4136 return; 4137 } 4138 4139 status = ZwQueryValueKey(hardwareKey, 4140 &unicodeString, 4141 KeyValueFullInformation, 4142 keyData, 4143 VALUE_BUFFER_SIZE, 4144 &length); 4145 4146 if (!NT_SUCCESS(status)) { 4147 DebugPrint((1, 4148 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n", 4149 status)); 4150 ZwClose(hardwareKey); 4151 ExFreePool(keyData); 4152 return; 4153 } 4154 4155 // 4156 // Open EISA bus key. 4157 // 4158 4159 RtlInitUnicodeString(&unicodeString, L"EisaAdapter"); 4160 4161 InitializeObjectAttributes(&objectAttributes, 4162 &unicodeString, 4163 OBJ_CASE_INSENSITIVE, 4164 hardwareKey, 4165 (PSECURITY_DESCRIPTOR)NULL); 4166 4167 status = ZwOpenKey(&busKey, 4168 KEY_READ, 4169 &objectAttributes); 4170 4171 if (!NT_SUCCESS(status)) { 4172 goto openMultiKey; 4173 } 4174 4175 DebugPrint((3, 4176 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n")); 4177 if (EnumerateBusKey(DeviceExtension, 4178 busKey, 4179 &diskNumber)) { 4180 4181 ZwClose(hardwareKey); 4182 goto diskMatched; 4183 } 4184 4185 openMultiKey: 4186 4187 // 4188 // Open Multifunction bus key. 4189 // 4190 4191 RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter"); 4192 4193 InitializeObjectAttributes(&objectAttributes, 4194 &unicodeString, 4195 OBJ_CASE_INSENSITIVE, 4196 hardwareKey, 4197 (PSECURITY_DESCRIPTOR)NULL); 4198 4199 status = ZwOpenKey(&busKey, 4200 KEY_READ, 4201 &objectAttributes); 4202 4203 ZwClose(hardwareKey); 4204 if (NT_SUCCESS(status)) { 4205 DebugPrint((3, 4206 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n")); 4207 if (EnumerateBusKey(DeviceExtension, 4208 busKey, 4209 &diskNumber)) { 4210 4211 goto diskMatched; 4212 } 4213 } 4214 4215 ExFreePool(keyData); 4216 return; 4217 4218 diskMatched: 4219 4220 resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)keyData + 4221 keyData->DataOffset); 4222 4223 // 4224 // Check that the data is long enough to hold a full resource descriptor, 4225 // and that the last resource list is device-specific and long enough. 4226 // 4227 4228 if (keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR) || 4229 resourceDescriptor->PartialResourceList.Count == 0 || 4230 resourceDescriptor->PartialResourceList.PartialDescriptors[0].Type != 4231 CmResourceTypeDeviceSpecific || 4232 resourceDescriptor->PartialResourceList.PartialDescriptors[0] 4233 .u.DeviceSpecificData.DataSize < sizeof(ULONG)) { 4234 4235 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n")); 4236 ExFreePool(keyData); 4237 return; 4238 } 4239 4240 length = 4241 resourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize; 4242 4243 // 4244 // Point to the BIOS data. The BIOS data is located after the first 4245 // partial Resource list which should be device specific data. 4246 // 4247 4248 buffer = (PUCHAR) keyData + keyData->DataOffset + 4249 sizeof(CM_FULL_RESOURCE_DESCRIPTOR); 4250 4251 4252 numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER); 4253 4254 // 4255 // Use the defaults if the drive number is greater than the 4256 // number of drives detected by the BIOS. 4257 // 4258 4259 if (numberOfDrives <= diskNumber) { 4260 ExFreePool(keyData); 4261 return; 4262 } 4263 4264 // 4265 // Point to the array of drive parameters. 4266 // 4267 4268 driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer + diskNumber; 4269 cylinders = driveParameters->MaxCylinders + 1; 4270 sectorsPerTrack = driveParameters->SectorsPerTrack; 4271 tracksPerCylinder = driveParameters->MaxHeads +1; 4272 4273 // 4274 // Calculate the actual number of sectors. 4275 // 4276 4277 sectors = (ULONG)(DeviceExtension->PartitionLength.QuadPart >> 4278 DeviceExtension->SectorShift); 4279 4280 #if DBG 4281 if (sectors >= cylinders * tracksPerCylinder * sectorsPerTrack) { 4282 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n" 4283 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n", 4284 sectors, cylinders, tracksPerCylinder, sectorsPerTrack)); 4285 } 4286 #endif 4287 4288 // 4289 // Since the BIOS may not report the full drive, recalculate the drive 4290 // size based on the volume size and the BIOS values for tracks per 4291 // cylinder and sectors per track.. 4292 // 4293 4294 length = tracksPerCylinder * sectorsPerTrack; 4295 4296 if (length == 0) { 4297 4298 // 4299 // The BIOS information is bogus. 4300 // 4301 4302 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n")); 4303 ExFreePool(keyData); 4304 return; 4305 } 4306 4307 cylinders = sectors / length; 4308 4309 // 4310 // Update the actual geometry information. 4311 // 4312 4313 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack = sectorsPerTrack; 4314 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder; 4315 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)cylinders; 4316 DeviceExtension->DiskGeometry->DiskSize.QuadPart = (LONGLONG)cylinders * tracksPerCylinder * sectorsPerTrack * 4317 DeviceExtension->DiskGeometry->Geometry.BytesPerSector; 4318 4319 DebugPrint((3, 4320 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n", 4321 sectorsPerTrack, 4322 tracksPerCylinder, 4323 cylinders)); 4324 4325 ExFreePool(keyData); 4326 4327 foundEZHooker = FALSE; 4328 4329 if (!DeviceExtension->DMActive) { 4330 4331 HalExamineMBR(DeviceExtension->DeviceObject, 4332 DeviceExtension->DiskGeometry->Geometry.BytesPerSector, 4333 (ULONG)0x55, 4334 &tmpPtr 4335 ); 4336 4337 if (tmpPtr) { 4338 4339 ExFreePool(tmpPtr); 4340 foundEZHooker = TRUE; 4341 4342 } 4343 4344 } 4345 4346 if (DeviceExtension->DMActive || foundEZHooker) { 4347 4348 while (cylinders > 1024) { 4349 4350 tracksPerCylinder = tracksPerCylinder*2; 4351 cylinders = cylinders/2; 4352 4353 } 4354 4355 // 4356 // int 13 values are always 1 less. 4357 // 4358 4359 tracksPerCylinder -= 1; 4360 cylinders -= 1; 4361 4362 // 4363 // DM reserves the CE cylinder 4364 // 4365 4366 cylinders -= 1; 4367 4368 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = cylinders + 1; 4369 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder + 1; 4370 4371 DeviceExtension->PartitionLength.QuadPart = 4372 DeviceExtension->DiskGeometry->DiskSize.QuadPart = 4373 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart * 4374 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack * 4375 DeviceExtension->DiskGeometry->Geometry.BytesPerSector * 4376 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder; 4377 4378 if (DeviceExtension->DMActive) { 4379 4380 DeviceExtension->DMByteSkew = DeviceExtension->DMSkew * DeviceExtension->DiskGeometry->Geometry.BytesPerSector; 4381 4382 } 4383 4384 } else { 4385 4386 DeviceExtension->DMByteSkew = 0; 4387 4388 } 4389 4390 return; 4391 4392 } // end UpdateGeometry() 4393 4394 4395 4396 NTSTATUS 4397 NTAPI 4398 UpdateRemovableGeometry ( 4399 IN PDEVICE_OBJECT DeviceObject, 4400 IN PIRP Irp 4401 ) 4402 4403 /*++ 4404 4405 Routine Description: 4406 4407 This routines updates the size and starting offset of the device. This is 4408 used when the media on the device may have changed thereby changing the 4409 size of the device. If this is the physical device then a 4410 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done. 4411 4412 Arguments: 4413 4414 DeviceObject - Supplies the device object whos size needs to be updated. 4415 4416 Irp - Supplies a reference where the status can be updated. 4417 4418 Return Value: 4419 4420 Returns the status of the operation. 4421 4422 --*/ 4423 { 4424 4425 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 4426 PDRIVE_LAYOUT_INFORMATION partitionList; 4427 NTSTATUS status; 4428 PDISK_DATA diskData; 4429 ULONG partitionNumber; 4430 4431 // 4432 // Determine if the size of the partition may have changed because 4433 // the media has changed. 4434 // 4435 4436 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) { 4437 4438 return(STATUS_SUCCESS); 4439 4440 } 4441 4442 // 4443 // If this request is for partition zero then do a read drive 4444 // capacity otherwise do a I/O read partition table. 4445 // 4446 4447 diskData = (PDISK_DATA) (deviceExtension + 1); 4448 4449 // 4450 // Read the drive capacity. If that fails, give up. 4451 // 4452 4453 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice); 4454 4455 if (!NT_SUCCESS(status)) { 4456 return(status); 4457 } 4458 4459 // 4460 // Read the partition table again. 4461 // 4462 4463 status = IoReadPartitionTable(deviceExtension->PhysicalDevice, 4464 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 4465 TRUE, 4466 &partitionList); 4467 4468 4469 if (!NT_SUCCESS(status)) { 4470 4471 // 4472 // Fail the request. 4473 // 4474 4475 return(status); 4476 } 4477 4478 if (diskData->PartitionNumber != 0 && 4479 diskData->PartitionNumber <= partitionList->PartitionCount ) { 4480 4481 partitionNumber = diskData->PartitionNumber - 1; 4482 4483 // 4484 // Update the partition information for this partition. 4485 // 4486 4487 diskData->PartitionType = 4488 partitionList->PartitionEntry[partitionNumber].PartitionType; 4489 4490 diskData->BootIndicator = 4491 partitionList->PartitionEntry[partitionNumber].BootIndicator; 4492 4493 deviceExtension->StartingOffset = 4494 partitionList->PartitionEntry[partitionNumber].StartingOffset; 4495 4496 deviceExtension->PartitionLength = 4497 partitionList->PartitionEntry[partitionNumber].PartitionLength; 4498 4499 diskData->HiddenSectors = 4500 partitionList->PartitionEntry[partitionNumber].HiddenSectors; 4501 4502 deviceExtension->SectorShift = ((PDEVICE_EXTENSION) 4503 deviceExtension->PhysicalDevice->DeviceExtension)->SectorShift; 4504 4505 } else if (diskData->PartitionNumber != 0) { 4506 4507 // 4508 // The partition does not exist. Zero all the data. 4509 // 4510 4511 diskData->PartitionType = 0; 4512 diskData->BootIndicator = 0; 4513 diskData->HiddenSectors = 0; 4514 deviceExtension->StartingOffset.QuadPart = (LONGLONG)0; 4515 deviceExtension->PartitionLength.QuadPart = (LONGLONG)0; 4516 } 4517 4518 // 4519 // Free the partition list allocate by I/O read partition table. 4520 // 4521 4522 ExFreePool(partitionList); 4523 4524 4525 return(STATUS_SUCCESS); 4526 } 4527 4528 4529 VOID 4530 NTAPI 4531 ScsiDiskProcessError( 4532 PDEVICE_OBJECT DeviceObject, 4533 PSCSI_REQUEST_BLOCK Srb, 4534 NTSTATUS *Status, 4535 BOOLEAN *Retry 4536 ) 4537 /*++ 4538 4539 Routine Description: 4540 4541 This routine checks the type of error. If the error indicates an underrun 4542 then indicate the request should be retried. 4543 4544 Arguments: 4545 4546 DeviceObject - Supplies a pointer to the device object. 4547 4548 Srb - Supplies a pointer to the failing Srb. 4549 4550 Status - Status with which the IRP will be completed. 4551 4552 Retry - Indication of whether the request will be retried. 4553 4554 Return Value: 4555 4556 None. 4557 4558 --*/ 4559 4560 { 4561 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 4562 4563 if (*Status == STATUS_DATA_OVERRUN && 4564 ( Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_READ)) { 4565 4566 *Retry = TRUE; 4567 4568 // 4569 // Update the error count for the device. 4570 // 4571 4572 deviceExtension->ErrorCount++; 4573 } 4574 4575 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR && 4576 Srb->ScsiStatus == SCSISTAT_BUSY) { 4577 4578 // 4579 // The disk drive should never be busy this long. Reset the scsi bus 4580 // maybe this will clear the condition. 4581 // 4582 4583 ResetScsiBus(DeviceObject); 4584 4585 // 4586 // Update the error count for the device. 4587 // 4588 4589 deviceExtension->ErrorCount++; 4590 } 4591 } 4592 4593 VOID 4594 NTAPI 4595 ScanForSpecial( 4596 PDEVICE_OBJECT DeviceObject, 4597 PSCSI_INQUIRY_DATA LunInfo, 4598 PIO_SCSI_CAPABILITIES PortCapabilities 4599 ) 4600 4601 /*++ 4602 4603 Routine Description: 4604 4605 This function checks to see if an SCSI logical unit requires special 4606 flags to be set. 4607 4608 Arguments: 4609 4610 DeviceObject - Supplies the device object to be tested. 4611 4612 InquiryData - Supplies the inquiry data returned by the device of interest. 4613 4614 PortCapabilities - Supplies the capabilities of the device object. 4615 4616 Return Value: 4617 4618 None. 4619 4620 --*/ 4621 4622 { 4623 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 4624 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData; 4625 BAD_CONTROLLER_INFORMATION const *controller; 4626 ULONG j; 4627 4628 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) { 4629 4630 controller = &ScsiDiskBadControllers[j]; 4631 4632 if (strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) { 4633 continue; 4634 } 4635 4636 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller->InquiryString)); 4637 4638 // 4639 // Found a listed controller. Determine what must be done. 4640 // 4641 4642 if (controller->DisableTaggedQueuing) { 4643 4644 // 4645 // Disable tagged queuing. 4646 // 4647 4648 deviceExtension->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE; 4649 } 4650 4651 if (controller->DisableSynchronousTransfers) { 4652 4653 // 4654 // Disable synchronous data transfers. 4655 // 4656 4657 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 4658 4659 } 4660 4661 if (controller->DisableDisconnects) { 4662 4663 // 4664 // Disable disconnects. 4665 // 4666 4667 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT; 4668 4669 } 4670 4671 // 4672 // Found device so exit the loop and return. 4673 // 4674 4675 break; 4676 } 4677 4678 // 4679 // Set the StartUnit flag appropriately. 4680 // 4681 4682 if (DeviceObject->DeviceType == FILE_DEVICE_DISK) { 4683 deviceExtension->DeviceFlags |= DEV_SAFE_START_UNIT; 4684 4685 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 4686 if (_strnicmp((PCCHAR)InquiryData->VendorId, "iomega", strlen("iomega"))) { 4687 deviceExtension->DeviceFlags &= ~DEV_SAFE_START_UNIT; 4688 } 4689 } 4690 } 4691 4692 return; 4693 } 4694 4695 VOID 4696 NTAPI 4697 ResetScsiBus( 4698 IN PDEVICE_OBJECT DeviceObject 4699 ) 4700 4701 /*++ 4702 4703 Routine Description: 4704 4705 This command sends a reset bus command to the SCSI port driver. 4706 4707 Arguments: 4708 4709 DeviceObject - The device object for the logical unit with 4710 hardware problem. 4711 4712 Return Value: 4713 4714 None. 4715 4716 --*/ 4717 { 4718 PIO_STACK_LOCATION irpStack; 4719 PIRP irp; 4720 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 4721 PSCSI_REQUEST_BLOCK srb; 4722 PCOMPLETION_CONTEXT context; 4723 4724 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n")); 4725 4726 // 4727 // Allocate Srb from nonpaged pool. 4728 // 4729 4730 context = ExAllocatePool(NonPagedPoolMustSucceed, 4731 sizeof(COMPLETION_CONTEXT)); 4732 4733 // 4734 // Save the device object in the context for use by the completion 4735 // routine. 4736 // 4737 4738 context->DeviceObject = DeviceObject; 4739 srb = &context->Srb; 4740 4741 // 4742 // Zero out srb. 4743 // 4744 4745 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 4746 4747 // 4748 // Write length to SRB. 4749 // 4750 4751 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 4752 4753 // 4754 // Set up SCSI bus address. 4755 // 4756 4757 srb->PathId = deviceExtension->PathId; 4758 srb->TargetId = deviceExtension->TargetId; 4759 srb->Lun = deviceExtension->Lun; 4760 4761 srb->Function = SRB_FUNCTION_RESET_BUS; 4762 4763 // 4764 // Build the asynchronous request to be sent to the port driver. 4765 // Since this routine is called from a DPC the IRP should always be 4766 // available. 4767 // 4768 4769 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 4770 4771 IoSetCompletionRoutine(irp, 4772 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion, 4773 context, 4774 TRUE, 4775 TRUE, 4776 TRUE); 4777 4778 irpStack = IoGetNextIrpStackLocation(irp); 4779 4780 irpStack->MajorFunction = IRP_MJ_SCSI; 4781 4782 srb->OriginalRequest = irp; 4783 4784 // 4785 // Store the SRB address in next stack for port driver. 4786 // 4787 4788 irpStack->Parameters.Scsi.Srb = srb; 4789 4790 // 4791 // Call the port driver with the IRP. 4792 // 4793 4794 IoCallDriver(deviceExtension->PortDeviceObject, irp); 4795 4796 return; 4797 4798 } // end ResetScsiBus() 4799 4800 4801 VOID 4802 NTAPI 4803 UpdateDeviceObjects( 4804 IN PDEVICE_OBJECT PhysicalDisk, 4805 IN PIRP Irp 4806 ) 4807 4808 /*++ 4809 4810 Routine Description: 4811 4812 This routine creates, deletes and changes device objects when 4813 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates 4814 the drive layout information for the user. It is possible to 4815 call this routine even in the GET_LAYOUT case because RewritePartition 4816 will be false. 4817 4818 Arguments: 4819 4820 DeviceObject - Device object for physical disk. 4821 Irp - IO Request Packet (IRP). 4822 4823 Return Value: 4824 4825 None. 4826 4827 --*/ 4828 { 4829 PDEVICE_EXTENSION physicalExtension = PhysicalDisk->DeviceExtension; 4830 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer; 4831 ULONG partition; 4832 ULONG partitionNumber; 4833 ULONG partitionCount; 4834 ULONG lastPartition; 4835 ULONG partitionOrdinal; 4836 PPARTITION_INFORMATION partitionEntry; 4837 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH]; 4838 STRING ntNameString; 4839 UNICODE_STRING ntUnicodeString; 4840 PDEVICE_OBJECT deviceObject; 4841 PDEVICE_EXTENSION deviceExtension; 4842 PDISK_DATA diskData; 4843 NTSTATUS status; 4844 ULONG numberListElements; 4845 BOOLEAN found; 4846 4847 partitionCount = ((partitionList->PartitionCount + 3) / 4) * 4; 4848 4849 // 4850 // Zero all of the partition numbers. 4851 // 4852 4853 for (partition = 0; partition < partitionCount; partition++) { 4854 partitionEntry = &partitionList->PartitionEntry[partition]; 4855 partitionEntry->PartitionNumber = 0; 4856 } 4857 4858 // 4859 // Walk through chain of partitions for this disk to determine 4860 // which existing partitions have no match. 4861 // 4862 4863 deviceExtension = physicalExtension; 4864 diskData = (PDISK_DATA)(deviceExtension + 1); 4865 lastPartition = 0; 4866 4867 do { 4868 4869 deviceExtension = diskData->NextPartition; 4870 4871 // 4872 // Check if this is the last partition in the chain. 4873 // 4874 4875 if (!deviceExtension) { 4876 break; 4877 } 4878 4879 // 4880 // Get the partition device extension from disk data. 4881 // 4882 4883 diskData = (PDISK_DATA)(deviceExtension + 1); 4884 4885 // 4886 // Check for highest partition number this far. 4887 // 4888 4889 if (diskData->PartitionNumber > lastPartition) { 4890 lastPartition = diskData->PartitionNumber; 4891 } 4892 4893 // 4894 // Check if this partition is not currently being used. 4895 // 4896 4897 if (!deviceExtension->PartitionLength.QuadPart) { 4898 continue; 4899 } 4900 4901 // 4902 // Loop through partition information to look for match. 4903 // 4904 4905 found = FALSE; 4906 partitionOrdinal = 0; 4907 4908 for (partition = 0; partition < partitionCount; partition++) { 4909 4910 // 4911 // Get partition descriptor. 4912 // 4913 4914 partitionEntry = &partitionList->PartitionEntry[partition]; 4915 4916 // 4917 // Check if empty, or describes extended partition or hasn't changed. 4918 // 4919 4920 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED || 4921 IsContainerPartition(partitionEntry->PartitionType)) { 4922 continue; 4923 } 4924 4925 // 4926 // Advance partition ordinal. 4927 // 4928 4929 partitionOrdinal++; 4930 4931 // 4932 // Check if new partition starts where this partition starts. 4933 // 4934 4935 if (partitionEntry->StartingOffset.QuadPart != 4936 deviceExtension->StartingOffset.QuadPart) { 4937 continue; 4938 } 4939 4940 // 4941 // Check if partition length is the same. 4942 // 4943 4944 if (partitionEntry->PartitionLength.QuadPart == 4945 deviceExtension->PartitionLength.QuadPart) { 4946 4947 DebugPrint((3, 4948 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n", 4949 physicalExtension->DeviceNumber, 4950 diskData->PartitionNumber)); 4951 4952 // 4953 // Indicate match is found and set partition number 4954 // in user buffer. 4955 // 4956 4957 found = TRUE; 4958 partitionEntry->PartitionNumber = diskData->PartitionNumber; 4959 break; 4960 } 4961 } 4962 4963 if (found) { 4964 4965 // 4966 // A match is found. 4967 // 4968 4969 diskData = (PDISK_DATA)(deviceExtension + 1); 4970 4971 // 4972 // If this partition is marked for update then update partition type. 4973 // 4974 4975 if (partitionEntry->RewritePartition) { 4976 diskData->PartitionType = partitionEntry->PartitionType; 4977 } 4978 4979 // 4980 // Update partitional ordinal for calls to HAL routine 4981 // IoSetPartitionInformation. 4982 // 4983 4984 diskData->PartitionOrdinal = partitionOrdinal; 4985 4986 DebugPrint((1, 4987 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n", 4988 physicalExtension->DeviceNumber, 4989 diskData->PartitionOrdinal, 4990 diskData->PartitionNumber)); 4991 4992 } else { 4993 4994 // 4995 // no match was found, indicate this partition is gone. 4996 // 4997 4998 DebugPrint((1, 4999 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n", 5000 physicalExtension->DeviceNumber, 5001 diskData->PartitionNumber)); 5002 5003 deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0; 5004 } 5005 5006 } while (TRUE); 5007 5008 // 5009 // Walk through partition loop to find new partitions and set up 5010 // device extensions to describe them. In some cases new device 5011 // objects will be created. 5012 // 5013 5014 partitionOrdinal = 0; 5015 5016 for (partition = 0; 5017 partition < partitionCount; 5018 partition++) { 5019 5020 // 5021 // Get partition descriptor. 5022 // 5023 5024 partitionEntry = &partitionList->PartitionEntry[partition]; 5025 5026 // 5027 // Check if empty, or describes an extended partition. 5028 // 5029 5030 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED || 5031 IsContainerPartition(partitionEntry->PartitionType)) { 5032 continue; 5033 } 5034 5035 // 5036 // Keep track of position on the disk for calls to IoSetPartitionInformation. 5037 // 5038 5039 partitionOrdinal++; 5040 5041 // 5042 // Check if this entry should be rewritten. 5043 // 5044 5045 if (!partitionEntry->RewritePartition) { 5046 continue; 5047 } 5048 5049 if (partitionEntry->PartitionNumber) { 5050 5051 // 5052 // Partition is an exact match with an existing partition, but is 5053 // being written anyway. 5054 // 5055 5056 continue; 5057 } 5058 5059 // 5060 // Check first if existing device object is available by 5061 // walking partition extension list. 5062 // 5063 5064 partitionNumber = 0; 5065 deviceExtension = physicalExtension; 5066 diskData = (PDISK_DATA)(deviceExtension + 1); 5067 5068 do { 5069 5070 // 5071 // Get next partition device extension from disk data. 5072 // 5073 5074 deviceExtension = diskData->NextPartition; 5075 5076 if (!deviceExtension) { 5077 break; 5078 } 5079 5080 diskData = (PDISK_DATA)(deviceExtension + 1); 5081 5082 // 5083 // A device object is free if the partition length is set to zero. 5084 // 5085 5086 if (!deviceExtension->PartitionLength.QuadPart) { 5087 partitionNumber = diskData->PartitionNumber; 5088 break; 5089 } 5090 5091 } while (TRUE); 5092 5093 // 5094 // If partition number is still zero then a new device object 5095 // must be created. 5096 // 5097 5098 if (partitionNumber == 0) { 5099 5100 lastPartition++; 5101 partitionNumber = lastPartition; 5102 5103 // 5104 // Get or create partition object and set up partition parameters. 5105 // 5106 5107 sprintf(ntNameBuffer, 5108 "\\Device\\Harddisk%lu\\Partition%lu", 5109 physicalExtension->DeviceNumber, 5110 partitionNumber); 5111 5112 RtlInitString(&ntNameString, 5113 ntNameBuffer); 5114 5115 status = RtlAnsiStringToUnicodeString(&ntUnicodeString, 5116 &ntNameString, 5117 TRUE); 5118 5119 if (!NT_SUCCESS(status)) { 5120 continue; 5121 } 5122 5123 DebugPrint((3, 5124 "UpdateDeviceObjects: Create device object %s\n", 5125 ntNameBuffer)); 5126 5127 // 5128 // This is a new name. Create the device object to represent it. 5129 // 5130 5131 status = IoCreateDevice(PhysicalDisk->DriverObject, 5132 DEVICE_EXTENSION_SIZE, 5133 &ntUnicodeString, 5134 FILE_DEVICE_DISK, 5135 0, 5136 FALSE, 5137 &deviceObject); 5138 5139 if (!NT_SUCCESS(status)) { 5140 DebugPrint((1, 5141 "UpdateDeviceObjects: Can't create device %s\n", 5142 ntNameBuffer)); 5143 RtlFreeUnicodeString(&ntUnicodeString); 5144 continue; 5145 } 5146 5147 // 5148 // Set up device object fields. 5149 // 5150 5151 deviceObject->Flags |= DO_DIRECT_IO; 5152 deviceObject->StackSize = PhysicalDisk->StackSize; 5153 5154 // 5155 // Set up device extension fields. 5156 // 5157 5158 deviceExtension = deviceObject->DeviceExtension; 5159 5160 // 5161 // Copy physical disk extension to partition extension. 5162 // 5163 5164 RtlMoveMemory(deviceExtension, 5165 physicalExtension, 5166 sizeof(DEVICE_EXTENSION)); 5167 5168 // 5169 // Initialize the new S-List. 5170 // 5171 5172 if (deviceExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) { 5173 numberListElements = 30; 5174 } else { 5175 numberListElements = 8; 5176 } 5177 5178 // 5179 // Build the lookaside list for srb's for this partition based on 5180 // whether the adapter and disk can do tagged queueing. 5181 // 5182 5183 ScsiClassInitializeSrbLookasideList(deviceExtension, 5184 numberListElements); 5185 5186 // 5187 // Allocate spinlock for zoning for split-request completion. 5188 // 5189 5190 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock); 5191 5192 // 5193 // Write back partition number used in creating object name. 5194 // 5195 5196 partitionEntry->PartitionNumber = partitionNumber; 5197 5198 // 5199 // Clear flags initializing bit. 5200 // 5201 5202 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 5203 5204 // 5205 // Point back at device object. 5206 // 5207 5208 deviceExtension->DeviceObject = deviceObject; 5209 5210 RtlFreeUnicodeString(&ntUnicodeString); 5211 5212 // 5213 // Link to end of partition chain using previous disk data. 5214 // 5215 5216 diskData->NextPartition = deviceExtension; 5217 5218 // 5219 // Get new disk data and zero next partition pointer. 5220 // 5221 5222 diskData = (PDISK_DATA)(deviceExtension + 1); 5223 diskData->NextPartition = NULL; 5224 5225 } else { 5226 5227 // 5228 // Set pointer to disk data area that follows device extension. 5229 // 5230 5231 diskData = (PDISK_DATA)(deviceExtension + 1); 5232 5233 DebugPrint((1, 5234 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n", 5235 physicalExtension->DeviceNumber, 5236 partitionNumber)); 5237 } 5238 5239 // 5240 // Update partition information in partition device extension. 5241 // 5242 5243 diskData->PartitionNumber = partitionNumber; 5244 diskData->PartitionType = partitionEntry->PartitionType; 5245 diskData->BootIndicator = partitionEntry->BootIndicator; 5246 deviceExtension->StartingOffset = partitionEntry->StartingOffset; 5247 deviceExtension->PartitionLength = partitionEntry->PartitionLength; 5248 diskData->HiddenSectors = partitionEntry->HiddenSectors; 5249 diskData->PartitionOrdinal = partitionOrdinal; 5250 5251 DebugPrint((1, 5252 "UpdateDeviceObjects: Ordinal %d is partition %d\n", 5253 diskData->PartitionOrdinal, 5254 diskData->PartitionNumber)); 5255 5256 // 5257 // Update partition number passed in to indicate the 5258 // device name for this partition. 5259 // 5260 5261 partitionEntry->PartitionNumber = partitionNumber; 5262 } 5263 5264 } // end UpdateDeviceObjects() 5265 5266