Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendisk.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Storage Stack 00003 * LICENSE: DDK - see license.txt in the root dir 00004 * FILE: drivers/storage/disk/disk.c 00005 * PURPOSE: Disk class driver 00006 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK 00007 */ 00008 00009 #include <ntddk.h> 00010 #include <ntdddisk.h> 00011 #include <scsi.h> 00012 #include <ntddscsi.h> 00013 #include <mountdev.h> 00014 #include <mountmgr.h> 00015 #include <include/class2.h> 00016 #include <stdio.h> 00017 00018 #define NDEBUG 00019 #include <debug.h> 00020 00021 #define IO_WRITE_CACHE_ENABLED ((NTSTATUS)0x80040020L) 00022 #define IO_WRITE_CACHE_DISABLED ((NTSTATUS)0x80040022L) 00023 00024 #ifdef POOL_TAGGING 00025 #ifdef ExAllocatePool 00026 #undef ExAllocatePool 00027 #endif 00028 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'DscS') 00029 #endif 00030 00031 typedef enum { 00032 NotInitialized, 00033 Initializing, 00034 Initialized 00035 } PARTITION_LIST_STATE; 00036 00037 // 00038 // Disk device data 00039 // 00040 00041 typedef struct _DISK_DATA { 00042 00043 // 00044 // Partition chain 00045 // 00046 00047 PDEVICE_EXTENSION NextPartition; 00048 00049 // 00050 // Disk signature (from MBR) 00051 // 00052 00053 ULONG Signature; 00054 00055 // 00056 // MBR checksum 00057 // 00058 00059 ULONG MbrCheckSum; 00060 00061 // 00062 // Number of hidden sectors for BPB. 00063 // 00064 00065 ULONG HiddenSectors; 00066 00067 // 00068 // Partition number of this device object 00069 // 00070 // This field is set during driver initialization or when the partition 00071 // is created to identify a parition to the system. 00072 // 00073 00074 ULONG PartitionNumber; 00075 00076 // 00077 // This field is the ordinal of a partition as it appears on a disk. 00078 // 00079 00080 ULONG PartitionOrdinal; 00081 00082 // 00083 // Partition type of this device object 00084 // 00085 // This field is set by: 00086 // 00087 // 1) Initially set according to the partition list entry partition 00088 // type returned by IoReadPartitionTable. 00089 // 00090 // 2) Subsequently set by the IOCTL_DISK_SET_PARTITION_INFORMATION 00091 // I/O control function when IoSetPartitionInformation function 00092 // successfully updates the partition type on the disk. 00093 // 00094 00095 UCHAR PartitionType; 00096 00097 // 00098 // Boot indicator - indicates whether this partition is a bootable (active) 00099 // partition for this device 00100 // 00101 // This field is set according to the partition list entry boot indicator 00102 // returned by IoReadPartitionTable. 00103 // 00104 00105 BOOLEAN BootIndicator; 00106 00107 // 00108 // DriveNotReady - inidicates that the this device is currenly not ready 00109 // because there is no media in the device. 00110 // 00111 00112 BOOLEAN DriveNotReady; 00113 00114 // 00115 // State of PartitionList initialization 00116 // 00117 00118 PARTITION_LIST_STATE PartitionListState; 00119 00120 } DISK_DATA, *PDISK_DATA; 00121 00122 // 00123 // Define a general structure of identfing disk controllers with bad 00124 // hardware. 00125 // 00126 00127 typedef struct _BAD_CONTROLLER_INFORMATION { 00128 PCHAR InquiryString; 00129 BOOLEAN DisableTaggedQueuing; 00130 BOOLEAN DisableSynchronousTransfers; 00131 BOOLEAN DisableDisconnects; 00132 BOOLEAN DisableWriteCache; 00133 }BAD_CONTROLLER_INFORMATION, *PBAD_CONTROLLER_INFORMATION; 00134 00135 BAD_CONTROLLER_INFORMATION const ScsiDiskBadControllers[] = { 00136 { "TOSHIBA MK538FB 60", TRUE, FALSE, FALSE, FALSE }, 00137 { "CONNER CP3500", FALSE, TRUE, FALSE, FALSE }, 00138 { "OLIVETTICP3500", FALSE, TRUE, FALSE, FALSE }, 00139 { "SyQuest SQ5110 CHC", TRUE, TRUE, FALSE, FALSE }, 00140 { "SEAGATE ST41601N 0102", FALSE, TRUE, FALSE, FALSE }, 00141 { "SEAGATE ST3655N", FALSE, FALSE, FALSE, TRUE }, 00142 { "SEAGATE ST3390N", FALSE, FALSE, FALSE, TRUE }, 00143 { "SEAGATE ST12550N", FALSE, FALSE, FALSE, TRUE }, 00144 { "SEAGATE ST32430N", FALSE, FALSE, FALSE, TRUE }, 00145 { "SEAGATE ST31230N", FALSE, FALSE, FALSE, TRUE }, 00146 { "SEAGATE ST15230N", FALSE, FALSE, FALSE, TRUE }, 00147 { "FUJITSU M2652S-512", TRUE, FALSE, FALSE, FALSE }, 00148 { "MAXTOR MXT-540SL I1.2", TRUE, FALSE, FALSE, FALSE }, 00149 { "COMPAQ PD-1", FALSE, TRUE, FALSE, FALSE } 00150 }; 00151 00152 00153 #define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION)) 00154 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA) 00155 00156 #define MODE_DATA_SIZE 192 00157 #define VALUE_BUFFER_SIZE 2048 00158 #define SCSI_DISK_TIMEOUT 10 00159 #define PARTITION0_LIST_SIZE 4 00160 00161 00162 NTSTATUS 00163 NTAPI 00164 DriverEntry( 00165 IN PDRIVER_OBJECT DriverObject, 00166 IN PUNICODE_STRING RegistryPath 00167 ); 00168 00169 BOOLEAN 00170 NTAPI 00171 ScsiDiskDeviceVerification( 00172 IN PINQUIRYDATA InquiryData 00173 ); 00174 00175 BOOLEAN 00176 NTAPI 00177 FindScsiDisks( 00178 IN PDRIVER_OBJECT DriveObject, 00179 IN PUNICODE_STRING RegistryPath, 00180 IN PCLASS_INIT_DATA InitializationData, 00181 IN PDEVICE_OBJECT PortDeviceObject, 00182 IN ULONG PortNumber 00183 ); 00184 00185 NTSTATUS 00186 NTAPI 00187 ScsiDiskCreateClose ( 00188 IN PDEVICE_OBJECT DeviceObject, 00189 IN PIRP Irp 00190 ); 00191 00192 NTSTATUS 00193 NTAPI 00194 ScsiDiskReadWriteVerification( 00195 IN PDEVICE_OBJECT DeviceObject, 00196 IN PIRP Irp 00197 ); 00198 00199 NTSTATUS 00200 NTAPI 00201 ScsiDiskDeviceControl( 00202 IN PDEVICE_OBJECT DeviceObject, 00203 IN PIRP Irp 00204 ); 00205 00206 VOID 00207 NTAPI 00208 ScsiDiskProcessError( 00209 PDEVICE_OBJECT DeviceObject, 00210 PSCSI_REQUEST_BLOCK Srb, 00211 NTSTATUS *Status, 00212 BOOLEAN *Retry 00213 ); 00214 00215 NTSTATUS 00216 NTAPI 00217 ScsiDiskShutdownFlush( 00218 IN PDEVICE_OBJECT DeviceObject, 00219 IN PIRP Irp 00220 ); 00221 00222 VOID 00223 NTAPI 00224 DisableWriteCache( 00225 IN PDEVICE_OBJECT DeviceObject, 00226 IN PSCSI_INQUIRY_DATA LunInfo 00227 ); 00228 00229 BOOLEAN 00230 NTAPI 00231 ScsiDiskModeSelect( 00232 IN PDEVICE_OBJECT DeviceObject, 00233 IN PCHAR ModeSelectBuffer, 00234 IN ULONG Length, 00235 IN BOOLEAN SavePage 00236 ); 00237 00238 BOOLEAN 00239 NTAPI 00240 IsFloppyDevice( 00241 IN PDEVICE_OBJECT DeviceObject 00242 ); 00243 00244 BOOLEAN 00245 NTAPI 00246 CalculateMbrCheckSum( 00247 IN PDEVICE_EXTENSION DeviceExtension, 00248 OUT PULONG Checksum 00249 ); 00250 00251 BOOLEAN 00252 NTAPI 00253 EnumerateBusKey( 00254 IN PDEVICE_EXTENSION DeviceExtension, 00255 HANDLE BusKey, 00256 PULONG DiskNumber 00257 ); 00258 00259 VOID 00260 NTAPI 00261 UpdateGeometry( 00262 IN PDEVICE_EXTENSION DeviceExtension 00263 ); 00264 00265 NTSTATUS 00266 NTAPI 00267 UpdateRemovableGeometry ( 00268 IN PDEVICE_OBJECT DeviceObject, 00269 IN PIRP Irp 00270 ); 00271 00272 NTSTATUS 00273 NTAPI 00274 CreateDiskDeviceObject( 00275 IN PDRIVER_OBJECT DriverObject, 00276 IN PUNICODE_STRING RegistryPath, 00277 IN PDEVICE_OBJECT PortDeviceObject, 00278 IN ULONG PortNumber, 00279 IN PULONG DeviceCount, 00280 IN PIO_SCSI_CAPABILITIES PortCapabilities, 00281 IN PSCSI_INQUIRY_DATA LunInfo, 00282 IN PCLASS_INIT_DATA InitData 00283 ); 00284 00285 NTSTATUS 00286 NTAPI 00287 CreatePartitionDeviceObjects( 00288 IN PDEVICE_OBJECT PhysicalDeviceObject, 00289 IN PUNICODE_STRING RegistryPath 00290 ); 00291 00292 VOID 00293 NTAPI 00294 UpdateDeviceObjects( 00295 IN PDEVICE_OBJECT DeviceObject, 00296 IN PIRP Irp 00297 ); 00298 00299 VOID 00300 NTAPI 00301 ScanForSpecial( 00302 PDEVICE_OBJECT DeviceObject, 00303 PSCSI_INQUIRY_DATA LunInfo, 00304 PIO_SCSI_CAPABILITIES PortCapabilities 00305 ); 00306 00307 VOID 00308 NTAPI 00309 ResetScsiBus( 00310 IN PDEVICE_OBJECT DeviceObject 00311 ); 00312 00313 #ifdef ALLOC_PRAGMA 00314 #pragma alloc_text(PAGE, DriverEntry) 00315 #pragma alloc_text(PAGE, FindScsiDisks) 00316 #pragma alloc_text(PAGE, CreateDiskDeviceObject) 00317 #pragma alloc_text(PAGE, CalculateMbrCheckSum) 00318 #pragma alloc_text(PAGE, EnumerateBusKey) 00319 #pragma alloc_text(PAGE, UpdateGeometry) 00320 #pragma alloc_text(PAGE, IsFloppyDevice) 00321 #pragma alloc_text(PAGE, ScanForSpecial) 00322 #pragma alloc_text(PAGE, ScsiDiskDeviceControl) 00323 #pragma alloc_text(PAGE, ScsiDiskModeSelect) 00324 #endif 00325 00326 00327 NTSTATUS 00328 NTAPI 00329 DriverEntry( 00330 IN PDRIVER_OBJECT DriverObject, 00331 IN PUNICODE_STRING RegistryPath 00332 ) 00333 00334 /*++ 00335 00336 Routine Description: 00337 00338 This routine initializes the SCSI hard disk class driver. 00339 00340 Arguments: 00341 00342 DriverObject - Pointer to driver object created by system. 00343 00344 RegistryPath - Pointer to the name of the services node for this driver. 00345 00346 Return Value: 00347 00348 The function value is the final status from the initialization operation. 00349 00350 --*/ 00351 00352 { 00353 CLASS_INIT_DATA InitializationData; 00354 00355 // 00356 // Zero InitData 00357 // 00358 00359 RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA)); 00360 00361 // 00362 // Set sizes 00363 // 00364 00365 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA); 00366 InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE; 00367 00368 InitializationData.DeviceType = FILE_DEVICE_DISK; 00369 InitializationData.DeviceCharacteristics = 0; 00370 00371 // 00372 // Set entry points 00373 // 00374 00375 InitializationData.ClassError = ScsiDiskProcessError; 00376 InitializationData.ClassReadWriteVerification = ScsiDiskReadWriteVerification; 00377 InitializationData.ClassFindDevices = FindScsiDisks; 00378 InitializationData.ClassFindDeviceCallBack = ScsiDiskDeviceVerification; 00379 InitializationData.ClassDeviceControl = ScsiDiskDeviceControl; 00380 InitializationData.ClassShutdownFlush = ScsiDiskShutdownFlush; 00381 InitializationData.ClassCreateClose = NULL; 00382 00383 // 00384 // Call the class init routine 00385 // 00386 00387 return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData); 00388 00389 } // end DriverEntry() 00390 00391 00392 00393 BOOLEAN 00394 NTAPI 00395 ScsiDiskDeviceVerification( 00396 IN PINQUIRYDATA InquiryData 00397 ) 00398 00399 /*++ 00400 00401 Routine Description: 00402 00403 This routine checks InquiryData for the correct device type and qualifier. 00404 00405 Arguments: 00406 00407 InquiryData - Pointer to the inquiry data for the device in question. 00408 00409 Return Value: 00410 00411 True is returned if the correct device type is found. 00412 00413 --*/ 00414 { 00415 00416 if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) || 00417 (InquiryData->DeviceType == OPTICAL_DEVICE)) && 00418 InquiryData->DeviceTypeQualifier == 0) { 00419 00420 return TRUE; 00421 00422 } else { 00423 return FALSE; 00424 } 00425 } 00426 00427 00428 BOOLEAN 00429 NTAPI 00430 FindScsiDisks( 00431 IN PDRIVER_OBJECT DriverObject, 00432 IN PUNICODE_STRING RegistryPath, 00433 IN PCLASS_INIT_DATA InitializationData, 00434 IN PDEVICE_OBJECT PortDeviceObject, 00435 IN ULONG PortNumber 00436 ) 00437 00438 /*++ 00439 00440 Routine Description: 00441 00442 This routine gets a port drivers capabilities, obtains the 00443 inquiry data, searches the SCSI bus for the port driver and creates 00444 the device objects for the disks found. 00445 00446 Arguments: 00447 00448 DriverObject - Pointer to driver object created by system. 00449 00450 PortDeviceObject - Device object use to send requests to port driver. 00451 00452 PortNumber - Number for port driver. Used to pass on to 00453 CreateDiskDeviceObjects() and create device objects. 00454 00455 Return Value: 00456 00457 True is returned if one disk was found and successfully created. 00458 00459 --*/ 00460 00461 { 00462 PIO_SCSI_CAPABILITIES portCapabilities; 00463 PULONG diskCount; 00464 PCONFIGURATION_INFORMATION configurationInformation; 00465 PCHAR buffer; 00466 PSCSI_INQUIRY_DATA lunInfo; 00467 PSCSI_ADAPTER_BUS_INFO adapterInfo; 00468 PINQUIRYDATA inquiryData; 00469 ULONG scsiBus; 00470 ULONG adapterDisk; 00471 NTSTATUS status; 00472 BOOLEAN foundOne = FALSE; 00473 00474 PAGED_CODE(); 00475 00476 // 00477 // Call port driver to get adapter capabilities. 00478 // 00479 00480 status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities); 00481 00482 if (!NT_SUCCESS(status)) { 00483 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n")); 00484 return(FALSE); 00485 } 00486 00487 // 00488 // Call port driver to get inquiry information to find disks. 00489 // 00490 00491 status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer); 00492 00493 if (!NT_SUCCESS(status)) { 00494 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n")); 00495 return(FALSE); 00496 } 00497 00498 // 00499 // Do a quick scan of the devices on this adapter to determine how many 00500 // disks are on this adapter. This is used to determine the number of 00501 // SRB zone elements to allocate. 00502 // 00503 00504 adapterDisk = 0; 00505 adapterInfo = (PVOID) buffer; 00506 00507 adapterDisk = ScsiClassFindUnclaimedDevices(InitializationData, adapterInfo); 00508 00509 // 00510 // Allocate a zone of SRB for disks on this adapter. 00511 // 00512 00513 if (adapterDisk == 0) { 00514 00515 // 00516 // No free disks were found. 00517 // 00518 00519 return(FALSE); 00520 } 00521 00522 // 00523 // Get the number of disks already initialized. 00524 // 00525 00526 configurationInformation = IoGetConfigurationInformation(); 00527 diskCount = &configurationInformation->DiskCount; 00528 00529 // 00530 // For each SCSI bus this adapter supports ... 00531 // 00532 00533 for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) { 00534 00535 // 00536 // Get the SCSI bus scan data for this bus. 00537 // 00538 00539 lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset); 00540 00541 // 00542 // Search list for unclaimed disk devices. 00543 // 00544 00545 while (adapterInfo->BusData[scsiBus].InquiryDataOffset) { 00546 00547 inquiryData = (PVOID)lunInfo->InquiryData; 00548 00549 if (((inquiryData->DeviceType == DIRECT_ACCESS_DEVICE) || 00550 (inquiryData->DeviceType == OPTICAL_DEVICE)) && 00551 inquiryData->DeviceTypeQualifier == 0 && 00552 (!lunInfo->DeviceClaimed)) { 00553 00554 DebugPrint((1, 00555 "FindScsiDevices: Vendor string is %.24s\n", 00556 inquiryData->VendorId)); 00557 00558 // 00559 // Create device objects for disk 00560 // 00561 00562 status = CreateDiskDeviceObject(DriverObject, 00563 RegistryPath, 00564 PortDeviceObject, 00565 PortNumber, 00566 diskCount, 00567 portCapabilities, 00568 lunInfo, 00569 InitializationData); 00570 00571 if (NT_SUCCESS(status)) { 00572 00573 // 00574 // Increment system disk device count. 00575 // 00576 00577 (*diskCount)++; 00578 foundOne = TRUE; 00579 00580 } 00581 } 00582 00583 // 00584 // Get next LunInfo. 00585 // 00586 00587 if (lunInfo->NextInquiryDataOffset == 0) { 00588 break; 00589 } 00590 00591 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset); 00592 00593 } 00594 } 00595 00596 // 00597 // Buffer is allocated by ScsiClassGetInquiryData and must be free returning. 00598 // 00599 00600 ExFreePool(buffer); 00601 00602 return(foundOne); 00603 00604 } // end FindScsiDisks() 00605 00606 00607 NTSTATUS 00608 NTAPI 00609 CreateDiskDeviceObject( 00610 IN PDRIVER_OBJECT DriverObject, 00611 IN PUNICODE_STRING RegistryPath, 00612 IN PDEVICE_OBJECT PortDeviceObject, 00613 IN ULONG PortNumber, 00614 IN PULONG DeviceCount, 00615 IN PIO_SCSI_CAPABILITIES PortCapabilities, 00616 IN PSCSI_INQUIRY_DATA LunInfo, 00617 IN PCLASS_INIT_DATA InitData 00618 ) 00619 00620 /*++ 00621 00622 Routine Description: 00623 00624 This routine creates an object for the physical device and then searches 00625 the device for partitions and creates an object for each partition. 00626 00627 Arguments: 00628 00629 DriverObject - Pointer to driver object created by system. 00630 00631 PortDeviceObject - Miniport device object. 00632 00633 PortNumber - port number. Used in creating disk objects. 00634 00635 DeviceCount - Number of previously installed devices. 00636 00637 PortCapabilities - Capabilities of this SCSI port. 00638 00639 LunInfo - LUN specific information. 00640 00641 Return Value: 00642 00643 NTSTATUS 00644 00645 --*/ 00646 { 00647 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH]; 00648 STRING ntNameString; 00649 UNICODE_STRING ntUnicodeString; 00650 OBJECT_ATTRIBUTES objectAttributes; 00651 HANDLE handle; 00652 NTSTATUS status; 00653 PDEVICE_OBJECT deviceObject = NULL; 00654 //PDEVICE_OBJECT physicalDevice; 00655 PDISK_GEOMETRY_EX diskGeometry = NULL; 00656 PDEVICE_EXTENSION deviceExtension = NULL; 00657 //PDEVICE_EXTENSION physicalDeviceExtension; 00658 UCHAR pathId = LunInfo->PathId; 00659 UCHAR targetId = LunInfo->TargetId; 00660 UCHAR lun = LunInfo->Lun; 00661 //BOOLEAN writeCache; 00662 PVOID senseData = NULL; 00663 //ULONG srbFlags; 00664 ULONG timeOut = 0; 00665 BOOLEAN srbListInitialized = FALSE; 00666 00667 00668 PAGED_CODE(); 00669 00670 // 00671 // Set up an object directory to contain the objects for this 00672 // device and all its partitions. 00673 // 00674 00675 sprintf(ntNameBuffer, 00676 "\\Device\\Harddisk%lu", 00677 *DeviceCount); 00678 00679 RtlInitString(&ntNameString, 00680 ntNameBuffer); 00681 00682 status = RtlAnsiStringToUnicodeString(&ntUnicodeString, 00683 &ntNameString, 00684 TRUE); 00685 00686 if (!NT_SUCCESS(status)) { 00687 return(status); 00688 } 00689 00690 InitializeObjectAttributes(&objectAttributes, 00691 &ntUnicodeString, 00692 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, 00693 NULL, 00694 NULL); 00695 00696 status = ZwCreateDirectoryObject(&handle, 00697 DIRECTORY_ALL_ACCESS, 00698 &objectAttributes); 00699 00700 RtlFreeUnicodeString(&ntUnicodeString); 00701 00702 if (!NT_SUCCESS(status)) { 00703 00704 DebugPrint((1, 00705 "CreateDiskDeviceObjects: Could not create directory %s\n", 00706 ntNameBuffer)); 00707 00708 return(status); 00709 } 00710 00711 // 00712 // Claim the device. 00713 // 00714 00715 status = ScsiClassClaimDevice(PortDeviceObject, 00716 LunInfo, 00717 FALSE, 00718 &PortDeviceObject); 00719 00720 if (!NT_SUCCESS(status)) { 00721 ZwMakeTemporaryObject(handle); 00722 ZwClose(handle); 00723 return status; 00724 } 00725 00726 // 00727 // Create a device object for this device. Each physical disk will 00728 // have at least one device object. The required device object 00729 // describes the entire device. Its directory path is 00730 // \Device\HarddiskN\Partition0, where N = device number. 00731 // 00732 00733 sprintf(ntNameBuffer, 00734 "\\Device\\Harddisk%lu\\Partition0", 00735 *DeviceCount); 00736 00737 00738 status = ScsiClassCreateDeviceObject(DriverObject, 00739 ntNameBuffer, 00740 NULL, 00741 &deviceObject, 00742 InitData); 00743 00744 if (!NT_SUCCESS(status)) { 00745 00746 DebugPrint((1, 00747 "CreateDiskDeviceObjects: Can not create device object %s\n", 00748 ntNameBuffer)); 00749 00750 goto CreateDiskDeviceObjectsExit; 00751 } 00752 00753 // 00754 // Indicate that IRPs should include MDLs for data transfers. 00755 // 00756 00757 deviceObject->Flags |= DO_DIRECT_IO; 00758 00759 // 00760 // Check if this is during initialization. If not indicate that 00761 // system initialization already took place and this disk is ready 00762 // to be accessed. 00763 // 00764 00765 if (!RegistryPath) { 00766 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 00767 } 00768 00769 // 00770 // Check for removable media support. 00771 // 00772 00773 if (((PINQUIRYDATA)LunInfo->InquiryData)->RemovableMedia) { 00774 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA; 00775 } 00776 00777 // 00778 // Set up required stack size in device object. 00779 // 00780 00781 deviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1; 00782 00783 deviceExtension = deviceObject->DeviceExtension; 00784 00785 // 00786 // Allocate spinlock for split request completion. 00787 // 00788 00789 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock); 00790 00791 // 00792 // Initialize lock count to zero. The lock count is used to 00793 // disable the ejection mechanism on devices that support 00794 // removable media. Only the lock count in the physical 00795 // device extension is used. 00796 // 00797 00798 deviceExtension->LockCount = 0; 00799 00800 // 00801 // Save system disk number. 00802 // 00803 00804 deviceExtension->DeviceNumber = *DeviceCount; 00805 00806 // 00807 // Copy port device object pointer to the device extension. 00808 // 00809 00810 deviceExtension->PortDeviceObject = PortDeviceObject; 00811 00812 // 00813 // Set the alignment requirements for the device based on the 00814 // host adapter requirements 00815 // 00816 00817 if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) { 00818 deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement; 00819 } 00820 00821 // 00822 // This is the physical device object. 00823 // 00824 00825 //physicalDevice = deviceObject; 00826 //physicalDeviceExtension = deviceExtension; 00827 00828 // 00829 // Save address of port driver capabilities. 00830 // 00831 00832 deviceExtension->PortCapabilities = PortCapabilities; 00833 00834 // 00835 // Build the lookaside list for srb's for the physical disk. Should only 00836 // need a couple. 00837 // 00838 00839 ScsiClassInitializeSrbLookasideList(deviceExtension, 00840 PARTITION0_LIST_SIZE); 00841 00842 srbListInitialized = TRUE; 00843 00844 // 00845 // Initialize the srb flags. 00846 // 00847 00848 if (((PINQUIRYDATA)LunInfo->InquiryData)->CommandQueue && 00849 PortCapabilities->TaggedQueuing) { 00850 00851 deviceExtension->SrbFlags = SRB_FLAGS_QUEUE_ACTION_ENABLE; 00852 00853 } else { 00854 00855 deviceExtension->SrbFlags = 0; 00856 00857 } 00858 00859 // 00860 // Allow queued requests if this is not removable media. 00861 // 00862 00863 if (!(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) { 00864 00865 deviceExtension->SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE; 00866 00867 } 00868 00869 // 00870 // Look for controller that require special flags. 00871 // 00872 00873 ScanForSpecial(deviceObject, 00874 LunInfo, 00875 PortCapabilities); 00876 00877 //srbFlags = deviceExtension->SrbFlags; 00878 00879 // 00880 // Allocate buffer for drive geometry. 00881 // 00882 00883 diskGeometry = ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY_EX)); 00884 00885 if (diskGeometry == NULL) { 00886 00887 DebugPrint((1, 00888 "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n")); 00889 status = STATUS_INSUFFICIENT_RESOURCES; 00890 goto CreateDiskDeviceObjectsExit; 00891 } 00892 00893 deviceExtension->DiskGeometry = diskGeometry; 00894 00895 // 00896 // Allocate request sense buffer. 00897 // 00898 00899 senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE); 00900 00901 if (senseData == NULL) { 00902 00903 // 00904 // The buffer can not be allocated. 00905 // 00906 00907 DebugPrint((1, 00908 "CreateDiskDeviceObjects: Can not allocate request sense buffer\n")); 00909 00910 status = STATUS_INSUFFICIENT_RESOURCES; 00911 goto CreateDiskDeviceObjectsExit; 00912 } 00913 00914 // 00915 // Set the sense data pointer in the device extension. 00916 // 00917 00918 deviceExtension->SenseData = senseData; 00919 00920 // 00921 // Physical device object will describe the entire 00922 // device, starting at byte offset 0. 00923 // 00924 00925 deviceExtension->StartingOffset.QuadPart = (LONGLONG)(0); 00926 00927 // 00928 // TargetId/LUN describes a device location on the SCSI bus. 00929 // This information comes from the inquiry buffer. 00930 // 00931 00932 deviceExtension->PortNumber = (UCHAR)PortNumber; 00933 deviceExtension->PathId = pathId; 00934 deviceExtension->TargetId = targetId; 00935 deviceExtension->Lun = lun; 00936 00937 // 00938 // Set timeout value in seconds. 00939 // 00940 00941 timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath); 00942 if (timeOut) { 00943 deviceExtension->TimeOutValue = timeOut; 00944 } else { 00945 deviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT; 00946 } 00947 00948 // 00949 // Back pointer to device object. 00950 // 00951 00952 deviceExtension->DeviceObject = deviceObject; 00953 00954 // 00955 // If this is a removable device, then make sure it is not a floppy. 00956 // Perform a mode sense command to determine the media type. Note 00957 // IsFloppyDevice also checks for write cache enabled. 00958 // 00959 00960 if (IsFloppyDevice(deviceObject) && deviceObject->Characteristics & FILE_REMOVABLE_MEDIA && 00961 (((PINQUIRYDATA)LunInfo->InquiryData)->DeviceType == DIRECT_ACCESS_DEVICE)) { 00962 00963 status = STATUS_NO_SUCH_DEVICE; 00964 goto CreateDiskDeviceObjectsExit; 00965 } 00966 00967 DisableWriteCache(deviceObject,LunInfo); 00968 00969 //writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE; 00970 00971 // 00972 // NOTE: At this point one device object has been successfully created. 00973 // from here on out return success. 00974 // 00975 00976 // 00977 // Do READ CAPACITY. This SCSI command 00978 // returns the number of bytes on a device. 00979 // Device extension is updated with device size. 00980 // 00981 00982 status = ScsiClassReadDriveCapacity(deviceObject); 00983 00984 // 00985 // If the read capcity failed then just return, unless this is a 00986 // removable disk where a device object partition needs to be created. 00987 // 00988 00989 if (!NT_SUCCESS(status) && 00990 !(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) { 00991 00992 DebugPrint((1, 00993 "CreateDiskDeviceObjects: Can't read capacity for device %s\n", 00994 ntNameBuffer)); 00995 00996 return(STATUS_SUCCESS); 00997 00998 } else { 00999 01000 // 01001 // Make sure the volume verification bit is off so that 01002 // IoReadPartitionTable will work. 01003 // 01004 01005 deviceObject->Flags &= ~DO_VERIFY_VOLUME; 01006 } 01007 01008 status = CreatePartitionDeviceObjects(deviceObject, RegistryPath); 01009 01010 if (NT_SUCCESS(status)) 01011 return STATUS_SUCCESS; 01012 01013 01014 CreateDiskDeviceObjectsExit: 01015 01016 // 01017 // Release the device since an error occurred. 01018 // 01019 01020 ScsiClassClaimDevice(PortDeviceObject, 01021 LunInfo, 01022 TRUE, 01023 NULL); 01024 01025 if (diskGeometry != NULL) { 01026 ExFreePool(diskGeometry); 01027 } 01028 01029 if (senseData != NULL) { 01030 ExFreePool(senseData); 01031 } 01032 01033 if (deviceObject != NULL) { 01034 01035 if (srbListInitialized) { 01036 ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead); 01037 } 01038 01039 IoDeleteDevice(deviceObject); 01040 } 01041 01042 // 01043 // Delete directory and return. 01044 // 01045 01046 if (!NT_SUCCESS(status)) { 01047 ZwMakeTemporaryObject(handle); 01048 } 01049 01050 ZwClose(handle); 01051 01052 return(status); 01053 01054 } // end CreateDiskDeviceObjects() 01055 01056 01057 NTSTATUS 01058 NTAPI 01059 CreatePartitionDeviceObjects( 01060 IN PDEVICE_OBJECT PhysicalDeviceObject, 01061 IN PUNICODE_STRING RegistryPath 01062 ) 01063 { 01064 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH]; 01065 ULONG partitionNumber = 0; 01066 NTSTATUS status; 01067 PDEVICE_OBJECT deviceObject = NULL; 01068 PDISK_GEOMETRY_EX diskGeometry = NULL; 01069 PDRIVE_LAYOUT_INFORMATION partitionList = NULL; 01070 PDEVICE_EXTENSION deviceExtension; 01071 PDEVICE_EXTENSION physicalDeviceExtension; 01072 PCLASS_INIT_DATA initData = NULL; 01073 PDISK_DATA diskData; 01074 PDISK_DATA physicalDiskData; 01075 ULONG bytesPerSector; 01076 UCHAR sectorShift; 01077 ULONG srbFlags; 01078 ULONG dmByteSkew = 0; 01079 PULONG dmSkew; 01080 BOOLEAN dmActive = FALSE; 01081 ULONG numberListElements = 0; 01082 01083 01084 // 01085 // Get physical device geometry information for partition table reads. 01086 // 01087 01088 physicalDeviceExtension = PhysicalDeviceObject->DeviceExtension; 01089 diskGeometry = physicalDeviceExtension->DiskGeometry; 01090 bytesPerSector = diskGeometry->Geometry.BytesPerSector; 01091 01092 // 01093 // Make sure sector size is not zero. 01094 // 01095 01096 if (bytesPerSector == 0) { 01097 01098 // 01099 // Default sector size for disk is 512. 01100 // 01101 01102 bytesPerSector = diskGeometry->Geometry.BytesPerSector = 512; 01103 } 01104 01105 sectorShift = physicalDeviceExtension->SectorShift; 01106 01107 // 01108 // Set pointer to disk data area that follows device extension. 01109 // 01110 01111 diskData = (PDISK_DATA)(physicalDeviceExtension + 1); 01112 diskData->PartitionListState = Initializing; 01113 01114 // 01115 // Determine is DM Driver is loaded on an IDE drive that is 01116 // under control of Atapi - this could be either a crashdump or 01117 // an Atapi device is sharing the controller with an IDE disk. 01118 // 01119 01120 HalExamineMBR(PhysicalDeviceObject, 01121 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector, 01122 (ULONG)0x54, 01123 (PVOID)&dmSkew); 01124 01125 if (dmSkew) { 01126 01127 // 01128 // Update the device extension, so that the call to IoReadPartitionTable 01129 // will get the correct information. Any I/O to this disk will have 01130 // to be skewed by *dmSkew sectors aka DMByteSkew. 01131 // 01132 01133 physicalDeviceExtension->DMSkew = *dmSkew; 01134 physicalDeviceExtension->DMActive = TRUE; 01135 physicalDeviceExtension->DMByteSkew = physicalDeviceExtension->DMSkew * bytesPerSector; 01136 01137 // 01138 // Save away the infomation that we need, since this deviceExtension will soon be 01139 // blown away. 01140 // 01141 01142 dmActive = TRUE; 01143 dmByteSkew = physicalDeviceExtension->DMByteSkew; 01144 01145 } 01146 01147 // 01148 // Create objects for all the partitions on the device. 01149 // 01150 01151 status = IoReadPartitionTable(PhysicalDeviceObject, 01152 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector, 01153 TRUE, 01154 (PVOID)&partitionList); 01155 01156 // 01157 // If the I/O read partition table failed and this is a removable device, 01158 // then fix up the partition list to make it look like there is one 01159 // zero length partition. 01160 // 01161 DPRINT("IoReadPartitionTable() status: 0x%08X\n", status); 01162 if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) && 01163 PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 01164 01165 if (!NT_SUCCESS(status)) { 01166 01167 // 01168 // Remember this disk is not ready. 01169 // 01170 01171 diskData->DriveNotReady = TRUE; 01172 01173 } else { 01174 01175 // 01176 // Free the partition list allocated by IoReadPartitionTable. 01177 // 01178 01179 ExFreePool(partitionList); 01180 } 01181 01182 // 01183 // Allocate and zero a partition list. 01184 // 01185 01186 partitionList = ExAllocatePool(NonPagedPool, sizeof(*partitionList )); 01187 01188 01189 if (partitionList != NULL) { 01190 01191 RtlZeroMemory( partitionList, sizeof( *partitionList )); 01192 01193 // 01194 // Set the partition count to one and the status to success 01195 // so one device object will be created. Set the partition type 01196 // to a bogus value. 01197 // 01198 01199 partitionList->PartitionCount = 1; 01200 01201 status = STATUS_SUCCESS; 01202 } 01203 } 01204 01205 if (NT_SUCCESS(status)) { 01206 01207 // 01208 // Record disk signature. 01209 // 01210 01211 diskData->Signature = partitionList->Signature; 01212 01213 // 01214 // If disk signature is zero, then calculate the MBR checksum. 01215 // 01216 01217 if (!diskData->Signature) { 01218 01219 if (!CalculateMbrCheckSum(physicalDeviceExtension, 01220 &diskData->MbrCheckSum)) { 01221 01222 DebugPrint((1, 01223 "SCSIDISK: Can't calculate MBR checksum for disk %x\n", 01224 physicalDeviceExtension->DeviceNumber)); 01225 } else { 01226 01227 DebugPrint((2, 01228 "SCSIDISK: MBR checksum for disk %x is %x\n", 01229 physicalDeviceExtension->DeviceNumber, 01230 diskData->MbrCheckSum)); 01231 } 01232 } 01233 01234 // 01235 // Check the registry and determine if the BIOS knew about this drive. If 01236 // it did then update the geometry with the BIOS information. 01237 // 01238 01239 UpdateGeometry(physicalDeviceExtension); 01240 01241 srbFlags = physicalDeviceExtension->SrbFlags; 01242 01243 initData = ExAllocatePool(NonPagedPool, sizeof(CLASS_INIT_DATA)); 01244 if (!initData) 01245 { 01246 DebugPrint((1, 01247 "Disk.CreatePartionDeviceObjects - Allocation of initData failed\n")); 01248 01249 status = STATUS_INSUFFICIENT_RESOURCES; 01250 goto CreatePartitionDeviceObjectsExit; 01251 } 01252 01253 RtlZeroMemory(initData, sizeof(CLASS_INIT_DATA)); 01254 01255 initData->InitializationDataSize = sizeof(CLASS_INIT_DATA); 01256 initData->DeviceExtensionSize = DEVICE_EXTENSION_SIZE; 01257 initData->DeviceType = FILE_DEVICE_DISK; 01258 initData->DeviceCharacteristics = PhysicalDeviceObject->Characteristics; 01259 initData->ClassError = physicalDeviceExtension->ClassError; 01260 initData->ClassReadWriteVerification = physicalDeviceExtension->ClassReadWriteVerification; 01261 initData->ClassFindDevices = physicalDeviceExtension->ClassFindDevices; 01262 initData->ClassDeviceControl = physicalDeviceExtension->ClassDeviceControl; 01263 initData->ClassShutdownFlush = physicalDeviceExtension->ClassShutdownFlush; 01264 initData->ClassCreateClose = physicalDeviceExtension->ClassCreateClose; 01265 initData->ClassStartIo = physicalDeviceExtension->ClassStartIo; 01266 01267 // 01268 // Create device objects for the device partitions (if any). 01269 // PartitionCount includes physical device partition 0, 01270 // so only one partition means no objects to create. 01271 // 01272 01273 DebugPrint((2, 01274 "CreateDiskDeviceObjects: Number of partitions is %d\n", 01275 partitionList->PartitionCount)); 01276 01277 for (partitionNumber = 0; partitionNumber < 01278 partitionList->PartitionCount; partitionNumber++) { 01279 01280 // 01281 // Create partition object and set up partition parameters. 01282 // 01283 01284 sprintf(ntNameBuffer, 01285 "\\Device\\Harddisk%lu\\Partition%lu", 01286 physicalDeviceExtension->DeviceNumber, 01287 partitionNumber + 1); 01288 01289 DebugPrint((2, 01290 "CreateDiskDeviceObjects: Create device object %s\n", 01291 ntNameBuffer)); 01292 01293 status = ScsiClassCreateDeviceObject(PhysicalDeviceObject->DriverObject, 01294 ntNameBuffer, 01295 PhysicalDeviceObject, 01296 &deviceObject, 01297 initData); 01298 01299 if (!NT_SUCCESS(status)) { 01300 01301 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer)); 01302 01303 break; 01304 } 01305 01306 // 01307 // Set up device object fields. 01308 // 01309 01310 deviceObject->Flags |= DO_DIRECT_IO; 01311 01312 // 01313 // Check if this is during initialization. If not indicate that 01314 // system initialization already took place and this disk is ready 01315 // to be accessed. 01316 // 01317 01318 if (!RegistryPath) { 01319 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 01320 } 01321 01322 deviceObject->StackSize = (CCHAR)physicalDeviceExtension->PortDeviceObject->StackSize + 1; 01323 01324 // 01325 // Set up device extension fields. 01326 // 01327 01328 deviceExtension = deviceObject->DeviceExtension; 01329 01330 if (dmActive) { 01331 01332 // 01333 // Restore any saved DM values. 01334 // 01335 01336 deviceExtension->DMByteSkew = dmByteSkew; 01337 deviceExtension->DMSkew = *dmSkew; 01338 deviceExtension->DMActive = TRUE; 01339 01340 } 01341 01342 // 01343 // Link new device extension to previous disk data 01344 // to support dynamic partitioning. 01345 // 01346 01347 diskData->NextPartition = deviceExtension; 01348 01349 // 01350 // Get pointer to new disk data. 01351 // 01352 01353 diskData = (PDISK_DATA)(deviceExtension + 1); 01354 01355 // 01356 // Set next partition pointer to NULL in case this is the 01357 // last partition. 01358 // 01359 01360 diskData->NextPartition = NULL; 01361 01362 // 01363 // Allocate spinlock for zoning for split-request completion. 01364 // 01365 01366 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock); 01367 01368 // 01369 // Copy port device object pointer to device extension. 01370 // 01371 01372 deviceExtension->PortDeviceObject = physicalDeviceExtension->PortDeviceObject; 01373 01374 // 01375 // Set the alignment requirements for the device based on the 01376 // host adapter requirements 01377 // 01378 01379 if (physicalDeviceExtension->PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) { 01380 deviceObject->AlignmentRequirement = physicalDeviceExtension->PortDeviceObject->AlignmentRequirement; 01381 } 01382 01383 01384 if (srbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) { 01385 numberListElements = 30; 01386 } else { 01387 numberListElements = 8; 01388 } 01389 01390 // 01391 // Build the lookaside list for srb's for this partition based on 01392 // whether the adapter and disk can do tagged queueing. 01393 // 01394 01395 ScsiClassInitializeSrbLookasideList(deviceExtension, 01396 numberListElements); 01397 01398 deviceExtension->SrbFlags = srbFlags; 01399 01400 // 01401 // Set the sense-data pointer in the device extension. 01402 // 01403 01404 deviceExtension->SenseData = physicalDeviceExtension->SenseData; 01405 deviceExtension->PortCapabilities = physicalDeviceExtension->PortCapabilities; 01406 deviceExtension->DiskGeometry = diskGeometry; 01407 diskData->PartitionOrdinal = diskData->PartitionNumber = partitionNumber + 1; 01408 diskData->PartitionType = partitionList->PartitionEntry[partitionNumber].PartitionType; 01409 diskData->BootIndicator = partitionList->PartitionEntry[partitionNumber].BootIndicator; 01410 01411 DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n", 01412 diskData->PartitionType)); 01413 01414 deviceExtension->StartingOffset = partitionList->PartitionEntry[partitionNumber].StartingOffset; 01415 deviceExtension->PartitionLength = partitionList->PartitionEntry[partitionNumber].PartitionLength; 01416 diskData->HiddenSectors = partitionList->PartitionEntry[partitionNumber].HiddenSectors; 01417 deviceExtension->PortNumber = physicalDeviceExtension->PortNumber; 01418 deviceExtension->PathId = physicalDeviceExtension->PathId; 01419 deviceExtension->TargetId = physicalDeviceExtension->TargetId; 01420 deviceExtension->Lun = physicalDeviceExtension->Lun; 01421 01422 // 01423 // Check for removable media support. 01424 // 01425 01426 if (PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 01427 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA; 01428 } 01429 01430 // 01431 // Set timeout value in seconds. 01432 // 01433 01434 deviceExtension->TimeOutValue = physicalDeviceExtension->TimeOutValue; 01435 deviceExtension->DiskGeometry->Geometry.BytesPerSector = bytesPerSector; 01436 deviceExtension->SectorShift = sectorShift; 01437 deviceExtension->DeviceObject = deviceObject; 01438 deviceExtension->DeviceFlags |= physicalDeviceExtension->DeviceFlags; 01439 01440 } // end for (partitionNumber) ... 01441 01442 // 01443 // Free the buffer allocated by reading the 01444 // partition table. 01445 // 01446 01447 ExFreePool(partitionList); 01448 01449 } else { 01450 01451 CreatePartitionDeviceObjectsExit: 01452 01453 if (partitionList) { 01454 ExFreePool(partitionList); 01455 } 01456 if (initData) { 01457 ExFreePool(initData); 01458 } 01459 01460 return status; 01461 01462 } // end if...else 01463 01464 01465 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1); 01466 physicalDiskData->PartitionListState = Initialized; 01467 01468 return(STATUS_SUCCESS); 01469 01470 01471 } // end CreatePartitionDeviceObjects() 01472 01473 01474 NTSTATUS 01475 NTAPI 01476 ScsiDiskReadWriteVerification( 01477 IN PDEVICE_OBJECT DeviceObject, 01478 IN PIRP Irp 01479 ) 01480 01481 /*++ 01482 01483 Routine Description: 01484 01485 I/O System entry for read and write requests to SCSI disks. 01486 01487 Arguments: 01488 01489 DeviceObject - Pointer to driver object created by system. 01490 Irp - IRP involved. 01491 01492 Return Value: 01493 01494 NT Status 01495 01496 --*/ 01497 01498 { 01499 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 01500 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 01501 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; 01502 LARGE_INTEGER startingOffset; 01503 01504 // 01505 // Verify parameters of this request. 01506 // Check that ending sector is within partition and 01507 // that number of bytes to transfer is a multiple of 01508 // the sector size. 01509 // 01510 01511 startingOffset.QuadPart = (currentIrpStack->Parameters.Read.ByteOffset.QuadPart + 01512 transferByteCount); 01513 01514 if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) || 01515 (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) { 01516 01517 // 01518 // This error maybe caused by the fact that the drive is not ready. 01519 // 01520 01521 if (((PDISK_DATA)(deviceExtension + 1))->DriveNotReady) { 01522 01523 // 01524 // Flag this as a user errror so that a popup is generated. 01525 // 01526 01527 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY; 01528 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 01529 01530 } else { 01531 01532 // 01533 // Note fastfat depends on this parameter to determine when to 01534 // remount do to a sector size change. 01535 // 01536 01537 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 01538 } 01539 01540 return STATUS_INVALID_PARAMETER; 01541 } 01542 01543 return STATUS_SUCCESS; 01544 01545 } // end ScsiDiskReadWrite() 01546 01547 01548 NTSTATUS 01549 NTAPI 01550 ScsiDiskDeviceControl( 01551 PDEVICE_OBJECT DeviceObject, 01552 PIRP Irp 01553 ) 01554 01555 /*++ 01556 01557 Routine Description: 01558 01559 I/O system entry for device controls to SCSI disks. 01560 01561 Arguments: 01562 01563 DeviceObject - Pointer to driver object created by system. 01564 Irp - IRP involved. 01565 01566 Return Value: 01567 01568 Status is returned. 01569 01570 --*/ 01571 01572 { 01573 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 01574 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 01575 PDISK_DATA diskData = (PDISK_DATA)(deviceExtension + 1); 01576 PSCSI_REQUEST_BLOCK srb; 01577 PCDB cdb; 01578 PMODE_PARAMETER_HEADER modeData; 01579 PIRP irp2; 01580 ULONG length; 01581 NTSTATUS status; 01582 KEVENT event; 01583 IO_STATUS_BLOCK ioStatus; 01584 01585 PAGED_CODE(); 01586 01587 srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE); 01588 01589 if (srb == NULL) { 01590 01591 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 01592 IoCompleteRequest(Irp, IO_NO_INCREMENT); 01593 return(STATUS_INSUFFICIENT_RESOURCES); 01594 } 01595 01596 // 01597 // Write zeros to Srb. 01598 // 01599 01600 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 01601 01602 cdb = (PCDB)srb->Cdb; 01603 01604 switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { 01605 01606 case SMART_GET_VERSION: { 01607 01608 ULONG_PTR buffer; 01609 PSRB_IO_CONTROL srbControl; 01610 PGETVERSIONINPARAMS versionParams; 01611 01612 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 01613 sizeof(GETVERSIONINPARAMS)) { 01614 status = STATUS_INVALID_PARAMETER; 01615 break; 01616 } 01617 01618 // 01619 // Create notification event object to be used to signal the 01620 // request completion. 01621 // 01622 01623 KeInitializeEvent(&event, NotificationEvent, FALSE); 01624 01625 srbControl = ExAllocatePool(NonPagedPool, 01626 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS)); 01627 01628 if (!srbControl) { 01629 status = STATUS_INSUFFICIENT_RESOURCES; 01630 break; 01631 } 01632 01633 // 01634 // fill in srbControl fields 01635 // 01636 01637 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); 01638 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); 01639 srbControl->Timeout = deviceExtension->TimeOutValue; 01640 srbControl->Length = sizeof(GETVERSIONINPARAMS); 01641 srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION; 01642 01643 // 01644 // Point to the 'buffer' portion of the SRB_CONTROL 01645 // 01646 01647 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 01648 01649 // 01650 // Ensure correct target is set in the cmd parameters. 01651 // 01652 01653 versionParams = (PGETVERSIONINPARAMS)buffer; 01654 versionParams->bIDEDeviceMap = deviceExtension->TargetId; 01655 01656 // 01657 // Copy the IOCTL parameters to the srb control buffer area. 01658 // 01659 01660 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(GETVERSIONINPARAMS)); 01661 01662 01663 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT, 01664 deviceExtension->PortDeviceObject, 01665 srbControl, 01666 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS), 01667 srbControl, 01668 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS), 01669 FALSE, 01670 &event, 01671 &ioStatus); 01672 01673 if (irp2 == NULL) { 01674 status = STATUS_INSUFFICIENT_RESOURCES; 01675 break; 01676 } 01677 01678 // 01679 // Call the port driver with the request and wait for it to complete. 01680 // 01681 01682 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2); 01683 01684 if (status == STATUS_PENDING) { 01685 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 01686 status = ioStatus.Status; 01687 } 01688 01689 // 01690 // If successful, copy the data received into the output buffer. 01691 // This should only fail in the event that the IDE driver is older than this driver. 01692 // 01693 01694 if (NT_SUCCESS(status)) { 01695 01696 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 01697 01698 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, sizeof(GETVERSIONINPARAMS)); 01699 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS); 01700 } 01701 01702 ExFreePool(srbControl); 01703 break; 01704 } 01705 01706 case SMART_RCV_DRIVE_DATA: { 01707 01708 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer); 01709 ULONG controlCode = 0; 01710 PSRB_IO_CONTROL srbControl; 01711 ULONG_PTR buffer; 01712 01713 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 01714 (sizeof(SENDCMDINPARAMS) - 1)) { 01715 status = STATUS_INVALID_PARAMETER; 01716 break; 01717 01718 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 01719 (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) { 01720 status = STATUS_INVALID_PARAMETER; 01721 break; 01722 } 01723 01724 // 01725 // Create notification event object to be used to signal the 01726 // request completion. 01727 // 01728 01729 KeInitializeEvent(&event, NotificationEvent, FALSE); 01730 01731 if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) { 01732 01733 length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); 01734 controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY; 01735 01736 } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) { 01737 switch (cmdInParameters->irDriveRegs.bFeaturesReg) { 01738 case READ_ATTRIBUTES: 01739 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; 01740 length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); 01741 break; 01742 case READ_THRESHOLDS: 01743 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; 01744 length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS); 01745 break; 01746 default: 01747 status = STATUS_INVALID_PARAMETER; 01748 break; 01749 } 01750 } else { 01751 01752 status = STATUS_INVALID_PARAMETER; 01753 } 01754 01755 if (controlCode == 0) { 01756 status = STATUS_INVALID_PARAMETER; 01757 break; 01758 } 01759 01760 srbControl = ExAllocatePool(NonPagedPool, 01761 sizeof(SRB_IO_CONTROL) + length); 01762 01763 if (!srbControl) { 01764 status = STATUS_INSUFFICIENT_RESOURCES; 01765 break; 01766 } 01767 01768 // 01769 // fill in srbControl fields 01770 // 01771 01772 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); 01773 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); 01774 srbControl->Timeout = deviceExtension->TimeOutValue; 01775 srbControl->Length = length; 01776 srbControl->ControlCode = controlCode; 01777 01778 // 01779 // Point to the 'buffer' portion of the SRB_CONTROL 01780 // 01781 01782 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 01783 01784 // 01785 // Ensure correct target is set in the cmd parameters. 01786 // 01787 01788 cmdInParameters->bDriveNumber = deviceExtension->TargetId; 01789 01790 // 01791 // Copy the IOCTL parameters to the srb control buffer area. 01792 // 01793 01794 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1); 01795 01796 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT, 01797 deviceExtension->PortDeviceObject, 01798 srbControl, 01799 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1, 01800 srbControl, 01801 sizeof(SRB_IO_CONTROL) + length, 01802 FALSE, 01803 &event, 01804 &ioStatus); 01805 01806 if (irp2 == NULL) { 01807 status = STATUS_INSUFFICIENT_RESOURCES; 01808 break; 01809 } 01810 01811 // 01812 // Call the port driver with the request and wait for it to complete. 01813 // 01814 01815 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2); 01816 01817 if (status == STATUS_PENDING) { 01818 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 01819 status = ioStatus.Status; 01820 } 01821 01822 // 01823 // If successful, copy the data received into the output buffer 01824 // 01825 01826 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 01827 01828 if (NT_SUCCESS(status)) { 01829 01830 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length - 1); 01831 Irp->IoStatus.Information = length - 1; 01832 01833 } else { 01834 01835 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, (sizeof(SENDCMDOUTPARAMS) - 1)); 01836 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1; 01837 01838 } 01839 01840 ExFreePool(srbControl); 01841 break; 01842 01843 } 01844 01845 case SMART_SEND_DRIVE_COMMAND: { 01846 01847 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer); 01848 PSRB_IO_CONTROL srbControl; 01849 ULONG controlCode = 0; 01850 ULONG_PTR buffer; 01851 01852 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 01853 (sizeof(SENDCMDINPARAMS) - 1)) { 01854 status = STATUS_INVALID_PARAMETER; 01855 break; 01856 01857 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 01858 (sizeof(SENDCMDOUTPARAMS) - 1)) { 01859 status = STATUS_INVALID_PARAMETER; 01860 break; 01861 } 01862 01863 // 01864 // Create notification event object to be used to signal the 01865 // request completion. 01866 // 01867 01868 KeInitializeEvent(&event, NotificationEvent, FALSE); 01869 01870 length = 0; 01871 01872 if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) { 01873 switch (cmdInParameters->irDriveRegs.bFeaturesReg) { 01874 01875 case ENABLE_SMART: 01876 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART; 01877 break; 01878 01879 case DISABLE_SMART: 01880 controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART; 01881 break; 01882 01883 case RETURN_SMART_STATUS: 01884 01885 // 01886 // Ensure bBuffer is at least 2 bytes (to hold the values of 01887 // cylinderLow and cylinderHigh). 01888 // 01889 01890 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 01891 (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) { 01892 01893 status = STATUS_INVALID_PARAMETER; 01894 break; 01895 } 01896 01897 controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS; 01898 length = sizeof(IDEREGS); 01899 break; 01900 01901 case ENABLE_DISABLE_AUTOSAVE: 01902 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; 01903 break; 01904 01905 case SAVE_ATTRIBUTE_VALUES: 01906 controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; 01907 break; 01908 01909 case EXECUTE_OFFLINE_DIAGS: 01910 controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; 01911 break; 01912 01913 default: 01914 status = STATUS_INVALID_PARAMETER; 01915 break; 01916 } 01917 } else { 01918 01919 status = STATUS_INVALID_PARAMETER; 01920 } 01921 01922 if (controlCode == 0) { 01923 status = STATUS_INVALID_PARAMETER; 01924 break; 01925 } 01926 01927 length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS); 01928 srbControl = ExAllocatePool(NonPagedPool, 01929 sizeof(SRB_IO_CONTROL) + length); 01930 01931 if (!srbControl) { 01932 status = STATUS_INSUFFICIENT_RESOURCES; 01933 break; 01934 } 01935 01936 // 01937 // fill in srbControl fields 01938 // 01939 01940 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); 01941 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8); 01942 srbControl->Timeout = deviceExtension->TimeOutValue; 01943 srbControl->Length = length; 01944 01945 // 01946 // Point to the 'buffer' portion of the SRB_CONTROL 01947 // 01948 01949 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 01950 01951 // 01952 // Ensure correct target is set in the cmd parameters. 01953 // 01954 01955 cmdInParameters->bDriveNumber = deviceExtension->TargetId; 01956 01957 // 01958 // Copy the IOCTL parameters to the srb control buffer area. 01959 // 01960 01961 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1); 01962 01963 srbControl->ControlCode = controlCode; 01964 01965 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT, 01966 deviceExtension->PortDeviceObject, 01967 srbControl, 01968 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1, 01969 srbControl, 01970 sizeof(SRB_IO_CONTROL) + length, 01971 FALSE, 01972 &event, 01973 &ioStatus); 01974 01975 if (irp2 == NULL) { 01976 status = STATUS_INSUFFICIENT_RESOURCES; 01977 break; 01978 } 01979 01980 // 01981 // Call the port driver with the request and wait for it to complete. 01982 // 01983 01984 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2); 01985 01986 if (status == STATUS_PENDING) { 01987 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 01988 status = ioStatus.Status; 01989 } 01990 01991 // 01992 // Copy the data received into the output buffer. Since the status buffer 01993 // contains error information also, always perform this copy. IO will will 01994 // either pass this back to the app, or zero it, in case of error. 01995 // 01996 01997 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength; 01998 01999 // 02000 // Update the return buffer size based on the sub-command. 02001 // 02002 02003 if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) { 02004 length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS); 02005 } else { 02006 length = sizeof(SENDCMDOUTPARAMS) - 1; 02007 } 02008 02009 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length); 02010 Irp->IoStatus.Information = length; 02011 02012 ExFreePool(srbControl); 02013 break; 02014 02015 } 02016 02017 case IOCTL_DISK_GET_DRIVE_GEOMETRY: 02018 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: 02019 { 02020 02021 PDEVICE_EXTENSION physicalDeviceExtension; 02022 PDISK_DATA physicalDiskData; 02023 BOOLEAN removable = FALSE; 02024 BOOLEAN listInitialized = FALSE; 02025 02026 if ((irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY && 02027 irpStack->Parameters.DeviceIoControl.OutputBufferLength < 02028 sizeof(DISK_GEOMETRY)) || 02029 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX && 02030 irpStack->Parameters.DeviceIoControl.OutputBufferLength < 02031 sizeof(DISK_GEOMETRY_EX))) { 02032 02033 status = STATUS_INFO_LENGTH_MISMATCH; 02034 break; 02035 } 02036 02037 status = STATUS_SUCCESS; 02038 02039 physicalDeviceExtension = deviceExtension->PhysicalDevice->DeviceExtension; 02040 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1); 02041 02042 removable = (BOOLEAN)DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA; 02043 listInitialized = (physicalDiskData->PartitionListState == Initialized); 02044 02045 if (removable || (!listInitialized)) 02046 { 02047 // 02048 // Issue ReadCapacity to update device extension 02049 // with information for current media. 02050 // 02051 02052 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice); 02053 02054 } 02055 02056 if (removable) { 02057 02058 if (!NT_SUCCESS(status)) { 02059 02060 // 02061 // Note the drive is not ready. 02062 // 02063 02064 diskData->DriveNotReady = TRUE; 02065 02066 break; 02067 } 02068 02069 // 02070 // Note the drive is now ready. 02071 // 02072 02073 diskData->DriveNotReady = FALSE; 02074 02075 } else if (NT_SUCCESS(status)) { 02076 02077 // ReadDriveCapacity was allright, create Partition Objects 02078 02079 if (physicalDiskData->PartitionListState == NotInitialized) { 02080 status = CreatePartitionDeviceObjects(deviceExtension->PhysicalDevice, NULL); 02081 } 02082 } 02083 02084 if (NT_SUCCESS(status)) { 02085 02086 // 02087 // Copy drive geometry information from device extension. 02088 // 02089 02090 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, 02091 deviceExtension->DiskGeometry, 02092 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ? 02093 sizeof(DISK_GEOMETRY) : 02094 sizeof(DISK_GEOMETRY_EX)); 02095 02096 status = STATUS_SUCCESS; 02097 Irp->IoStatus.Information = 02098 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ? 02099 sizeof(DISK_GEOMETRY) : 02100 sizeof(DISK_GEOMETRY_EX); 02101 } 02102 02103 break; 02104 02105 } 02106 02107 case IOCTL_DISK_VERIFY: 02108 02109 { 02110 02111 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer; 02112 LARGE_INTEGER byteOffset; 02113 ULONG sectorOffset; 02114 USHORT sectorCount; 02115 02116 // 02117 // Validate buffer length. 02118 // 02119 02120 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 02121 sizeof(VERIFY_INFORMATION)) { 02122 02123 status = STATUS_INFO_LENGTH_MISMATCH; 02124 break; 02125 } 02126 02127 // 02128 // Verify sectors 02129 // 02130 02131 srb->CdbLength = 10; 02132 02133 cdb->CDB10.OperationCode = SCSIOP_VERIFY; 02134 02135 // 02136 // Add disk offset to starting sector. 02137 // 02138 02139 byteOffset.QuadPart = deviceExtension->StartingOffset.QuadPart + 02140 verifyInfo->StartingOffset.QuadPart; 02141 02142 // 02143 // Convert byte offset to sector offset. 02144 // 02145 02146 sectorOffset = (ULONG)(byteOffset.QuadPart >> deviceExtension->SectorShift); 02147 02148 // 02149 // Convert ULONG byte count to USHORT sector count. 02150 // 02151 02152 sectorCount = (USHORT)(verifyInfo->Length >> deviceExtension->SectorShift); 02153 02154 // 02155 // Move little endian values into CDB in big endian format. 02156 // 02157 02158 cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)§orOffset)->Byte3; 02159 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)§orOffset)->Byte2; 02160 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)§orOffset)->Byte1; 02161 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)§orOffset)->Byte0; 02162 02163 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)§orCount)->Byte1; 02164 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)§orCount)->Byte0; 02165 02166 // 02167 // The verify command is used by the NT FORMAT utility and 02168 // requests are sent down for 5% of the volume size. The 02169 // request timeout value is calculated based on the number of 02170 // sectors verified. 02171 // 02172 02173 srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) * 02174 deviceExtension->TimeOutValue; 02175 02176 status = ScsiClassSendSrbAsynchronous(DeviceObject, 02177 srb, 02178 Irp, 02179 NULL, 02180 0, 02181 FALSE); 02182 02183 return(status); 02184 02185 } 02186 02187 case IOCTL_DISK_GET_PARTITION_INFO: 02188 02189 // 02190 // Return the information about the partition specified by the device 02191 // object. Note that no information is ever returned about the size 02192 // or partition type of the physical disk, as this doesn't make any 02193 // sense. 02194 // 02195 02196 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 02197 sizeof(PARTITION_INFORMATION)) { 02198 02199 status = STATUS_INFO_LENGTH_MISMATCH; 02200 02201 } 02202 #if 0 // HACK: ReactOS partition numbers must be wrong 02203 else if (diskData->PartitionNumber == 0) { 02204 02205 // 02206 // Paritition zero is not a partition so this is not a 02207 // reasonable request. 02208 // 02209 02210 status = STATUS_INVALID_DEVICE_REQUEST; 02211 02212 } 02213 #endif 02214 else { 02215 02216 PPARTITION_INFORMATION outputBuffer; 02217 02218 // 02219 // Update the geometry in case it has changed. 02220 // 02221 02222 status = UpdateRemovableGeometry (DeviceObject, Irp); 02223 02224 if (!NT_SUCCESS(status)) { 02225 02226 // 02227 // Note the drive is not ready. 02228 // 02229 02230 diskData->DriveNotReady = TRUE; 02231 break; 02232 } 02233 02234 // 02235 // Note the drive is now ready. 02236 // 02237 02238 diskData->DriveNotReady = FALSE; 02239 // HACK: ReactOS partition numbers must be wrong (>0 part) 02240 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) { 02241 02242 status = STATUS_INVALID_DEVICE_REQUEST; 02243 break; 02244 } 02245 02246 outputBuffer = 02247 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 02248 02249 outputBuffer->PartitionType = diskData->PartitionType; 02250 outputBuffer->StartingOffset = deviceExtension->StartingOffset; 02251 outputBuffer->PartitionLength.QuadPart = (diskData->PartitionNumber) ? 02252 deviceExtension->PartitionLength.QuadPart : 2305843009213693951LL; // HACK 02253 outputBuffer->HiddenSectors = diskData->HiddenSectors; 02254 outputBuffer->PartitionNumber = diskData->PartitionNumber; 02255 outputBuffer->BootIndicator = diskData->BootIndicator; 02256 outputBuffer->RewritePartition = FALSE; 02257 outputBuffer->RecognizedPartition = 02258 IsRecognizedPartition(diskData->PartitionType); 02259 02260 status = STATUS_SUCCESS; 02261 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION); 02262 } 02263 02264 break; 02265 02266 case IOCTL_DISK_GET_PARTITION_INFO_EX: 02267 02268 // 02269 // Return the information about the partition specified by the device 02270 // object. Note that no information is ever returned about the size 02271 // or partition type of the physical disk, as this doesn't make any 02272 // sense. 02273 // 02274 02275 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 02276 sizeof(PARTITION_INFORMATION_EX)) { 02277 02278 status = STATUS_INFO_LENGTH_MISMATCH; 02279 02280 } 02281 else if (diskData->PartitionNumber == 0) { 02282 02283 // 02284 // Paritition zero is not a partition so this is not a 02285 // reasonable request. 02286 // 02287 02288 status = STATUS_INVALID_DEVICE_REQUEST; 02289 02290 } 02291 else { 02292 02293 PPARTITION_INFORMATION_EX outputBuffer; 02294 02295 // 02296 // Update the geometry in case it has changed. 02297 // 02298 02299 status = UpdateRemovableGeometry (DeviceObject, Irp); 02300 02301 if (!NT_SUCCESS(status)) { 02302 02303 // 02304 // Note the drive is not ready. 02305 // 02306 02307 diskData->DriveNotReady = TRUE; 02308 break; 02309 } 02310 02311 // 02312 // Note the drive is now ready. 02313 // 02314 02315 diskData->DriveNotReady = FALSE; 02316 02317 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) { 02318 02319 status = STATUS_INVALID_DEVICE_REQUEST; 02320 break; 02321 } 02322 02323 outputBuffer = 02324 (PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer; 02325 02326 // 02327 // FIXME: hack of the year, assume that partition is MBR 02328 // Thing that can obviously be wrong... 02329 // 02330 02331 outputBuffer->PartitionStyle = PARTITION_STYLE_MBR; 02332 outputBuffer->Mbr.PartitionType = diskData->PartitionType; 02333 outputBuffer->StartingOffset = deviceExtension->StartingOffset; 02334 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart; 02335 outputBuffer->Mbr.HiddenSectors = diskData->HiddenSectors; 02336 outputBuffer->PartitionNumber = diskData->PartitionNumber; 02337 outputBuffer->Mbr.BootIndicator = diskData->BootIndicator; 02338 outputBuffer->RewritePartition = FALSE; 02339 outputBuffer->Mbr.RecognizedPartition = 02340 IsRecognizedPartition(diskData->PartitionType); 02341 02342 status = STATUS_SUCCESS; 02343 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX); 02344 } 02345 02346 break; 02347 02348 case IOCTL_DISK_SET_PARTITION_INFO: 02349 02350 if (diskData->PartitionNumber == 0) { 02351 02352 status = STATUS_UNSUCCESSFUL; 02353 02354 } else { 02355 02356 PSET_PARTITION_INFORMATION inputBuffer = 02357 (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 02358 02359 // 02360 // Validate buffer length. 02361 // 02362 02363 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 02364 sizeof(SET_PARTITION_INFORMATION)) { 02365 02366 status = STATUS_INFO_LENGTH_MISMATCH; 02367 break; 02368 } 02369 02370 // 02371 // The HAL routines IoGet- and IoSetPartitionInformation were 02372 // developed before support of dynamic partitioning and therefore 02373 // don't distinguish between partition ordinal (that is the order 02374 // of a partition on a disk) and the partition number. (The 02375 // partition number is assigned to a partition to identify it to 02376 // the system.) Use partition ordinals for these legacy calls. 02377 // 02378 02379 status = IoSetPartitionInformation( 02380 deviceExtension->PhysicalDevice, 02381 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 02382 diskData->PartitionOrdinal, 02383 inputBuffer->PartitionType); 02384 02385 if (NT_SUCCESS(status)) { 02386 02387 diskData->PartitionType = inputBuffer->PartitionType; 02388 } 02389 } 02390 02391 break; 02392 02393 case IOCTL_DISK_GET_DRIVE_LAYOUT: 02394 02395 // 02396 // Return the partition layout for the physical drive. Note that 02397 // the layout is returned for the actual physical drive, regardless 02398 // of which partition was specified for the request. 02399 // 02400 02401 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 02402 sizeof(DRIVE_LAYOUT_INFORMATION)) { 02403 status = STATUS_INFO_LENGTH_MISMATCH; 02404 02405 } else { 02406 02407 PDRIVE_LAYOUT_INFORMATION partitionList; 02408 PDEVICE_EXTENSION physicalExtension = deviceExtension; 02409 PPARTITION_INFORMATION partitionEntry; 02410 PDISK_DATA diskData; 02411 ULONG tempSize; 02412 ULONG i; 02413 02414 // 02415 // Read partition information. 02416 // 02417 02418 status = IoReadPartitionTable(deviceExtension->PhysicalDevice, 02419 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 02420 FALSE, 02421 &partitionList); 02422 02423 if (!NT_SUCCESS(status)) { 02424 break; 02425 } 02426 02427 // 02428 // The disk layout has been returned in the partitionList 02429 // buffer. Determine its size and, if the data will fit 02430 // into the intermediatery buffer, return it. 02431 // 02432 02433 tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]); 02434 tempSize += partitionList->PartitionCount * 02435 sizeof(PARTITION_INFORMATION); 02436 02437 if (tempSize > 02438 irpStack->Parameters.DeviceIoControl.OutputBufferLength) { 02439 02440 status = STATUS_BUFFER_TOO_SMALL; 02441 ExFreePool(partitionList); 02442 break; 02443 } 02444 02445 // 02446 // Walk partition list to associate partition numbers with 02447 // partition entries. 02448 // 02449 02450 for (i = 0; i < partitionList->PartitionCount; i++) { 02451 02452 // 02453 // Walk partition chain anchored at physical disk extension. 02454 // 02455 02456 deviceExtension = physicalExtension; 02457 diskData = (PDISK_DATA)(deviceExtension + 1); 02458 02459 do { 02460 02461 deviceExtension = diskData->NextPartition; 02462 02463 // 02464 // Check if this is the last partition in the chain. 02465 // 02466 02467 if (!deviceExtension) { 02468 break; 02469 } 02470 02471 // 02472 // Get the partition device extension from disk data. 02473 // 02474 02475 diskData = (PDISK_DATA)(deviceExtension + 1); 02476 02477 // 02478 // Check if this partition is not currently being used. 02479 // 02480 02481 if (!deviceExtension->PartitionLength.QuadPart) { 02482 continue; 02483 } 02484 02485 partitionEntry = &partitionList->PartitionEntry[i]; 02486 02487 // 02488 // Check if empty, or describes extended partiton or hasn't changed. 02489 // 02490 02491 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED || 02492 IsContainerPartition(partitionEntry->PartitionType)) { 02493 continue; 02494 } 02495 02496 // 02497 // Check if new partition starts where this partition starts. 02498 // 02499 02500 if (partitionEntry->StartingOffset.QuadPart != 02501 deviceExtension->StartingOffset.QuadPart) { 02502 continue; 02503 } 02504 02505 // 02506 // Check if partition length is the same. 02507 // 02508 02509 if (partitionEntry->PartitionLength.QuadPart == 02510 deviceExtension->PartitionLength.QuadPart) { 02511 02512 // 02513 // Partitions match. Update partition number. 02514 // 02515 02516 partitionEntry->PartitionNumber = 02517 diskData->PartitionNumber; 02518 break; 02519 } 02520 02521 } while (TRUE); 02522 } 02523 02524 // 02525 // Copy partition information to system buffer. 02526 // 02527 02528 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, 02529 partitionList, 02530 tempSize); 02531 status = STATUS_SUCCESS; 02532 Irp->IoStatus.Information = tempSize; 02533 02534 // 02535 // Finally, free the buffer allocated by reading the 02536 // partition table. 02537 // 02538 02539 ExFreePool(partitionList); 02540 } 02541 02542 break; 02543 02544 case IOCTL_DISK_SET_DRIVE_LAYOUT: 02545 02546 { 02547 02548 // 02549 // Update the disk with new partition information. 02550 // 02551 02552 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer; 02553 02554 // 02555 // Validate buffer length. 02556 // 02557 02558 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 02559 sizeof(DRIVE_LAYOUT_INFORMATION)) { 02560 02561 status = STATUS_INFO_LENGTH_MISMATCH; 02562 break; 02563 } 02564 02565 length = sizeof(DRIVE_LAYOUT_INFORMATION) + 02566 (partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION); 02567 02568 02569 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 02570 length) { 02571 02572 status = STATUS_BUFFER_TOO_SMALL; 02573 break; 02574 } 02575 02576 // 02577 // Verify that device object is for physical disk. 02578 // 02579 02580 if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) { 02581 status = STATUS_INVALID_PARAMETER; 02582 break; 02583 } 02584 02585 // 02586 // Walk through partition table comparing partitions to 02587 // existing partitions to create, delete and change 02588 // device objects as necessary. 02589 // 02590 02591 UpdateDeviceObjects(DeviceObject, 02592 Irp); 02593 02594 // 02595 // Write changes to disk. 02596 // 02597 02598 status = IoWritePartitionTable( 02599 deviceExtension->DeviceObject, 02600 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 02601 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack, 02602 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder, 02603 partitionList); 02604 } 02605 02606 // 02607 // Update IRP with bytes returned. 02608 // 02609 02610 if (NT_SUCCESS(status)) { 02611 Irp->IoStatus.Information = length; 02612 } 02613 02614 break; 02615 02616 case IOCTL_DISK_REASSIGN_BLOCKS: 02617 02618 // 02619 // Map defective blocks to new location on disk. 02620 // 02621 02622 { 02623 02624 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer; 02625 ULONG bufferSize; 02626 ULONG blockNumber; 02627 ULONG blockCount; 02628 02629 // 02630 // Validate buffer length. 02631 // 02632 02633 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 02634 sizeof(REASSIGN_BLOCKS)) { 02635 02636 status = STATUS_INFO_LENGTH_MISMATCH; 02637 break; 02638 } 02639 02640 bufferSize = sizeof(REASSIGN_BLOCKS) + 02641 (badBlocks->Count - 1) * sizeof(ULONG); 02642 02643 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 02644 bufferSize) { 02645 02646 status = STATUS_INFO_LENGTH_MISMATCH; 02647 break; 02648 } 02649 02650 // 02651 // Build the data buffer to be transferred in the input buffer. 02652 // The format of the data to the device is: 02653 // 02654 // 2 bytes Reserved 02655 // 2 bytes Length 02656 // x * 4 btyes Block Address 02657 // 02658 // All values are big endian. 02659 // 02660 02661 badBlocks->Reserved = 0; 02662 blockCount = badBlocks->Count; 02663 02664 // 02665 // Convert # of entries to # of bytes. 02666 // 02667 02668 blockCount *= 4; 02669 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF); 02670 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00); 02671 02672 // 02673 // Convert back to number of entries. 02674 // 02675 02676 blockCount /= 4; 02677 02678 for (; blockCount > 0; blockCount--) { 02679 02680 blockNumber = badBlocks->BlockNumber[blockCount-1]; 02681 02682 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1], 02683 (PFOUR_BYTE) &blockNumber); 02684 } 02685 02686 srb->CdbLength = 6; 02687 02688 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS; 02689 02690 // 02691 // Set timeout value. 02692 // 02693 02694 srb->TimeOutValue = deviceExtension->TimeOutValue; 02695 02696 status = ScsiClassSendSrbSynchronous(DeviceObject, 02697 srb, 02698 badBlocks, 02699 bufferSize, 02700 TRUE); 02701 02702 Irp->IoStatus.Status = status; 02703 Irp->IoStatus.Information = 0; 02704 ExFreePool(srb); 02705 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 02706 } 02707 02708 return(status); 02709 02710 case IOCTL_DISK_IS_WRITABLE: 02711 02712 // 02713 // Determine if the device is writable. 02714 // 02715 02716 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE); 02717 02718 if (modeData == NULL) { 02719 status = STATUS_INSUFFICIENT_RESOURCES; 02720 break; 02721 } 02722 02723 RtlZeroMemory(modeData, MODE_DATA_SIZE); 02724 02725 length = ScsiClassModeSense(DeviceObject, 02726 (PCHAR) modeData, 02727 MODE_DATA_SIZE, 02728 MODE_SENSE_RETURN_ALL); 02729 02730 if (length < sizeof(MODE_PARAMETER_HEADER)) { 02731 02732 // 02733 // Retry the request in case of a check condition. 02734 // 02735 02736 length = ScsiClassModeSense(DeviceObject, 02737 (PCHAR) modeData, 02738 MODE_DATA_SIZE, 02739 MODE_SENSE_RETURN_ALL); 02740 02741 if (length < sizeof(MODE_PARAMETER_HEADER)) { 02742 status = STATUS_IO_DEVICE_ERROR; 02743 ExFreePool(modeData); 02744 break; 02745 } 02746 } 02747 02748 if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) { 02749 status = STATUS_MEDIA_WRITE_PROTECTED; 02750 } else { 02751 status = STATUS_SUCCESS; 02752 } 02753 02754 ExFreePool(modeData); 02755 break; 02756 02757 case IOCTL_DISK_INTERNAL_SET_VERIFY: 02758 02759 // 02760 // If the caller is kernel mode, set the verify bit. 02761 // 02762 02763 if (Irp->RequestorMode == KernelMode) { 02764 DeviceObject->Flags |= DO_VERIFY_VOLUME; 02765 } 02766 status = STATUS_SUCCESS; 02767 break; 02768 02769 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY: 02770 02771 // 02772 // If the caller is kernel mode, clear the verify bit. 02773 // 02774 02775 if (Irp->RequestorMode == KernelMode) { 02776 DeviceObject->Flags &= ~DO_VERIFY_VOLUME; 02777 } 02778 status = STATUS_SUCCESS; 02779 break; 02780 02781 case IOCTL_DISK_FIND_NEW_DEVICES: 02782 02783 // 02784 // Search for devices that have been powered on since the last 02785 // device search or system initialization. 02786 // 02787 02788 DebugPrint((3,"CdRomDeviceControl: Find devices\n")); 02789 status = DriverEntry(DeviceObject->DriverObject, 02790 NULL); 02791 02792 Irp->IoStatus.Status = status; 02793 ExFreePool(srb); 02794 IoCompleteRequest(Irp, IO_NO_INCREMENT); 02795 return status; 02796 02797 case IOCTL_DISK_MEDIA_REMOVAL: 02798 02799 // 02800 // If the disk is not removable then don't allow this command. 02801 // 02802 02803 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) { 02804 status = STATUS_INVALID_DEVICE_REQUEST; 02805 break; 02806 } 02807 02808 // 02809 // Fall through and let the class driver process the request. 02810 // 02811 02812 case IOCTL_DISK_GET_LENGTH_INFO: 02813 02814 // 02815 // Validate buffer length. 02816 // 02817 02818 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 02819 sizeof(GET_LENGTH_INFORMATION)) { 02820 status = STATUS_BUFFER_TOO_SMALL; 02821 02822 } else { 02823 02824 PGET_LENGTH_INFORMATION lengthInformation = Irp->AssociatedIrp.SystemBuffer; 02825 02826 // 02827 // Update the geometry in case it has changed. 02828 // 02829 02830 status = UpdateRemovableGeometry (DeviceObject, Irp); 02831 02832 if (!NT_SUCCESS(status)) { 02833 02834 // 02835 // Note the drive is not ready. 02836 // 02837 02838 diskData->DriveNotReady = TRUE; 02839 break; 02840 } 02841 02842 // 02843 // Note the drive is now ready. 02844 // 02845 02846 diskData->DriveNotReady = FALSE; 02847 02848 // 02849 // Output data, and return 02850 // 02851 02852 lengthInformation->Length.QuadPart = deviceExtension->PartitionLength.QuadPart; 02853 status = STATUS_SUCCESS; 02854 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION); 02855 } 02856 02857 break; 02858 02859 default: 02860 02861 // 02862 // Free the Srb, since it is not needed. 02863 // 02864 02865 ExFreePool(srb); 02866 02867 // 02868 // Pass the request to the common device control routine. 02869 // 02870 02871 return(ScsiClassDeviceControl(DeviceObject, Irp)); 02872 02873 break; 02874 02875 } // end switch( ... 02876 02877 Irp->IoStatus.Status = status; 02878 02879 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) { 02880 02881 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 02882 } 02883 02884 IoCompleteRequest(Irp, IO_NO_INCREMENT); 02885 ExFreePool(srb); 02886 return(status); 02887 02888 } // end ScsiDiskDeviceControl() 02889 02890 NTSTATUS 02891 NTAPI 02892 ScsiDiskShutdownFlush ( 02893 IN PDEVICE_OBJECT DeviceObject, 02894 IN PIRP Irp 02895 ) 02896 02897 /*++ 02898 02899 Routine Description: 02900 02901 This routine is called for a shutdown and flush IRPs. These are sent by the 02902 system before it actually shuts down or when the file system does a flush. 02903 A synchronize cache command is sent to the device if it is write caching. 02904 If the device is removable an unlock command will be sent. This routine 02905 will sent a shutdown or flush Srb to the port driver. 02906 02907 Arguments: 02908 02909 DriverObject - Pointer to device object to being shutdown by system. 02910 02911 Irp - IRP involved. 02912 02913 Return Value: 02914 02915 NT Status 02916 02917 --*/ 02918 02919 { 02920 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 02921 PIO_STACK_LOCATION irpStack; 02922 PSCSI_REQUEST_BLOCK srb; 02923 NTSTATUS status; 02924 PCDB cdb; 02925 02926 // 02927 // Allocate SCSI request block. 02928 // 02929 02930 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK)); 02931 02932 if (srb == NULL) { 02933 02934 // 02935 // Set the status and complete the request. 02936 // 02937 02938 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 02939 IoCompleteRequest(Irp, IO_NO_INCREMENT); 02940 return(STATUS_INSUFFICIENT_RESOURCES); 02941 } 02942 02943 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 02944 02945 // 02946 // Write length to SRB. 02947 // 02948 02949 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 02950 02951 // 02952 // Set SCSI bus address. 02953 // 02954 02955 srb->PathId = deviceExtension->PathId; 02956 srb->TargetId = deviceExtension->TargetId; 02957 srb->Lun = deviceExtension->Lun; 02958 02959 // 02960 // Set timeout value and mark the request as not being a tagged request. 02961 // 02962 02963 srb->TimeOutValue = deviceExtension->TimeOutValue * 4; 02964 srb->QueueTag = SP_UNTAGGED; 02965 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 02966 srb->SrbFlags = deviceExtension->SrbFlags; 02967 02968 // 02969 // If the write cache is enabled then send a synchronize cache request. 02970 // 02971 02972 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) { 02973 02974 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 02975 srb->CdbLength = 10; 02976 02977 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE; 02978 02979 status = ScsiClassSendSrbSynchronous(DeviceObject, 02980 srb, 02981 NULL, 02982 0, 02983 TRUE); 02984 02985 DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status )); 02986 } 02987 02988 // 02989 // Unlock the device if it is removable and this is a shutdown. 02990 // 02991 02992 irpStack = IoGetCurrentIrpStackLocation(Irp); 02993 02994 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA && 02995 irpStack->MajorFunction == IRP_MJ_SHUTDOWN) { 02996 02997 srb->CdbLength = 6; 02998 cdb = (PVOID) srb->Cdb; 02999 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; 03000 cdb->MEDIA_REMOVAL.Prevent = FALSE; 03001 03002 // 03003 // Set timeout value. 03004 // 03005 03006 srb->TimeOutValue = deviceExtension->TimeOutValue; 03007 status = ScsiClassSendSrbSynchronous(DeviceObject, 03008 srb, 03009 NULL, 03010 0, 03011 TRUE); 03012 03013 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status )); 03014 } 03015 03016 srb->CdbLength = 0; 03017 03018 // 03019 // Save a few parameters in the current stack location. 03020 // 03021 03022 srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ? 03023 SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH; 03024 03025 // 03026 // Set the retry count to zero. 03027 // 03028 03029 irpStack->Parameters.Others.Argument4 = (PVOID) 0; 03030 03031 // 03032 // Set up IoCompletion routine address. 03033 // 03034 03035 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE); 03036 03037 // 03038 // Get next stack location and 03039 // set major function code. 03040 // 03041 03042 irpStack = IoGetNextIrpStackLocation(Irp); 03043 03044 irpStack->MajorFunction = IRP_MJ_SCSI; 03045 03046 // 03047 // Set up SRB for execute scsi request. 03048 // Save SRB address in next stack for port driver. 03049 // 03050 03051 irpStack->Parameters.Scsi.Srb = srb; 03052 03053 // 03054 // Set up Irp Address. 03055 // 03056 03057 srb->OriginalRequest = Irp; 03058 03059 // 03060 // Call the port driver to process the request. 03061 // 03062 03063 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp)); 03064 03065 } // end ScsiDiskShutdown() 03066 03067 03068 BOOLEAN 03069 NTAPI 03070 IsFloppyDevice( 03071 PDEVICE_OBJECT DeviceObject 03072 ) 03073 /*++ 03074 03075 Routine Description: 03076 03077 The routine performs the necessary functions to determine if a device is 03078 really a floppy rather than a harddisk. This is done by a mode sense 03079 command. First, a check is made to see if the medimum type is set. Second 03080 a check is made for the flexible parameters mode page. Also a check is 03081 made to see if the write cache is enabled. 03082 03083 Arguments: 03084 03085 DeviceObject - Supplies the device object to be tested. 03086 03087 Return Value: 03088 03089 Return TRUE if the indicated device is a floppy. 03090 03091 --*/ 03092 { 03093 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 03094 PVOID modeData; 03095 PUCHAR pageData; 03096 ULONG length; 03097 03098 PAGED_CODE(); 03099 03100 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE); 03101 03102 if (modeData == NULL) { 03103 return(FALSE); 03104 } 03105 03106 RtlZeroMemory(modeData, MODE_DATA_SIZE); 03107 03108 length = ScsiClassModeSense(DeviceObject, 03109 modeData, 03110 MODE_DATA_SIZE, 03111 MODE_SENSE_RETURN_ALL); 03112 03113 if (length < sizeof(MODE_PARAMETER_HEADER)) { 03114 03115 // 03116 // Retry the request in case of a check condition. 03117 // 03118 03119 length = ScsiClassModeSense(DeviceObject, 03120 modeData, 03121 MODE_DATA_SIZE, 03122 MODE_SENSE_RETURN_ALL); 03123 03124 if (length < sizeof(MODE_PARAMETER_HEADER)) { 03125 03126 ExFreePool(modeData); 03127 return(FALSE); 03128 03129 } 03130 } 03131 03132 // 03133 // If the length is greater than length indicated by the mode data reset 03134 // the data to the mode data. 03135 // 03136 03137 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) { 03138 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1; 03139 } 03140 03141 // 03142 // Look for the flexible disk mode page. 03143 // 03144 03145 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE); 03146 03147 if (pageData != NULL) { 03148 03149 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n")); 03150 ExFreePool(modeData); 03151 return(TRUE); 03152 } 03153 03154 // 03155 // Check to see if the write cache is enabled. 03156 // 03157 03158 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE); 03159 03160 // 03161 // Assume that write cache is disabled or not supported. 03162 // 03163 03164 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 03165 03166 // 03167 // Check if valid caching page exists. 03168 // 03169 03170 if (pageData != NULL) { 03171 03172 // 03173 // Check if write cache is disabled. 03174 // 03175 03176 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) { 03177 03178 DebugPrint((1, 03179 "SCSIDISK: Disk write cache enabled\n")); 03180 03181 // 03182 // Check if forced unit access (FUA) is supported. 03183 // 03184 03185 if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) { 03186 03187 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE; 03188 03189 } else { 03190 03191 DebugPrint((1, 03192 "SCSIDISK: Disk does not support FUA or DPO\n")); 03193 03194 // 03195 // TODO: Log this. 03196 // 03197 03198 } 03199 } 03200 } 03201 03202 ExFreePool(modeData); 03203 return(FALSE); 03204 03205 } // end IsFloppyDevice() 03206 03207 03208 BOOLEAN 03209 NTAPI 03210 ScsiDiskModeSelect( 03211 IN PDEVICE_OBJECT DeviceObject, 03212 IN PCHAR ModeSelectBuffer, 03213 IN ULONG Length, 03214 IN BOOLEAN SavePage 03215 ) 03216 03217 /*++ 03218 03219 Routine Description: 03220 03221 This routine sends a mode select command. 03222 03223 Arguments: 03224 03225 DeviceObject - Supplies the device object associated with this request. 03226 03227 ModeSelectBuffer - Supplies a buffer containing the page data. 03228 03229 Length - Supplies the length in bytes of the mode select buffer. 03230 03231 SavePage - Indicates that parameters should be written to disk. 03232 03233 Return Value: 03234 03235 Length of the transferred data is returned. 03236 03237 --*/ 03238 { 03239 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 03240 PCDB cdb; 03241 SCSI_REQUEST_BLOCK srb; 03242 ULONG retries = 1; 03243 ULONG length2; 03244 NTSTATUS status; 03245 ULONG_PTR buffer; 03246 PMODE_PARAMETER_BLOCK blockDescriptor; 03247 03248 PAGED_CODE(); 03249 03250 length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK); 03251 03252 // 03253 // Allocate buffer for mode select header, block descriptor, and mode page. 03254 // 03255 03256 buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2); 03257 03258 RtlZeroMemory((PVOID)buffer, length2); 03259 03260 // 03261 // Set length in header to size of mode page. 03262 // 03263 03264 ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK); 03265 03266 blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1); 03267 03268 // 03269 // Set size 03270 // 03271 03272 blockDescriptor->BlockLength[1]=0x02; 03273 03274 // 03275 // Copy mode page to buffer. 03276 // 03277 03278 RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length); 03279 03280 // 03281 // Zero SRB. 03282 // 03283 03284 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 03285 03286 // 03287 // Build the MODE SELECT CDB. 03288 // 03289 03290 srb.CdbLength = 6; 03291 cdb = (PCDB)srb.Cdb; 03292 03293 // 03294 // Set timeout value from device extension. 03295 // 03296 03297 srb.TimeOutValue = deviceExtension->TimeOutValue * 2; 03298 03299 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; 03300 cdb->MODE_SELECT.SPBit = SavePage; 03301 cdb->MODE_SELECT.PFBit = 1; 03302 cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2); 03303 03304 Retry: 03305 03306 status = ScsiClassSendSrbSynchronous(DeviceObject, 03307 &srb, 03308 (PVOID)buffer, 03309 length2, 03310 TRUE); 03311 03312 03313 if (status == STATUS_VERIFY_REQUIRED) { 03314 03315 // 03316 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with 03317 // this status. 03318 // 03319 03320 if (retries--) { 03321 03322 // 03323 // Retry request. 03324 // 03325 03326 goto Retry; 03327 } 03328 03329 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) { 03330 status = STATUS_SUCCESS; 03331 } 03332 03333 ExFreePool((PVOID)buffer); 03334 03335 if (NT_SUCCESS(status)) { 03336 return(TRUE); 03337 } else { 03338 return(FALSE); 03339 } 03340 03341 } // end SciDiskModeSelect() 03342 03343 03344 VOID 03345 NTAPI 03346 DisableWriteCache( 03347 IN PDEVICE_OBJECT DeviceObject, 03348 IN PSCSI_INQUIRY_DATA LunInfo 03349 ) 03350 03351 { 03352 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 03353 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData; 03354 BAD_CONTROLLER_INFORMATION const *controller; 03355 ULONG j,length; 03356 PVOID modeData; 03357 PUCHAR pageData; 03358 03359 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) { 03360 03361 controller = &ScsiDiskBadControllers[j]; 03362 03363 if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) { 03364 continue; 03365 } 03366 03367 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString)); 03368 03369 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE); 03370 03371 if (modeData == NULL) { 03372 03373 DebugPrint((1, 03374 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n")); 03375 return; 03376 } 03377 03378 RtlZeroMemory(modeData, MODE_DATA_SIZE); 03379 03380 length = ScsiClassModeSense(DeviceObject, 03381 modeData, 03382 MODE_DATA_SIZE, 03383 MODE_SENSE_RETURN_ALL); 03384 03385 if (length < sizeof(MODE_PARAMETER_HEADER)) { 03386 03387 // 03388 // Retry the request in case of a check condition. 03389 // 03390 03391 length = ScsiClassModeSense(DeviceObject, 03392 modeData, 03393 MODE_DATA_SIZE, 03394 MODE_SENSE_RETURN_ALL); 03395 03396 if (length < sizeof(MODE_PARAMETER_HEADER)) { 03397 03398 03399 DebugPrint((1, 03400 "ScsiDisk.DisableWriteCache: Mode Sense failed\n")); 03401 03402 ExFreePool(modeData); 03403 return; 03404 03405 } 03406 } 03407 03408 // 03409 // If the length is greater than length indicated by the mode data reset 03410 // the data to the mode data. 03411 // 03412 03413 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) { 03414 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1; 03415 } 03416 03417 // 03418 // Check to see if the write cache is enabled. 03419 // 03420 03421 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE); 03422 03423 // 03424 // Assume that write cache is disabled or not supported. 03425 // 03426 03427 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 03428 03429 // 03430 // Check if valid caching page exists. 03431 // 03432 03433 if (pageData != NULL) { 03434 03435 BOOLEAN savePage = FALSE; 03436 03437 savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable); 03438 03439 // 03440 // Check if write cache is disabled. 03441 // 03442 03443 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) { 03444 03445 PIO_ERROR_LOG_PACKET errorLogEntry; 03446 LONG errorCode; 03447 03448 03449 // 03450 // Disable write cache and ensure necessary fields are zeroed. 03451 // 03452 03453 ((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE; 03454 ((PMODE_CACHING_PAGE)pageData)->Reserved = 0; 03455 ((PMODE_CACHING_PAGE)pageData)->PageSavable = 0; 03456 ((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0; 03457 03458 // 03459 // Extract length from caching page. 03460 // 03461 03462 length = ((PMODE_CACHING_PAGE)pageData)->PageLength; 03463 03464 // 03465 // Compensate for page code and page length. 03466 // 03467 03468 length += 2; 03469 03470 // 03471 // Issue mode select to set the parameter. 03472 // 03473 03474 if (ScsiDiskModeSelect(DeviceObject, 03475 (PCHAR)pageData, 03476 length, 03477 savePage)) { 03478 03479 DebugPrint((1, 03480 "SCSIDISK: Disk write cache disabled\n")); 03481 03482 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 03483 errorCode = IO_WRITE_CACHE_DISABLED; 03484 03485 } else { 03486 if (ScsiDiskModeSelect(DeviceObject, 03487 (PCHAR)pageData, 03488 length, 03489 savePage)) { 03490 03491 DebugPrint((1, 03492 "SCSIDISK: Disk write cache disabled\n")); 03493 03494 03495 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 03496 errorCode = IO_WRITE_CACHE_DISABLED; 03497 03498 } else { 03499 03500 DebugPrint((1, 03501 "SCSIDISK: Mode select to disable write cache failed\n")); 03502 03503 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE; 03504 errorCode = IO_WRITE_CACHE_ENABLED; 03505 } 03506 } 03507 03508 // 03509 // Log the appropriate informational or error entry. 03510 // 03511 03512 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( 03513 DeviceObject, 03514 sizeof(IO_ERROR_LOG_PACKET) + 3 03515 * sizeof(ULONG)); 03516 03517 if (errorLogEntry != NULL) { 03518 03519 errorLogEntry->FinalStatus = STATUS_SUCCESS; 03520 errorLogEntry->ErrorCode = errorCode; 03521 errorLogEntry->SequenceNumber = 0; 03522 errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI; 03523 errorLogEntry->IoControlCode = 0; 03524 errorLogEntry->RetryCount = 0; 03525 errorLogEntry->UniqueErrorValue = 0x1; 03526 errorLogEntry->DumpDataSize = 3 * sizeof(ULONG); 03527 errorLogEntry->DumpData[0] = LunInfo->PathId; 03528 errorLogEntry->DumpData[1] = LunInfo->TargetId; 03529 errorLogEntry->DumpData[2] = LunInfo->Lun; 03530 03531 // 03532 // Write the error log packet. 03533 // 03534 03535 IoWriteErrorLogEntry(errorLogEntry); 03536 } 03537 } 03538 } 03539 03540 // 03541 // Found device so exit the loop and return. 03542 // 03543 03544 break; 03545 } 03546 03547 return; 03548 } 03549 03550 03551 BOOLEAN 03552 NTAPI 03553 CalculateMbrCheckSum( 03554 IN PDEVICE_EXTENSION DeviceExtension, 03555 OUT PULONG Checksum 03556 ) 03557 03558 /*++ 03559 03560 Routine Description: 03561 03562 Read MBR and calculate checksum. 03563 03564 Arguments: 03565 03566 DeviceExtension - Supplies a pointer to the device information for disk. 03567 Checksum - Memory location to return MBR checksum. 03568 03569 Return Value: 03570 03571 Returns TRUE if checksum is valid. 03572 03573 --*/ 03574 { 03575 LARGE_INTEGER sectorZero; 03576 PIRP irp; 03577 IO_STATUS_BLOCK ioStatus; 03578 KEVENT event; 03579 NTSTATUS status; 03580 ULONG sectorSize; 03581 PULONG mbr; 03582 ULONG i; 03583 03584 PAGED_CODE(); 03585 sectorZero.QuadPart = (LONGLONG) 0; 03586 03587 // 03588 // Create notification event object to be used to signal the inquiry 03589 // request completion. 03590 // 03591 03592 KeInitializeEvent(&event, NotificationEvent, FALSE); 03593 03594 // 03595 // Get sector size. 03596 // 03597 03598 sectorSize = DeviceExtension->DiskGeometry->Geometry.BytesPerSector; 03599 03600 // 03601 // Make sure sector size is at least 512 bytes. 03602 // 03603 03604 if (sectorSize < 512) { 03605 sectorSize = 512; 03606 } 03607 03608 // 03609 // Allocate buffer for sector read. 03610 // 03611 03612 mbr = ExAllocatePool(NonPagedPoolCacheAligned, sectorSize); 03613 03614 if (!mbr) { 03615 return FALSE; 03616 } 03617 03618 // 03619 // Build IRP to read MBR. 03620 // 03621 03622 irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 03623 DeviceExtension->DeviceObject, 03624 mbr, 03625 sectorSize, 03626 §orZero, 03627 &event, 03628 &ioStatus ); 03629 03630 if (!irp) { 03631 ExFreePool(mbr); 03632 return FALSE; 03633 } 03634 03635 // 03636 // Pass request to port driver and wait for request to complete. 03637 // 03638 03639 status = IoCallDriver(DeviceExtension->DeviceObject, 03640 irp); 03641 03642 if (status == STATUS_PENDING) { 03643 KeWaitForSingleObject(&event, 03644 Suspended, 03645 KernelMode, 03646 FALSE, 03647 NULL); 03648 status = ioStatus.Status; 03649 } 03650 03651 if (!NT_SUCCESS(status)) { 03652 ExFreePool(mbr); 03653 return FALSE; 03654 } 03655 03656 // 03657 // Calculate MBR checksum. 03658 // 03659 03660 *Checksum = 0; 03661 03662 for (i = 0; i < 128; i++) { 03663 *Checksum += mbr[i]; 03664 } 03665 03666 *Checksum = ~*Checksum + 1; 03667 03668 ExFreePool(mbr); 03669 return TRUE; 03670 } 03671 03672 03673 BOOLEAN 03674 NTAPI 03675 EnumerateBusKey( 03676 IN PDEVICE_EXTENSION DeviceExtension, 03677 HANDLE BusKey, 03678 PULONG DiskNumber 03679 ) 03680 03681 /*++ 03682 03683 Routine Description: 03684 03685 The routine queries the registry to determine if this disk is visible to 03686 the BIOS. If the disk is visable to the BIOS, then the geometry information 03687 is updated. 03688 03689 Arguments: 03690 03691 DeviceExtension - Supplies a pointer to the device information for disk. 03692 Signature - Unique identifier recorded in MBR. 03693 BusKey - Handle of bus key. 03694 DiskNumber - Returns ordinal of disk as BIOS sees it. 03695 03696 Return Value: 03697 03698 TRUE is disk signature matched. 03699 03700 --*/ 03701 { 03702 PDISK_DATA diskData = (PDISK_DATA)(DeviceExtension + 1); 03703 BOOLEAN diskFound = FALSE; 03704 OBJECT_ATTRIBUTES objectAttributes; 03705 UNICODE_STRING unicodeString; 03706 UNICODE_STRING identifier; 03707 ULONG busNumber; 03708 ULONG adapterNumber; 03709 ULONG diskNumber; 03710 HANDLE adapterKey; 03711 HANDLE spareKey; 03712 HANDLE diskKey; 03713 HANDLE targetKey; 03714 NTSTATUS status; 03715 STRING string; 03716 STRING anotherString; 03717 ULONG length; 03718 UCHAR buffer[20]; 03719 PKEY_VALUE_FULL_INFORMATION keyData; 03720 03721 PAGED_CODE(); 03722 03723 for (busNumber = 0; ; busNumber++) { 03724 03725 // 03726 // Open controller name key. 03727 // 03728 03729 sprintf((PCHAR)buffer, 03730 "%lu", 03731 busNumber); 03732 03733 RtlInitString(&string, 03734 (PCSZ)buffer); 03735 03736 status = RtlAnsiStringToUnicodeString(&unicodeString, 03737 &string, 03738 TRUE); 03739 03740 if (!NT_SUCCESS(status)){ 03741 break; 03742 } 03743 03744 InitializeObjectAttributes(&objectAttributes, 03745 &unicodeString, 03746 OBJ_CASE_INSENSITIVE, 03747 BusKey, 03748 (PSECURITY_DESCRIPTOR)NULL); 03749 03750 status = ZwOpenKey(&spareKey, 03751 KEY_READ, 03752 &objectAttributes); 03753 03754 RtlFreeUnicodeString(&unicodeString); 03755 03756 if (!NT_SUCCESS(status)) { 03757 break; 03758 } 03759 03760 // 03761 // Open up controller ordinal key. 03762 // 03763 03764 RtlInitUnicodeString(&unicodeString, L"DiskController"); 03765 InitializeObjectAttributes(&objectAttributes, 03766 &unicodeString, 03767 OBJ_CASE_INSENSITIVE, 03768 spareKey, 03769 (PSECURITY_DESCRIPTOR)NULL); 03770 03771 status = ZwOpenKey(&adapterKey, 03772 KEY_READ, 03773 &objectAttributes); 03774 03775 // 03776 // This could fail even with additional adapters of this type 03777 // to search. 03778 // 03779 03780 if (!NT_SUCCESS(status)) { 03781 continue; 03782 } 03783 03784 for (adapterNumber = 0; ; adapterNumber++) { 03785 03786 // 03787 // Open disk key. 03788 // 03789 03790 sprintf((PCHAR)buffer, 03791 "%lu\\DiskPeripheral", 03792 adapterNumber); 03793 03794 RtlInitString(&string, 03795 (PCSZ)buffer); 03796 03797 status = RtlAnsiStringToUnicodeString(&unicodeString, 03798 &string, 03799 TRUE); 03800 03801 if (!NT_SUCCESS(status)){ 03802 break; 03803 } 03804 03805 InitializeObjectAttributes(&objectAttributes, 03806 &unicodeString, 03807 OBJ_CASE_INSENSITIVE, 03808 adapterKey, 03809 (PSECURITY_DESCRIPTOR)NULL); 03810 03811 status = ZwOpenKey(&diskKey, 03812 KEY_READ, 03813 &objectAttributes); 03814 03815 RtlFreeUnicodeString(&unicodeString); 03816 03817 if (!NT_SUCCESS(status)) { 03818 break; 03819 } 03820 03821 for (diskNumber = 0; ; diskNumber++) { 03822 03823 sprintf((PCHAR)buffer, 03824 "%lu", 03825 diskNumber); 03826 03827 RtlInitString(&string, 03828 (PCSZ)buffer); 03829 03830 status = RtlAnsiStringToUnicodeString(&unicodeString, 03831 &string, 03832 TRUE); 03833 03834 if (!NT_SUCCESS(status)){ 03835 break; 03836 } 03837 03838 InitializeObjectAttributes(&objectAttributes, 03839 &unicodeString, 03840 OBJ_CASE_INSENSITIVE, 03841 diskKey, 03842 (PSECURITY_DESCRIPTOR)NULL); 03843 03844 status = ZwOpenKey(&targetKey, 03845 KEY_READ, 03846 &objectAttributes); 03847 03848 RtlFreeUnicodeString(&unicodeString); 03849 03850 if (!NT_SUCCESS(status)) { 03851 break; 03852 } 03853 03854 // 03855 // Allocate buffer for registry query. 03856 // 03857 03858 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE); 03859 03860 if (keyData == NULL) { 03861 ZwClose(targetKey); 03862 continue; 03863 } 03864 03865 // 03866 // Get disk peripheral identifier. 03867 // 03868 03869 RtlInitUnicodeString(&unicodeString, L"Identifier"); 03870 status = ZwQueryValueKey(targetKey, 03871 &unicodeString, 03872 KeyValueFullInformation, 03873 keyData, 03874 VALUE_BUFFER_SIZE, 03875 &length); 03876 03877 ZwClose(targetKey); 03878 03879 if (!NT_SUCCESS(status)) { 03880 continue; 03881 } 03882 03883 // 03884 // Complete unicode string. 03885 // 03886 03887 identifier.Buffer = 03888 (PWSTR)((PUCHAR)keyData + keyData->DataOffset); 03889 identifier.Length = (USHORT)keyData->DataLength; 03890 identifier.MaximumLength = (USHORT)keyData->DataLength; 03891 03892 // 03893 // Convert unicode identifier to ansi string. 03894 // 03895 03896 status = 03897 RtlUnicodeStringToAnsiString(&anotherString, 03898 &identifier, 03899 TRUE); 03900 03901 if (!NT_SUCCESS(status)) { 03902 continue; 03903 } 03904 03905 // 03906 // If checksum is zero, then the MBR is valid and 03907 // the signature is meaningful. 03908 // 03909 03910 if (diskData->MbrCheckSum) { 03911 03912 // 03913 // Convert checksum to ansi string. 03914 // 03915 03916 sprintf((PCHAR)buffer, "%08lx", diskData->MbrCheckSum); 03917 03918 } else { 03919 03920 // 03921 // Convert signature to ansi string. 03922 // 03923 03924 sprintf((PCHAR)buffer, "%08lx", diskData->Signature); 03925 03926 // 03927 // Make string point at signature. Can't use scan 03928 // functions because they are not exported for driver use. 03929 // 03930 03931 anotherString.Buffer+=9; 03932 } 03933 03934 // 03935 // Convert to ansi string. 03936 // 03937 03938 RtlInitString(&string, 03939 (PCSZ)buffer); 03940 03941 03942 // 03943 // Make string lengths equal. 03944 // 03945 03946 anotherString.Length = string.Length; 03947 03948 // 03949 // Check if strings match. 03950 // 03951 03952 if (RtlCompareString(&string, 03953 &anotherString, 03954 TRUE) == 0) { 03955 03956 diskFound = TRUE; 03957 *DiskNumber = diskNumber; 03958 } 03959 03960 ExFreePool(keyData); 03961 03962 // 03963 // Readjust indentifier string if necessary. 03964 // 03965 03966 if (!diskData->MbrCheckSum) { 03967 anotherString.Buffer-=9; 03968 } 03969 03970 RtlFreeAnsiString(&anotherString); 03971 03972 if (diskFound) { 03973 break; 03974 } 03975 } 03976 03977 ZwClose(diskKey); 03978 } 03979 03980 ZwClose(adapterKey); 03981 } 03982 03983 ZwClose(BusKey); 03984 return diskFound; 03985 03986 } // end EnumerateBusKey() 03987 03988 03989 VOID 03990 NTAPI 03991 UpdateGeometry( 03992 IN PDEVICE_EXTENSION DeviceExtension 03993 ) 03994 /*++ 03995 03996 Routine Description: 03997 03998 The routine queries the registry to determine if this disk is visible to 03999 the BIOS. If the disk is visable to the BIOS, then the geometry information 04000 is updated. 04001 04002 Arguments: 04003 04004 DeviceExtension - Supplies a pointer to the device information for disk. 04005 04006 Return Value: 04007 04008 None. 04009 04010 --*/ 04011 04012 { 04013 OBJECT_ATTRIBUTES objectAttributes; 04014 UNICODE_STRING unicodeString; 04015 NTSTATUS status; 04016 HANDLE hardwareKey; 04017 HANDLE busKey; 04018 PCM_INT13_DRIVE_PARAMETER driveParameters; 04019 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor; 04020 PKEY_VALUE_FULL_INFORMATION keyData; 04021 ULONG diskNumber; 04022 PUCHAR buffer; 04023 ULONG length; 04024 ULONG numberOfDrives; 04025 ULONG cylinders; 04026 ULONG sectors; 04027 ULONG sectorsPerTrack; 04028 ULONG tracksPerCylinder; 04029 BOOLEAN foundEZHooker; 04030 PVOID tmpPtr; 04031 04032 PAGED_CODE(); 04033 04034 // 04035 // Initialize the object for the key. 04036 // 04037 04038 InitializeObjectAttributes(&objectAttributes, 04039 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase, 04040 OBJ_CASE_INSENSITIVE, 04041 NULL, 04042 (PSECURITY_DESCRIPTOR) NULL); 04043 04044 // 04045 // Create the hardware base key. 04046 // 04047 04048 status = ZwOpenKey(&hardwareKey, 04049 KEY_READ, 04050 &objectAttributes); 04051 04052 04053 if (!NT_SUCCESS(status)) { 04054 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension->DeviceObject->DriverObject->HardwareDatabase)); 04055 return; 04056 } 04057 04058 04059 // 04060 // Get disk BIOS geometry information. 04061 // 04062 04063 RtlInitUnicodeString(&unicodeString, L"Configuration Data"); 04064 04065 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE); 04066 04067 if (keyData == NULL) { 04068 ZwClose(hardwareKey); 04069 return; 04070 } 04071 04072 status = ZwQueryValueKey(hardwareKey, 04073 &unicodeString, 04074 KeyValueFullInformation, 04075 keyData, 04076 VALUE_BUFFER_SIZE, 04077 &length); 04078 04079 if (!NT_SUCCESS(status)) { 04080 DebugPrint((1, 04081 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n", 04082 status)); 04083 ExFreePool(keyData); 04084 return; 04085 } 04086 04087 // 04088 // Open EISA bus key. 04089 // 04090 04091 RtlInitUnicodeString(&unicodeString, L"EisaAdapter"); 04092 04093 InitializeObjectAttributes(&objectAttributes, 04094 &unicodeString, 04095 OBJ_CASE_INSENSITIVE, 04096 hardwareKey, 04097 (PSECURITY_DESCRIPTOR)NULL); 04098 04099 status = ZwOpenKey(&busKey, 04100 KEY_READ, 04101 &objectAttributes); 04102 04103 if (!NT_SUCCESS(status)) { 04104 goto openMultiKey; 04105 } 04106 04107 DebugPrint((3, 04108 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n")); 04109 if (EnumerateBusKey(DeviceExtension, 04110 busKey, 04111 &diskNumber)) { 04112 04113 ZwClose(hardwareKey); 04114 goto diskMatched; 04115 } 04116 04117 openMultiKey: 04118 04119 // 04120 // Open Multifunction bus key. 04121 // 04122 04123 RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter"); 04124 04125 InitializeObjectAttributes(&objectAttributes, 04126 &unicodeString, 04127 OBJ_CASE_INSENSITIVE, 04128 hardwareKey, 04129 (PSECURITY_DESCRIPTOR)NULL); 04130 04131 status = ZwOpenKey(&busKey, 04132 KEY_READ, 04133 &objectAttributes); 04134 04135 ZwClose(hardwareKey); 04136 if (NT_SUCCESS(status)) { 04137 DebugPrint((3, 04138 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n")); 04139 if (EnumerateBusKey(DeviceExtension, 04140 busKey, 04141 &diskNumber)) { 04142 04143 goto diskMatched; 04144 } 04145 } 04146 04147 ExFreePool(keyData); 04148 return; 04149 04150 diskMatched: 04151 04152 resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)keyData + 04153 keyData->DataOffset); 04154 04155 // 04156 // Check that the data is long enough to hold a full resource descriptor, 04157 // and that the last resouce list is device-specific and long enough. 04158 // 04159 04160 if (keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR) || 04161 resourceDescriptor->PartialResourceList.Count == 0 || 04162 resourceDescriptor->PartialResourceList.PartialDescriptors[0].Type != 04163 CmResourceTypeDeviceSpecific || 04164 resourceDescriptor->PartialResourceList.PartialDescriptors[0] 04165 .u.DeviceSpecificData.DataSize < sizeof(ULONG)) { 04166 04167 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n")); 04168 ExFreePool(keyData); 04169 return; 04170 } 04171 04172 length = 04173 resourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize; 04174 04175 // 04176 // Point to the BIOS data. The BIOS data is located after the first 04177 // partial Resource list which should be device specific data. 04178 // 04179 04180 buffer = (PUCHAR) keyData + keyData->DataOffset + 04181 sizeof(CM_FULL_RESOURCE_DESCRIPTOR); 04182 04183 04184 numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER); 04185 04186 // 04187 // Use the defaults if the drive number is greater than the 04188 // number of drives detected by the BIOS. 04189 // 04190 04191 if (numberOfDrives <= diskNumber) { 04192 ExFreePool(keyData); 04193 return; 04194 } 04195 04196 // 04197 // Point to the array of drive parameters. 04198 // 04199 04200 driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer + diskNumber; 04201 cylinders = driveParameters->MaxCylinders + 1; 04202 sectorsPerTrack = driveParameters->SectorsPerTrack; 04203 tracksPerCylinder = driveParameters->MaxHeads +1; 04204 04205 // 04206 // Calculate the actual number of sectors. 04207 // 04208 04209 sectors = (ULONG)(DeviceExtension->PartitionLength.QuadPart >> 04210 DeviceExtension->SectorShift); 04211 04212 #if DBG 04213 if (sectors >= cylinders * tracksPerCylinder * sectorsPerTrack) { 04214 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n" 04215 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n", 04216 sectors, cylinders, tracksPerCylinder, sectorsPerTrack)); 04217 } 04218 #endif 04219 04220 // 04221 // Since the BIOS may not report the full drive, recalculate the drive 04222 // size based on the volume size and the BIOS values for tracks per 04223 // cylinder and sectors per track.. 04224 // 04225 04226 length = tracksPerCylinder * sectorsPerTrack; 04227 04228 if (length == 0) { 04229 04230 // 04231 // The BIOS information is bogus. 04232 // 04233 04234 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n")); 04235 ExFreePool(keyData); 04236 return; 04237 } 04238 04239 cylinders = sectors / length; 04240 04241 // 04242 // Update the actual geometry information. 04243 // 04244 04245 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack = sectorsPerTrack; 04246 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder; 04247 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)cylinders; 04248 DeviceExtension->DiskGeometry->DiskSize.QuadPart = cylinders * tracksPerCylinder * sectorsPerTrack * 04249 DeviceExtension->DiskGeometry->Geometry.BytesPerSector; 04250 04251 DebugPrint((3, 04252 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n", 04253 sectorsPerTrack, 04254 tracksPerCylinder, 04255 cylinders)); 04256 04257 ExFreePool(keyData); 04258 04259 foundEZHooker = FALSE; 04260 04261 if (!DeviceExtension->DMActive) { 04262 04263 HalExamineMBR(DeviceExtension->DeviceObject, 04264 DeviceExtension->DiskGeometry->Geometry.BytesPerSector, 04265 (ULONG)0x55, 04266 &tmpPtr 04267 ); 04268 04269 if (tmpPtr) { 04270 04271 ExFreePool(tmpPtr); 04272 foundEZHooker = TRUE; 04273 04274 } 04275 04276 } 04277 04278 if (DeviceExtension->DMActive || foundEZHooker) { 04279 04280 while (cylinders > 1024) { 04281 04282 tracksPerCylinder = tracksPerCylinder*2; 04283 cylinders = cylinders/2; 04284 04285 } 04286 04287 // 04288 // int 13 values are always 1 less. 04289 // 04290 04291 tracksPerCylinder -= 1; 04292 cylinders -= 1; 04293 04294 // 04295 // DM reserves the CE cylinder 04296 // 04297 04298 cylinders -= 1; 04299 04300 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = cylinders + 1; 04301 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder + 1; 04302 04303 DeviceExtension->PartitionLength.QuadPart = 04304 DeviceExtension->DiskGeometry->DiskSize.QuadPart = 04305 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart * 04306 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack * 04307 DeviceExtension->DiskGeometry->Geometry.BytesPerSector * 04308 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder; 04309 04310 if (DeviceExtension->DMActive) { 04311 04312 DeviceExtension->DMByteSkew = DeviceExtension->DMSkew * DeviceExtension->DiskGeometry->Geometry.BytesPerSector; 04313 04314 } 04315 04316 } else { 04317 04318 DeviceExtension->DMByteSkew = 0; 04319 04320 } 04321 04322 return; 04323 04324 } // end UpdateGeometry() 04325 04326 04327 04328 NTSTATUS 04329 NTAPI 04330 UpdateRemovableGeometry ( 04331 IN PDEVICE_OBJECT DeviceObject, 04332 IN PIRP Irp 04333 ) 04334 04335 /*++ 04336 04337 Routine Description: 04338 04339 This routines updates the size and starting offset of the device. This is 04340 used when the media on the device may have changed thereby changing the 04341 size of the device. If this is the physical device then a 04342 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done. 04343 04344 Arguments: 04345 04346 DeviceObject - Supplies the device object whos size needs to be updated. 04347 04348 Irp - Supplies a reference where the status can be updated. 04349 04350 Return Value: 04351 04352 Returns the status of the opertion. 04353 04354 --*/ 04355 { 04356 04357 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 04358 PDRIVE_LAYOUT_INFORMATION partitionList; 04359 NTSTATUS status; 04360 PDISK_DATA diskData; 04361 ULONG partitionNumber; 04362 04363 // 04364 // Determine if the size of the partition may have changed because 04365 // the media has changed. 04366 // 04367 04368 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) { 04369 04370 return(STATUS_SUCCESS); 04371 04372 } 04373 04374 // 04375 // If this request is for partition zero then do a read drive 04376 // capacity otherwise do a I/O read partition table. 04377 // 04378 04379 diskData = (PDISK_DATA) (deviceExtension + 1); 04380 04381 // 04382 // Read the drive capcity. If that fails, give up. 04383 // 04384 04385 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice); 04386 04387 if (!NT_SUCCESS(status)) { 04388 return(status); 04389 } 04390 04391 // 04392 // Read the partition table agian. 04393 // 04394 04395 status = IoReadPartitionTable(deviceExtension->PhysicalDevice, 04396 deviceExtension->DiskGeometry->Geometry.BytesPerSector, 04397 TRUE, 04398 &partitionList); 04399 04400 04401 if (!NT_SUCCESS(status)) { 04402 04403 // 04404 // Fail the request. 04405 // 04406 04407 return(status); 04408 } 04409 04410 if (diskData->PartitionNumber != 0 && 04411 diskData->PartitionNumber <= partitionList->PartitionCount ) { 04412 04413 partitionNumber = diskData->PartitionNumber - 1; 04414 04415 // 04416 // Update the partition information for this parition. 04417 // 04418 04419 diskData->PartitionType = 04420 partitionList->PartitionEntry[partitionNumber].PartitionType; 04421 04422 diskData->BootIndicator = 04423 partitionList->PartitionEntry[partitionNumber].BootIndicator; 04424 04425 deviceExtension->StartingOffset = 04426 partitionList->PartitionEntry[partitionNumber].StartingOffset; 04427 04428 deviceExtension->PartitionLength = 04429 partitionList->PartitionEntry[partitionNumber].PartitionLength; 04430 04431 diskData->HiddenSectors = 04432 partitionList->PartitionEntry[partitionNumber].HiddenSectors; 04433 04434 deviceExtension->SectorShift = ((PDEVICE_EXTENSION) 04435 deviceExtension->PhysicalDevice->DeviceExtension)->SectorShift; 04436 04437 } else if (diskData->PartitionNumber != 0) { 04438 04439 // 04440 // The paritition does not exist. Zero all the data. 04441 // 04442 04443 diskData->PartitionType = 0; 04444 diskData->BootIndicator = 0; 04445 diskData->HiddenSectors = 0; 04446 deviceExtension->StartingOffset.QuadPart = (LONGLONG)0; 04447 deviceExtension->PartitionLength.QuadPart = (LONGLONG)0; 04448 } 04449 04450 // 04451 // Free the parition list allocate by I/O read partition table. 04452 // 04453 04454 ExFreePool(partitionList); 04455 04456 04457 return(STATUS_SUCCESS); 04458 } 04459 04460 04461 VOID 04462 NTAPI 04463 ScsiDiskProcessError( 04464 PDEVICE_OBJECT DeviceObject, 04465 PSCSI_REQUEST_BLOCK Srb, 04466 NTSTATUS *Status, 04467 BOOLEAN *Retry 04468 ) 04469 /*++ 04470 04471 Routine Description: 04472 04473 This routine checks the type of error. If the error indicates an underrun 04474 then indicate the request should be retried. 04475 04476 Arguments: 04477 04478 DeviceObject - Supplies a pointer to the device object. 04479 04480 Srb - Supplies a pointer to the failing Srb. 04481 04482 Status - Status with which the IRP will be completed. 04483 04484 Retry - Indication of whether the request will be retried. 04485 04486 Return Value: 04487 04488 None. 04489 04490 --*/ 04491 04492 { 04493 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 04494 04495 if (*Status == STATUS_DATA_OVERRUN && 04496 ( Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_READ)) { 04497 04498 *Retry = TRUE; 04499 04500 // 04501 // Update the error count for the device. 04502 // 04503 04504 deviceExtension->ErrorCount++; 04505 } 04506 04507 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR && 04508 Srb->ScsiStatus == SCSISTAT_BUSY) { 04509 04510 // 04511 // The disk drive should never be busy this long. Reset the scsi bus 04512 // maybe this will clear the condition. 04513 // 04514 04515 ResetScsiBus(DeviceObject); 04516 04517 // 04518 // Update the error count for the device. 04519 // 04520 04521 deviceExtension->ErrorCount++; 04522 } 04523 } 04524 04525 VOID 04526 NTAPI 04527 ScanForSpecial( 04528 PDEVICE_OBJECT DeviceObject, 04529 PSCSI_INQUIRY_DATA LunInfo, 04530 PIO_SCSI_CAPABILITIES PortCapabilities 04531 ) 04532 04533 /*++ 04534 04535 Routine Description: 04536 04537 This function checks to see if an SCSI logical unit requires speical 04538 flags to be set. 04539 04540 Arguments: 04541 04542 DeviceObject - Supplies the device object to be tested. 04543 04544 InquiryData - Supplies the inquiry data returned by the device of interest. 04545 04546 PortCapabilities - Supplies the capabilities of the device object. 04547 04548 Return Value: 04549 04550 None. 04551 04552 --*/ 04553 04554 { 04555 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 04556 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData; 04557 BAD_CONTROLLER_INFORMATION const *controller; 04558 ULONG j; 04559 04560 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) { 04561 04562 controller = &ScsiDiskBadControllers[j]; 04563 04564 if (strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) { 04565 continue; 04566 } 04567 04568 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller->InquiryString)); 04569 04570 // 04571 // Found a listed controller. Determine what must be done. 04572 // 04573 04574 if (controller->DisableTaggedQueuing) { 04575 04576 // 04577 // Disable tagged queuing. 04578 // 04579 04580 deviceExtension->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE; 04581 } 04582 04583 if (controller->DisableSynchronousTransfers) { 04584 04585 // 04586 // Disable synchronous data transfers. 04587 // 04588 04589 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 04590 04591 } 04592 04593 if (controller->DisableDisconnects) { 04594 04595 // 04596 // Disable disconnects. 04597 // 04598 04599 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT; 04600 04601 } 04602 04603 // 04604 // Found device so exit the loop and return. 04605 // 04606 04607 break; 04608 } 04609 04610 // 04611 // Set the StartUnit flag appropriately. 04612 // 04613 04614 if (DeviceObject->DeviceType == FILE_DEVICE_DISK) { 04615 deviceExtension->DeviceFlags |= DEV_SAFE_START_UNIT; 04616 04617 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 04618 if (_strnicmp((PCCHAR)InquiryData->VendorId, "iomega", strlen("iomega"))) { 04619 deviceExtension->DeviceFlags &= ~DEV_SAFE_START_UNIT; 04620 } 04621 } 04622 } 04623 04624 return; 04625 } 04626 04627 VOID 04628 NTAPI 04629 ResetScsiBus( 04630 IN PDEVICE_OBJECT DeviceObject 04631 ) 04632 04633 /*++ 04634 04635 Routine Description: 04636 04637 This command sends a reset bus command to the SCSI port driver. 04638 04639 Arguments: 04640 04641 DeviceObject - The device object for the logical unit with 04642 hardware problem. 04643 04644 Return Value: 04645 04646 None. 04647 04648 --*/ 04649 { 04650 PIO_STACK_LOCATION irpStack; 04651 PIRP irp; 04652 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 04653 PSCSI_REQUEST_BLOCK srb; 04654 PCOMPLETION_CONTEXT context; 04655 04656 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n")); 04657 04658 // 04659 // Allocate Srb from nonpaged pool. 04660 // 04661 04662 context = ExAllocatePool(NonPagedPoolMustSucceed, 04663 sizeof(COMPLETION_CONTEXT)); 04664 04665 // 04666 // Save the device object in the context for use by the completion 04667 // routine. 04668 // 04669 04670 context->DeviceObject = DeviceObject; 04671 srb = &context->Srb; 04672 04673 // 04674 // Zero out srb. 04675 // 04676 04677 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 04678 04679 // 04680 // Write length to SRB. 04681 // 04682 04683 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 04684 04685 // 04686 // Set up SCSI bus address. 04687 // 04688 04689 srb->PathId = deviceExtension->PathId; 04690 srb->TargetId = deviceExtension->TargetId; 04691 srb->Lun = deviceExtension->Lun; 04692 04693 srb->Function = SRB_FUNCTION_RESET_BUS; 04694 04695 // 04696 // Build the asynchronous request to be sent to the port driver. 04697 // Since this routine is called from a DPC the IRP should always be 04698 // available. 04699 // 04700 04701 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 04702 04703 IoSetCompletionRoutine(irp, 04704 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion, 04705 context, 04706 TRUE, 04707 TRUE, 04708 TRUE); 04709 04710 irpStack = IoGetNextIrpStackLocation(irp); 04711 04712 irpStack->MajorFunction = IRP_MJ_SCSI; 04713 04714 srb->OriginalRequest = irp; 04715 04716 // 04717 // Store the SRB address in next stack for port driver. 04718 // 04719 04720 irpStack->Parameters.Scsi.Srb = srb; 04721 04722 // 04723 // Call the port driver with the IRP. 04724 // 04725 04726 IoCallDriver(deviceExtension->PortDeviceObject, irp); 04727 04728 return; 04729 04730 } // end ResetScsiBus() 04731 04732 04733 VOID 04734 NTAPI 04735 UpdateDeviceObjects( 04736 IN PDEVICE_OBJECT PhysicalDisk, 04737 IN PIRP Irp 04738 ) 04739 04740 /*++ 04741 04742 Routine Description: 04743 04744 This routine creates, deletes and changes device objects when 04745 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates 04746 the drive layout information for the user. It is possible to 04747 call this routine even in the GET_LAYOUT case because RewritePartition 04748 will be false. 04749 04750 Arguments: 04751 04752 DeviceObject - Device object for physical disk. 04753 Irp - IO Request Packet (IRP). 04754 04755 Return Value: 04756 04757 None. 04758 04759 --*/ 04760 { 04761 PDEVICE_EXTENSION physicalExtension = PhysicalDisk->DeviceExtension; 04762 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer; 04763 ULONG partition; 04764 ULONG partitionNumber; 04765 ULONG partitionCount; 04766 ULONG lastPartition; 04767 ULONG partitionOrdinal; 04768 PPARTITION_INFORMATION partitionEntry; 04769 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH]; 04770 STRING ntNameString; 04771 UNICODE_STRING ntUnicodeString; 04772 PDEVICE_OBJECT deviceObject; 04773 PDEVICE_EXTENSION deviceExtension; 04774 PDISK_DATA diskData; 04775 NTSTATUS status; 04776 ULONG numberListElements; 04777 BOOLEAN found; 04778 04779 partitionCount = ((partitionList->PartitionCount + 3) / 4) * 4; 04780 04781 // 04782 // Zero all of the partition numbers. 04783 // 04784 04785 for (partition = 0; partition < partitionCount; partition++) { 04786 partitionEntry = &partitionList->PartitionEntry[partition]; 04787 partitionEntry->PartitionNumber = 0; 04788 } 04789 04790 // 04791 // Walk through chain of partitions for this disk to determine 04792 // which existing partitions have no match. 04793 // 04794 04795 deviceExtension = physicalExtension; 04796 diskData = (PDISK_DATA)(deviceExtension + 1); 04797 lastPartition = 0; 04798 04799 do { 04800 04801 deviceExtension = diskData->NextPartition; 04802 04803 // 04804 // Check if this is the last partition in the chain. 04805 // 04806 04807 if (!deviceExtension) { 04808 break; 04809 } 04810 04811 // 04812 // Get the partition device extension from disk data. 04813 // 04814 04815 diskData = (PDISK_DATA)(deviceExtension + 1); 04816 04817 // 04818 // Check for highest partition number this far. 04819 // 04820 04821 if (diskData->PartitionNumber > lastPartition) { 04822 lastPartition = diskData->PartitionNumber; 04823 } 04824 04825 // 04826 // Check if this partition is not currently being used. 04827 // 04828 04829 if (!deviceExtension->PartitionLength.QuadPart) { 04830 continue; 04831 } 04832 04833 // 04834 // Loop through partition information to look for match. 04835 // 04836 04837 found = FALSE; 04838 partitionOrdinal = 0; 04839 04840 for (partition = 0; partition < partitionCount; partition++) { 04841 04842 // 04843 // Get partition descriptor. 04844 // 04845 04846 partitionEntry = &partitionList->PartitionEntry[partition]; 04847 04848 // 04849 // Check if empty, or describes extended partiton or hasn't changed. 04850 // 04851 04852 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED || 04853 IsContainerPartition(partitionEntry->PartitionType)) { 04854 continue; 04855 } 04856 04857 // 04858 // Advance partition ordinal. 04859 // 04860 04861 partitionOrdinal++; 04862 04863 // 04864 // Check if new partition starts where this partition starts. 04865 // 04866 04867 if (partitionEntry->StartingOffset.QuadPart != 04868 deviceExtension->StartingOffset.QuadPart) { 04869 continue; 04870 } 04871 04872 // 04873 // Check if partition length is the same. 04874 // 04875 04876 if (partitionEntry->PartitionLength.QuadPart == 04877 deviceExtension->PartitionLength.QuadPart) { 04878 04879 DebugPrint((3, 04880 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n", 04881 physicalExtension->DeviceNumber, 04882 diskData->PartitionNumber)); 04883 04884 // 04885 // Indicate match is found and set partition number 04886 // in user buffer. 04887 // 04888 04889 found = TRUE; 04890 partitionEntry->PartitionNumber = diskData->PartitionNumber; 04891 break; 04892 } 04893 } 04894 04895 if (found) { 04896 04897 // 04898 // A match is found. 04899 // 04900 04901 diskData = (PDISK_DATA)(deviceExtension + 1); 04902 04903 // 04904 // If this partition is marked for update then update partition type. 04905 // 04906 04907 if (partitionEntry->RewritePartition) { 04908 diskData->PartitionType = partitionEntry->PartitionType; 04909 } 04910 04911 // 04912 // Update partitional ordinal for calls to HAL routine 04913 // IoSetPartitionInformation. 04914 // 04915 04916 diskData->PartitionOrdinal = partitionOrdinal; 04917 04918 DebugPrint((1, 04919 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n", 04920 physicalExtension->DeviceNumber, 04921 diskData->PartitionOrdinal, 04922 diskData->PartitionNumber)); 04923 04924 } else { 04925 04926 // 04927 // no match was found, indicate this partition is gone. 04928 // 04929 04930 DebugPrint((1, 04931 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n", 04932 physicalExtension->DeviceNumber, 04933 diskData->PartitionNumber)); 04934 04935 deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0; 04936 } 04937 04938 } while (TRUE); 04939 04940 // 04941 // Walk through partition loop to find new partitions and set up 04942 // device extensions to describe them. In some cases new device 04943 // objects will be created. 04944 // 04945 04946 partitionOrdinal = 0; 04947 04948 for (partition = 0; 04949 partition < partitionCount; 04950 partition++) { 04951 04952 // 04953 // Get partition descriptor. 04954 // 04955 04956 partitionEntry = &partitionList->PartitionEntry[partition]; 04957 04958 // 04959 // Check if empty, or describes an extended partiton. 04960 // 04961 04962 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED || 04963 IsContainerPartition(partitionEntry->PartitionType)) { 04964 continue; 04965 } 04966 04967 // 04968 // Keep track of position on the disk for calls to IoSetPartitionInformation. 04969 // 04970 04971 partitionOrdinal++; 04972 04973 // 04974 // Check if this entry should be rewritten. 04975 // 04976 04977 if (!partitionEntry->RewritePartition) { 04978 continue; 04979 } 04980 04981 if (partitionEntry->PartitionNumber) { 04982 04983 // 04984 // Partition is an exact match with an existing partition, but is 04985 // being written anyway. 04986 // 04987 04988 continue; 04989 } 04990 04991 // 04992 // Check first if existing device object is available by 04993 // walking partition extension list. 04994 // 04995 04996 partitionNumber = 0; 04997 deviceExtension = physicalExtension; 04998 diskData = (PDISK_DATA)(deviceExtension + 1); 04999 05000 do { 05001 05002 // 05003 // Get next partition device extension from disk data. 05004 // 05005 05006 deviceExtension = diskData->NextPartition; 05007 05008 if (!deviceExtension) { 05009 break; 05010 } 05011 05012 diskData = (PDISK_DATA)(deviceExtension + 1); 05013 05014 // 05015 // A device object is free if the partition length is set to zero. 05016 // 05017 05018 if (!deviceExtension->PartitionLength.QuadPart) { 05019 partitionNumber = diskData->PartitionNumber; 05020 break; 05021 } 05022 05023 } while (TRUE); 05024 05025 // 05026 // If partition number is still zero then a new device object 05027 // must be created. 05028 // 05029 05030 if (partitionNumber == 0) { 05031 05032 lastPartition++; 05033 partitionNumber = lastPartition; 05034 05035 // 05036 // Get or create partition object and set up partition parameters. 05037 // 05038 05039 sprintf(ntNameBuffer, 05040 "\\Device\\Harddisk%lu\\Partition%lu", 05041 physicalExtension->DeviceNumber, 05042 partitionNumber); 05043 05044 RtlInitString(&ntNameString, 05045 ntNameBuffer); 05046 05047 status = RtlAnsiStringToUnicodeString(&ntUnicodeString, 05048 &ntNameString, 05049 TRUE); 05050 05051 if (!NT_SUCCESS(status)) { 05052 continue; 05053 } 05054 05055 DebugPrint((3, 05056 "UpdateDeviceObjects: Create device object %s\n", 05057 ntNameBuffer)); 05058 05059 // 05060 // This is a new name. Create the device object to represent it. 05061 // 05062 05063 status = IoCreateDevice(PhysicalDisk->DriverObject, 05064 DEVICE_EXTENSION_SIZE, 05065 &ntUnicodeString, 05066 FILE_DEVICE_DISK, 05067 0, 05068 FALSE, 05069 &deviceObject); 05070 05071 if (!NT_SUCCESS(status)) { 05072 DebugPrint((1, 05073 "UpdateDeviceObjects: Can't create device %s\n", 05074 ntNameBuffer)); 05075 RtlFreeUnicodeString(&ntUnicodeString); 05076 continue; 05077 } 05078 05079 // 05080 // Set up device object fields. 05081 // 05082 05083 deviceObject->Flags |= DO_DIRECT_IO; 05084 deviceObject->StackSize = PhysicalDisk->StackSize; 05085 05086 // 05087 // Set up device extension fields. 05088 // 05089 05090 deviceExtension = deviceObject->DeviceExtension; 05091 05092 // 05093 // Copy physical disk extension to partition extension. 05094 // 05095 05096 RtlMoveMemory(deviceExtension, 05097 physicalExtension, 05098 sizeof(DEVICE_EXTENSION)); 05099 05100 // 05101 // Initialize the new S-List. 05102 // 05103 05104 if (deviceExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) { 05105 numberListElements = 30; 05106 } else { 05107 numberListElements = 8; 05108 } 05109 05110 // 05111 // Build the lookaside list for srb's for this partition based on 05112 // whether the adapter and disk can do tagged queueing. 05113 // 05114 05115 ScsiClassInitializeSrbLookasideList(deviceExtension, 05116 numberListElements); 05117 05118 // 05119 // Allocate spinlock for zoning for split-request completion. 05120 // 05121 05122 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock); 05123 05124 // 05125 // Write back partition number used in creating object name. 05126 // 05127 05128 partitionEntry->PartitionNumber = partitionNumber; 05129 05130 // 05131 // Clear flags initializing bit. 05132 // 05133 05134 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 05135 05136 // 05137 // Point back at device object. 05138 // 05139 05140 deviceExtension->DeviceObject = deviceObject; 05141 05142 RtlFreeUnicodeString(&ntUnicodeString); 05143 05144 // 05145 // Link to end of partition chain using previous disk data. 05146 // 05147 05148 diskData->NextPartition = deviceExtension; 05149 05150 // 05151 // Get new disk data and zero next partition pointer. 05152 // 05153 05154 diskData = (PDISK_DATA)(deviceExtension + 1); 05155 diskData->NextPartition = NULL; 05156 05157 } else { 05158 05159 // 05160 // Set pointer to disk data area that follows device extension. 05161 // 05162 05163 diskData = (PDISK_DATA)(deviceExtension + 1); 05164 05165 DebugPrint((1, 05166 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n", 05167 physicalExtension->DeviceNumber, 05168 partitionNumber)); 05169 } 05170 05171 // 05172 // Update partition information in partition device extension. 05173 // 05174 05175 diskData->PartitionNumber = partitionNumber; 05176 diskData->PartitionType = partitionEntry->PartitionType; 05177 diskData->BootIndicator = partitionEntry->BootIndicator; 05178 deviceExtension->StartingOffset = partitionEntry->StartingOffset; 05179 deviceExtension->PartitionLength = partitionEntry->PartitionLength; 05180 diskData->HiddenSectors = partitionEntry->HiddenSectors; 05181 diskData->PartitionOrdinal = partitionOrdinal; 05182 05183 DebugPrint((1, 05184 "UpdateDeviceObjects: Ordinal %d is partition %d\n", 05185 diskData->PartitionOrdinal, 05186 diskData->PartitionNumber)); 05187 05188 // 05189 // Update partition number passed in to indicate the 05190 // device name for this partition. 05191 // 05192 05193 partitionEntry->PartitionNumber = partitionNumber; 05194 } 05195 05196 } // end UpdateDeviceObjects() Generated on Sat May 26 2012 04:17:54 for ReactOS by
1.7.6.1
|