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.

1248 lines
32 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. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE, DiskConvertExtendedToLayout)
  15. #pragma alloc_text(PAGE, DiskConvertPartitionToExtended)
  16. #pragma alloc_text(PAGE, DiskConvertLayoutToExtended)
  17. #pragma alloc_text(PAGE, DiskCreatePdo)
  18. #pragma alloc_text(PAGE, DiskEnumerateDevice)
  19. #pragma alloc_text(PAGE, DiskUpdateRemovablePartitions)
  20. #pragma alloc_text(PAGE, DiskUpdatePartitions)
  21. #pragma alloc_text(PAGE, DiskCreatePdo)
  22. #endif
  23. PDRIVE_LAYOUT_INFORMATION
  24. DiskConvertExtendedToLayout(
  25. IN CONST PDRIVE_LAYOUT_INFORMATION_EX LayoutEx
  26. )
  27. {
  28. ULONG i;
  29. ULONG LayoutSize;
  30. PDRIVE_LAYOUT_INFORMATION Layout;
  31. PPARTITION_INFORMATION Partition;
  32. PPARTITION_INFORMATION_EX PartitionEx;
  33. PAGED_CODE ();
  34. ASSERT ( LayoutEx );
  35. //
  36. // The only valid conversion is from an MBR extended layout structure to
  37. // the old structure.
  38. //
  39. if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR) {
  40. ASSERT ( FALSE );
  41. return NULL;
  42. }
  43. LayoutSize = FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]) +
  44. LayoutEx->PartitionCount * sizeof (PARTITION_INFORMATION);
  45. Layout = ExAllocatePoolWithTag (
  46. NonPagedPool,
  47. LayoutSize,
  48. DISK_TAG_PART_LIST
  49. );
  50. if ( Layout == NULL ) {
  51. return NULL;
  52. }
  53. Layout->Signature = LayoutEx->Mbr.Signature;
  54. Layout->PartitionCount = LayoutEx->PartitionCount;
  55. for (i = 0; i < LayoutEx->PartitionCount; i++) {
  56. Partition = &Layout->PartitionEntry[i];
  57. PartitionEx = &LayoutEx->PartitionEntry[i];
  58. Partition->StartingOffset = PartitionEx->StartingOffset;
  59. Partition->PartitionLength = PartitionEx->PartitionLength;
  60. Partition->RewritePartition = PartitionEx->RewritePartition;
  61. Partition->PartitionNumber = PartitionEx->PartitionNumber;
  62. Partition->PartitionType = PartitionEx->Mbr.PartitionType;
  63. Partition->BootIndicator = PartitionEx->Mbr.BootIndicator;
  64. Partition->RecognizedPartition = PartitionEx->Mbr.RecognizedPartition;
  65. Partition->HiddenSectors = PartitionEx->Mbr.HiddenSectors;
  66. }
  67. return Layout;
  68. }
  69. VOID
  70. DiskConvertPartitionToExtended(
  71. IN PPARTITION_INFORMATION Partition,
  72. OUT PPARTITION_INFORMATION_EX PartitionEx
  73. )
  74. /*++
  75. Routine Description:
  76. Convert a PARTITION_INFORMATION structure to a PARTITION_INFORMATION_EX
  77. structure.
  78. Arguments:
  79. Partition - A pointer to the PARTITION_INFORMATION structure to convert.
  80. PartitionEx - A pointer to a buffer where the converted
  81. PARTITION_INFORMATION_EX structure is to be stored.
  82. Return Values:
  83. None.
  84. --*/
  85. {
  86. PAGED_CODE ();
  87. ASSERT ( PartitionEx != NULL );
  88. ASSERT ( Partition != NULL );
  89. PartitionEx->PartitionStyle = PARTITION_STYLE_MBR;
  90. PartitionEx->StartingOffset = Partition->StartingOffset;
  91. PartitionEx->PartitionLength = Partition->PartitionLength;
  92. PartitionEx->RewritePartition = Partition->RewritePartition;
  93. PartitionEx->PartitionNumber = Partition->PartitionNumber;
  94. PartitionEx->Mbr.PartitionType = Partition->PartitionType;
  95. PartitionEx->Mbr.BootIndicator = Partition->BootIndicator;
  96. PartitionEx->Mbr.RecognizedPartition = Partition->RecognizedPartition;
  97. PartitionEx->Mbr.HiddenSectors = Partition->HiddenSectors;
  98. }
  99. PDRIVE_LAYOUT_INFORMATION_EX
  100. DiskConvertLayoutToExtended(
  101. IN CONST PDRIVE_LAYOUT_INFORMATION Layout
  102. )
  103. /*++
  104. Routine Description:
  105. Convert a DRIVE_LAYOUT_INFORMATION structure into a
  106. DRIVE_LAYOUT_INFORMATION_EX structure.
  107. Arguments:
  108. Layout - The source DRIVE_LAYOUT_INFORMATION structure.
  109. Return Values:
  110. The resultant DRIVE_LAYOUT_INFORMATION_EX structure. This buffer must
  111. be freed by the callee using ExFreePool.
  112. --*/
  113. {
  114. ULONG i;
  115. ULONG size;
  116. PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
  117. PAGED_CODE ();
  118. ASSERT ( Layout != NULL );
  119. //
  120. // Allocate enough space for a DRIVE_LAYOUT_INFORMATION_EX structure
  121. // plus as many PARTITION_INFORMATION_EX structures as are in the
  122. // source array.
  123. //
  124. size = FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]) +
  125. Layout->PartitionCount * sizeof ( PARTITION_INFORMATION_EX );
  126. layoutEx = ExAllocatePoolWithTag(
  127. NonPagedPool,
  128. size,
  129. DISK_TAG_PART_LIST
  130. );
  131. if ( layoutEx == NULL ) {
  132. return NULL;
  133. }
  134. //
  135. // Convert the disk information.
  136. //
  137. layoutEx->PartitionStyle = PARTITION_STYLE_MBR;
  138. layoutEx->PartitionCount = Layout->PartitionCount;
  139. layoutEx->Mbr.Signature = Layout->Signature;
  140. for (i = 0; i < Layout->PartitionCount; i++) {
  141. //
  142. // Convert each entry.
  143. //
  144. DiskConvertPartitionToExtended (
  145. &Layout->PartitionEntry[i],
  146. &layoutEx->PartitionEntry[i]
  147. );
  148. }
  149. return layoutEx;
  150. }
  151. NTSTATUS
  152. DiskEnumerateDevice(
  153. IN PDEVICE_OBJECT Fdo
  154. )
  155. /*++
  156. Routine Description:
  157. This routine is called by the class driver to update the PDO list off
  158. of this FDO. The disk driver also calls it internally to re-create
  159. device objects.
  160. This routine will read the partition table and create new PDO objects as
  161. necessary. PDO's that no longer exist will be pulled out of the PDO list
  162. so that pnp will destroy them.
  163. Arguments:
  164. Fdo - a pointer to the FDO being re-enumerated
  165. Return Value:
  166. status
  167. --*/
  168. {
  169. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  170. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  171. PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
  172. PDISK_DATA diskData = (PDISK_DATA) commonExtension->DriverData;
  173. PDEVICE_OBJECT pdo = NULL;
  174. ULONG numberListElements = 0;
  175. PDRIVE_LAYOUT_INFORMATION_EX partitionList;
  176. NTSTATUS status;
  177. ASSERT(commonExtension->IsFdo);
  178. PAGED_CODE();
  179. //
  180. // Update our image of the size of the drive. This may be necessary if
  181. // the drive size is extended or we just released a reservation to
  182. // ensure the kernel doesn't reject the partition table.
  183. //
  184. DiskReadDriveCapacity(Fdo);
  185. //
  186. // Lock out anyone else trying to repartition the disk.
  187. //
  188. DiskAcquirePartitioningLock(fdoExtension);
  189. //
  190. // Create objects for all the partitions on the device.
  191. //
  192. status = DiskReadPartitionTableEx(fdoExtension, FALSE, &partitionList);
  193. //
  194. // If the I/O read partition table failed and this is a removable device,
  195. // then fix up the partition list to make it look like there is one
  196. // zero length partition.
  197. //
  198. if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) &&
  199. Fdo->Characteristics & FILE_REMOVABLE_MEDIA) {
  200. SIZE_T partitionListSize;
  201. //
  202. // Remember whether the drive is ready.
  203. //
  204. diskData->ReadyStatus = status;
  205. //
  206. // Allocate and zero a partition list.
  207. //
  208. partitionListSize =
  209. FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]);
  210. partitionList = ExAllocatePoolWithTag(NonPagedPool,
  211. partitionListSize,
  212. DISK_TAG_PART_LIST);
  213. if (partitionList != NULL) {
  214. RtlZeroMemory( partitionList, partitionListSize );
  215. //
  216. // Set the partition count to one and the status to success
  217. // so one device object will be created. Set the partition type
  218. // to a bogus value.
  219. //
  220. partitionList->PartitionStyle = PARTITION_STYLE_MBR;
  221. partitionList->PartitionCount = 1;
  222. status = STATUS_SUCCESS;
  223. } else {
  224. status = STATUS_INSUFFICIENT_RESOURCES;
  225. }
  226. }
  227. if (NT_SUCCESS(status)) {
  228. diskData->UpdatePartitionRoutine(Fdo, partitionList);
  229. //
  230. // Record disk signature.
  231. //
  232. if (partitionList->PartitionStyle == PARTITION_STYLE_MBR) {
  233. diskData->PartitionStyle = PARTITION_STYLE_MBR;
  234. diskData->Mbr.Signature = partitionList->Mbr.Signature;
  235. } else {
  236. diskData->PartitionStyle = PARTITION_STYLE_GPT;
  237. diskData->Efi.DiskId = partitionList->Gpt.DiskId;
  238. }
  239. }
  240. DiskReleasePartitioningLock(fdoExtension);
  241. return(STATUS_SUCCESS);
  242. } // end DiskEnumerateDevice()
  243. VOID
  244. DiskUpdateRemovablePartitions(
  245. IN PDEVICE_OBJECT Fdo,
  246. IN OUT PDRIVE_LAYOUT_INFORMATION_EX PartitionList
  247. )
  248. /*++
  249. Routine Description:
  250. This routine is called by the class DLL to update the PDO list off of this
  251. FDO. The disk driver also calls it internally to re-create device objects.
  252. This routine will read the partition table and update the size of the
  253. single partition device object which always exists for removable devices.
  254. Arguments:
  255. Fdo - a pointer to the FDO being reenumerated.
  256. Return Value:
  257. status
  258. --*/
  259. {
  260. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  261. PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
  262. ULONG partitionCount;
  263. ULONG partitionNumber;
  264. ULONG partitionOrdinal = 0;
  265. ULONG newPartitionNumber;
  266. PDISK_DATA pdoData;
  267. NTSTATUS status;
  268. PPARTITION_INFORMATION_EX partitionEntry;
  269. PARTITION_STYLE partitionStyle;
  270. PAGED_CODE();
  271. ASSERT(Fdo->Characteristics & FILE_REMOVABLE_MEDIA);
  272. partitionStyle = PartitionList->PartitionStyle;
  273. partitionCount = PartitionList->PartitionCount;
  274. for(partitionNumber = 0;
  275. partitionNumber < partitionCount;
  276. partitionNumber++) {
  277. partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
  278. partitionEntry->PartitionNumber = 0;
  279. }
  280. //
  281. // Get exclusive access to the child list while repartitioning.
  282. //
  283. ClassAcquireChildLock(fdoExtension);
  284. //
  285. // Removable media should never have more than one PDO.
  286. //
  287. pdoExtension = fdoExtension->CommonExtension.ChildList;
  288. if(pdoExtension == NULL) {
  289. PARTITION_INFORMATION_EX tmpPartitionEntry;
  290. PDEVICE_OBJECT pdo;
  291. //
  292. // There is no PDO currently. Create one and pre-initialize it with
  293. // a zero length.
  294. //
  295. RtlZeroMemory(&tmpPartitionEntry, sizeof(tmpPartitionEntry));
  296. tmpPartitionEntry.PartitionNumber = 1;
  297. DebugPrint((1, "DiskUpdateRemovablePartitions: Creating RM partition\n"));
  298. status = DiskCreatePdo(Fdo,
  299. 0,
  300. &tmpPartitionEntry,
  301. partitionStyle,
  302. &pdo);
  303. if(!NT_SUCCESS(status)) {
  304. DebugPrint((1, "DiskUpdateRemovablePartitions: error %lx creating "
  305. "new PDO for RM partition\n",
  306. status));
  307. ClassReleaseChildLock(fdoExtension);
  308. return;
  309. }
  310. //
  311. // mark the new device as enumerated
  312. //
  313. pdoExtension = pdo->DeviceExtension;
  314. pdoExtension->IsMissing = FALSE;
  315. }
  316. pdoData = pdoExtension->CommonExtension.DriverData;
  317. //
  318. // Search the partition list for a valid entry. We're looking for a
  319. // primary partition since we only support the one.
  320. //
  321. for(partitionNumber = 0;
  322. partitionNumber < partitionCount;
  323. partitionNumber++) {
  324. partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
  325. //
  326. // Is this partition interesting?
  327. //
  328. if (partitionStyle == PARTITION_STYLE_MBR) {
  329. if(partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
  330. IsContainerPartition(partitionEntry->Mbr.PartitionType)) {
  331. continue;
  332. }
  333. }
  334. partitionOrdinal++;
  335. //
  336. // We have found the first and thus only partition allowed on
  337. // this disk. Update the information in the PDO to match the new
  338. // partition.
  339. //
  340. DebugPrint((1, "DiskUpdateRemovablePartitions: Matched %wZ to #%d, "
  341. "ordinal %d\n",
  342. &pdoExtension->CommonExtension.DeviceName,
  343. partitionEntry->PartitionNumber,
  344. partitionOrdinal));
  345. partitionEntry->PartitionNumber = 1;
  346. pdoData->PartitionStyle = partitionStyle;
  347. pdoData->PartitionOrdinal = partitionOrdinal;
  348. ASSERT(partitionEntry->PartitionLength.LowPart != 0x23456789);
  349. pdoExtension->CommonExtension.StartingOffset =
  350. partitionEntry->StartingOffset;
  351. pdoExtension->CommonExtension.PartitionLength =
  352. partitionEntry->PartitionLength;
  353. if (partitionStyle == PARTITION_STYLE_MBR) {
  354. pdoData->Mbr.HiddenSectors = partitionEntry->Mbr.HiddenSectors;
  355. pdoData->Mbr.BootIndicator = partitionEntry->Mbr.BootIndicator;
  356. //
  357. // If this partition is being re-written then update the type
  358. // information as well
  359. //
  360. if (partitionEntry->RewritePartition) {
  361. pdoData->Mbr.PartitionType = partitionEntry->Mbr.PartitionType;
  362. }
  363. } else {
  364. pdoData->Efi.PartitionType = partitionEntry->Gpt.PartitionType;
  365. pdoData->Efi.PartitionId = partitionEntry->Gpt.PartitionId;
  366. pdoData->Efi.Attributes = partitionEntry->Gpt.Attributes;
  367. RtlCopyMemory(
  368. pdoData->Efi.PartitionName,
  369. partitionEntry->Gpt.Name,
  370. sizeof (pdoData->Efi.PartitionName)
  371. );
  372. }
  373. //
  374. // Mark this one as found
  375. //
  376. pdoExtension->IsMissing = FALSE;
  377. ClassReleaseChildLock(fdoExtension);
  378. return;
  379. }
  380. //
  381. // No interesting partition was found.
  382. //
  383. if (partitionStyle == PARTITION_STYLE_MBR) {
  384. pdoData->Mbr.HiddenSectors = 0;
  385. pdoData->Mbr.PartitionType = PARTITION_ENTRY_UNUSED;
  386. } else {
  387. RtlZeroMemory (&pdoData->Efi,
  388. sizeof (pdoData->Efi)
  389. );
  390. }
  391. pdoExtension->CommonExtension.StartingOffset.QuadPart = 0;
  392. pdoExtension->CommonExtension.PartitionLength.QuadPart = 0;
  393. ClassReleaseChildLock(fdoExtension);
  394. return;
  395. }
  396. VOID
  397. DiskUpdatePartitions(
  398. IN PDEVICE_OBJECT Fdo,
  399. IN OUT PDRIVE_LAYOUT_INFORMATION_EX PartitionList
  400. )
  401. /*++
  402. Routine Description:
  403. This routine will synchronize the information held in the partition list
  404. with the device objects hanging off this Fdo. Any new partition objects
  405. will be created, any non-existant ones will be marked as un-enumerated.
  406. This will be done in several stages:
  407. * Clear state (partition number) from every entry in the partition
  408. list
  409. * Set IsMissing flag on every child of this FDO
  410. * For each child of the FDO:
  411. if a matching partition exists in the partition list,
  412. update the partition number in the table, update the
  413. ordinal in the object and mark the object as enumerated
  414. * For each un-enumerated device object
  415. zero out the partition information to invalidate the device
  416. delete the symbolic link if any
  417. * For each un-matched entry in the partition list:
  418. create a new partition object
  419. update the partition number in the list entry
  420. create a new symbolic link if necessary
  421. Arguments:
  422. Fdo - a pointer to the functional device object this partition list is for
  423. PartitionList - a pointer to the partition list being updated
  424. Return Value:
  425. none
  426. --*/
  427. {
  428. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  429. PPHYSICAL_DEVICE_EXTENSION oldChildList = NULL;
  430. PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
  431. ULONG partitionCount;
  432. ULONG partitionNumber;
  433. ULONG partitionOrdinal;
  434. ULONG newPartitionNumber;
  435. PPARTITION_INFORMATION_EX partitionEntry;
  436. PDISK_DATA pdoData;
  437. PARTITION_STYLE partitionStyle;
  438. NTSTATUS status;
  439. PAGED_CODE();
  440. //
  441. // Get exclusive access to the child list.
  442. //
  443. ClassAcquireChildLock(fdoExtension);
  444. partitionStyle = PartitionList->PartitionStyle;
  445. partitionCount = PartitionList->PartitionCount;
  446. //
  447. // Pull all the child device objects off the children list. We'll
  448. // add them back later.
  449. //
  450. oldChildList = fdoExtension->CommonExtension.ChildList;
  451. fdoExtension->CommonExtension.ChildList = NULL;
  452. //
  453. // Clear the partition numbers from the list entries
  454. //
  455. for(partitionNumber = 0;
  456. partitionNumber < partitionCount;
  457. partitionNumber++) {
  458. partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
  459. partitionEntry->PartitionNumber = 0;
  460. }
  461. //
  462. // Now match each child partition to it's entry (if any) in the partition
  463. // list.
  464. //
  465. while(oldChildList != NULL) {
  466. pdoExtension = oldChildList;
  467. pdoData = pdoExtension->CommonExtension.DriverData;
  468. //
  469. // Check all partition entries for a match on offset and length
  470. //
  471. partitionOrdinal = 0;
  472. for(partitionNumber = 0;
  473. partitionNumber < partitionCount;
  474. partitionNumber++) {
  475. partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
  476. //
  477. // Is this an interesting partition entry?
  478. //
  479. if (partitionStyle == PARTITION_STYLE_MBR) {
  480. if((partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) ||
  481. (IsContainerPartition(partitionEntry->Mbr.PartitionType))) {
  482. continue;
  483. }
  484. }
  485. partitionOrdinal++;
  486. if(partitionEntry->PartitionNumber) {
  487. //
  488. // This partition has already been found - skip it
  489. //
  490. continue;
  491. }
  492. //
  493. // Let's see if the partition information matches
  494. //
  495. if(partitionEntry->StartingOffset.QuadPart !=
  496. pdoExtension->CommonExtension.StartingOffset.QuadPart) {
  497. continue;
  498. }
  499. if(partitionEntry->PartitionLength.QuadPart !=
  500. pdoExtension->CommonExtension.PartitionLength.QuadPart) {
  501. continue;
  502. }
  503. //
  504. // Yep - it matches. Update the information in the entry
  505. //
  506. partitionEntry->PartitionNumber = pdoExtension->CommonExtension.PartitionNumber;
  507. if (partitionStyle == PARTITION_STYLE_MBR) {
  508. pdoData->Mbr.HiddenSectors = partitionEntry->Mbr.HiddenSectors;
  509. }
  510. break;
  511. }
  512. if(partitionNumber != partitionCount) {
  513. DebugPrint((1, "DiskUpdatePartitions: Matched %wZ to #%d, ordinal "
  514. "%d\n",
  515. &pdoExtension->CommonExtension.DeviceName,
  516. partitionEntry->PartitionNumber,
  517. partitionOrdinal));
  518. ASSERT(partitionEntry->PartitionLength.LowPart != 0x23456789);
  519. // ASSERT(pdoExtension->CommonExtension.PartitionLength.QuadPart != 0);
  520. pdoData->PartitionStyle = partitionStyle;
  521. //
  522. // we found a match - update the information in the device object
  523. // extension and driverdata
  524. //
  525. pdoData->PartitionOrdinal = partitionOrdinal;
  526. //
  527. // If this partition is being re-written then update the type
  528. // information as well
  529. //
  530. if (partitionStyle == PARTITION_STYLE_MBR) {
  531. if(partitionEntry->RewritePartition) {
  532. pdoData->Mbr.PartitionType = partitionEntry->Mbr.PartitionType;
  533. }
  534. } else {
  535. DebugPrint((1, "DiskUpdatePartitions: EFI Partition %ws\n",
  536. pdoData->Efi.PartitionName
  537. ));
  538. pdoData->Efi.PartitionType = partitionEntry->Gpt.PartitionType;
  539. pdoData->Efi.PartitionId = partitionEntry->Gpt.PartitionId;
  540. pdoData->Efi.Attributes = partitionEntry->Gpt.Attributes;
  541. RtlCopyMemory(
  542. pdoData->Efi.PartitionName,
  543. partitionEntry->Gpt.Name,
  544. sizeof (pdoData->Efi.PartitionName)
  545. );
  546. }
  547. //
  548. // Mark this one as found.
  549. //
  550. pdoExtension->IsMissing = FALSE;
  551. //
  552. // Pull it out of the old child list and add it into the
  553. // real one.
  554. //
  555. oldChildList = pdoExtension->CommonExtension.ChildList;
  556. pdoExtension->CommonExtension.ChildList =
  557. fdoExtension->CommonExtension.ChildList;
  558. fdoExtension->CommonExtension.ChildList = pdoExtension;
  559. } else {
  560. PDEVICE_OBJECT nextPdo;
  561. DebugPrint ((1, "DiskUpdatePartitions: Deleting %wZ\n",
  562. &pdoExtension->CommonExtension.DeviceName));
  563. if (partitionStyle == PARTITION_STYLE_GPT) {
  564. DebugPrint ((1, "DiskUpdatePartitions: EFI Partition %ws\n",
  565. pdoData->Efi.PartitionName
  566. ));
  567. }
  568. //
  569. // no matching entry in the partition list - throw this partition
  570. // object away
  571. //
  572. pdoExtension->CommonExtension.PartitionLength.QuadPart = 0;
  573. //
  574. // grab a pointer to the next child before we mark this one as
  575. // missing since missing devices could vanish at any time.
  576. //
  577. oldChildList = pdoExtension->CommonExtension.ChildList;
  578. pdoExtension->CommonExtension.ChildList = (PVOID) -1;
  579. //
  580. // Now tell the class driver that this child is "missing" - this
  581. // will cause it to be deleted.
  582. //
  583. ClassMarkChildMissing(pdoExtension, FALSE);
  584. }
  585. }
  586. //
  587. // At this point the old child list had best be empty.
  588. //
  589. ASSERT(oldChildList == NULL);
  590. //
  591. // Iterate through the partition entries and create any partition
  592. // objects that don't already exist
  593. //
  594. partitionOrdinal = 0;
  595. newPartitionNumber = 0;
  596. for(partitionNumber = 0;
  597. partitionNumber < partitionCount;
  598. partitionNumber++) {
  599. PDEVICE_OBJECT pdo;
  600. partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
  601. //
  602. // Is this partition interesting
  603. //
  604. if (partitionStyle == PARTITION_STYLE_MBR) {
  605. if((partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) ||
  606. (IsContainerPartition(partitionEntry->Mbr.PartitionType))) {
  607. continue;
  608. }
  609. }
  610. //
  611. // Increment the count of interesting partitions
  612. //
  613. partitionOrdinal++;
  614. newPartitionNumber++;
  615. //
  616. // Has this already been matched
  617. //
  618. if(partitionEntry->PartitionNumber == 0) {
  619. LONG i;
  620. //
  621. // find the first safe partition number for this device
  622. //
  623. for(i = 0; i < (LONG) partitionCount; i++) {
  624. PPARTITION_INFORMATION_EX tmp = &(PartitionList->PartitionEntry[i]);
  625. if (partitionStyle == PARTITION_STYLE_MBR) {
  626. if (tmp->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
  627. IsContainerPartition(tmp->Mbr.PartitionType)) {
  628. continue;
  629. }
  630. }
  631. if(tmp->PartitionNumber == newPartitionNumber) {
  632. //
  633. // Found a matching partition number - increment the count
  634. // and restart the scan.
  635. //
  636. newPartitionNumber++;
  637. i = -1;
  638. continue;
  639. }
  640. }
  641. //
  642. // Assign this partition a partition number
  643. //
  644. partitionEntry->PartitionNumber = newPartitionNumber;
  645. DebugPrint((1, "DiskUpdatePartitions: Found new partition #%d, ord %d "
  646. "starting at %#016I64x and running for %#016I64x\n",
  647. partitionEntry->PartitionNumber,
  648. partitionOrdinal,
  649. partitionEntry->StartingOffset.QuadPart,
  650. partitionEntry->PartitionLength.QuadPart));
  651. ClassReleaseChildLock(fdoExtension);
  652. status = DiskCreatePdo(Fdo,
  653. partitionOrdinal,
  654. partitionEntry,
  655. partitionStyle,
  656. &pdo);
  657. ClassAcquireChildLock(fdoExtension);
  658. if(!NT_SUCCESS(status)) {
  659. DebugPrint((1, "DiskUpdatePartitions: error %lx creating "
  660. "new PDO for partition ordinal %d, number %d\n",
  661. status,
  662. partitionOrdinal,
  663. partitionEntry->PartitionNumber));
  664. //
  665. // don't increment the partition number - we'll try to reuse
  666. // it for the next child.
  667. //
  668. partitionEntry->PartitionNumber = 0;
  669. newPartitionNumber--;
  670. continue;
  671. }
  672. //
  673. // mark the new device as enumerated
  674. //
  675. pdoExtension = pdo->DeviceExtension;
  676. pdoExtension->IsMissing = FALSE;
  677. //
  678. // This number's taken already - try to scanning the partition
  679. // table more than once for a new number.
  680. //
  681. }
  682. }
  683. //
  684. // ISSUE - 2000/02/09 - math: Review.
  685. // Is PartitionStyle the only field that needs updating?
  686. //
  687. {
  688. PCOMMON_DEVICE_EXTENSION commonExtension;
  689. PDISK_DATA diskData;
  690. commonExtension = Fdo->DeviceExtension;
  691. diskData = (PDISK_DATA)(commonExtension->DriverData);
  692. diskData->PartitionStyle = partitionStyle;
  693. }
  694. ClassReleaseChildLock(fdoExtension);
  695. return;
  696. }
  697. NTSTATUS
  698. DiskCreatePdo(
  699. IN PDEVICE_OBJECT Fdo,
  700. IN ULONG PartitionOrdinal,
  701. IN PPARTITION_INFORMATION_EX PartitionEntry,
  702. IN PARTITION_STYLE PartitionStyle,
  703. OUT PDEVICE_OBJECT *Pdo
  704. )
  705. /*++
  706. Routine Description:
  707. This routine will create and initialize a new partition device object
  708. (PDO) and insert it into the FDO partition list.
  709. Arguments:
  710. Fdo - a pointer to the functional device object this PDO will be a child
  711. of
  712. PartitionOrdinal - the partition ordinal for this PDO
  713. PartitionEntry - the partition information for this device object
  714. PartitionStyle - what style of partition table entry PartitionEntry is;
  715. currently either MBR or EFI
  716. Pdo - a location to store the pdo pointer upon successful completion
  717. Return Value:
  718. status
  719. --*/
  720. {
  721. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  722. PDEVICE_OBJECT pdo = NULL;
  723. PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
  724. PUCHAR deviceName = NULL;
  725. PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData;
  726. ULONG numberListElements;
  727. NTSTATUS status = STATUS_SUCCESS;
  728. PAGED_CODE();
  729. //
  730. // Create partition object and set up partition parameters.
  731. //
  732. status = DiskGenerateDeviceName(FALSE,
  733. fdoExtension->DeviceNumber,
  734. PartitionEntry->PartitionNumber,
  735. &PartitionEntry->StartingOffset,
  736. &PartitionEntry->PartitionLength,
  737. &deviceName);
  738. if(!NT_SUCCESS(status)) {
  739. DebugPrint((1, "DiskCreatePdo - Can't generate name %lx\n", status));
  740. return status;
  741. }
  742. DebugPrint((2, "DiskCreatePdo: Create device object %s\n", deviceName));
  743. status = ClassCreateDeviceObject(Fdo->DriverObject,
  744. deviceName,
  745. Fdo,
  746. FALSE,
  747. &pdo);
  748. if (!NT_SUCCESS(status)) {
  749. DebugPrint((1, "DiskEnumerateDevice: Can't create device object for %s\n", deviceName));
  750. return status;
  751. }
  752. //
  753. // Set up device extension fields.
  754. //
  755. pdoExtension = pdo->DeviceExtension;
  756. //
  757. // Set up device object fields.
  758. //
  759. SET_FLAG(pdo->Flags, DO_DIRECT_IO);
  760. pdo->StackSize = (CCHAR)
  761. pdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1;
  762. //
  763. // Get pointer to new disk data.
  764. //
  765. diskData = (PDISK_DATA) pdoExtension->CommonExtension.DriverData;
  766. //
  767. // Set the alignment requirements for the device based on the
  768. // host adapter requirements
  769. //
  770. if (Fdo->AlignmentRequirement > pdo->AlignmentRequirement) {
  771. pdo->AlignmentRequirement = Fdo->AlignmentRequirement;
  772. }
  773. if (fdoExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
  774. numberListElements = 30;
  775. } else {
  776. numberListElements = 8;
  777. }
  778. //
  779. // Build the lookaside list for srb's for this partition based on
  780. // whether the adapter and disk can do tagged queueing. Don't bother to
  781. // check the status - this can't fail when called for a PDO.
  782. //
  783. ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION) pdoExtension,
  784. numberListElements);
  785. //
  786. // Set the sense-data pointer in the device extension.
  787. //
  788. diskData->PartitionOrdinal = PartitionOrdinal;
  789. pdoExtension->CommonExtension.PartitionNumber = PartitionEntry->PartitionNumber;
  790. //
  791. // Initialize relevant data.
  792. //
  793. if (PartitionStyle == PARTITION_STYLE_MBR) {
  794. diskData->Mbr.PartitionType = PartitionEntry->Mbr.PartitionType;
  795. diskData->Mbr.BootIndicator = PartitionEntry->Mbr.BootIndicator;
  796. diskData->Mbr.HiddenSectors = PartitionEntry->Mbr.HiddenSectors;
  797. } else {
  798. diskData->Efi.PartitionType = PartitionEntry->Gpt.PartitionType;
  799. diskData->Efi.PartitionId = PartitionEntry->Gpt.PartitionType;
  800. diskData->Efi.Attributes = PartitionEntry->Gpt.Attributes;
  801. RtlCopyMemory (diskData->Efi.PartitionName,
  802. PartitionEntry->Gpt.Name,
  803. sizeof (diskData->Efi.PartitionName)
  804. );
  805. }
  806. DebugPrint((2, "DiskEnumerateDevice: Partition type is %x\n",
  807. diskData->Mbr.PartitionType));
  808. pdoExtension->CommonExtension.StartingOffset =
  809. PartitionEntry->StartingOffset;
  810. pdoExtension->CommonExtension.PartitionLength =
  811. PartitionEntry->PartitionLength;
  812. DebugPrint((1, "DiskCreatePdo: hidden sectors value for pdo %#p set to %#x\n",
  813. pdo,
  814. diskData->Mbr.HiddenSectors));
  815. //
  816. // Check for removable media support.
  817. //
  818. if (fdoExtension->DeviceDescriptor->RemovableMedia) {
  819. SET_FLAG(pdo->Characteristics, FILE_REMOVABLE_MEDIA);
  820. }
  821. pdoExtension->CommonExtension.DeviceObject = pdo;
  822. CLEAR_FLAG(pdo->Flags, DO_DEVICE_INITIALIZING);
  823. *Pdo = pdo;
  824. return status;
  825. }
  826. VOID
  827. DiskAcquirePartitioningLock(
  828. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  829. )
  830. {
  831. PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
  832. PAGED_CODE();
  833. ASSERT_FDO(FdoExtension->DeviceObject);
  834. KeWaitForSingleObject(&(diskData->PartitioningEvent),
  835. UserRequest,
  836. UserMode,
  837. FALSE,
  838. NULL);
  839. return;
  840. }
  841. VOID
  842. DiskReleasePartitioningLock(
  843. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  844. )
  845. {
  846. PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
  847. PAGED_CODE();
  848. ASSERT_FDO(FdoExtension->DeviceObject);
  849. KeSetEvent(&(diskData->PartitioningEvent), IO_NO_INCREMENT, FALSE);
  850. return;
  851. }