Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1394 lines
38 KiB

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