1 /* $Id: disk.c,v 1.5 2002/02/03 20:21:45 ekohl Exp $
5 /* INCLUDES *****************************************************************/
9 #include "../include/scsi.h"
10 #include "../include/class2.h"
11 #include "../include/ntddscsi.h"
16 #define VERSION "V0.0.1"
19 typedef struct _DISK_DEVICE_EXTENSION
22 } DISK_DEVICE_EXTENSION
, *PDISK_DEVICE_EXTENSION
;
27 DiskClassFindDevices(PDRIVER_OBJECT DriverObject
,
28 PUNICODE_STRING RegistryPath
,
29 PCLASS_INIT_DATA InitializationData
,
30 PDEVICE_OBJECT PortDeviceObject
,
34 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData
);
37 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
42 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
43 IN PUNICODE_STRING RegistryPath
, /* what's this used for? */
44 IN PDEVICE_OBJECT PortDeviceObject
,
47 IN PIO_SCSI_CAPABILITIES Capabilities
,
48 IN PSCSI_INQUIRY_DATA InquiryData
,
49 IN PCLASS_INIT_DATA InitializationData
);
52 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
56 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
61 /* FUNCTIONS ****************************************************************/
66 // This function initializes the driver, locates and claims
67 // hardware resources, and creates various NT objects needed
68 // to process I/O requests.
74 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
76 // IN PUNICODE_STRING RegistryPath Name of registry driver service
83 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
84 IN PUNICODE_STRING RegistryPath
)
86 CLASS_INIT_DATA InitData
;
88 DbgPrint("Disk Class Driver %s\n",
90 DPRINT("RegistryPath '%wZ'\n",
93 RtlZeroMemory(&InitData
,
94 sizeof(CLASS_INIT_DATA
));
96 InitData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
97 InitData
.DeviceExtensionSize
= sizeof(DEVICE_EXTENSION
) + sizeof(DISK_DEVICE_EXTENSION
);
98 InitData
.DeviceType
= FILE_DEVICE_DISK
;
99 InitData
.DeviceCharacteristics
= 0;
101 InitData
.ClassError
= NULL
; // DiskClassProcessError;
102 InitData
.ClassReadWriteVerification
= DiskClassCheckReadWrite
;
103 InitData
.ClassFindDeviceCallBack
= DiskClassCheckDevice
;
104 InitData
.ClassFindDevices
= DiskClassFindDevices
;
105 InitData
.ClassDeviceControl
= DiskClassDeviceControl
;
106 InitData
.ClassShutdownFlush
= DiskClassShutdownFlush
;
107 InitData
.ClassCreateClose
= NULL
;
108 InitData
.ClassStartIo
= NULL
;
110 return(ScsiClassInitialize(DriverObject
,
116 /**********************************************************************
118 * DiskClassFindDevices
121 * This function searches for device that are attached to the
129 * System allocated Driver Object for this driver
132 * Name of registry driver service key
135 * Pointer to the main initialization data
138 * Pointer to the port Device Object
144 * TRUE: At least one disk drive was found
145 * FALSE: No disk drive found
149 DiskClassFindDevices(PDRIVER_OBJECT DriverObject
,
150 PUNICODE_STRING RegistryPath
,
151 PCLASS_INIT_DATA InitializationData
,
152 PDEVICE_OBJECT PortDeviceObject
,
155 PCONFIGURATION_INFORMATION ConfigInfo
;
156 PIO_SCSI_CAPABILITIES PortCapabilities
;
157 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
158 PSCSI_INQUIRY_DATA UnitInfo
;
159 PINQUIRYDATA InquiryData
;
166 DPRINT("DiskClassFindDevices() called.\n");
168 /* Get port capabilities */
169 Status
= ScsiClassGetCapabilities(PortDeviceObject
,
171 if (!NT_SUCCESS(Status
))
173 DPRINT("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status
);
177 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities
->MaximumTransferLength
);
179 /* Get inquiry data */
180 Status
= ScsiClassGetInquiryData(PortDeviceObject
,
181 (PSCSI_ADAPTER_BUS_INFO
*)&Buffer
);
182 if (!NT_SUCCESS(Status
))
184 DPRINT("ScsiClassGetInquiryData() failed! (Status %x)\n", Status
);
188 /* Check whether there are unclaimed devices */
189 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
190 DeviceCount
= ScsiClassFindUnclaimedDevices(InitializationData
,
192 if (DeviceCount
== 0)
194 DPRINT1("No unclaimed devices!\n");
198 DPRINT1("Found %lu unclaimed devices!\n", DeviceCount
);
200 ConfigInfo
= IoGetConfigurationInformation();
202 /* Search each bus of this adapter */
203 for (Bus
= 0; Bus
< (ULONG
)AdapterBusInfo
->NumberOfBuses
; Bus
++)
205 DPRINT("Searching bus %lu\n", Bus
);
207 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
);
209 while (AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
)
211 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
213 if (((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
214 (InquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
215 (InquiryData
->DeviceTypeQualifier
== 0) &&
216 (UnitInfo
->DeviceClaimed
== FALSE
))
218 DPRINT1("Vendor: '%.24s'\n",
219 InquiryData
->VendorId
);
221 /* Create device objects for disk */
222 Status
= DiskClassCreateDeviceObject(DriverObject
,
226 ConfigInfo
->DiskCount
,
230 if (NT_SUCCESS(Status
))
232 ConfigInfo
->DiskCount
++;
237 if (UnitInfo
->NextInquiryDataOffset
== 0)
240 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ UnitInfo
->NextInquiryDataOffset
);
245 ExFreePool(PortCapabilities
);
247 DPRINT("DiskClassFindDevices() done\n");
253 /**********************************************************************
255 * DiskClassCheckDevice
258 * This function checks the InquiryData for the correct device
259 * type and qualifier.
266 * Pointer to the inquiry data for the device in question.
269 * TRUE: A disk device was found.
274 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData
)
276 return((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
||
277 InquiryData
->DeviceType
== OPTICAL_DEVICE
) &&
278 InquiryData
->DeviceTypeQualifier
== 0);
283 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
286 DPRINT("DiskClassCheckReadWrite() called\n");
288 return(STATUS_SUCCESS
);
292 // DiskClassCreateDeviceObject
295 // Create the raw device and any partition devices on this drive
301 // IN PDRIVER_OBJECT DriverObject The system created driver object
302 // IN PCONTROLLER_OBJECT ControllerObject
303 // IN PIDE_CONTROLLER_EXTENSION ControllerExtension
304 // The IDE controller extension for
306 // IN int DriveIdx The index of the drive on this
308 // IN int HarddiskIdx The NT device number for this
312 // TRUE Drive exists and devices were created
313 // FALSE no devices were created for this device
317 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
318 IN PUNICODE_STRING RegistryPath
, /* what's this used for? */
319 IN PDEVICE_OBJECT PortDeviceObject
,
322 IN PIO_SCSI_CAPABILITIES Capabilities
,
323 IN PSCSI_INQUIRY_DATA InquiryData
,
324 IN PCLASS_INIT_DATA InitializationData
)
326 OBJECT_ATTRIBUTES ObjectAttributes
;
327 UNICODE_STRING UnicodeDeviceDirName
;
328 WCHAR NameBuffer
[80];
329 CHAR NameBuffer2
[80];
330 PDEVICE_OBJECT DiskDeviceObject
;
331 PDEVICE_OBJECT PartitionDeviceObject
;
332 PDEVICE_EXTENSION DiskDeviceExtension
; /* defined in class2.h */
333 PDEVICE_EXTENSION PartitionDeviceExtension
; /* defined in class2.h */
334 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
336 PPARTITION_INFORMATION PartitionEntry
;
337 PDISK_DEVICE_EXTENSION DiskData
;
338 ULONG PartitionNumber
;
341 WCHAR ArcNameBuffer
[120];
342 UNICODE_STRING ArcName
;
343 ANSI_STRING DeviceNameA
;
344 UNICODE_STRING DeviceName
;
346 DPRINT1("DiskClassCreateDeviceObject() called\n");
348 /* Create the harddisk device directory */
350 L
"\\Device\\Harddisk%lu",
352 RtlInitUnicodeString(&UnicodeDeviceDirName
,
354 InitializeObjectAttributes(&ObjectAttributes
,
355 &UnicodeDeviceDirName
,
359 Status
= ZwCreateDirectoryObject(&Handle
,
362 if (!NT_SUCCESS(Status
))
364 DbgPrint("Could not create device dir object\n");
368 /* Claim the disk device */
369 Status
= ScsiClassClaimDevice(PortDeviceObject
,
373 if (!NT_SUCCESS(Status
))
375 DbgPrint("Could not claim disk device\n");
377 ZwMakeTemporaryObject(Handle
);
383 /* Create disk device (Partition 0) */
385 "\\Device\\Harddisk%lu\\Partition0",
388 Status
= ScsiClassCreateDeviceObject(DriverObject
,
393 if (!NT_SUCCESS(Status
))
395 DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status
);
397 /* Release (unclaim) the disk */
398 ScsiClassClaimDevice(PortDeviceObject
,
403 /* Delete the harddisk device directory */
404 ZwMakeTemporaryObject(Handle
);
410 DiskDeviceObject
->Flags
|= DO_DIRECT_IO
;
411 if (((PINQUIRYDATA
)InquiryData
->InquiryData
)->RemovableMedia
)
413 DiskDeviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
415 DiskDeviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
417 if (PortDeviceObject
->AlignmentRequirement
> DiskDeviceObject
->AlignmentRequirement
)
419 DiskDeviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
422 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
423 // DiskData = (PDISK_DEVICE_EXTENSION)((PUCHAR)DiskDeviceExtension + sizeof(DEVICE_EXTENSION));
425 DiskDeviceExtension
->LockCount
= 0;
426 DiskDeviceExtension
->DeviceNumber
= DiskNumber
;
427 DiskDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
429 /* FIXME: Not yet! Will cause pointer corruption! */
430 // DiskDeviceExtension->PortCapabilities = PortCapabilities;
432 DiskDeviceExtension
->StartingOffset
.QuadPart
= 0;
433 DiskDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
434 DiskDeviceExtension
->PathId
= InquiryData
->PathId
;
435 DiskDeviceExtension
->TargetId
= InquiryData
->TargetId
;
436 DiskDeviceExtension
->Lun
= InquiryData
->Lun
;
439 /* Get disk geometry */
440 DiskDeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
441 sizeof(DISK_GEOMETRY
));
442 if (DiskDeviceExtension
->DiskGeometry
== NULL
)
444 DPRINT1("Failed to allocate geometry buffer!\n");
446 IoDeleteDevice(DiskDeviceObject
);
448 /* Release (unclaim) the disk */
449 ScsiClassClaimDevice(PortDeviceObject
,
454 /* Delete the harddisk device directory */
455 ZwMakeTemporaryObject(Handle
);
458 return(STATUS_INSUFFICIENT_RESOURCES
);
461 /* Read the drive's capacity */
462 Status
= ScsiClassReadDriveCapacity(DiskDeviceObject
);
463 if (!NT_SUCCESS(Status
) &&
464 (DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) == 0)
466 DPRINT1("Failed to retrieve drive capacity!\n");
467 return(STATUS_SUCCESS
);
471 /* Clear the verify flag for non-removable media drives. */
472 DiskDeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
475 DPRINT1("SectorSize: %lu\n", DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
477 /* assign arc name */
478 RtlInitAnsiString(&DeviceNameA
,
480 RtlAnsiStringToUnicodeString(&DeviceName
,
483 swprintf(ArcNameBuffer
,
484 L
"\\ArcName\\multi(0)disk(0)rdisk(%lu)",
486 RtlInitUnicodeString(&ArcName
,
488 DPRINT1("ArcNameBuffer '%S'\n", ArcNameBuffer
);
489 DPRINT1("%wZ ==> %wZ\n", &ArcName
, &DeviceName
);
490 Status
= IoAssignArcName(&ArcName
,
492 RtlFreeUnicodeString(&DeviceName
);
494 if (!NT_SUCCESS(Status
))
496 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName
, Status
);
501 /* Read partition table */
502 Status
= IoReadPartitionTable(DiskDeviceObject
,
503 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
,
507 DPRINT1("IoReadPartitionTable(): Status: %lx\n", Status
);
509 if ((!NT_SUCCESS(Status
) || PartitionList
->PartitionCount
== 0) &&
510 DiskDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
512 if (!NT_SUCCESS(Status
))
514 /* Drive is not ready. */
515 // diskData->DriveNotReady = TRUE;
519 ExFreePool(PartitionList
);
522 /* Allocate a partition list for a single entry. */
523 PartitionList
= ExAllocatePool(NonPagedPool
,
524 sizeof(DRIVE_LAYOUT_INFORMATION
));
525 if (PartitionList
!= NULL
)
527 RtlZeroMemory(PartitionList
,
528 sizeof(DRIVE_LAYOUT_INFORMATION
));
529 PartitionList
->PartitionCount
= 1;
531 Status
= STATUS_SUCCESS
;
535 if (NT_SUCCESS(Status
))
537 DPRINT1("Read partition table!\n");
539 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
541 for (PartitionNumber
= 0; PartitionNumber
< PartitionList
->PartitionCount
; PartitionNumber
++)
543 PartitionEntry
= &PartitionList
->PartitionEntry
[PartitionNumber
];
545 DPRINT1("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
547 PartitionEntry
->PartitionNumber
,
548 PartitionEntry
->BootIndicator
,
549 PartitionEntry
->PartitionType
,
550 PartitionEntry
->StartingOffset
.QuadPart
/ 512 /*DrvParms.BytesPerSector*/,
551 PartitionEntry
->PartitionLength
.QuadPart
/ 512 /* DrvParms.BytesPerSector*/);
553 /* Create partition device (Partition 0) */
555 "\\Device\\Harddisk%lu\\Partition%lu",
557 PartitionNumber
+ 1);
559 Status
= ScsiClassCreateDeviceObject(DriverObject
,
562 &PartitionDeviceObject
,
564 DPRINT1("ScsiClassCreateDeviceObject(): Status %x\n", Status
);
565 if (NT_SUCCESS(Status
))
567 PartitionDeviceObject
->Flags
= DiskDeviceObject
->Flags
;
568 PartitionDeviceObject
->Characteristics
= DiskDeviceObject
->Characteristics
;
569 PartitionDeviceObject
->StackSize
= DiskDeviceObject
->StackSize
;
570 PartitionDeviceObject
->AlignmentRequirement
= DiskDeviceObject
->AlignmentRequirement
;
572 PartitionDeviceExtension
= PartitionDeviceObject
->DeviceExtension
;
573 PartitionDeviceExtension
->LockCount
= 0;
574 PartitionDeviceExtension
->DeviceNumber
= DiskNumber
;
575 PartitionDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
577 /* FIXME: Not yet! Will cause pointer corruption! */
578 // PartitionDeviceExtension->PortCapabilities = PortCapabilities;
580 PartitionDeviceExtension
->StartingOffset
.QuadPart
=
581 PartitionEntry
->StartingOffset
.QuadPart
;
582 PartitionDeviceExtension
->PartitionLength
.QuadPart
=
583 PartitionEntry
->PartitionLength
.QuadPart
;
584 PartitionDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
585 PartitionDeviceExtension
->PathId
= InquiryData
->PathId
;
586 PartitionDeviceExtension
->TargetId
= InquiryData
->TargetId
;
587 PartitionDeviceExtension
->Lun
= InquiryData
->Lun
;
590 /* assign arc name */
591 RtlInitAnsiString(&DeviceNameA
,
593 RtlAnsiStringToUnicodeString(&DeviceName
,
596 swprintf(ArcNameBuffer
,
597 L
"\\ArcName\\multi(0)disk(0)rdisk(%lu)partition(%lu)",
599 PartitionNumber
+ 1);
600 RtlInitUnicodeString(&ArcName
,
602 DPRINT1("ArcNameBuffer '%S'\n", ArcNameBuffer
);
603 DPRINT1("%wZ ==> %wZ\n", &ArcName
, &DeviceName
);
604 Status
= IoAssignArcName(&ArcName
,
606 RtlFreeUnicodeString(&DeviceName
);
608 if (!NT_SUCCESS(Status
))
610 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName
, Status
);
617 DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status
);
626 if (PartitionList
!= NULL
)
627 ExFreePool(PartitionList
);
629 DPRINT1("DiskClassCreateDeviceObjects() done\n");
631 return(STATUS_SUCCESS
);
638 // DiskClassDeviceControl
641 // Answer requests for device control calls
647 // Standard dispatch arguments
654 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
657 PDEVICE_EXTENSION DeviceExtension
;
658 PIO_STACK_LOCATION IrpStack
;
659 ULONG ControlCode
, InputLength
, OutputLength
;
662 DPRINT1("DiskClassDeviceControl() called!\n");
664 Status
= STATUS_SUCCESS
;
665 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
666 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
667 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
668 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
669 DeviceExtension
= (PDEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
671 /* A huge switch statement in a Windows program?! who would have thought? */
674 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
675 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
677 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
678 Irp
->IoStatus
.Information
= 0;
682 PDISK_GEOMETRY Geometry
;
684 Geometry
= (PDISK_GEOMETRY
) Irp
->AssociatedIrp
.SystemBuffer
;
685 RtlMoveMemory(Geometry
,
686 DeviceExtension
->DiskGeometry
,
687 sizeof(DISK_GEOMETRY
));
691 RtlCopyMemory(DiskData
->Geometry
,
692 DiskDeviceExtension
->DiskGeometry
,
693 sizeof(DISK_GEOMETRY
));
694 Geometry
->MediaType
= FixedMedia
;
695 // FIXME: should report for RawDevice even on partition
696 Geometry
->Cylinders
.QuadPart
= DeviceExtension
->Size
/
697 DeviceExtension
->SectorsPerLogCyl
;
698 Geometry
->TracksPerCylinder
= DeviceExtension
->SectorsPerLogTrk
/
699 DeviceExtension
->SectorsPerLogCyl
;
700 Geometry
->SectorsPerTrack
= DeviceExtension
->SectorsPerLogTrk
;
701 Geometry
->BytesPerSector
= DeviceExtension
->BytesPerSector
;
703 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
704 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
708 case IOCTL_DISK_GET_PARTITION_INFO
:
709 case IOCTL_DISK_SET_PARTITION_INFO
:
710 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
711 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
712 case IOCTL_DISK_VERIFY
:
713 case IOCTL_DISK_FORMAT_TRACKS
:
714 case IOCTL_DISK_PERFORMANCE
:
715 case IOCTL_DISK_IS_WRITABLE
:
716 case IOCTL_DISK_LOGGING
:
717 case IOCTL_DISK_FORMAT_TRACKS_EX
:
718 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
719 case IOCTL_DISK_HISTOGRAM_DATA
:
720 case IOCTL_DISK_HISTOGRAM_RESET
:
721 case IOCTL_DISK_REQUEST_STRUCTURE
:
722 case IOCTL_DISK_REQUEST_DATA
:
724 /* If we get here, something went wrong. inform the requestor */
726 DPRINT1("Unhandled control code: %lx\n", ControlCode
);
727 Status
= STATUS_INVALID_DEVICE_REQUEST
;
728 Irp
->IoStatus
.Status
= Status
;
729 Irp
->IoStatus
.Information
= 0;
733 IoCompleteRequest(Irp
,
740 // DiskClassShutdownFlush
743 // Answer requests for shutdown and flush calls
749 // Standard dispatch arguments
756 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
759 DPRINT("DiskClassShutdownFlush() called!\n");
761 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
762 Irp
->IoStatus
.Information
= 0;
763 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
765 return(STATUS_SUCCESS
);