1 /*++
2
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4
5 Module Name:
6
7 pnp.c
8
9 Abstract:
10
11 SCSI disk class driver
12
13 Environment:
14
15 kernel mode only
16
17 Notes:
18
19 Revision History:
20
21 --*/
22
23 #include "disk.h"
24
25
26 #ifdef DEBUG_USE_WPP
27 #include "pnp.tmh"
28 #endif
29
30 #ifndef __REACTOS__
31 extern PULONG InitSafeBootMode;
32 #else
33 extern NTSYSAPI ULONG InitSafeBootMode;
34 #endif
35 ULONG diskDeviceSequenceNumber = 0;
36 extern BOOLEAN DiskIsPastReinit;
37
38
39 #ifdef ALLOC_PRAGMA
40
41 #pragma alloc_text(PAGE, DiskAddDevice)
42 #pragma alloc_text(PAGE, DiskInitFdo)
43 #pragma alloc_text(PAGE, DiskStartFdo)
44 #pragma alloc_text(PAGE, DiskGenerateDeviceName)
45 #pragma alloc_text(PAGE, DiskCreateSymbolicLinks)
46 #pragma alloc_text(PAGE, DiskDeleteSymbolicLinks)
47 #pragma alloc_text(PAGE, DiskRemoveDevice)
48 #endif
49
50
51 NTSTATUS
52 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject)53 DiskAddDevice(
54 IN PDRIVER_OBJECT DriverObject,
55 IN PDEVICE_OBJECT PhysicalDeviceObject
56 )
57
58 /*++
59
60 Routine Description:
61
62 This routine gets a port drivers capabilities, obtains the
63 inquiry data, searches the SCSI bus for the port driver and creates
64 the device objects for the disks found.
65
66 Arguments:
67
68 DriverObject - Pointer to driver object created by system.
69
70 Pdo - Device object use to send requests to port driver.
71
72 Return Value:
73
74 True is returned if one disk was found and successfully created.
75
76 --*/
77
78 {
79 ULONG rootPartitionMountable = FALSE;
80
81 PCONFIGURATION_INFORMATION configurationInformation;
82 ULONG diskCount;
83
84 NTSTATUS status;
85
86 PAGED_CODE();
87
88 //
89 // See if we should be allowing file systems to mount on partition zero.
90 //
91
92 TRY {
93 HANDLE deviceKey = NULL;
94
95 UNICODE_STRING diskKeyName;
96 OBJECT_ATTRIBUTES objectAttributes = {0};
97 HANDLE diskKey;
98
99 RTL_QUERY_REGISTRY_TABLE queryTable[2] = { 0 };
100
101 status = IoOpenDeviceRegistryKey(PhysicalDeviceObject,
102 PLUGPLAY_REGKEY_DEVICE,
103 KEY_READ,
104 &deviceKey);
105
106 if(!NT_SUCCESS(status)) {
107 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskAddDevice: Error %#08lx opening device key "
108 "for pdo %p\n",
109 status, PhysicalDeviceObject));
110 LEAVE;
111 }
112
113 RtlInitUnicodeString(&diskKeyName, L"Disk");
114 InitializeObjectAttributes(&objectAttributes,
115 &diskKeyName,
116 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
117 deviceKey,
118 NULL);
119
120 status = ZwOpenKey(&diskKey, KEY_READ, &objectAttributes);
121 ZwClose(deviceKey);
122
123 if(!NT_SUCCESS(status)) {
124 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskAddDevice: Error %#08lx opening disk key "
125 "for pdo %p device key %p\n",
126 status, PhysicalDeviceObject, deviceKey));
127 LEAVE;
128 }
129
130 queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK;
131 queryTable[0].Name = L"RootPartitionMountable";
132 queryTable[0].EntryContext = &(rootPartitionMountable);
133 queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;
134
135 #ifdef _MSC_VER
136 #pragma prefast(suppress:6309, "We don't have QueryRoutine so Context doesn't make any sense")
137 #endif
138 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
139 diskKey,
140 queryTable,
141 NULL,
142 NULL);
143
144 if(!NT_SUCCESS(status)) {
145 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskAddDevice: Error %#08lx reading value from "
146 "disk key %p for pdo %p\n",
147 status, diskKey, PhysicalDeviceObject));
148 }
149
150 ZwClose(diskKey);
151
152 } FINALLY {
153
154 //
155 // Do nothing.
156 //
157
158 if(!NT_SUCCESS(status)) {
159 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DiskAddDevice: Will %sallow file system to mount on "
160 "partition zero of disk %p\n",
161 (rootPartitionMountable ? "" : "not "),
162 PhysicalDeviceObject));
163 }
164 }
165
166 //
167 // Create device objects for disk
168 //
169
170 diskCount = 0;
171
172 status = DiskCreateFdo(
173 DriverObject,
174 PhysicalDeviceObject,
175 &diskCount,
176 (BOOLEAN) !rootPartitionMountable
177 );
178
179 //
180 // Get the number of disks already initialized.
181 //
182
183 configurationInformation = IoGetConfigurationInformation();
184
185 if (NT_SUCCESS(status)) {
186
187 //
188 // Increment system disk device count.
189 //
190
191 configurationInformation->DiskCount++;
192
193 }
194
195 return status;
196
197 } // end DiskAddDevice()
198
199
200 NTSTATUS
201 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskInitFdo(IN PDEVICE_OBJECT Fdo)202 DiskInitFdo(
203 IN PDEVICE_OBJECT Fdo
204 )
205
206 /*++
207
208 Routine Description:
209
210 This routine is called to do one-time initialization of new device objects
211
212
213 Arguments:
214
215 Fdo - a pointer to the functional device object for this device
216
217 Return Value:
218
219 status
220
221 --*/
222
223 {
224 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
225 PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;
226
227 ULONG srbFlags = 0;
228 ULONG timeOut = 0;
229 ULONG bytesPerSector;
230
231 PULONG dmSkew;
232
233 NTSTATUS status = STATUS_SUCCESS;
234
235 PAGED_CODE();
236
237 //
238 // Build the lookaside list for srb's for the physical disk. Should only
239 // need a couple. If this fails then we don't have an emergency SRB so
240 // fail the call to initialize.
241 //
242
243 ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION) fdoExtension,
244 PARTITION0_LIST_SIZE);
245
246 if (fdoExtension->DeviceDescriptor->RemovableMedia)
247 {
248 SET_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA);
249 }
250
251 //
252 // Initialize the srb flags.
253 //
254
255 //
256 // Because all requests share a common sense buffer, it is possible
257 // for the buffer to be overwritten if the port driver completes
258 // multiple failed requests that require a request sense before the
259 // class driver's completion routine can consume the data in the buffer.
260 // To prevent this, we allow the port driver to allocate a unique sense
261 // buffer each time it needs one. We are responsible for freeing this
262 // buffer. This also allows the adapter to be configured to support
263 // additional sense data beyond the minimum 18 bytes.
264 //
265
266 SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE);
267
268 if (fdoExtension->DeviceDescriptor->CommandQueueing &&
269 fdoExtension->AdapterDescriptor->CommandQueueing) {
270
271 SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
272
273 }
274
275 //
276 // Look for controllers that require special flags.
277 //
278
279 ClassScanForSpecial(fdoExtension, DiskBadControllers, DiskSetSpecialHacks);
280
281 //
282 // Clear buffer for drive geometry.
283 //
284
285 RtlZeroMemory(&(fdoExtension->DiskGeometry),
286 sizeof(DISK_GEOMETRY));
287
288 //
289 // Allocate request sense buffer.
290 //
291
292 fdoExtension->SenseData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
293 SENSE_BUFFER_SIZE_EX,
294 DISK_TAG_START);
295
296 if (fdoExtension->SenseData == NULL) {
297
298 //
299 // The buffer can not be allocated.
300 //
301
302 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskInitFdo: Can not allocate request sense buffer\n"));
303
304 status = STATUS_INSUFFICIENT_RESOURCES;
305 return status;
306 }
307
308 //
309 // Set the buffer size of SenseData
310 //
311
312 fdoExtension->SenseDataLength = SENSE_BUFFER_SIZE_EX;
313
314 //
315 // Physical device object will describe the entire
316 // device, starting at byte offset 0.
317 //
318
319 fdoExtension->CommonExtension.StartingOffset.QuadPart = (LONGLONG)(0);
320
321 //
322 // Set timeout value in seconds.
323 //
324 if ( (fdoExtension->MiniportDescriptor != NULL) &&
325 (fdoExtension->MiniportDescriptor->IoTimeoutValue > 0) ) {
326 //
327 // use the value set by Storport miniport driver
328 //
329 fdoExtension->TimeOutValue = fdoExtension->MiniportDescriptor->IoTimeoutValue;
330 } else {
331 //
332 // get timeout value from registry
333 //
334 timeOut = ClassQueryTimeOutRegistryValue(Fdo);
335
336 if (timeOut) {
337 fdoExtension->TimeOutValue = timeOut;
338 } else {
339 fdoExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
340 }
341 }
342 //
343 // If this is a removable drive, build an entry in devicemap\scsi
344 // indicating it's physicaldriveN name, set up the appropriate
345 // update partitions routine and set the flags correctly.
346 // note: only do this after the timeout value is set, above.
347 //
348
349 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
350
351 ClassUpdateInformationInRegistry( Fdo,
352 "PhysicalDrive",
353 fdoExtension->DeviceNumber,
354 NULL,
355 0);
356 //
357 // Enable media change notification for removable disks
358 //
359 ClassInitializeMediaChangeDetection(fdoExtension,
360 (PUCHAR)"Disk");
361
362 } else {
363
364 SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
365 SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
366
367 }
368
369 //
370 // The commands we send during the init could cause the flags to change
371 // in case of any error. Save the SRB flags locally and restore it at
372 // the end of this function, so that the class driver can get it.
373 //
374
375 srbFlags = fdoExtension->SrbFlags;
376
377
378 //
379 // Read the drive capacity. Don't use the disk version of the routine here
380 // since we don't know the disk signature yet - the disk version will
381 // attempt to determine the BIOS reported geometry.
382 //
383
384 (VOID)ClassReadDriveCapacity(Fdo);
385
386 //
387 // Set up sector size fields.
388 //
389 // Stack variables will be used to update
390 // the partition device extensions.
391 //
392 // The device extension field SectorShift is
393 // used to calculate sectors in I/O transfers.
394 //
395 // The DiskGeometry structure is used to service
396 // IOCTls used by the format utility.
397 //
398
399 bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
400
401 //
402 // Make sure sector size is not zero.
403 //
404
405 if (bytesPerSector == 0) {
406
407 //
408 // Default sector size for disk is 512.
409 //
410
411 bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector = 512;
412 fdoExtension->SectorShift = 9;
413 }
414
415 //
416 // Determine is DM Driver is loaded on an IDE drive that is
417 // under control of Atapi - this could be either a crashdump or
418 // an Atapi device is sharing the controller with an IDE disk.
419 //
420
421 HalExamineMBR(fdoExtension->CommonExtension.DeviceObject,
422 fdoExtension->DiskGeometry.BytesPerSector,
423 (ULONG)0x54,
424 (PVOID *)&dmSkew);
425
426 if (dmSkew) {
427
428 //
429 // Update the device extension, so that the call to IoReadPartitionTable
430 // will get the correct information. Any I/O to this disk will have
431 // to be skewed by *dmSkew sectors aka DMByteSkew.
432 //
433
434 fdoExtension->DMSkew = *dmSkew;
435 fdoExtension->DMActive = TRUE;
436 fdoExtension->DMByteSkew = fdoExtension->DMSkew * bytesPerSector;
437
438 FREE_POOL(dmSkew);
439 }
440
441 #if defined(_X86_) || defined(_AMD64_)
442
443 //
444 // Try to read the signature off the disk and determine the correct drive
445 // geometry based on that. This requires rereading the disk size to get
446 // the cylinder count updated correctly.
447 //
448
449 if(!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
450
451 DiskReadSignature(Fdo);
452 DiskReadDriveCapacity(Fdo);
453
454 if (diskData->GeometrySource == DiskGeometryUnknown)
455 {
456 //
457 // Neither the BIOS nor the port driver could provide us with a reliable
458 // geometry. Before we use the default, look to see if it was partitioned
459 // under Windows NT4 [or earlier] and apply the one that was used back then
460 //
461
462 if (DiskIsNT4Geometry(fdoExtension))
463 {
464 diskData->RealGeometry = fdoExtension->DiskGeometry;
465 diskData->RealGeometry.SectorsPerTrack = 0x20;
466 diskData->RealGeometry.TracksPerCylinder = 0x40;
467 fdoExtension->DiskGeometry = diskData->RealGeometry;
468
469 diskData->GeometrySource = DiskGeometryFromNT4;
470 }
471 }
472 }
473
474 #endif
475
476 DiskCreateSymbolicLinks(Fdo);
477
478 //
479 // Get the SCSI address if it's available for use with SMART ioctls.
480 // SMART ioctls are used for failure prediction, so we need to get
481 // the SCSI address before initializing failure prediction.
482 //
483
484 {
485 PIRP irp;
486 KEVENT event;
487 IO_STATUS_BLOCK statusBlock = { 0 };
488
489 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
490
491 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_ADDRESS,
492 fdoExtension->CommonExtension.LowerDeviceObject,
493 NULL,
494 0L,
495 &(diskData->ScsiAddress),
496 sizeof(SCSI_ADDRESS),
497 FALSE,
498 &event,
499 &statusBlock);
500
501 status = STATUS_UNSUCCESSFUL;
502
503 if(irp != NULL) {
504
505 status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
506
507 if(status == STATUS_PENDING) {
508 KeWaitForSingleObject(&event,
509 Executive,
510 KernelMode,
511 FALSE,
512 NULL);
513 status = statusBlock.Status;
514 }
515 }
516 }
517
518 //
519 // Determine the type of disk and enable failure prediction in the hardware
520 // and enable failure prediction polling.
521 //
522
523 if (InitSafeBootMode == 0) // __REACTOS__
524 {
525 DiskDetectFailurePrediction(fdoExtension,
526 &diskData->FailurePredictionCapability,
527 NT_SUCCESS(status));
528
529 if (diskData->FailurePredictionCapability != FailurePredictionNone)
530 {
531 //
532 // Cool, we've got some sort of failure prediction, enable it
533 // at the hardware and then enable polling for it
534 //
535
536 //
537 // By default we allow performance to be degradeded if failure
538 // prediction is enabled.
539 //
540
541 diskData->AllowFPPerfHit = TRUE;
542
543 //
544 // Enable polling only after Atapi and SBP2 add support for the new
545 // SRB flag that indicates that the request should not reset the
546 // drive spin down idle timer.
547 //
548
549 status = DiskEnableDisableFailurePredictPolling(fdoExtension,
550 TRUE,
551 DISK_DEFAULT_FAILURE_POLLING_PERIOD);
552
553 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DiskInitFdo: Failure Prediction Poll enabled as "
554 "%d for device %p, Status = %lx\n",
555 diskData->FailurePredictionCapability,
556 Fdo,
557 status));
558 }
559 } else {
560
561 //
562 // In safe boot mode we do not enable failure prediction, as perhaps
563 // it is the reason why normal boot does not work
564 //
565
566 diskData->FailurePredictionCapability = FailurePredictionNone;
567
568 }
569
570 //
571 // Initialize the verify mutex
572 //
573
574 KeInitializeMutex(&diskData->VerifyMutex, MAX_SECTORS_PER_VERIFY);
575
576 //
577 // Initialize the flush group context
578 //
579
580 RtlZeroMemory(&diskData->FlushContext, sizeof(DISK_GROUP_CONTEXT));
581
582 InitializeListHead(&diskData->FlushContext.CurrList);
583 InitializeListHead(&diskData->FlushContext.NextList);
584
585 KeInitializeSpinLock(&diskData->FlushContext.Spinlock);
586 KeInitializeEvent(&diskData->FlushContext.Event, SynchronizationEvent, FALSE);
587
588
589 //
590 // Restore the saved value
591 //
592 fdoExtension->SrbFlags = srbFlags;
593
594 return STATUS_SUCCESS;
595
596 } // end DiskInitFdo()
597
598 NTSTATUS
599 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskStopDevice(IN PDEVICE_OBJECT DeviceObject,IN UCHAR Type)600 DiskStopDevice(
601 IN PDEVICE_OBJECT DeviceObject,
602 IN UCHAR Type
603 )
604
605 {
606 UNREFERENCED_PARAMETER(DeviceObject);
607 UNREFERENCED_PARAMETER(Type);
608 return STATUS_SUCCESS;
609 }
610
611 NTSTATUS
DiskGenerateDeviceName(IN ULONG DeviceNumber,OUT PCCHAR * RawName)612 DiskGenerateDeviceName(
613 IN ULONG DeviceNumber,
614 OUT PCCHAR *RawName
615 )
616
617 /*++
618
619 Routine Description:
620
621 This routine will allocate a unicode string buffer and then fill it in
622 with a generated name for the specified device object.
623
624 It is the responsibility of the user to allocate a UNICODE_STRING structure
625 to pass in and to free UnicodeName->Buffer when done with it.
626
627 Arguments:
628
629 DeviceObject - a pointer to the device object
630
631 UnicodeName - a unicode string to put the name buffer into
632
633 Return Value:
634
635 status
636
637 --*/
638
639 #define FDO_NAME_FORMAT "\\Device\\Harddisk%d\\DR%d"
640
641 {
642 CHAR rawName[64] = { 0 };
643 NTSTATUS status;
644
645 PAGED_CODE();
646
647 status = RtlStringCchPrintfA(rawName, sizeof(rawName) - 1, FDO_NAME_FORMAT, DeviceNumber,
648 diskDeviceSequenceNumber++);
649 if (!NT_SUCCESS(status)) {
650 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskGenerateDeviceName: Format FDO name failed with error: 0x%X\n", status));
651 return status;
652 }
653
654 *RawName = ExAllocatePoolWithTag(PagedPool,
655 strlen(rawName) + 1,
656 DISK_TAG_NAME);
657
658 if(*RawName == NULL) {
659 return STATUS_INSUFFICIENT_RESOURCES;
660 }
661
662 status = RtlStringCchCopyA(*RawName, strlen(rawName) + 1, rawName);
663 if (!NT_SUCCESS(status)) {
664 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskGenerateDeviceName: Device name copy failed with error: 0x%X\n", status));
665 FREE_POOL(*RawName);
666 return status;
667 }
668
669 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DiskGenerateDeviceName: generated \"%s\"\n", rawName));
670
671 return STATUS_SUCCESS;
672 }
673
674
675 VOID
DiskCreateSymbolicLinks(IN PDEVICE_OBJECT DeviceObject)676 DiskCreateSymbolicLinks(
677 IN PDEVICE_OBJECT DeviceObject
678 )
679
680 /*++
681
682 Routine Description:
683
684 This routine will generate a symbolic link for the specified device object
685 using the well known form \\Device\HarddiskX\PartitionY, where X and Y is
686 always 0 which represents the entire disk object.
687
688 This routine will not try to delete any previous symbolic link for the
689 same generated name - the caller must make sure the symbolic link has
690 been broken before calling this routine.
691
692 Arguments:
693
694 DeviceObject - the device object to make a well known name for
695
696 Return Value:
697
698 STATUS
699
700 --*/
701
702 {
703 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
704 PDISK_DATA diskData = commonExtension->DriverData;
705
706 WCHAR wideSourceName[64] = { 0 };
707 UNICODE_STRING unicodeSourceName;
708
709 NTSTATUS status;
710
711 PAGED_CODE();
712
713 //
714 // Build the destination for the link first using the device name
715 // stored in the device object
716 //
717
718 NT_ASSERT(commonExtension->DeviceName.Buffer);
719
720 if(!diskData->LinkStatus.WellKnownNameCreated) {
721 //
722 // Put together the source name using the partition and device number
723 // in the device extension and disk data segment
724 //
725
726 status = RtlStringCchPrintfW(wideSourceName, sizeof(wideSourceName) / sizeof(wideSourceName[0]) - 1,
727 L"\\Device\\Harddisk%d\\Partition0",
728 commonExtension->PartitionZeroExtension->DeviceNumber);
729
730 if (NT_SUCCESS(status)) {
731
732 RtlInitUnicodeString(&unicodeSourceName, wideSourceName);
733
734 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DiskCreateSymbolicLink: Linking %wZ to %wZ\n",
735 &unicodeSourceName,
736 &commonExtension->DeviceName));
737
738 status = IoCreateSymbolicLink(&unicodeSourceName,
739 &commonExtension->DeviceName);
740
741 if(NT_SUCCESS(status)){
742 diskData->LinkStatus.WellKnownNameCreated = TRUE;
743 }
744 }
745 }
746
747 if (!diskData->LinkStatus.PhysicalDriveLinkCreated) {
748
749 //
750 // Create a physical drive N link using the device number we saved
751 // away during AddDevice.
752 //
753
754 status = RtlStringCchPrintfW(wideSourceName, sizeof(wideSourceName) / sizeof(wideSourceName[0]) - 1,
755 L"\\DosDevices\\PhysicalDrive%d",
756 commonExtension->PartitionZeroExtension->DeviceNumber);
757 if (NT_SUCCESS(status)) {
758
759 RtlInitUnicodeString(&unicodeSourceName, wideSourceName);
760
761 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DiskCreateSymbolicLink: Linking %wZ to %wZ\n",
762 &unicodeSourceName,
763 &(commonExtension->DeviceName)));
764
765 status = IoCreateSymbolicLink(&unicodeSourceName,
766 &(commonExtension->DeviceName));
767
768 if(NT_SUCCESS(status)) {
769 diskData->LinkStatus.PhysicalDriveLinkCreated = TRUE;
770 }
771 }
772 }
773
774
775 return;
776 }
777
778
779 VOID
DiskDeleteSymbolicLinks(IN PDEVICE_OBJECT DeviceObject)780 DiskDeleteSymbolicLinks(
781 IN PDEVICE_OBJECT DeviceObject
782 )
783
784 /*++
785
786 Routine Description:
787
788 This routine will delete the well known name (symlink) for the specified
789 device. It generates the link name using information stored in the
790 device extension
791
792 Arguments:
793
794 DeviceObject - the device object we are unlinking
795
796 Return Value:
797
798 status
799
800 --*/
801
802 {
803 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
804 PDISK_DATA diskData = commonExtension->DriverData;
805
806 WCHAR wideLinkName[64] = { 0 };
807 UNICODE_STRING unicodeLinkName;
808 NTSTATUS status;
809
810 PAGED_CODE();
811
812 if(diskData->LinkStatus.WellKnownNameCreated) {
813
814 status = RtlStringCchPrintfW(wideLinkName, sizeof(wideLinkName) / sizeof(wideLinkName[0]) - 1,
815 L"\\Device\\Harddisk%d\\Partition0",
816 commonExtension->PartitionZeroExtension->DeviceNumber);
817 if (NT_SUCCESS(status)) {
818 RtlInitUnicodeString(&unicodeLinkName, wideLinkName);
819 IoDeleteSymbolicLink(&unicodeLinkName);
820 }
821 diskData->LinkStatus.WellKnownNameCreated = FALSE;
822 }
823
824 if(diskData->LinkStatus.PhysicalDriveLinkCreated) {
825
826 status = RtlStringCchPrintfW(wideLinkName, sizeof(wideLinkName) / sizeof(wideLinkName[0]) - 1,
827 L"\\DosDevices\\PhysicalDrive%d",
828 commonExtension->PartitionZeroExtension->DeviceNumber);
829 if (NT_SUCCESS(status)) {
830 RtlInitUnicodeString(&unicodeLinkName, wideLinkName);
831 IoDeleteSymbolicLink(&unicodeLinkName);
832 }
833 diskData->LinkStatus.PhysicalDriveLinkCreated = FALSE;
834 }
835
836
837 return;
838 }
839
840
841 NTSTATUS
842 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskRemoveDevice(IN PDEVICE_OBJECT DeviceObject,IN UCHAR Type)843 DiskRemoveDevice(
844 IN PDEVICE_OBJECT DeviceObject,
845 IN UCHAR Type
846 )
847
848 /*++
849
850 Routine Description:
851
852 This routine will release any resources the device may have allocated for
853 this device object and return.
854
855 Arguments:
856
857 DeviceObject - the device object being removed
858
859 Return Value:
860
861 status
862
863 --*/
864
865 {
866 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
867 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
868
869 PAGED_CODE();
870
871 //
872 // Handle query and cancel
873 //
874
875 if((Type == IRP_MN_QUERY_REMOVE_DEVICE) ||
876 (Type == IRP_MN_CANCEL_REMOVE_DEVICE)) {
877 return STATUS_SUCCESS;
878 }
879
880 //
881 // Delete our object directory.
882 //
883
884 if(fdoExtension->DeviceDirectory != NULL) {
885 ZwMakeTemporaryObject(fdoExtension->DeviceDirectory);
886 ZwClose(fdoExtension->DeviceDirectory);
887 fdoExtension->DeviceDirectory = NULL;
888 }
889
890 if(Type == IRP_MN_REMOVE_DEVICE) {
891
892 FREE_POOL(fdoExtension->SenseData);
893
894 IoGetConfigurationInformation()->DiskCount--;
895
896 }
897
898 DiskDeleteSymbolicLinks(DeviceObject);
899
900 if (Type == IRP_MN_REMOVE_DEVICE)
901 {
902 ClassDeleteSrbLookasideList(commonExtension);
903 }
904
905 return STATUS_SUCCESS;
906 }
907
908
909 NTSTATUS
910 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskStartFdo(IN PDEVICE_OBJECT Fdo)911 DiskStartFdo(
912 IN PDEVICE_OBJECT Fdo
913 )
914
915 /*++
916
917 Routine Description:
918
919 This routine will query the underlying device for any information necessary
920 to complete initialization of the device. This will include physical
921 disk geometry, mode sense information and such.
922
923 This routine does not perform partition enumeration - that is left to the
924 re-enumeration routine
925
926 If this routine fails it will return an error value. It does not clean up
927 any resources - that is left for the Stop/Remove routine.
928
929 Arguments:
930
931 Fdo - a pointer to the functional device object for this device
932
933 Return Value:
934
935 status
936
937 --*/
938
939 {
940 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
941 PCOMMON_DEVICE_EXTENSION commonExtension = &(fdoExtension->CommonExtension);
942 PDISK_DATA diskData = commonExtension->DriverData;
943 STORAGE_HOTPLUG_INFO hotplugInfo = { 0 };
944 DISK_CACHE_INFORMATION cacheInfo = { 0 };
945 ULONG isPowerProtected = 0;
946 NTSTATUS status;
947
948 PAGED_CODE();
949
950 //
951 // Get the hotplug information, so we can turn off write cache if needed
952 //
953 // NOTE: Capabilities info is not good enough to determine hotplugedness
954 // as we cannot determine device relations information and other
955 // dependencies. Get the hotplug info instead
956 //
957
958 {
959 PIRP irp;
960 KEVENT event;
961 IO_STATUS_BLOCK statusBlock = { 0 };
962
963 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
964
965 irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_HOTPLUG_INFO,
966 Fdo,
967 NULL,
968 0L,
969 &hotplugInfo,
970 sizeof(STORAGE_HOTPLUG_INFO),
971 FALSE,
972 &event,
973 &statusBlock);
974
975 if (irp != NULL) {
976
977 // send to self -- classpnp handles this
978 status = IoCallDriver(Fdo, irp);
979 if (status == STATUS_PENDING) {
980 KeWaitForSingleObject(&event,
981 Executive,
982 KernelMode,
983 FALSE,
984 NULL);
985
986 status = statusBlock.Status;
987 }
988 NT_ASSERT(NT_SUCCESS(status));
989 }
990 }
991
992 //
993 // Clear the DEV_WRITE_CACHE flag now and set
994 // it below only if we read that from the disk
995 //
996 CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE);
997 ADJUST_FUA_FLAG(fdoExtension);
998
999 diskData->WriteCacheOverride = DiskWriteCacheDefault;
1000
1001 //
1002 // Look into the registry to see if the user
1003 // has chosen to override the default setting
1004 //
1005 ClassGetDeviceParameter(fdoExtension,
1006 DiskDeviceParameterSubkey,
1007 DiskDeviceUserWriteCacheSetting,
1008 (PULONG)&diskData->WriteCacheOverride);
1009
1010 if (diskData->WriteCacheOverride == DiskWriteCacheDefault)
1011 {
1012 //
1013 // The user has not overridden the default settings
1014 //
1015 if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_WRITE_CACHE))
1016 {
1017 //
1018 // This flag indicates that we have faulty firmware and this
1019 // may cause the filesystem to refuse to mount on this media
1020 //
1021 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DiskStartFdo: Turning off write cache for %p due to a firmware issue\n", Fdo));
1022
1023 diskData->WriteCacheOverride = DiskWriteCacheDisable;
1024 }
1025 else if (hotplugInfo.DeviceHotplug && !hotplugInfo.WriteCacheEnableOverride)
1026 {
1027 //
1028 // This flag indicates that the device is hotpluggable making it unsafe to enable caching
1029 //
1030 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DiskStartFdo: Turning off write cache for %p due to hotpluggable device\n", Fdo));
1031
1032 diskData->WriteCacheOverride = DiskWriteCacheDisable;
1033 }
1034 else if (hotplugInfo.MediaHotplug)
1035 {
1036 //
1037 // This flag indicates that the media in the device cannot be reliably locked
1038 //
1039 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DiskStartFdo: Turning off write cache for %p due to unlockable media\n", Fdo));
1040
1041 diskData->WriteCacheOverride = DiskWriteCacheDisable;
1042 }
1043 else
1044 {
1045 //
1046 // Even though the device does not seem to have any obvious problems
1047 // we leave it to the user to modify the previous write cache setting
1048 //
1049 }
1050 }
1051
1052 //
1053 // Query the disk to see if write cache is enabled
1054 // and set the DEV_WRITE_CACHE flag appropriately
1055 //
1056
1057 status = DiskGetCacheInformation(fdoExtension, &cacheInfo);
1058
1059 if (NT_SUCCESS(status))
1060 {
1061 if (cacheInfo.WriteCacheEnabled == TRUE)
1062 {
1063 SET_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE);
1064 ADJUST_FUA_FLAG(fdoExtension);
1065
1066 if (diskData->WriteCacheOverride == DiskWriteCacheDisable)
1067 {
1068 //
1069 // Write cache is currently enabled on this
1070 // device, but we would like to turn it off
1071 //
1072 cacheInfo.WriteCacheEnabled = FALSE;
1073
1074 DiskSetCacheInformation(fdoExtension, &cacheInfo);
1075 }
1076 }
1077 else
1078 {
1079 if (diskData->WriteCacheOverride == DiskWriteCacheEnable)
1080 {
1081 //
1082 // Write cache is currently disabled on this
1083 // device, but we would like to turn it on
1084 //
1085 cacheInfo.WriteCacheEnabled = TRUE;
1086
1087 DiskSetCacheInformation(fdoExtension, &cacheInfo);
1088 }
1089 }
1090 }
1091
1092 //
1093 // Query the registry to see if this disk is power-protected or not
1094 //
1095
1096 CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
1097
1098 ClassGetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey, DiskDeviceCacheIsPowerProtected, &isPowerProtected);
1099
1100 if (isPowerProtected == 1)
1101 {
1102 SET_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
1103 }
1104
1105 ADJUST_FUA_FLAG(fdoExtension);
1106
1107 return STATUS_SUCCESS;
1108
1109 } // end DiskStartFdo()
1110
1111