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
;
393 PIO_STACK_LOCATION IrpStack
;
394 ULARGE_INTEGER EndingOffset
;
396 DPRINT("DiskClassCheckReadWrite() called\n");
398 DeviceExtension
= DeviceObject
->DeviceExtension
;
399 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
401 if (DiskData
->DriveNotReady
== TRUE
)
403 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
404 IoSetHardErrorOrVerifyDevice(Irp
,
406 return(STATUS_INVALID_PARAMETER
);
411 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
412 EndingOffset
.QuadPart
= IrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
413 IrpStack
->Parameters
.Read
.Length
;
416 DPRINT("Ending %I64d, and RealEnding %I64d! PartSize %I64d\n",EndingOffset
.QuadPart
,
417 DeviceExtension
->PartitionLength
.QuadPart
,
418 DeviceExtension
->PartitionLength
.QuadPart
/
419 DeviceExtension
->DiskGeometry
->BytesPerSector
);
421 if ((DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
422 (DeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
424 /* Assume if removable media and if Partition length is 0, Partition not built yet! */
425 if (DeviceExtension
->PartitionLength
.QuadPart
== 0)
426 return(STATUS_SUCCESS
);
429 if (EndingOffset
.QuadPart
> DeviceExtension
->PartitionLength
.QuadPart
)
431 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
432 return(STATUS_INVALID_PARAMETER
);
435 return(STATUS_SUCCESS
);
439 /**********************************************************************
441 * DiskClassCreateDeviceObject
444 * Create the raw device and any partition devices on this drive
451 * The system created driver object
461 * STATUS_SUCCESS: Device objects for disk and partitions were created.
466 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
467 IN PUNICODE_STRING RegistryPath
,
468 IN PDEVICE_OBJECT PortDeviceObject
,
471 IN PIO_SCSI_CAPABILITIES Capabilities
,
472 IN PSCSI_INQUIRY_DATA InquiryData
,
473 IN PCLASS_INIT_DATA InitializationData
)
475 OBJECT_ATTRIBUTES ObjectAttributes
;
476 UNICODE_STRING UnicodeDeviceDirName
;
477 WCHAR NameBuffer
[80];
478 CHAR NameBuffer2
[80];
479 PDEVICE_OBJECT DiskDeviceObject
;
480 PDEVICE_OBJECT PartitionDeviceObject
;
481 PDEVICE_EXTENSION DiskDeviceExtension
; /* defined in class2.h */
482 PDEVICE_EXTENSION PartitionDeviceExtension
; /* defined in class2.h */
483 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
485 PPARTITION_INFORMATION PartitionEntry
;
487 ULONG PartitionNumber
;
491 DPRINT("DiskClassCreateDeviceObject() called\n");
493 /* Create the harddisk device directory */
495 L
"\\Device\\Harddisk%lu",
497 RtlInitUnicodeString(&UnicodeDeviceDirName
,
499 InitializeObjectAttributes(&ObjectAttributes
,
500 &UnicodeDeviceDirName
,
504 Status
= ZwCreateDirectoryObject(&Handle
,
507 if (!NT_SUCCESS(Status
))
509 DbgPrint("Could not create device dir object\n");
513 /* Claim the disk device */
514 Status
= ScsiClassClaimDevice(PortDeviceObject
,
518 if (!NT_SUCCESS(Status
))
520 DbgPrint("Could not claim disk device\n");
522 ZwMakeTemporaryObject(Handle
);
528 /* Create disk device (Partition 0) */
530 "\\Device\\Harddisk%lu\\Partition0",
533 Status
= ScsiClassCreateDeviceObject(DriverObject
,
538 if (!NT_SUCCESS(Status
))
540 DPRINT("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status
);
542 /* Release (unclaim) the disk */
543 ScsiClassClaimDevice(PortDeviceObject
,
548 /* Delete the harddisk device directory */
549 ZwMakeTemporaryObject(Handle
);
555 DiskDeviceObject
->Flags
|= DO_DIRECT_IO
;
556 if (((PINQUIRYDATA
)InquiryData
->InquiryData
)->RemovableMedia
)
558 DiskDeviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
560 DiskDeviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
562 if (PortDeviceObject
->AlignmentRequirement
> DiskDeviceObject
->AlignmentRequirement
)
564 DiskDeviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
567 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
568 DiskDeviceExtension
->LockCount
= 0;
569 DiskDeviceExtension
->DeviceNumber
= DiskNumber
;
570 DiskDeviceExtension
->DeviceObject
= DiskDeviceObject
;
571 DiskDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
572 DiskDeviceExtension
->PhysicalDevice
= DiskDeviceObject
;
573 DiskDeviceExtension
->PortCapabilities
= Capabilities
;
574 DiskDeviceExtension
->StartingOffset
.QuadPart
= 0;
575 DiskDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
576 DiskDeviceExtension
->PathId
= InquiryData
->PathId
;
577 DiskDeviceExtension
->TargetId
= InquiryData
->TargetId
;
578 DiskDeviceExtension
->Lun
= InquiryData
->Lun
;
579 DiskDeviceExtension
->SrbFlags
= 0;
581 /* Enable the command queueing, if it possible */
582 if (Capabilities
->TaggedQueuing
&&
583 ((PINQUIRYDATA
)InquiryData
->InquiryData
)->CommandQueue
)
585 DiskDeviceExtension
->SrbFlags
|= SRB_FLAGS_QUEUE_ACTION_ENABLE
;
588 /* Get timeout value */
589 DiskDeviceExtension
->TimeOutValue
=
590 ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
591 if (DiskDeviceExtension
->TimeOutValue
== 0)
592 DiskDeviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
594 /* Initialize the lookaside list for SRBs */
595 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension
,
598 /* zero-out disk data */
599 DiskData
= (PDISK_DATA
)(DiskDeviceExtension
+ 1);
600 RtlZeroMemory(DiskData
,
603 /* Get disk geometry */
604 DiskDeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
605 sizeof(DISK_GEOMETRY
));
606 if (DiskDeviceExtension
->DiskGeometry
== NULL
)
608 DPRINT("Failed to allocate geometry buffer!\n");
610 ExDeleteNPagedLookasideList(&DiskDeviceExtension
->SrbLookasideListHead
);
612 IoDeleteDevice(DiskDeviceObject
);
614 /* Release (unclaim) the disk */
615 ScsiClassClaimDevice(PortDeviceObject
,
620 /* Delete the harddisk device directory */
621 ZwMakeTemporaryObject(Handle
);
624 return(STATUS_INSUFFICIENT_RESOURCES
);
627 /* Allocate sense data buffer */
628 DiskDeviceExtension
->SenseData
= ExAllocatePool(NonPagedPoolCacheAligned
,
630 if (DiskDeviceExtension
->SenseData
== NULL
)
632 DPRINT("Failed to allocate sense data buffer!\n");
634 ExFreePool (DiskDeviceExtension
->DiskGeometry
);
636 ExDeleteNPagedLookasideList(&DiskDeviceExtension
->SrbLookasideListHead
);
638 IoDeleteDevice(DiskDeviceObject
);
640 /* Release (unclaim) the disk */
641 ScsiClassClaimDevice(PortDeviceObject
,
646 /* Delete the harddisk device directory */
647 ZwMakeTemporaryObject(Handle
);
650 return(STATUS_INSUFFICIENT_RESOURCES
);
653 /* Read the drive's capacity */
654 Status
= ScsiClassReadDriveCapacity(DiskDeviceObject
);
655 if (!NT_SUCCESS(Status
) &&
656 (DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) == 0)
658 DPRINT("Failed to retrieve drive capacity!\n");
659 return(STATUS_SUCCESS
);
663 /* Clear the verify flag for removable media drives. */
664 DiskDeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
667 DPRINT("SectorSize: %lu\n", DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
669 if ((DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
670 (DiskDeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
672 DiskClassCreateMediaChangeEvent(DiskDeviceExtension
,DiskNumber
);
673 if (DiskDeviceExtension
->MediaChangeEvent
!= NULL
)
675 DPRINT("Allocated media change event!\n");
679 /* Check disk for presence of a disk manager */
680 HalExamineMBR(DiskDeviceObject
,
681 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
684 if (MbrBuffer
!= NULL
)
686 /* Start disk at sector 63 if the Ontrack Disk Manager was found */
687 DPRINT("Found 'Ontrack Disk Manager'!\n");
689 DiskDeviceExtension
->DMSkew
= 63;
690 DiskDeviceExtension
->DMByteSkew
=
691 63 * DiskDeviceExtension
->DiskGeometry
->BytesPerSector
;
692 DiskDeviceExtension
->DMActive
= TRUE
;
694 ExFreePool(MbrBuffer
);
698 if ((DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
699 (DiskDeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
701 /* Allocate a partition list for a single entry. */
702 PartitionList
= ExAllocatePool(NonPagedPool
,
703 sizeof(DRIVE_LAYOUT_INFORMATION
));
704 if (PartitionList
!= NULL
)
706 RtlZeroMemory(PartitionList
,
707 sizeof(DRIVE_LAYOUT_INFORMATION
));
708 PartitionList
->PartitionCount
= 1;
710 DiskData
->DriveNotReady
= TRUE
;
711 Status
= STATUS_SUCCESS
;
716 /* Read partition table */
717 Status
= IoReadPartitionTable(DiskDeviceObject
,
718 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
722 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status
);
724 if ((!NT_SUCCESS(Status
) || PartitionList
->PartitionCount
== 0) &&
725 DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
727 if (!NT_SUCCESS(Status
))
729 /* Drive is not ready. */
730 DPRINT("Drive not ready\n");
731 DiskData
->DriveNotReady
= TRUE
;
735 ExFreePool(PartitionList
);
738 /* Allocate a partition list for a single entry. */
739 PartitionList
= ExAllocatePool(NonPagedPool
,
740 sizeof(DRIVE_LAYOUT_INFORMATION
));
741 if (PartitionList
!= NULL
)
743 RtlZeroMemory(PartitionList
,
744 sizeof(DRIVE_LAYOUT_INFORMATION
));
745 PartitionList
->PartitionCount
= 1;
747 Status
= STATUS_SUCCESS
;
752 if (NT_SUCCESS(Status
))
754 DPRINT("Read partition table!\n");
755 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
757 /* Set disk signature */
758 DiskData
->Signature
= PartitionList
->Signature
;
760 /* Calculate MBR checksum if disk got no signature */
761 if (DiskData
->Signature
== 0)
763 if (!ScsiDiskCalcMbrCheckSum(DiskDeviceExtension
,
764 &DiskData
->MbrCheckSum
))
766 DPRINT("MBR checksum calculation failed for disk %lu\n",
767 DiskDeviceExtension
->DeviceNumber
);
771 DPRINT("MBR checksum for disk %lu is %lx\n",
772 DiskDeviceExtension
->DeviceNumber
,
773 DiskData
->MbrCheckSum
);
778 DPRINT("Signature on disk %lu is %lx\n",
779 DiskDeviceExtension
->DeviceNumber
,
780 DiskData
->Signature
);
783 /* Update disk geometry if disk is visible to the BIOS */
784 ScsiDiskUpdateFixedDiskGeometry(DiskDeviceExtension
);
786 for (PartitionNumber
= 0; PartitionNumber
< PartitionList
->PartitionCount
; PartitionNumber
++)
788 PartitionEntry
= &PartitionList
->PartitionEntry
[PartitionNumber
];
790 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
792 PartitionEntry
->PartitionNumber
,
793 PartitionEntry
->BootIndicator
,
794 PartitionEntry
->PartitionType
,
795 PartitionEntry
->StartingOffset
.QuadPart
/
796 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
797 PartitionEntry
->PartitionLength
.QuadPart
/
798 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
800 /* Create partition device object */
802 "\\Device\\Harddisk%lu\\Partition%lu",
804 PartitionNumber
+ 1);
806 Status
= ScsiClassCreateDeviceObject(DriverObject
,
809 &PartitionDeviceObject
,
811 DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status
);
812 if (NT_SUCCESS(Status
))
814 PartitionDeviceObject
->Flags
= DiskDeviceObject
->Flags
;
815 PartitionDeviceObject
->Characteristics
= DiskDeviceObject
->Characteristics
;
816 PartitionDeviceObject
->StackSize
= DiskDeviceObject
->StackSize
;
817 PartitionDeviceObject
->AlignmentRequirement
= DiskDeviceObject
->AlignmentRequirement
;
819 PartitionDeviceExtension
= PartitionDeviceObject
->DeviceExtension
;
820 PartitionDeviceExtension
->SenseData
= DiskDeviceExtension
->SenseData
;
821 PartitionDeviceExtension
->LockCount
= 0;
822 PartitionDeviceExtension
->DeviceNumber
= DiskNumber
;
823 PartitionDeviceExtension
->DeviceObject
= PartitionDeviceObject
;
824 PartitionDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
825 PartitionDeviceExtension
->DiskGeometry
= DiskDeviceExtension
->DiskGeometry
;
826 PartitionDeviceExtension
->PhysicalDevice
= DiskDeviceExtension
->PhysicalDevice
;
827 PartitionDeviceExtension
->PortCapabilities
= Capabilities
;
828 PartitionDeviceExtension
->StartingOffset
.QuadPart
=
829 PartitionEntry
->StartingOffset
.QuadPart
;
830 PartitionDeviceExtension
->PartitionLength
.QuadPart
=
831 PartitionEntry
->PartitionLength
.QuadPart
;
832 PartitionDeviceExtension
->DMSkew
= DiskDeviceExtension
->DMSkew
;
833 PartitionDeviceExtension
->DMByteSkew
= DiskDeviceExtension
->DMByteSkew
;
834 PartitionDeviceExtension
->DMActive
= DiskDeviceExtension
->DMActive
;
835 PartitionDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
836 PartitionDeviceExtension
->PathId
= InquiryData
->PathId
;
837 PartitionDeviceExtension
->TargetId
= InquiryData
->TargetId
;
838 PartitionDeviceExtension
->Lun
= InquiryData
->Lun
;
839 PartitionDeviceExtension
->SectorShift
= DiskDeviceExtension
->SectorShift
;
840 PartitionDeviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
842 /* Initialize lookaside list for SRBs */
843 ScsiClassInitializeSrbLookasideList(PartitionDeviceExtension
,
846 /* Link current partition device extension to previous disk data */
847 DiskData
->NextPartition
= PartitionDeviceExtension
;
849 /* Initialize current disk data */
850 DiskData
= (PDISK_DATA
)(PartitionDeviceExtension
+ 1);
851 DiskData
->NextPartition
= NULL
;
852 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
853 DiskData
->PartitionNumber
= PartitionNumber
+ 1;
854 DiskData
->PartitionOrdinal
= PartitionNumber
+ 1;
855 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
856 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
857 DiskData
->DriveNotReady
= FALSE
;
861 DPRINT("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status
);
868 if (PartitionList
!= NULL
)
869 ExFreePool(PartitionList
);
871 DPRINT("DiskClassCreateDeviceObjects() done\n");
873 return(STATUS_SUCCESS
);
878 DiskBuildPartitionTable(IN PDEVICE_OBJECT DiskDeviceObject
,
881 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
882 PDEVICE_EXTENSION DiskDeviceExtension
, DDE
;
883 PDISK_DATA DiskData
, DD
;
884 PPARTITION_INFORMATION PartitionEntry
;
885 ULONG PartitionNumber
;
888 DPRINT("DiskBuildPartitionTable() start\n");
890 DiskDeviceExtension
= (PDEVICE_EXTENSION
)DiskDeviceObject
->DeviceExtension
;
891 DiskData
= (PDISK_DATA
)(DiskDeviceExtension
+ 1);
893 DDE
= (PDEVICE_EXTENSION
) DiskDeviceExtension
->PhysicalDevice
->DeviceExtension
;
894 DD
= (PDISK_DATA
)(DDE
+1);
896 /* Clear flag for Partition0, just incase it was set. */
897 DD
->DriveNotReady
= FALSE
;
899 Status
= ScsiClassReadDriveCapacity(DiskDeviceObject
);
900 if (!NT_SUCCESS(Status
))
902 /* Drive is not ready. */
903 DPRINT("Drive not ready\n");
904 DiskData
->DriveNotReady
= TRUE
;
908 /* Read partition table */
909 Status
= IoReadPartitionTable(DiskDeviceExtension
->PhysicalDevice
,
910 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
914 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status
);
916 if (!NT_SUCCESS(Status
))
918 /* Drive is not ready. */
919 DPRINT("Drive not ready\n");
920 DiskData
->DriveNotReady
= TRUE
;
921 if (PartitionList
!= NULL
)
922 ExFreePool(PartitionList
);
926 if (NT_SUCCESS(Status
))
928 DPRINT("Read partition table!\n");
929 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
931 /* Set disk signature */
932 DiskData
->Signature
= PartitionList
->Signature
;
934 DiskData
->NextPartition
= NULL
;
936 if (PartitionList
->PartitionCount
)
938 for (PartitionNumber
= 0; PartitionNumber
< PartitionList
->PartitionCount
; PartitionNumber
++)
940 PartitionEntry
= &PartitionList
->PartitionEntry
[PartitionNumber
];
942 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
943 DiskData
->PartitionNumber
= PartitionNumber
+ 1;
944 DiskData
->PartitionOrdinal
= PartitionNumber
+ 1;
945 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
946 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
947 DiskData
->DriveNotReady
= FALSE
;
948 DiskDeviceExtension
->StartingOffset
= PartitionEntry
->StartingOffset
;
949 DiskDeviceExtension
->PartitionLength
= PartitionEntry
->PartitionLength
;
951 DPRINT1("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
953 DiskData
->PartitionNumber
,
954 DiskData
->BootIndicator
,
955 DiskData
->PartitionType
,
956 DiskDeviceExtension
->StartingOffset
.QuadPart
/
957 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
958 DiskDeviceExtension
->PartitionLength
.QuadPart
/
959 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
964 DiskData
->PartitionType
= 0;
965 DiskData
->PartitionNumber
= 1;
966 DiskData
->PartitionOrdinal
= 0;
967 DiskData
->HiddenSectors
= 0;
968 DiskData
->BootIndicator
= 0;
969 DiskData
->DriveNotReady
= FALSE
;
970 DiskDeviceExtension
->StartingOffset
.QuadPart
= 0;
971 DiskDeviceExtension
->PartitionLength
.QuadPart
+= DiskDeviceExtension
->StartingOffset
.QuadPart
;
975 DPRINT("DiskBuildPartitionTable() done\n");
976 if (PartitionList
!= NULL
)
977 ExFreePool(PartitionList
);
978 return(STATUS_SUCCESS
);
982 /**********************************************************************
984 * DiskClassDeviceControl
987 * Answer requests for device control calls
993 * Standard dispatch arguments
1000 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
1003 PDEVICE_EXTENSION DeviceExtension
;
1004 PIO_STACK_LOCATION IrpStack
;
1005 ULONG ControlCode
, InputLength
, OutputLength
;
1006 PDISK_DATA DiskData
;
1010 DPRINT("DiskClassDeviceControl() called!\n");
1012 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1014 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1015 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
1016 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
1017 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
1018 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1019 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1021 switch (ControlCode
)
1023 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
1024 DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
1025 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
1027 Status
= STATUS_INVALID_PARAMETER
;
1031 if (DeviceExtension
->DiskGeometry
== NULL
)
1033 DPRINT("No disk geometry available!\n");
1034 DeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
1035 sizeof(DISK_GEOMETRY
));
1038 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
1040 Status
= ScsiClassReadDriveCapacity(DeviceObject
);
1041 DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status
);
1042 if (!NT_SUCCESS(Status
))
1044 /* Drive is not ready */
1045 DiskData
->DriveNotReady
= TRUE
;
1049 /* Drive is ready */
1050 DiskData
->DriveNotReady
= FALSE
;
1053 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1054 DeviceExtension
->DiskGeometry
,
1055 sizeof(DISK_GEOMETRY
));
1057 Status
= STATUS_SUCCESS
;
1058 Information
= sizeof(DISK_GEOMETRY
);
1061 case IOCTL_DISK_GET_PARTITION_INFO
:
1062 DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
1064 if ((DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
1065 (DeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
1067 /* Update a partition list for a single entry. */
1068 Status
= DiskBuildPartitionTable(DeviceObject
,Irp
);
1071 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1072 sizeof(PARTITION_INFORMATION
))
1074 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1076 else if (DiskData
->PartitionNumber
== 0)
1078 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1082 PPARTITION_INFORMATION PartitionInfo
;
1084 PartitionInfo
= (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
1086 PartitionInfo
->PartitionType
= DiskData
->PartitionType
;
1087 PartitionInfo
->StartingOffset
= DeviceExtension
->StartingOffset
;
1088 PartitionInfo
->PartitionLength
= DeviceExtension
->PartitionLength
;
1089 PartitionInfo
->HiddenSectors
= DiskData
->HiddenSectors
;
1090 PartitionInfo
->PartitionNumber
= DiskData
->PartitionNumber
;
1091 PartitionInfo
->BootIndicator
= DiskData
->BootIndicator
;
1092 PartitionInfo
->RewritePartition
= FALSE
;
1093 PartitionInfo
->RecognizedPartition
=
1094 IsRecognizedPartition(DiskData
->PartitionType
);
1096 Status
= STATUS_SUCCESS
;
1097 Information
= sizeof(PARTITION_INFORMATION
);
1101 case IOCTL_DISK_SET_PARTITION_INFO
:
1102 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1103 sizeof(SET_PARTITION_INFORMATION
))
1105 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1107 else if (DiskData
->PartitionNumber
== 0)
1109 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1113 PSET_PARTITION_INFORMATION PartitionInfo
;
1115 PartitionInfo
= (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
1117 Status
= IoSetPartitionInformation(DeviceExtension
->PhysicalDevice
,
1118 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1119 DiskData
->PartitionOrdinal
,
1120 PartitionInfo
->PartitionType
);
1121 if (NT_SUCCESS(Status
))
1123 DiskData
->PartitionType
= PartitionInfo
->PartitionType
;
1128 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1129 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1130 sizeof(DRIVE_LAYOUT_INFORMATION
))
1132 Status
= STATUS_BUFFER_TOO_SMALL
;
1136 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1138 Status
= IoReadPartitionTable(DeviceExtension
->PhysicalDevice
,
1139 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1142 if (NT_SUCCESS(Status
))
1146 BufferSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
1148 BufferSize
+= PartitionList
->PartitionCount
* sizeof(PARTITION_INFORMATION
);
1150 if (BufferSize
> IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
1152 Status
= STATUS_BUFFER_TOO_SMALL
;
1156 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1159 Status
= STATUS_SUCCESS
;
1160 Information
= BufferSize
;
1162 ExFreePool(PartitionList
);
1167 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
1168 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1169 sizeof(DRIVE_LAYOUT_INFORMATION
))
1171 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1173 else if (DeviceExtension
->PhysicalDevice
->DeviceExtension
!= DeviceExtension
)
1175 Status
= STATUS_INVALID_PARAMETER
;
1179 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1182 PartitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
1183 TableSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
1184 ((PartitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
));
1186 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< TableSize
)
1188 Status
= STATUS_BUFFER_TOO_SMALL
;
1192 /* Update partition device objects */
1193 DiskClassUpdatePartitionDeviceObjects (DeviceObject
,
1196 /* Write partition table */
1197 Status
= IoWritePartitionTable(DeviceExtension
->PhysicalDevice
,
1198 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1199 DeviceExtension
->DiskGeometry
->SectorsPerTrack
,
1200 DeviceExtension
->DiskGeometry
->TracksPerCylinder
,
1206 case IOCTL_DISK_IS_WRITABLE
:
1208 PMODE_PARAMETER_HEADER ModeData
;
1211 ModeData
= ExAllocatePool (NonPagedPool
,
1213 if (ModeData
== NULL
)
1215 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1218 RtlZeroMemory (ModeData
,
1221 Length
= ScsiClassModeSense (DeviceObject
,
1224 MODE_SENSE_RETURN_ALL
);
1225 if (Length
< sizeof(MODE_PARAMETER_HEADER
))
1228 Status
= STATUS_IO_DEVICE_ERROR
;
1229 ExFreePool (ModeData
);
1233 if (ModeData
->DeviceSpecificParameter
& MODE_DSP_WRITE_PROTECT
)
1235 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1239 Status
= STATUS_SUCCESS
;
1241 ExFreePool (ModeData
);
1245 case IOCTL_DISK_VERIFY
:
1246 case IOCTL_DISK_FORMAT_TRACKS
:
1247 case IOCTL_DISK_PERFORMANCE
:
1248 case IOCTL_DISK_LOGGING
:
1249 case IOCTL_DISK_FORMAT_TRACKS_EX
:
1250 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
1251 case IOCTL_DISK_HISTOGRAM_DATA
:
1252 case IOCTL_DISK_HISTOGRAM_RESET
:
1253 case IOCTL_DISK_REQUEST_STRUCTURE
:
1254 case IOCTL_DISK_REQUEST_DATA
:
1255 /* If we get here, something went wrong. Inform the requestor */
1256 DPRINT("Unhandled control code: %lx\n", ControlCode
);
1257 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1262 /* Call the common device control function */
1263 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
1266 /* Verify the device if the user caused the error */
1267 if (!NT_SUCCESS(Status
) && IoIsErrorUserInduced(Status
))
1269 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1272 Irp
->IoStatus
.Status
= Status
;
1273 Irp
->IoStatus
.Information
= Information
;
1274 IoCompleteRequest(Irp
,
1281 /**********************************************************************
1283 * DiskClassShutdownFlush
1286 * Answer requests for shutdown and flush calls.
1293 * Pointer to the device.
1296 * Pointer to the IRP
1303 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
1306 PDEVICE_EXTENSION DeviceExtension
;
1307 PIO_STACK_LOCATION IrpStack
;
1308 PSCSI_REQUEST_BLOCK Srb
;
1310 DPRINT("DiskClassShutdownFlush() called!\n");
1312 DeviceExtension
= DeviceObject
->DeviceExtension
;
1315 Srb
= ExAllocatePool(NonPagedPool
,
1316 sizeof(SCSI_REQUEST_BLOCK
));
1319 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1320 Irp
->IoStatus
.Information
= 0;
1321 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1323 return(STATUS_INSUFFICIENT_RESOURCES
);
1326 /* Initialize SRB */
1327 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
1328 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
1330 /* Set device IDs */
1331 Srb
->PathId
= DeviceExtension
->PathId
;
1332 Srb
->TargetId
= DeviceExtension
->TargetId
;
1333 Srb
->Lun
= DeviceExtension
->Lun
;
1336 Srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
* 4;
1338 /* Flush write cache */
1339 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1340 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1341 Srb
->CdbLength
= 10;
1342 Srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
1343 ScsiClassSendSrbSynchronous(DeviceObject
,
1349 /* Get current stack location */
1350 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1352 /* FIXME: Unlock removable media upon shutdown */
1356 IrpStack
->Parameters
.Others
.Argument4
= (PVOID
)0;
1358 /* Send shutdown or flush request to the port driver */
1360 if (IrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
)
1361 Srb
->Function
= SRB_FUNCTION_SHUTDOWN
;
1363 Srb
->Function
= SRB_FUNCTION_FLUSH
;
1365 /* Init completion routine */
1366 IoSetCompletionRoutine(Irp
,
1367 ScsiClassIoComplete
,
1373 /* Prepare next stack location for a call to the port driver */
1374 IrpStack
= IoGetNextIrpStackLocation(Irp
);
1375 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1376 IrpStack
->Parameters
.Scsi
.Srb
= Srb
;
1377 Srb
->OriginalRequest
= Irp
;
1379 /* Call port driver */
1380 return(IoCallDriver(DeviceExtension
->PortDeviceObject
, Irp
));
1384 /**********************************************************************
1386 * DiskClassUpdatePartitionDeviceObjects
1389 * Deletes, modifies or creates partition device objects.
1396 * Pointer to the device.
1399 * Pointer to the IRP
1406 DiskClassUpdatePartitionDeviceObjects(IN PDEVICE_OBJECT DiskDeviceObject
,
1409 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1410 PPARTITION_INFORMATION PartitionEntry
;
1411 PDEVICE_EXTENSION DeviceExtension
;
1412 PDEVICE_EXTENSION DiskDeviceExtension
;
1413 PDISK_DATA DiskData
;
1414 ULONG PartitionCount
;
1415 ULONG PartitionOrdinal
;
1416 ULONG PartitionNumber
;
1417 ULONG LastPartitionNumber
;
1420 WCHAR NameBuffer
[MAX_PATH
];
1421 UNICODE_STRING DeviceName
;
1422 PDEVICE_OBJECT DeviceObject
;
1425 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() called\n");
1427 /* Get partition list */
1428 PartitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
1430 /* Round partition count up by 4 */
1431 PartitionCount
= ((PartitionList
->PartitionCount
+ 3) / 4) * 4;
1433 /* Remove the partition numbers from the partition list */
1434 for (i
= 0; i
< PartitionCount
; i
++)
1436 PartitionList
->PartitionEntry
[i
].PartitionNumber
= 0;
1439 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
1441 /* Traverse on-disk partition list */
1442 LastPartitionNumber
= 0;
1443 DeviceExtension
= DiskDeviceExtension
;
1444 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1447 DeviceExtension
= DiskData
->NextPartition
;
1448 if (DeviceExtension
== NULL
)
1452 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1454 /* Update last partition number */
1455 if (DiskData
->PartitionNumber
> LastPartitionNumber
)
1456 LastPartitionNumber
= DiskData
->PartitionNumber
;
1458 /* Ignore unused on-disk partitions */
1459 if (DeviceExtension
->PartitionLength
.QuadPart
== 0ULL)
1463 PartitionOrdinal
= 0;
1464 for (i
= 0; i
< PartitionCount
; i
++)
1466 /* Get current partition entry */
1467 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
1469 /* Ignore empty (aka unused) or extended partitions */
1470 if (PartitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
1471 IsContainerPartition (PartitionEntry
->PartitionType
))
1476 /* Check for matching partition start offset and length */
1477 if ((PartitionEntry
->StartingOffset
.QuadPart
!=
1478 DeviceExtension
->StartingOffset
.QuadPart
) ||
1479 (PartitionEntry
->PartitionLength
.QuadPart
!=
1480 DeviceExtension
->PartitionLength
.QuadPart
))
1483 DPRINT("Found matching partition entry for partition %lu\n",
1484 DiskData
->PartitionNumber
);
1486 /* Found matching partition */
1489 /* Update partition number in partition list */
1490 PartitionEntry
->PartitionNumber
= DiskData
->PartitionNumber
;
1496 /* Get disk data for current partition */
1497 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1499 /* Update partition type if partiton will be rewritten */
1500 if (PartitionEntry
->RewritePartition
== TRUE
)
1501 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
1503 /* Assign new partiton ordinal */
1504 DiskData
->PartitionOrdinal
= PartitionOrdinal
;
1506 DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1507 DiskData
->PartitionOrdinal
,
1508 DiskData
->PartitionNumber
);
1512 /* Delete this partition */
1513 DeviceExtension
->PartitionLength
.QuadPart
= 0ULL;
1515 DPRINT("Deleting partition %lu\n",
1516 DiskData
->PartitionNumber
);
1520 /* Traverse partiton list and create new partiton devices */
1521 PartitionOrdinal
= 0;
1522 for (i
= 0; i
< PartitionCount
; i
++)
1524 /* Get current partition entry */
1525 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
1527 /* Ignore empty (aka unused) or extended partitions */
1528 if (PartitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
1529 IsContainerPartition (PartitionEntry
->PartitionType
))
1534 /* Ignore unchanged partition entries */
1535 if (PartitionEntry
->RewritePartition
== FALSE
)
1538 /* Check for an unused device object */
1539 PartitionNumber
= 0;
1540 DeviceExtension
= DiskDeviceExtension
;
1541 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1544 DeviceExtension
= DiskData
->NextPartition
;
1545 if (DeviceExtension
== NULL
)
1548 /* Get partition disk data */
1549 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1551 /* Found a free (unused) partition (device object) */
1552 if (DeviceExtension
->PartitionLength
.QuadPart
== 0ULL)
1554 PartitionNumber
= DiskData
->PartitionNumber
;
1559 if (PartitionNumber
== 0)
1561 /* Create a new partition device object */
1562 DPRINT("Create new partition device object\n");
1564 /* Get new partiton number */
1565 LastPartitionNumber
++;
1566 PartitionNumber
= LastPartitionNumber
;
1568 /* Create partition device object */
1569 swprintf(NameBuffer
,
1570 L
"\\Device\\Harddisk%lu\\Partition%lu",
1571 DiskDeviceExtension
->DeviceNumber
,
1573 RtlInitUnicodeString(&DeviceName
,
1576 Status
= IoCreateDevice(DiskDeviceObject
->DriverObject
,
1577 sizeof(DEVICE_EXTENSION
) + sizeof(DISK_DATA
),
1583 if (!NT_SUCCESS(Status
))
1585 DPRINT("IoCreateDevice() failed (Status %lx)\n", Status
);
1589 DeviceObject
->Flags
|= DO_DIRECT_IO
;
1590 DeviceObject
->StackSize
= DiskDeviceObject
->StackSize
;
1591 DeviceObject
->Characteristics
= DiskDeviceObject
->Characteristics
;
1592 DeviceObject
->AlignmentRequirement
= DiskDeviceObject
->AlignmentRequirement
;
1594 /* Initialize device extension */
1595 DeviceExtension
= DeviceObject
->DeviceExtension
;
1596 RtlCopyMemory(DeviceExtension
,
1597 DiskDeviceObject
->DeviceExtension
,
1598 sizeof(DEVICE_EXTENSION
));
1599 DeviceExtension
->DeviceObject
= DeviceObject
;
1601 /* Initialize lookaside list for SRBs */
1602 ScsiClassInitializeSrbLookasideList(DeviceExtension
,
1605 /* Link current partition device extension to previous disk data */
1606 DiskData
->NextPartition
= DeviceExtension
;
1607 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1608 DiskData
->NextPartition
= NULL
;
1612 /* Reuse an existing partition device object */
1613 DPRINT("Reuse an exisiting partition device object\n");
1614 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1617 /* Update partition data and device extension */
1618 DiskData
->PartitionNumber
= PartitionNumber
;
1619 DiskData
->PartitionOrdinal
= PartitionOrdinal
;
1620 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
1621 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
1622 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
1623 DeviceExtension
->StartingOffset
= PartitionEntry
->StartingOffset
;
1624 DeviceExtension
->PartitionLength
= PartitionEntry
->PartitionLength
;
1626 /* Update partition number in the partition list */
1627 PartitionEntry
->PartitionNumber
= PartitionNumber
;
1629 DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1630 DiskData
->PartitionOrdinal
,
1631 DiskData
->PartitionNumber
);
1634 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() done\n");
1638 /**********************************************************************
1640 * ScsiDiskSearchForDisk
1643 * Searches the hardware tree for the given disk.
1650 * Disk device extension.
1653 * Handle to the hardware bus key.
1655 * DetectedDiskNumber
1656 * Returned disk number.
1659 * TRUE: Disk was found.
1660 * FALSE: Search failed.
1664 ScsiDiskSearchForDisk(IN PDEVICE_EXTENSION DeviceExtension
,
1666 OUT PULONG DetectedDiskNumber
)
1668 PKEY_VALUE_FULL_INFORMATION ValueData
;
1669 OBJECT_ATTRIBUTES ObjectAttributes
;
1670 PDISK_DATA DiskData
;
1671 UNICODE_STRING IdentifierString
;
1672 UNICODE_STRING NameString
;
1673 HANDLE BusInstanceKey
;
1674 HANDLE ControllerKey
;
1676 HANDLE DiskInstanceKey
;
1678 ULONG ControllerNumber
;
1685 DPRINT("ScsiDiskSearchForDiskData() called\n");
1689 /* Enumerate buses */
1690 for (BusNumber
= 0; ; BusNumber
++)
1692 /* Open bus instance subkey */
1697 RtlInitUnicodeString(&NameString
,
1700 InitializeObjectAttributes(&ObjectAttributes
,
1702 OBJ_CASE_INSENSITIVE
,
1706 Status
= ZwOpenKey(&BusInstanceKey
,
1709 if (!NT_SUCCESS(Status
))
1714 /* Open 'DiskController' subkey */
1715 RtlInitUnicodeString(&NameString
,
1718 InitializeObjectAttributes(&ObjectAttributes
,
1720 OBJ_CASE_INSENSITIVE
,
1724 Status
= ZwOpenKey(&ControllerKey
,
1727 if (!NT_SUCCESS(Status
))
1729 ZwClose(BusInstanceKey
);
1733 /* Enumerate controllers */
1734 for (ControllerNumber
= 0; ; ControllerNumber
++)
1736 /* Open 'DiskPeripheral' subkey */
1738 L
"%lu\\DiskPeripheral",
1741 RtlInitUnicodeString(&NameString
,
1744 InitializeObjectAttributes(&ObjectAttributes
,
1746 OBJ_CASE_INSENSITIVE
,
1750 Status
= ZwOpenKey(&DiskKey
,
1753 if (!NT_SUCCESS(Status
))
1758 /* Enumerate disks */
1759 for (DiskNumber
= 0; ; DiskNumber
++)
1761 /* Open disk instance subkey */
1766 RtlInitUnicodeString(&NameString
,
1769 InitializeObjectAttributes(&ObjectAttributes
,
1771 OBJ_CASE_INSENSITIVE
,
1775 Status
= ZwOpenKey(&DiskInstanceKey
,
1778 if (!NT_SUCCESS(Status
))
1783 DPRINT("Found disk key: bus %lu controller %lu disk %lu\n",
1788 /* Allocate data buffer */
1789 ValueData
= ExAllocatePool(PagedPool
,
1791 if (ValueData
== NULL
)
1793 ZwClose(DiskInstanceKey
);
1797 /* Get the 'Identifier' value */
1798 RtlInitUnicodeString(&NameString
,
1800 Status
= ZwQueryValueKey(DiskInstanceKey
,
1802 KeyValueFullInformation
,
1807 ZwClose(DiskInstanceKey
);
1808 if (!NT_SUCCESS(Status
))
1810 ExFreePool(ValueData
);
1814 IdentifierString
.Buffer
=
1815 (PWSTR
)((PUCHAR
)ValueData
+ ValueData
->DataOffset
);
1816 IdentifierString
.Length
= (USHORT
)ValueData
->DataLength
- 2;
1817 IdentifierString
.MaximumLength
= (USHORT
)ValueData
->DataLength
;
1819 DPRINT("DiskIdentifier: %wZ\n",
1822 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1823 if (DiskData
->Signature
!= 0)
1825 /* Comapre disk signature */
1828 DiskData
->Signature
);
1829 if (!_wcsnicmp(Buffer
, &IdentifierString
.Buffer
[9], 8))
1831 DPRINT("Found disk %lu\n", DiskNumber
);
1833 *DetectedDiskNumber
= DiskNumber
;
1838 /* Comapre mbr checksum */
1841 DiskData
->MbrCheckSum
);
1842 if (!_wcsnicmp(Buffer
, &IdentifierString
.Buffer
[0], 8))
1844 DPRINT("Found disk %lu\n", DiskNumber
);
1846 *DetectedDiskNumber
= DiskNumber
;
1850 ExFreePool(ValueData
);
1852 ZwClose(DiskInstanceKey
);
1854 if (DiskFound
== TRUE
)
1861 ZwClose(ControllerKey
);
1862 ZwClose(BusInstanceKey
);
1865 DPRINT("ScsiDiskSearchForDisk() done\n");
1871 /**********************************************************************
1873 * DiskClassUpdateFixedDiskGeometry
1876 * Updated the geometry of a disk if the disk can be accessed
1884 * Disk device extension.
1891 ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension
)
1893 PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
1894 PCM_INT13_DRIVE_PARAMETER DriveParameters
;
1895 PKEY_VALUE_FULL_INFORMATION ValueBuffer
;
1896 OBJECT_ATTRIBUTES ObjectAttributes
;
1897 UNICODE_STRING KeyName
;
1898 UNICODE_STRING ValueName
;
1908 ULONG SectorsPerTrack
;
1909 ULONG TracksPerCylinder
;
1912 DPRINT("ScsiDiskUpdateFixedDiskGeometry() called\n");
1914 RtlInitUnicodeString(&KeyName
,
1915 L
"\\Registry\\Machine\\Hardware\\Description\\System");
1917 InitializeObjectAttributes(&ObjectAttributes
,
1919 OBJ_CASE_INSENSITIVE
,
1923 /* Open the adapter key */
1924 Status
= ZwOpenKey(&SystemKey
,
1927 if (!NT_SUCCESS(Status
))
1929 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status
);
1933 /* Allocate value buffer */
1934 ValueBuffer
= ExAllocatePool(PagedPool
,
1936 if (ValueBuffer
== NULL
)
1938 DPRINT("Failed to allocate value buffer\n");
1943 RtlInitUnicodeString(&ValueName
,
1944 L
"Configuration Data");
1946 /* Query 'Configuration Data' value */
1947 Status
= ZwQueryValueKey(SystemKey
,
1949 KeyValueFullInformation
,
1953 if (!NT_SUCCESS(Status
))
1955 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status
);
1956 ExFreePool(ValueBuffer
);
1961 /* Open the 'MultifunctionAdapter' subkey */
1962 RtlInitUnicodeString(&KeyName
,
1963 L
"MultifunctionAdapter");
1965 InitializeObjectAttributes(&ObjectAttributes
,
1967 OBJ_CASE_INSENSITIVE
,
1971 Status
= ZwOpenKey(&BusKey
,
1975 if (!NT_SUCCESS(Status
))
1977 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status
);
1978 ExFreePool(ValueBuffer
);
1982 if (!ScsiDiskSearchForDisk(DeviceExtension
, BusKey
, &DiskNumber
))
1984 DPRINT("ScsiDiskSearchForDisk() failed\n");
1986 ExFreePool(ValueBuffer
);
1992 ResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)
1993 ((PUCHAR
)ValueBuffer
+ ValueBuffer
->DataOffset
);
1995 DriveParameters
= (PCM_INT13_DRIVE_PARAMETER
)
1996 ((PUCHAR
)ResourceDescriptor
+ sizeof(CM_FULL_RESOURCE_DESCRIPTOR
));
1999 for (i
= 0; i
< DriveParameters
[0].NumberDrives
; i
++)
2001 DPRINT("Drive %lu: %lu Cylinders %hu Heads %hu Sectors\n",
2003 DriveParameters
[i
].MaxCylinders
,
2004 DriveParameters
[i
].MaxHeads
,
2005 DriveParameters
[i
].SectorsPerTrack
);
2009 Cylinders
= DriveParameters
[DiskNumber
].MaxCylinders
+ 1;
2010 TracksPerCylinder
= DriveParameters
[DiskNumber
].MaxHeads
+1;
2011 SectorsPerTrack
= DriveParameters
[DiskNumber
].SectorsPerTrack
;
2013 DPRINT("BIOS geometry: %lu Cylinders %hu Heads %hu Sectors\n",
2019 (DeviceExtension
->PartitionLength
.QuadPart
>> DeviceExtension
->SectorShift
);
2021 DPRINT("Physical sectors: %lu\n",
2024 Length
= TracksPerCylinder
* SectorsPerTrack
;
2027 DPRINT("Invalid track length 0\n");
2028 ExFreePool(ValueBuffer
);
2032 Cylinders
= Sectors
/ Length
;
2034 DPRINT("Logical geometry: %lu Cylinders %hu Heads %hu Sectors\n",
2039 /* Update the disk geometry */
2040 DeviceExtension
->DiskGeometry
->SectorsPerTrack
= SectorsPerTrack
;
2041 DeviceExtension
->DiskGeometry
->TracksPerCylinder
= TracksPerCylinder
;
2042 DeviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (ULONGLONG
)Cylinders
;
2044 if (DeviceExtension
->DMActive
)
2046 DPRINT("FIXME: Update geometry with respect to the installed disk manager!\n");
2048 /* FIXME: Update geometry for disk managers */
2052 ExFreePool(ValueBuffer
);
2054 DPRINT("ScsiDiskUpdateFixedDiskGeometry() done\n");
2058 /**********************************************************************
2060 * ScsiDiskCalcMbrCheckSum
2063 * Calculates the Checksum from drives MBR.
2070 * Disk device extension.
2073 * Pointer to the caller supplied cecksum variable.
2076 * TRUE: Checksum was calculated.
2077 * FALSE: Calculation failed.
2081 ScsiDiskCalcMbrCheckSum(IN PDEVICE_EXTENSION DeviceExtension
,
2082 OUT PULONG Checksum
)
2084 IO_STATUS_BLOCK IoStatusBlock
;
2085 LARGE_INTEGER SectorOffset
;
2094 KeInitializeEvent(&Event
,
2098 /* Get the disk sector size */
2099 SectorSize
= DeviceExtension
->DiskGeometry
->BytesPerSector
;
2100 if (SectorSize
< 512)
2105 /* Allocate MBR buffer */
2106 MbrBuffer
= ExAllocatePool(NonPagedPool
,
2108 if (MbrBuffer
== NULL
)
2113 /* Allocate an IRP */
2114 SectorOffset
.QuadPart
= 0ULL;
2115 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
2116 DeviceExtension
->DeviceObject
,
2124 ExFreePool(MbrBuffer
);
2128 /* Call the miniport driver */
2129 Status
= IoCallDriver(DeviceExtension
->DeviceObject
,
2131 if (Status
== STATUS_PENDING
)
2133 KeWaitForSingleObject(&Event
,
2138 Status
= IoStatusBlock
.Status
;
2141 if (!NT_SUCCESS(Status
))
2143 ExFreePool(MbrBuffer
);
2147 /* Calculate MBR checksum */
2149 for (i
= 0; i
< 128; i
++)
2151 Sum
+= MbrBuffer
[i
];
2153 *Checksum
= ~Sum
+ 1;
2155 ExFreePool(MbrBuffer
);