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.36 2004/03/31 03:33:48 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 DiskClassStartIo (IN PDEVICE_OBJECT DeviceObject
,
119 DiskDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject
,
124 /* FUNCTIONS ****************************************************************/
126 /**********************************************************************
131 * This function initializes the driver, locates and claims
132 * hardware resources, and creates various NT objects needed
133 * to process I/O requests.
140 * System allocated Driver Object for this driver
143 * Name of registry driver service key
150 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
151 IN PUNICODE_STRING RegistryPath
)
153 CLASS_INIT_DATA InitData
;
155 DPRINT("Disk Class Driver %s\n",
157 DPRINT("RegistryPath '%wZ'\n",
160 RtlZeroMemory(&InitData
,
161 sizeof(CLASS_INIT_DATA
));
163 InitData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
164 InitData
.DeviceExtensionSize
= sizeof(DEVICE_EXTENSION
) + sizeof(DISK_DATA
);
165 InitData
.DeviceType
= FILE_DEVICE_DISK
;
166 InitData
.DeviceCharacteristics
= 0;
168 InitData
.ClassError
= NULL
; // DiskClassProcessError;
169 InitData
.ClassReadWriteVerification
= DiskClassCheckReadWrite
;
170 InitData
.ClassFindDeviceCallBack
= DiskClassCheckDevice
;
171 InitData
.ClassFindDevices
= DiskClassFindDevices
;
172 InitData
.ClassDeviceControl
= DiskClassDeviceControl
;
173 InitData
.ClassShutdownFlush
= DiskClassShutdownFlush
;
174 InitData
.ClassCreateClose
= NULL
;
175 InitData
.ClassStartIo
= NULL
;
177 return(ScsiClassInitialize(DriverObject
,
183 /**********************************************************************
185 * DiskClassFindDevices
188 * This function searches for device that are attached to the
196 * System allocated Driver Object for this driver
199 * Name of registry driver service key
202 * Pointer to the main initialization data
205 * Pointer to the port Device Object
211 * TRUE: At least one disk drive was found
212 * FALSE: No disk drive found
216 DiskClassFindDevices(PDRIVER_OBJECT DriverObject
,
217 PUNICODE_STRING RegistryPath
,
218 PCLASS_INIT_DATA InitializationData
,
219 PDEVICE_OBJECT PortDeviceObject
,
222 PCONFIGURATION_INFORMATION ConfigInfo
;
223 PIO_SCSI_CAPABILITIES PortCapabilities
;
224 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
225 PSCSI_INQUIRY_DATA UnitInfo
;
226 PINQUIRYDATA InquiryData
;
233 DPRINT("DiskClassFindDevices() called.\n");
235 /* Get port capabilities */
236 Status
= ScsiClassGetCapabilities(PortDeviceObject
,
238 if (!NT_SUCCESS(Status
))
240 DPRINT("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status
);
244 DPRINT("PortCapabilities: %p\n", PortCapabilities
);
245 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities
->MaximumTransferLength
);
246 DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities
->MaximumPhysicalPages
);
248 /* Get inquiry data */
249 Status
= ScsiClassGetInquiryData(PortDeviceObject
,
250 (PSCSI_ADAPTER_BUS_INFO
*)&Buffer
);
251 if (!NT_SUCCESS(Status
))
253 DPRINT("ScsiClassGetInquiryData() failed! (Status %x)\n", Status
);
257 /* Check whether there are unclaimed devices */
258 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
259 DeviceCount
= ScsiClassFindUnclaimedDevices(InitializationData
,
261 if (DeviceCount
== 0)
263 DPRINT("No unclaimed devices!\n");
267 DPRINT("Found %lu unclaimed devices!\n", DeviceCount
);
269 ConfigInfo
= IoGetConfigurationInformation();
271 /* Search each bus of this adapter */
272 for (Bus
= 0; Bus
< (ULONG
)AdapterBusInfo
->NumberOfBuses
; Bus
++)
274 DPRINT("Searching bus %lu\n", Bus
);
276 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
);
278 while (AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
)
280 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
282 DPRINT("Device type %u\n", InquiryData
->DeviceType
);
284 if (((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
285 (InquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
286 (InquiryData
->DeviceTypeQualifier
== 0) &&
287 (UnitInfo
->DeviceClaimed
== FALSE
))
289 DPRINT("Vendor: '%.24s'\n",
290 InquiryData
->VendorId
);
292 /* Create device objects for disk */
293 Status
= DiskClassCreateDeviceObject(DriverObject
,
297 ConfigInfo
->DiskCount
,
301 if (NT_SUCCESS(Status
))
303 ConfigInfo
->DiskCount
++;
308 if (UnitInfo
->NextInquiryDataOffset
== 0)
311 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ UnitInfo
->NextInquiryDataOffset
);
317 DPRINT("DiskClassFindDevices() done\n");
324 DiskClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension
,
325 IN ULONG DeviceNumber
)
327 WCHAR NameBuffer
[MAX_PATH
];
330 swprintf (NameBuffer
,
331 L
"\\Device\\MediaChangeEvent%lu",
333 RtlInitUnicodeString (&Name
,
336 DeviceExtension
->MediaChangeEvent
=
337 IoCreateSynchronizationEvent (&Name
,
338 &DeviceExtension
->MediaChangeEventHandle
);
340 KeClearEvent (DeviceExtension
->MediaChangeEvent
);
345 /**********************************************************************
347 * DiskClassCheckDevice
350 * This function checks the InquiryData for the correct device
351 * type and qualifier.
358 * Pointer to the inquiry data for the device in question.
361 * TRUE: A disk device was found.
366 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData
)
368 return((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
||
369 InquiryData
->DeviceType
== OPTICAL_DEVICE
) &&
370 InquiryData
->DeviceTypeQualifier
== 0);
374 /**********************************************************************
376 * DiskClassCheckReadWrite
379 * This function checks the given IRP for correct data.
386 * Pointer to the device.
392 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
397 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
400 PDEVICE_EXTENSION DeviceExtension
;
403 DPRINT("DiskClassCheckReadWrite() called\n");
405 DeviceExtension
= DeviceObject
->DeviceExtension
;
406 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
408 if (DiskData
->DriveNotReady
== TRUE
)
410 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
411 IoSetHardErrorOrVerifyDevice(Irp
,
413 return(STATUS_INVALID_PARAMETER
);
416 return(STATUS_SUCCESS
);
420 /**********************************************************************
422 * DiskClassCreateDeviceObject
425 * Create the raw device and any partition devices on this drive
432 * The system created driver object
442 * STATUS_SUCCESS: Device objects for disk and partitions were created.
447 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
448 IN PUNICODE_STRING RegistryPath
,
449 IN PDEVICE_OBJECT PortDeviceObject
,
452 IN PIO_SCSI_CAPABILITIES Capabilities
,
453 IN PSCSI_INQUIRY_DATA InquiryData
,
454 IN PCLASS_INIT_DATA InitializationData
)
456 OBJECT_ATTRIBUTES ObjectAttributes
;
457 UNICODE_STRING UnicodeDeviceDirName
;
458 WCHAR NameBuffer
[80];
459 CHAR NameBuffer2
[80];
460 PDEVICE_OBJECT DiskDeviceObject
;
461 PDEVICE_OBJECT PartitionDeviceObject
;
462 PDEVICE_EXTENSION DiskDeviceExtension
; /* defined in class2.h */
463 PDEVICE_EXTENSION PartitionDeviceExtension
; /* defined in class2.h */
464 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
466 PPARTITION_INFORMATION PartitionEntry
;
468 ULONG PartitionNumber
;
472 DPRINT("DiskClassCreateDeviceObject() called\n");
474 /* Create the harddisk device directory */
476 L
"\\Device\\Harddisk%lu",
478 RtlInitUnicodeString(&UnicodeDeviceDirName
,
480 InitializeObjectAttributes(&ObjectAttributes
,
481 &UnicodeDeviceDirName
,
485 Status
= ZwCreateDirectoryObject(&Handle
,
488 if (!NT_SUCCESS(Status
))
490 DbgPrint("Could not create device dir object\n");
494 /* Claim the disk device */
495 Status
= ScsiClassClaimDevice(PortDeviceObject
,
499 if (!NT_SUCCESS(Status
))
501 DbgPrint("Could not claim disk device\n");
503 ZwMakeTemporaryObject(Handle
);
509 /* Create disk device (Partition 0) */
511 "\\Device\\Harddisk%lu\\Partition0",
514 Status
= ScsiClassCreateDeviceObject(DriverObject
,
519 if (!NT_SUCCESS(Status
))
521 DPRINT("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status
);
523 /* Release (unclaim) the disk */
524 ScsiClassClaimDevice(PortDeviceObject
,
529 /* Delete the harddisk device directory */
530 ZwMakeTemporaryObject(Handle
);
536 DiskDeviceObject
->Flags
|= DO_DIRECT_IO
;
537 if (((PINQUIRYDATA
)InquiryData
->InquiryData
)->RemovableMedia
)
539 DiskDeviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
541 DiskDeviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
543 if (PortDeviceObject
->AlignmentRequirement
> DiskDeviceObject
->AlignmentRequirement
)
545 DiskDeviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
548 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
549 DiskDeviceExtension
->LockCount
= 0;
550 DiskDeviceExtension
->DeviceNumber
= DiskNumber
;
551 DiskDeviceExtension
->DeviceObject
= DiskDeviceObject
;
552 DiskDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
553 DiskDeviceExtension
->PhysicalDevice
= DiskDeviceObject
;
554 DiskDeviceExtension
->PortCapabilities
= Capabilities
;
555 DiskDeviceExtension
->StartingOffset
.QuadPart
= 0;
556 DiskDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
557 DiskDeviceExtension
->PathId
= InquiryData
->PathId
;
558 DiskDeviceExtension
->TargetId
= InquiryData
->TargetId
;
559 DiskDeviceExtension
->Lun
= InquiryData
->Lun
;
561 /* Get timeout value */
562 DiskDeviceExtension
->TimeOutValue
=
563 ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
564 if (DiskDeviceExtension
->TimeOutValue
== 0)
565 DiskDeviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
567 /* Initialize the lookaside list for SRBs */
568 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension
,
571 /* zero-out disk data */
572 DiskData
= (PDISK_DATA
)(DiskDeviceExtension
+ 1);
573 RtlZeroMemory(DiskData
,
576 /* Get disk geometry */
577 DiskDeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
578 sizeof(DISK_GEOMETRY
));
579 if (DiskDeviceExtension
->DiskGeometry
== NULL
)
581 DPRINT("Failed to allocate geometry buffer!\n");
583 ExDeleteNPagedLookasideList(&DiskDeviceExtension
->SrbLookasideListHead
);
585 IoDeleteDevice(DiskDeviceObject
);
587 /* Release (unclaim) the disk */
588 ScsiClassClaimDevice(PortDeviceObject
,
593 /* Delete the harddisk device directory */
594 ZwMakeTemporaryObject(Handle
);
597 return(STATUS_INSUFFICIENT_RESOURCES
);
600 /* Allocate sense data buffer */
601 DiskDeviceExtension
->SenseData
= ExAllocatePool(NonPagedPool
,
603 if (DiskDeviceExtension
->SenseData
== NULL
)
605 DPRINT("Failed to allocate sense data buffer!\n");
607 ExFreePool (DiskDeviceExtension
->DiskGeometry
);
609 ExDeleteNPagedLookasideList(&DiskDeviceExtension
->SrbLookasideListHead
);
611 IoDeleteDevice(DiskDeviceObject
);
613 /* Release (unclaim) the disk */
614 ScsiClassClaimDevice(PortDeviceObject
,
619 /* Delete the harddisk device directory */
620 ZwMakeTemporaryObject(Handle
);
623 return(STATUS_INSUFFICIENT_RESOURCES
);
626 /* Read the drive's capacity */
627 Status
= ScsiClassReadDriveCapacity(DiskDeviceObject
);
628 if (!NT_SUCCESS(Status
) &&
629 (DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) == 0)
631 DPRINT("Failed to retrieve drive capacity!\n");
632 return(STATUS_SUCCESS
);
636 /* Clear the verify flag for removable media drives. */
637 DiskDeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
640 DPRINT("SectorSize: %lu\n", DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
642 if ((DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
643 (DiskDeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
646 DiskClassCreateMediaChangeEvent(DiskDeviceExtension
,DiskNumber
);
647 if(DiskDeviceExtension
->MediaChangeEvent
!= NULL
)
649 DPRINT("Allocated media change event!\n");
654 /* Check disk for presence of a disk manager */
655 HalExamineMBR(DiskDeviceObject
,
656 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
659 if (MbrBuffer
!= NULL
)
661 /* Start disk at sector 63 if the Ontrack Disk Manager was found */
662 DPRINT("Found 'Ontrack Disk Manager'!\n");
664 DiskDeviceExtension
->DMSkew
= 63;
665 DiskDeviceExtension
->DMByteSkew
=
666 63 * DiskDeviceExtension
->DiskGeometry
->BytesPerSector
;
667 DiskDeviceExtension
->DMActive
= TRUE
;
669 ExFreePool(MbrBuffer
);
672 if ((DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
673 (DiskDeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
675 /* Allocate a partition list for a single entry. */
676 PartitionList
= ExAllocatePool(NonPagedPool
,
677 sizeof(DRIVE_LAYOUT_INFORMATION
));
678 if (PartitionList
!= NULL
)
680 RtlZeroMemory(PartitionList
,
681 sizeof(DRIVE_LAYOUT_INFORMATION
));
682 PartitionList
->PartitionCount
= 1;
684 DiskData
->DriveNotReady
= TRUE
;
685 Status
= STATUS_SUCCESS
;
690 /* Read partition table */
691 Status
= IoReadPartitionTable(DiskDeviceObject
,
692 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
696 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status
);
698 if ((!NT_SUCCESS(Status
) || PartitionList
->PartitionCount
== 0) &&
699 DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
701 if (!NT_SUCCESS(Status
))
703 /* Drive is not ready. */
704 DPRINT("Drive not ready\n");
705 DiskData
->DriveNotReady
= TRUE
;
709 ExFreePool(PartitionList
);
712 /* Allocate a partition list for a single entry. */
713 PartitionList
= ExAllocatePool(NonPagedPool
,
714 sizeof(DRIVE_LAYOUT_INFORMATION
));
715 if (PartitionList
!= NULL
)
717 RtlZeroMemory(PartitionList
,
718 sizeof(DRIVE_LAYOUT_INFORMATION
));
719 PartitionList
->PartitionCount
= 1;
721 Status
= STATUS_SUCCESS
;
726 if (NT_SUCCESS(Status
))
728 DPRINT("Read partition table!\n");
729 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
731 /* Set disk signature */
732 DiskData
->Signature
= PartitionList
->Signature
;
734 /* Calculate MBR checksum if disk got no signature */
735 if (DiskData
->Signature
== 0)
737 if (!ScsiDiskCalcMbrCheckSum(DiskDeviceExtension
,
738 &DiskData
->MbrCheckSum
))
740 DPRINT("MBR checksum calculation failed for disk %lu\n",
741 DiskDeviceExtension
->DeviceNumber
);
745 DPRINT("MBR checksum for disk %lu is %lx\n",
746 DiskDeviceExtension
->DeviceNumber
,
747 DiskData
->MbrCheckSum
);
752 DPRINT("Signature on disk %lu is %lx\n",
753 DiskDeviceExtension
->DeviceNumber
,
754 DiskData
->Signature
);
757 /* Update disk geometry if disk is visible to the BIOS */
758 ScsiDiskUpdateFixedDiskGeometry(DiskDeviceExtension
);
760 for (PartitionNumber
= 0; PartitionNumber
< PartitionList
->PartitionCount
; PartitionNumber
++)
762 PartitionEntry
= &PartitionList
->PartitionEntry
[PartitionNumber
];
764 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
766 PartitionEntry
->PartitionNumber
,
767 PartitionEntry
->BootIndicator
,
768 PartitionEntry
->PartitionType
,
769 PartitionEntry
->StartingOffset
.QuadPart
/ 512 /*DrvParms.BytesPerSector*/,
770 PartitionEntry
->PartitionLength
.QuadPart
/ 512 /* DrvParms.BytesPerSector*/);
772 /* Create partition device object */
774 "\\Device\\Harddisk%lu\\Partition%lu",
776 PartitionNumber
+ 1);
778 Status
= ScsiClassCreateDeviceObject(DriverObject
,
781 &PartitionDeviceObject
,
783 DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status
);
784 if (NT_SUCCESS(Status
))
786 PartitionDeviceObject
->Flags
= DiskDeviceObject
->Flags
;
787 PartitionDeviceObject
->Characteristics
= DiskDeviceObject
->Characteristics
;
788 PartitionDeviceObject
->StackSize
= DiskDeviceObject
->StackSize
;
789 PartitionDeviceObject
->AlignmentRequirement
= DiskDeviceObject
->AlignmentRequirement
;
791 PartitionDeviceExtension
= PartitionDeviceObject
->DeviceExtension
;
792 PartitionDeviceExtension
->SenseData
= DiskDeviceExtension
->SenseData
;
793 PartitionDeviceExtension
->LockCount
= 0;
794 PartitionDeviceExtension
->DeviceNumber
= DiskNumber
;
795 PartitionDeviceExtension
->DeviceObject
= PartitionDeviceObject
;
796 PartitionDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
797 PartitionDeviceExtension
->DiskGeometry
= DiskDeviceExtension
->DiskGeometry
;
798 PartitionDeviceExtension
->PhysicalDevice
= DiskDeviceExtension
->PhysicalDevice
;
799 PartitionDeviceExtension
->PortCapabilities
= Capabilities
;
800 PartitionDeviceExtension
->StartingOffset
.QuadPart
=
801 PartitionEntry
->StartingOffset
.QuadPart
;
802 PartitionDeviceExtension
->PartitionLength
.QuadPart
=
803 PartitionEntry
->PartitionLength
.QuadPart
;
804 PartitionDeviceExtension
->DMSkew
= DiskDeviceExtension
->DMSkew
;
805 PartitionDeviceExtension
->DMByteSkew
= DiskDeviceExtension
->DMByteSkew
;
806 PartitionDeviceExtension
->DMActive
= DiskDeviceExtension
->DMActive
;
807 PartitionDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
808 PartitionDeviceExtension
->PathId
= InquiryData
->PathId
;
809 PartitionDeviceExtension
->TargetId
= InquiryData
->TargetId
;
810 PartitionDeviceExtension
->Lun
= InquiryData
->Lun
;
811 PartitionDeviceExtension
->SectorShift
= DiskDeviceExtension
->SectorShift
;
812 PartitionDeviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
814 /* Initialize lookaside list for SRBs */
815 ScsiClassInitializeSrbLookasideList(PartitionDeviceExtension
,
818 /* Link current partition device extension to previous disk data */
819 DiskData
->NextPartition
= PartitionDeviceExtension
;
821 /* Initialize current disk data */
822 DiskData
= (PDISK_DATA
)(PartitionDeviceExtension
+ 1);
823 DiskData
->NextPartition
= NULL
;
824 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
825 DiskData
->PartitionNumber
= PartitionNumber
+ 1;
826 DiskData
->PartitionOrdinal
= PartitionNumber
+ 1;
827 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
828 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
829 DiskData
->DriveNotReady
= FALSE
;
833 DPRINT("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status
);
840 if (PartitionList
!= NULL
)
841 ExFreePool(PartitionList
);
843 DPRINT("DiskClassCreateDeviceObjects() done\n");
845 return(STATUS_SUCCESS
);
850 DiskBuildPartionTable(IN PDEVICE_OBJECT DiskDeviceObject
,
853 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
854 PDEVICE_EXTENSION DiskDeviceExtension
;
856 PPARTITION_INFORMATION PartitionEntry
;
857 ULONG PartitionNumber
;
860 DPRINT("DiskBuildPartitionTable() start\n");
862 DiskDeviceExtension
= (PDEVICE_EXTENSION
)DiskDeviceObject
->DeviceExtension
;
863 DiskData
= (PDISK_DATA
)(DiskDeviceExtension
+ 1);
865 if (DiskDeviceExtension
->StartingOffset
.QuadPart
)
867 DPRINT("Partition already installed\n");
868 return(STATUS_SUCCESS
);
871 /* Read partition table */
872 Status
= IoReadPartitionTable(DiskDeviceObject
,
873 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
878 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status
);
880 if (!NT_SUCCESS(Status
))
882 /* Drive is not ready. */
883 DPRINT("Drive not ready\n");
884 DiskData
->DriveNotReady
= TRUE
;
886 if (PartitionList
!= NULL
)
887 ExFreePool(PartitionList
);
891 if (NT_SUCCESS(Status
))
893 DPRINT("Read partition table!\n");
894 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
896 /* Set disk signature */
897 DiskData
->Signature
= PartitionList
->Signature
;
899 for (PartitionNumber
= 0; PartitionNumber
< PartitionList
->PartitionCount
; PartitionNumber
++)
901 PartitionEntry
= &PartitionList
->PartitionEntry
[PartitionNumber
];
903 DiskData
->NextPartition
= NULL
;
904 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
905 DiskData
->PartitionNumber
= PartitionNumber
+ 1;
906 DiskData
->PartitionOrdinal
= PartitionNumber
+ 1;
907 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
908 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
909 DiskData
->DriveNotReady
= FALSE
;
910 DiskDeviceExtension
->StartingOffset
= PartitionEntry
->StartingOffset
;
911 DiskDeviceExtension
->PartitionLength
= PartitionEntry
->PartitionLength
;
913 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
915 DiskData
->PartitionNumber
,
916 DiskData
->BootIndicator
,
917 DiskData
->PartitionType
,
918 DiskDeviceExtension
->StartingOffset
.QuadPart
/ 512 /*DrvParms.BytesPerSector*/,
919 DiskDeviceExtension
->PartitionLength
.QuadPart
/ 512 /* DrvParms.BytesPerSector*/);
922 if (PartitionList
!= NULL
)
923 ExFreePool(PartitionList
);
925 DPRINT("DiskBuildPartitionTable() done\n");
927 return(STATUS_SUCCESS
);
931 /**********************************************************************
933 * DiskClassDeviceControl
936 * Answer requests for device control calls
942 * Standard dispatch arguments
949 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
952 PDEVICE_EXTENSION DeviceExtension
;
953 PIO_STACK_LOCATION IrpStack
;
954 ULONG ControlCode
, InputLength
, OutputLength
;
959 DPRINT("DiskClassDeviceControl() called!\n");
961 Status
= STATUS_INVALID_DEVICE_REQUEST
;
963 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
964 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
965 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
966 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
967 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
968 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
972 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
973 DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
974 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
976 Status
= STATUS_INVALID_PARAMETER
;
980 if (DeviceExtension
->DiskGeometry
== NULL
)
982 DPRINT("No disk geometry available!\n");
983 DeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
984 sizeof(DISK_GEOMETRY
));
987 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
989 Status
= ScsiClassReadDriveCapacity(DeviceObject
);
990 DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status
);
991 if (!NT_SUCCESS(Status
))
993 /* Drive is not ready */
994 DiskData
->DriveNotReady
= FALSE
;
999 DiskData
->DriveNotReady
= FALSE
;
1002 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1003 DeviceExtension
->DiskGeometry
,
1004 sizeof(DISK_GEOMETRY
));
1006 Status
= STATUS_SUCCESS
;
1007 Information
= sizeof(DISK_GEOMETRY
);
1010 case IOCTL_DISK_GET_PARTITION_INFO
:
1011 DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
1013 if ((DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
1014 (DeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
1016 /* Allocate a partition list for a single entry. */
1017 Status
= DiskBuildPartionTable(DeviceObject
,Irp
);
1020 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1021 sizeof(PARTITION_INFORMATION
))
1023 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1025 else if (DiskData
->PartitionNumber
== 0)
1027 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1031 PPARTITION_INFORMATION PartitionInfo
;
1033 PartitionInfo
= (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
1035 PartitionInfo
->PartitionType
= DiskData
->PartitionType
;
1036 PartitionInfo
->StartingOffset
= DeviceExtension
->StartingOffset
;
1037 PartitionInfo
->PartitionLength
= DeviceExtension
->PartitionLength
;
1038 PartitionInfo
->HiddenSectors
= DiskData
->HiddenSectors
;
1039 PartitionInfo
->PartitionNumber
= DiskData
->PartitionNumber
;
1040 PartitionInfo
->BootIndicator
= DiskData
->BootIndicator
;
1041 PartitionInfo
->RewritePartition
= FALSE
;
1042 PartitionInfo
->RecognizedPartition
=
1043 IsRecognizedPartition(DiskData
->PartitionType
);
1045 Status
= STATUS_SUCCESS
;
1046 Information
= sizeof(PARTITION_INFORMATION
);
1050 case IOCTL_DISK_SET_PARTITION_INFO
:
1051 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1052 sizeof(SET_PARTITION_INFORMATION
))
1054 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1056 else if (DiskData
->PartitionNumber
== 0)
1058 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1062 PSET_PARTITION_INFORMATION PartitionInfo
;
1064 PartitionInfo
= (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
1066 Status
= IoSetPartitionInformation(DeviceExtension
->PhysicalDevice
,
1067 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1068 DiskData
->PartitionOrdinal
,
1069 PartitionInfo
->PartitionType
);
1070 if (NT_SUCCESS(Status
))
1072 DiskData
->PartitionType
= PartitionInfo
->PartitionType
;
1077 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1078 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1079 sizeof(DRIVE_LAYOUT_INFORMATION
))
1081 Status
= STATUS_BUFFER_TOO_SMALL
;
1085 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1087 Status
= IoReadPartitionTable(DeviceExtension
->PhysicalDevice
,
1088 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1091 if (NT_SUCCESS(Status
))
1095 BufferSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
1097 BufferSize
+= PartitionList
->PartitionCount
* sizeof(PARTITION_INFORMATION
);
1099 if (BufferSize
> IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
1101 Status
= STATUS_BUFFER_TOO_SMALL
;
1105 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1108 Status
= STATUS_SUCCESS
;
1109 Information
= BufferSize
;
1111 ExFreePool(PartitionList
);
1116 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
1117 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1118 sizeof(DRIVE_LAYOUT_INFORMATION
))
1120 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1122 else if (DeviceExtension
->PhysicalDevice
->DeviceExtension
!= DeviceExtension
)
1124 Status
= STATUS_INVALID_PARAMETER
;
1128 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1131 PartitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
1132 TableSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
1133 ((PartitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
));
1135 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< TableSize
)
1137 Status
= STATUS_BUFFER_TOO_SMALL
;
1141 /* Update partition device objects */
1142 DiskClassUpdatePartitionDeviceObjects (DeviceObject
,
1145 /* Write partition table */
1146 Status
= IoWritePartitionTable(DeviceExtension
->PhysicalDevice
,
1147 DeviceExtension
->DiskGeometry
->BytesPerSector
,
1148 DeviceExtension
->DiskGeometry
->SectorsPerTrack
,
1149 DeviceExtension
->DiskGeometry
->TracksPerCylinder
,
1155 case IOCTL_DISK_IS_WRITABLE
:
1157 PMODE_PARAMETER_HEADER ModeData
;
1160 ModeData
= ExAllocatePool (NonPagedPool
,
1162 if (ModeData
== NULL
)
1164 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1167 RtlZeroMemory (ModeData
,
1170 Length
= ScsiClassModeSense (DeviceObject
,
1173 MODE_SENSE_RETURN_ALL
);
1174 if (Length
< sizeof(MODE_PARAMETER_HEADER
))
1177 Status
= STATUS_IO_DEVICE_ERROR
;
1178 ExFreePool (ModeData
);
1182 if (ModeData
->DeviceSpecificParameter
& MODE_DSP_WRITE_PROTECT
)
1184 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1188 Status
= STATUS_SUCCESS
;
1190 ExFreePool (ModeData
);
1195 case IOCTL_DISK_CHECK_VERIFY
:
1196 DPRINT("IOCTL_DISK_CHECK_VERIFY\n");
1197 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
)
1199 DPRINT("Do Verify Set\n");
1200 Status
= STATUS_VERIFY_REQUIRED
;
1205 DPRINT("Do Verify Clear\n");
1206 Status
= STATUS_SUCCESS
;
1211 case IOCTL_DISK_VERIFY
:
1212 case IOCTL_DISK_FORMAT_TRACKS
:
1213 case IOCTL_DISK_PERFORMANCE
:
1214 case IOCTL_DISK_LOGGING
:
1215 case IOCTL_DISK_FORMAT_TRACKS_EX
:
1216 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
1217 case IOCTL_DISK_HISTOGRAM_DATA
:
1218 case IOCTL_DISK_HISTOGRAM_RESET
:
1219 case IOCTL_DISK_REQUEST_STRUCTURE
:
1220 case IOCTL_DISK_REQUEST_DATA
:
1221 /* If we get here, something went wrong. Inform the requestor */
1222 DPRINT("Unhandled control code: %lx\n", ControlCode
);
1223 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1228 /* Call the common device control function */
1229 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
1232 /* Verify the device if the user caused the error */
1233 if (!NT_SUCCESS(Status
) && IoIsErrorUserInduced(Status
))
1235 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1238 Irp
->IoStatus
.Status
= Status
;
1239 Irp
->IoStatus
.Information
= Information
;
1240 IoCompleteRequest(Irp
,
1247 /**********************************************************************
1249 * DiskClassShutdownFlush
1252 * Answer requests for shutdown and flush calls.
1259 * Pointer to the device.
1262 * Pointer to the IRP
1269 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
1272 PDEVICE_EXTENSION DeviceExtension
;
1273 PIO_STACK_LOCATION IrpStack
;
1274 PSCSI_REQUEST_BLOCK Srb
;
1276 DPRINT("DiskClassShutdownFlush() called!\n");
1278 DeviceExtension
= DeviceObject
->DeviceExtension
;
1281 Srb
= ExAllocatePool(NonPagedPool
,
1282 sizeof(SCSI_REQUEST_BLOCK
));
1285 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1286 Irp
->IoStatus
.Information
= 0;
1287 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1289 return(STATUS_INSUFFICIENT_RESOURCES
);
1292 /* Initialize SRB */
1293 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
1294 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
1296 /* Set device IDs */
1297 Srb
->PathId
= DeviceExtension
->PathId
;
1298 Srb
->TargetId
= DeviceExtension
->TargetId
;
1299 Srb
->Lun
= DeviceExtension
->Lun
;
1302 Srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
* 4;
1304 /* Flush write cache */
1305 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1306 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1307 Srb
->CdbLength
= 10;
1308 Srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
1309 ScsiClassSendSrbSynchronous(DeviceObject
,
1315 /* Get current stack location */
1316 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1318 /* FIXME: Unlock removable media upon shutdown */
1322 IrpStack
->Parameters
.Others
.Argument4
= (PVOID
)0;
1324 /* Send shutdown or flush request to the port driver */
1326 if (IrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
)
1327 Srb
->Function
= SRB_FUNCTION_SHUTDOWN
;
1329 Srb
->Function
= SRB_FUNCTION_FLUSH
;
1331 /* Init completion routine */
1332 IoSetCompletionRoutine(Irp
,
1333 ScsiClassIoComplete
,
1339 /* Prepare next stack location for a call to the port driver */
1340 IrpStack
= IoGetNextIrpStackLocation(Irp
);
1341 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1342 IrpStack
->Parameters
.Scsi
.Srb
= Srb
;
1343 Srb
->OriginalRequest
= Irp
;
1345 /* Call port driver */
1346 return(IoCallDriver(DeviceExtension
->PortDeviceObject
, Irp
));
1350 /**********************************************************************
1352 * DiskClassUpdatePartitionDeviceObjects
1355 * Deletes, modifies or creates partition device objects.
1362 * Pointer to the device.
1365 * Pointer to the IRP
1372 DiskClassUpdatePartitionDeviceObjects(IN PDEVICE_OBJECT DiskDeviceObject
,
1375 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1376 PPARTITION_INFORMATION PartitionEntry
;
1377 PDEVICE_EXTENSION DeviceExtension
;
1378 PDEVICE_EXTENSION DiskDeviceExtension
;
1379 PDISK_DATA DiskData
;
1380 ULONG PartitionCount
;
1381 ULONG PartitionOrdinal
;
1382 ULONG PartitionNumber
;
1383 ULONG LastPartitionNumber
;
1386 WCHAR NameBuffer
[MAX_PATH
];
1387 UNICODE_STRING DeviceName
;
1388 PDEVICE_OBJECT DeviceObject
;
1391 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() called\n");
1393 /* Get partition list */
1394 PartitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
1396 /* Round partition count up by 4 */
1397 PartitionCount
= ((PartitionList
->PartitionCount
+ 3) / 4) * 4;
1399 /* Remove the partition numbers from the partition list */
1400 for (i
= 0; i
< PartitionCount
; i
++)
1402 PartitionList
->PartitionEntry
[i
].PartitionNumber
= 0;
1405 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
1407 /* Traverse on-disk partition list */
1408 LastPartitionNumber
= 0;
1409 DeviceExtension
= DiskDeviceExtension
;
1410 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1413 DeviceExtension
= DiskData
->NextPartition
;
1414 if (DeviceExtension
== NULL
)
1418 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1420 /* Update last partition number */
1421 if (DiskData
->PartitionNumber
> LastPartitionNumber
)
1422 LastPartitionNumber
= DiskData
->PartitionNumber
;
1424 /* Ignore unused on-disk partitions */
1425 if (DeviceExtension
->PartitionLength
.QuadPart
== 0ULL)
1429 PartitionOrdinal
= 0;
1430 for (i
= 0; i
< PartitionCount
; i
++)
1432 /* Get current partition entry */
1433 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
1435 /* Ignore empty (aka unused) or extended partitions */
1436 if (PartitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
1437 IsContainerPartition (PartitionEntry
->PartitionType
))
1442 /* Check for matching partition start offset and length */
1443 if ((PartitionEntry
->StartingOffset
.QuadPart
!=
1444 DeviceExtension
->StartingOffset
.QuadPart
) ||
1445 (PartitionEntry
->PartitionLength
.QuadPart
!=
1446 DeviceExtension
->PartitionLength
.QuadPart
))
1449 DPRINT("Found matching partition entry for partition %lu\n",
1450 DiskData
->PartitionNumber
);
1452 /* Found matching partition */
1455 /* Update partition number in partition list */
1456 PartitionEntry
->PartitionNumber
= DiskData
->PartitionNumber
;
1462 /* Get disk data for current partition */
1463 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1465 /* Update partition type if partiton will be rewritten */
1466 if (PartitionEntry
->RewritePartition
== TRUE
)
1467 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
1469 /* Assign new partiton ordinal */
1470 DiskData
->PartitionOrdinal
= PartitionOrdinal
;
1472 DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1473 DiskData
->PartitionOrdinal
,
1474 DiskData
->PartitionNumber
);
1478 /* Delete this partition */
1479 DeviceExtension
->PartitionLength
.QuadPart
= 0ULL;
1481 DPRINT("Deleting partition %lu\n",
1482 DiskData
->PartitionNumber
);
1486 /* Traverse partiton list and create new partiton devices */
1487 PartitionOrdinal
= 0;
1488 for (i
= 0; i
< PartitionCount
; i
++)
1490 /* Get current partition entry */
1491 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
1493 /* Ignore empty (aka unused) or extended partitions */
1494 if (PartitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
1495 IsContainerPartition (PartitionEntry
->PartitionType
))
1500 /* Ignore unchanged partition entries */
1501 if (PartitionEntry
->RewritePartition
== FALSE
)
1504 /* Check for an unused device object */
1505 PartitionNumber
= 0;
1506 DeviceExtension
= DiskDeviceExtension
;
1507 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1510 DeviceExtension
= DiskData
->NextPartition
;
1511 if (DeviceExtension
== NULL
)
1514 /* Get partition disk data */
1515 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1517 /* Found a free (unused) partition (device object) */
1518 if (DeviceExtension
->PartitionLength
.QuadPart
== 0ULL)
1520 PartitionNumber
= DiskData
->PartitionNumber
;
1525 if (PartitionNumber
== 0)
1527 /* Create a new partition device object */
1528 DPRINT("Create new partition device object\n");
1530 /* Get new partiton number */
1531 LastPartitionNumber
++;
1532 PartitionNumber
= LastPartitionNumber
;
1534 /* Create partition device object */
1535 swprintf(NameBuffer
,
1536 L
"\\Device\\Harddisk%lu\\Partition%lu",
1537 DiskDeviceExtension
->DeviceNumber
,
1539 RtlInitUnicodeString(&DeviceName
,
1542 Status
= IoCreateDevice(DiskDeviceObject
->DriverObject
,
1543 sizeof(DEVICE_EXTENSION
) + sizeof(DISK_DATA
),
1549 if (!NT_SUCCESS(Status
))
1551 DPRINT("IoCreateDevice() failed (Status %lx)\n", Status
);
1555 DeviceObject
->Flags
|= DO_DIRECT_IO
;
1556 DeviceObject
->StackSize
= DiskDeviceObject
->StackSize
;
1557 DeviceObject
->Characteristics
= DiskDeviceObject
->Characteristics
;
1558 DeviceObject
->AlignmentRequirement
= DiskDeviceObject
->AlignmentRequirement
;
1560 /* Initialize device extension */
1561 DeviceExtension
= DeviceObject
->DeviceExtension
;
1562 RtlCopyMemory(DeviceExtension
,
1563 DiskDeviceObject
->DeviceExtension
,
1564 sizeof(DEVICE_EXTENSION
));
1565 DeviceExtension
->DeviceObject
= DeviceObject
;
1567 /* Initialize lookaside list for SRBs */
1568 ScsiClassInitializeSrbLookasideList(DeviceExtension
,
1571 /* Link current partition device extension to previous disk data */
1572 DiskData
->NextPartition
= DeviceExtension
;
1573 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1574 DiskData
->NextPartition
= NULL
;
1578 /* Reuse an existing partition device object */
1579 DPRINT("Reuse an exisiting partition device object\n");
1580 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1583 /* Update partition data and device extension */
1584 DiskData
->PartitionNumber
= PartitionNumber
;
1585 DiskData
->PartitionOrdinal
= PartitionOrdinal
;
1586 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
1587 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
1588 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
1589 DeviceExtension
->StartingOffset
= PartitionEntry
->StartingOffset
;
1590 DeviceExtension
->PartitionLength
= PartitionEntry
->PartitionLength
;
1592 /* Update partition number in the partition list */
1593 PartitionEntry
->PartitionNumber
= PartitionNumber
;
1595 DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1596 DiskData
->PartitionOrdinal
,
1597 DiskData
->PartitionNumber
);
1600 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() done\n");
1604 /**********************************************************************
1606 * ScsiDiskSearchForDisk
1609 * Searches the hardware tree for the given disk.
1616 * Disk device extension.
1619 * Handle to the hardware bus key.
1621 * DetectedDiskNumber
1622 * Returned disk number.
1625 * TRUE: Disk was found.
1626 * FALSE: Search failed.
1630 ScsiDiskSearchForDisk(IN PDEVICE_EXTENSION DeviceExtension
,
1632 OUT PULONG DetectedDiskNumber
)
1634 PKEY_VALUE_FULL_INFORMATION ValueData
;
1635 OBJECT_ATTRIBUTES ObjectAttributes
;
1636 PDISK_DATA DiskData
;
1637 UNICODE_STRING IdentifierString
;
1638 UNICODE_STRING NameString
;
1639 HANDLE BusInstanceKey
;
1640 HANDLE ControllerKey
;
1642 HANDLE DiskInstanceKey
;
1644 ULONG ControllerNumber
;
1651 DPRINT("ScsiDiskSearchForDiskData() called\n");
1655 /* Enumerate buses */
1656 for (BusNumber
= 0; ; BusNumber
++)
1658 /* Open bus instance subkey */
1663 RtlInitUnicodeString(&NameString
,
1666 InitializeObjectAttributes(&ObjectAttributes
,
1668 OBJ_CASE_INSENSITIVE
,
1672 Status
= ZwOpenKey(&BusInstanceKey
,
1675 if (!NT_SUCCESS(Status
))
1680 /* Open 'DiskController' subkey */
1681 RtlInitUnicodeString(&NameString
,
1684 InitializeObjectAttributes(&ObjectAttributes
,
1686 OBJ_CASE_INSENSITIVE
,
1690 Status
= ZwOpenKey(&ControllerKey
,
1693 if (!NT_SUCCESS(Status
))
1695 ZwClose(BusInstanceKey
);
1699 /* Enumerate controllers */
1700 for (ControllerNumber
= 0; ; ControllerNumber
++)
1702 /* Open 'DiskPeripheral' subkey */
1704 L
"%lu\\DiskPeripheral",
1707 RtlInitUnicodeString(&NameString
,
1710 InitializeObjectAttributes(&ObjectAttributes
,
1712 OBJ_CASE_INSENSITIVE
,
1716 Status
= ZwOpenKey(&DiskKey
,
1719 if (!NT_SUCCESS(Status
))
1724 /* Enumerate disks */
1725 for (DiskNumber
= 0; ; DiskNumber
++)
1727 /* Open disk instance subkey */
1732 RtlInitUnicodeString(&NameString
,
1735 InitializeObjectAttributes(&ObjectAttributes
,
1737 OBJ_CASE_INSENSITIVE
,
1741 Status
= ZwOpenKey(&DiskInstanceKey
,
1744 if (!NT_SUCCESS(Status
))
1749 DPRINT("Found disk key: bus %lu controller %lu disk %lu\n",
1754 /* Allocate data buffer */
1755 ValueData
= ExAllocatePool(PagedPool
,
1757 if (ValueData
== NULL
)
1759 ZwClose(DiskInstanceKey
);
1763 /* Get the 'Identifier' value */
1764 RtlInitUnicodeString(&NameString
,
1766 Status
= ZwQueryValueKey(DiskInstanceKey
,
1768 KeyValueFullInformation
,
1773 ZwClose(DiskInstanceKey
);
1774 if (!NT_SUCCESS(Status
))
1776 ExFreePool(ValueData
);
1780 IdentifierString
.Buffer
=
1781 (PWSTR
)((PUCHAR
)ValueData
+ ValueData
->DataOffset
);
1782 IdentifierString
.Length
= (USHORT
)ValueData
->DataLength
- 2;
1783 IdentifierString
.MaximumLength
= (USHORT
)ValueData
->DataLength
;
1785 DPRINT("DiskIdentifier: %wZ\n",
1788 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1789 if (DiskData
->Signature
!= 0)
1791 /* Comapre disk signature */
1794 DiskData
->Signature
);
1795 if (!_wcsnicmp(Buffer
, &IdentifierString
.Buffer
[9], 8))
1797 DPRINT("Found disk %lu\n", DiskNumber
);
1799 *DetectedDiskNumber
= DiskNumber
;
1804 /* Comapre mbr checksum */
1807 DiskData
->MbrCheckSum
);
1808 if (!_wcsnicmp(Buffer
, &IdentifierString
.Buffer
[0], 8))
1810 DPRINT("Found disk %lu\n", DiskNumber
);
1812 *DetectedDiskNumber
= DiskNumber
;
1816 ExFreePool(ValueData
);
1818 ZwClose(DiskInstanceKey
);
1820 if (DiskFound
== TRUE
)
1827 ZwClose(ControllerKey
);
1828 ZwClose(BusInstanceKey
);
1831 DPRINT("ScsiDiskSearchForDisk() done\n");
1837 /**********************************************************************
1839 * DiskClassUpdateFixedDiskGeometry
1842 * Updated the geometry of a disk if the disk can be accessed
1850 * Disk device extension.
1857 ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension
)
1859 PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
1860 PCM_INT13_DRIVE_PARAMETER DriveParameters
;
1861 PKEY_VALUE_FULL_INFORMATION ValueBuffer
;
1862 OBJECT_ATTRIBUTES ObjectAttributes
;
1863 UNICODE_STRING KeyName
;
1864 UNICODE_STRING ValueName
;
1874 ULONG SectorsPerTrack
;
1875 ULONG TracksPerCylinder
;
1878 DPRINT("ScsiDiskUpdateFixedDiskGeometry() called\n");
1880 RtlInitUnicodeString(&KeyName
,
1881 L
"\\Registry\\Machine\\Hardware\\Description\\System");
1883 InitializeObjectAttributes(&ObjectAttributes
,
1885 OBJ_CASE_INSENSITIVE
,
1889 /* Open the adapter key */
1890 Status
= ZwOpenKey(&SystemKey
,
1893 if (!NT_SUCCESS(Status
))
1895 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status
);
1899 /* Allocate value buffer */
1900 ValueBuffer
= ExAllocatePool(PagedPool
,
1902 if (ValueBuffer
== NULL
)
1904 DPRINT("Failed to allocate value buffer\n");
1909 RtlInitUnicodeString(&ValueName
,
1910 L
"Configuration Data");
1912 /* Query 'Configuration Data' value */
1913 Status
= ZwQueryValueKey(SystemKey
,
1915 KeyValueFullInformation
,
1919 if (!NT_SUCCESS(Status
))
1921 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status
);
1922 ExFreePool(ValueBuffer
);
1927 /* Open the 'MultifunctionAdapter' subkey */
1928 RtlInitUnicodeString(&KeyName
,
1929 L
"MultifunctionAdapter");
1931 InitializeObjectAttributes(&ObjectAttributes
,
1933 OBJ_CASE_INSENSITIVE
,
1937 Status
= ZwOpenKey(&BusKey
,
1941 if (!NT_SUCCESS(Status
))
1943 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status
);
1944 ExFreePool(ValueBuffer
);
1948 if (!ScsiDiskSearchForDisk(DeviceExtension
, BusKey
, &DiskNumber
))
1950 DPRINT("ScsiDiskSearchForDisk() failed\n");
1952 ExFreePool(ValueBuffer
);
1958 ResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)
1959 ((PUCHAR
)ValueBuffer
+ ValueBuffer
->DataOffset
);
1961 DriveParameters
= (PCM_INT13_DRIVE_PARAMETER
)
1962 ((PUCHAR
)ResourceDescriptor
+ sizeof(CM_FULL_RESOURCE_DESCRIPTOR
));
1965 for (i
= 0; i
< DriveParameters
[0].NumberDrives
; i
++)
1967 DPRINT("Drive %lu: %lu Cylinders %hu Heads %hu Sectors\n",
1969 DriveParameters
[i
].MaxCylinders
,
1970 DriveParameters
[i
].MaxHeads
,
1971 DriveParameters
[i
].SectorsPerTrack
);
1975 Cylinders
= DriveParameters
[DiskNumber
].MaxCylinders
+ 1;
1976 TracksPerCylinder
= DriveParameters
[DiskNumber
].MaxHeads
+1;
1977 SectorsPerTrack
= DriveParameters
[DiskNumber
].SectorsPerTrack
;
1979 DPRINT("BIOS geometry: %lu Cylinders %hu Heads %hu Sectors\n",
1985 (DeviceExtension
->PartitionLength
.QuadPart
>> DeviceExtension
->SectorShift
);
1987 DPRINT("Physical sectors: %lu\n",
1990 Length
= TracksPerCylinder
* SectorsPerTrack
;
1993 DPRINT("Invalid track length 0\n");
1994 ExFreePool(ValueBuffer
);
1998 Cylinders
= Sectors
/ Length
;
2000 DPRINT("Logical geometry: %lu Cylinders %hu Heads %hu Sectors\n",
2005 /* Update the disk geometry */
2006 DeviceExtension
->DiskGeometry
->SectorsPerTrack
= SectorsPerTrack
;
2007 DeviceExtension
->DiskGeometry
->TracksPerCylinder
= TracksPerCylinder
;
2008 DeviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (ULONGLONG
)Cylinders
;
2010 if (DeviceExtension
->DMActive
)
2012 DPRINT("FIXME: Update geometry with respect to the installed disk manager!\n");
2014 /* FIXME: Update geometry for disk managers */
2018 ExFreePool(ValueBuffer
);
2020 DPRINT("ScsiDiskUpdateFixedDiskGeometry() done\n");
2024 /**********************************************************************
2026 * ScsiDiskCalcMbrCheckSum
2029 * Calculates the Checksum from drives MBR.
2036 * Disk device extension.
2039 * Pointer to the caller supplied cecksum variable.
2042 * TRUE: Checksum was calculated.
2043 * FALSE: Calculation failed.
2047 ScsiDiskCalcMbrCheckSum(IN PDEVICE_EXTENSION DeviceExtension
,
2048 OUT PULONG Checksum
)
2050 IO_STATUS_BLOCK IoStatusBlock
;
2051 LARGE_INTEGER SectorOffset
;
2060 KeInitializeEvent(&Event
,
2064 /* Get the disk sector size */
2065 SectorSize
= DeviceExtension
->DiskGeometry
->BytesPerSector
;
2066 if (SectorSize
< 512)
2071 /* Allocate MBR buffer */
2072 MbrBuffer
= ExAllocatePool(NonPagedPool
,
2074 if (MbrBuffer
== NULL
)
2079 /* Allocate an IRP */
2080 SectorOffset
.QuadPart
= 0ULL;
2081 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
2082 DeviceExtension
->DeviceObject
,
2090 ExFreePool(MbrBuffer
);
2094 /* Call the miniport driver */
2095 Status
= IoCallDriver(DeviceExtension
->DeviceObject
,
2097 if (Status
== STATUS_PENDING
)
2099 KeWaitForSingleObject(&Event
,
2104 Status
= IoStatusBlock
.Status
;
2107 if (!NT_SUCCESS(Status
))
2109 ExFreePool(MbrBuffer
);
2113 /* Calculate MBR checksum */
2115 for (i
= 0; i
< 128; i
++)
2117 Sum
+= MbrBuffer
[i
];
2119 *Checksum
= ~Sum
+ 1;
2121 ExFreePool(MbrBuffer
);