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 */ 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 */ 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 */ 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 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 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 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 */ 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 */ 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