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.26 2003/04/27 18:10:38 ekohl 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"
41 typedef struct _DISK_DATA
43 PDEVICE_EXTENSION NextPartition
;
45 ULONG PartitionNumber
;
46 ULONG PartitionOrdinal
;
48 BOOLEAN BootIndicator
;
49 BOOLEAN DriveNotReady
;
50 } DISK_DATA
, *PDISK_DATA
;
54 DiskClassFindDevices(PDRIVER_OBJECT DriverObject
,
55 PUNICODE_STRING RegistryPath
,
56 PCLASS_INIT_DATA InitializationData
,
57 PDEVICE_OBJECT PortDeviceObject
,
61 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData
);
64 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
69 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
70 IN PUNICODE_STRING RegistryPath
, /* what's this used for? */
71 IN PDEVICE_OBJECT PortDeviceObject
,
74 IN PIO_SCSI_CAPABILITIES Capabilities
,
75 IN PSCSI_INQUIRY_DATA InquiryData
,
76 IN PCLASS_INIT_DATA InitializationData
);
79 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
83 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
87 DiskClassUpdatePartitionDeviceObjects (IN PDEVICE_OBJECT DeviceObject
,
91 ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension
);
94 /* FUNCTIONS ****************************************************************/
96 /**********************************************************************
101 * This function initializes the driver, locates and claims
102 * hardware resources, and creates various NT objects needed
103 * to process I/O requests.
110 * System allocated Driver Object for this driver
113 * Name of registry driver service key
120 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
121 IN PUNICODE_STRING RegistryPath
)
123 CLASS_INIT_DATA InitData
;
125 DPRINT("Disk Class Driver %s\n",
127 DPRINT("RegistryPath '%wZ'\n",
130 RtlZeroMemory(&InitData
,
131 sizeof(CLASS_INIT_DATA
));
133 InitData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
134 InitData
.DeviceExtensionSize
= sizeof(DEVICE_EXTENSION
) + sizeof(DISK_DATA
);
135 InitData
.DeviceType
= FILE_DEVICE_DISK
;
136 InitData
.DeviceCharacteristics
= 0;
138 InitData
.ClassError
= NULL
; // DiskClassProcessError;
139 InitData
.ClassReadWriteVerification
= DiskClassCheckReadWrite
;
140 InitData
.ClassFindDeviceCallBack
= DiskClassCheckDevice
;
141 InitData
.ClassFindDevices
= DiskClassFindDevices
;
142 InitData
.ClassDeviceControl
= DiskClassDeviceControl
;
143 InitData
.ClassShutdownFlush
= DiskClassShutdownFlush
;
144 InitData
.ClassCreateClose
= NULL
;
145 InitData
.ClassStartIo
= NULL
;
147 return(ScsiClassInitialize(DriverObject
,
153 /**********************************************************************
155 * DiskClassFindDevices
158 * This function searches for device that are attached to the
166 * System allocated Driver Object for this driver
169 * Name of registry driver service key
172 * Pointer to the main initialization data
175 * Pointer to the port Device Object
181 * TRUE: At least one disk drive was found
182 * FALSE: No disk drive found
186 DiskClassFindDevices(PDRIVER_OBJECT DriverObject
,
187 PUNICODE_STRING RegistryPath
,
188 PCLASS_INIT_DATA InitializationData
,
189 PDEVICE_OBJECT PortDeviceObject
,
192 PCONFIGURATION_INFORMATION ConfigInfo
;
193 PIO_SCSI_CAPABILITIES PortCapabilities
;
194 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
195 PSCSI_INQUIRY_DATA UnitInfo
;
196 PINQUIRYDATA InquiryData
;
203 DPRINT("DiskClassFindDevices() called.\n");
205 /* Get port capabilities */
206 Status
= ScsiClassGetCapabilities(PortDeviceObject
,
208 if (!NT_SUCCESS(Status
))
210 DPRINT("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status
);
214 DPRINT("PortCapabilities: %p\n", PortCapabilities
);
215 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities
->MaximumTransferLength
);
216 DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities
->MaximumPhysicalPages
);
218 /* Get inquiry data */
219 Status
= ScsiClassGetInquiryData(PortDeviceObject
,
220 (PSCSI_ADAPTER_BUS_INFO
*)&Buffer
);
221 if (!NT_SUCCESS(Status
))
223 DPRINT("ScsiClassGetInquiryData() failed! (Status %x)\n", Status
);
227 /* Check whether there are unclaimed devices */
228 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
229 DeviceCount
= ScsiClassFindUnclaimedDevices(InitializationData
,
231 if (DeviceCount
== 0)
233 DPRINT("No unclaimed devices!\n");
237 DPRINT("Found %lu unclaimed devices!\n", DeviceCount
);
239 ConfigInfo
= IoGetConfigurationInformation();
241 /* Search each bus of this adapter */
242 for (Bus
= 0; Bus
< (ULONG
)AdapterBusInfo
->NumberOfBuses
; Bus
++)
244 DPRINT("Searching bus %lu\n", Bus
);
246 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
);
248 while (AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
)
250 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
252 if (((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
253 (InquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
254 (InquiryData
->DeviceTypeQualifier
== 0) &&
255 (UnitInfo
->DeviceClaimed
== FALSE
))
257 DPRINT("Vendor: '%.24s'\n",
258 InquiryData
->VendorId
);
260 /* Create device objects for disk */
261 Status
= DiskClassCreateDeviceObject(DriverObject
,
265 ConfigInfo
->DiskCount
,
269 if (NT_SUCCESS(Status
))
271 ConfigInfo
->DiskCount
++;
276 if (UnitInfo
->NextInquiryDataOffset
== 0)
279 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ UnitInfo
->NextInquiryDataOffset
);
285 DPRINT("DiskClassFindDevices() done\n");
291 /**********************************************************************
293 * DiskClassCheckDevice
296 * This function checks the InquiryData for the correct device
297 * type and qualifier.
304 * Pointer to the inquiry data for the device in question.
307 * TRUE: A disk device was found.
312 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData
)
314 return((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
||
315 InquiryData
->DeviceType
== OPTICAL_DEVICE
) &&
316 InquiryData
->DeviceTypeQualifier
== 0);
320 /**********************************************************************
322 * DiskClassCheckReadWrite
325 * This function checks the given IRP for correct data.
332 * Pointer to the device.
338 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
343 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
346 PDEVICE_EXTENSION DeviceExtension
;
349 DPRINT("DiskClassCheckReadWrite() called\n");
351 DeviceExtension
= DeviceObject
->DeviceExtension
;
352 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
354 if (DiskData
->DriveNotReady
== TRUE
)
356 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
357 IoSetHardErrorOrVerifyDevice(Irp
,
359 return(STATUS_INVALID_PARAMETER
);
362 return(STATUS_SUCCESS
);
366 /**********************************************************************
368 * DiskClassCreateDeviceObject
371 * Create the raw device and any partition devices on this drive
378 * The system created driver object
388 * STATUS_SUCCESS: Device objects for disk and partitions were created.
393 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
394 IN PUNICODE_STRING RegistryPath
, /* what's this used for? */
395 IN PDEVICE_OBJECT PortDeviceObject
,
398 IN PIO_SCSI_CAPABILITIES Capabilities
,
399 IN PSCSI_INQUIRY_DATA InquiryData
,
400 IN PCLASS_INIT_DATA InitializationData
)
402 OBJECT_ATTRIBUTES ObjectAttributes
;
403 UNICODE_STRING UnicodeDeviceDirName
;
404 WCHAR NameBuffer
[80];
405 CHAR NameBuffer2
[80];
406 PDEVICE_OBJECT DiskDeviceObject
;
407 PDEVICE_OBJECT PartitionDeviceObject
;
408 PDEVICE_EXTENSION DiskDeviceExtension
; /* defined in class2.h */
409 PDEVICE_EXTENSION PartitionDeviceExtension
; /* defined in class2.h */
410 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
412 PPARTITION_INFORMATION PartitionEntry
;
414 ULONG PartitionNumber
;
418 DPRINT("DiskClassCreateDeviceObject() called\n");
420 /* Create the harddisk device directory */
422 L
"\\Device\\Harddisk%lu",
424 RtlInitUnicodeString(&UnicodeDeviceDirName
,
426 InitializeObjectAttributes(&ObjectAttributes
,
427 &UnicodeDeviceDirName
,
431 Status
= ZwCreateDirectoryObject(&Handle
,
434 if (!NT_SUCCESS(Status
))
436 DbgPrint("Could not create device dir object\n");
440 /* Claim the disk device */
441 Status
= ScsiClassClaimDevice(PortDeviceObject
,
445 if (!NT_SUCCESS(Status
))
447 DbgPrint("Could not claim disk device\n");
449 ZwMakeTemporaryObject(Handle
);
455 /* Create disk device (Partition 0) */
457 "\\Device\\Harddisk%lu\\Partition0",
460 Status
= ScsiClassCreateDeviceObject(DriverObject
,
465 if (!NT_SUCCESS(Status
))
467 DPRINT("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status
);
469 /* Release (unclaim) the disk */
470 ScsiClassClaimDevice(PortDeviceObject
,
475 /* Delete the harddisk device directory */
476 ZwMakeTemporaryObject(Handle
);
482 DiskDeviceObject
->Flags
|= DO_DIRECT_IO
;
483 if (((PINQUIRYDATA
)InquiryData
->InquiryData
)->RemovableMedia
)
485 DiskDeviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
487 DiskDeviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
489 if (PortDeviceObject
->AlignmentRequirement
> DiskDeviceObject
->AlignmentRequirement
)
491 DiskDeviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
494 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
495 DiskDeviceExtension
->LockCount
= 0;
496 DiskDeviceExtension
->DeviceNumber
= DiskNumber
;
497 DiskDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
498 DiskDeviceExtension
->PhysicalDevice
= DiskDeviceObject
;
499 DiskDeviceExtension
->PortCapabilities
= Capabilities
;
500 DiskDeviceExtension
->StartingOffset
.QuadPart
= 0;
501 DiskDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
502 DiskDeviceExtension
->PathId
= InquiryData
->PathId
;
503 DiskDeviceExtension
->TargetId
= InquiryData
->TargetId
;
504 DiskDeviceExtension
->Lun
= InquiryData
->Lun
;
506 /* Initialize the lookaside list for SRBs */
507 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension
,
510 /* zero-out disk data */
511 DiskData
= (PDISK_DATA
)(DiskDeviceExtension
+ 1);
512 RtlZeroMemory(DiskData
,
515 /* Get disk geometry */
516 DiskDeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
517 sizeof(DISK_GEOMETRY
));
518 if (DiskDeviceExtension
->DiskGeometry
== NULL
)
520 DPRINT("Failed to allocate geometry buffer!\n");
522 ExDeleteNPagedLookasideList(&DiskDeviceExtension
->SrbLookasideListHead
);
524 IoDeleteDevice(DiskDeviceObject
);
526 /* Release (unclaim) the disk */
527 ScsiClassClaimDevice(PortDeviceObject
,
532 /* Delete the harddisk device directory */
533 ZwMakeTemporaryObject(Handle
);
536 return(STATUS_INSUFFICIENT_RESOURCES
);
539 /* Read the drive's capacity */
540 Status
= ScsiClassReadDriveCapacity(DiskDeviceObject
);
541 if (!NT_SUCCESS(Status
) &&
542 (DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) == 0)
544 DPRINT1("Failed to retrieve drive capacity!\n");
545 return(STATUS_SUCCESS
);
549 /* Clear the verify flag for removable media drives. */
550 DiskDeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
553 DPRINT("SectorSize: %lu\n", DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
555 /* Check disk for presence of a disk manager */
556 HalExamineMBR(DiskDeviceObject
,
557 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
560 if (MbrBuffer
!= NULL
)
562 /* Start disk at sector 63 if the Ontrack Disk Manager was found */
563 DPRINT("Found 'Ontrack Disk Manager'!\n");
565 DiskDeviceExtension
->DMSkew
= 63;
566 DiskDeviceExtension
->DMByteSkew
=
567 63 * DiskDeviceExtension
->DiskGeometry
->BytesPerSector
;
568 DiskDeviceExtension
->DMActive
= TRUE
;
570 ExFreePool(MbrBuffer
);
574 if ((DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
575 (DiskDeviceExtension
->DiskGeometry
->MediaType
== RemovableMedia
))
577 /* Allocate a partition list for a single entry. */
578 PartitionList
= ExAllocatePool(NonPagedPool
,
579 sizeof(DRIVE_LAYOUT_INFORMATION
));
580 if (PartitionList
!= NULL
)
582 RtlZeroMemory(PartitionList
,
583 sizeof(DRIVE_LAYOUT_INFORMATION
));
584 PartitionList
->PartitionCount
= 1;
586 DiskData
->DriveNotReady
= TRUE
;
587 Status
= STATUS_SUCCESS
;
592 /* Read partition table */
593 Status
= IoReadPartitionTable(DiskDeviceObject
,
594 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
598 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status
);
600 if ((!NT_SUCCESS(Status
) || PartitionList
->PartitionCount
== 0) &&
601 DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
603 if (!NT_SUCCESS(Status
))
605 /* Drive is not ready. */
606 DPRINT("Drive not ready\n");
607 DiskData
->DriveNotReady
= TRUE
;
611 ExFreePool(PartitionList
);
614 /* Allocate a partition list for a single entry. */
615 PartitionList
= ExAllocatePool(NonPagedPool
,
616 sizeof(DRIVE_LAYOUT_INFORMATION
));
617 if (PartitionList
!= NULL
)
619 RtlZeroMemory(PartitionList
,
620 sizeof(DRIVE_LAYOUT_INFORMATION
));
621 PartitionList
->PartitionCount
= 1;
623 Status
= STATUS_SUCCESS
;
628 if (NT_SUCCESS(Status
))
630 DPRINT("Read partition table!\n");
632 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
634 ScsiDiskUpdateFixedDiskGeometry(DiskDeviceExtension
);
636 for (PartitionNumber
= 0; PartitionNumber
< PartitionList
->PartitionCount
; PartitionNumber
++)
638 PartitionEntry
= &PartitionList
->PartitionEntry
[PartitionNumber
];
640 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
642 PartitionEntry
->PartitionNumber
,
643 PartitionEntry
->BootIndicator
,
644 PartitionEntry
->PartitionType
,
645 PartitionEntry
->StartingOffset
.QuadPart
/ 512 /*DrvParms.BytesPerSector*/,
646 PartitionEntry
->PartitionLength
.QuadPart
/ 512 /* DrvParms.BytesPerSector*/);
648 /* Create partition device object */
650 "\\Device\\Harddisk%lu\\Partition%lu",
652 PartitionNumber
+ 1);
654 Status
= ScsiClassCreateDeviceObject(DriverObject
,
657 &PartitionDeviceObject
,
659 DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status
);
660 if (NT_SUCCESS(Status
))
662 PartitionDeviceObject
->Flags
= DiskDeviceObject
->Flags
;
663 PartitionDeviceObject
->Characteristics
= DiskDeviceObject
->Characteristics
;
664 PartitionDeviceObject
->StackSize
= DiskDeviceObject
->StackSize
;
665 PartitionDeviceObject
->AlignmentRequirement
= DiskDeviceObject
->AlignmentRequirement
;
667 PartitionDeviceExtension
= PartitionDeviceObject
->DeviceExtension
;
668 PartitionDeviceExtension
->LockCount
= 0;
669 PartitionDeviceExtension
->DeviceNumber
= DiskNumber
;
670 PartitionDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
671 PartitionDeviceExtension
->DiskGeometry
= DiskDeviceExtension
->DiskGeometry
;
672 PartitionDeviceExtension
->PhysicalDevice
= DiskDeviceExtension
->PhysicalDevice
;
673 PartitionDeviceExtension
->PortCapabilities
= Capabilities
;
674 PartitionDeviceExtension
->StartingOffset
.QuadPart
=
675 PartitionEntry
->StartingOffset
.QuadPart
;
676 PartitionDeviceExtension
->PartitionLength
.QuadPart
=
677 PartitionEntry
->PartitionLength
.QuadPart
;
678 PartitionDeviceExtension
->DMSkew
= DiskDeviceExtension
->DMSkew
;
679 PartitionDeviceExtension
->DMByteSkew
= DiskDeviceExtension
->DMByteSkew
;
680 PartitionDeviceExtension
->DMActive
= DiskDeviceExtension
->DMActive
;
681 PartitionDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
682 PartitionDeviceExtension
->PathId
= InquiryData
->PathId
;
683 PartitionDeviceExtension
->TargetId
= InquiryData
->TargetId
;
684 PartitionDeviceExtension
->Lun
= InquiryData
->Lun
;
685 PartitionDeviceExtension
->SectorShift
= DiskDeviceExtension
->SectorShift
;
687 /* Initialize lookaside list for SRBs */
688 ScsiClassInitializeSrbLookasideList(PartitionDeviceExtension
,
691 /* Link current partition device extension to previous disk data */
692 DiskData
->NextPartition
= PartitionDeviceExtension
;
694 /* Initialize current disk data */
695 DiskData
= (PDISK_DATA
)(PartitionDeviceExtension
+ 1);
696 DiskData
->NextPartition
= NULL
;
697 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
698 DiskData
->PartitionNumber
= PartitionNumber
+ 1;
699 DiskData
->PartitionOrdinal
= PartitionNumber
+ 1;
700 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
701 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
702 DiskData
->DriveNotReady
= FALSE
;
706 DPRINT1("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status
);
713 if (PartitionList
!= NULL
)
714 ExFreePool(PartitionList
);
716 DPRINT("DiskClassCreateDeviceObjects() done\n");
718 return(STATUS_SUCCESS
);
722 /**********************************************************************
724 * DiskClassDeviceControl
727 * Answer requests for device control calls
733 * Standard dispatch arguments
740 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
743 PDEVICE_EXTENSION DeviceExtension
;
744 PIO_STACK_LOCATION IrpStack
;
745 ULONG ControlCode
, InputLength
, OutputLength
;
750 DPRINT("DiskClassDeviceControl() called!\n");
752 Status
= STATUS_INVALID_DEVICE_REQUEST
;
754 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
755 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
756 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
757 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
758 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
759 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
763 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
764 DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
765 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
767 Status
= STATUS_INVALID_PARAMETER
;
771 PDISK_GEOMETRY Geometry
;
773 if (DeviceExtension
->DiskGeometry
== NULL
)
775 DPRINT("No disk geometry available!\n");
776 DeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
777 sizeof(DISK_GEOMETRY
));
779 Status
= ScsiClassReadDriveCapacity(DeviceObject
);
780 DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status
);
781 if (NT_SUCCESS(Status
))
783 Geometry
= (PDISK_GEOMETRY
)Irp
->AssociatedIrp
.SystemBuffer
;
784 RtlMoveMemory(Geometry
,
785 DeviceExtension
->DiskGeometry
,
786 sizeof(DISK_GEOMETRY
));
788 Status
= STATUS_SUCCESS
;
789 Information
= sizeof(DISK_GEOMETRY
);
794 case IOCTL_DISK_GET_PARTITION_INFO
:
795 DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
796 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
797 sizeof(PARTITION_INFORMATION
))
799 Status
= STATUS_INFO_LENGTH_MISMATCH
;
801 else if (DiskData
->PartitionNumber
== 0)
803 Status
= STATUS_INVALID_DEVICE_REQUEST
;
807 PPARTITION_INFORMATION PartitionInfo
;
809 PartitionInfo
= (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
811 PartitionInfo
->PartitionType
= DiskData
->PartitionType
;
812 PartitionInfo
->StartingOffset
= DeviceExtension
->StartingOffset
;
813 PartitionInfo
->PartitionLength
= DeviceExtension
->PartitionLength
;
814 PartitionInfo
->HiddenSectors
= DiskData
->HiddenSectors
;
815 PartitionInfo
->PartitionNumber
= DiskData
->PartitionNumber
;
816 PartitionInfo
->BootIndicator
= DiskData
->BootIndicator
;
817 PartitionInfo
->RewritePartition
= FALSE
;
818 PartitionInfo
->RecognizedPartition
=
819 IsRecognizedPartition(DiskData
->PartitionType
);
821 Status
= STATUS_SUCCESS
;
822 Information
= sizeof(PARTITION_INFORMATION
);
826 case IOCTL_DISK_SET_PARTITION_INFO
:
827 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
828 sizeof(SET_PARTITION_INFORMATION
))
830 Status
= STATUS_INFO_LENGTH_MISMATCH
;
832 else if (DiskData
->PartitionNumber
== 0)
834 Status
= STATUS_INVALID_DEVICE_REQUEST
;
838 PSET_PARTITION_INFORMATION PartitionInfo
;
840 PartitionInfo
= (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
842 Status
= IoSetPartitionInformation(DeviceExtension
->PhysicalDevice
,
843 DeviceExtension
->DiskGeometry
->BytesPerSector
,
844 DiskData
->PartitionOrdinal
,
845 PartitionInfo
->PartitionType
);
846 if (NT_SUCCESS(Status
))
848 DiskData
->PartitionType
= PartitionInfo
->PartitionType
;
853 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
854 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
855 sizeof(DRIVE_LAYOUT_INFORMATION
))
857 Status
= STATUS_BUFFER_TOO_SMALL
;
861 PDRIVE_LAYOUT_INFORMATION PartitionList
;
863 Status
= IoReadPartitionTable(DeviceExtension
->PhysicalDevice
,
864 DeviceExtension
->DiskGeometry
->BytesPerSector
,
867 if (NT_SUCCESS(Status
))
871 BufferSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
873 BufferSize
+= PartitionList
->PartitionCount
* sizeof(PARTITION_INFORMATION
);
875 if (BufferSize
> IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
877 Status
= STATUS_BUFFER_TOO_SMALL
;
881 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
884 Status
= STATUS_SUCCESS
;
885 Information
= BufferSize
;
887 ExFreePool(PartitionList
);
892 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
893 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
894 sizeof(DRIVE_LAYOUT_INFORMATION
))
896 Status
= STATUS_INFO_LENGTH_MISMATCH
;
898 else if (DeviceExtension
->PhysicalDevice
->DeviceExtension
!= DeviceExtension
)
900 Status
= STATUS_INVALID_PARAMETER
;
904 PDRIVE_LAYOUT_INFORMATION PartitionList
;
907 PartitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
908 TableSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
909 ((PartitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
));
911 if (IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< TableSize
)
913 Status
= STATUS_BUFFER_TOO_SMALL
;
917 /* Update partition device objects */
918 DiskClassUpdatePartitionDeviceObjects (DeviceObject
,
921 /* Write partition table */
922 Status
= IoWritePartitionTable(DeviceExtension
->PhysicalDevice
,
923 DeviceExtension
->DiskGeometry
->BytesPerSector
,
924 DeviceExtension
->DiskGeometry
->SectorsPerTrack
,
925 DeviceExtension
->DiskGeometry
->TracksPerCylinder
,
927 if (NT_SUCCESS(Status
))
929 Information
= TableSize
;
935 case IOCTL_DISK_VERIFY
:
936 case IOCTL_DISK_FORMAT_TRACKS
:
937 case IOCTL_DISK_PERFORMANCE
:
938 case IOCTL_DISK_IS_WRITABLE
:
939 case IOCTL_DISK_LOGGING
:
940 case IOCTL_DISK_FORMAT_TRACKS_EX
:
941 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
942 case IOCTL_DISK_HISTOGRAM_DATA
:
943 case IOCTL_DISK_HISTOGRAM_RESET
:
944 case IOCTL_DISK_REQUEST_STRUCTURE
:
945 case IOCTL_DISK_REQUEST_DATA
:
946 /* If we get here, something went wrong. Inform the requestor */
947 DPRINT1("Unhandled control code: %lx\n", ControlCode
);
948 Status
= STATUS_INVALID_DEVICE_REQUEST
;
953 /* Call the common device control function */
954 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
957 /* Verify the device if the user caused the error */
958 if (!NT_SUCCESS(Status
) && IoIsErrorUserInduced(Status
))
960 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
963 Irp
->IoStatus
.Status
= Status
;
964 Irp
->IoStatus
.Information
= Information
;
965 IoCompleteRequest(Irp
,
972 /**********************************************************************
974 * DiskClassShutdownFlush
977 * Answer requests for shutdown and flush calls.
984 * Pointer to the device.
994 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
997 PDEVICE_EXTENSION DeviceExtension
;
998 PIO_STACK_LOCATION IrpStack
;
999 PSCSI_REQUEST_BLOCK Srb
;
1001 DPRINT("DiskClassShutdownFlush() called!\n");
1003 DeviceExtension
= DeviceObject
->DeviceExtension
;
1006 Srb
= ExAllocatePool(NonPagedPool
,
1007 sizeof(SCSI_REQUEST_BLOCK
));
1010 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1011 Irp
->IoStatus
.Information
= 0;
1012 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1014 return(STATUS_INSUFFICIENT_RESOURCES
);
1017 /* Initialize SRB */
1018 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
1019 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
1021 /* Set device IDs */
1022 Srb
->PathId
= DeviceExtension
->PathId
;
1023 Srb
->TargetId
= DeviceExtension
->TargetId
;
1024 Srb
->Lun
= DeviceExtension
->Lun
;
1026 /* Flush write cache */
1027 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1028 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1029 Srb
->CdbLength
= 10;
1030 Srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
1031 ScsiClassSendSrbSynchronous(DeviceObject
,
1037 /* Get current stack location */
1038 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1040 /* FIXME: Unlock removable media upon shutdown */
1044 IrpStack
->Parameters
.Others
.Argument4
= (PVOID
)0;
1046 /* Send shutdown or flush request to the port driver */
1048 if (IrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
)
1049 Srb
->Function
= SRB_FUNCTION_SHUTDOWN
;
1051 Srb
->Function
= SRB_FUNCTION_FLUSH
;
1053 /* Init completion routine */
1054 IoSetCompletionRoutine(Irp
,
1055 ScsiClassIoComplete
,
1061 /* Prepare next stack location for a call to the port driver */
1062 IrpStack
= IoGetNextIrpStackLocation(Irp
);
1063 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1064 IrpStack
->Parameters
.Scsi
.Srb
= Srb
;
1065 Srb
->OriginalRequest
= Irp
;
1067 /* Call port driver */
1068 return(IoCallDriver(DeviceExtension
->PortDeviceObject
, Irp
));
1072 /**********************************************************************
1074 * DiskClassUpdatePartitionDeviceObjects
1077 * Deletes, modifies or creates partition device objects.
1084 * Pointer to the device.
1087 * Pointer to the IRP
1094 DiskClassUpdatePartitionDeviceObjects(IN PDEVICE_OBJECT DiskDeviceObject
,
1097 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1098 PPARTITION_INFORMATION PartitionEntry
;
1099 PDEVICE_EXTENSION DeviceExtension
;
1100 PDEVICE_EXTENSION DiskDeviceExtension
;
1101 PDISK_DATA DiskData
;
1102 ULONG PartitionCount
;
1103 ULONG PartitionOrdinal
;
1104 ULONG PartitionNumber
;
1105 ULONG LastPartitionNumber
;
1108 WCHAR NameBuffer
[MAX_PATH
];
1109 UNICODE_STRING DeviceName
;
1110 PDEVICE_OBJECT DeviceObject
;
1113 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() called\n");
1115 /* Get partition list */
1116 PartitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
1118 /* Round partition count up by 4 */
1119 PartitionCount
= ((PartitionList
->PartitionCount
+ 3) / 4) * 4;
1121 /* Remove the partition numbers from the partition list */
1122 for (i
= 0; i
< PartitionCount
; i
++)
1124 PartitionList
->PartitionEntry
[i
].PartitionNumber
= 0;
1127 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
1129 /* Traverse on-disk partition list */
1130 LastPartitionNumber
= 0;
1131 DeviceExtension
= DiskDeviceExtension
;
1132 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1135 DeviceExtension
= DiskData
->NextPartition
;
1136 if (DeviceExtension
== NULL
)
1140 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1142 /* Update last partition number */
1143 if (DiskData
->PartitionNumber
> LastPartitionNumber
)
1144 LastPartitionNumber
= DiskData
->PartitionNumber
;
1146 /* Ignore unused on-disk partitions */
1147 if (DeviceExtension
->PartitionLength
.QuadPart
== 0ULL)
1151 PartitionOrdinal
= 0;
1152 for (i
= 0; i
< PartitionCount
; i
++)
1154 /* Get current partition entry */
1155 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
1157 /* Ignore empty (aka unused) or extended partitions */
1158 if (PartitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
1159 IsContainerPartition (PartitionEntry
->PartitionType
))
1164 /* Check for matching partition start offset and length */
1165 if ((PartitionEntry
->StartingOffset
.QuadPart
!=
1166 DeviceExtension
->StartingOffset
.QuadPart
) ||
1167 (PartitionEntry
->PartitionLength
.QuadPart
!=
1168 DeviceExtension
->PartitionLength
.QuadPart
))
1171 DPRINT1("Found matching partition entry for partition %lu\n",
1172 DiskData
->PartitionNumber
);
1174 /* Found matching partition */
1177 /* Update partition number in partition list */
1178 PartitionEntry
->PartitionNumber
= DiskData
->PartitionNumber
;
1184 /* Get disk data for current partition */
1185 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1187 /* Update partition type if partiton will be rewritten */
1188 if (PartitionEntry
->RewritePartition
== TRUE
)
1189 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
1191 /* Assign new partiton ordinal */
1192 DiskData
->PartitionOrdinal
= PartitionOrdinal
;
1194 DPRINT1("Partition ordinal %lu was assigned to partition %lu\n",
1195 DiskData
->PartitionOrdinal
,
1196 DiskData
->PartitionNumber
);
1200 /* Delete this partition */
1201 DeviceExtension
->PartitionLength
.QuadPart
= 0ULL;
1203 DPRINT1("Deleting partition %lu\n",
1204 DiskData
->PartitionNumber
);
1208 /* Traverse partiton list and create new partiton devices */
1209 PartitionOrdinal
= 0;
1210 for (i
= 0; i
< PartitionCount
; i
++)
1212 /* Get current partition entry */
1213 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
1215 /* Ignore empty (aka unused) or extended partitions */
1216 if (PartitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
1217 IsContainerPartition (PartitionEntry
->PartitionType
))
1222 /* Ignore unchanged partition entries */
1223 if (PartitionEntry
->RewritePartition
== FALSE
)
1226 /* Check for an unused device object */
1227 PartitionNumber
= 0;
1228 DeviceExtension
= DiskDeviceExtension
;
1229 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1232 DeviceExtension
= DiskData
->NextPartition
;
1233 if (DeviceExtension
== NULL
)
1236 /* Get partition disk data */
1237 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1239 /* Found a free (unused) partition (device object) */
1240 if (DeviceExtension
->PartitionLength
.QuadPart
== 0ULL)
1242 PartitionNumber
= DiskData
->PartitionNumber
;
1247 if (PartitionNumber
== 0)
1249 /* Create a new partition device object */
1250 DPRINT1("Create new partition device object\n");
1252 /* Get new partiton number */
1253 LastPartitionNumber
++;
1254 PartitionNumber
= LastPartitionNumber
;
1256 /* Create partition device object */
1257 swprintf(NameBuffer
,
1258 L
"\\Device\\Harddisk%lu\\Partition%lu",
1259 DiskDeviceExtension
->DeviceNumber
,
1261 RtlInitUnicodeString(&DeviceName
,
1264 Status
= IoCreateDevice(DiskDeviceObject
->DriverObject
,
1265 sizeof(DEVICE_EXTENSION
) + sizeof(DISK_DATA
),
1271 if (!NT_SUCCESS(Status
))
1273 DPRINT1("IoCreateDevice() failed (Status %lx)\n", Status
);
1277 DeviceObject
->Flags
|= DO_DIRECT_IO
;
1278 DeviceObject
->StackSize
= DiskDeviceObject
->StackSize
;
1279 DeviceObject
->Characteristics
= DiskDeviceObject
->Characteristics
;
1280 DeviceObject
->AlignmentRequirement
= DiskDeviceObject
->AlignmentRequirement
;
1282 /* Initialize device extension */
1283 DeviceExtension
= DeviceObject
->DeviceExtension
;
1284 RtlCopyMemory(DeviceExtension
,
1285 DiskDeviceObject
->DeviceExtension
,
1286 sizeof(DEVICE_EXTENSION
));
1287 DeviceExtension
->DeviceObject
= DeviceObject
;
1289 /* Initialize lookaside list for SRBs */
1290 ScsiClassInitializeSrbLookasideList(DeviceExtension
,
1293 /* Link current partition device extension to previous disk data */
1294 DiskData
->NextPartition
= DeviceExtension
;
1295 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1296 DiskData
->NextPartition
= NULL
;
1300 /* Reuse an existing partition device object */
1301 DPRINT1("Reuse an exisiting partition device object\n");
1302 DiskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
1305 /* Update partition data and device extension */
1306 DiskData
->PartitionNumber
= PartitionNumber
;
1307 DiskData
->PartitionOrdinal
= PartitionOrdinal
;
1308 DiskData
->PartitionType
= PartitionEntry
->PartitionType
;
1309 DiskData
->BootIndicator
= PartitionEntry
->BootIndicator
;
1310 DiskData
->HiddenSectors
= PartitionEntry
->HiddenSectors
;
1311 DeviceExtension
->StartingOffset
= PartitionEntry
->StartingOffset
;
1312 DeviceExtension
->PartitionLength
= PartitionEntry
->PartitionLength
;
1314 /* Update partition number in the partition list */
1315 PartitionEntry
->PartitionNumber
= PartitionNumber
;
1317 DPRINT1("Partition ordinal %lu was assigned to partition %lu\n",
1318 DiskData
->PartitionOrdinal
,
1319 DiskData
->PartitionNumber
);
1322 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() done\n");
1326 /**********************************************************************
1328 * DiskClassUpdateFixedDiskGeometry
1331 * Updated the geometry of a disk if the disk can be accessed
1339 * Disk device extension.
1346 ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension
)
1348 PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
1349 PCM_INT13_DRIVE_PARAMETER DriveParameters
;
1350 PKEY_VALUE_FULL_INFORMATION ValueBuffer
;
1351 OBJECT_ATTRIBUTES ObjectAttributes
;
1352 UNICODE_STRING KeyName
;
1353 UNICODE_STRING ValueName
;
1359 DPRINT1("ScsiDiskUpdateFixedDiskGeometry() called\n");
1361 RtlInitUnicodeString(&KeyName
,
1362 L
"\\Registry\\Machine\\Hardware\\Description\\System");
1364 InitializeObjectAttributes(&ObjectAttributes
,
1366 OBJ_CASE_INSENSITIVE
,
1370 /* Open the adapter key */
1371 Status
= ZwOpenKey(&SystemKey
,
1374 if (!NT_SUCCESS(Status
))
1376 DPRINT1("ZwOpenKey() failed (Status %lx)\n", Status
);
1380 /* Allocate value buffer */
1381 ValueBuffer
= ExAllocatePool(PagedPool
,
1383 if (ValueBuffer
== NULL
)
1385 DPRINT1("Failed to allocate value buffer\n");
1390 RtlInitUnicodeString(&ValueName
,
1391 L
"Configuration Data");
1393 /* Query 'Configuration Data' value */
1394 Status
= ZwQueryValueKey(SystemKey
,
1396 KeyValueFullInformation
,
1400 if (!NT_SUCCESS(Status
))
1402 DPRINT1("ZwQueryValueKey() failed (Status %lx)\n", Status
);
1403 ExFreePool(ValueBuffer
);
1411 ResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)
1412 ((PUCHAR
)ValueBuffer
+ ValueBuffer
->DataOffset
);
1414 DriveParameters
= (PCM_INT13_DRIVE_PARAMETER
)
1415 ((PUCHAR
)ResourceDescriptor
+ sizeof(CM_FULL_RESOURCE_DESCRIPTOR
));
1417 for (i
= 0; i
< DriveParameters
[0].NumberDrives
; i
++)
1419 DPRINT1("Drive %lu: %lu Cylinders %hu Heads %hu Sectors\n",
1421 DriveParameters
[i
].MaxCylinders
,
1422 DriveParameters
[i
].MaxHeads
,
1423 DriveParameters
[i
].SectorsPerTrack
);
1426 DPRINT1("*** System stopped ***\n");
1429 ExFreePool(ValueBuffer
);
1431 DPRINT1("ScsiDiskUpdateFixedDiskGeometry() done\n");