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()
191 IN PDEVICE_OBJECT Fdo
198 This routine is called to do one-time initialization of new device objects
203 Fdo - a pointer to the functional device object for this device
212 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
214 PDISK_DATA diskData
= (PDISK_DATA
) fdoExtension
->CommonExtension
.DriverData
;
216 //ULONG srbFlags = 0;
220 ULONG bytesPerSector
;
223 //BOOLEAN dmActive = FALSE;
232 // Build the lookaside list for srb's for the physical disk. Should only
233 // need a couple. If this fails then we don't have an emergency SRB so
234 // fail the call to initialize.
237 ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION
) fdoExtension
,
238 PARTITION0_LIST_SIZE
);
241 // Because all requests share a common sense buffer, it is possible
242 // for the buffer to be overwritten if the port driver completes
243 // multiple failed requests that require a request sense before the
244 // class driver's completion routine can consume the data in the buffer.
245 // To prevent this, we allow the port driver to allocate a unique sense
246 // buffer each time it needs one. We are responsible for freeing this
247 // buffer. This also allows the adapter to be configured to support
248 // additional sense data beyond the minimum 18 bytes.
251 fdoExtension
->SrbFlags
= SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
;
254 // Initialize the srb flags.
257 if (fdoExtension
->DeviceDescriptor
->CommandQueueing
&&
258 fdoExtension
->AdapterDescriptor
->CommandQueueing
) {
260 fdoExtension
->SrbFlags
= SRB_FLAGS_QUEUE_ACTION_ENABLE
;
264 if (!TEST_FLAG(Fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
265 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
269 // Look for controllers that require special flags.
272 ClassScanForSpecial(fdoExtension
, DiskBadControllers
, DiskSetSpecialHacks
);
275 // Look into the registry to see if this device
276 // requires special attention - [ like a hack ]
279 DiskScanRegistryForSpecial(fdoExtension
);
281 //srbFlags = fdoExtension->SrbFlags;
284 // Clear buffer for drive geometry.
287 RtlZeroMemory(&(fdoExtension
->DiskGeometry
),
288 sizeof(DISK_GEOMETRY
));
291 // Allocate request sense buffer.
294 fdoExtension
->SenseData
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
298 if (fdoExtension
->SenseData
== NULL
) {
301 // The buffer can not be allocated.
304 DebugPrint((1, "DiskInitFdo: Can not allocate request sense buffer\n"));
306 status
= STATUS_INSUFFICIENT_RESOURCES
;
311 // Physical device object will describe the entire
312 // device, starting at byte offset 0.
315 fdoExtension
->CommonExtension
.StartingOffset
.QuadPart
= (LONGLONG
)(0);
318 // Set timeout value in seconds.
321 timeOut
= ClassQueryTimeOutRegistryValue(Fdo
);
323 fdoExtension
->TimeOutValue
= timeOut
;
325 fdoExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
329 // If this is a removable drive, build an entry in devicemap\scsi
330 // indicating it's physicaldriveN name, set up the appropriate
331 // update partitions routine and set the flags correctly.
332 // note: only do this after the timeout value is set, above.
335 if (fdoExtension
->DeviceDescriptor
->RemovableMedia
) {
336 ClassUpdateInformationInRegistry( Fdo
,
338 fdoExtension
->DeviceNumber
,
342 // Enable media change notification for removable disks
344 ClassInitializeMediaChangeDetection(fdoExtension
,
347 SET_FLAG(Fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
);
348 diskData
->UpdatePartitionRoutine
= DiskUpdateRemovablePartitions
;
352 SET_FLAG(fdoExtension
->SrbFlags
, SRB_FLAGS_NO_QUEUE_FREEZE
);
353 diskData
->UpdatePartitionRoutine
= DiskUpdatePartitions
;
358 // Read the drive capacity. Don't use the disk version of the routine here
359 // since we don't know the disk signature yet - the disk version will
360 // attempt to determine the BIOS reported geometry.
363 status
= ClassReadDriveCapacity(Fdo
);
366 // If the read capcity failed then just return, unless this is a
367 // removable disk where a device object partition needs to be created.
370 if (!NT_SUCCESS(status
) &&
371 !(Fdo
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
374 "DiskInitFdo: Can't read capacity for device %p\n",
377 if (fdoExtension
->DeviceDescriptor
->RemovableMedia
) {
378 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;
379 Fdo
->Flags
&= ~DO_VERIFY_VOLUME
;
381 fdoExtension
->DiskGeometry
.MediaType
= FixedMedia
;
384 status
= STATUS_SUCCESS
;
388 // Set up sector size fields.
390 // Stack variables will be used to update
391 // the partition device extensions.
393 // The device extension field SectorShift is
394 // used to calculate sectors in I/O transfers.
396 // The DiskGeometry structure is used to service
397 // IOCTls used by the format utility.
400 bytesPerSector
= fdoExtension
->DiskGeometry
.BytesPerSector
;
403 // Make sure sector size is not zero.
406 if (bytesPerSector
== 0) {
409 // Default sector size for disk is 512.
412 bytesPerSector
= fdoExtension
->DiskGeometry
.BytesPerSector
= 512;
415 //sectorShift = fdoExtension->SectorShift;
418 // Determine is DM Driver is loaded on an IDE drive that is
419 // under control of Atapi - this could be either a crashdump or
420 // an Atapi device is sharing the controller with an IDE disk.
423 HalExamineMBR(fdoExtension
->CommonExtension
.DeviceObject
,
424 fdoExtension
->DiskGeometry
.BytesPerSector
,
431 // Update the device extension, so that the call to IoReadPartitionTable
432 // will get the correct information. Any I/O to this disk will have
433 // to be skewed by *dmSkew sectors aka DMByteSkew.
436 fdoExtension
->DMSkew
= *dmSkew
;
437 fdoExtension
->DMActive
= TRUE
;
438 fdoExtension
->DMByteSkew
= fdoExtension
->DMSkew
* bytesPerSector
;
441 // Save away the infomation that we need, since this deviceExtension will soon be
446 //dmByteSkew = fdoExtension->DMByteSkew;
452 // Try to read the signature off the disk and determine the correct drive
453 // geometry based on that. This requires rereading the disk size to get
454 // the cylinder count updated correctly.
457 if(fdoExtension
->DeviceDescriptor
->RemovableMedia
== FALSE
) {
458 DiskReadSignature(Fdo
);
459 DiskReadDriveCapacity(Fdo
);
464 // Register interfaces for this device
467 UNICODE_STRING interfaceName
;
469 RtlInitUnicodeString(&interfaceName
, NULL
);
471 status
= IoRegisterDeviceInterface(fdoExtension
->LowerPdo
,
472 (LPGUID
) &DiskClassGuid
,
476 if(NT_SUCCESS(status
)) {
478 diskData
->DiskInterfaceString
= interfaceName
;
479 status
= IoSetDeviceInterfaceState(&interfaceName
, TRUE
);
482 interfaceName
.Buffer
= NULL
;
485 if(!NT_SUCCESS(status
)) {
487 DebugPrint((1, "DiskInitFdo: Unable to register or set disk DCA "
488 "for fdo %p [%lx]\n", Fdo
, status
));
490 RtlFreeUnicodeString(&interfaceName
);
491 RtlInitUnicodeString(&(diskData
->DiskInterfaceString
), NULL
);
495 DiskCreateSymbolicLinks(Fdo
);
498 // Determine the type of disk and enable failure preiction in the hardware
499 // and enable failure prediction polling.
502 if (InitSafeBootMode
== 0)
504 DiskDetectFailurePrediction(fdoExtension
,
505 &diskData
->FailurePredictionCapability
);
507 if (diskData
->FailurePredictionCapability
!= FailurePredictionNone
)
510 // Cool, we've got some sort of failure prediction, enable it
511 // at the hardware and then enable polling for it
515 // By default we allow performance to be degradeded if failure
516 // prediction is enabled.
518 // TODO: Make a registry entry ?
521 diskData
->AllowFPPerfHit
= TRUE
;
524 // Enable polling only after Atapi and SBP2 add support for the new
525 // SRB flag that indicates that the request should not reset the
526 // drive spin down idle timer.
529 status
= DiskEnableDisableFailurePredictPolling(fdoExtension
,
531 DISK_DEFAULT_FAILURE_POLLING_PERIOD
);
533 DebugPrint((3, "DiskInitFdo: Failure Prediction Poll enabled as "
534 "%d for device %p\n",
535 diskData
->FailurePredictionCapability
,
541 // In safe boot mode we do not enable failure prediction, as perhaps
542 // it is the reason why normal boot does not work
545 diskData
->FailurePredictionCapability
= FailurePredictionNone
;
550 // Initialize the verify mutex
553 KeInitializeMutex(&diskData
->VerifyMutex
, MAX_SECTORS_PER_VERIFY
);
555 return(STATUS_SUCCESS
);
557 } // end DiskInitFdo()
562 IN PDEVICE_OBJECT Pdo
569 This routine will create the well known names for a PDO and register
570 it's device interfaces.
575 PCOMMON_DEVICE_EXTENSION pdoExtension
= Pdo
->DeviceExtension
;
576 PDISK_DATA diskData
= pdoExtension
->DriverData
;
578 UNICODE_STRING interfaceName
;
584 DiskCreateSymbolicLinks(Pdo
);
587 // Register interfaces for this device
590 RtlInitUnicodeString(&interfaceName
, NULL
);
592 status
= IoRegisterDeviceInterface(Pdo
,
593 (LPGUID
) &PartitionClassGuid
,
597 if(NT_SUCCESS(status
)) {
599 diskData
->PartitionInterfaceString
= interfaceName
;
600 status
= IoSetDeviceInterfaceState(&interfaceName
, TRUE
);
603 interfaceName
.Buffer
= NULL
;
606 if(!NT_SUCCESS(status
)) {
607 DebugPrint((1, "DiskInitPdo: Unable to register partition DCA for "
608 "pdo %p [%lx]\n", Pdo
, status
));
610 RtlFreeUnicodeString(&interfaceName
);
611 RtlInitUnicodeString(&(diskData
->PartitionInterfaceString
), NULL
);
614 return STATUS_SUCCESS
;
620 IN PDEVICE_OBJECT Pdo
627 This routine will create the well known names for a PDO and register
628 it's device interfaces.
635 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()