3 Copyright (C) Microsoft Corporation, 1991 - 1999
11 SCSI disk class driver
25 extern NTSYSAPI ULONG 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()
192 IN PDEVICE_OBJECT Fdo
199 This routine is called to do one-time initialization of new device objects
204 Fdo - a pointer to the functional device object for this device
213 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
215 PDISK_DATA diskData
= (PDISK_DATA
) fdoExtension
->CommonExtension
.DriverData
;
221 ULONG bytesPerSector
;
224 BOOLEAN dmActive
= FALSE
;
233 // Build the lookaside list for srb's for the physical disk. Should only
234 // need a couple. If this fails then we don't have an emergency SRB so
235 // fail the call to initialize.
238 ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION
) fdoExtension
,
239 PARTITION0_LIST_SIZE
);
242 // Because all requests share a common sense buffer, it is possible
243 // for the buffer to be overwritten if the port driver completes
244 // multiple failed requests that require a request sense before the
245 // class driver's completion routine can consume the data in the buffer.
246 // To prevent this, we allow the port driver to allocate a unique sense
247 // buffer each time it needs one. We are responsible for freeing this
248 // buffer. This also allows the adapter to be configured to support
249 // additional sense data beyond the minimum 18 bytes.
252 fdoExtension
->SrbFlags
= SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
;
255 // Initialize the srb flags.
258 if (fdoExtension
->DeviceDescriptor
->CommandQueueing
&&
259 fdoExtension
->AdapterDescriptor
->CommandQueueing
) {
261 fdoExtension
->SrbFlags
= SRB_FLAGS_QUEUE_ACTION_ENABLE
;
265 if (!TEST_FLAG(Fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
266 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
270 // Look for controllers that require special flags.
273 ClassScanForSpecial(fdoExtension
, DiskBadControllers
, DiskSetSpecialHacks
);
276 // Look into the registry to see if this device
277 // requires special attention - [ like a hack ]
280 DiskScanRegistryForSpecial(fdoExtension
);
282 srbFlags
= fdoExtension
->SrbFlags
;
285 // Clear buffer for drive geometry.
288 RtlZeroMemory(&(fdoExtension
->DiskGeometry
),
289 sizeof(DISK_GEOMETRY
));
292 // Allocate request sense buffer.
295 fdoExtension
->SenseData
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
299 if (fdoExtension
->SenseData
== NULL
) {
302 // The buffer can not be allocated.
305 DebugPrint((1, "DiskInitFdo: Can not allocate request sense buffer\n"));
307 status
= STATUS_INSUFFICIENT_RESOURCES
;
312 // Physical device object will describe the entire
313 // device, starting at byte offset 0.
316 fdoExtension
->CommonExtension
.StartingOffset
.QuadPart
= (LONGLONG
)(0);
319 // Set timeout value in seconds.
322 timeOut
= ClassQueryTimeOutRegistryValue(Fdo
);
324 fdoExtension
->TimeOutValue
= timeOut
;
326 fdoExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
330 // If this is a removable drive, build an entry in devicemap\scsi
331 // indicating it's physicaldriveN name, set up the appropriate
332 // update partitions routine and set the flags correctly.
333 // note: only do this after the timeout value is set, above.
336 if (fdoExtension
->DeviceDescriptor
->RemovableMedia
) {
337 ClassUpdateInformationInRegistry( Fdo
,
339 fdoExtension
->DeviceNumber
,
343 // Enable media change notification for removable disks
345 ClassInitializeMediaChangeDetection(fdoExtension
,
348 SET_FLAG(Fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
);
349 diskData
->UpdatePartitionRoutine
= DiskUpdateRemovablePartitions
;
353 SET_FLAG(fdoExtension
->SrbFlags
, SRB_FLAGS_NO_QUEUE_FREEZE
);
354 diskData
->UpdatePartitionRoutine
= DiskUpdatePartitions
;
359 // Read the drive capacity. Don't use the disk version of the routine here
360 // since we don't know the disk signature yet - the disk version will
361 // attempt to determine the BIOS reported geometry.
364 status
= ClassReadDriveCapacity(Fdo
);
367 // If the read capcity failed then just return, unless this is a
368 // removable disk where a device object partition needs to be created.
371 if (!NT_SUCCESS(status
) &&
372 !(Fdo
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
375 "DiskInitFdo: Can't read capacity for device %p\n",
378 if (fdoExtension
->DeviceDescriptor
->RemovableMedia
) {
379 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;
380 Fdo
->Flags
&= ~DO_VERIFY_VOLUME
;
382 fdoExtension
->DiskGeometry
.MediaType
= FixedMedia
;
385 status
= STATUS_SUCCESS
;
389 // Set up sector size fields.
391 // Stack variables will be used to update
392 // the partition device extensions.
394 // The device extension field SectorShift is
395 // used to calculate sectors in I/O transfers.
397 // The DiskGeometry structure is used to service
398 // IOCTls used by the format utility.
401 bytesPerSector
= fdoExtension
->DiskGeometry
.BytesPerSector
;
404 // Make sure sector size is not zero.
407 if (bytesPerSector
== 0) {
410 // Default sector size for disk is 512.
413 bytesPerSector
= fdoExtension
->DiskGeometry
.BytesPerSector
= 512;
416 sectorShift
= fdoExtension
->SectorShift
;
419 // Determine is DM Driver is loaded on an IDE drive that is
420 // under control of Atapi - this could be either a crashdump or
421 // an Atapi device is sharing the controller with an IDE disk.
424 HalExamineMBR(fdoExtension
->CommonExtension
.DeviceObject
,
425 fdoExtension
->DiskGeometry
.BytesPerSector
,
432 // Update the device extension, so that the call to IoReadPartitionTable
433 // will get the correct information. Any I/O to this disk will have
434 // to be skewed by *dmSkew sectors aka DMByteSkew.
437 fdoExtension
->DMSkew
= *dmSkew
;
438 fdoExtension
->DMActive
= TRUE
;
439 fdoExtension
->DMByteSkew
= fdoExtension
->DMSkew
* bytesPerSector
;
442 // Save away the infomation that we need, since this deviceExtension will soon be
447 dmByteSkew
= fdoExtension
->DMByteSkew
;
453 // Try to read the signature off the disk and determine the correct drive
454 // geometry based on that. This requires rereading the disk size to get
455 // the cylinder count updated correctly.
458 if(fdoExtension
->DeviceDescriptor
->RemovableMedia
== FALSE
) {
459 DiskReadSignature(Fdo
);
460 DiskReadDriveCapacity(Fdo
);
465 // Register interfaces for this device
468 UNICODE_STRING interfaceName
;
470 RtlInitUnicodeString(&interfaceName
, NULL
);
472 status
= IoRegisterDeviceInterface(fdoExtension
->LowerPdo
,
473 (LPGUID
) &DiskClassGuid
,
477 if(NT_SUCCESS(status
)) {
479 diskData
->DiskInterfaceString
= interfaceName
;
480 status
= IoSetDeviceInterfaceState(&interfaceName
, TRUE
);
483 interfaceName
.Buffer
= NULL
;
486 if(!NT_SUCCESS(status
)) {
488 DebugPrint((1, "DiskInitFdo: Unable to register or set disk DCA "
489 "for fdo %p [%lx]\n", Fdo
, status
));
491 RtlFreeUnicodeString(&interfaceName
);
492 RtlInitUnicodeString(&(diskData
->DiskInterfaceString
), NULL
);
496 DiskCreateSymbolicLinks(Fdo
);
499 // Determine the type of disk and enable failure preiction in the hardware
500 // and enable failure prediction polling.
503 if (InitSafeBootMode
== 0)
505 DiskDetectFailurePrediction(fdoExtension
,
506 &diskData
->FailurePredictionCapability
);
508 if (diskData
->FailurePredictionCapability
!= FailurePredictionNone
)
511 // Cool, we've got some sort of failure prediction, enable it
512 // at the hardware and then enable polling for it
516 // By default we allow performance to be degradeded if failure
517 // prediction is enabled.
519 // TODO: Make a registry entry ?
522 diskData
->AllowFPPerfHit
= TRUE
;
525 // Enable polling only after Atapi and SBP2 add support for the new
526 // SRB flag that indicates that the request should not reset the
527 // drive spin down idle timer.
530 status
= DiskEnableDisableFailurePredictPolling(fdoExtension
,
532 DISK_DEFAULT_FAILURE_POLLING_PERIOD
);
534 DebugPrint((3, "DiskInitFdo: Failure Prediction Poll enabled as "
535 "%d for device %p\n",
536 diskData
->FailurePredictionCapability
,
542 // In safe boot mode we do not enable failure prediction, as perhaps
543 // it is the reason why normal boot does not work
546 diskData
->FailurePredictionCapability
= FailurePredictionNone
;
551 // Initialize the verify mutex
554 KeInitializeMutex(&diskData
->VerifyMutex
, MAX_SECTORS_PER_VERIFY
);
556 return(STATUS_SUCCESS
);
558 } // end DiskInitFdo()
563 IN PDEVICE_OBJECT Pdo
570 This routine will create the well known names for a PDO and register
571 it's device interfaces.
576 PCOMMON_DEVICE_EXTENSION pdoExtension
= Pdo
->DeviceExtension
;
577 PDISK_DATA diskData
= pdoExtension
->DriverData
;
579 UNICODE_STRING interfaceName
;
585 DiskCreateSymbolicLinks(Pdo
);
588 // Register interfaces for this device
591 RtlInitUnicodeString(&interfaceName
, NULL
);
593 status
= IoRegisterDeviceInterface(Pdo
,
594 (LPGUID
) &PartitionClassGuid
,
598 if(NT_SUCCESS(status
)) {
600 diskData
->PartitionInterfaceString
= interfaceName
;
601 status
= IoSetDeviceInterfaceState(&interfaceName
, TRUE
);
604 interfaceName
.Buffer
= NULL
;
607 if(!NT_SUCCESS(status
)) {
608 DebugPrint((1, "DiskInitPdo: Unable to register partition DCA for "
609 "pdo %p [%lx]\n", Pdo
, status
));
611 RtlFreeUnicodeString(&interfaceName
);
612 RtlInitUnicodeString(&(diskData
->PartitionInterfaceString
), NULL
);
615 return STATUS_SUCCESS
;
621 IN PDEVICE_OBJECT Pdo
628 This routine will create the well known names for a PDO and register
629 it's device interfaces.
636 return STATUS_SUCCESS
;
641 IN PDEVICE_OBJECT DeviceObject
,
646 PFUNCTIONAL_DEVICE_EXTENSION fdo
= DeviceObject
->DeviceExtension
;
648 if(fdo
->CommonExtension
.IsFdo
) {
649 DiskAcquirePartitioningLock(fdo
);
650 DiskInvalidatePartitionTable(fdo
, TRUE
);
651 DiskReleasePartitioningLock(fdo
);
654 return STATUS_SUCCESS
;
660 IN PDEVICE_OBJECT Pdo
,
661 IN BUS_QUERY_ID_TYPE IdType
,
662 IN PUNICODE_STRING UnicodeIdString
669 This routine generates the PNP id's for the disk's "children". If the
670 specified ID isn't one that the routine can generate it must return
671 STATUS_NOT_IMPLEMENTED so classpnp will know not to do anything with the
672 PNP request's status.
674 This routine allocates the buffer for the UnicodeIdString. It is the
675 caller's responsibility to free the buffer when it's done.
679 Pdo - a pointer to the PDO we are to generate an ID for
681 IdType - the type of ID to be generated
683 UnicodeIdString - a string to put the results into.
687 STATUS_SUCCCESS if successful
689 STATUS_NOT_IMPLEMENTED if the IdType is not one supported by this routine
691 error status otherwise.
696 ANSI_STRING ansiIdString
;
703 if(IdType
== BusQueryDeviceID
) {
705 if((Pdo
->Characteristics
& FILE_REMOVABLE_MEDIA
) == 0) {
706 RtlInitAnsiString(&ansiIdString
, "STORAGE\\Partition");
707 return RtlAnsiStringToUnicodeString(UnicodeIdString
, &ansiIdString
, TRUE
);
710 RtlInitAnsiString(&ansiIdString
,
711 "STORAGE\\RemovableMedia");
713 return RtlAnsiStringToUnicodeString(UnicodeIdString
, &ansiIdString
, TRUE
);
716 if(IdType
== BusQueryInstanceID
) {
718 PPHYSICAL_DEVICE_EXTENSION pdoExtension
= Pdo
->DeviceExtension
;
719 PCOMMON_DEVICE_EXTENSION commonExtension
= Pdo
->DeviceExtension
;
720 PDISK_DATA diskData
= commonExtension
->PartitionZeroExtension
->CommonExtension
.DriverData
;
724 if((Pdo
->Characteristics
& FILE_REMOVABLE_MEDIA
) == 0) {
726 if (diskData
->PartitionStyle
== PARTITION_STYLE_MBR
) {
727 sprintf(string
, "S%08lx_O%I64lx_L%I64lx",
728 diskData
->Mbr
.Signature
,
729 commonExtension
->StartingOffset
,
730 commonExtension
->PartitionLength
);
733 "S%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02xS_O%I64lx_L%I64lx",
734 diskData
->Efi
.DiskId
.Data1
,
735 diskData
->Efi
.DiskId
.Data2
,
736 diskData
->Efi
.DiskId
.Data3
,
737 diskData
->Efi
.DiskId
.Data4
[0],
738 diskData
->Efi
.DiskId
.Data4
[1],
739 diskData
->Efi
.DiskId
.Data4
[2],
740 diskData
->Efi
.DiskId
.Data4
[3],
741 diskData
->Efi
.DiskId
.Data4
[4],
742 diskData
->Efi
.DiskId
.Data4
[5],
743 diskData
->Efi
.DiskId
.Data4
[6],
744 diskData
->Efi
.DiskId
.Data4
[7],
745 commonExtension
->StartingOffset
,
746 commonExtension
->PartitionLength
);
749 sprintf(string
, "RM");
752 RtlInitAnsiString(&ansiIdString
, string
);
754 return RtlAnsiStringToUnicodeString(UnicodeIdString
, &ansiIdString
, TRUE
);
757 if((IdType
== BusQueryHardwareIDs
) || (IdType
== BusQueryCompatibleIDs
)) {
759 RtlInitAnsiString(&ansiIdString
, "STORAGE\\Volume");
761 UnicodeIdString
->MaximumLength
= (USHORT
) RtlAnsiStringToUnicodeSize(&ansiIdString
) + sizeof(UNICODE_NULL
);
763 UnicodeIdString
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
764 UnicodeIdString
->MaximumLength
,
767 if(UnicodeIdString
->Buffer
== NULL
) {
768 return STATUS_INSUFFICIENT_RESOURCES
;
771 RtlZeroMemory(UnicodeIdString
->Buffer
, UnicodeIdString
->MaximumLength
);
773 return RtlAnsiStringToUnicodeString(UnicodeIdString
,
778 return STATUS_NOT_IMPLEMENTED
;
783 DiskGenerateDeviceName(
785 IN ULONG DeviceNumber
,
786 IN OPTIONAL ULONG PartitionNumber
,
787 IN OPTIONAL PLARGE_INTEGER StartingOffset
,
788 IN OPTIONAL PLARGE_INTEGER PartitionLength
,
796 This routine will allocate a unicode string buffer and then fill it in
797 with a generated name for the specified device object.
799 It is the responsibility of the user to allocate a UNICODE_STRING structure
800 to pass in and to free UnicodeName->Buffer when done with it.
804 DeviceObject - a pointer to the device object
806 UnicodeName - a unicode string to put the name buffer into
814 //#define PDO_NAME_FORMAT "\\Device\\Harddisk%d\\DP(%d)%d"
815 #define PDO_NAME_FORMAT "\\Device\\Harddisk%d\\DP(%d)%#I64x-%#I64x+%lx"
816 #define FDO_NAME_FORMAT "\\Device\\Harddisk%d\\DR%d"
818 //#define PDO_NAME_FORMAT (PDO_BASE_NAME "+%#I64x+%#I64x+%#lx")
822 static ULONG diskDeviceSequenceNumber
= 0;
828 ASSERT(ARGUMENT_PRESENT((PVOID
)(ULONG_PTR
) PartitionNumber
));
829 ASSERT(ARGUMENT_PRESENT(PartitionLength
));
830 ASSERT(ARGUMENT_PRESENT(StartingOffset
));
832 sprintf(rawName
, PDO_NAME_FORMAT
, DeviceNumber
, PartitionNumber
,
833 StartingOffset
->QuadPart
,
834 PartitionLength
->QuadPart
,
835 diskDeviceSequenceNumber
++);
838 ASSERT(!ARGUMENT_PRESENT((PVOID
)(ULONG_PTR
) PartitionNumber
));
839 ASSERT(!ARGUMENT_PRESENT(PartitionLength
));
840 ASSERT(!ARGUMENT_PRESENT(StartingOffset
));
842 sprintf(rawName
, FDO_NAME_FORMAT
, DeviceNumber
,
843 diskDeviceSequenceNumber
++);
847 *RawName
= ExAllocatePoolWithTag(PagedPool
,
851 if(*RawName
== NULL
) {
852 return STATUS_INSUFFICIENT_RESOURCES
;
855 strcpy(*RawName
, rawName
);
857 DebugPrint((2, "DiskGenerateDeviceName: generated \"%s\"\n", rawName
));
859 return STATUS_SUCCESS
;
864 DiskCreateSymbolicLinks(
865 IN PDEVICE_OBJECT DeviceObject
872 This routine will generate a symbolic link for the specified device object
873 using the well known form \\Device\HarddiskX\PartitionY, where X and Y are
874 filled in using the partition information in the device object's extension.
876 This routine will not try to delete any previous symbolic link for the
877 same generated name - the caller must make sure the symbolic link has
878 been broken before calling this routine.
882 DeviceObject - the device object to make a well known name for
891 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
893 PDISK_DATA diskData
= commonExtension
->DriverData
;
895 WCHAR wideSourceName
[64];
896 UNICODE_STRING unicodeSourceName
;
903 // Build the destination for the link first using the device name
904 // stored in the device object
907 ASSERT(commonExtension
->DeviceName
.Buffer
);
909 if(!diskData
->LinkStatus
.WellKnownNameCreated
) {
911 // Put together the source name using the partition and device number
912 // in the device extension and disk data segment
915 swprintf(wideSourceName
, L
"\\Device\\Harddisk%d\\Partition%d",
916 commonExtension
->PartitionZeroExtension
->DeviceNumber
,
917 (commonExtension
->IsFdo
?
919 commonExtension
->PartitionNumber
));
921 RtlInitUnicodeString(&unicodeSourceName
, wideSourceName
);
923 DebugPrint((1, "DiskCreateSymbolicLink: Linking %wZ to %wZ\n",
925 &commonExtension
->DeviceName
));
927 status
= IoCreateSymbolicLink(&unicodeSourceName
,
928 &commonExtension
->DeviceName
);
932 if((status
== STATUS_OBJECT_NAME_EXISTS
) ||
933 (status
== STATUS_OBJECT_NAME_COLLISION
)) {
935 DebugPrint((1, "DiskCreateSymbolicLink: name %wZ already exists\n",
936 &unicodeSourceName
));
940 if(NT_SUCCESS(status
)){
941 diskData
->LinkStatus
.WellKnownNameCreated
= TRUE
;
945 if((!diskData
->LinkStatus
.PhysicalDriveLinkCreated
) &&
946 (commonExtension
->IsFdo
)) {
949 // Create a physical drive N link using the device number we saved
950 // away during AddDevice.
953 swprintf(wideSourceName
,
954 L
"\\DosDevices\\PhysicalDrive%d",
955 commonExtension
->PartitionZeroExtension
->DeviceNumber
);
957 RtlInitUnicodeString(&unicodeSourceName
, wideSourceName
);
959 DebugPrint((1, "DiskCreateSymbolicLink: Linking %wZ to %wZ\n",
961 &(commonExtension
->DeviceName
)));
963 status
= IoCreateSymbolicLink(&unicodeSourceName
,
964 &(commonExtension
->DeviceName
));
968 if((status
== STATUS_OBJECT_NAME_EXISTS
) ||
969 (status
== STATUS_OBJECT_NAME_COLLISION
)) {
971 DebugPrint((1, "DiskCreateSymbolicLink: name %wZ already exists\n",
972 &unicodeSourceName
));
976 if(NT_SUCCESS(status
)) {
977 diskData
->LinkStatus
.PhysicalDriveLinkCreated
= TRUE
;
979 } else if(commonExtension
->IsFdo
== FALSE
) {
980 diskData
->LinkStatus
.PhysicalDriveLinkCreated
= FALSE
;
988 DiskDeleteSymbolicLinks(
989 IN PDEVICE_OBJECT DeviceObject
996 This routine will delete the well known name (symlink) for the specified
997 device. It generates the link name using information stored in the
1002 DeviceObject - the device object we are unlinking
1011 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1012 PDISK_DATA diskData
= commonExtension
->DriverData
;
1014 WCHAR wideLinkName
[64];
1015 UNICODE_STRING unicodeLinkName
;
1019 if(diskData
->LinkStatus
.WellKnownNameCreated
) {
1021 swprintf(wideLinkName
,
1022 L
"\\Device\\Harddisk%d\\Partition%d",
1023 commonExtension
->PartitionZeroExtension
->DeviceNumber
,
1024 (commonExtension
->IsFdo
? 0 :
1025 commonExtension
->PartitionNumber
));
1027 RtlInitUnicodeString(&unicodeLinkName
, wideLinkName
);
1029 IoDeleteSymbolicLink(&unicodeLinkName
);
1031 diskData
->LinkStatus
.WellKnownNameCreated
= FALSE
;
1034 if(diskData
->LinkStatus
.PhysicalDriveLinkCreated
) {
1036 ASSERT_FDO(DeviceObject
);
1038 swprintf(wideLinkName
,
1039 L
"\\DosDevices\\PhysicalDrive%d",
1040 commonExtension
->PartitionZeroExtension
->DeviceNumber
);
1042 RtlInitUnicodeString(&unicodeLinkName
, wideLinkName
);
1044 IoDeleteSymbolicLink(&unicodeLinkName
);
1046 diskData
->LinkStatus
.PhysicalDriveLinkCreated
= FALSE
;
1055 IN PDEVICE_OBJECT DeviceObject
,
1061 Routine Description:
1063 This routine will release any resources the device may have allocated for
1064 this device object and return.
1068 DeviceObject - the device object being removed
1077 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1078 PDISK_DATA diskData
= commonExtension
->DriverData
;
1083 // Handle query and cancel
1086 if((Type
== IRP_MN_QUERY_REMOVE_DEVICE
) ||
1087 (Type
== IRP_MN_CANCEL_REMOVE_DEVICE
)) {
1088 return STATUS_SUCCESS
;
1091 if(commonExtension
->IsFdo
) {
1093 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
=
1094 DeviceObject
->DeviceExtension
;
1097 // Purge the cached partition table (if any).
1100 DiskAcquirePartitioningLock(fdoExtension
);
1101 DiskInvalidatePartitionTable(fdoExtension
, TRUE
);
1102 DiskReleasePartitioningLock(fdoExtension
);
1105 // Delete our object directory.
1108 if(fdoExtension
->AdapterDescriptor
) {
1109 ExFreePool(fdoExtension
->AdapterDescriptor
);
1110 fdoExtension
->AdapterDescriptor
= NULL
;
1113 if(fdoExtension
->DeviceDescriptor
) {
1114 ExFreePool(fdoExtension
->DeviceDescriptor
);
1115 fdoExtension
->DeviceDescriptor
= NULL
;
1118 if(fdoExtension
->SenseData
) {
1119 ExFreePool(fdoExtension
->SenseData
);
1120 fdoExtension
->SenseData
= NULL
;
1123 if(fdoExtension
->DeviceDirectory
!= NULL
) {
1124 ZwMakeTemporaryObject(fdoExtension
->DeviceDirectory
);
1125 ZwClose(fdoExtension
->DeviceDirectory
);
1126 fdoExtension
->DeviceDirectory
= NULL
;
1129 if(Type
== IRP_MN_REMOVE_DEVICE
) {
1130 IoGetConfigurationInformation()->DiskCount
--;
1135 PPHYSICAL_DEVICE_EXTENSION pdoExtension
= DeviceObject
->DeviceExtension
;
1139 DiskDeleteSymbolicLinks(DeviceObject
);
1142 // Release the mounted device interface if we've set it.
1145 if(diskData
->PartitionInterfaceString
.Buffer
!= NULL
) {
1146 IoSetDeviceInterfaceState(&(diskData
->PartitionInterfaceString
), FALSE
);
1147 RtlFreeUnicodeString(&(diskData
->PartitionInterfaceString
));
1148 RtlInitUnicodeString(&(diskData
->PartitionInterfaceString
), NULL
);
1150 if(diskData
->DiskInterfaceString
.Buffer
!= NULL
) {
1151 IoSetDeviceInterfaceState(&(diskData
->DiskInterfaceString
), FALSE
);
1152 RtlFreeUnicodeString(&(diskData
->DiskInterfaceString
));
1153 RtlInitUnicodeString(&(diskData
->DiskInterfaceString
), NULL
);
1156 ClassDeleteSrbLookasideList(commonExtension
);
1157 return STATUS_SUCCESS
;
1163 IN PDEVICE_OBJECT Fdo
1168 Routine Description:
1170 This routine will query the underlying device for any information necessary
1171 to complete initialization of the device. This will include physical
1172 disk geometry, mode sense information and such.
1174 This routine does not perform partition enumeration - that is left to the
1175 re-enumeration routine
1177 If this routine fails it will return an error value. It does not clean up
1178 any resources - that is left for the Stop/Remove routine.
1182 Fdo - a pointer to the functional device object for this device
1191 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
1192 PCOMMON_DEVICE_EXTENSION commonExtension
= &(fdoExtension
->CommonExtension
);
1193 PDISK_DATA diskData
= commonExtension
->DriverData
;
1194 STORAGE_HOTPLUG_INFO hotplugInfo
;
1195 ULONG writeCacheOverride
= DiskWriteCacheDefault
;
1196 DISK_CACHE_INFORMATION cacheInfo
;
1202 // Get the hotplug information, so we can turn off write cache if needed
1204 // NOTE: Capabilities info is not good enough to determine hotplugedness
1205 // as we cannot determine device relations information and other
1206 // dependencies. Get the hotplug info instead
1212 IO_STATUS_BLOCK statusBlock
;
1214 KeInitializeEvent(&event
, SynchronizationEvent
, FALSE
);
1215 RtlZeroMemory(&hotplugInfo
, sizeof(STORAGE_HOTPLUG_INFO
));
1217 irp
= IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_HOTPLUG_INFO
,
1222 sizeof(STORAGE_HOTPLUG_INFO
),
1229 // send to self -- classpnp handles this
1230 status
= IoCallDriver(Fdo
, irp
);
1231 if (status
== STATUS_PENDING
) {
1232 KeWaitForSingleObject(&event
,
1237 status
= statusBlock
.Status
;
1243 // Clear the DEV_WRITE_CACHE flag now and set
1244 // it below only if we read that from the disk
1247 CLEAR_FLAG(fdoExtension
->DeviceFlags
, DEV_WRITE_CACHE
);
1249 if (TEST_FLAG(fdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_DISABLE_WRITE_CACHE
))
1252 // This flag overrides the user's setting, because faulty firmware
1253 // may cause the filesystem to refuse to format media on this device
1256 "DiskStartFdo: Shutting off write cache for %p due to %s\n",
1258 "Possible Firmware Issue"));
1260 writeCacheOverride
= DiskWriteCacheDisable
;
1265 // Look into the registry to see if the user
1266 // has chosen to override the default setting
1268 ClassGetDeviceParameter(fdoExtension
,
1269 DiskDeviceParameterSubkey
,
1270 DiskDeviceUserWriteCacheSetting
,
1271 &writeCacheOverride
);
1273 if (writeCacheOverride
== DiskWriteCacheDefault
)
1276 // The user has not overridden the default settings
1278 if (hotplugInfo
.DeviceHotplug
&& !hotplugInfo
.WriteCacheEnableOverride
)
1281 "DiskStartFdo: Shutting off write cache for %p due to %s\n",
1285 writeCacheOverride
= DiskWriteCacheDisable
;
1287 else if (hotplugInfo
.MediaHotplug
)
1290 "DiskStartFdo: Shutting off write cache for %p due to %s\n",
1292 "Hotplug (unlockable) Media"));
1294 writeCacheOverride
= DiskWriteCacheDisable
;
1299 // We enable write cache if this device has no specific issues
1301 writeCacheOverride
= DiskWriteCacheEnable
;
1307 // Query the disk to see if write cache is enabled
1308 // and set the DEV_WRITE_CACHE flag appropriately
1311 RtlZeroMemory(&cacheInfo
, sizeof(DISK_CACHE_INFORMATION
));
1313 status
= DiskGetCacheInformation(fdoExtension
, &cacheInfo
);
1315 if (NT_SUCCESS(status
))
1317 if (cacheInfo
.WriteCacheEnabled
== TRUE
)
1319 if (writeCacheOverride
== DiskWriteCacheDisable
)
1322 // Write cache is currently enabled on this
1323 // device, but we would like to turn it off
1325 cacheInfo
.WriteCacheEnabled
= FALSE
;
1327 status
= DiskSetCacheInformation(fdoExtension
, &cacheInfo
);
1332 // The write cache setting either matches
1333 // our needs or we don't care
1335 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_WRITE_CACHE
);
1340 if (writeCacheOverride
== DiskWriteCacheEnable
)
1343 // Write cache is currently disabled on this
1344 // device, but we would like to turn it on
1346 cacheInfo
.WriteCacheEnabled
= TRUE
;
1348 status
= DiskSetCacheInformation(fdoExtension
, &cacheInfo
);
1350 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_WRITE_CACHE
);
1356 // In the event that there's a cached partition table flush it now.
1359 DiskAcquirePartitioningLock(fdoExtension
);
1360 DiskInvalidatePartitionTable(fdoExtension
, TRUE
);
1361 DiskReleasePartitioningLock(fdoExtension
);
1364 // Get the SCSI address if it's available for use with SMART ioctls.
1370 IO_STATUS_BLOCK statusBlock
;
1372 KeInitializeEvent(&event
, SynchronizationEvent
, FALSE
);
1374 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_ADDRESS
,
1375 commonExtension
->LowerDeviceObject
,
1378 &(diskData
->ScsiAddress
),
1379 sizeof(SCSI_ADDRESS
),
1387 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, irp
);
1389 if(status
== STATUS_PENDING
) {
1390 KeWaitForSingleObject(&event
,
1395 status
= statusBlock
.Status
;
1400 return STATUS_SUCCESS
;
1402 } // end DiskStartFdo()