3 * Copyright (C) 2001, 2002, 2003 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.
19 /* $Id: disk.c,v 1.37 2004/03/31 03:39:12 jimtabor Exp $
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 (ekohl@rz-online.de)
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 DiskBuildPartionTable(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
;
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
;
552 /* Get timeout value */
553 DiskDeviceExtension
->TimeOutValue
=
554 ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
555 if (DiskDeviceExtension
->TimeOutValue
== 0)
556 DiskDeviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
558 /* Initialize the lookaside list for SRBs */
559 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension
,
562 /* zero-out disk data */
563 DiskData
= (PDISK_DATA
)(DiskDeviceExtension
+ 1);
564 RtlZeroMemory(DiskData
,
567 /* Get disk geometry */
568 DiskDeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
569 sizeof(DISK_GEOMETRY
));
570 if (DiskDeviceExtension
->DiskGeometry
== NULL
)
572 DPRINT("Failed to allocate geometry buffer!\n");
574 ExDeleteNPagedLookasideList(&DiskDeviceExtension
->SrbLookasideListHead
);
576 IoDeleteDevice(DiskDeviceObject
);
578 /* Release (unclaim) the disk */
579 ScsiClassClaimDevice(PortDeviceObject
,
584 /* Delete the harddisk device directory */
585 ZwMakeTemporaryObject(Handle
);
588 return(STATUS_INSUFFICIENT_RESOURCES
);
591 /* Allocate sense data buffer */
592 DiskDeviceExtension
->SenseData
= ExAllocatePool(NonPagedPool
,
594 if (DiskDeviceExtension
->SenseData
== NULL
)
596 DPRINT("Failed to allocate sense data buffer!\n");
598 ExFreePool (DiskDeviceExtension
->DiskGeometry
);
600 ExDeleteNPagedLookasideList(&DiskDeviceExtension
->SrbLookasideListHead
);
602 IoDeleteDevice(DiskDeviceObject
);
604 /* Release (unclaim) the disk */
605 ScsiClassClaimDevice(PortDeviceObject
,
610 /* Delete the harddisk device directory */
611 ZwMakeTemporaryObject(Handle
);
614 return(STATUS_INSUFFICIENT_RESOURCES
);
617 /* Read the drive's capacity */
618 Status
= ScsiClassReadDriveCapacity(DiskDeviceObject
);
619 if (!NT_SUCCESS(Status
) &&
620 (DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) == 0)
622 DPRINT("Failed to retrieve drive capacity!\n");
623 return(STATUS_SUCCESS
);
627 /* Clear the verify flag for removable media drives. */
628 DiskDeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
631 DPRINT("SectorSize: %lu\n", DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
633 if ((DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
634 (DiskDeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
637 DiskClassCreateMediaChangeEvent(DiskDeviceExtension
,DiskNumber
);
638 if(DiskDeviceExtension
->MediaChangeEvent
!= NULL
)
640 DPRINT("Allocated media change event!\n");
645 /* Check disk for presence of a disk manager */
646 HalExamineMBR(DiskDeviceObject
,
647 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
650 if (MbrBuffer
!= NULL
)
652 /* Start disk at sector 63 if the Ontrack Disk Manager was found */
653 DPRINT("Found 'Ontrack Disk Manager'!\n");
655 DiskDeviceExtension
->DMSkew
= 63;
656 DiskDeviceExtension
->DMByteSkew
=
657 63 * DiskDeviceExtension
->DiskGeometry
->BytesPerSector
;
658 DiskDeviceExtension
->DMActive
= TRUE
;
660 ExFreePool(MbrBuffer
);
663 if ((DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
664 (DiskDeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
666 /* Allocate a partition list for a single entry. */
667 PartitionList
= ExAllocatePool(NonPagedPool
,
668 sizeof(DRIVE_LAYOUT_INFORMATION
));
669 if (PartitionList
!= NULL
)
671 RtlZeroMemory(PartitionList
,
672 sizeof(DRIVE_LAYOUT_INFORMATION
));
673 PartitionList
->PartitionCount
= 1;
675 DiskData
->DriveNotReady
= TRUE
;
676 Status
= STATUS_SUCCESS
;
681 /* Read partition table */
682 Status
= IoReadPartitionTable(DiskDeviceObject
,
683 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
687 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status
);
689 if ((!NT_SUCCESS(Status
) || PartitionList
->PartitionCount
== 0) &&
690 DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
692 if (!NT_SUCCESS(Status
))
694 /* Drive is not ready. */
695 DPRINT("Drive not ready\n");
696 DiskData
->DriveNotReady
= TRUE
;
700 ExFreePool(PartitionList
);
703 /* Allocate a partition list for a single entry. */
704 PartitionList
= ExAllocatePool(NonPagedPool
,
705 sizeof(DRIVE_LAYOUT_INFORMATION
));
706 if (PartitionList
!= NULL
)
708 RtlZeroMemory(PartitionList
,
709 sizeof(DRIVE_LAYOUT_INFORMATION
));
710 PartitionList
->PartitionCount
= 1;
712 Status
= STATUS_SUCCESS
;
717 if (NT_SUCCESS(Status
))
719 DPRINT("Read partition table!\n");
720 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
722 /* Set disk signature */
723 DiskData
->Signature
= PartitionList
->Signature
;
725 /* Calculate MBR checksum if disk got no signature */
726 if (DiskData
->Signature
== 0)
728 if (!ScsiDiskCalcMbrCheckSum(DiskDeviceExtension
,
729 &DiskData
->MbrCheckSum
))
731 DPRINT("MBR checksum calculation failed for disk %lu\n",
732 DiskDeviceExtension
->DeviceNumber
);
736 DPRINT("MBR checksum for disk %lu is %lx\n",
737 DiskDeviceExtension
->DeviceNumber
,
738 DiskData
->MbrCheckSum
);
743 DPRINT("Signature on disk %lu is %lx\n",
744 DiskDeviceExtension
->DeviceNumber
,
745 DiskData
->Signature
);
748 /* Update disk geometry if disk is visible to the BIOS */
749 ScsiDiskUpdateFixedDiskGeometry(DiskDeviceExtension
);
751 for (PartitionNumber
= 0; PartitionNumber
< PartitionList
->PartitionCount
; PartitionNumber
++)
753 PartitionEntry
= &PartitionList
->PartitionEntry
[PartitionNumber
];
755 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
757 PartitionEntry
->PartitionNumber
,
758 PartitionEntry
->BootIndicator
,
759 PartitionEntry
->PartitionType
,
760 PartitionEntry
->StartingOffset
.QuadPart
/ 512 /*DrvParms.BytesPerSector*/,
761 PartitionEntry
->PartitionLength
.QuadPart
/ 512 /* DrvParms.BytesPerSector*/);
763 /* Create partition device object */
765 "\\Device\\Harddisk%lu\\Partition%lu",
767 PartitionNumber
+ 1);
769 Status
= ScsiClassCreateDeviceObject(DriverObject
,
772 &PartitionDeviceObject
,
774 DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status
);
775 if (NT_SUCCESS(Status
))
777 PartitionDeviceObject
->Flags
= DiskDeviceObject
->Flags
;
778 PartitionDeviceObject
->Characteristics
= DiskDeviceObject
->Characteristics
;
779 PartitionDeviceObject
->StackSize
= DiskDeviceObject
->StackSize
;
780 PartitionDeviceObject
->AlignmentRequirement
= DiskDeviceObject
->AlignmentRequirement
;
782 PartitionDeviceExtension
= PartitionDeviceObject
->DeviceExtension
;
783 PartitionDeviceExtension
->SenseData
= DiskDeviceExtension
->SenseData
;
784 PartitionDeviceExtension
->LockCount
= 0;
785 PartitionDeviceExtension
->DeviceNumber
= DiskNumber
;
786 PartitionDeviceExtension
->DeviceObject
= PartitionDeviceObject
;
787 PartitionDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
788 PartitionDeviceExtension
->DiskGeometry
= DiskDeviceExtension
->DiskGeometry
;
789 PartitionDeviceExtension
->PhysicalDevice
= DiskDeviceExtension
->PhysicalDevice
;
790 PartitionDeviceExtension
->PortCapabilities
= Capabilities
;
791 PartitionDeviceExtension
->StartingOffset
.QuadPart
=
792 PartitionEntry
->StartingOffset
.QuadPart
;
793 PartitionDeviceExtension
->PartitionLength
.QuadPart
=
794 PartitionEntry
->PartitionLength
.QuadPart
;
795 PartitionDeviceExtension
->DMSkew
= DiskDeviceExtension
->DMSkew
;
796 PartitionDeviceExtension
->DMByteSkew
= DiskDeviceExtension
->DMByteSkew
;
797 PartitionDeviceExtension
->DMActive
= DiskDeviceExtension
->DMActive
;
798 PartitionDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
799 PartitionDeviceExtension
->PathId
= InquiryData
->PathId
;
800 PartitionDeviceExtension
->TargetId
= InquiryData
->TargetId
;
801 PartitionDeviceExtension
->Lun
= InquiryData
->Lun
;
802 PartitionDeviceExtension
->SectorShift
= DiskDeviceExtension
->SectorShift
;
803 PartitionDeviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
805 /* Initialize lookaside list for SRBs */
806 ScsiClassInitializeSrbLookasideList(PartitionDeviceExtension
,
809 /* Link current partition device extension to previous disk data */
810 DiskData
->NextPartition
= PartitionDeviceExtension
;
812 /* Initialize current disk data */
813 DiskData
= (PDISK_DATA
)(PartitionDeviceExtension
+ 1);
814 DiskData
->NextPartition
= NULL
;
815 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
816 DiskData
->PartitionNumber
= PartitionNumber
+ 1;
817 DiskData
->PartitionOrdinal
= PartitionNumber
+ 1;
818 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
819 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
820 DiskData
->DriveNotReady
= FALSE
;
824 DPRINT("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status
);
831 if (PartitionList
!= NULL
)
832 ExFreePool(PartitionList
);
834 DPRINT("DiskClassCreateDeviceObjects() done\n");
836 return(STATUS_SUCCESS
);
841 DiskBuildPartionTable(IN PDEVICE_OBJECT DiskDeviceObject
,
844 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
845 PDEVICE_EXTENSION DiskDeviceExtension
;
847 PPARTITION_INFORMATION PartitionEntry
;
848 ULONG PartitionNumber
;
851 DPRINT("DiskBuildPartitionTable() start\n");
853 DiskDeviceExtension
= (PDEVICE_EXTENSION
)DiskDeviceObject
->DeviceExtension
;
854 DiskData
= (PDISK_DATA
)(DiskDeviceExtension
+ 1);
856 if (DiskDeviceExtension
->StartingOffset
.QuadPart
)
858 DPRINT("Partition already installed\n");
859 return(STATUS_SUCCESS
);
862 /* Read partition table */
863 Status
= IoReadPartitionTable(DiskDeviceObject
,
864 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
869 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status
);
871 if (!NT_SUCCESS(Status
))
873 /* Drive is not ready. */
874 DPRINT("Drive not ready\n");
875 DiskData
->DriveNotReady
= TRUE
;
877 if (PartitionList
!= NULL
)
878 ExFreePool(PartitionList
);
882 if (NT_SUCCESS(Status
))
884 DPRINT("Read partition table!\n");
885 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
887 /* Set disk signature */
888 DiskData
->Signature
= PartitionList
->Signature
;
890 for (PartitionNumber
= 0; PartitionNumber
< PartitionList
->PartitionCount
; PartitionNumber
++)
892 PartitionEntry
= &PartitionList
->PartitionEntry
[PartitionNumber
];
894 DiskData
->NextPartition
= NULL
;
895 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
896 DiskData
->PartitionNumber
= PartitionNumber
+ 1;
897 DiskData
->PartitionOrdinal
= PartitionNumber
+ 1;
898 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
899 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
900 DiskData
->DriveNotReady
= FALSE
;
901 DiskDeviceExtension
->StartingOffset
= PartitionEntry
->StartingOffset
;
902 DiskDeviceExtension
->PartitionLength
= PartitionEntry
->PartitionLength
;
904 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
906 DiskData
->PartitionNumber
,
907 DiskData
->BootIndicator
,
908 DiskData
->PartitionType
,
909 DiskDeviceExtension
->StartingOffset
.QuadPart
/ 512 /*DrvParms.BytesPerSector*/,
910 DiskDeviceExtension
->PartitionLength
.QuadPart
/ 512 /* DrvParms.BytesPerSector*/);
913 if (PartitionList
!= NULL
)
914 ExFreePool(PartitionList
);
916 DPRINT("DiskBuildPartitionTable() done\n");
918 return(STATUS_SUCCESS
);
922 /**********************************************************************
924 * DiskClassDeviceControl
927 * Answer requests for device control calls
933 * Standard dispatch arguments
940 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
943 PDEVICE_EXTENSION DeviceExtension
;
944 PIO_STACK_LOCATION IrpStack
;
945 ULONG ControlCode
, InputLength
, OutputLength
;
950 DPRINT("DiskClassDeviceControl() called!\n");
952 Status
= STATUS_INVALID_DEVICE_REQUEST
;
954 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
955 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
956 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
957 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
958 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
959 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
963 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
964 DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
965 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
967 Status
= STATUS_INVALID_PARAMETER
;
971 if (DeviceExtension
->DiskGeometry
== NULL
)
973 DPRINT("No disk geometry available!\n");
974 DeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
975 sizeof(DISK_GEOMETRY
));
978 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
980 Status
= ScsiClassReadDriveCapacity(DeviceObject
);
981 DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status
);
982 if (!NT_SUCCESS(Status
))
984 /* Drive is not ready */
985 DiskData
->DriveNotReady
= FALSE
;
990 DiskData
->DriveNotReady
= FALSE
;
993 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
994 DeviceExtension
->DiskGeometry
,
995 sizeof(DISK_GEOMETRY
));
997 Status
= STATUS_SUCCESS
;
998 Information
= sizeof(DISK_GEOMETRY
);
1001 case IOCTL_DISK_GET_PARTITION_INFO
:
1002 DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
1004 if ((DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
1005 (DeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
1007 /* Allocate a partition list for a single entry. */
1008 Status
= DiskBuildPartionTable(DeviceObject
,Irp
);
1011 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1012 sizeof(PARTITION_INFORMATION
))
1014 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1016 else if (DiskData
->PartitionNumber
== 0)
1018 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1022 PPARTITION_INFORMATION PartitionInfo
;
1024 PartitionInfo
= (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
1026 PartitionInfo
->PartitionType
= DiskData
->PartitionType
;
1027 PartitionInfo
->StartingOffset
= DeviceExtension
->StartingOffset
;
1028 PartitionInfo
->PartitionLength
= DeviceExtension
->PartitionLength
;
1029 PartitionInfo
->HiddenSectors
= DiskData
->HiddenSectors
;
1030 PartitionInfo
->PartitionNumber
= DiskData
->PartitionNumber
;
1031 PartitionInfo
->BootIndicator
= DiskData
->BootIndicator
;
1032 PartitionInfo
->RewritePartition
= FALSE
;
1033 PartitionInfo
->RecognizedPartition
=
1034 IsRecognizedPartition(DiskData
->PartitionType
);
1036 Status
= STATUS_SUCCESS
;
1037 Information
= sizeof(PARTITION_INFORMATION
);
1041 case IOCTL_DISK_SET_PARTITION_INFO
:
1042 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1043 sizeof(SET_PARTITION_INFORMATION
))
1045 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1047 else if (DiskData
->PartitionNumber
== 0)
1049 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1053 PSET_PARTITION_INFORMATION PartitionInfo
;
1055 PartitionInfo
= (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
1057 Status
= IoSetPartitionInformation(DeviceExtension
->PhysicalDevice
,
1058 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1059 DiskData
->PartitionOrdinal
,
1060 PartitionInfo
->PartitionType
);
1061 if (NT_SUCCESS(Status
))
1063 DiskData
->PartitionType
= PartitionInfo
->PartitionType
;
1068 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1069 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1070 sizeof(DRIVE_LAYOUT_INFORMATION
))
1072 Status
= STATUS_BUFFER_TOO_SMALL
;
1076 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1078 Status
= IoReadPartitionTable(DeviceExtension
->PhysicalDevice
,
1079 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1082 if (NT_SUCCESS(Status
))
1086 BufferSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
1088 BufferSize
+= PartitionList
->PartitionCount
* sizeof(PARTITION_INFORMATION
);
1090 if (BufferSize
> IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
1092 Status
= STATUS_BUFFER_TOO_SMALL
;
1096 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1099 Status
= STATUS_SUCCESS
;
1100 Information
= BufferSize
;
1102 ExFreePool(PartitionList
);
1107 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
1108 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1109 sizeof(DRIVE_LAYOUT_INFORMATION
))
1111 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1113 else if (DeviceExtension
->PhysicalDevice
->DeviceExtension
!= DeviceExtension
)
1115 Status
= STATUS_INVALID_PARAMETER
;
1119 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1122 PartitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
1123 TableSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
1124 ((PartitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
));
1126 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< TableSize
)
1128 Status
= STATUS_BUFFER_TOO_SMALL
;
1132 /* Update partition device objects */
1133 DiskClassUpdatePartitionDeviceObjects (DeviceObject
,
1136 /* Write partition table */
1137 Status
= IoWritePartitionTable(DeviceExtension
->PhysicalDevice
,
1138 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1139 DeviceExtension
->DiskGeometry
->SectorsPerTrack
,
1140 DeviceExtension
->DiskGeometry
->TracksPerCylinder
,
1146 case IOCTL_DISK_IS_WRITABLE
:
1148 PMODE_PARAMETER_HEADER ModeData
;
1151 ModeData
= ExAllocatePool (NonPagedPool
,
1153 if (ModeData
== NULL
)
1155 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1158 RtlZeroMemory (ModeData
,
1161 Length
= ScsiClassModeSense (DeviceObject
,
1164 MODE_SENSE_RETURN_ALL
);
1165 if (Length
< sizeof(MODE_PARAMETER_HEADER
))
1168 Status
= STATUS_IO_DEVICE_ERROR
;
1169 ExFreePool (ModeData
);
1173 if (ModeData
->DeviceSpecificParameter
& MODE_DSP_WRITE_PROTECT
)
1175 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1179 Status
= STATUS_SUCCESS
;
1181 ExFreePool (ModeData
);
1186 case IOCTL_DISK_CHECK_VERIFY
:
1187 DPRINT("IOCTL_DISK_CHECK_VERIFY\n");
1188 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
)
1190 DPRINT("Do Verify Set\n");
1191 Status
= STATUS_VERIFY_REQUIRED
;
1196 DPRINT("Do Verify Clear\n");
1197 Status
= STATUS_SUCCESS
;
1202 case IOCTL_DISK_VERIFY
:
1203 case IOCTL_DISK_FORMAT_TRACKS
:
1204 case IOCTL_DISK_PERFORMANCE
:
1205 case IOCTL_DISK_LOGGING
:
1206 case IOCTL_DISK_FORMAT_TRACKS_EX
:
1207 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
1208 case IOCTL_DISK_HISTOGRAM_DATA
:
1209 case IOCTL_DISK_HISTOGRAM_RESET
:
1210 case IOCTL_DISK_REQUEST_STRUCTURE
:
1211 case IOCTL_DISK_REQUEST_DATA
:
1212 /* If we get here, something went wrong. Inform the requestor */
1213 DPRINT("Unhandled control code: %lx\n", ControlCode
);
1214 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1219 /* Call the common device control function */
1220 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
1223 /* Verify the device if the user caused the error */
1224 if (!NT_SUCCESS(Status
) && IoIsErrorUserInduced(Status
))
1226 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1229 Irp
->IoStatus
.Status
= Status
;
1230 Irp
->IoStatus
.Information
= Information
;
1231 IoCompleteRequest(Irp
,
1238 /**********************************************************************
1240 * DiskClassShutdownFlush
1243 * Answer requests for shutdown and flush calls.
1250 * Pointer to the device.
1253 * Pointer to the IRP
1260 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
1263 PDEVICE_EXTENSION DeviceExtension
;
1264 PIO_STACK_LOCATION IrpStack
;
1265 PSCSI_REQUEST_BLOCK Srb
;
1267 DPRINT("DiskClassShutdownFlush() called!\n");
1269 DeviceExtension
= DeviceObject
->DeviceExtension
;
1272 Srb
= ExAllocatePool(NonPagedPool
,
1273 sizeof(SCSI_REQUEST_BLOCK
));
1276 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1277 Irp
->IoStatus
.Information
= 0;
1278 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1280 return(STATUS_INSUFFICIENT_RESOURCES
);
1283 /* Initialize SRB */
1284 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
1285 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
1287 /* Set device IDs */
1288 Srb
->PathId
= DeviceExtension
->PathId
;
1289 Srb
->TargetId
= DeviceExtension
->TargetId
;
1290 Srb
->Lun
= DeviceExtension
->Lun
;
1293 Srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
* 4;
1295 /* Flush write cache */
1296 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1297 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1298 Srb
->CdbLength
= 10;
1299 Srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
1300 ScsiClassSendSrbSynchronous(DeviceObject
,
1306 /* Get current stack location */
1307 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1309 /* FIXME: Unlock removable media upon shutdown */
1313 IrpStack
->Parameters
.Others
.Argument4
= (PVOID
)0;
1315 /* Send shutdown or flush request to the port driver */
1317 if (IrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
)
1318 Srb
->Function
= SRB_FUNCTION_SHUTDOWN
;
1320 Srb
->Function
= SRB_FUNCTION_FLUSH
;
1322 /* Init completion routine */
1323 IoSetCompletionRoutine(Irp
,
1324 ScsiClassIoComplete
,
1330 /* Prepare next stack location for a call to the port driver */
1331 IrpStack
= IoGetNextIrpStackLocation(Irp
);
1332 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1333 IrpStack
->Parameters
.Scsi
.Srb
= Srb
;
1334 Srb
->OriginalRequest
= Irp
;
1336 /* Call port driver */
1337 return(IoCallDriver(DeviceExtension
->PortDeviceObject
, Irp
));
1341 /**********************************************************************
1343 * DiskClassUpdatePartitionDeviceObjects
1346 * Deletes, modifies or creates partition device objects.
1353 * Pointer to the device.
1356 * Pointer to the IRP
1363 DiskClassUpdatePartitionDeviceObjects(IN PDEVICE_OBJECT DiskDeviceObject
,
1366 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1367 PPARTITION_INFORMATION PartitionEntry
;
1368 PDEVICE_EXTENSION DeviceExtension
;
1369 PDEVICE_EXTENSION DiskDeviceExtension
;
1370 PDISK_DATA DiskData
;
1371 ULONG PartitionCount
;
1372 ULONG PartitionOrdinal
;
1373 ULONG PartitionNumber
;
1374 ULONG LastPartitionNumber
;
1377 WCHAR NameBuffer
[MAX_PATH
];
1378 UNICODE_STRING DeviceName
;
1379 PDEVICE_OBJECT DeviceObject
;
1382 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() called\n");
1384 /* Get partition list */
1385 PartitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
1387 /* Round partition count up by 4 */
1388 PartitionCount
= ((PartitionList
->PartitionCount
+ 3) / 4) * 4;
1390 /* Remove the partition numbers from the partition list */
1391 for (i
= 0; i
< PartitionCount
; i
++)
1393 PartitionList
->PartitionEntry
[i
].PartitionNumber
= 0;
1396 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
1398 /* Traverse on-disk partition list */
1399 LastPartitionNumber
= 0;
1400 DeviceExtension
= DiskDeviceExtension
;
1401 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1404 DeviceExtension
= DiskData
->NextPartition
;
1405 if (DeviceExtension
== NULL
)
1409 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1411 /* Update last partition number */
1412 if (DiskData
->PartitionNumber
> LastPartitionNumber
)
1413 LastPartitionNumber
= DiskData
->PartitionNumber
;
1415 /* Ignore unused on-disk partitions */
1416 if (DeviceExtension
->PartitionLength
.QuadPart
== 0ULL)
1420 PartitionOrdinal
= 0;
1421 for (i
= 0; i
< PartitionCount
; i
++)
1423 /* Get current partition entry */
1424 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
1426 /* Ignore empty (aka unused) or extended partitions */
1427 if (PartitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
1428 IsContainerPartition (PartitionEntry
->PartitionType
))
1433 /* Check for matching partition start offset and length */
1434 if ((PartitionEntry
->StartingOffset
.QuadPart
!=
1435 DeviceExtension
->StartingOffset
.QuadPart
) ||
1436 (PartitionEntry
->PartitionLength
.QuadPart
!=
1437 DeviceExtension
->PartitionLength
.QuadPart
))
1440 DPRINT("Found matching partition entry for partition %lu\n",
1441 DiskData
->PartitionNumber
);
1443 /* Found matching partition */
1446 /* Update partition number in partition list */
1447 PartitionEntry
->PartitionNumber
= DiskData
->PartitionNumber
;
1453 /* Get disk data for current partition */
1454 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1456 /* Update partition type if partiton will be rewritten */
1457 if (PartitionEntry
->RewritePartition
== TRUE
)
1458 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
1460 /* Assign new partiton ordinal */
1461 DiskData
->PartitionOrdinal
= PartitionOrdinal
;
1463 DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1464 DiskData
->PartitionOrdinal
,
1465 DiskData
->PartitionNumber
);
1469 /* Delete this partition */
1470 DeviceExtension
->PartitionLength
.QuadPart
= 0ULL;
1472 DPRINT("Deleting partition %lu\n",
1473 DiskData
->PartitionNumber
);
1477 /* Traverse partiton list and create new partiton devices */
1478 PartitionOrdinal
= 0;
1479 for (i
= 0; i
< PartitionCount
; i
++)
1481 /* Get current partition entry */
1482 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
1484 /* Ignore empty (aka unused) or extended partitions */
1485 if (PartitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
1486 IsContainerPartition (PartitionEntry
->PartitionType
))
1491 /* Ignore unchanged partition entries */
1492 if (PartitionEntry
->RewritePartition
== FALSE
)
1495 /* Check for an unused device object */
1496 PartitionNumber
= 0;
1497 DeviceExtension
= DiskDeviceExtension
;
1498 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1501 DeviceExtension
= DiskData
->NextPartition
;
1502 if (DeviceExtension
== NULL
)
1505 /* Get partition disk data */
1506 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1508 /* Found a free (unused) partition (device object) */
1509 if (DeviceExtension
->PartitionLength
.QuadPart
== 0ULL)
1511 PartitionNumber
= DiskData
->PartitionNumber
;
1516 if (PartitionNumber
== 0)
1518 /* Create a new partition device object */
1519 DPRINT("Create new partition device object\n");
1521 /* Get new partiton number */
1522 LastPartitionNumber
++;
1523 PartitionNumber
= LastPartitionNumber
;
1525 /* Create partition device object */
1526 swprintf(NameBuffer
,
1527 L
"\\Device\\Harddisk%lu\\Partition%lu",
1528 DiskDeviceExtension
->DeviceNumber
,
1530 RtlInitUnicodeString(&DeviceName
,
1533 Status
= IoCreateDevice(DiskDeviceObject
->DriverObject
,
1534 sizeof(DEVICE_EXTENSION
) + sizeof(DISK_DATA
),
1540 if (!NT_SUCCESS(Status
))
1542 DPRINT("IoCreateDevice() failed (Status %lx)\n", Status
);
1546 DeviceObject
->Flags
|= DO_DIRECT_IO
;
1547 DeviceObject
->StackSize
= DiskDeviceObject
->StackSize
;
1548 DeviceObject
->Characteristics
= DiskDeviceObject
->Characteristics
;
1549 DeviceObject
->AlignmentRequirement
= DiskDeviceObject
->AlignmentRequirement
;
1551 /* Initialize device extension */
1552 DeviceExtension
= DeviceObject
->DeviceExtension
;
1553 RtlCopyMemory(DeviceExtension
,
1554 DiskDeviceObject
->DeviceExtension
,
1555 sizeof(DEVICE_EXTENSION
));
1556 DeviceExtension
->DeviceObject
= DeviceObject
;
1558 /* Initialize lookaside list for SRBs */
1559 ScsiClassInitializeSrbLookasideList(DeviceExtension
,
1562 /* Link current partition device extension to previous disk data */
1563 DiskData
->NextPartition
= DeviceExtension
;
1564 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1565 DiskData
->NextPartition
= NULL
;
1569 /* Reuse an existing partition device object */
1570 DPRINT("Reuse an exisiting partition device object\n");
1571 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1574 /* Update partition data and device extension */
1575 DiskData
->PartitionNumber
= PartitionNumber
;
1576 DiskData
->PartitionOrdinal
= PartitionOrdinal
;
1577 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
1578 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
1579 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
1580 DeviceExtension
->StartingOffset
= PartitionEntry
->StartingOffset
;
1581 DeviceExtension
->PartitionLength
= PartitionEntry
->PartitionLength
;
1583 /* Update partition number in the partition list */
1584 PartitionEntry
->PartitionNumber
= PartitionNumber
;
1586 DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1587 DiskData
->PartitionOrdinal
,
1588 DiskData
->PartitionNumber
);
1591 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() done\n");
1595 /**********************************************************************
1597 * ScsiDiskSearchForDisk
1600 * Searches the hardware tree for the given disk.
1607 * Disk device extension.
1610 * Handle to the hardware bus key.
1612 * DetectedDiskNumber
1613 * Returned disk number.
1616 * TRUE: Disk was found.
1617 * FALSE: Search failed.
1621 ScsiDiskSearchForDisk(IN PDEVICE_EXTENSION DeviceExtension
,
1623 OUT PULONG DetectedDiskNumber
)
1625 PKEY_VALUE_FULL_INFORMATION ValueData
;
1626 OBJECT_ATTRIBUTES ObjectAttributes
;
1627 PDISK_DATA DiskData
;
1628 UNICODE_STRING IdentifierString
;
1629 UNICODE_STRING NameString
;
1630 HANDLE BusInstanceKey
;
1631 HANDLE ControllerKey
;
1633 HANDLE DiskInstanceKey
;
1635 ULONG ControllerNumber
;
1642 DPRINT("ScsiDiskSearchForDiskData() called\n");
1646 /* Enumerate buses */
1647 for (BusNumber
= 0; ; BusNumber
++)
1649 /* Open bus instance subkey */
1654 RtlInitUnicodeString(&NameString
,
1657 InitializeObjectAttributes(&ObjectAttributes
,
1659 OBJ_CASE_INSENSITIVE
,
1663 Status
= ZwOpenKey(&BusInstanceKey
,
1666 if (!NT_SUCCESS(Status
))
1671 /* Open 'DiskController' subkey */
1672 RtlInitUnicodeString(&NameString
,
1675 InitializeObjectAttributes(&ObjectAttributes
,
1677 OBJ_CASE_INSENSITIVE
,
1681 Status
= ZwOpenKey(&ControllerKey
,
1684 if (!NT_SUCCESS(Status
))
1686 ZwClose(BusInstanceKey
);
1690 /* Enumerate controllers */
1691 for (ControllerNumber
= 0; ; ControllerNumber
++)
1693 /* Open 'DiskPeripheral' subkey */
1695 L
"%lu\\DiskPeripheral",
1698 RtlInitUnicodeString(&NameString
,
1701 InitializeObjectAttributes(&ObjectAttributes
,
1703 OBJ_CASE_INSENSITIVE
,
1707 Status
= ZwOpenKey(&DiskKey
,
1710 if (!NT_SUCCESS(Status
))
1715 /* Enumerate disks */
1716 for (DiskNumber
= 0; ; DiskNumber
++)
1718 /* Open disk instance subkey */
1723 RtlInitUnicodeString(&NameString
,
1726 InitializeObjectAttributes(&ObjectAttributes
,
1728 OBJ_CASE_INSENSITIVE
,
1732 Status
= ZwOpenKey(&DiskInstanceKey
,
1735 if (!NT_SUCCESS(Status
))
1740 DPRINT("Found disk key: bus %lu controller %lu disk %lu\n",
1745 /* Allocate data buffer */
1746 ValueData
= ExAllocatePool(PagedPool
,
1748 if (ValueData
== NULL
)
1750 ZwClose(DiskInstanceKey
);
1754 /* Get the 'Identifier' value */
1755 RtlInitUnicodeString(&NameString
,
1757 Status
= ZwQueryValueKey(DiskInstanceKey
,
1759 KeyValueFullInformation
,
1764 ZwClose(DiskInstanceKey
);
1765 if (!NT_SUCCESS(Status
))
1767 ExFreePool(ValueData
);
1771 IdentifierString
.Buffer
=
1772 (PWSTR
)((PUCHAR
)ValueData
+ ValueData
->DataOffset
);
1773 IdentifierString
.Length
= (USHORT
)ValueData
->DataLength
- 2;
1774 IdentifierString
.MaximumLength
= (USHORT
)ValueData
->DataLength
;
1776 DPRINT("DiskIdentifier: %wZ\n",
1779 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1780 if (DiskData
->Signature
!= 0)
1782 /* Comapre disk signature */
1785 DiskData
->Signature
);
1786 if (!_wcsnicmp(Buffer
, &IdentifierString
.Buffer
[9], 8))
1788 DPRINT("Found disk %lu\n", DiskNumber
);
1790 *DetectedDiskNumber
= DiskNumber
;
1795 /* Comapre mbr checksum */
1798 DiskData
->MbrCheckSum
);
1799 if (!_wcsnicmp(Buffer
, &IdentifierString
.Buffer
[0], 8))
1801 DPRINT("Found disk %lu\n", DiskNumber
);
1803 *DetectedDiskNumber
= DiskNumber
;
1807 ExFreePool(ValueData
);
1809 ZwClose(DiskInstanceKey
);
1811 if (DiskFound
== TRUE
)
1818 ZwClose(ControllerKey
);
1819 ZwClose(BusInstanceKey
);
1822 DPRINT("ScsiDiskSearchForDisk() done\n");
1828 /**********************************************************************
1830 * DiskClassUpdateFixedDiskGeometry
1833 * Updated the geometry of a disk if the disk can be accessed
1841 * Disk device extension.
1848 ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension
)
1850 PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
1851 PCM_INT13_DRIVE_PARAMETER DriveParameters
;
1852 PKEY_VALUE_FULL_INFORMATION ValueBuffer
;
1853 OBJECT_ATTRIBUTES ObjectAttributes
;
1854 UNICODE_STRING KeyName
;
1855 UNICODE_STRING ValueName
;
1865 ULONG SectorsPerTrack
;
1866 ULONG TracksPerCylinder
;
1869 DPRINT("ScsiDiskUpdateFixedDiskGeometry() called\n");
1871 RtlInitUnicodeString(&KeyName
,
1872 L
"\\Registry\\Machine\\Hardware\\Description\\System");
1874 InitializeObjectAttributes(&ObjectAttributes
,
1876 OBJ_CASE_INSENSITIVE
,
1880 /* Open the adapter key */
1881 Status
= ZwOpenKey(&SystemKey
,
1884 if (!NT_SUCCESS(Status
))
1886 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status
);
1890 /* Allocate value buffer */
1891 ValueBuffer
= ExAllocatePool(PagedPool
,
1893 if (ValueBuffer
== NULL
)
1895 DPRINT("Failed to allocate value buffer\n");
1900 RtlInitUnicodeString(&ValueName
,
1901 L
"Configuration Data");
1903 /* Query 'Configuration Data' value */
1904 Status
= ZwQueryValueKey(SystemKey
,
1906 KeyValueFullInformation
,
1910 if (!NT_SUCCESS(Status
))
1912 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status
);
1913 ExFreePool(ValueBuffer
);
1918 /* Open the 'MultifunctionAdapter' subkey */
1919 RtlInitUnicodeString(&KeyName
,
1920 L
"MultifunctionAdapter");
1922 InitializeObjectAttributes(&ObjectAttributes
,
1924 OBJ_CASE_INSENSITIVE
,
1928 Status
= ZwOpenKey(&BusKey
,
1932 if (!NT_SUCCESS(Status
))
1934 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status
);
1935 ExFreePool(ValueBuffer
);
1939 if (!ScsiDiskSearchForDisk(DeviceExtension
, BusKey
, &DiskNumber
))
1941 DPRINT("ScsiDiskSearchForDisk() failed\n");
1943 ExFreePool(ValueBuffer
);
1949 ResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)
1950 ((PUCHAR
)ValueBuffer
+ ValueBuffer
->DataOffset
);
1952 DriveParameters
= (PCM_INT13_DRIVE_PARAMETER
)
1953 ((PUCHAR
)ResourceDescriptor
+ sizeof(CM_FULL_RESOURCE_DESCRIPTOR
));
1956 for (i
= 0; i
< DriveParameters
[0].NumberDrives
; i
++)
1958 DPRINT("Drive %lu: %lu Cylinders %hu Heads %hu Sectors\n",
1960 DriveParameters
[i
].MaxCylinders
,
1961 DriveParameters
[i
].MaxHeads
,
1962 DriveParameters
[i
].SectorsPerTrack
);
1966 Cylinders
= DriveParameters
[DiskNumber
].MaxCylinders
+ 1;
1967 TracksPerCylinder
= DriveParameters
[DiskNumber
].MaxHeads
+1;
1968 SectorsPerTrack
= DriveParameters
[DiskNumber
].SectorsPerTrack
;
1970 DPRINT("BIOS geometry: %lu Cylinders %hu Heads %hu Sectors\n",
1976 (DeviceExtension
->PartitionLength
.QuadPart
>> DeviceExtension
->SectorShift
);
1978 DPRINT("Physical sectors: %lu\n",
1981 Length
= TracksPerCylinder
* SectorsPerTrack
;
1984 DPRINT("Invalid track length 0\n");
1985 ExFreePool(ValueBuffer
);
1989 Cylinders
= Sectors
/ Length
;
1991 DPRINT("Logical geometry: %lu Cylinders %hu Heads %hu Sectors\n",
1996 /* Update the disk geometry */
1997 DeviceExtension
->DiskGeometry
->SectorsPerTrack
= SectorsPerTrack
;
1998 DeviceExtension
->DiskGeometry
->TracksPerCylinder
= TracksPerCylinder
;
1999 DeviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (ULONGLONG
)Cylinders
;
2001 if (DeviceExtension
->DMActive
)
2003 DPRINT("FIXME: Update geometry with respect to the installed disk manager!\n");
2005 /* FIXME: Update geometry for disk managers */
2009 ExFreePool(ValueBuffer
);
2011 DPRINT("ScsiDiskUpdateFixedDiskGeometry() done\n");
2015 /**********************************************************************
2017 * ScsiDiskCalcMbrCheckSum
2020 * Calculates the Checksum from drives MBR.
2027 * Disk device extension.
2030 * Pointer to the caller supplied cecksum variable.
2033 * TRUE: Checksum was calculated.
2034 * FALSE: Calculation failed.
2038 ScsiDiskCalcMbrCheckSum(IN PDEVICE_EXTENSION DeviceExtension
,
2039 OUT PULONG Checksum
)
2041 IO_STATUS_BLOCK IoStatusBlock
;
2042 LARGE_INTEGER SectorOffset
;
2051 KeInitializeEvent(&Event
,
2055 /* Get the disk sector size */
2056 SectorSize
= DeviceExtension
->DiskGeometry
->BytesPerSector
;
2057 if (SectorSize
< 512)
2062 /* Allocate MBR buffer */
2063 MbrBuffer
= ExAllocatePool(NonPagedPool
,
2065 if (MbrBuffer
== NULL
)
2070 /* Allocate an IRP */
2071 SectorOffset
.QuadPart
= 0ULL;
2072 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
2073 DeviceExtension
->DeviceObject
,
2081 ExFreePool(MbrBuffer
);
2085 /* Call the miniport driver */
2086 Status
= IoCallDriver(DeviceExtension
->DeviceObject
,
2088 if (Status
== STATUS_PENDING
)
2090 KeWaitForSingleObject(&Event
,
2095 Status
= IoStatusBlock
.Status
;
2098 if (!NT_SUCCESS(Status
))
2100 ExFreePool(MbrBuffer
);
2104 /* Calculate MBR checksum */
2106 for (i
= 0; i
< 128; i
++)
2108 Sum
+= MbrBuffer
[i
];
2110 *Checksum
= ~Sum
+ 1;
2112 ExFreePool(MbrBuffer
);