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 WCHAR NameBuffer
[MAX_PATH
];
321 swprintf (NameBuffer
,
322 L
"\\Device\\MediaChangeEvent%lu",
324 RtlInitUnicodeString (&Name
,
327 DeviceExtension
->MediaChangeEvent
=
328 IoCreateSynchronizationEvent (&Name
,
329 &DeviceExtension
->MediaChangeEventHandle
);
331 KeClearEvent (DeviceExtension
->MediaChangeEvent
);
336 /**********************************************************************
338 * DiskClassCheckDevice
341 * This function checks the InquiryData for the correct device
342 * type and qualifier.
349 * Pointer to the inquiry data for the device in question.
352 * TRUE: A disk device was found.
357 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData
)
359 return((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
||
360 InquiryData
->DeviceType
== OPTICAL_DEVICE
) &&
361 InquiryData
->DeviceTypeQualifier
== 0);
365 /**********************************************************************
367 * DiskClassCheckReadWrite
370 * This function checks the given IRP for correct data.
377 * Pointer to the device.
383 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
388 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
391 PDEVICE_EXTENSION DeviceExtension
;
394 DPRINT("DiskClassCheckReadWrite() called\n");
396 DeviceExtension
= DeviceObject
->DeviceExtension
;
397 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
399 if (DiskData
->DriveNotReady
== TRUE
)
401 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
402 IoSetHardErrorOrVerifyDevice(Irp
,
404 return(STATUS_INVALID_PARAMETER
);
407 return(STATUS_SUCCESS
);
411 /**********************************************************************
413 * DiskClassCreateDeviceObject
416 * Create the raw device and any partition devices on this drive
423 * The system created driver object
433 * STATUS_SUCCESS: Device objects for disk and partitions were created.
438 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
439 IN PUNICODE_STRING RegistryPath
,
440 IN PDEVICE_OBJECT PortDeviceObject
,
443 IN PIO_SCSI_CAPABILITIES Capabilities
,
444 IN PSCSI_INQUIRY_DATA InquiryData
,
445 IN PCLASS_INIT_DATA InitializationData
)
447 OBJECT_ATTRIBUTES ObjectAttributes
;
448 UNICODE_STRING UnicodeDeviceDirName
;
449 WCHAR NameBuffer
[80];
450 CHAR NameBuffer2
[80];
451 PDEVICE_OBJECT DiskDeviceObject
;
452 PDEVICE_OBJECT PartitionDeviceObject
;
453 PDEVICE_EXTENSION DiskDeviceExtension
; /* defined in class2.h */
454 PDEVICE_EXTENSION PartitionDeviceExtension
; /* defined in class2.h */
455 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
457 PPARTITION_INFORMATION PartitionEntry
;
459 ULONG PartitionNumber
;
463 DPRINT("DiskClassCreateDeviceObject() called\n");
465 /* Create the harddisk device directory */
467 L
"\\Device\\Harddisk%lu",
469 RtlInitUnicodeString(&UnicodeDeviceDirName
,
471 InitializeObjectAttributes(&ObjectAttributes
,
472 &UnicodeDeviceDirName
,
476 Status
= ZwCreateDirectoryObject(&Handle
,
479 if (!NT_SUCCESS(Status
))
481 DbgPrint("Could not create device dir object\n");
485 /* Claim the disk device */
486 Status
= ScsiClassClaimDevice(PortDeviceObject
,
490 if (!NT_SUCCESS(Status
))
492 DbgPrint("Could not claim disk device\n");
494 ZwMakeTemporaryObject(Handle
);
500 /* Create disk device (Partition 0) */
502 "\\Device\\Harddisk%lu\\Partition0",
505 Status
= ScsiClassCreateDeviceObject(DriverObject
,
510 if (!NT_SUCCESS(Status
))
512 DPRINT("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status
);
514 /* Release (unclaim) the disk */
515 ScsiClassClaimDevice(PortDeviceObject
,
520 /* Delete the harddisk device directory */
521 ZwMakeTemporaryObject(Handle
);
527 DiskDeviceObject
->Flags
|= DO_DIRECT_IO
;
528 if (((PINQUIRYDATA
)InquiryData
->InquiryData
)->RemovableMedia
)
530 DiskDeviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
532 DiskDeviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
534 if (PortDeviceObject
->AlignmentRequirement
> DiskDeviceObject
->AlignmentRequirement
)
536 DiskDeviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
539 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
540 DiskDeviceExtension
->LockCount
= 0;
541 DiskDeviceExtension
->DeviceNumber
= DiskNumber
;
542 DiskDeviceExtension
->DeviceObject
= DiskDeviceObject
;
543 DiskDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
544 DiskDeviceExtension
->PhysicalDevice
= DiskDeviceObject
;
545 DiskDeviceExtension
->PortCapabilities
= Capabilities
;
546 DiskDeviceExtension
->StartingOffset
.QuadPart
= 0;
547 DiskDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
548 DiskDeviceExtension
->PathId
= InquiryData
->PathId
;
549 DiskDeviceExtension
->TargetId
= InquiryData
->TargetId
;
550 DiskDeviceExtension
->Lun
= InquiryData
->Lun
;
551 DiskDeviceExtension
->SrbFlags
= 0;
553 /* Enable the command queueing, if it possible */
554 if (Capabilities
->TaggedQueuing
&&
555 ((PINQUIRYDATA
)InquiryData
->InquiryData
)->CommandQueue
)
557 DiskDeviceExtension
->SrbFlags
|= SRB_FLAGS_QUEUE_ACTION_ENABLE
;
560 /* Get timeout value */
561 DiskDeviceExtension
->TimeOutValue
=
562 ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
563 if (DiskDeviceExtension
->TimeOutValue
== 0)
564 DiskDeviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
566 /* Initialize the lookaside list for SRBs */
567 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension
,
570 /* zero-out disk data */
571 DiskData
= (PDISK_DATA
)(DiskDeviceExtension
+ 1);
572 RtlZeroMemory(DiskData
,
575 /* Get disk geometry */
576 DiskDeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
577 sizeof(DISK_GEOMETRY
));
578 if (DiskDeviceExtension
->DiskGeometry
== NULL
)
580 DPRINT("Failed to allocate geometry buffer!\n");
582 ExDeleteNPagedLookasideList(&DiskDeviceExtension
->SrbLookasideListHead
);
584 IoDeleteDevice(DiskDeviceObject
);
586 /* Release (unclaim) the disk */
587 ScsiClassClaimDevice(PortDeviceObject
,
592 /* Delete the harddisk device directory */
593 ZwMakeTemporaryObject(Handle
);
596 return(STATUS_INSUFFICIENT_RESOURCES
);
599 /* Allocate sense data buffer */
600 DiskDeviceExtension
->SenseData
= ExAllocatePool(NonPagedPoolCacheAligned
,
602 if (DiskDeviceExtension
->SenseData
== NULL
)
604 DPRINT("Failed to allocate sense data buffer!\n");
606 ExFreePool (DiskDeviceExtension
->DiskGeometry
);
608 ExDeleteNPagedLookasideList(&DiskDeviceExtension
->SrbLookasideListHead
);
610 IoDeleteDevice(DiskDeviceObject
);
612 /* Release (unclaim) the disk */
613 ScsiClassClaimDevice(PortDeviceObject
,
618 /* Delete the harddisk device directory */
619 ZwMakeTemporaryObject(Handle
);
622 return(STATUS_INSUFFICIENT_RESOURCES
);
625 /* Read the drive's capacity */
626 Status
= ScsiClassReadDriveCapacity(DiskDeviceObject
);
627 if (!NT_SUCCESS(Status
) &&
628 (DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) == 0)
630 DPRINT("Failed to retrieve drive capacity!\n");
631 return(STATUS_SUCCESS
);
635 /* Clear the verify flag for removable media drives. */
636 DiskDeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
639 DPRINT("SectorSize: %lu\n", DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
641 if ((DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
642 (DiskDeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
644 DiskClassCreateMediaChangeEvent(DiskDeviceExtension
,DiskNumber
);
645 if (DiskDeviceExtension
->MediaChangeEvent
!= NULL
)
647 DPRINT("Allocated media change event!\n");
651 /* Check disk for presence of a disk manager */
652 HalExamineMBR(DiskDeviceObject
,
653 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
656 if (MbrBuffer
!= NULL
)
658 /* Start disk at sector 63 if the Ontrack Disk Manager was found */
659 DPRINT("Found 'Ontrack Disk Manager'!\n");
661 DiskDeviceExtension
->DMSkew
= 63;
662 DiskDeviceExtension
->DMByteSkew
=
663 63 * DiskDeviceExtension
->DiskGeometry
->BytesPerSector
;
664 DiskDeviceExtension
->DMActive
= TRUE
;
666 ExFreePool(MbrBuffer
);
670 if ((DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
671 (DiskDeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
673 /* Allocate a partition list for a single entry. */
674 PartitionList
= ExAllocatePool(NonPagedPool
,
675 sizeof(DRIVE_LAYOUT_INFORMATION
));
676 if (PartitionList
!= NULL
)
678 RtlZeroMemory(PartitionList
,
679 sizeof(DRIVE_LAYOUT_INFORMATION
));
680 PartitionList
->PartitionCount
= 1;
682 DiskData
->DriveNotReady
= TRUE
;
683 Status
= STATUS_SUCCESS
;
688 /* Read partition table */
689 Status
= IoReadPartitionTable(DiskDeviceObject
,
690 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
694 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status
);
696 if ((!NT_SUCCESS(Status
) || PartitionList
->PartitionCount
== 0) &&
697 DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
699 if (!NT_SUCCESS(Status
))
701 /* Drive is not ready. */
702 DPRINT("Drive not ready\n");
703 DiskData
->DriveNotReady
= TRUE
;
707 ExFreePool(PartitionList
);
710 /* Allocate a partition list for a single entry. */
711 PartitionList
= ExAllocatePool(NonPagedPool
,
712 sizeof(DRIVE_LAYOUT_INFORMATION
));
713 if (PartitionList
!= NULL
)
715 RtlZeroMemory(PartitionList
,
716 sizeof(DRIVE_LAYOUT_INFORMATION
));
717 PartitionList
->PartitionCount
= 1;
719 Status
= STATUS_SUCCESS
;
724 if (NT_SUCCESS(Status
))
726 DPRINT("Read partition table!\n");
727 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
729 /* Set disk signature */
730 DiskData
->Signature
= PartitionList
->Signature
;
732 /* Calculate MBR checksum if disk got no signature */
733 if (DiskData
->Signature
== 0)
735 if (!ScsiDiskCalcMbrCheckSum(DiskDeviceExtension
,
736 &DiskData
->MbrCheckSum
))
738 DPRINT("MBR checksum calculation failed for disk %lu\n",
739 DiskDeviceExtension
->DeviceNumber
);
743 DPRINT("MBR checksum for disk %lu is %lx\n",
744 DiskDeviceExtension
->DeviceNumber
,
745 DiskData
->MbrCheckSum
);
750 DPRINT("Signature on disk %lu is %lx\n",
751 DiskDeviceExtension
->DeviceNumber
,
752 DiskData
->Signature
);
755 /* Update disk geometry if disk is visible to the BIOS */
756 ScsiDiskUpdateFixedDiskGeometry(DiskDeviceExtension
);
758 for (PartitionNumber
= 0; PartitionNumber
< PartitionList
->PartitionCount
; PartitionNumber
++)
760 PartitionEntry
= &PartitionList
->PartitionEntry
[PartitionNumber
];
762 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
764 PartitionEntry
->PartitionNumber
,
765 PartitionEntry
->BootIndicator
,
766 PartitionEntry
->PartitionType
,
767 PartitionEntry
->StartingOffset
.QuadPart
/
768 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
769 PartitionEntry
->PartitionLength
.QuadPart
/
770 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
772 /* Create partition device object */
774 "\\Device\\Harddisk%lu\\Partition%lu",
776 PartitionNumber
+ 1);
778 Status
= ScsiClassCreateDeviceObject(DriverObject
,
781 &PartitionDeviceObject
,
783 DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status
);
784 if (NT_SUCCESS(Status
))
786 PartitionDeviceObject
->Flags
= DiskDeviceObject
->Flags
;
787 PartitionDeviceObject
->Characteristics
= DiskDeviceObject
->Characteristics
;
788 PartitionDeviceObject
->StackSize
= DiskDeviceObject
->StackSize
;
789 PartitionDeviceObject
->AlignmentRequirement
= DiskDeviceObject
->AlignmentRequirement
;
791 PartitionDeviceExtension
= PartitionDeviceObject
->DeviceExtension
;
792 PartitionDeviceExtension
->SenseData
= DiskDeviceExtension
->SenseData
;
793 PartitionDeviceExtension
->LockCount
= 0;
794 PartitionDeviceExtension
->DeviceNumber
= DiskNumber
;
795 PartitionDeviceExtension
->DeviceObject
= PartitionDeviceObject
;
796 PartitionDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
797 PartitionDeviceExtension
->DiskGeometry
= DiskDeviceExtension
->DiskGeometry
;
798 PartitionDeviceExtension
->PhysicalDevice
= DiskDeviceExtension
->PhysicalDevice
;
799 PartitionDeviceExtension
->PortCapabilities
= Capabilities
;
800 PartitionDeviceExtension
->StartingOffset
.QuadPart
=
801 PartitionEntry
->StartingOffset
.QuadPart
;
802 PartitionDeviceExtension
->PartitionLength
.QuadPart
=
803 PartitionEntry
->PartitionLength
.QuadPart
;
804 PartitionDeviceExtension
->DMSkew
= DiskDeviceExtension
->DMSkew
;
805 PartitionDeviceExtension
->DMByteSkew
= DiskDeviceExtension
->DMByteSkew
;
806 PartitionDeviceExtension
->DMActive
= DiskDeviceExtension
->DMActive
;
807 PartitionDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
808 PartitionDeviceExtension
->PathId
= InquiryData
->PathId
;
809 PartitionDeviceExtension
->TargetId
= InquiryData
->TargetId
;
810 PartitionDeviceExtension
->Lun
= InquiryData
->Lun
;
811 PartitionDeviceExtension
->SectorShift
= DiskDeviceExtension
->SectorShift
;
812 PartitionDeviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
814 /* Initialize lookaside list for SRBs */
815 ScsiClassInitializeSrbLookasideList(PartitionDeviceExtension
,
818 /* Link current partition device extension to previous disk data */
819 DiskData
->NextPartition
= PartitionDeviceExtension
;
821 /* Initialize current disk data */
822 DiskData
= (PDISK_DATA
)(PartitionDeviceExtension
+ 1);
823 DiskData
->NextPartition
= NULL
;
824 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
825 DiskData
->PartitionNumber
= PartitionNumber
+ 1;
826 DiskData
->PartitionOrdinal
= PartitionNumber
+ 1;
827 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
828 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
829 DiskData
->DriveNotReady
= FALSE
;
833 DPRINT("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status
);
840 if (PartitionList
!= NULL
)
841 ExFreePool(PartitionList
);
843 DPRINT("DiskClassCreateDeviceObjects() done\n");
845 return(STATUS_SUCCESS
);
850 DiskBuildPartitionTable(IN PDEVICE_OBJECT DiskDeviceObject
,
853 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
854 PDEVICE_EXTENSION DiskDeviceExtension
, DDE
;
855 PDISK_DATA DiskData
, DD
;
856 PPARTITION_INFORMATION PartitionEntry
;
857 ULONG PartitionNumber
;
860 DPRINT("DiskBuildPartitionTable() start\n");
862 DiskDeviceExtension
= (PDEVICE_EXTENSION
)DiskDeviceObject
->DeviceExtension
;
863 DiskData
= (PDISK_DATA
)(DiskDeviceExtension
+ 1);
865 DDE
= (PDEVICE_EXTENSION
) DiskDeviceExtension
->PhysicalDevice
->DeviceExtension
;
866 DD
= (PDISK_DATA
)(DDE
+1);
868 /* Clear flag for Partition0, just incase it was set. */
869 DD
->DriveNotReady
= FALSE
;
871 Status
= ScsiClassReadDriveCapacity(DiskDeviceObject
);
872 if (!NT_SUCCESS(Status
))
874 /* Drive is not ready. */
875 DPRINT("Drive not ready\n");
876 DiskData
->DriveNotReady
= TRUE
;
880 /* Read partition table */
881 Status
= IoReadPartitionTable(DiskDeviceExtension
->PhysicalDevice
,
882 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
886 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status
);
888 if (!NT_SUCCESS(Status
))
890 /* Drive is not ready. */
891 DPRINT("Drive not ready\n");
892 DiskData
->DriveNotReady
= TRUE
;
893 if (PartitionList
!= NULL
)
894 ExFreePool(PartitionList
);
898 if (NT_SUCCESS(Status
))
900 DPRINT("Read partition table!\n");
901 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
903 /* Set disk signature */
904 DiskData
->Signature
= PartitionList
->Signature
;
906 DiskData
->NextPartition
= NULL
;
908 if (PartitionList
->PartitionCount
)
910 for (PartitionNumber
= 0; PartitionNumber
< PartitionList
->PartitionCount
; PartitionNumber
++)
912 PartitionEntry
= &PartitionList
->PartitionEntry
[PartitionNumber
];
914 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
915 DiskData
->PartitionNumber
= PartitionNumber
+ 1;
916 DiskData
->PartitionOrdinal
= PartitionNumber
+ 1;
917 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
918 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
919 DiskData
->DriveNotReady
= FALSE
;
920 DiskDeviceExtension
->StartingOffset
= PartitionEntry
->StartingOffset
;
921 DiskDeviceExtension
->PartitionLength
= PartitionEntry
->PartitionLength
;
923 DPRINT1("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
925 DiskData
->PartitionNumber
,
926 DiskData
->BootIndicator
,
927 DiskData
->PartitionType
,
928 DiskDeviceExtension
->StartingOffset
.QuadPart
/
929 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
930 DiskDeviceExtension
->PartitionLength
.QuadPart
/
931 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
936 DiskData
->PartitionType
= 0;
937 DiskData
->PartitionNumber
= 1;
938 DiskData
->PartitionOrdinal
= 0;
939 DiskData
->HiddenSectors
= 0;
940 DiskData
->BootIndicator
= 0;
941 DiskData
->DriveNotReady
= FALSE
;
942 DiskDeviceExtension
->StartingOffset
.QuadPart
= 0;
943 DiskDeviceExtension
->PartitionLength
.QuadPart
+= DiskDeviceExtension
->StartingOffset
.QuadPart
;
947 DPRINT("DiskBuildPartitionTable() done\n");
948 if (PartitionList
!= NULL
)
949 ExFreePool(PartitionList
);
950 return(STATUS_SUCCESS
);
954 /**********************************************************************
956 * DiskClassDeviceControl
959 * Answer requests for device control calls
965 * Standard dispatch arguments
972 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
975 PDEVICE_EXTENSION DeviceExtension
;
976 PIO_STACK_LOCATION IrpStack
;
977 ULONG ControlCode
, InputLength
, OutputLength
;
982 DPRINT("DiskClassDeviceControl() called!\n");
984 Status
= STATUS_INVALID_DEVICE_REQUEST
;
986 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
987 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
988 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
989 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
990 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
991 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
995 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
996 DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
997 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
999 Status
= STATUS_INVALID_PARAMETER
;
1003 if (DeviceExtension
->DiskGeometry
== NULL
)
1005 DPRINT("No disk geometry available!\n");
1006 DeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
1007 sizeof(DISK_GEOMETRY
));
1010 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
1012 Status
= ScsiClassReadDriveCapacity(DeviceObject
);
1013 DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status
);
1014 if (!NT_SUCCESS(Status
))
1016 /* Drive is not ready */
1017 DiskData
->DriveNotReady
= TRUE
;
1021 /* Drive is ready */
1022 DiskData
->DriveNotReady
= FALSE
;
1025 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1026 DeviceExtension
->DiskGeometry
,
1027 sizeof(DISK_GEOMETRY
));
1029 Status
= STATUS_SUCCESS
;
1030 Information
= sizeof(DISK_GEOMETRY
);
1033 case IOCTL_DISK_GET_PARTITION_INFO
:
1034 DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
1036 if ((DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
1037 (DeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
1039 /* Update a partition list for a single entry. */
1040 Status
= DiskBuildPartitionTable(DeviceObject
,Irp
);
1043 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1044 sizeof(PARTITION_INFORMATION
))
1046 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1048 else if (DiskData
->PartitionNumber
== 0)
1050 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1054 PPARTITION_INFORMATION PartitionInfo
;
1056 PartitionInfo
= (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
1058 PartitionInfo
->PartitionType
= DiskData
->PartitionType
;
1059 PartitionInfo
->StartingOffset
= DeviceExtension
->StartingOffset
;
1060 PartitionInfo
->PartitionLength
= DeviceExtension
->PartitionLength
;
1061 PartitionInfo
->HiddenSectors
= DiskData
->HiddenSectors
;
1062 PartitionInfo
->PartitionNumber
= DiskData
->PartitionNumber
;
1063 PartitionInfo
->BootIndicator
= DiskData
->BootIndicator
;
1064 PartitionInfo
->RewritePartition
= FALSE
;
1065 PartitionInfo
->RecognizedPartition
=
1066 IsRecognizedPartition(DiskData
->PartitionType
);
1068 Status
= STATUS_SUCCESS
;
1069 Information
= sizeof(PARTITION_INFORMATION
);
1073 case IOCTL_DISK_SET_PARTITION_INFO
:
1074 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1075 sizeof(SET_PARTITION_INFORMATION
))
1077 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1079 else if (DiskData
->PartitionNumber
== 0)
1081 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1085 PSET_PARTITION_INFORMATION PartitionInfo
;
1087 PartitionInfo
= (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
1089 Status
= IoSetPartitionInformation(DeviceExtension
->PhysicalDevice
,
1090 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1091 DiskData
->PartitionOrdinal
,
1092 PartitionInfo
->PartitionType
);
1093 if (NT_SUCCESS(Status
))
1095 DiskData
->PartitionType
= PartitionInfo
->PartitionType
;
1100 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1101 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1102 sizeof(DRIVE_LAYOUT_INFORMATION
))
1104 Status
= STATUS_BUFFER_TOO_SMALL
;
1108 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1110 Status
= IoReadPartitionTable(DeviceExtension
->PhysicalDevice
,
1111 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1114 if (NT_SUCCESS(Status
))
1118 BufferSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
1120 BufferSize
+= PartitionList
->PartitionCount
* sizeof(PARTITION_INFORMATION
);
1122 if (BufferSize
> IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
1124 Status
= STATUS_BUFFER_TOO_SMALL
;
1128 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1131 Status
= STATUS_SUCCESS
;
1132 Information
= BufferSize
;
1134 ExFreePool(PartitionList
);
1139 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
1140 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1141 sizeof(DRIVE_LAYOUT_INFORMATION
))
1143 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1145 else if (DeviceExtension
->PhysicalDevice
->DeviceExtension
!= DeviceExtension
)
1147 Status
= STATUS_INVALID_PARAMETER
;
1151 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1154 PartitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
1155 TableSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
1156 ((PartitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
));
1158 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< TableSize
)
1160 Status
= STATUS_BUFFER_TOO_SMALL
;
1164 /* Update partition device objects */
1165 DiskClassUpdatePartitionDeviceObjects (DeviceObject
,
1168 /* Write partition table */
1169 Status
= IoWritePartitionTable(DeviceExtension
->PhysicalDevice
,
1170 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1171 DeviceExtension
->DiskGeometry
->SectorsPerTrack
,
1172 DeviceExtension
->DiskGeometry
->TracksPerCylinder
,
1178 case IOCTL_DISK_IS_WRITABLE
:
1180 PMODE_PARAMETER_HEADER ModeData
;
1183 ModeData
= ExAllocatePool (NonPagedPool
,
1185 if (ModeData
== NULL
)
1187 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1190 RtlZeroMemory (ModeData
,
1193 Length
= ScsiClassModeSense (DeviceObject
,
1196 MODE_SENSE_RETURN_ALL
);
1197 if (Length
< sizeof(MODE_PARAMETER_HEADER
))
1200 Status
= STATUS_IO_DEVICE_ERROR
;
1201 ExFreePool (ModeData
);
1205 if (ModeData
->DeviceSpecificParameter
& MODE_DSP_WRITE_PROTECT
)
1207 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1211 Status
= STATUS_SUCCESS
;
1213 ExFreePool (ModeData
);
1217 case IOCTL_DISK_VERIFY
:
1218 case IOCTL_DISK_FORMAT_TRACKS
:
1219 case IOCTL_DISK_PERFORMANCE
:
1220 case IOCTL_DISK_LOGGING
:
1221 case IOCTL_DISK_FORMAT_TRACKS_EX
:
1222 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
1223 case IOCTL_DISK_HISTOGRAM_DATA
:
1224 case IOCTL_DISK_HISTOGRAM_RESET
:
1225 case IOCTL_DISK_REQUEST_STRUCTURE
:
1226 case IOCTL_DISK_REQUEST_DATA
:
1227 /* If we get here, something went wrong. Inform the requestor */
1228 DPRINT("Unhandled control code: %lx\n", ControlCode
);
1229 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1234 /* Call the common device control function */
1235 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
1238 /* Verify the device if the user caused the error */
1239 if (!NT_SUCCESS(Status
) && IoIsErrorUserInduced(Status
))
1241 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1244 Irp
->IoStatus
.Status
= Status
;
1245 Irp
->IoStatus
.Information
= Information
;
1246 IoCompleteRequest(Irp
,
1253 /**********************************************************************
1255 * DiskClassShutdownFlush
1258 * Answer requests for shutdown and flush calls.
1265 * Pointer to the device.
1268 * Pointer to the IRP
1275 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
1278 PDEVICE_EXTENSION DeviceExtension
;
1279 PIO_STACK_LOCATION IrpStack
;
1280 PSCSI_REQUEST_BLOCK Srb
;
1282 DPRINT("DiskClassShutdownFlush() called!\n");
1284 DeviceExtension
= DeviceObject
->DeviceExtension
;
1287 Srb
= ExAllocatePool(NonPagedPool
,
1288 sizeof(SCSI_REQUEST_BLOCK
));
1291 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1292 Irp
->IoStatus
.Information
= 0;
1293 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1295 return(STATUS_INSUFFICIENT_RESOURCES
);
1298 /* Initialize SRB */
1299 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
1300 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
1302 /* Set device IDs */
1303 Srb
->PathId
= DeviceExtension
->PathId
;
1304 Srb
->TargetId
= DeviceExtension
->TargetId
;
1305 Srb
->Lun
= DeviceExtension
->Lun
;
1308 Srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
* 4;
1310 /* Flush write cache */
1311 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1312 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1313 Srb
->CdbLength
= 10;
1314 Srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
1315 ScsiClassSendSrbSynchronous(DeviceObject
,
1321 /* Get current stack location */
1322 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1324 /* FIXME: Unlock removable media upon shutdown */
1328 IrpStack
->Parameters
.Others
.Argument4
= (PVOID
)0;
1330 /* Send shutdown or flush request to the port driver */
1332 if (IrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
)
1333 Srb
->Function
= SRB_FUNCTION_SHUTDOWN
;
1335 Srb
->Function
= SRB_FUNCTION_FLUSH
;
1337 /* Init completion routine */
1338 IoSetCompletionRoutine(Irp
,
1339 ScsiClassIoComplete
,
1345 /* Prepare next stack location for a call to the port driver */
1346 IrpStack
= IoGetNextIrpStackLocation(Irp
);
1347 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1348 IrpStack
->Parameters
.Scsi
.Srb
= Srb
;
1349 Srb
->OriginalRequest
= Irp
;
1351 /* Call port driver */
1352 return(IoCallDriver(DeviceExtension
->PortDeviceObject
, Irp
));
1356 /**********************************************************************
1358 * DiskClassUpdatePartitionDeviceObjects
1361 * Deletes, modifies or creates partition device objects.
1368 * Pointer to the device.
1371 * Pointer to the IRP
1378 DiskClassUpdatePartitionDeviceObjects(IN PDEVICE_OBJECT DiskDeviceObject
,
1381 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1382 PPARTITION_INFORMATION PartitionEntry
;
1383 PDEVICE_EXTENSION DeviceExtension
;
1384 PDEVICE_EXTENSION DiskDeviceExtension
;
1385 PDISK_DATA DiskData
;
1386 ULONG PartitionCount
;
1387 ULONG PartitionOrdinal
;
1388 ULONG PartitionNumber
;
1389 ULONG LastPartitionNumber
;
1392 WCHAR NameBuffer
[MAX_PATH
];
1393 UNICODE_STRING DeviceName
;
1394 PDEVICE_OBJECT DeviceObject
;
1397 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() called\n");
1399 /* Get partition list */
1400 PartitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
1402 /* Round partition count up by 4 */
1403 PartitionCount
= ((PartitionList
->PartitionCount
+ 3) / 4) * 4;
1405 /* Remove the partition numbers from the partition list */
1406 for (i
= 0; i
< PartitionCount
; i
++)
1408 PartitionList
->PartitionEntry
[i
].PartitionNumber
= 0;
1411 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
1413 /* Traverse on-disk partition list */
1414 LastPartitionNumber
= 0;
1415 DeviceExtension
= DiskDeviceExtension
;
1416 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1419 DeviceExtension
= DiskData
->NextPartition
;
1420 if (DeviceExtension
== NULL
)
1424 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1426 /* Update last partition number */
1427 if (DiskData
->PartitionNumber
> LastPartitionNumber
)
1428 LastPartitionNumber
= DiskData
->PartitionNumber
;
1430 /* Ignore unused on-disk partitions */
1431 if (DeviceExtension
->PartitionLength
.QuadPart
== 0ULL)
1435 PartitionOrdinal
= 0;
1436 for (i
= 0; i
< PartitionCount
; i
++)
1438 /* Get current partition entry */
1439 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
1441 /* Ignore empty (aka unused) or extended partitions */
1442 if (PartitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
1443 IsContainerPartition (PartitionEntry
->PartitionType
))
1448 /* Check for matching partition start offset and length */
1449 if ((PartitionEntry
->StartingOffset
.QuadPart
!=
1450 DeviceExtension
->StartingOffset
.QuadPart
) ||
1451 (PartitionEntry
->PartitionLength
.QuadPart
!=
1452 DeviceExtension
->PartitionLength
.QuadPart
))
1455 DPRINT("Found matching partition entry for partition %lu\n",
1456 DiskData
->PartitionNumber
);
1458 /* Found matching partition */
1461 /* Update partition number in partition list */
1462 PartitionEntry
->PartitionNumber
= DiskData
->PartitionNumber
;
1468 /* Get disk data for current partition */
1469 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1471 /* Update partition type if partiton will be rewritten */
1472 if (PartitionEntry
->RewritePartition
== TRUE
)
1473 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
1475 /* Assign new partiton ordinal */
1476 DiskData
->PartitionOrdinal
= PartitionOrdinal
;
1478 DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1479 DiskData
->PartitionOrdinal
,
1480 DiskData
->PartitionNumber
);
1484 /* Delete this partition */
1485 DeviceExtension
->PartitionLength
.QuadPart
= 0ULL;
1487 DPRINT("Deleting partition %lu\n",
1488 DiskData
->PartitionNumber
);
1492 /* Traverse partiton list and create new partiton devices */
1493 PartitionOrdinal
= 0;
1494 for (i
= 0; i
< PartitionCount
; i
++)
1496 /* Get current partition entry */
1497 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
1499 /* Ignore empty (aka unused) or extended partitions */
1500 if (PartitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
1501 IsContainerPartition (PartitionEntry
->PartitionType
))
1506 /* Ignore unchanged partition entries */
1507 if (PartitionEntry
->RewritePartition
== FALSE
)
1510 /* Check for an unused device object */
1511 PartitionNumber
= 0;
1512 DeviceExtension
= DiskDeviceExtension
;
1513 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1516 DeviceExtension
= DiskData
->NextPartition
;
1517 if (DeviceExtension
== NULL
)
1520 /* Get partition disk data */
1521 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1523 /* Found a free (unused) partition (device object) */
1524 if (DeviceExtension
->PartitionLength
.QuadPart
== 0ULL)
1526 PartitionNumber
= DiskData
->PartitionNumber
;
1531 if (PartitionNumber
== 0)
1533 /* Create a new partition device object */
1534 DPRINT("Create new partition device object\n");
1536 /* Get new partiton number */
1537 LastPartitionNumber
++;
1538 PartitionNumber
= LastPartitionNumber
;
1540 /* Create partition device object */
1541 swprintf(NameBuffer
,
1542 L
"\\Device\\Harddisk%lu\\Partition%lu",
1543 DiskDeviceExtension
->DeviceNumber
,
1545 RtlInitUnicodeString(&DeviceName
,
1548 Status
= IoCreateDevice(DiskDeviceObject
->DriverObject
,
1549 sizeof(DEVICE_EXTENSION
) + sizeof(DISK_DATA
),
1555 if (!NT_SUCCESS(Status
))
1557 DPRINT("IoCreateDevice() failed (Status %lx)\n", Status
);
1561 DeviceObject
->Flags
|= DO_DIRECT_IO
;
1562 DeviceObject
->StackSize
= DiskDeviceObject
->StackSize
;
1563 DeviceObject
->Characteristics
= DiskDeviceObject
->Characteristics
;
1564 DeviceObject
->AlignmentRequirement
= DiskDeviceObject
->AlignmentRequirement
;
1566 /* Initialize device extension */
1567 DeviceExtension
= DeviceObject
->DeviceExtension
;
1568 RtlCopyMemory(DeviceExtension
,
1569 DiskDeviceObject
->DeviceExtension
,
1570 sizeof(DEVICE_EXTENSION
));
1571 DeviceExtension
->DeviceObject
= DeviceObject
;
1573 /* Initialize lookaside list for SRBs */
1574 ScsiClassInitializeSrbLookasideList(DeviceExtension
,
1577 /* Link current partition device extension to previous disk data */
1578 DiskData
->NextPartition
= DeviceExtension
;
1579 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1580 DiskData
->NextPartition
= NULL
;
1584 /* Reuse an existing partition device object */
1585 DPRINT("Reuse an exisiting partition device object\n");
1586 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1589 /* Update partition data and device extension */
1590 DiskData
->PartitionNumber
= PartitionNumber
;
1591 DiskData
->PartitionOrdinal
= PartitionOrdinal
;
1592 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
1593 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
1594 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
1595 DeviceExtension
->StartingOffset
= PartitionEntry
->StartingOffset
;
1596 DeviceExtension
->PartitionLength
= PartitionEntry
->PartitionLength
;
1598 /* Update partition number in the partition list */
1599 PartitionEntry
->PartitionNumber
= PartitionNumber
;
1601 DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1602 DiskData
->PartitionOrdinal
,
1603 DiskData
->PartitionNumber
);
1606 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() done\n");
1610 /**********************************************************************
1612 * ScsiDiskSearchForDisk
1615 * Searches the hardware tree for the given disk.
1622 * Disk device extension.
1625 * Handle to the hardware bus key.
1627 * DetectedDiskNumber
1628 * Returned disk number.
1631 * TRUE: Disk was found.
1632 * FALSE: Search failed.
1636 ScsiDiskSearchForDisk(IN PDEVICE_EXTENSION DeviceExtension
,
1638 OUT PULONG DetectedDiskNumber
)
1640 PKEY_VALUE_FULL_INFORMATION ValueData
;
1641 OBJECT_ATTRIBUTES ObjectAttributes
;
1642 PDISK_DATA DiskData
;
1643 UNICODE_STRING IdentifierString
;
1644 UNICODE_STRING NameString
;
1645 HANDLE BusInstanceKey
;
1646 HANDLE ControllerKey
;
1648 HANDLE DiskInstanceKey
;
1650 ULONG ControllerNumber
;
1657 DPRINT("ScsiDiskSearchForDiskData() called\n");
1661 /* Enumerate buses */
1662 for (BusNumber
= 0; ; BusNumber
++)
1664 /* Open bus instance subkey */
1669 RtlInitUnicodeString(&NameString
,
1672 InitializeObjectAttributes(&ObjectAttributes
,
1674 OBJ_CASE_INSENSITIVE
,
1678 Status
= ZwOpenKey(&BusInstanceKey
,
1681 if (!NT_SUCCESS(Status
))
1686 /* Open 'DiskController' subkey */
1687 RtlInitUnicodeString(&NameString
,
1690 InitializeObjectAttributes(&ObjectAttributes
,
1692 OBJ_CASE_INSENSITIVE
,
1696 Status
= ZwOpenKey(&ControllerKey
,
1699 if (!NT_SUCCESS(Status
))
1701 ZwClose(BusInstanceKey
);
1705 /* Enumerate controllers */
1706 for (ControllerNumber
= 0; ; ControllerNumber
++)
1708 /* Open 'DiskPeripheral' subkey */
1710 L
"%lu\\DiskPeripheral",
1713 RtlInitUnicodeString(&NameString
,
1716 InitializeObjectAttributes(&ObjectAttributes
,
1718 OBJ_CASE_INSENSITIVE
,
1722 Status
= ZwOpenKey(&DiskKey
,
1725 if (!NT_SUCCESS(Status
))
1730 /* Enumerate disks */
1731 for (DiskNumber
= 0; ; DiskNumber
++)
1733 /* Open disk instance subkey */
1738 RtlInitUnicodeString(&NameString
,
1741 InitializeObjectAttributes(&ObjectAttributes
,
1743 OBJ_CASE_INSENSITIVE
,
1747 Status
= ZwOpenKey(&DiskInstanceKey
,
1750 if (!NT_SUCCESS(Status
))
1755 DPRINT("Found disk key: bus %lu controller %lu disk %lu\n",
1760 /* Allocate data buffer */
1761 ValueData
= ExAllocatePool(PagedPool
,
1763 if (ValueData
== NULL
)
1765 ZwClose(DiskInstanceKey
);
1769 /* Get the 'Identifier' value */
1770 RtlInitUnicodeString(&NameString
,
1772 Status
= ZwQueryValueKey(DiskInstanceKey
,
1774 KeyValueFullInformation
,
1779 ZwClose(DiskInstanceKey
);
1780 if (!NT_SUCCESS(Status
))
1782 ExFreePool(ValueData
);
1786 IdentifierString
.Buffer
=
1787 (PWSTR
)((PUCHAR
)ValueData
+ ValueData
->DataOffset
);
1788 IdentifierString
.Length
= (USHORT
)ValueData
->DataLength
- 2;
1789 IdentifierString
.MaximumLength
= (USHORT
)ValueData
->DataLength
;
1791 DPRINT("DiskIdentifier: %wZ\n",
1794 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1795 if (DiskData
->Signature
!= 0)
1797 /* Comapre disk signature */
1800 DiskData
->Signature
);
1801 if (!_wcsnicmp(Buffer
, &IdentifierString
.Buffer
[9], 8))
1803 DPRINT("Found disk %lu\n", DiskNumber
);
1805 *DetectedDiskNumber
= DiskNumber
;
1810 /* Comapre mbr checksum */
1813 DiskData
->MbrCheckSum
);
1814 if (!_wcsnicmp(Buffer
, &IdentifierString
.Buffer
[0], 8))
1816 DPRINT("Found disk %lu\n", DiskNumber
);
1818 *DetectedDiskNumber
= DiskNumber
;
1822 ExFreePool(ValueData
);
1824 ZwClose(DiskInstanceKey
);
1826 if (DiskFound
== TRUE
)
1833 ZwClose(ControllerKey
);
1834 ZwClose(BusInstanceKey
);
1837 DPRINT("ScsiDiskSearchForDisk() done\n");
1843 /**********************************************************************
1845 * DiskClassUpdateFixedDiskGeometry
1848 * Updated the geometry of a disk if the disk can be accessed
1856 * Disk device extension.
1863 ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension
)
1865 PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
1866 PCM_INT13_DRIVE_PARAMETER DriveParameters
;
1867 PKEY_VALUE_FULL_INFORMATION ValueBuffer
;
1868 OBJECT_ATTRIBUTES ObjectAttributes
;
1869 UNICODE_STRING KeyName
;
1870 UNICODE_STRING ValueName
;
1880 ULONG SectorsPerTrack
;
1881 ULONG TracksPerCylinder
;
1884 DPRINT("ScsiDiskUpdateFixedDiskGeometry() called\n");
1886 RtlInitUnicodeString(&KeyName
,
1887 L
"\\Registry\\Machine\\Hardware\\Description\\System");
1889 InitializeObjectAttributes(&ObjectAttributes
,
1891 OBJ_CASE_INSENSITIVE
,
1895 /* Open the adapter key */
1896 Status
= ZwOpenKey(&SystemKey
,
1899 if (!NT_SUCCESS(Status
))
1901 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status
);
1905 /* Allocate value buffer */
1906 ValueBuffer
= ExAllocatePool(PagedPool
,
1908 if (ValueBuffer
== NULL
)
1910 DPRINT("Failed to allocate value buffer\n");
1915 RtlInitUnicodeString(&ValueName
,
1916 L
"Configuration Data");
1918 /* Query 'Configuration Data' value */
1919 Status
= ZwQueryValueKey(SystemKey
,
1921 KeyValueFullInformation
,
1925 if (!NT_SUCCESS(Status
))
1927 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status
);
1928 ExFreePool(ValueBuffer
);
1933 /* Open the 'MultifunctionAdapter' subkey */
1934 RtlInitUnicodeString(&KeyName
,
1935 L
"MultifunctionAdapter");
1937 InitializeObjectAttributes(&ObjectAttributes
,
1939 OBJ_CASE_INSENSITIVE
,
1943 Status
= ZwOpenKey(&BusKey
,
1947 if (!NT_SUCCESS(Status
))
1949 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status
);
1950 ExFreePool(ValueBuffer
);
1954 if (!ScsiDiskSearchForDisk(DeviceExtension
, BusKey
, &DiskNumber
))
1956 DPRINT("ScsiDiskSearchForDisk() failed\n");
1958 ExFreePool(ValueBuffer
);
1964 ResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)
1965 ((PUCHAR
)ValueBuffer
+ ValueBuffer
->DataOffset
);
1967 DriveParameters
= (PCM_INT13_DRIVE_PARAMETER
)
1968 ((PUCHAR
)ResourceDescriptor
+ sizeof(CM_FULL_RESOURCE_DESCRIPTOR
));
1971 for (i
= 0; i
< DriveParameters
[0].NumberDrives
; i
++)
1973 DPRINT("Drive %lu: %lu Cylinders %hu Heads %hu Sectors\n",
1975 DriveParameters
[i
].MaxCylinders
,
1976 DriveParameters
[i
].MaxHeads
,
1977 DriveParameters
[i
].SectorsPerTrack
);
1981 Cylinders
= DriveParameters
[DiskNumber
].MaxCylinders
+ 1;
1982 TracksPerCylinder
= DriveParameters
[DiskNumber
].MaxHeads
+1;
1983 SectorsPerTrack
= DriveParameters
[DiskNumber
].SectorsPerTrack
;
1985 DPRINT("BIOS geometry: %lu Cylinders %hu Heads %hu Sectors\n",
1991 (DeviceExtension
->PartitionLength
.QuadPart
>> DeviceExtension
->SectorShift
);
1993 DPRINT("Physical sectors: %lu\n",
1996 Length
= TracksPerCylinder
* SectorsPerTrack
;
1999 DPRINT("Invalid track length 0\n");
2000 ExFreePool(ValueBuffer
);
2004 Cylinders
= Sectors
/ Length
;
2006 DPRINT("Logical geometry: %lu Cylinders %hu Heads %hu Sectors\n",
2011 /* Update the disk geometry */
2012 DeviceExtension
->DiskGeometry
->SectorsPerTrack
= SectorsPerTrack
;
2013 DeviceExtension
->DiskGeometry
->TracksPerCylinder
= TracksPerCylinder
;
2014 DeviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (ULONGLONG
)Cylinders
;
2016 if (DeviceExtension
->DMActive
)
2018 DPRINT("FIXME: Update geometry with respect to the installed disk manager!\n");
2020 /* FIXME: Update geometry for disk managers */
2024 ExFreePool(ValueBuffer
);
2026 DPRINT("ScsiDiskUpdateFixedDiskGeometry() done\n");
2030 /**********************************************************************
2032 * ScsiDiskCalcMbrCheckSum
2035 * Calculates the Checksum from drives MBR.
2042 * Disk device extension.
2045 * Pointer to the caller supplied cecksum variable.
2048 * TRUE: Checksum was calculated.
2049 * FALSE: Calculation failed.
2053 ScsiDiskCalcMbrCheckSum(IN PDEVICE_EXTENSION DeviceExtension
,
2054 OUT PULONG Checksum
)
2056 IO_STATUS_BLOCK IoStatusBlock
;
2057 LARGE_INTEGER SectorOffset
;
2066 KeInitializeEvent(&Event
,
2070 /* Get the disk sector size */
2071 SectorSize
= DeviceExtension
->DiskGeometry
->BytesPerSector
;
2072 if (SectorSize
< 512)
2077 /* Allocate MBR buffer */
2078 MbrBuffer
= ExAllocatePool(NonPagedPool
,
2080 if (MbrBuffer
== NULL
)
2085 /* Allocate an IRP */
2086 SectorOffset
.QuadPart
= 0ULL;
2087 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
2088 DeviceExtension
->DeviceObject
,
2096 ExFreePool(MbrBuffer
);
2100 /* Call the miniport driver */
2101 Status
= IoCallDriver(DeviceExtension
->DeviceObject
,
2103 if (Status
== STATUS_PENDING
)
2105 KeWaitForSingleObject(&Event
,
2110 Status
= IoStatusBlock
.Status
;
2113 if (!NT_SUCCESS(Status
))
2115 ExFreePool(MbrBuffer
);
2119 /* Calculate MBR checksum */
2121 for (i
= 0; i
< 128; i
++)
2123 Sum
+= MbrBuffer
[i
];
2125 *Checksum
= ~Sum
+ 1;
2127 ExFreePool(MbrBuffer
);