3 Copyright (C) Microsoft Corporation, 1991 - 1999
11 SCSI disk class driver
25 extern PULONG InitSafeBootMode
;
29 #pragma alloc_text(PAGE, DiskAddDevice)
30 #pragma alloc_text(PAGE, DiskInitFdo)
31 #pragma alloc_text(PAGE, DiskInitPdo)
32 #pragma alloc_text(PAGE, DiskStartFdo)
33 #pragma alloc_text(PAGE, DiskStartPdo)
34 #pragma alloc_text(PAGE, DiskQueryId)
35 #pragma alloc_text(PAGE, DiskGenerateDeviceName)
36 #pragma alloc_text(PAGE, DiskCreateSymbolicLinks)
37 #pragma alloc_text(PAGE, DiskDeleteSymbolicLinks)
38 #pragma alloc_text(PAGE, DiskRemoveDevice)
45 IN PDRIVER_OBJECT DriverObject
,
46 IN PDEVICE_OBJECT PhysicalDeviceObject
53 This routine gets a port drivers capabilities, obtains the
54 inquiry data, searches the SCSI bus for the port driver and creates
55 the device objects for the disks found.
59 DriverObject - Pointer to driver object created by system.
61 Pdo - Device object use to send requests to port driver.
65 True is returned if one disk was found and successfully created.
70 ULONG rootPartitionMountable
= FALSE
;
72 PCONFIGURATION_INFORMATION configurationInformation
;
80 // See if we should be allowing file systems to mount on partition zero.
86 UNICODE_STRING diskKeyName
;
87 OBJECT_ATTRIBUTES objectAttributes
;
90 RTL_QUERY_REGISTRY_TABLE queryTable
[2];
92 status
= IoOpenDeviceRegistryKey(PhysicalDeviceObject
,
93 PLUGPLAY_REGKEY_DEVICE
,
97 if(!NT_SUCCESS(status
)) {
98 DebugPrint((1, "DiskAddDevice: Error %#08lx opening device key "
100 status
, PhysicalDeviceObject
));
104 RtlInitUnicodeString(&diskKeyName
, L
"Disk");
105 InitializeObjectAttributes(&objectAttributes
,
107 OBJ_CASE_INSENSITIVE
,
111 status
= ZwOpenKey(&diskKey
, KEY_READ
, &objectAttributes
);
114 if(!NT_SUCCESS(status
)) {
115 DebugPrint((1, "DiskAddDevice: Error %#08lx opening disk key "
116 "for pdo %#08lx device key %#x\n",
117 status
, PhysicalDeviceObject
, deviceKey
));
121 RtlZeroMemory(queryTable
, sizeof(queryTable
));
123 queryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
124 queryTable
[0].Name
= L
"RootPartitionMountable";
125 queryTable
[0].EntryContext
= &(rootPartitionMountable
);
127 status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
133 if(!NT_SUCCESS(status
)) {
134 DebugPrint((1, "DiskAddDevice: Error %#08lx reading value from "
135 "disk key %#x for pdo %#08lx\n",
136 status
, diskKey
, PhysicalDeviceObject
));
147 if(!NT_SUCCESS(status
)) {
148 DebugPrint((1, "DiskAddDevice: Will %sallow file system to mount on "
149 "partition zero of disk %#08lx\n",
150 (rootPartitionMountable
? "" : "not "),
151 PhysicalDeviceObject
));
156 // Create device objects for disk
161 status
= DiskCreateFdo(
163 PhysicalDeviceObject
,
165 (BOOLEAN
) !rootPartitionMountable
169 // Get the number of disks already initialized.
172 configurationInformation
= IoGetConfigurationInformation();
174 if (NT_SUCCESS(status
)) {
177 // Increment system disk device count.
180 configurationInformation
->DiskCount
++;
186 } // end DiskAddDevice()
193 IN PDEVICE_OBJECT Fdo
200 This routine is called to do one-time initialization of new device objects
205 Fdo - a pointer to the functional device object for this device
214 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
216 PDISK_DATA diskData
= (PDISK_DATA
) fdoExtension
->CommonExtension
.DriverData
;
222 ULONG bytesPerSector
;
225 BOOLEAN dmActive
= FALSE
;
234 // Build the lookaside list for srb's for the physical disk. Should only
235 // need a couple. If this fails then we don't have an emergency SRB so
236 // fail the call to initialize.
239 ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION
) fdoExtension
,
240 PARTITION0_LIST_SIZE
);
243 // Because all requests share a common sense buffer, it is possible
244 // for the buffer to be overwritten if the port driver completes
245 // multiple failed requests that require a request sense before the
246 // class driver's completion routine can consume the data in the buffer.
247 // To prevent this, we allow the port driver to allocate a unique sense
248 // buffer each time it needs one. We are responsible for freeing this
249 // buffer. This also allows the adapter to be configured to support
250 // additional sense data beyond the minimum 18 bytes.
253 fdoExtension
->SrbFlags
= SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
;
256 // Initialize the srb flags.
259 if (fdoExtension
->DeviceDescriptor
->CommandQueueing
&&
260 fdoExtension
->AdapterDescriptor
->CommandQueueing
) {
262 fdoExtension
->SrbFlags
= SRB_FLAGS_QUEUE_ACTION_ENABLE
;
266 if (!TEST_FLAG(Fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
267 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
271 // Look for controllers that require special flags.
274 ClassScanForSpecial(fdoExtension
, DiskBadControllers
, DiskSetSpecialHacks
);
277 // Look into the registry to see if this device
278 // requires special attention - [ like a hack ]
281 DiskScanRegistryForSpecial(fdoExtension
);
283 srbFlags
= fdoExtension
->SrbFlags
;
286 // Clear buffer for drive geometry.
289 RtlZeroMemory(&(fdoExtension
->DiskGeometry
),
290 sizeof(DISK_GEOMETRY
));
293 // Allocate request sense buffer.
296 fdoExtension
->SenseData
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
300 if (fdoExtension
->SenseData
== NULL
) {
303 // The buffer can not be allocated.
306 DebugPrint((1, "DiskInitFdo: Can not allocate request sense buffer\n"));
308 status
= STATUS_INSUFFICIENT_RESOURCES
;
313 // Physical device object will describe the entire
314 // device, starting at byte offset 0.
317 fdoExtension
->CommonExtension
.StartingOffset
.QuadPart
= (LONGLONG
)(0);
320 // Set timeout value in seconds.
323 timeOut
= ClassQueryTimeOutRegistryValue(Fdo
);
325 fdoExtension
->TimeOutValue
= timeOut
;
327 fdoExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
331 // If this is a removable drive, build an entry in devicemap\scsi
332 // indicating it's physicaldriveN name, set up the appropriate
333 // update partitions routine and set the flags correctly.
334 // note: only do this after the timeout value is set, above.
337 if (fdoExtension
->DeviceDescriptor
->RemovableMedia
) {
338 ClassUpdateInformationInRegistry( Fdo
,
340 fdoExtension
->DeviceNumber
,
344 // Enable media change notification for removable disks
346 ClassInitializeMediaChangeDetection(fdoExtension
,
349 SET_FLAG(Fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
);
350 diskData
->UpdatePartitionRoutine
= DiskUpdateRemovablePartitions
;
354 SET_FLAG(fdoExtension
->SrbFlags
, SRB_FLAGS_NO_QUEUE_FREEZE
);
355 diskData
->UpdatePartitionRoutine
= DiskUpdatePartitions
;
360 // Read the drive capacity. Don't use the disk version of the routine here
361 // since we don't know the disk signature yet - the disk version will
362 // attempt to determine the BIOS reported geometry.
365 status
= ClassReadDriveCapacity(Fdo
);
368 // If the read capcity failed then just return, unless this is a
369 // removable disk where a device object partition needs to be created.
372 if (!NT_SUCCESS(status
) &&
373 !(Fdo
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
376 "DiskInitFdo: Can't read capacity for device %p\n",
379 if (fdoExtension
->DeviceDescriptor
->RemovableMedia
) {
380 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;
381 Fdo
->Flags
&= ~DO_VERIFY_VOLUME
;
383 fdoExtension
->DiskGeometry
.MediaType
= FixedMedia
;
386 status
= STATUS_SUCCESS
;
390 // Set up sector size fields.
392 // Stack variables will be used to update
393 // the partition device extensions.
395 // The device extension field SectorShift is
396 // used to calculate sectors in I/O transfers.
398 // The DiskGeometry structure is used to service
399 // IOCTls used by the format utility.
402 bytesPerSector
= fdoExtension
->DiskGeometry
.BytesPerSector
;
405 // Make sure sector size is not zero.
408 if (bytesPerSector
== 0) {
411 // Default sector size for disk is 512.
414 bytesPerSector
= fdoExtension
->DiskGeometry
.BytesPerSector
= 512;
417 sectorShift
= fdoExtension
->SectorShift
;
420 // Determine is DM Driver is loaded on an IDE drive that is
421 // under control of Atapi - this could be either a crashdump or
422 // an Atapi device is sharing the controller with an IDE disk.
425 HalExamineMBR(fdoExtension
->CommonExtension
.DeviceObject
,
426 fdoExtension
->DiskGeometry
.BytesPerSector
,
433 // Update the device extension, so that the call to IoReadPartitionTable
434 // will get the correct information. Any I/O to this disk will have
435 // to be skewed by *dmSkew sectors aka DMByteSkew.
438 fdoExtension
->DMSkew
= *dmSkew
;
439 fdoExtension
->DMActive
= TRUE
;
440 fdoExtension
->DMByteSkew
= fdoExtension
->DMSkew
* bytesPerSector
;
443 // Save away the infomation that we need, since this deviceExtension will soon be
448 dmByteSkew
= fdoExtension
->DMByteSkew
;
454 // Try to read the signature off the disk and determine the correct drive
455 // geometry based on that. This requires rereading the disk size to get
456 // the cylinder count updated correctly.
459 if(fdoExtension
->DeviceDescriptor
->RemovableMedia
== FALSE
) {
460 DiskReadSignature(Fdo
);
461 DiskReadDriveCapacity(Fdo
);
466 // Register interfaces for this device
469 UNICODE_STRING interfaceName
;
471 RtlInitUnicodeString(&interfaceName
, NULL
);
473 status
= IoRegisterDeviceInterface(fdoExtension
->LowerPdo
,
474 (LPGUID
) &DiskClassGuid
,
478 if(NT_SUCCESS(status
)) {
480 diskData
->DiskInterfaceString
= interfaceName
;
481 status
= IoSetDeviceInterfaceState(&interfaceName
, TRUE
);
484 interfaceName
.Buffer
= NULL
;
487 if(!NT_SUCCESS(status
)) {
489 DebugPrint((1, "DiskInitFdo: Unable to register or set disk DCA "
490 "for fdo %p [%lx]\n", Fdo
, status
));
492 RtlFreeUnicodeString(&interfaceName
);
493 RtlInitUnicodeString(&(diskData
->DiskInterfaceString
), NULL
);
497 DiskCreateSymbolicLinks(Fdo
);
500 // Determine the type of disk and enable failure preiction in the hardware
501 // and enable failure prediction polling.
504 if (*InitSafeBootMode
== 0)
506 DiskDetectFailurePrediction(fdoExtension
,
507 &diskData
->FailurePredictionCapability
);
509 if (diskData
->FailurePredictionCapability
!= FailurePredictionNone
)
512 // Cool, we've got some sort of failure prediction, enable it
513 // at the hardware and then enable polling for it
517 // By default we allow performance to be degradeded if failure
518 // prediction is enabled.
520 // TODO: Make a registry entry ?
523 diskData
->AllowFPPerfHit
= TRUE
;
526 // Enable polling only after Atapi and SBP2 add support for the new
527 // SRB flag that indicates that the request should not reset the
528 // drive spin down idle timer.
531 status
= DiskEnableDisableFailurePredictPolling(fdoExtension
,
533 DISK_DEFAULT_FAILURE_POLLING_PERIOD
);
535 DebugPrint((3, "DiskInitFdo: Failure Prediction Poll enabled as "
536 "%d for device %p\n",
537 diskData
->FailurePredictionCapability
,
543 // In safe boot mode we do not enable failure prediction, as perhaps
544 // it is the reason why normal boot does not work
547 diskData
->FailurePredictionCapability
= FailurePredictionNone
;
552 // Initialize the verify mutex
555 KeInitializeMutex(&diskData
->VerifyMutex
, MAX_SECTORS_PER_VERIFY
);
557 return(STATUS_SUCCESS
);
559 } // end DiskInitFdo()
564 IN PDEVICE_OBJECT Pdo
571 This routine will create the well known names for a PDO and register
572 it's device interfaces.
577 PCOMMON_DEVICE_EXTENSION pdoExtension
= Pdo
->DeviceExtension
;
578 PDISK_DATA diskData
= pdoExtension
->DriverData
;
580 UNICODE_STRING interfaceName
;
586 DiskCreateSymbolicLinks(Pdo
);
589 // Register interfaces for this device
592 RtlInitUnicodeString(&interfaceName
, NULL
);
594 status
= IoRegisterDeviceInterface(Pdo
,
595 (LPGUID
) &PartitionClassGuid
,
599 if(NT_SUCCESS(status
)) {
601 diskData
->PartitionInterfaceString
= interfaceName
;
602 status
= IoSetDeviceInterfaceState(&interfaceName
, TRUE
);
605 interfaceName
.Buffer
= NULL
;
608 if(!NT_SUCCESS(status
)) {
609 DebugPrint((1, "DiskInitPdo: Unable to register partition DCA for "
610 "pdo %p [%lx]\n", Pdo
, status
));
612 RtlFreeUnicodeString(&interfaceName
);
613 RtlInitUnicodeString(&(diskData
->PartitionInterfaceString
), NULL
);
616 return STATUS_SUCCESS
;
622 IN PDEVICE_OBJECT Pdo
629 This routine will create the well known names for a PDO and register
630 it's device interfaces.
637 return STATUS_SUCCESS
;
642 IN PDEVICE_OBJECT DeviceObject
,
647 PFUNCTIONAL_DEVICE_EXTENSION fdo
= DeviceObject
->DeviceExtension
;
649 if(fdo
->CommonExtension
.IsFdo
) {
650 DiskAcquirePartitioningLock(fdo
);
651 DiskInvalidatePartitionTable(fdo
, TRUE
);
652 DiskReleasePartitioningLock(fdo
);
655 return STATUS_SUCCESS
;
662 IN PDEVICE_OBJECT Pdo
,
663 IN BUS_QUERY_ID_TYPE IdType
,
664 IN PUNICODE_STRING UnicodeIdString
671 This routine generates the PNP id's for the disk's "children". If the
672 specified ID isn't one that the routine can generate it must return
673 STATUS_NOT_IMPLEMENTED so classpnp will know not to do anything with the
674 PNP request's status.
676 This routine allocates the buffer for the UnicodeIdString. It is the
677 caller's responsibility to free the buffer when it's done.
681 Pdo - a pointer to the PDO we are to generate an ID for
683 IdType - the type of ID to be generated
685 UnicodeIdString - a string to put the results into.
689 STATUS_SUCCCESS if successful
691 STATUS_NOT_IMPLEMENTED if the IdType is not one supported by this routine
693 error status otherwise.
698 ANSI_STRING ansiIdString
;
705 if(IdType
== BusQueryDeviceID
) {
707 if((Pdo
->Characteristics
& FILE_REMOVABLE_MEDIA
) == 0) {
708 RtlInitAnsiString(&ansiIdString
, "STORAGE\\Partition");
709 return RtlAnsiStringToUnicodeString(UnicodeIdString
, &ansiIdString
, TRUE
);
712 RtlInitAnsiString(&ansiIdString
,
713 "STORAGE\\RemovableMedia");
715 return RtlAnsiStringToUnicodeString(UnicodeIdString
, &ansiIdString
, TRUE
);
718 if(IdType
== BusQueryInstanceID
) {
720 PPHYSICAL_DEVICE_EXTENSION pdoExtension
= Pdo
->DeviceExtension
;
721 PCOMMON_DEVICE_EXTENSION commonExtension
= Pdo
->DeviceExtension
;
722 PDISK_DATA diskData
= commonExtension
->PartitionZeroExtension
->CommonExtension
.DriverData
;
726 if((Pdo
->Characteristics
& FILE_REMOVABLE_MEDIA
) == 0) {
728 if (diskData
->PartitionStyle
== PARTITION_STYLE_MBR
) {
729 sprintf(string
, "S%08lx_O%I64lx_L%I64lx",
730 diskData
->Mbr
.Signature
,
731 commonExtension
->StartingOffset
,
732 commonExtension
->PartitionLength
);
735 "S%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02xS_O%I64lx_L%I64lx",
736 diskData
->Efi
.DiskId
.Data1
,
737 diskData
->Efi
.DiskId
.Data2
,
738 diskData
->Efi
.DiskId
.Data3
,
739 diskData
->Efi
.DiskId
.Data4
[0],
740 diskData
->Efi
.DiskId
.Data4
[1],
741 diskData
->Efi
.DiskId
.Data4
[2],
742 diskData
->Efi
.DiskId
.Data4
[3],
743 diskData
->Efi
.DiskId
.Data4
[4],
744 diskData
->Efi
.DiskId
.Data4
[5],
745 diskData
->Efi
.DiskId
.Data4
[6],
746 diskData
->Efi
.DiskId
.Data4
[7],
747 commonExtension
->StartingOffset
,
748 commonExtension
->PartitionLength
);
751 sprintf(string
, "RM");
754 RtlInitAnsiString(&ansiIdString
, string
);
756 return RtlAnsiStringToUnicodeString(UnicodeIdString
, &ansiIdString
, TRUE
);
759 if((IdType
== BusQueryHardwareIDs
) || (IdType
== BusQueryCompatibleIDs
)) {
761 RtlInitAnsiString(&ansiIdString
, "STORAGE\\Volume");
763 UnicodeIdString
->MaximumLength
= (USHORT
) RtlAnsiStringToUnicodeSize(&ansiIdString
) + sizeof(UNICODE_NULL
);
765 UnicodeIdString
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
766 UnicodeIdString
->MaximumLength
,
769 if(UnicodeIdString
->Buffer
== NULL
) {
770 return STATUS_INSUFFICIENT_RESOURCES
;
773 RtlZeroMemory(UnicodeIdString
->Buffer
, UnicodeIdString
->MaximumLength
);
775 return RtlAnsiStringToUnicodeString(UnicodeIdString
,
780 return STATUS_NOT_IMPLEMENTED
;
785 DiskGenerateDeviceName(
787 IN ULONG DeviceNumber
,
788 IN OPTIONAL ULONG PartitionNumber
,
789 IN OPTIONAL PLARGE_INTEGER StartingOffset
,
790 IN OPTIONAL PLARGE_INTEGER PartitionLength
,
798 This routine will allocate a unicode string buffer and then fill it in
799 with a generated name for the specified device object.
801 It is the responsibility of the user to allocate a UNICODE_STRING structure
802 to pass in and to free UnicodeName->Buffer when done with it.
806 DeviceObject - a pointer to the device object
808 UnicodeName - a unicode string to put the name buffer into
816 //#define PDO_NAME_FORMAT "\\Device\\Harddisk%d\\DP(%d)%d"
817 #define PDO_NAME_FORMAT "\\Device\\Harddisk%d\\DP(%d)%#I64x-%#I64x+%lx"
818 #define FDO_NAME_FORMAT "\\Device\\Harddisk%d\\DR%d"
820 //#define PDO_NAME_FORMAT (PDO_BASE_NAME "+%#I64x+%#I64x+%#lx")
824 static ULONG diskDeviceSequenceNumber
= 0;
830 ASSERT(ARGUMENT_PRESENT((PVOID
)(ULONG_PTR
) PartitionNumber
));
831 ASSERT(ARGUMENT_PRESENT(PartitionLength
));
832 ASSERT(ARGUMENT_PRESENT(StartingOffset
));
834 sprintf(rawName
, PDO_NAME_FORMAT
, DeviceNumber
, PartitionNumber
,
835 StartingOffset
->QuadPart
,
836 PartitionLength
->QuadPart
,
837 diskDeviceSequenceNumber
++);
840 ASSERT(!ARGUMENT_PRESENT((PVOID
)(ULONG_PTR
) PartitionNumber
));
841 ASSERT(!ARGUMENT_PRESENT(PartitionLength
));
842 ASSERT(!ARGUMENT_PRESENT(StartingOffset
));
844 sprintf(rawName
, FDO_NAME_FORMAT
, DeviceNumber
,
845 diskDeviceSequenceNumber
++);
849 *RawName
= ExAllocatePoolWithTag(PagedPool
,
853 if(*RawName
== NULL
) {
854 return STATUS_INSUFFICIENT_RESOURCES
;
857 strcpy(*RawName
, rawName
);
859 DebugPrint((2, "DiskGenerateDeviceName: generated \"%s\"\n", rawName
));
861 return STATUS_SUCCESS
;
866 DiskCreateSymbolicLinks(
867 IN PDEVICE_OBJECT DeviceObject
874 This routine will generate a symbolic link for the specified device object
875 using the well known form \\Device\HarddiskX\PartitionY, where X and Y are
876 filled in using the partition information in the device object's extension.
878 This routine will not try to delete any previous symbolic link for the
879 same generated name - the caller must make sure the symbolic link has
880 been broken before calling this routine.
884 DeviceObject - the device object to make a well known name for
893 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
895 PDISK_DATA diskData
= commonExtension
->DriverData
;
897 WCHAR wideSourceName
[64];
898 UNICODE_STRING unicodeSourceName
;
905 // Build the destination for the link first using the device name
906 // stored in the device object
909 ASSERT(commonExtension
->DeviceName
.Buffer
);
911 if(!diskData
->LinkStatus
.WellKnownNameCreated
) {
913 // Put together the source name using the partition and device number
914 // in the device extension and disk data segment
917 swprintf(wideSourceName
, L
"\\Device\\Harddisk%d\\Partition%d",
918 commonExtension
->PartitionZeroExtension
->DeviceNumber
,
919 (commonExtension
->IsFdo
?
921 commonExtension
->PartitionNumber
));
923 RtlInitUnicodeString(&unicodeSourceName
, wideSourceName
);
925 DebugPrint((1, "DiskCreateSymbolicLink: Linking %wZ to %wZ\n",
927 &commonExtension
->DeviceName
));
929 status
= IoCreateSymbolicLink(&unicodeSourceName
,
930 &commonExtension
->DeviceName
);
934 if((status
== STATUS_OBJECT_NAME_EXISTS
) ||
935 (status
== STATUS_OBJECT_NAME_COLLISION
)) {
937 DebugPrint((1, "DiskCreateSymbolicLink: name %wZ already exists\n",
938 &unicodeSourceName
));
942 if(NT_SUCCESS(status
)){
943 diskData
->LinkStatus
.WellKnownNameCreated
= TRUE
;
947 if((!diskData
->LinkStatus
.PhysicalDriveLinkCreated
) &&
948 (commonExtension
->IsFdo
)) {
951 // Create a physical drive N link using the device number we saved
952 // away during AddDevice.
955 swprintf(wideSourceName
,
956 L
"\\DosDevices\\PhysicalDrive%d",
957 commonExtension
->PartitionZeroExtension
->DeviceNumber
);
959 RtlInitUnicodeString(&unicodeSourceName
, wideSourceName
);
961 DebugPrint((1, "DiskCreateSymbolicLink: Linking %wZ to %wZ\n",
963 &(commonExtension
->DeviceName
)));
965 status
= IoCreateSymbolicLink(&unicodeSourceName
,
966 &(commonExtension
->DeviceName
));
970 if((status
== STATUS_OBJECT_NAME_EXISTS
) ||
971 (status
== STATUS_OBJECT_NAME_COLLISION
)) {
973 DebugPrint((1, "DiskCreateSymbolicLink: name %wZ already exists\n",
974 &unicodeSourceName
));
978 if(NT_SUCCESS(status
)) {
979 diskData
->LinkStatus
.PhysicalDriveLinkCreated
= TRUE
;
981 } else if(commonExtension
->IsFdo
== FALSE
) {
982 diskData
->LinkStatus
.PhysicalDriveLinkCreated
= FALSE
;
990 DiskDeleteSymbolicLinks(
991 IN PDEVICE_OBJECT DeviceObject
998 This routine will delete the well known name (symlink) for the specified
999 device. It generates the link name using information stored in the
1004 DeviceObject - the device object we are unlinking
1013 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1014 PDISK_DATA diskData
= commonExtension
->DriverData
;
1016 WCHAR wideLinkName
[64];
1017 UNICODE_STRING unicodeLinkName
;
1021 if(diskData
->LinkStatus
.WellKnownNameCreated
) {
1023 swprintf(wideLinkName
,
1024 L
"\\Device\\Harddisk%d\\Partition%d",
1025 commonExtension
->PartitionZeroExtension
->DeviceNumber
,
1026 (commonExtension
->IsFdo
? 0 :
1027 commonExtension
->PartitionNumber
));
1029 RtlInitUnicodeString(&unicodeLinkName
, wideLinkName
);
1031 IoDeleteSymbolicLink(&unicodeLinkName
);
1033 diskData
->LinkStatus
.WellKnownNameCreated
= FALSE
;
1036 if(diskData
->LinkStatus
.PhysicalDriveLinkCreated
) {
1038 ASSERT_FDO(DeviceObject
);
1040 swprintf(wideLinkName
,
1041 L
"\\DosDevices\\PhysicalDrive%d",
1042 commonExtension
->PartitionZeroExtension
->DeviceNumber
);
1044 RtlInitUnicodeString(&unicodeLinkName
, wideLinkName
);
1046 IoDeleteSymbolicLink(&unicodeLinkName
);
1048 diskData
->LinkStatus
.PhysicalDriveLinkCreated
= FALSE
;
1057 IN PDEVICE_OBJECT DeviceObject
,
1063 Routine Description:
1065 This routine will release any resources the device may have allocated for
1066 this device object and return.
1070 DeviceObject - the device object being removed
1079 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1080 PDISK_DATA diskData
= commonExtension
->DriverData
;
1085 // Handle query and cancel
1088 if((Type
== IRP_MN_QUERY_REMOVE_DEVICE
) ||
1089 (Type
== IRP_MN_CANCEL_REMOVE_DEVICE
)) {
1090 return STATUS_SUCCESS
;
1093 if(commonExtension
->IsFdo
) {
1095 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
=
1096 DeviceObject
->DeviceExtension
;
1099 // Purge the cached partition table (if any).
1102 DiskAcquirePartitioningLock(fdoExtension
);
1103 DiskInvalidatePartitionTable(fdoExtension
, TRUE
);
1104 DiskReleasePartitioningLock(fdoExtension
);
1107 // Delete our object directory.
1110 if(fdoExtension
->AdapterDescriptor
) {
1111 ExFreePool(fdoExtension
->AdapterDescriptor
);
1112 fdoExtension
->AdapterDescriptor
= NULL
;
1115 if(fdoExtension
->DeviceDescriptor
) {
1116 ExFreePool(fdoExtension
->DeviceDescriptor
);
1117 fdoExtension
->DeviceDescriptor
= NULL
;
1120 if(fdoExtension
->SenseData
) {
1121 ExFreePool(fdoExtension
->SenseData
);
1122 fdoExtension
->SenseData
= NULL
;
1125 if(fdoExtension
->DeviceDirectory
!= NULL
) {
1126 ZwMakeTemporaryObject(fdoExtension
->DeviceDirectory
);
1127 ZwClose(fdoExtension
->DeviceDirectory
);
1128 fdoExtension
->DeviceDirectory
= NULL
;
1131 if(Type
== IRP_MN_REMOVE_DEVICE
) {
1132 IoGetConfigurationInformation()->DiskCount
--;
1137 PPHYSICAL_DEVICE_EXTENSION pdoExtension
= DeviceObject
->DeviceExtension
;
1141 DiskDeleteSymbolicLinks(DeviceObject
);
1144 // Release the mounted device interface if we've set it.
1147 if(diskData
->PartitionInterfaceString
.Buffer
!= NULL
) {
1148 IoSetDeviceInterfaceState(&(diskData
->PartitionInterfaceString
), FALSE
);
1149 RtlFreeUnicodeString(&(diskData
->PartitionInterfaceString
));
1150 RtlInitUnicodeString(&(diskData
->PartitionInterfaceString
), NULL
);
1152 if(diskData
->DiskInterfaceString
.Buffer
!= NULL
) {
1153 IoSetDeviceInterfaceState(&(diskData
->DiskInterfaceString
), FALSE
);
1154 RtlFreeUnicodeString(&(diskData
->DiskInterfaceString
));
1155 RtlInitUnicodeString(&(diskData
->DiskInterfaceString
), NULL
);
1158 ClassDeleteSrbLookasideList(commonExtension
);
1159 return STATUS_SUCCESS
;
1166 IN PDEVICE_OBJECT Fdo
1171 Routine Description:
1173 This routine will query the underlying device for any information necessary
1174 to complete initialization of the device. This will include physical
1175 disk geometry, mode sense information and such.
1177 This routine does not perform partition enumeration - that is left to the
1178 re-enumeration routine
1180 If this routine fails it will return an error value. It does not clean up
1181 any resources - that is left for the Stop/Remove routine.
1185 Fdo - a pointer to the functional device object for this device
1194 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
1195 PCOMMON_DEVICE_EXTENSION commonExtension
= &(fdoExtension
->CommonExtension
);
1196 PDISK_DATA diskData
= commonExtension
->DriverData
;
1197 STORAGE_HOTPLUG_INFO hotplugInfo
;
1198 ULONG writeCacheOverride
= DiskWriteCacheDefault
;
1199 DISK_CACHE_INFORMATION cacheInfo
;
1205 // Get the hotplug information, so we can turn off write cache if needed
1207 // NOTE: Capabilities info is not good enough to determine hotplugedness
1208 // as we cannot determine device relations information and other
1209 // dependencies. Get the hotplug info instead
1215 IO_STATUS_BLOCK statusBlock
;
1217 KeInitializeEvent(&event
, SynchronizationEvent
, FALSE
);
1218 RtlZeroMemory(&hotplugInfo
, sizeof(STORAGE_HOTPLUG_INFO
));
1220 irp
= IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_HOTPLUG_INFO
,
1225 sizeof(STORAGE_HOTPLUG_INFO
),
1232 // send to self -- classpnp handles this
1233 status
= IoCallDriver(Fdo
, irp
);
1234 if (status
== STATUS_PENDING
) {
1235 KeWaitForSingleObject(&event
,
1240 status
= statusBlock
.Status
;
1246 // Clear the DEV_WRITE_CACHE flag now and set
1247 // it below only if we read that from the disk
1250 CLEAR_FLAG(fdoExtension
->DeviceFlags
, DEV_WRITE_CACHE
);
1252 if (TEST_FLAG(fdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_DISABLE_WRITE_CACHE
))
1255 // This flag overrides the user's setting, because faulty firmware
1256 // may cause the filesystem to refuse to format media on this device
1259 "DiskStartFdo: Shutting off write cache for %p due to %s\n",
1261 "Possible Firmware Issue"));
1263 writeCacheOverride
= DiskWriteCacheDisable
;
1268 // Look into the registry to see if the user
1269 // has chosen to override the default setting
1271 ClassGetDeviceParameter(fdoExtension
,
1272 DiskDeviceParameterSubkey
,
1273 DiskDeviceUserWriteCacheSetting
,
1274 &writeCacheOverride
);
1276 if (writeCacheOverride
== DiskWriteCacheDefault
)
1279 // The user has not overridden the default settings
1281 if (hotplugInfo
.DeviceHotplug
&& !hotplugInfo
.WriteCacheEnableOverride
)
1284 "DiskStartFdo: Shutting off write cache for %p due to %s\n",
1288 writeCacheOverride
= DiskWriteCacheDisable
;
1290 else if (hotplugInfo
.MediaHotplug
)
1293 "DiskStartFdo: Shutting off write cache for %p due to %s\n",
1295 "Hotplug (unlockable) Media"));
1297 writeCacheOverride
= DiskWriteCacheDisable
;
1302 // We enable write cache if this device has no specific issues
1304 writeCacheOverride
= DiskWriteCacheEnable
;
1310 // Query the disk to see if write cache is enabled
1311 // and set the DEV_WRITE_CACHE flag appropriately
1314 RtlZeroMemory(&cacheInfo
, sizeof(DISK_CACHE_INFORMATION
));
1316 status
= DiskGetCacheInformation(fdoExtension
, &cacheInfo
);
1318 if (NT_SUCCESS(status
))
1320 if (cacheInfo
.WriteCacheEnabled
== TRUE
)
1322 if (writeCacheOverride
== DiskWriteCacheDisable
)
1325 // Write cache is currently enabled on this
1326 // device, but we would like to turn it off
1328 cacheInfo
.WriteCacheEnabled
= FALSE
;
1330 status
= DiskSetCacheInformation(fdoExtension
, &cacheInfo
);
1335 // The write cache setting either matches
1336 // our needs or we don't care
1338 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_WRITE_CACHE
);
1343 if (writeCacheOverride
== DiskWriteCacheEnable
)
1346 // Write cache is currently disabled on this
1347 // device, but we would like to turn it on
1349 cacheInfo
.WriteCacheEnabled
= TRUE
;
1351 status
= DiskSetCacheInformation(fdoExtension
, &cacheInfo
);
1353 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_WRITE_CACHE
);
1359 // In the event that there's a cached partition table flush it now.
1362 DiskAcquirePartitioningLock(fdoExtension
);
1363 DiskInvalidatePartitionTable(fdoExtension
, TRUE
);
1364 DiskReleasePartitioningLock(fdoExtension
);
1367 // Get the SCSI address if it's available for use with SMART ioctls.
1373 IO_STATUS_BLOCK statusBlock
;
1375 KeInitializeEvent(&event
, SynchronizationEvent
, FALSE
);
1377 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_ADDRESS
,
1378 commonExtension
->LowerDeviceObject
,
1381 &(diskData
->ScsiAddress
),
1382 sizeof(SCSI_ADDRESS
),
1390 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, irp
);
1392 if(status
== STATUS_PENDING
) {
1393 KeWaitForSingleObject(&event
,
1398 status
= statusBlock
.Status
;
1403 return STATUS_SUCCESS
;
1405 } // end DiskStartFdo()