Leaked source code of windows server 2003
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.

1662 lines
46 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. geometry.c
  5. Abstract:
  6. SCSI disk class driver - this module contains all the code for generating
  7. disk geometries.
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. Revision History:
  12. --*/
  13. #include "disk.h"
  14. #include "ntddstor.h"
  15. #if defined (_X86_)
  16. DISK_GEOMETRY_SOURCE
  17. DiskUpdateGeometry(
  18. IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension
  19. );
  20. NTSTATUS
  21. DiskUpdateRemovableGeometry (
  22. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  23. );
  24. VOID
  25. DiskScanBusDetectInfo(
  26. IN PDRIVER_OBJECT DriverObject,
  27. IN HANDLE BusKey
  28. );
  29. NTSTATUS
  30. DiskSaveBusDetectInfo(
  31. IN PDRIVER_OBJECT DriverObject,
  32. IN HANDLE TargetKey,
  33. IN ULONG DiskNumber
  34. );
  35. NTSTATUS
  36. DiskSaveGeometryDetectInfo(
  37. IN PDRIVER_OBJECT DriverObject,
  38. IN HANDLE HardwareKey
  39. );
  40. NTSTATUS
  41. DiskGetPortGeometry(
  42. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  43. OUT PDISK_GEOMETRY Geometry
  44. );
  45. typedef struct _DISK_DETECT_INFO {
  46. BOOLEAN Initialized;
  47. ULONG Style;
  48. ULONG Signature;
  49. ULONG MbrCheckSum;
  50. PDEVICE_OBJECT Device;
  51. CM_INT13_DRIVE_PARAMETER DriveParameters;
  52. } DISK_DETECT_INFO, *PDISK_DETECT_INFO;
  53. //
  54. // Information about the disk geometries collected and saved into the registry
  55. // by NTDETECT.COM or the system firmware.
  56. //
  57. PDISK_DETECT_INFO DetectInfoList = NULL;
  58. ULONG DetectInfoCount = 0;
  59. ULONG DetectInfoUsedCount = 0;
  60. #define GET_STARTING_SECTOR(p) ( \
  61. (ULONG) (p->StartingSectorLsb0) + \
  62. (ULONG) (p->StartingSectorLsb1 << 8 ) + \
  63. (ULONG) (p->StartingSectorMsb0 << 16) + \
  64. (ULONG) (p->StartingSectorMsb1 << 24) )
  65. #define GET_ENDING_S_OF_CHS(p) ( \
  66. (UCHAR) (p->EndingCylinderLsb & 0x3F) )
  67. //
  68. // Definitions from hal.h
  69. //
  70. //
  71. // Boot record disk partition table entry structure format
  72. //
  73. typedef struct _PARTITION_DESCRIPTOR
  74. {
  75. UCHAR ActiveFlag;
  76. UCHAR StartingTrack;
  77. UCHAR StartingCylinderLsb;
  78. UCHAR StartingCylinderMsb;
  79. UCHAR PartitionType;
  80. UCHAR EndingTrack;
  81. UCHAR EndingCylinderLsb;
  82. UCHAR EndingCylinderMsb;
  83. UCHAR StartingSectorLsb0;
  84. UCHAR StartingSectorLsb1;
  85. UCHAR StartingSectorMsb0;
  86. UCHAR StartingSectorMsb1;
  87. UCHAR PartitionLengthLsb0;
  88. UCHAR PartitionLengthLsb1;
  89. UCHAR PartitionLengthMsb0;
  90. UCHAR PartitionLengthMsb1;
  91. } PARTITION_DESCRIPTOR, *PPARTITION_DESCRIPTOR;
  92. //
  93. // Number of partition table entries
  94. //
  95. #define NUM_PARTITION_TABLE_ENTRIES 4
  96. //
  97. // Partition table record and boot signature offsets in 16-bit words
  98. //
  99. #define PARTITION_TABLE_OFFSET ( 0x1be / 2)
  100. #define BOOT_SIGNATURE_OFFSET ((0x200 / 2) - 1)
  101. //
  102. // Boot record signature value
  103. //
  104. #define BOOT_RECORD_SIGNATURE (0xaa55)
  105. #ifdef ALLOC_PRAGMA
  106. #pragma alloc_text(INIT, DiskSaveDetectInfo)
  107. #pragma alloc_text(INIT, DiskScanBusDetectInfo)
  108. #pragma alloc_text(INIT, DiskSaveBusDetectInfo)
  109. #pragma alloc_text(INIT, DiskSaveGeometryDetectInfo)
  110. #pragma alloc_text(PAGE, DiskUpdateGeometry)
  111. #pragma alloc_text(PAGE, DiskUpdateRemovableGeometry)
  112. #pragma alloc_text(PAGE, DiskGetPortGeometry)
  113. #pragma alloc_text(PAGE, DiskIsNT4Geometry)
  114. #pragma alloc_text(PAGE, DiskGetDetectInfo)
  115. #pragma alloc_text(PAGE, DiskReadSignature)
  116. #endif
  117. NTSTATUS
  118. DiskSaveDetectInfo(
  119. PDRIVER_OBJECT DriverObject
  120. )
  121. /*++
  122. Routine Description:
  123. This routine saves away the firmware information about the disks which has
  124. been saved in the registry. It generates a list (DetectInfoList) which
  125. contains the disk geometries, signatures & checksums of all drives which
  126. were examined by NtDetect. This list is later used to assign geometries
  127. to disks as they are initialized.
  128. Arguments:
  129. DriverObject - the driver being initialized. This is used to get to the
  130. hardware database.
  131. Return Value:
  132. status.
  133. --*/
  134. {
  135. OBJECT_ATTRIBUTES objectAttributes = {0};
  136. HANDLE hardwareKey;
  137. UNICODE_STRING unicodeString;
  138. HANDLE busKey;
  139. NTSTATUS status;
  140. PAGED_CODE();
  141. InitializeObjectAttributes(
  142. &objectAttributes,
  143. DriverObject->HardwareDatabase,
  144. OBJ_CASE_INSENSITIVE,
  145. NULL,
  146. NULL);
  147. //
  148. // Create the hardware base key.
  149. //
  150. status = ZwOpenKey(&hardwareKey, KEY_READ, &objectAttributes);
  151. if(!NT_SUCCESS(status)) {
  152. DebugPrint((1, "DiskSaveDetectInfo: Cannot open hardware data. "
  153. "Name: %wZ\n",
  154. DriverObject->HardwareDatabase));
  155. return status;
  156. }
  157. status = DiskSaveGeometryDetectInfo(DriverObject, hardwareKey);
  158. if(!NT_SUCCESS(status)) {
  159. DebugPrint((1, "DiskSaveDetectInfo: Can't query configuration data "
  160. "(%#08lx)\n",
  161. status));
  162. ZwClose(hardwareKey);
  163. return status;
  164. }
  165. //
  166. // Open EISA bus key.
  167. //
  168. RtlInitUnicodeString(&unicodeString, L"EisaAdapter");
  169. InitializeObjectAttributes(&objectAttributes,
  170. &unicodeString,
  171. OBJ_CASE_INSENSITIVE,
  172. hardwareKey,
  173. NULL);
  174. status = ZwOpenKey(&busKey,
  175. KEY_READ,
  176. &objectAttributes);
  177. if(NT_SUCCESS(status)) {
  178. DebugPrint((1, "DiskSaveDetectInfo: Opened EisaAdapter key\n"));
  179. DiskScanBusDetectInfo(DriverObject, busKey);
  180. ZwClose(busKey);
  181. }
  182. //
  183. // Open MultiFunction bus key.
  184. //
  185. RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter");
  186. InitializeObjectAttributes(&objectAttributes,
  187. &unicodeString,
  188. OBJ_CASE_INSENSITIVE,
  189. hardwareKey,
  190. NULL);
  191. status = ZwOpenKey(&busKey,
  192. KEY_READ,
  193. &objectAttributes);
  194. if(NT_SUCCESS(status)) {
  195. DebugPrint((1, "DiskSaveDetectInfo: Opened MultifunctionAdapter key\n"));
  196. DiskScanBusDetectInfo(DriverObject, busKey);
  197. ZwClose(busKey);
  198. }
  199. ZwClose(hardwareKey);
  200. return STATUS_SUCCESS;
  201. }
  202. VOID
  203. DiskCleanupDetectInfo(
  204. IN PDRIVER_OBJECT DriverObject
  205. )
  206. /*++
  207. Routine Description:
  208. This routine will cleanup the data structure built by DiskSaveDetectInfo.
  209. Arguments:
  210. DriverObject - a pointer to the kernel object for this driver.
  211. Return Value:
  212. none
  213. --*/
  214. {
  215. if (DetectInfoList != NULL) {
  216. ExFreePool(DetectInfoList);
  217. DetectInfoList = NULL;
  218. }
  219. return;
  220. }
  221. NTSTATUS
  222. DiskSaveGeometryDetectInfo(
  223. IN PDRIVER_OBJECT DriverObject,
  224. IN HANDLE HardwareKey
  225. )
  226. {
  227. UNICODE_STRING unicodeString;
  228. PKEY_VALUE_FULL_INFORMATION keyData;
  229. ULONG length;
  230. PCM_FULL_RESOURCE_DESCRIPTOR fullDescriptor;
  231. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
  232. PCM_INT13_DRIVE_PARAMETER driveParameters;
  233. ULONG numberOfDrives;
  234. ULONG i;
  235. NTSTATUS status;
  236. PAGED_CODE();
  237. //
  238. // Get disk BIOS geometry information.
  239. //
  240. RtlInitUnicodeString(&unicodeString, L"Configuration Data");
  241. keyData = ExAllocatePoolWithTag(PagedPool,
  242. VALUE_BUFFER_SIZE,
  243. DISK_TAG_UPDATE_GEOM);
  244. if(keyData == NULL) {
  245. DebugPrint((1, "DiskSaveGeometryDetectInfo: Can't allocate config "
  246. "data buffer\n"));
  247. return STATUS_INSUFFICIENT_RESOURCES;
  248. }
  249. status = ZwQueryValueKey(HardwareKey,
  250. &unicodeString,
  251. KeyValueFullInformation,
  252. keyData,
  253. VALUE_BUFFER_SIZE,
  254. &length);
  255. if(!NT_SUCCESS(status)) {
  256. DebugPrint((1, "DiskSaveGeometryDetectInfo: Can't query configuration "
  257. "data (%#08lx)\n",
  258. status));
  259. ExFreePool(keyData);
  260. return status;
  261. }
  262. //
  263. // Extract the resource list out of the key data.
  264. //
  265. fullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
  266. (((PUCHAR) keyData) + keyData->DataOffset);
  267. partialDescriptor =
  268. fullDescriptor->PartialResourceList.PartialDescriptors;
  269. length = partialDescriptor->u.DeviceSpecificData.DataSize;
  270. if((keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) ||
  271. (fullDescriptor->PartialResourceList.Count == 0) ||
  272. (partialDescriptor->Type != CmResourceTypeDeviceSpecific) ||
  273. (length < sizeof(ULONG))) {
  274. DebugPrint((1, "DiskSaveGeometryDetectInfo: BIOS header data too small "
  275. "or invalid\n"));
  276. ExFreePool(keyData);
  277. return STATUS_INVALID_PARAMETER;
  278. }
  279. //
  280. // Point to the BIOS data. THe BIOS data is located after the first
  281. // partial Resource list which should be device specific data.
  282. //
  283. {
  284. PUCHAR buffer = (PUCHAR) keyData;
  285. buffer += keyData->DataOffset;
  286. buffer += sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
  287. driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer;
  288. }
  289. numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER);
  290. //
  291. // Allocate our detect info list now that we know how many entries there
  292. // are going to be. No other routine allocates detect info and this is
  293. // done out of DriverEntry so we don't need to synchronize it's creation.
  294. //
  295. length = sizeof(DISK_DETECT_INFO) * numberOfDrives;
  296. DetectInfoList = ExAllocatePoolWithTag(PagedPool,
  297. length,
  298. DISK_TAG_UPDATE_GEOM);
  299. if(DetectInfoList == NULL) {
  300. DebugPrint((1, "DiskSaveGeometryDetectInfo: Couldn't allocate %x bytes "
  301. "for DetectInfoList\n",
  302. length));
  303. ExFreePool(keyData);
  304. return STATUS_INSUFFICIENT_RESOURCES;
  305. }
  306. DetectInfoCount = numberOfDrives;
  307. RtlZeroMemory(DetectInfoList, length);
  308. //
  309. // Copy the information out of the key data and into the list we've
  310. // allocated.
  311. //
  312. for(i = 0; i < numberOfDrives; i++) {
  313. DetectInfoList[i].DriveParameters = driveParameters[i];
  314. }
  315. ExFreePool(keyData);
  316. return STATUS_SUCCESS;
  317. }
  318. VOID
  319. DiskScanBusDetectInfo(
  320. IN PDRIVER_OBJECT DriverObject,
  321. IN HANDLE BusKey
  322. )
  323. /*++
  324. Routine Description:
  325. The routine queries the registry to determine which disks are visible to
  326. the BIOS. If a disk is visable to the BIOS then the geometry information
  327. is updated with the disk's signature and MBR checksum.
  328. Arguments:
  329. DriverObject - the object for this driver.
  330. BusKey - handle to the bus key to be enumerated.
  331. Return Value:
  332. status
  333. --*/
  334. {
  335. ULONG busNumber;
  336. NTSTATUS status;
  337. for(busNumber = 0; ; busNumber++) {
  338. WCHAR buffer[32] = { 0 };
  339. UNICODE_STRING unicodeString;
  340. OBJECT_ATTRIBUTES objectAttributes = {0};
  341. HANDLE spareKey;
  342. HANDLE adapterKey;
  343. ULONG adapterNumber;
  344. DebugPrint((1, "DiskScanBusDetectInfo: Scanning bus %d\n", busNumber));
  345. //
  346. // Open controller name key.
  347. //
  348. _snwprintf(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d", busNumber);
  349. RtlInitUnicodeString(&unicodeString, buffer);
  350. InitializeObjectAttributes(&objectAttributes,
  351. &unicodeString,
  352. OBJ_CASE_INSENSITIVE,
  353. BusKey,
  354. NULL);
  355. status = ZwOpenKey(&spareKey, KEY_READ, &objectAttributes);
  356. if(!NT_SUCCESS(status)) {
  357. DebugPrint((1, "DiskScanBusDetectInfo: Error %#08lx opening bus "
  358. "key %#x\n",
  359. status, busNumber));
  360. break;
  361. }
  362. //
  363. // Open up a controller ordinal key.
  364. //
  365. RtlInitUnicodeString(&unicodeString, L"DiskController");
  366. InitializeObjectAttributes(&objectAttributes,
  367. &unicodeString,
  368. OBJ_CASE_INSENSITIVE,
  369. spareKey,
  370. NULL);
  371. status = ZwOpenKey(&adapterKey, KEY_READ, &objectAttributes);
  372. ZwClose(spareKey);
  373. if(!NT_SUCCESS(status)) {
  374. DebugPrint((1, "DiskScanBusDetectInfo: Error %#08lx opening "
  375. "DiskController key\n",
  376. status));
  377. continue;
  378. }
  379. for(adapterNumber = 0; ; adapterNumber++) {
  380. HANDLE diskKey;
  381. ULONG diskNumber;
  382. //
  383. // Open disk key.
  384. //
  385. DebugPrint((1, "DiskScanBusDetectInfo: Scanning disk key "
  386. "%d\\DiskController\\%d\\DiskPeripheral\n",
  387. busNumber, adapterNumber));
  388. _snwprintf(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d\\DiskPeripheral", adapterNumber);
  389. RtlInitUnicodeString(&unicodeString, buffer);
  390. InitializeObjectAttributes(&objectAttributes,
  391. &unicodeString,
  392. OBJ_CASE_INSENSITIVE,
  393. adapterKey,
  394. NULL);
  395. status = ZwOpenKey(&diskKey, KEY_READ, &objectAttributes);
  396. if(!NT_SUCCESS(status)) {
  397. DebugPrint((1, "DiskScanBusDetectInfo: Error %#08lx opening "
  398. "disk key\n",
  399. status));
  400. break;
  401. }
  402. for(diskNumber = 0; ; diskNumber++) {
  403. HANDLE targetKey;
  404. DebugPrint((1, "DiskScanBusDetectInfo: Scanning target key "
  405. "%d\\DiskController\\%d\\DiskPeripheral\\%d\n",
  406. busNumber, adapterNumber, diskNumber));
  407. _snwprintf(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d", diskNumber);
  408. RtlInitUnicodeString(&unicodeString, buffer);
  409. InitializeObjectAttributes(&objectAttributes,
  410. &unicodeString,
  411. OBJ_CASE_INSENSITIVE,
  412. diskKey,
  413. NULL);
  414. status = ZwOpenKey(&targetKey, KEY_READ, &objectAttributes);
  415. if(!NT_SUCCESS(status)) {
  416. DebugPrint((1, "DiskScanBusDetectInfo: Error %#08lx "
  417. "opening target key\n",
  418. status));
  419. break;
  420. }
  421. status = DiskSaveBusDetectInfo(DriverObject,
  422. targetKey,
  423. diskNumber);
  424. ZwClose(targetKey);
  425. }
  426. ZwClose(diskKey);
  427. }
  428. ZwClose(adapterKey);
  429. }
  430. return;
  431. }
  432. NTSTATUS
  433. DiskSaveBusDetectInfo(
  434. IN PDRIVER_OBJECT DriverObject,
  435. IN HANDLE TargetKey,
  436. IN ULONG DiskNumber
  437. )
  438. /*++
  439. Routine Description:
  440. This routine will transfer the firmware/ntdetect reported information
  441. in the specified target key into the appropriate entry in the
  442. DetectInfoList.
  443. Arguments:
  444. DriverObject - the object for this driver.
  445. TargetKey - the key for the disk being saved.
  446. DiskNumber - the ordinal of the entry in the DiskPeripheral tree for this
  447. entry
  448. Return Value:
  449. status
  450. --*/
  451. {
  452. PDISK_DETECT_INFO diskInfo;
  453. UNICODE_STRING unicodeString;
  454. PKEY_VALUE_FULL_INFORMATION keyData;
  455. ULONG length;
  456. NTSTATUS status;
  457. PAGED_CODE();
  458. if (DiskNumber >= DetectInfoCount)
  459. {
  460. return STATUS_UNSUCCESSFUL;
  461. }
  462. diskInfo = &(DetectInfoList[DiskNumber]);
  463. if(diskInfo->Initialized) {
  464. ASSERT(FALSE);
  465. DebugPrint((1, "DiskSaveBusDetectInfo: disk entry %#x already has a "
  466. "signature of %#08lx and mbr checksum of %#08lx\n",
  467. DiskNumber,
  468. diskInfo->Signature,
  469. diskInfo->MbrCheckSum));
  470. return STATUS_UNSUCCESSFUL;
  471. }
  472. RtlInitUnicodeString(&unicodeString, L"Identifier");
  473. keyData = ExAllocatePoolWithTag(PagedPool,
  474. VALUE_BUFFER_SIZE,
  475. DISK_TAG_UPDATE_GEOM);
  476. if(keyData == NULL) {
  477. DebugPrint((1, "DiskSaveBusDetectInfo: Couldn't allocate space for "
  478. "registry data\n"));
  479. return STATUS_INSUFFICIENT_RESOURCES;
  480. }
  481. //
  482. // Get disk peripheral identifier.
  483. //
  484. status = ZwQueryValueKey(TargetKey,
  485. &unicodeString,
  486. KeyValueFullInformation,
  487. keyData,
  488. VALUE_BUFFER_SIZE,
  489. &length);
  490. if(!NT_SUCCESS(status)) {
  491. DebugPrint((1, "DiskSaveBusDetectInfo: Error %#08lx getting "
  492. "Identifier\n",
  493. status));
  494. ExFreePool(keyData);
  495. return status;
  496. } else if (keyData->DataLength < 9*sizeof(WCHAR)) {
  497. //
  498. // the data is too short to use (we subtract 9 chars in normal path)
  499. //
  500. DebugPrint((1, "DiskSaveBusDetectInfo: Saved data was invalid, "
  501. "not enough data in registry!\n"));
  502. ExFreePool(keyData);
  503. return STATUS_UNSUCCESSFUL;
  504. } else {
  505. UNICODE_STRING identifier;
  506. ULONG value;
  507. //
  508. // Complete unicode string.
  509. //
  510. identifier.Buffer = (PWSTR) ((PUCHAR)keyData + keyData->DataOffset);
  511. identifier.Length = (USHORT) keyData->DataLength;
  512. identifier.MaximumLength = (USHORT) keyData->DataLength;
  513. //
  514. // Get the first value out of the identifier - this will be the MBR
  515. // checksum.
  516. //
  517. status = RtlUnicodeStringToInteger(&identifier, 16, &value);
  518. if(!NT_SUCCESS(status)) {
  519. DebugPrint((1, "DiskSaveBusDetectInfo: Error %#08lx converting "
  520. "identifier %wZ into MBR xsum\n",
  521. status,
  522. &identifier));
  523. ExFreePool(keyData);
  524. return status;
  525. }
  526. diskInfo->MbrCheckSum = value;
  527. //
  528. // Shift the string over to get the disk signature
  529. //
  530. identifier.Buffer += 9;
  531. identifier.Length -= 9 * sizeof(WCHAR);
  532. identifier.MaximumLength -= 9 * sizeof(WCHAR);
  533. status = RtlUnicodeStringToInteger(&identifier, 16, &value);
  534. if(!NT_SUCCESS(status)) {
  535. DebugPrint((1, "DiskSaveBusDetectInfo: Error %#08lx converting "
  536. "identifier %wZ into disk signature\n",
  537. status,
  538. &identifier));
  539. ExFreePool(keyData);
  540. value = 0;
  541. }
  542. diskInfo->Signature = value;
  543. }
  544. //
  545. // Here is where we would save away the extended int13 data.
  546. //
  547. //
  548. // Mark this entry as initialized so we can make sure not to do it again.
  549. //
  550. diskInfo->Initialized = TRUE;
  551. return STATUS_SUCCESS;
  552. }
  553. DISK_GEOMETRY_SOURCE
  554. DiskUpdateGeometry(
  555. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  556. )
  557. /*++
  558. Routine Description:
  559. This routine checks the DetectInfoList saved away during disk driver init
  560. to see if any geometry information was reported for this drive. If the
  561. geometry data exists (determined by matching non-zero signatures or
  562. non-zero MBR checksums) then it will be saved in the RealGeometry member
  563. of the disk data block.
  564. ClassReadDriveCapacity MUST be called after calling this routine to update
  565. the cylinder count based on the size of the disk and the presence of any
  566. disk management software.
  567. Arguments:
  568. DeviceExtension - Supplies a pointer to the device information for disk.
  569. Return Value:
  570. Inidicates whether the "RealGeometry" in the data block is now valid.
  571. --*/
  572. {
  573. PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
  574. ULONG i;
  575. PDISK_DETECT_INFO diskInfo;
  576. BOOLEAN found = FALSE;
  577. NTSTATUS status;
  578. PAGED_CODE();
  579. ASSERT(FdoExtension->CommonExtension.IsFdo);
  580. ASSERT((FdoExtension->DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0);
  581. //
  582. // If we've already set a non-default geometry for this drive then there's
  583. // no need to try and update again.
  584. //
  585. if(diskData->GeometrySource != DiskGeometryUnknown) {
  586. return diskData->GeometrySource;
  587. }
  588. //
  589. // Scan through the saved detect info to see if we can find a match
  590. // for this device.
  591. //
  592. for(i = 0; i < DetectInfoCount; i++) {
  593. ASSERT(DetectInfoList != NULL);
  594. diskInfo = &(DetectInfoList[i]);
  595. if((diskData->Mbr.Signature != 0) &&
  596. (diskData->Mbr.Signature == diskInfo->Signature)) {
  597. DebugPrint((1, "DiskUpdateGeometry: found match for signature "
  598. "%#08lx\n",
  599. diskData->Mbr.Signature));
  600. found = TRUE;
  601. break;
  602. } else if((diskData->Mbr.Signature == 0) &&
  603. (diskData->Mbr.MbrCheckSum != 0) &&
  604. (diskData->Mbr.MbrCheckSum == diskInfo->MbrCheckSum)) {
  605. DebugPrint((1, "DiskUpdateGeometry: found match for xsum %#08lx\n",
  606. diskData->Mbr.MbrCheckSum));
  607. found = TRUE;
  608. break;
  609. }
  610. }
  611. if(found) {
  612. ULONG cylinders;
  613. ULONG sectorsPerTrack;
  614. ULONG tracksPerCylinder;
  615. ULONG sectors;
  616. ULONG length;
  617. //
  618. // Point to the array of drive parameters.
  619. //
  620. cylinders = diskInfo->DriveParameters.MaxCylinders + 1;
  621. sectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack;
  622. tracksPerCylinder = diskInfo->DriveParameters.MaxHeads + 1;
  623. //
  624. // Since the BIOS may not report the full drive, recalculate the drive
  625. // size based on the volume size and the BIOS values for tracks per
  626. // cylinder and sectors per track..
  627. //
  628. length = tracksPerCylinder * sectorsPerTrack;
  629. if (length == 0) {
  630. //
  631. // The BIOS information is bogus.
  632. //
  633. DebugPrint((1, "DiskUpdateGeometry: H (%d) or S(%d) is zero\n",
  634. tracksPerCylinder, sectorsPerTrack));
  635. return DiskGeometryUnknown;
  636. }
  637. //
  638. // since we are copying the structure RealGeometry here, we should
  639. // really initialize all the fields, especially since a zero'd
  640. // BytesPerSector field would cause a trap in xHalReadPartitionTable()
  641. //
  642. diskData->RealGeometry = FdoExtension->DiskGeometry;
  643. //
  644. // Save the geometry information away in the disk data block and
  645. // set the bit indicating that we found a valid one.
  646. //
  647. diskData->RealGeometry.SectorsPerTrack = sectorsPerTrack;
  648. diskData->RealGeometry.TracksPerCylinder = tracksPerCylinder;
  649. diskData->RealGeometry.Cylinders.QuadPart = (LONGLONG)cylinders;
  650. DebugPrint((1, "DiskUpdateGeometry: BIOS spt %#x, #heads %#x, "
  651. "#cylinders %#x\n",
  652. sectorsPerTrack, tracksPerCylinder, cylinders));
  653. diskData->GeometrySource = DiskGeometryFromBios;
  654. diskInfo->Device = FdoExtension->DeviceObject;
  655. //
  656. // Increment the count of used geometry entries.
  657. //
  658. InterlockedIncrement(&DetectInfoUsedCount);
  659. } else {
  660. DebugPrint((1, "DiskUpdateGeometry: no match found for signature %#08lx\n", diskData->Mbr.Signature));
  661. }
  662. if(diskData->GeometrySource == DiskGeometryUnknown) {
  663. //
  664. // We couldn't find a geometry from the BIOS. Check with the port
  665. // driver and see if it can provide one.
  666. //
  667. status = DiskGetPortGeometry(FdoExtension, &(diskData->RealGeometry));
  668. if(NT_SUCCESS(status)) {
  669. //
  670. // Check the geometry to make sure it's valid.
  671. //
  672. if((diskData->RealGeometry.TracksPerCylinder *
  673. diskData->RealGeometry.SectorsPerTrack) != 0) {
  674. diskData->GeometrySource = DiskGeometryFromPort;
  675. DebugPrint((1, "DiskUpdateGeometry: using Port geometry for disk %#p\n", FdoExtension));
  676. if (diskData->RealGeometry.BytesPerSector == 0) {
  677. DebugPrint((0, "DiskDriverReinit: Port driver failed to "
  678. "set BytesPerSector in the RealGeometry\n"));
  679. diskData->RealGeometry.BytesPerSector =
  680. FdoExtension->DiskGeometry.BytesPerSector;
  681. if (diskData->RealGeometry.BytesPerSector == 0) {
  682. ASSERT(!"BytesPerSector is still zero!");
  683. }
  684. }
  685. }
  686. }
  687. }
  688. //
  689. // If we came up with a "real" geometry for this drive then set it in the
  690. // device extension.
  691. //
  692. if (diskData->GeometrySource != DiskGeometryUnknown) {
  693. FdoExtension->DiskGeometry = diskData->RealGeometry;
  694. }
  695. return diskData->GeometrySource;
  696. }
  697. NTSTATUS
  698. DiskUpdateRemovableGeometry (
  699. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  700. )
  701. /*++
  702. Routine Description:
  703. This routine updates the geometry of the disk. It will query the port
  704. driver to see if it can provide any geometry info. If not it will use
  705. the current head & sector count.
  706. Based on these values & the capacity of the drive as reported by
  707. ClassReadDriveCapacity it will determine a new cylinder count for the
  708. device.
  709. Arguments:
  710. Fdo - Supplies the functional device object whos size needs to be updated.
  711. Return Value:
  712. Returns the status of the opertion.
  713. --*/
  714. {
  715. PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension);
  716. PDISK_DATA diskData = commonExtension->DriverData;
  717. PDISK_GEOMETRY geometry = &(diskData->RealGeometry);
  718. NTSTATUS status;
  719. PAGED_CODE();
  720. ASSERT_FDO(commonExtension->DeviceObject);
  721. if (FdoExtension->DeviceDescriptor) {
  722. ASSERT(FdoExtension->DeviceDescriptor->RemovableMedia);
  723. }
  724. ASSERT(TEST_FLAG(FdoExtension->DeviceObject->Characteristics,
  725. FILE_REMOVABLE_MEDIA));
  726. //
  727. // Attempt to determine the disk geometry. First we'll check with the
  728. // port driver to see what it suggests for a value.
  729. //
  730. status = DiskGetPortGeometry(FdoExtension, geometry);
  731. if(NT_SUCCESS(status) &&
  732. ((geometry->TracksPerCylinder * geometry->SectorsPerTrack) != 0)) {
  733. FdoExtension->DiskGeometry = (*geometry);
  734. }
  735. return status;
  736. }
  737. NTSTATUS
  738. DiskGetPortGeometry(
  739. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  740. OUT PDISK_GEOMETRY Geometry
  741. )
  742. /*++
  743. Routine Description:
  744. This routine will query the port driver for disk geometry. Some port
  745. drivers (in particular IDEPORT) may be able to provide geometry for the
  746. device.
  747. Arguments:
  748. FdoExtension - the device object for the disk.
  749. Geometry - a structure to save the geometry information into (if any is
  750. available)
  751. Return Value:
  752. STATUS_SUCCESS if geometry information can be provided or
  753. error status indicating why it can't.
  754. --*/
  755. {
  756. PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension);
  757. PIRP irp;
  758. PIO_STACK_LOCATION irpStack;
  759. KEVENT event;
  760. NTSTATUS status;
  761. PAGED_CODE();
  762. //
  763. // Build an irp to send IOCTL_DISK_GET_DRIVE_GEOMETRY to the lower driver.
  764. //
  765. irp = IoAllocateIrp(commonExtension->LowerDeviceObject->StackSize, FALSE);
  766. if(irp == NULL) {
  767. return STATUS_INSUFFICIENT_RESOURCES;
  768. }
  769. irpStack = IoGetNextIrpStackLocation(irp);
  770. irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  771. irpStack->Parameters.DeviceIoControl.IoControlCode =
  772. IOCTL_DISK_GET_DRIVE_GEOMETRY;
  773. irpStack->Parameters.DeviceIoControl.OutputBufferLength =
  774. sizeof(DISK_GEOMETRY);
  775. irp->AssociatedIrp.SystemBuffer = Geometry;
  776. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  777. IoSetCompletionRoutine(irp,
  778. ClassSignalCompletion,
  779. &event,
  780. TRUE,
  781. TRUE,
  782. TRUE);
  783. status = IoCallDriver(commonExtension->LowerDeviceObject, irp);
  784. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  785. status = irp->IoStatus.Status;
  786. IoFreeIrp(irp);
  787. return status;
  788. }
  789. BOOLEAN
  790. DiskIsNT4Geometry(
  791. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  792. )
  793. /*++
  794. Routine Description:
  795. The default geometry that was used in partitioning disks under Windows NT 4.0 was
  796. Sectors per Track = 0x20 = 32
  797. Tracks per Cylinder = 0x40 = 64
  798. This was changed in Windows 2000 to
  799. Sectors per Track = 0x3F = 63
  800. Tracks per Cylinder = 0xFF = 255
  801. If neither the BIOS nor the port driver can report the correct geometry, we will
  802. default to the new numbers on such disks. Now LVM uses the geometry when creating
  803. logical volumes and dynamic disks. So reporting an incorrect geometry will cause
  804. the entire extended partition / dynamic disk to be destroyed
  805. In this routine, we will look at the Master Boot Record. In 90% of the cases, the
  806. first entry corresponds to a partition that starts on the first track. If this is
  807. so, we shall retrieve the logical block address associated with it and calculate
  808. the correct geometry. Now, all partitions start on a cylinder boundary. So, for
  809. the remaining 10% we will look at the ending CHS number to determine the geometry
  810. --*/
  811. {
  812. PUSHORT readBuffer = NULL;
  813. BOOLEAN bFoundNT4 = FALSE;
  814. PAGED_CODE();
  815. readBuffer = ExAllocatePoolWithTag(NonPagedPool, FdoExtension->DiskGeometry.BytesPerSector, DISK_TAG_UPDATE_GEOM);
  816. if (readBuffer)
  817. {
  818. KEVENT event;
  819. LARGE_INTEGER diskOffset;
  820. IO_STATUS_BLOCK ioStatus = { 0 };
  821. PIRP irp;
  822. KeInitializeEvent(&event, NotificationEvent, FALSE);
  823. //
  824. // Read the Master Boot Record at disk offset 0
  825. //
  826. diskOffset.QuadPart = 0;
  827. irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, FdoExtension->DeviceObject, readBuffer, FdoExtension->DiskGeometry.BytesPerSector, &diskOffset, &event, &ioStatus);
  828. if (irp)
  829. {
  830. PIO_STACK_LOCATION irpSp = IoGetNextIrpStackLocation(irp);
  831. NTSTATUS status;
  832. irpSp->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
  833. status = IoCallDriver(FdoExtension->DeviceObject, irp);
  834. if (status == STATUS_PENDING)
  835. {
  836. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  837. status = ioStatus.Status;
  838. }
  839. if (NT_SUCCESS(status))
  840. {
  841. //
  842. // Match the boot record signature
  843. //
  844. if (readBuffer[BOOT_SIGNATURE_OFFSET] == BOOT_RECORD_SIGNATURE)
  845. {
  846. PPARTITION_DESCRIPTOR partitionTableEntry = (PPARTITION_DESCRIPTOR)&readBuffer[PARTITION_TABLE_OFFSET];
  847. ULONG uCount = 0;
  848. //
  849. // Walk the entries looking for a clue as to what the geometry might be
  850. //
  851. for (uCount = 0; uCount < NUM_PARTITION_TABLE_ENTRIES; uCount++)
  852. {
  853. //
  854. // We are only concerned if there might be a logical volume or if this disk is part of a dynamic set
  855. //
  856. if (IsContainerPartition(partitionTableEntry->PartitionType) || partitionTableEntry->PartitionType == PARTITION_LDM)
  857. {
  858. //
  859. // In 90% of the cases, the first entry corresponds to a partition that starts on the first track
  860. //
  861. if (partitionTableEntry->StartingTrack == 1 && GET_STARTING_SECTOR(partitionTableEntry) == 0x20)
  862. {
  863. bFoundNT4 = TRUE;
  864. break;
  865. }
  866. //
  867. // In almost every case, the ending CHS number is on a cylinder boundary
  868. //
  869. if (partitionTableEntry->EndingTrack == 0x3F && GET_ENDING_S_OF_CHS(partitionTableEntry) == 0x20)
  870. {
  871. bFoundNT4 = TRUE;
  872. break;
  873. }
  874. }
  875. partitionTableEntry++;
  876. }
  877. }
  878. else
  879. {
  880. //
  881. // The Master Boot Record is invalid
  882. //
  883. }
  884. }
  885. }
  886. ExFreePool(readBuffer);
  887. }
  888. return bFoundNT4;
  889. }
  890. NTSTATUS
  891. DiskReadDriveCapacity(
  892. IN PDEVICE_OBJECT Fdo
  893. )
  894. /*++
  895. Routine Description:
  896. This routine is used by disk.sys as a wrapper for the classpnp API
  897. ClassReadDriveCapacity. It will perform some additional operations to
  898. attempt to determine drive geometry before it calls the classpnp version
  899. of the routine.
  900. For fixed disks this involves calling DiskUpdateGeometry which will check
  901. various sources (the BIOS, the port driver) for geometry information.
  902. Arguments:
  903. Fdo - a pointer to the device object to be checked.
  904. Return Value:
  905. status of ClassReadDriveCapacity.
  906. --*/
  907. {
  908. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  909. NTSTATUS status;
  910. ASSERT_FDO(Fdo);
  911. if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
  912. DiskUpdateRemovableGeometry(fdoExtension);
  913. } else {
  914. DiskUpdateGeometry(fdoExtension);
  915. }
  916. status = ClassReadDriveCapacity(Fdo);
  917. return status;
  918. }
  919. VOID
  920. DiskDriverReinitialization(
  921. IN PDRIVER_OBJECT DriverObject,
  922. IN PVOID Nothing,
  923. IN ULONG Count
  924. )
  925. /*++
  926. Routine Description:
  927. This routine will scan through the current list of disks and attempt to
  928. match them to any remaining geometry information. This will only be done
  929. on the first call to the routine.
  930. Note: This routine assumes that the system will not be adding or removing
  931. devices during this phase of the init process. This is very likely
  932. a bad assumption but it greatly simplifies the code.
  933. Arguments:
  934. DriverObject - a pointer to the object for the disk driver.
  935. Nothing - unused
  936. Count - an indication of how many times this routine has been called.
  937. Return Value:
  938. none
  939. --*/
  940. {
  941. PDEVICE_OBJECT deviceObject;
  942. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  943. PDISK_DATA diskData;
  944. ULONG unmatchedDiskCount;
  945. PDEVICE_OBJECT unmatchedDisk = NULL;
  946. ULONG i;
  947. PDISK_DETECT_INFO diskInfo = NULL;
  948. if(Count != 1) {
  949. DebugPrint((1, "DiskDriverReinitialization: ignoring call %d\n",
  950. Count));
  951. return;
  952. }
  953. //
  954. // Check to see how many entries in the detect info list have been matched.
  955. // If there's only one remaining we'll see if we can find a disk to go with
  956. // it.
  957. //
  958. if(DetectInfoCount == 0) {
  959. DebugPrint((1, "DiskDriverReinitialization: no detect info saved\n"));
  960. return;
  961. }
  962. if((DetectInfoCount - DetectInfoUsedCount) != 1) {
  963. DebugPrint((1, "DiskDriverReinitialization: %d of %d geometry entries "
  964. "used - will not attempt match\n"));
  965. return;
  966. }
  967. //
  968. // Scan through the list of disks and see if any of them are missing
  969. // geometry information. If there is only one such disk we'll try to
  970. // match it to the unmatched geometry.
  971. //
  972. //
  973. // ISSUE-2000/5/24-henrygab - figure out if there's a way to keep
  974. // removals from happening while doing this.
  975. //
  976. for(deviceObject = DriverObject->DeviceObject, unmatchedDiskCount = 0;
  977. deviceObject != NULL;
  978. deviceObject = deviceObject->NextDevice) {
  979. //
  980. // Make sure this is a disk and not a partition.
  981. //
  982. fdoExtension = deviceObject->DeviceExtension;
  983. if(fdoExtension->CommonExtension.IsFdo == FALSE) {
  984. DebugPrint((1, "DiskDriverReinit: DO %#p is not an FDO\n",
  985. deviceObject));
  986. continue;
  987. }
  988. //
  989. // If the geometry for this one is already known then skip it.
  990. //
  991. diskData = fdoExtension->CommonExtension.DriverData;
  992. if(diskData->GeometrySource != DiskGeometryUnknown) {
  993. DebugPrint((1, "DiskDriverReinit: FDO %#p has a geometry\n",
  994. deviceObject));
  995. continue;
  996. }
  997. DebugPrint((1, "DiskDriverReinit: FDO %#p has no geometry\n",
  998. deviceObject));
  999. //
  1000. // Mark this one as using the default. It's past the time when disk
  1001. // might blunder across the geometry info. If we set the geometry
  1002. // from the bios we'll reset this field down below.
  1003. //
  1004. diskData->GeometrySource = DiskGeometryFromDefault;
  1005. //
  1006. // As long as we've only got one unmatched disk we're fine.
  1007. //
  1008. unmatchedDiskCount++;
  1009. if(unmatchedDiskCount > 1) {
  1010. ASSERT(unmatchedDisk != NULL);
  1011. DebugPrint((1, "DiskDriverReinit: FDO %#p also has no geometry\n",
  1012. unmatchedDisk));
  1013. unmatchedDisk = NULL;
  1014. break;
  1015. }
  1016. unmatchedDisk = deviceObject;
  1017. }
  1018. //
  1019. // If there's more or less than one ungeometried disk then we can't do
  1020. // anything about the geometry.
  1021. //
  1022. if(unmatchedDiskCount != 1) {
  1023. DebugPrint((1, "DiskDriverReinit: Unable to match geometry\n"));
  1024. return;
  1025. }
  1026. fdoExtension = unmatchedDisk->DeviceExtension;
  1027. diskData = fdoExtension->CommonExtension.DriverData;
  1028. DebugPrint((1, "DiskDriverReinit: Found possible match\n"));
  1029. //
  1030. // Find the geometry which wasn't assigned.
  1031. //
  1032. for(i = 0; i < DetectInfoCount; i++) {
  1033. if(DetectInfoList[i].Device == NULL) {
  1034. diskInfo = &(DetectInfoList[i]);
  1035. break;
  1036. }
  1037. }
  1038. ASSERT(diskInfo != NULL);
  1039. {
  1040. //
  1041. // Save the geometry information away in the disk data block and
  1042. // set the bit indicating that we found a valid one.
  1043. //
  1044. ULONG cylinders;
  1045. ULONG sectorsPerTrack;
  1046. ULONG tracksPerCylinder;
  1047. ULONG sectors;
  1048. ULONG length;
  1049. //
  1050. // Point to the array of drive parameters.
  1051. //
  1052. cylinders = diskInfo->DriveParameters.MaxCylinders + 1;
  1053. sectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack;
  1054. tracksPerCylinder = diskInfo->DriveParameters.MaxHeads + 1;
  1055. //
  1056. // Since the BIOS may not report the full drive, recalculate the drive
  1057. // size based on the volume size and the BIOS values for tracks per
  1058. // cylinder and sectors per track..
  1059. //
  1060. length = tracksPerCylinder * sectorsPerTrack;
  1061. if (length == 0) {
  1062. //
  1063. // The BIOS information is bogus.
  1064. //
  1065. DebugPrint((1, "DiskDriverReinit: H (%d) or S(%d) is zero\n",
  1066. tracksPerCylinder, sectorsPerTrack));
  1067. return;
  1068. }
  1069. //
  1070. // since we are copying the structure RealGeometry here, we should
  1071. // really initialize all the fields, especially since a zero'd
  1072. // BytesPerSector field would cause a trap in xHalReadPartitionTable()
  1073. //
  1074. diskData->RealGeometry = fdoExtension->DiskGeometry;
  1075. //
  1076. // Save the geometry information away in the disk data block and
  1077. // set the bit indicating that we found a valid one.
  1078. //
  1079. diskData->RealGeometry.SectorsPerTrack = sectorsPerTrack;
  1080. diskData->RealGeometry.TracksPerCylinder = tracksPerCylinder;
  1081. diskData->RealGeometry.Cylinders.QuadPart = (LONGLONG)cylinders;
  1082. DebugPrint((1, "DiskDriverReinit: BIOS spt %#x, #heads %#x, "
  1083. "#cylinders %#x\n",
  1084. sectorsPerTrack, tracksPerCylinder, cylinders));
  1085. diskData->GeometrySource = DiskGeometryGuessedFromBios;
  1086. diskInfo->Device = unmatchedDisk;
  1087. //
  1088. // Now copy the geometry over to the fdo extension and call
  1089. // classpnp to redetermine the disk size and cylinder count.
  1090. //
  1091. fdoExtension->DiskGeometry = diskData->RealGeometry;
  1092. ClassReadDriveCapacity(unmatchedDisk);
  1093. if (diskData->RealGeometry.BytesPerSector == 0) {
  1094. //
  1095. // if the BytesPerSector field is set to zero for a disk
  1096. // listed in the bios, then the system will bugcheck in
  1097. // xHalReadPartitionTable(). assert here since it is
  1098. // easier to determine what is happening this way.
  1099. //
  1100. ASSERT(!"RealGeometry not set to non-zero bps\n");
  1101. }
  1102. }
  1103. return;
  1104. }
  1105. NTSTATUS
  1106. DiskGetDetectInfo(
  1107. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  1108. OUT PDISK_DETECTION_INFO DetectInfo
  1109. )
  1110. /*++
  1111. Routine Description:
  1112. Get the Int13 information from the BIOS DetectInfoList.
  1113. Arguments:
  1114. FdoExtension - Supplies a pointer to the FDO extension that we want to
  1115. obtain the detect information for.
  1116. DetectInfo - A buffer where the detect information will be copied to.
  1117. Return Value:
  1118. NTSTATUS code.
  1119. --*/
  1120. {
  1121. ULONG i;
  1122. BOOLEAN found = FALSE;
  1123. PDISK_DETECT_INFO diskInfo;
  1124. PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
  1125. PAGED_CODE ();
  1126. ASSERT(FdoExtension->CommonExtension.IsFdo);
  1127. //
  1128. // Fail for non-fixed drives.
  1129. //
  1130. if (TEST_FLAG (FdoExtension->DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
  1131. return STATUS_NOT_SUPPORTED;
  1132. }
  1133. //
  1134. // There is no GPT detection info, so fail this.
  1135. //
  1136. if (diskData->PartitionStyle == PARTITION_STYLE_GPT) {
  1137. return STATUS_NOT_SUPPORTED;
  1138. }
  1139. for(i = 0; i < DetectInfoCount; i++) {
  1140. ASSERT(DetectInfoList != NULL);
  1141. diskInfo = &(DetectInfoList[i]);
  1142. if((diskData->Mbr.Signature != 0) &&
  1143. (diskData->Mbr.Signature == diskInfo->Signature)) {
  1144. DebugPrint((1, "DiskGetDetectInfo: found match for signature "
  1145. "%#08lx\n",
  1146. diskData->Mbr.Signature));
  1147. found = TRUE;
  1148. break;
  1149. } else if((diskData->Mbr.Signature == 0) &&
  1150. (diskData->Mbr.MbrCheckSum != 0) &&
  1151. (diskData->Mbr.MbrCheckSum == diskInfo->MbrCheckSum)) {
  1152. DebugPrint((1, "DiskGetDetectInfo: found match for xsum %#08lx\n",
  1153. diskData->Mbr.MbrCheckSum));
  1154. found = TRUE;
  1155. break;
  1156. }
  1157. }
  1158. if ( found ) {
  1159. DetectInfo->DetectionType = DetectInt13;
  1160. DetectInfo->Int13.DriveSelect = diskInfo->DriveParameters.DriveSelect;
  1161. DetectInfo->Int13.MaxCylinders = diskInfo->DriveParameters.MaxCylinders;
  1162. DetectInfo->Int13.SectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack;
  1163. DetectInfo->Int13.MaxHeads = diskInfo->DriveParameters.MaxHeads;
  1164. DetectInfo->Int13.NumberDrives = diskInfo->DriveParameters.NumberDrives;
  1165. RtlZeroMemory (&DetectInfo->ExInt13, sizeof (DetectInfo->ExInt13));
  1166. }
  1167. return (found ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
  1168. }
  1169. NTSTATUS
  1170. DiskReadSignature(
  1171. IN PDEVICE_OBJECT Fdo
  1172. )
  1173. /*++
  1174. Routine Description:
  1175. Read the disks signature from the drive. The signature can be either
  1176. a MBR signature or a GPT/EFI signature.
  1177. The low-level signature reading is done by IoReadDiskSignature().
  1178. Arguments:
  1179. Fdo - Pointer to the FDO of a disk to read the signature for.
  1180. Return Value:
  1181. NTSTATUS code.
  1182. --*/
  1183. {
  1184. NTSTATUS Status;
  1185. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  1186. PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData;
  1187. DISK_SIGNATURE Signature = { 0 };
  1188. PAGED_CODE();
  1189. Status = IoReadDiskSignature (Fdo,
  1190. fdoExtension->DiskGeometry.BytesPerSector,
  1191. &Signature);
  1192. if (!NT_SUCCESS (Status)) {
  1193. return Status;
  1194. }
  1195. if (Signature.PartitionStyle == PARTITION_STYLE_GPT) {
  1196. diskData->PartitionStyle = PARTITION_STYLE_GPT;
  1197. diskData->Efi.DiskId = Signature.Gpt.DiskId;
  1198. } else if (Signature.PartitionStyle == PARTITION_STYLE_MBR) {
  1199. diskData->PartitionStyle = PARTITION_STYLE_MBR;
  1200. diskData->Mbr.Signature = Signature.Mbr.Signature;
  1201. diskData->Mbr.MbrCheckSum = Signature.Mbr.CheckSum;
  1202. } else {
  1203. ASSERT (FALSE);
  1204. Status = STATUS_UNSUCCESSFUL;
  1205. }
  1206. return Status;
  1207. }
  1208. #endif // defined(_X86_)