3 * Copyright (C) 2001, 2002, 2003, 2004 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/disk/disk.c
24 * PURPOSE: disk class driver
25 * PROGRAMMER: Eric Kohl
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
32 #include <ddk/class2.h>
33 #include <ddk/ntddscsi.h>
38 #define VERSION "0.0.1"
40 #define SCSI_DISK_TIMEOUT 10 /* Default timeout: 10 seconds */
41 #define MODE_DATA_SIZE 192
44 typedef struct _DISK_DATA
46 PDEVICE_EXTENSION NextPartition
;
50 ULONG PartitionNumber
;
51 ULONG PartitionOrdinal
;
53 BOOLEAN BootIndicator
;
54 BOOLEAN DriveNotReady
;
55 } DISK_DATA
, *PDISK_DATA
;
58 DiskClassFindDevices(PDRIVER_OBJECT DriverObject
,
59 PUNICODE_STRING RegistryPath
,
60 PCLASS_INIT_DATA InitializationData
,
61 PDEVICE_OBJECT PortDeviceObject
,
65 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData
);
68 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
72 DiskClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension
,
73 IN ULONG DeviceNumber
);
76 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
77 IN PUNICODE_STRING RegistryPath
, /* what's this used for? */
78 IN PDEVICE_OBJECT PortDeviceObject
,
81 IN PIO_SCSI_CAPABILITIES Capabilities
,
82 IN PSCSI_INQUIRY_DATA InquiryData
,
83 IN PCLASS_INIT_DATA InitializationData
);
86 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
90 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
94 ScsiDiskSearchForDisk(IN PDEVICE_EXTENSION DeviceExtension
,
96 OUT PULONG DetectedDiskNumber
);
99 DiskClassUpdatePartitionDeviceObjects (IN PDEVICE_OBJECT DeviceObject
,
103 ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension
);
106 ScsiDiskCalcMbrCheckSum(IN PDEVICE_EXTENSION DeviceExtension
,
107 OUT PULONG Checksum
);
111 DiskBuildPartitionTable(IN PDEVICE_OBJECT DiskDeviceObject
,
115 /* FUNCTIONS ****************************************************************/
117 /**********************************************************************
122 * This function initializes the driver, locates and claims
123 * hardware resources, and creates various NT objects needed
124 * to process I/O requests.
131 * System allocated Driver Object for this driver
134 * Name of registry driver service key
141 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
142 IN PUNICODE_STRING RegistryPath
)
144 CLASS_INIT_DATA InitData
;
146 DPRINT("Disk Class Driver %s\n",
148 DPRINT("RegistryPath '%wZ'\n",
151 RtlZeroMemory(&InitData
,
152 sizeof(CLASS_INIT_DATA
));
154 InitData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
155 InitData
.DeviceExtensionSize
= sizeof(DEVICE_EXTENSION
) + sizeof(DISK_DATA
);
156 InitData
.DeviceType
= FILE_DEVICE_DISK
;
157 InitData
.DeviceCharacteristics
= 0;
159 InitData
.ClassError
= NULL
; // DiskClassProcessError;
160 InitData
.ClassReadWriteVerification
= DiskClassCheckReadWrite
;
161 InitData
.ClassFindDeviceCallBack
= DiskClassCheckDevice
;
162 InitData
.ClassFindDevices
= DiskClassFindDevices
;
163 InitData
.ClassDeviceControl
= DiskClassDeviceControl
;
164 InitData
.ClassShutdownFlush
= DiskClassShutdownFlush
;
165 InitData
.ClassCreateClose
= NULL
;
166 InitData
.ClassStartIo
= NULL
;
168 return(ScsiClassInitialize(DriverObject
,
174 /**********************************************************************
176 * DiskClassFindDevices
179 * This function searches for device that are attached to the
187 * System allocated Driver Object for this driver
190 * Name of registry driver service key
193 * Pointer to the main initialization data
196 * Pointer to the port Device Object
202 * TRUE: At least one disk drive was found
203 * FALSE: No disk drive found
207 DiskClassFindDevices(PDRIVER_OBJECT DriverObject
,
208 PUNICODE_STRING RegistryPath
,
209 PCLASS_INIT_DATA InitializationData
,
210 PDEVICE_OBJECT PortDeviceObject
,
213 PCONFIGURATION_INFORMATION ConfigInfo
;
214 PIO_SCSI_CAPABILITIES PortCapabilities
;
215 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
216 PSCSI_INQUIRY_DATA UnitInfo
;
217 PINQUIRYDATA InquiryData
;
221 BOOLEAN FoundDevice
= FALSE
;
224 DPRINT("DiskClassFindDevices() called.\n");
226 /* Get port capabilities */
227 Status
= ScsiClassGetCapabilities(PortDeviceObject
,
229 if (!NT_SUCCESS(Status
))
231 DPRINT("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status
);
235 DPRINT("PortCapabilities: %p\n", PortCapabilities
);
236 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities
->MaximumTransferLength
);
237 DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities
->MaximumPhysicalPages
);
239 /* Get inquiry data */
240 Status
= ScsiClassGetInquiryData(PortDeviceObject
,
241 (PSCSI_ADAPTER_BUS_INFO
*)&Buffer
);
242 if (!NT_SUCCESS(Status
))
244 DPRINT("ScsiClassGetInquiryData() failed! (Status %x)\n", Status
);
248 /* Check whether there are unclaimed devices */
249 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
250 DeviceCount
= ScsiClassFindUnclaimedDevices(InitializationData
,
252 if (DeviceCount
== 0)
254 DPRINT("No unclaimed devices!\n");
258 DPRINT("Found %lu unclaimed devices!\n", DeviceCount
);
260 ConfigInfo
= IoGetConfigurationInformation();
262 /* Search each bus of this adapter */
263 for (Bus
= 0; Bus
< (ULONG
)AdapterBusInfo
->NumberOfBuses
; Bus
++)
265 DPRINT("Searching bus %lu\n", Bus
);
267 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
);
269 while (AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
)
271 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
273 DPRINT("Device type %u\n", InquiryData
->DeviceType
);
275 if (((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
276 (InquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
277 (InquiryData
->DeviceTypeQualifier
== 0) &&
278 (UnitInfo
->DeviceClaimed
== FALSE
))
280 DPRINT("Vendor: '%.24s'\n",
281 InquiryData
->VendorId
);
283 /* Create device objects for disk */
284 Status
= DiskClassCreateDeviceObject(DriverObject
,
288 ConfigInfo
->DiskCount
,
292 if (NT_SUCCESS(Status
))
294 ConfigInfo
->DiskCount
++;
299 if (UnitInfo
->NextInquiryDataOffset
== 0)
302 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ UnitInfo
->NextInquiryDataOffset
);
308 DPRINT("DiskClassFindDevices() done\n");
315 DiskClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension
,
316 IN ULONG DeviceNumber
)
318 DeviceExtension
->MediaChangeEvent
=
319 IoCreateSynchronizationEvent (NULL
,
320 &DeviceExtension
->MediaChangeEventHandle
);
322 KeClearEvent (DeviceExtension
->MediaChangeEvent
);
327 /**********************************************************************
329 * DiskClassCheckDevice
332 * This function checks the InquiryData for the correct device
333 * type and qualifier.
340 * Pointer to the inquiry data for the device in question.
343 * TRUE: A disk device was found.
348 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData
)
350 return((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
||
351 InquiryData
->DeviceType
== OPTICAL_DEVICE
) &&
352 InquiryData
->DeviceTypeQualifier
== 0);
356 /**********************************************************************
358 * DiskClassCheckReadWrite
361 * This function checks the given IRP for correct data.
368 * Pointer to the device.
374 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
379 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
382 PDEVICE_EXTENSION DeviceExtension
;
384 PIO_STACK_LOCATION IrpStack
;
385 ULARGE_INTEGER EndingOffset
;
387 DPRINT("DiskClassCheckReadWrite() called\n");
389 DeviceExtension
= DeviceObject
->DeviceExtension
;
390 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
392 if (DiskData
->DriveNotReady
== TRUE
)
394 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
395 IoSetHardErrorOrVerifyDevice(Irp
,
397 return(STATUS_INVALID_PARAMETER
);
402 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
403 EndingOffset
.QuadPart
= IrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
404 IrpStack
->Parameters
.Read
.Length
;
407 DPRINT("Ending %I64d, and RealEnding %I64d! PartSize %I64d\n",EndingOffset
.QuadPart
,
408 DeviceExtension
->PartitionLength
.QuadPart
,
409 DeviceExtension
->PartitionLength
.QuadPart
/
410 DeviceExtension
->DiskGeometry
->BytesPerSector
);
412 if ((DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
413 (DeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
415 /* Assume if removable media and if Partition length is 0, Partition not built yet! */
416 if (DeviceExtension
->PartitionLength
.QuadPart
== 0)
417 return(STATUS_SUCCESS
);
420 if (EndingOffset
.QuadPart
> DeviceExtension
->PartitionLength
.QuadPart
)
422 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
423 return(STATUS_INVALID_PARAMETER
);
426 return(STATUS_SUCCESS
);
430 /**********************************************************************
432 * DiskClassCreateDeviceObject
435 * Create the raw device and any partition devices on this drive
442 * The system created driver object
452 * STATUS_SUCCESS: Device objects for disk and partitions were created.
457 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
458 IN PUNICODE_STRING RegistryPath
,
459 IN PDEVICE_OBJECT PortDeviceObject
,
462 IN PIO_SCSI_CAPABILITIES Capabilities
,
463 IN PSCSI_INQUIRY_DATA InquiryData
,
464 IN PCLASS_INIT_DATA InitializationData
)
466 OBJECT_ATTRIBUTES ObjectAttributes
;
467 UNICODE_STRING UnicodeDeviceDirName
;
468 WCHAR NameBuffer
[80];
469 CHAR NameBuffer2
[80];
470 PDEVICE_OBJECT DiskDeviceObject
;
471 PDEVICE_OBJECT PartitionDeviceObject
;
472 PDEVICE_EXTENSION DiskDeviceExtension
; /* defined in class2.h */
473 PDEVICE_EXTENSION PartitionDeviceExtension
; /* defined in class2.h */
474 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
476 PPARTITION_INFORMATION PartitionEntry
;
478 ULONG PartitionNumber
;
482 DPRINT("DiskClassCreateDeviceObject() called\n");
484 /* Create the harddisk device directory */
486 L
"\\Device\\Harddisk%lu",
488 RtlInitUnicodeString(&UnicodeDeviceDirName
,
490 InitializeObjectAttributes(&ObjectAttributes
,
491 &UnicodeDeviceDirName
,
495 Status
= ZwCreateDirectoryObject(&Handle
,
498 if (!NT_SUCCESS(Status
))
500 DbgPrint("Could not create device dir object\n");
504 /* Claim the disk device */
505 Status
= ScsiClassClaimDevice(PortDeviceObject
,
509 if (!NT_SUCCESS(Status
))
511 DbgPrint("Could not claim disk device\n");
513 ZwMakeTemporaryObject(Handle
);
519 /* Create disk device (Partition 0) */
521 "\\Device\\Harddisk%lu\\Partition0",
524 Status
= ScsiClassCreateDeviceObject(DriverObject
,
529 if (!NT_SUCCESS(Status
))
531 DPRINT("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status
);
533 /* Release (unclaim) the disk */
534 ScsiClassClaimDevice(PortDeviceObject
,
539 /* Delete the harddisk device directory */
540 ZwMakeTemporaryObject(Handle
);
546 DiskDeviceObject
->Flags
|= DO_DIRECT_IO
;
547 if (((PINQUIRYDATA
)InquiryData
->InquiryData
)->RemovableMedia
)
549 DiskDeviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
551 DiskDeviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
553 if (PortDeviceObject
->AlignmentRequirement
> DiskDeviceObject
->AlignmentRequirement
)
555 DiskDeviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
558 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
559 DiskDeviceExtension
->LockCount
= 0;
560 DiskDeviceExtension
->DeviceNumber
= DiskNumber
;
561 DiskDeviceExtension
->DeviceObject
= DiskDeviceObject
;
562 DiskDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
563 DiskDeviceExtension
->PhysicalDevice
= DiskDeviceObject
;
564 DiskDeviceExtension
->PortCapabilities
= Capabilities
;
565 DiskDeviceExtension
->StartingOffset
.QuadPart
= 0;
566 DiskDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
567 DiskDeviceExtension
->PathId
= InquiryData
->PathId
;
568 DiskDeviceExtension
->TargetId
= InquiryData
->TargetId
;
569 DiskDeviceExtension
->Lun
= InquiryData
->Lun
;
570 DiskDeviceExtension
->SrbFlags
= 0;
572 /* Enable the command queueing, if it possible */
573 if (Capabilities
->TaggedQueuing
&&
574 ((PINQUIRYDATA
)InquiryData
->InquiryData
)->CommandQueue
)
576 DiskDeviceExtension
->SrbFlags
|= SRB_FLAGS_QUEUE_ACTION_ENABLE
;
579 /* Get timeout value */
580 DiskDeviceExtension
->TimeOutValue
=
581 ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
582 if (DiskDeviceExtension
->TimeOutValue
== 0)
583 DiskDeviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
585 /* Initialize the lookaside list for SRBs */
586 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension
,
589 /* zero-out disk data */
590 DiskData
= (PDISK_DATA
)(DiskDeviceExtension
+ 1);
591 RtlZeroMemory(DiskData
,
594 /* Get disk geometry */
595 DiskDeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
596 sizeof(DISK_GEOMETRY
));
597 if (DiskDeviceExtension
->DiskGeometry
== NULL
)
599 DPRINT("Failed to allocate geometry buffer!\n");
601 ExDeleteNPagedLookasideList(&DiskDeviceExtension
->SrbLookasideListHead
);
603 IoDeleteDevice(DiskDeviceObject
);
605 /* Release (unclaim) the disk */
606 ScsiClassClaimDevice(PortDeviceObject
,
611 /* Delete the harddisk device directory */
612 ZwMakeTemporaryObject(Handle
);
615 return(STATUS_INSUFFICIENT_RESOURCES
);
618 /* Allocate sense data buffer */
619 DiskDeviceExtension
->SenseData
= ExAllocatePool(NonPagedPoolCacheAligned
,
621 if (DiskDeviceExtension
->SenseData
== NULL
)
623 DPRINT("Failed to allocate sense data buffer!\n");
625 ExFreePool (DiskDeviceExtension
->DiskGeometry
);
627 ExDeleteNPagedLookasideList(&DiskDeviceExtension
->SrbLookasideListHead
);
629 IoDeleteDevice(DiskDeviceObject
);
631 /* Release (unclaim) the disk */
632 ScsiClassClaimDevice(PortDeviceObject
,
637 /* Delete the harddisk device directory */
638 ZwMakeTemporaryObject(Handle
);
641 return(STATUS_INSUFFICIENT_RESOURCES
);
644 /* Read the drive's capacity */
645 Status
= ScsiClassReadDriveCapacity(DiskDeviceObject
);
646 if (!NT_SUCCESS(Status
) &&
647 (DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) == 0)
649 DPRINT("Failed to retrieve drive capacity!\n");
650 return(STATUS_SUCCESS
);
654 /* Clear the verify flag for removable media drives. */
655 DiskDeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
658 DPRINT("SectorSize: %lu\n", DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
660 if ((DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
661 (DiskDeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
663 DiskClassCreateMediaChangeEvent(DiskDeviceExtension
,DiskNumber
);
664 if (DiskDeviceExtension
->MediaChangeEvent
!= NULL
)
666 DPRINT("Allocated media change event!\n");
670 /* Check disk for presence of a disk manager */
671 HalExamineMBR(DiskDeviceObject
,
672 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
675 if (MbrBuffer
!= NULL
)
677 /* Start disk at sector 63 if the Ontrack Disk Manager was found */
678 DPRINT("Found 'Ontrack Disk Manager'!\n");
680 DiskDeviceExtension
->DMSkew
= 63;
681 DiskDeviceExtension
->DMByteSkew
=
682 63 * DiskDeviceExtension
->DiskGeometry
->BytesPerSector
;
683 DiskDeviceExtension
->DMActive
= TRUE
;
685 ExFreePool(MbrBuffer
);
689 if ((DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
690 (DiskDeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
692 /* Allocate a partition list for a single entry. */
693 PartitionList
= ExAllocatePool(NonPagedPool
,
694 sizeof(DRIVE_LAYOUT_INFORMATION
));
695 if (PartitionList
!= NULL
)
697 RtlZeroMemory(PartitionList
,
698 sizeof(DRIVE_LAYOUT_INFORMATION
));
699 PartitionList
->PartitionCount
= 1;
701 DiskData
->DriveNotReady
= TRUE
;
702 Status
= STATUS_SUCCESS
;
707 /* Read partition table */
708 Status
= IoReadPartitionTable(DiskDeviceObject
,
709 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
713 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status
);
715 if ((!NT_SUCCESS(Status
) || PartitionList
->PartitionCount
== 0) &&
716 DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
718 if (!NT_SUCCESS(Status
))
720 /* Drive is not ready. */
721 DPRINT("Drive not ready\n");
722 DiskData
->DriveNotReady
= TRUE
;
726 ExFreePool(PartitionList
);
729 /* Allocate a partition list for a single entry. */
730 PartitionList
= ExAllocatePool(NonPagedPool
,
731 sizeof(DRIVE_LAYOUT_INFORMATION
));
732 if (PartitionList
!= NULL
)
734 RtlZeroMemory(PartitionList
,
735 sizeof(DRIVE_LAYOUT_INFORMATION
));
736 PartitionList
->PartitionCount
= 1;
738 Status
= STATUS_SUCCESS
;
743 if (NT_SUCCESS(Status
))
745 DPRINT("Read partition table!\n");
746 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
748 /* Set disk signature */
749 DiskData
->Signature
= PartitionList
->Signature
;
751 /* Calculate MBR checksum if disk got no signature */
752 if (DiskData
->Signature
== 0)
754 if (!ScsiDiskCalcMbrCheckSum(DiskDeviceExtension
,
755 &DiskData
->MbrCheckSum
))
757 DPRINT("MBR checksum calculation failed for disk %lu\n",
758 DiskDeviceExtension
->DeviceNumber
);
762 DPRINT("MBR checksum for disk %lu is %lx\n",
763 DiskDeviceExtension
->DeviceNumber
,
764 DiskData
->MbrCheckSum
);
769 DPRINT("Signature on disk %lu is %lx\n",
770 DiskDeviceExtension
->DeviceNumber
,
771 DiskData
->Signature
);
774 /* Update disk geometry if disk is visible to the BIOS */
775 ScsiDiskUpdateFixedDiskGeometry(DiskDeviceExtension
);
777 for (PartitionNumber
= 0; PartitionNumber
< PartitionList
->PartitionCount
; PartitionNumber
++)
779 PartitionEntry
= &PartitionList
->PartitionEntry
[PartitionNumber
];
781 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
783 PartitionEntry
->PartitionNumber
,
784 PartitionEntry
->BootIndicator
,
785 PartitionEntry
->PartitionType
,
786 PartitionEntry
->StartingOffset
.QuadPart
/
787 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
788 PartitionEntry
->PartitionLength
.QuadPart
/
789 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
791 /* Create partition device object */
793 "\\Device\\Harddisk%lu\\Partition%lu",
795 PartitionNumber
+ 1);
797 Status
= ScsiClassCreateDeviceObject(DriverObject
,
800 &PartitionDeviceObject
,
802 DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status
);
803 if (NT_SUCCESS(Status
))
805 PartitionDeviceObject
->Flags
= DiskDeviceObject
->Flags
;
806 PartitionDeviceObject
->Characteristics
= DiskDeviceObject
->Characteristics
;
807 PartitionDeviceObject
->StackSize
= DiskDeviceObject
->StackSize
;
808 PartitionDeviceObject
->AlignmentRequirement
= DiskDeviceObject
->AlignmentRequirement
;
810 PartitionDeviceExtension
= PartitionDeviceObject
->DeviceExtension
;
811 PartitionDeviceExtension
->SenseData
= DiskDeviceExtension
->SenseData
;
812 PartitionDeviceExtension
->LockCount
= 0;
813 PartitionDeviceExtension
->DeviceNumber
= DiskNumber
;
814 PartitionDeviceExtension
->DeviceObject
= PartitionDeviceObject
;
815 PartitionDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
816 PartitionDeviceExtension
->DiskGeometry
= DiskDeviceExtension
->DiskGeometry
;
817 PartitionDeviceExtension
->PhysicalDevice
= DiskDeviceExtension
->PhysicalDevice
;
818 PartitionDeviceExtension
->PortCapabilities
= Capabilities
;
819 PartitionDeviceExtension
->StartingOffset
.QuadPart
=
820 PartitionEntry
->StartingOffset
.QuadPart
;
821 PartitionDeviceExtension
->PartitionLength
.QuadPart
=
822 PartitionEntry
->PartitionLength
.QuadPart
;
823 PartitionDeviceExtension
->DMSkew
= DiskDeviceExtension
->DMSkew
;
824 PartitionDeviceExtension
->DMByteSkew
= DiskDeviceExtension
->DMByteSkew
;
825 PartitionDeviceExtension
->DMActive
= DiskDeviceExtension
->DMActive
;
826 PartitionDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
827 PartitionDeviceExtension
->PathId
= InquiryData
->PathId
;
828 PartitionDeviceExtension
->TargetId
= InquiryData
->TargetId
;
829 PartitionDeviceExtension
->Lun
= InquiryData
->Lun
;
830 PartitionDeviceExtension
->SectorShift
= DiskDeviceExtension
->SectorShift
;
831 PartitionDeviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
833 /* Initialize lookaside list for SRBs */
834 ScsiClassInitializeSrbLookasideList(PartitionDeviceExtension
,
837 /* Link current partition device extension to previous disk data */
838 DiskData
->NextPartition
= PartitionDeviceExtension
;
840 /* Initialize current disk data */
841 DiskData
= (PDISK_DATA
)(PartitionDeviceExtension
+ 1);
842 DiskData
->NextPartition
= NULL
;
843 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
844 DiskData
->PartitionNumber
= PartitionNumber
+ 1;
845 DiskData
->PartitionOrdinal
= PartitionNumber
+ 1;
846 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
847 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
848 DiskData
->DriveNotReady
= FALSE
;
852 DPRINT("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status
);
859 if (PartitionList
!= NULL
)
860 ExFreePool(PartitionList
);
862 DPRINT("DiskClassCreateDeviceObjects() done\n");
864 return(STATUS_SUCCESS
);
869 DiskBuildPartitionTable(IN PDEVICE_OBJECT DiskDeviceObject
,
872 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
873 PDEVICE_EXTENSION DiskDeviceExtension
, DDE
;
874 PDISK_DATA DiskData
, DD
;
875 PPARTITION_INFORMATION PartitionEntry
;
876 ULONG PartitionNumber
;
879 DPRINT("DiskBuildPartitionTable() start\n");
881 DiskDeviceExtension
= (PDEVICE_EXTENSION
)DiskDeviceObject
->DeviceExtension
;
882 DiskData
= (PDISK_DATA
)(DiskDeviceExtension
+ 1);
884 DDE
= (PDEVICE_EXTENSION
) DiskDeviceExtension
->PhysicalDevice
->DeviceExtension
;
885 DD
= (PDISK_DATA
)(DDE
+1);
887 /* Clear flag for Partition0, just incase it was set. */
888 DD
->DriveNotReady
= FALSE
;
890 Status
= ScsiClassReadDriveCapacity(DiskDeviceObject
);
891 if (!NT_SUCCESS(Status
))
893 /* Drive is not ready. */
894 DPRINT("Drive not ready\n");
895 DiskData
->DriveNotReady
= TRUE
;
899 /* Read partition table */
900 Status
= IoReadPartitionTable(DiskDeviceExtension
->PhysicalDevice
,
901 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
905 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status
);
907 if (!NT_SUCCESS(Status
))
909 /* Drive is not ready. */
910 DPRINT("Drive not ready\n");
911 DiskData
->DriveNotReady
= TRUE
;
912 if (PartitionList
!= NULL
)
913 ExFreePool(PartitionList
);
917 if (NT_SUCCESS(Status
))
919 DPRINT("Read partition table!\n");
920 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
922 /* Set disk signature */
923 DiskData
->Signature
= PartitionList
->Signature
;
925 DiskData
->NextPartition
= NULL
;
927 if (PartitionList
->PartitionCount
)
929 for (PartitionNumber
= 0; PartitionNumber
< PartitionList
->PartitionCount
; PartitionNumber
++)
931 PartitionEntry
= &PartitionList
->PartitionEntry
[PartitionNumber
];
933 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
934 DiskData
->PartitionNumber
= PartitionNumber
+ 1;
935 DiskData
->PartitionOrdinal
= PartitionNumber
+ 1;
936 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
937 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
938 DiskData
->DriveNotReady
= FALSE
;
939 DiskDeviceExtension
->StartingOffset
= PartitionEntry
->StartingOffset
;
940 DiskDeviceExtension
->PartitionLength
= PartitionEntry
->PartitionLength
;
942 DPRINT1("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
944 DiskData
->PartitionNumber
,
945 DiskData
->BootIndicator
,
946 DiskData
->PartitionType
,
947 DiskDeviceExtension
->StartingOffset
.QuadPart
/
948 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
949 DiskDeviceExtension
->PartitionLength
.QuadPart
/
950 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
955 DiskData
->PartitionType
= 0;
956 DiskData
->PartitionNumber
= 1;
957 DiskData
->PartitionOrdinal
= 0;
958 DiskData
->HiddenSectors
= 0;
959 DiskData
->BootIndicator
= 0;
960 DiskData
->DriveNotReady
= FALSE
;
961 DiskDeviceExtension
->StartingOffset
.QuadPart
= 0;
962 DiskDeviceExtension
->PartitionLength
.QuadPart
+= DiskDeviceExtension
->StartingOffset
.QuadPart
;
966 DPRINT("DiskBuildPartitionTable() done\n");
967 if (PartitionList
!= NULL
)
968 ExFreePool(PartitionList
);
969 return(STATUS_SUCCESS
);
973 /**********************************************************************
975 * DiskClassDeviceControl
978 * Answer requests for device control calls
984 * Standard dispatch arguments
991 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
994 PDEVICE_EXTENSION DeviceExtension
;
995 PIO_STACK_LOCATION IrpStack
;
996 ULONG ControlCode
, InputLength
, OutputLength
;
1001 DPRINT("DiskClassDeviceControl() called!\n");
1003 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1005 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1006 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
1007 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
1008 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
1009 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1010 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1012 switch (ControlCode
)
1014 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
1015 DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
1016 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
1018 Status
= STATUS_INVALID_PARAMETER
;
1022 if (DeviceExtension
->DiskGeometry
== NULL
)
1024 DPRINT("No disk geometry available!\n");
1025 DeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
1026 sizeof(DISK_GEOMETRY
));
1029 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
1031 Status
= ScsiClassReadDriveCapacity(DeviceObject
);
1032 DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status
);
1033 if (!NT_SUCCESS(Status
))
1035 /* Drive is not ready */
1036 DiskData
->DriveNotReady
= TRUE
;
1040 /* Drive is ready */
1041 DiskData
->DriveNotReady
= FALSE
;
1044 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1045 DeviceExtension
->DiskGeometry
,
1046 sizeof(DISK_GEOMETRY
));
1048 Status
= STATUS_SUCCESS
;
1049 Information
= sizeof(DISK_GEOMETRY
);
1052 case IOCTL_DISK_GET_PARTITION_INFO
:
1053 DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
1055 if ((DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
1056 (DeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
1058 /* Update a partition list for a single entry. */
1059 Status
= DiskBuildPartitionTable(DeviceObject
,Irp
);
1062 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1063 sizeof(PARTITION_INFORMATION
))
1065 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1067 else if (DiskData
->PartitionNumber
== 0)
1069 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1073 PPARTITION_INFORMATION PartitionInfo
;
1075 PartitionInfo
= (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
1077 PartitionInfo
->PartitionType
= DiskData
->PartitionType
;
1078 PartitionInfo
->StartingOffset
= DeviceExtension
->StartingOffset
;
1079 PartitionInfo
->PartitionLength
= DeviceExtension
->PartitionLength
;
1080 PartitionInfo
->HiddenSectors
= DiskData
->HiddenSectors
;
1081 PartitionInfo
->PartitionNumber
= DiskData
->PartitionNumber
;
1082 PartitionInfo
->BootIndicator
= DiskData
->BootIndicator
;
1083 PartitionInfo
->RewritePartition
= FALSE
;
1084 PartitionInfo
->RecognizedPartition
=
1085 IsRecognizedPartition(DiskData
->PartitionType
);
1087 Status
= STATUS_SUCCESS
;
1088 Information
= sizeof(PARTITION_INFORMATION
);
1092 case IOCTL_DISK_SET_PARTITION_INFO
:
1093 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1094 sizeof(SET_PARTITION_INFORMATION
))
1096 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1098 else if (DiskData
->PartitionNumber
== 0)
1100 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1104 PSET_PARTITION_INFORMATION PartitionInfo
;
1106 PartitionInfo
= (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
1108 Status
= IoSetPartitionInformation(DeviceExtension
->PhysicalDevice
,
1109 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1110 DiskData
->PartitionOrdinal
,
1111 PartitionInfo
->PartitionType
);
1112 if (NT_SUCCESS(Status
))
1114 DiskData
->PartitionType
= PartitionInfo
->PartitionType
;
1119 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1120 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1121 sizeof(DRIVE_LAYOUT_INFORMATION
))
1123 Status
= STATUS_BUFFER_TOO_SMALL
;
1127 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1129 Status
= IoReadPartitionTable(DeviceExtension
->PhysicalDevice
,
1130 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1133 if (NT_SUCCESS(Status
))
1137 BufferSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
1139 BufferSize
+= PartitionList
->PartitionCount
* sizeof(PARTITION_INFORMATION
);
1141 if (BufferSize
> IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
1143 Status
= STATUS_BUFFER_TOO_SMALL
;
1147 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1150 Status
= STATUS_SUCCESS
;
1151 Information
= BufferSize
;
1153 ExFreePool(PartitionList
);
1158 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
1159 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1160 sizeof(DRIVE_LAYOUT_INFORMATION
))
1162 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1164 else if (DeviceExtension
->PhysicalDevice
->DeviceExtension
!= DeviceExtension
)
1166 Status
= STATUS_INVALID_PARAMETER
;
1170 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1173 PartitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
1174 TableSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
1175 ((PartitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
));
1177 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< TableSize
)
1179 Status
= STATUS_BUFFER_TOO_SMALL
;
1183 /* Update partition device objects */
1184 DiskClassUpdatePartitionDeviceObjects (DeviceObject
,
1187 /* Write partition table */
1188 Status
= IoWritePartitionTable(DeviceExtension
->PhysicalDevice
,
1189 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1190 DeviceExtension
->DiskGeometry
->SectorsPerTrack
,
1191 DeviceExtension
->DiskGeometry
->TracksPerCylinder
,
1197 case IOCTL_DISK_IS_WRITABLE
:
1199 PMODE_PARAMETER_HEADER ModeData
;
1202 ModeData
= ExAllocatePool (NonPagedPool
,
1204 if (ModeData
== NULL
)
1206 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1209 RtlZeroMemory (ModeData
,
1212 Length
= ScsiClassModeSense (DeviceObject
,
1215 MODE_SENSE_RETURN_ALL
);
1216 if (Length
< sizeof(MODE_PARAMETER_HEADER
))
1219 Status
= STATUS_IO_DEVICE_ERROR
;
1220 ExFreePool (ModeData
);
1224 if (ModeData
->DeviceSpecificParameter
& MODE_DSP_WRITE_PROTECT
)
1226 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1230 Status
= STATUS_SUCCESS
;
1232 ExFreePool (ModeData
);
1236 case IOCTL_DISK_VERIFY
:
1237 case IOCTL_DISK_FORMAT_TRACKS
:
1238 case IOCTL_DISK_PERFORMANCE
:
1239 case IOCTL_DISK_LOGGING
:
1240 case IOCTL_DISK_FORMAT_TRACKS_EX
:
1241 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
1242 case IOCTL_DISK_HISTOGRAM_DATA
:
1243 case IOCTL_DISK_HISTOGRAM_RESET
:
1244 case IOCTL_DISK_REQUEST_STRUCTURE
:
1245 case IOCTL_DISK_REQUEST_DATA
:
1246 /* If we get here, something went wrong. Inform the requestor */
1247 DPRINT("Unhandled control code: %lx\n", ControlCode
);
1248 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1253 /* Call the common device control function */
1254 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
1257 /* Verify the device if the user caused the error */
1258 if (!NT_SUCCESS(Status
) && IoIsErrorUserInduced(Status
))
1260 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1263 Irp
->IoStatus
.Status
= Status
;
1264 Irp
->IoStatus
.Information
= Information
;
1265 IoCompleteRequest(Irp
,
1272 /**********************************************************************
1274 * DiskClassShutdownFlush
1277 * Answer requests for shutdown and flush calls.
1284 * Pointer to the device.
1287 * Pointer to the IRP
1294 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
1297 PDEVICE_EXTENSION DeviceExtension
;
1298 PIO_STACK_LOCATION IrpStack
;
1299 PSCSI_REQUEST_BLOCK Srb
;
1301 DPRINT("DiskClassShutdownFlush() called!\n");
1303 DeviceExtension
= DeviceObject
->DeviceExtension
;
1306 Srb
= ExAllocatePool(NonPagedPool
,
1307 sizeof(SCSI_REQUEST_BLOCK
));
1310 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1311 Irp
->IoStatus
.Information
= 0;
1312 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1314 return(STATUS_INSUFFICIENT_RESOURCES
);
1317 /* Initialize SRB */
1318 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
1319 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
1321 /* Set device IDs */
1322 Srb
->PathId
= DeviceExtension
->PathId
;
1323 Srb
->TargetId
= DeviceExtension
->TargetId
;
1324 Srb
->Lun
= DeviceExtension
->Lun
;
1327 Srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
* 4;
1329 /* Flush write cache */
1330 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1331 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1332 Srb
->CdbLength
= 10;
1333 Srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
1334 ScsiClassSendSrbSynchronous(DeviceObject
,
1340 /* Get current stack location */
1341 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1343 /* FIXME: Unlock removable media upon shutdown */
1347 IrpStack
->Parameters
.Others
.Argument4
= (PVOID
)0;
1349 /* Send shutdown or flush request to the port driver */
1351 if (IrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
)
1352 Srb
->Function
= SRB_FUNCTION_SHUTDOWN
;
1354 Srb
->Function
= SRB_FUNCTION_FLUSH
;
1356 /* Init completion routine */
1357 IoSetCompletionRoutine(Irp
,
1358 ScsiClassIoComplete
,
1364 /* Prepare next stack location for a call to the port driver */
1365 IrpStack
= IoGetNextIrpStackLocation(Irp
);
1366 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1367 IrpStack
->Parameters
.Scsi
.Srb
= Srb
;
1368 Srb
->OriginalRequest
= Irp
;
1370 /* Call port driver */
1371 return(IoCallDriver(DeviceExtension
->PortDeviceObject
, Irp
));
1375 /**********************************************************************
1377 * DiskClassUpdatePartitionDeviceObjects
1380 * Deletes, modifies or creates partition device objects.
1387 * Pointer to the device.
1390 * Pointer to the IRP
1397 DiskClassUpdatePartitionDeviceObjects(IN PDEVICE_OBJECT DiskDeviceObject
,
1400 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1401 PPARTITION_INFORMATION PartitionEntry
;
1402 PDEVICE_EXTENSION DeviceExtension
;
1403 PDEVICE_EXTENSION DiskDeviceExtension
;
1404 PDISK_DATA DiskData
;
1405 ULONG PartitionCount
;
1406 ULONG PartitionOrdinal
;
1407 ULONG PartitionNumber
;
1408 ULONG LastPartitionNumber
;
1411 WCHAR NameBuffer
[MAX_PATH
];
1412 UNICODE_STRING DeviceName
;
1413 PDEVICE_OBJECT DeviceObject
;
1416 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() called\n");
1418 /* Get partition list */
1419 PartitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
1421 /* Round partition count up by 4 */
1422 PartitionCount
= ((PartitionList
->PartitionCount
+ 3) / 4) * 4;
1424 /* Remove the partition numbers from the partition list */
1425 for (i
= 0; i
< PartitionCount
; i
++)
1427 PartitionList
->PartitionEntry
[i
].PartitionNumber
= 0;
1430 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
1432 /* Traverse on-disk partition list */
1433 LastPartitionNumber
= 0;
1434 DeviceExtension
= DiskDeviceExtension
;
1435 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1438 DeviceExtension
= DiskData
->NextPartition
;
1439 if (DeviceExtension
== NULL
)
1443 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1445 /* Update last partition number */
1446 if (DiskData
->PartitionNumber
> LastPartitionNumber
)
1447 LastPartitionNumber
= DiskData
->PartitionNumber
;
1449 /* Ignore unused on-disk partitions */
1450 if (DeviceExtension
->PartitionLength
.QuadPart
== 0ULL)
1454 PartitionOrdinal
= 0;
1455 for (i
= 0; i
< PartitionCount
; i
++)
1457 /* Get current partition entry */
1458 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
1460 /* Ignore empty (aka unused) or extended partitions */
1461 if (PartitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
1462 IsContainerPartition (PartitionEntry
->PartitionType
))
1467 /* Check for matching partition start offset and length */
1468 if ((PartitionEntry
->StartingOffset
.QuadPart
!=
1469 DeviceExtension
->StartingOffset
.QuadPart
) ||
1470 (PartitionEntry
->PartitionLength
.QuadPart
!=
1471 DeviceExtension
->PartitionLength
.QuadPart
))
1474 DPRINT("Found matching partition entry for partition %lu\n",
1475 DiskData
->PartitionNumber
);
1477 /* Found matching partition */
1480 /* Update partition number in partition list */
1481 PartitionEntry
->PartitionNumber
= DiskData
->PartitionNumber
;
1487 /* Get disk data for current partition */
1488 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1490 /* Update partition type if partiton will be rewritten */
1491 if (PartitionEntry
->RewritePartition
== TRUE
)
1492 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
1494 /* Assign new partiton ordinal */
1495 DiskData
->PartitionOrdinal
= PartitionOrdinal
;
1497 DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1498 DiskData
->PartitionOrdinal
,
1499 DiskData
->PartitionNumber
);
1503 /* Delete this partition */
1504 DeviceExtension
->PartitionLength
.QuadPart
= 0ULL;
1506 DPRINT("Deleting partition %lu\n",
1507 DiskData
->PartitionNumber
);
1511 /* Traverse partiton list and create new partiton devices */
1512 PartitionOrdinal
= 0;
1513 for (i
= 0; i
< PartitionCount
; i
++)
1515 /* Get current partition entry */
1516 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
1518 /* Ignore empty (aka unused) or extended partitions */
1519 if (PartitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
1520 IsContainerPartition (PartitionEntry
->PartitionType
))
1525 /* Ignore unchanged partition entries */
1526 if (PartitionEntry
->RewritePartition
== FALSE
)
1529 /* Check for an unused device object */
1530 PartitionNumber
= 0;
1531 DeviceExtension
= DiskDeviceExtension
;
1532 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1535 DeviceExtension
= DiskData
->NextPartition
;
1536 if (DeviceExtension
== NULL
)
1539 /* Get partition disk data */
1540 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1542 /* Found a free (unused) partition (device object) */
1543 if (DeviceExtension
->PartitionLength
.QuadPart
== 0ULL)
1545 PartitionNumber
= DiskData
->PartitionNumber
;
1550 if (PartitionNumber
== 0)
1552 /* Create a new partition device object */
1553 DPRINT("Create new partition device object\n");
1555 /* Get new partiton number */
1556 LastPartitionNumber
++;
1557 PartitionNumber
= LastPartitionNumber
;
1559 /* Create partition device object */
1560 swprintf(NameBuffer
,
1561 L
"\\Device\\Harddisk%lu\\Partition%lu",
1562 DiskDeviceExtension
->DeviceNumber
,
1564 RtlInitUnicodeString(&DeviceName
,
1567 Status
= IoCreateDevice(DiskDeviceObject
->DriverObject
,
1568 sizeof(DEVICE_EXTENSION
) + sizeof(DISK_DATA
),
1574 if (!NT_SUCCESS(Status
))
1576 DPRINT("IoCreateDevice() failed (Status %lx)\n", Status
);
1580 DeviceObject
->Flags
|= DO_DIRECT_IO
;
1581 DeviceObject
->StackSize
= DiskDeviceObject
->StackSize
;
1582 DeviceObject
->Characteristics
= DiskDeviceObject
->Characteristics
;
1583 DeviceObject
->AlignmentRequirement
= DiskDeviceObject
->AlignmentRequirement
;
1585 /* Initialize device extension */
1586 DeviceExtension
= DeviceObject
->DeviceExtension
;
1587 RtlCopyMemory(DeviceExtension
,
1588 DiskDeviceObject
->DeviceExtension
,
1589 sizeof(DEVICE_EXTENSION
));
1590 DeviceExtension
->DeviceObject
= DeviceObject
;
1592 /* Initialize lookaside list for SRBs */
1593 ScsiClassInitializeSrbLookasideList(DeviceExtension
,
1596 /* Link current partition device extension to previous disk data */
1597 DiskData
->NextPartition
= DeviceExtension
;
1598 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1599 DiskData
->NextPartition
= NULL
;
1603 /* Reuse an existing partition device object */
1604 DPRINT("Reuse an exisiting partition device object\n");
1605 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1608 /* Update partition data and device extension */
1609 DiskData
->PartitionNumber
= PartitionNumber
;
1610 DiskData
->PartitionOrdinal
= PartitionOrdinal
;
1611 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
1612 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
1613 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
1614 DeviceExtension
->StartingOffset
= PartitionEntry
->StartingOffset
;
1615 DeviceExtension
->PartitionLength
= PartitionEntry
->PartitionLength
;
1617 /* Update partition number in the partition list */
1618 PartitionEntry
->PartitionNumber
= PartitionNumber
;
1620 DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1621 DiskData
->PartitionOrdinal
,
1622 DiskData
->PartitionNumber
);
1625 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() done\n");
1629 /**********************************************************************
1631 * ScsiDiskSearchForDisk
1634 * Searches the hardware tree for the given disk.
1641 * Disk device extension.
1644 * Handle to the hardware bus key.
1646 * DetectedDiskNumber
1647 * Returned disk number.
1650 * TRUE: Disk was found.
1651 * FALSE: Search failed.
1655 ScsiDiskSearchForDisk(IN PDEVICE_EXTENSION DeviceExtension
,
1657 OUT PULONG DetectedDiskNumber
)
1659 PKEY_VALUE_FULL_INFORMATION ValueData
;
1660 OBJECT_ATTRIBUTES ObjectAttributes
;
1661 PDISK_DATA DiskData
;
1662 UNICODE_STRING IdentifierString
;
1663 UNICODE_STRING NameString
;
1664 HANDLE BusInstanceKey
;
1665 HANDLE ControllerKey
;
1667 HANDLE DiskInstanceKey
;
1669 ULONG ControllerNumber
;
1676 DPRINT("ScsiDiskSearchForDiskData() called\n");
1680 /* Enumerate buses */
1681 for (BusNumber
= 0; ; BusNumber
++)
1683 /* Open bus instance subkey */
1688 RtlInitUnicodeString(&NameString
,
1691 InitializeObjectAttributes(&ObjectAttributes
,
1693 OBJ_CASE_INSENSITIVE
,
1697 Status
= ZwOpenKey(&BusInstanceKey
,
1700 if (!NT_SUCCESS(Status
))
1705 /* Open 'DiskController' subkey */
1706 RtlInitUnicodeString(&NameString
,
1709 InitializeObjectAttributes(&ObjectAttributes
,
1711 OBJ_CASE_INSENSITIVE
,
1715 Status
= ZwOpenKey(&ControllerKey
,
1718 if (!NT_SUCCESS(Status
))
1720 ZwClose(BusInstanceKey
);
1724 /* Enumerate controllers */
1725 for (ControllerNumber
= 0; ; ControllerNumber
++)
1727 /* Open 'DiskPeripheral' subkey */
1729 L
"%lu\\DiskPeripheral",
1732 RtlInitUnicodeString(&NameString
,
1735 InitializeObjectAttributes(&ObjectAttributes
,
1737 OBJ_CASE_INSENSITIVE
,
1741 Status
= ZwOpenKey(&DiskKey
,
1744 if (!NT_SUCCESS(Status
))
1749 /* Enumerate disks */
1750 for (DiskNumber
= 0; ; DiskNumber
++)
1752 /* Open disk instance subkey */
1757 RtlInitUnicodeString(&NameString
,
1760 InitializeObjectAttributes(&ObjectAttributes
,
1762 OBJ_CASE_INSENSITIVE
,
1766 Status
= ZwOpenKey(&DiskInstanceKey
,
1769 if (!NT_SUCCESS(Status
))
1774 DPRINT("Found disk key: bus %lu controller %lu disk %lu\n",
1779 /* Allocate data buffer */
1780 ValueData
= ExAllocatePool(PagedPool
,
1782 if (ValueData
== NULL
)
1784 ZwClose(DiskInstanceKey
);
1788 /* Get the 'Identifier' value */
1789 RtlInitUnicodeString(&NameString
,
1791 Status
= ZwQueryValueKey(DiskInstanceKey
,
1793 KeyValueFullInformation
,
1798 ZwClose(DiskInstanceKey
);
1799 if (!NT_SUCCESS(Status
))
1801 ExFreePool(ValueData
);
1805 IdentifierString
.Buffer
=
1806 (PWSTR
)((PUCHAR
)ValueData
+ ValueData
->DataOffset
);
1807 IdentifierString
.Length
= (USHORT
)ValueData
->DataLength
- 2;
1808 IdentifierString
.MaximumLength
= (USHORT
)ValueData
->DataLength
;
1810 DPRINT("DiskIdentifier: %wZ\n",
1813 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1814 if (DiskData
->Signature
!= 0)
1816 /* Comapre disk signature */
1819 DiskData
->Signature
);
1820 if (!_wcsnicmp(Buffer
, &IdentifierString
.Buffer
[9], 8))
1822 DPRINT("Found disk %lu\n", DiskNumber
);
1824 *DetectedDiskNumber
= DiskNumber
;
1829 /* Comapre mbr checksum */
1832 DiskData
->MbrCheckSum
);
1833 if (!_wcsnicmp(Buffer
, &IdentifierString
.Buffer
[0], 8))
1835 DPRINT("Found disk %lu\n", DiskNumber
);
1837 *DetectedDiskNumber
= DiskNumber
;
1841 ExFreePool(ValueData
);
1843 ZwClose(DiskInstanceKey
);
1845 if (DiskFound
== TRUE
)
1852 ZwClose(ControllerKey
);
1853 ZwClose(BusInstanceKey
);
1856 DPRINT("ScsiDiskSearchForDisk() done\n");
1862 /**********************************************************************
1864 * DiskClassUpdateFixedDiskGeometry
1867 * Updated the geometry of a disk if the disk can be accessed
1875 * Disk device extension.
1882 ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension
)
1884 PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
1885 PCM_INT13_DRIVE_PARAMETER DriveParameters
;
1886 PKEY_VALUE_FULL_INFORMATION ValueBuffer
;
1887 OBJECT_ATTRIBUTES ObjectAttributes
;
1888 UNICODE_STRING KeyName
;
1889 UNICODE_STRING ValueName
;
1892 ULONG DiskNumber
= 0;
1899 ULONG SectorsPerTrack
;
1900 ULONG TracksPerCylinder
;
1903 DPRINT("ScsiDiskUpdateFixedDiskGeometry() called\n");
1905 RtlInitUnicodeString(&KeyName
,
1906 L
"\\Registry\\Machine\\Hardware\\Description\\System");
1908 InitializeObjectAttributes(&ObjectAttributes
,
1910 OBJ_CASE_INSENSITIVE
,
1914 /* Open the adapter key */
1915 Status
= ZwOpenKey(&SystemKey
,
1918 if (!NT_SUCCESS(Status
))
1920 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status
);
1924 /* Allocate value buffer */
1925 ValueBuffer
= ExAllocatePool(PagedPool
,
1927 if (ValueBuffer
== NULL
)
1929 DPRINT("Failed to allocate value buffer\n");
1934 RtlInitUnicodeString(&ValueName
,
1935 L
"Configuration Data");
1937 /* Query 'Configuration Data' value */
1938 Status
= ZwQueryValueKey(SystemKey
,
1940 KeyValueFullInformation
,
1944 if (!NT_SUCCESS(Status
))
1946 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status
);
1947 ExFreePool(ValueBuffer
);
1952 /* Open the 'MultifunctionAdapter' subkey */
1953 RtlInitUnicodeString(&KeyName
,
1954 L
"MultifunctionAdapter");
1956 InitializeObjectAttributes(&ObjectAttributes
,
1958 OBJ_CASE_INSENSITIVE
,
1962 Status
= ZwOpenKey(&BusKey
,
1966 if (!NT_SUCCESS(Status
))
1968 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status
);
1969 ExFreePool(ValueBuffer
);
1973 if (!ScsiDiskSearchForDisk(DeviceExtension
, BusKey
, &DiskNumber
))
1975 DPRINT("ScsiDiskSearchForDisk() failed\n");
1977 ExFreePool(ValueBuffer
);
1983 ResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)
1984 ((PUCHAR
)ValueBuffer
+ ValueBuffer
->DataOffset
);
1986 DriveParameters
= (PCM_INT13_DRIVE_PARAMETER
)
1987 ((PUCHAR
)ResourceDescriptor
+ sizeof(CM_FULL_RESOURCE_DESCRIPTOR
));
1990 for (i
= 0; i
< DriveParameters
[0].NumberDrives
; i
++)
1992 DPRINT("Drive %lu: %lu Cylinders %hu Heads %hu Sectors\n",
1994 DriveParameters
[i
].MaxCylinders
,
1995 DriveParameters
[i
].MaxHeads
,
1996 DriveParameters
[i
].SectorsPerTrack
);
2000 Cylinders
= DriveParameters
[DiskNumber
].MaxCylinders
+ 1;
2001 TracksPerCylinder
= DriveParameters
[DiskNumber
].MaxHeads
+1;
2002 SectorsPerTrack
= DriveParameters
[DiskNumber
].SectorsPerTrack
;
2004 DPRINT("BIOS geometry: %lu Cylinders %hu Heads %hu Sectors\n",
2010 (DeviceExtension
->PartitionLength
.QuadPart
>> DeviceExtension
->SectorShift
);
2012 DPRINT("Physical sectors: %lu\n",
2015 Length
= TracksPerCylinder
* SectorsPerTrack
;
2018 DPRINT("Invalid track length 0\n");
2019 ExFreePool(ValueBuffer
);
2023 Cylinders
= Sectors
/ Length
;
2025 DPRINT("Logical geometry: %lu Cylinders %hu Heads %hu Sectors\n",
2030 /* Update the disk geometry */
2031 DeviceExtension
->DiskGeometry
->SectorsPerTrack
= SectorsPerTrack
;
2032 DeviceExtension
->DiskGeometry
->TracksPerCylinder
= TracksPerCylinder
;
2033 DeviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (ULONGLONG
)Cylinders
;
2035 if (DeviceExtension
->DMActive
)
2037 DPRINT("FIXME: Update geometry with respect to the installed disk manager!\n");
2039 /* FIXME: Update geometry for disk managers */
2043 ExFreePool(ValueBuffer
);
2045 DPRINT("ScsiDiskUpdateFixedDiskGeometry() done\n");
2049 /**********************************************************************
2051 * ScsiDiskCalcMbrCheckSum
2054 * Calculates the Checksum from drives MBR.
2061 * Disk device extension.
2064 * Pointer to the caller supplied cecksum variable.
2067 * TRUE: Checksum was calculated.
2068 * FALSE: Calculation failed.
2072 ScsiDiskCalcMbrCheckSum(IN PDEVICE_EXTENSION DeviceExtension
,
2073 OUT PULONG Checksum
)
2075 IO_STATUS_BLOCK IoStatusBlock
;
2076 LARGE_INTEGER SectorOffset
;
2085 KeInitializeEvent(&Event
,
2089 /* Get the disk sector size */
2090 SectorSize
= DeviceExtension
->DiskGeometry
->BytesPerSector
;
2091 if (SectorSize
< 512)
2096 /* Allocate MBR buffer */
2097 MbrBuffer
= ExAllocatePool(NonPagedPool
,
2099 if (MbrBuffer
== NULL
)
2104 /* Allocate an IRP */
2105 SectorOffset
.QuadPart
= 0ULL;
2106 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
2107 DeviceExtension
->DeviceObject
,
2115 ExFreePool(MbrBuffer
);
2119 /* Call the miniport driver */
2120 Status
= IoCallDriver(DeviceExtension
->DeviceObject
,
2122 if (Status
== STATUS_PENDING
)
2124 KeWaitForSingleObject(&Event
,
2129 Status
= IoStatusBlock
.Status
;
2132 if (!NT_SUCCESS(Status
))
2134 ExFreePool(MbrBuffer
);
2138 /* Calculate MBR checksum */
2140 for (i
= 0; i
< 128; i
++)
2142 Sum
+= MbrBuffer
[i
];
2144 *Checksum
= ~Sum
+ 1;
2146 ExFreePool(MbrBuffer
);