- Import disk.sys from Windows XP DDK
[reactos.git] / drivers / storage / class / disk_new / enum.c
1 /*++
2
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4
5 Module Name:
6
7 pnp.c
8
9 Abstract:
10
11 SCSI disk class driver
12
13 Environment:
14
15 kernel mode only
16
17 Notes:
18
19 Revision History:
20
21 --*/
22
23 #include "disk.h"
24
25 #ifdef ALLOC_PRAGMA
26
27 #pragma alloc_text(PAGE, DiskConvertExtendedToLayout)
28 #pragma alloc_text(PAGE, DiskConvertPartitionToExtended)
29 #pragma alloc_text(PAGE, DiskConvertLayoutToExtended)
30 #pragma alloc_text(PAGE, DiskCreatePdo)
31 #pragma alloc_text(PAGE, DiskEnumerateDevice)
32 #pragma alloc_text(PAGE, DiskUpdateRemovablePartitions)
33 #pragma alloc_text(PAGE, DiskUpdatePartitions)
34 #pragma alloc_text(PAGE, DiskCreatePdo)
35
36 #endif
37
38 PDRIVE_LAYOUT_INFORMATION
39 DiskConvertExtendedToLayout(
40 IN CONST PDRIVE_LAYOUT_INFORMATION_EX LayoutEx
41 )
42 {
43 ULONG i;
44 ULONG LayoutSize;
45 PDRIVE_LAYOUT_INFORMATION Layout;
46 PPARTITION_INFORMATION Partition;
47 PPARTITION_INFORMATION_EX PartitionEx;
48
49 PAGED_CODE ();
50
51 ASSERT ( LayoutEx );
52
53
54 //
55 // The only valid conversion is from an MBR extended layout structure to
56 // the old structure.
57 //
58
59 if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR) {
60 ASSERT ( FALSE );
61 return NULL;
62 }
63
64 LayoutSize = FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]) +
65 LayoutEx->PartitionCount * sizeof (PARTITION_INFORMATION);
66
67 Layout = ExAllocatePoolWithTag (
68 NonPagedPool,
69 LayoutSize,
70 DISK_TAG_PART_LIST
71 );
72
73 if ( Layout == NULL ) {
74 return NULL;
75 }
76
77 Layout->Signature = LayoutEx->Mbr.Signature;
78 Layout->PartitionCount = LayoutEx->PartitionCount;
79
80 for (i = 0; i < LayoutEx->PartitionCount; i++) {
81
82 Partition = &Layout->PartitionEntry[i];
83 PartitionEx = &LayoutEx->PartitionEntry[i];
84
85 Partition->StartingOffset = PartitionEx->StartingOffset;
86 Partition->PartitionLength = PartitionEx->PartitionLength;
87 Partition->RewritePartition = PartitionEx->RewritePartition;
88 Partition->PartitionNumber = PartitionEx->PartitionNumber;
89
90 Partition->PartitionType = PartitionEx->Mbr.PartitionType;
91 Partition->BootIndicator = PartitionEx->Mbr.BootIndicator;
92 Partition->RecognizedPartition = PartitionEx->Mbr.RecognizedPartition;
93 Partition->HiddenSectors = PartitionEx->Mbr.HiddenSectors;
94 }
95
96 return Layout;
97 }
98
99 VOID
100 DiskConvertPartitionToExtended(
101 IN PPARTITION_INFORMATION Partition,
102 OUT PPARTITION_INFORMATION_EX PartitionEx
103 )
104
105 /*++
106
107 Routine Description:
108
109 Convert a PARTITION_INFORMATION structure to a PARTITION_INFORMATION_EX
110 structure.
111
112 Arguments:
113
114 Partition - A pointer to the PARTITION_INFORMATION structure to convert.
115
116 PartitionEx - A pointer to a buffer where the converted
117 PARTITION_INFORMATION_EX structure is to be stored.
118
119 Return Values:
120
121 None.
122
123 --*/
124
125 {
126 PAGED_CODE ();
127
128 ASSERT ( PartitionEx != NULL );
129 ASSERT ( Partition != NULL );
130
131 PartitionEx->PartitionStyle = PARTITION_STYLE_MBR;
132 PartitionEx->StartingOffset = Partition->StartingOffset;
133 PartitionEx->PartitionLength = Partition->PartitionLength;
134 PartitionEx->RewritePartition = Partition->RewritePartition;
135 PartitionEx->PartitionNumber = Partition->PartitionNumber;
136
137 PartitionEx->Mbr.PartitionType = Partition->PartitionType;
138 PartitionEx->Mbr.BootIndicator = Partition->BootIndicator;
139 PartitionEx->Mbr.RecognizedPartition = Partition->RecognizedPartition;
140 PartitionEx->Mbr.HiddenSectors = Partition->HiddenSectors;
141 }
142
143
144 PDRIVE_LAYOUT_INFORMATION_EX
145 DiskConvertLayoutToExtended(
146 IN CONST PDRIVE_LAYOUT_INFORMATION Layout
147 )
148
149 /*++
150
151 Routine Description:
152
153 Convert a DRIVE_LAYOUT_INFORMATION structure into a
154 DRIVE_LAYOUT_INFORMATION_EX structure.
155
156 Arguments:
157
158 Layout - The source DRIVE_LAYOUT_INFORMATION structure.
159
160 Return Values:
161
162 The resultant DRIVE_LAYOUT_INFORMATION_EX structure. This buffer must
163 be freed by the callee using ExFreePool.
164
165 --*/
166
167 {
168 ULONG i;
169 ULONG size;
170 PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
171
172 PAGED_CODE ();
173
174 ASSERT ( Layout != NULL );
175
176
177 //
178 // Allocate enough space for a DRIVE_LAYOUT_INFORMATION_EX structure
179 // plus as many PARTITION_INFORMATION_EX structures as are in the
180 // source array.
181 //
182
183 size = FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]) +
184 Layout->PartitionCount * sizeof ( PARTITION_INFORMATION_EX );
185
186 layoutEx = ExAllocatePoolWithTag(
187 NonPagedPool,
188 size,
189 DISK_TAG_PART_LIST
190 );
191
192 if ( layoutEx == NULL ) {
193 return NULL;
194 }
195
196 //
197 // Convert the disk information.
198 //
199
200 layoutEx->PartitionStyle = PARTITION_STYLE_MBR;
201 layoutEx->PartitionCount = Layout->PartitionCount;
202 layoutEx->Mbr.Signature = Layout->Signature;
203
204 for (i = 0; i < Layout->PartitionCount; i++) {
205
206 //
207 // Convert each entry.
208 //
209
210 DiskConvertPartitionToExtended (
211 &Layout->PartitionEntry[i],
212 &layoutEx->PartitionEntry[i]
213 );
214 }
215
216 return layoutEx;
217 }
218
219
220 \f
221 NTSTATUS
222 NTAPI
223 DiskEnumerateDevice(
224 IN PDEVICE_OBJECT Fdo
225 )
226
227 /*++
228
229 Routine Description:
230
231 This routine is called by the class driver to update the PDO list off
232 of this FDO. The disk driver also calls it internally to re-create
233 device objects.
234
235 This routine will read the partition table and create new PDO objects as
236 necessary. PDO's that no longer exist will be pulled out of the PDO list
237 so that pnp will destroy them.
238
239 Arguments:
240
241 Fdo - a pointer to the FDO being re-enumerated
242
243 Return Value:
244
245 status
246
247 --*/
248
249 {
250 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
251 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
252
253 PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
254
255 PDISK_DATA diskData = (PDISK_DATA) commonExtension->DriverData;
256
257 PDEVICE_OBJECT pdo = NULL;
258
259 ULONG numberListElements = 0;
260
261 PDRIVE_LAYOUT_INFORMATION_EX partitionList;
262
263 NTSTATUS status;
264
265 ASSERT(commonExtension->IsFdo);
266
267 PAGED_CODE();
268
269 //
270 // Update our image of the size of the drive. This may be necessary if
271 // the drive size is extended or we just released a reservation to
272 // ensure the kernel doesn't reject the partition table.
273 //
274
275 DiskReadDriveCapacity(Fdo);
276
277 //
278 // Lock out anyone else trying to repartition the disk.
279 //
280
281 DiskAcquirePartitioningLock(fdoExtension);
282
283 //
284 // Create objects for all the partitions on the device.
285 //
286
287 status = DiskReadPartitionTableEx(fdoExtension, FALSE, &partitionList);
288
289 //
290 // If the I/O read partition table failed and this is a removable device,
291 // then fix up the partition list to make it look like there is one
292 // zero length partition.
293 //
294
295 if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) &&
296 Fdo->Characteristics & FILE_REMOVABLE_MEDIA) {
297
298 SIZE_T partitionListSize;
299
300 //
301 // Remember whether the drive is ready.
302 //
303
304 diskData->ReadyStatus = status;
305
306 //
307 // Allocate and zero a partition list.
308 //
309
310 partitionListSize =
311 FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]);
312
313 partitionList = ExAllocatePoolWithTag(NonPagedPool,
314 partitionListSize,
315 DISK_TAG_PART_LIST);
316
317 if (partitionList != NULL) {
318
319 RtlZeroMemory( partitionList, partitionListSize );
320
321 //
322 // Set the partition count to one and the status to success
323 // so one device object will be created. Set the partition type
324 // to a bogus value.
325 //
326
327 partitionList->PartitionStyle = PARTITION_STYLE_MBR;
328 partitionList->PartitionCount = 1;
329
330 status = STATUS_SUCCESS;
331 } else {
332 status = STATUS_INSUFFICIENT_RESOURCES;
333 }
334 }
335
336 if (NT_SUCCESS(status)) {
337
338 diskData->UpdatePartitionRoutine(Fdo, partitionList);
339
340 //
341 // Record disk signature.
342 //
343
344 if (partitionList->PartitionStyle == PARTITION_STYLE_MBR) {
345
346 diskData->PartitionStyle = PARTITION_STYLE_MBR;
347 diskData->Mbr.Signature = partitionList->Mbr.Signature;
348
349 } else {
350
351 diskData->PartitionStyle = PARTITION_STYLE_GPT;
352 diskData->Efi.DiskId = partitionList->Gpt.DiskId;
353 }
354 }
355
356 DiskReleasePartitioningLock(fdoExtension);
357
358 return(STATUS_SUCCESS);
359
360 } // end DiskEnumerateDevice()
361
362 \f
363 VOID
364 DiskUpdateRemovablePartitions(
365 IN PDEVICE_OBJECT Fdo,
366 IN OUT PDRIVE_LAYOUT_INFORMATION_EX PartitionList
367 )
368
369 /*++
370
371 Routine Description:
372
373 This routine is called by the class DLL to update the PDO list off of this
374 FDO. The disk driver also calls it internally to re-create device objects.
375
376 This routine will read the partition table and update the size of the
377 single partition device object which always exists for removable devices.
378
379 Arguments:
380
381 Fdo - a pointer to the FDO being reenumerated.
382
383 Return Value:
384
385 status
386
387 --*/
388
389 {
390
391 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
392
393 PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
394
395 ULONG partitionCount;
396
397 ULONG partitionNumber;
398 ULONG partitionOrdinal = 0;
399 ULONG newPartitionNumber;
400
401 PDISK_DATA pdoData;
402 NTSTATUS status;
403
404 PPARTITION_INFORMATION_EX partitionEntry;
405 PARTITION_STYLE partitionStyle;
406
407 PAGED_CODE();
408
409 ASSERT(Fdo->Characteristics & FILE_REMOVABLE_MEDIA);
410
411 partitionStyle = PartitionList->PartitionStyle;
412 partitionCount = PartitionList->PartitionCount;
413
414 for(partitionNumber = 0;
415 partitionNumber < partitionCount;
416 partitionNumber++) {
417
418 partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
419
420 partitionEntry->PartitionNumber = 0;
421 }
422
423 //
424 // Get exclusive access to the child list while repartitioning.
425 //
426
427 ClassAcquireChildLock(fdoExtension);
428
429 //
430 // Removable media should never have more than one PDO.
431 //
432
433 pdoExtension = fdoExtension->CommonExtension.ChildList;
434
435 if(pdoExtension == NULL) {
436
437 PARTITION_INFORMATION_EX tmpPartitionEntry;
438 PDEVICE_OBJECT pdo;
439
440 //
441 // There is no PDO currently. Create one and pre-initialize it with
442 // a zero length.
443 //
444
445 RtlZeroMemory(&tmpPartitionEntry, sizeof(tmpPartitionEntry));
446
447 tmpPartitionEntry.PartitionNumber = 1;
448
449 DebugPrint((1, "DiskUpdateRemovablePartitions: Creating RM partition\n"));
450
451 status = DiskCreatePdo(Fdo,
452 0,
453 &tmpPartitionEntry,
454 partitionStyle,
455 &pdo);
456
457 if(!NT_SUCCESS(status)) {
458
459 DebugPrint((1, "DiskUpdateRemovablePartitions: error %lx creating "
460 "new PDO for RM partition\n",
461 status));
462
463 ClassReleaseChildLock(fdoExtension);
464 return;
465 }
466
467 //
468 // mark the new device as enumerated
469 //
470
471 pdoExtension = pdo->DeviceExtension;
472 pdoExtension->IsMissing = FALSE;
473
474 }
475
476 pdoData = pdoExtension->CommonExtension.DriverData;
477
478 //
479 // Search the partition list for a valid entry. We're looking for a
480 // primary partition since we only support the one.
481 //
482
483 for(partitionNumber = 0;
484 partitionNumber < partitionCount;
485 partitionNumber++) {
486
487 partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
488
489
490 //
491 // Is this partition interesting?
492 //
493
494 if (partitionStyle == PARTITION_STYLE_MBR) {
495
496 if(partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
497 IsContainerPartition(partitionEntry->Mbr.PartitionType)) {
498
499 continue;
500 }
501 }
502
503 partitionOrdinal++;
504
505 //
506 // We have found the first and thus only partition allowed on
507 // this disk. Update the information in the PDO to match the new
508 // partition.
509 //
510 DebugPrint((1, "DiskUpdateRemovablePartitions: Matched %wZ to #%d, "
511 "ordinal %d\n",
512 &pdoExtension->CommonExtension.DeviceName,
513 partitionEntry->PartitionNumber,
514 partitionOrdinal));
515
516
517 partitionEntry->PartitionNumber = 1;
518
519 pdoData->PartitionStyle = partitionStyle;
520 pdoData->PartitionOrdinal = partitionOrdinal;
521 ASSERT(partitionEntry->PartitionLength.LowPart != 0x23456789);
522
523 pdoExtension->CommonExtension.StartingOffset =
524 partitionEntry->StartingOffset;
525
526 pdoExtension->CommonExtension.PartitionLength =
527 partitionEntry->PartitionLength;
528
529
530 if (partitionStyle == PARTITION_STYLE_MBR) {
531
532 pdoData->Mbr.HiddenSectors = partitionEntry->Mbr.HiddenSectors;
533 pdoData->Mbr.BootIndicator = partitionEntry->Mbr.BootIndicator;
534
535
536 //
537 // If this partition is being re-written then update the type
538 // information as well
539 //
540
541 if (partitionEntry->RewritePartition) {
542 pdoData->Mbr.PartitionType = partitionEntry->Mbr.PartitionType;
543 }
544
545 } else {
546
547 pdoData->Efi.PartitionType = partitionEntry->Gpt.PartitionType;
548 pdoData->Efi.PartitionId = partitionEntry->Gpt.PartitionId;
549 pdoData->Efi.Attributes = partitionEntry->Gpt.Attributes;
550
551 RtlCopyMemory(
552 pdoData->Efi.PartitionName,
553 partitionEntry->Gpt.Name,
554 sizeof (pdoData->Efi.PartitionName)
555 );
556 }
557
558 //
559 // Mark this one as found
560 //
561
562 pdoExtension->IsMissing = FALSE;
563 ClassReleaseChildLock(fdoExtension);
564 return;
565 }
566
567 //
568 // No interesting partition was found.
569 //
570
571 if (partitionStyle == PARTITION_STYLE_MBR) {
572
573 pdoData->Mbr.HiddenSectors = 0;
574 pdoData->Mbr.PartitionType = PARTITION_ENTRY_UNUSED;
575
576 } else {
577
578 RtlZeroMemory (&pdoData->Efi,
579 sizeof (pdoData->Efi)
580 );
581 }
582
583 pdoExtension->CommonExtension.StartingOffset.QuadPart = 0;
584 pdoExtension->CommonExtension.PartitionLength.QuadPart = 0;
585
586 ClassReleaseChildLock(fdoExtension);
587 return;
588 }
589
590 \f
591 VOID
592 DiskUpdatePartitions(
593 IN PDEVICE_OBJECT Fdo,
594 IN OUT PDRIVE_LAYOUT_INFORMATION_EX PartitionList
595 )
596
597 /*++
598
599 Routine Description:
600
601 This routine will synchronize the information held in the partition list
602 with the device objects hanging off this Fdo. Any new partition objects
603 will be created, any non-existant ones will be marked as un-enumerated.
604
605 This will be done in several stages:
606
607 * Clear state (partition number) from every entry in the partition
608 list
609
610 * Set IsMissing flag on every child of this FDO
611
612 * For each child of the FDO:
613 if a matching partition exists in the partition list,
614 update the partition number in the table, update the
615 ordinal in the object and mark the object as enumerated
616
617 * For each un-enumerated device object
618 zero out the partition information to invalidate the device
619 delete the symbolic link if any
620
621 * For each un-matched entry in the partition list:
622 create a new partition object
623 update the partition number in the list entry
624 create a new symbolic link if necessary
625
626 Arguments:
627
628 Fdo - a pointer to the functional device object this partition list is for
629
630 PartitionList - a pointer to the partition list being updated
631
632 Return Value:
633
634 none
635
636 --*/
637
638 {
639 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
640
641 PPHYSICAL_DEVICE_EXTENSION oldChildList = NULL;
642 PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
643
644 ULONG partitionCount;
645
646 ULONG partitionNumber;
647 ULONG partitionOrdinal;
648 ULONG newPartitionNumber;
649
650 PPARTITION_INFORMATION_EX partitionEntry;
651 PDISK_DATA pdoData;
652 PARTITION_STYLE partitionStyle;
653
654 NTSTATUS status;
655
656 PAGED_CODE();
657
658 //
659 // Get exclusive access to the child list.
660 //
661
662 ClassAcquireChildLock(fdoExtension);
663
664 partitionStyle = PartitionList->PartitionStyle;
665
666 partitionCount = PartitionList->PartitionCount;
667
668 //
669 // Pull all the child device objects off the children list. We'll
670 // add them back later.
671 //
672
673 oldChildList = fdoExtension->CommonExtension.ChildList;
674 fdoExtension->CommonExtension.ChildList = NULL;
675
676 //
677 // Clear the partition numbers from the list entries
678 //
679
680 for(partitionNumber = 0;
681 partitionNumber < partitionCount;
682 partitionNumber++) {
683
684 partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
685 partitionEntry->PartitionNumber = 0;
686 }
687
688 //
689 // Now match each child partition to it's entry (if any) in the partition
690 // list.
691 //
692
693 while(oldChildList != NULL) {
694
695 pdoExtension = oldChildList;
696 pdoData = pdoExtension->CommonExtension.DriverData;
697
698 //
699 // Check all partition entries for a match on offset and length
700 //
701
702 partitionOrdinal = 0;
703
704 for(partitionNumber = 0;
705 partitionNumber < partitionCount;
706 partitionNumber++) {
707
708 partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
709
710 //
711 // Is this an interesting partition entry?
712 //
713
714 if (partitionStyle == PARTITION_STYLE_MBR) {
715
716 if((partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) ||
717 (IsContainerPartition(partitionEntry->Mbr.PartitionType))) {
718
719 continue;
720 }
721 }
722
723 partitionOrdinal++;
724
725 if(partitionEntry->PartitionNumber) {
726
727 //
728 // This partition has already been found - skip it
729 //
730
731 continue;
732 }
733
734 //
735 // Let's see if the partition information matches
736 //
737
738 if(partitionEntry->StartingOffset.QuadPart !=
739 pdoExtension->CommonExtension.StartingOffset.QuadPart) {
740 continue;
741 }
742
743 if(partitionEntry->PartitionLength.QuadPart !=
744 pdoExtension->CommonExtension.PartitionLength.QuadPart) {
745 continue;
746 }
747
748 //
749 // Yep - it matches. Update the information in the entry
750 //
751
752 partitionEntry->PartitionNumber = pdoExtension->CommonExtension.PartitionNumber;
753
754 if (partitionStyle == PARTITION_STYLE_MBR) {
755
756 pdoData->Mbr.HiddenSectors = partitionEntry->Mbr.HiddenSectors;
757
758 }
759
760 break;
761 }
762
763 if(partitionNumber != partitionCount) {
764
765 DebugPrint((1, "DiskUpdatePartitions: Matched %wZ to #%d, ordinal "
766 "%d\n",
767 &pdoExtension->CommonExtension.DeviceName,
768 partitionEntry->PartitionNumber,
769 partitionOrdinal));
770
771 ASSERT(partitionEntry->PartitionLength.LowPart != 0x23456789);
772 // ASSERT(pdoExtension->CommonExtension.PartitionLength.QuadPart != 0);
773
774 pdoData->PartitionStyle = partitionStyle;
775
776 //
777 // we found a match - update the information in the device object
778 // extension and driverdata
779 //
780
781 pdoData->PartitionOrdinal = partitionOrdinal;
782
783 //
784 // If this partition is being re-written then update the type
785 // information as well
786 //
787
788
789 if (partitionStyle == PARTITION_STYLE_MBR) {
790
791 if(partitionEntry->RewritePartition) {
792 pdoData->Mbr.PartitionType = partitionEntry->Mbr.PartitionType;
793 }
794
795 } else {
796
797 DebugPrint((1, "DiskUpdatePartitions: EFI Partition %ws\n",
798 pdoData->Efi.PartitionName
799 ));
800
801 pdoData->Efi.PartitionType = partitionEntry->Gpt.PartitionType;
802 pdoData->Efi.PartitionId = partitionEntry->Gpt.PartitionId;
803 pdoData->Efi.Attributes = partitionEntry->Gpt.Attributes;
804
805 RtlCopyMemory(
806 pdoData->Efi.PartitionName,
807 partitionEntry->Gpt.Name,
808 sizeof (pdoData->Efi.PartitionName)
809 );
810 }
811
812 //
813 // Mark this one as found.
814 //
815
816 pdoExtension->IsMissing = FALSE;
817
818 //
819 // Pull it out of the old child list and add it into the
820 // real one.
821 //
822
823 oldChildList = pdoExtension->CommonExtension.ChildList;
824
825 pdoExtension->CommonExtension.ChildList =
826 fdoExtension->CommonExtension.ChildList;
827
828 fdoExtension->CommonExtension.ChildList = pdoExtension;
829
830 } else {
831
832 PDEVICE_OBJECT nextPdo;
833
834 DebugPrint ((1, "DiskUpdatePartitions: Deleting %wZ\n",
835 &pdoExtension->CommonExtension.DeviceName));
836
837 if (partitionStyle == PARTITION_STYLE_GPT) {
838
839 DebugPrint ((1, "DiskUpdatePartitions: EFI Partition %ws\n",
840 pdoData->Efi.PartitionName
841 ));
842 }
843 //
844 // no matching entry in the partition list - throw this partition
845 // object away
846 //
847
848 pdoExtension->CommonExtension.PartitionLength.QuadPart = 0;
849
850 //
851 // grab a pointer to the next child before we mark this one as
852 // missing since missing devices could vanish at any time.
853 //
854
855 oldChildList = pdoExtension->CommonExtension.ChildList;
856 pdoExtension->CommonExtension.ChildList = (PVOID) -1;
857
858 //
859 // Now tell the class driver that this child is "missing" - this
860 // will cause it to be deleted.
861 //
862
863
864 ClassMarkChildMissing(pdoExtension, FALSE);
865 }
866 }
867
868 //
869 // At this point the old child list had best be empty.
870 //
871
872 ASSERT(oldChildList == NULL);
873
874 //
875 // Iterate through the partition entries and create any partition
876 // objects that don't already exist
877 //
878
879 partitionOrdinal = 0;
880 newPartitionNumber = 0;
881
882 for(partitionNumber = 0;
883 partitionNumber < partitionCount;
884 partitionNumber++) {
885
886 PDEVICE_OBJECT pdo;
887
888 partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
889
890 //
891 // Is this partition interesting
892 //
893
894 if (partitionStyle == PARTITION_STYLE_MBR) {
895
896 if((partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) ||
897 (IsContainerPartition(partitionEntry->Mbr.PartitionType))) {
898
899 continue;
900 }
901 }
902
903 //
904 // Increment the count of interesting partitions
905 //
906
907 partitionOrdinal++;
908 newPartitionNumber++;
909
910 //
911 // Has this already been matched
912 //
913
914 if(partitionEntry->PartitionNumber == 0) {
915
916 LONG i;
917
918 //
919 // find the first safe partition number for this device
920 //
921
922 for(i = 0; i < (LONG) partitionCount; i++) {
923
924
925 PPARTITION_INFORMATION_EX tmp = &(PartitionList->PartitionEntry[i]);
926
927 if (partitionStyle == PARTITION_STYLE_MBR) {
928 if (tmp->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
929 IsContainerPartition(tmp->Mbr.PartitionType)) {
930 continue;
931 }
932 }
933
934 if(tmp->PartitionNumber == newPartitionNumber) {
935
936 //
937 // Found a matching partition number - increment the count
938 // and restart the scan.
939 //
940
941 newPartitionNumber++;
942 i = -1;
943 continue;
944 }
945 }
946
947 //
948 // Assign this partition a partition number
949 //
950
951 partitionEntry->PartitionNumber = newPartitionNumber;
952
953 DebugPrint((1, "DiskUpdatePartitions: Found new partition #%d, ord %d "
954 "starting at %#016I64x and running for %#016I64x\n",
955 partitionEntry->PartitionNumber,
956 partitionOrdinal,
957 partitionEntry->StartingOffset.QuadPart,
958 partitionEntry->PartitionLength.QuadPart));
959
960 ClassReleaseChildLock(fdoExtension);
961
962 status = DiskCreatePdo(Fdo,
963 partitionOrdinal,
964 partitionEntry,
965 partitionStyle,
966 &pdo);
967
968 ClassAcquireChildLock(fdoExtension);
969
970 if(!NT_SUCCESS(status)) {
971
972 DebugPrint((1, "DiskUpdatePartitions: error %lx creating "
973 "new PDO for partition ordinal %d, number %d\n",
974 status,
975 partitionOrdinal,
976 partitionEntry->PartitionNumber));
977
978 //
979 // don't increment the partition number - we'll try to reuse
980 // it for the next child.
981 //
982
983 partitionEntry->PartitionNumber = 0;
984 newPartitionNumber--;
985
986 continue;
987 }
988
989 //
990 // mark the new device as enumerated
991 //
992
993 pdoExtension = pdo->DeviceExtension;
994 pdoExtension->IsMissing = FALSE;
995
996 //
997 // This number's taken already - try to scanning the partition
998 // table more than once for a new number.
999 //
1000
1001 }
1002 }
1003
1004 //
1005 // ISSUE - 2000/02/09 - math: Review.
1006 // Is PartitionStyle the only field that needs updating?
1007 //
1008
1009 {
1010 PCOMMON_DEVICE_EXTENSION commonExtension;
1011 PDISK_DATA diskData;
1012
1013 commonExtension = Fdo->DeviceExtension;
1014 diskData = (PDISK_DATA)(commonExtension->DriverData);
1015
1016 diskData->PartitionStyle = partitionStyle;
1017 }
1018
1019 ClassReleaseChildLock(fdoExtension);
1020 return;
1021 }
1022
1023 \f
1024 NTSTATUS
1025 DiskCreatePdo(
1026 IN PDEVICE_OBJECT Fdo,
1027 IN ULONG PartitionOrdinal,
1028 IN PPARTITION_INFORMATION_EX PartitionEntry,
1029 IN PARTITION_STYLE PartitionStyle,
1030 OUT PDEVICE_OBJECT *Pdo
1031 )
1032
1033 /*++
1034
1035 Routine Description:
1036
1037 This routine will create and initialize a new partition device object
1038 (PDO) and insert it into the FDO partition list.
1039
1040 Arguments:
1041
1042 Fdo - a pointer to the functional device object this PDO will be a child
1043 of
1044
1045 PartitionOrdinal - the partition ordinal for this PDO
1046
1047 PartitionEntry - the partition information for this device object
1048
1049 PartitionStyle - what style of partition table entry PartitionEntry is;
1050 currently either MBR or EFI
1051
1052 Pdo - a location to store the pdo pointer upon successful completion
1053
1054 Return Value:
1055
1056 status
1057
1058 --*/
1059
1060 {
1061 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
1062
1063 PDEVICE_OBJECT pdo = NULL;
1064 PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
1065
1066 PUCHAR deviceName = NULL;
1067
1068 PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData;
1069
1070 ULONG numberListElements;
1071
1072 NTSTATUS status = STATUS_SUCCESS;
1073
1074 PAGED_CODE();
1075
1076 //
1077 // Create partition object and set up partition parameters.
1078 //
1079
1080 status = DiskGenerateDeviceName(FALSE,
1081 fdoExtension->DeviceNumber,
1082 PartitionEntry->PartitionNumber,
1083 &PartitionEntry->StartingOffset,
1084 &PartitionEntry->PartitionLength,
1085 &deviceName);
1086
1087 if(!NT_SUCCESS(status)) {
1088
1089 DebugPrint((1, "DiskCreatePdo - Can't generate name %lx\n", status));
1090 return status;
1091 }
1092
1093 DebugPrint((2, "DiskCreatePdo: Create device object %s\n", deviceName));
1094
1095 status = ClassCreateDeviceObject(Fdo->DriverObject,
1096 deviceName,
1097 Fdo,
1098 FALSE,
1099 &pdo);
1100
1101 if (!NT_SUCCESS(status)) {
1102
1103 DebugPrint((1, "DiskEnumerateDevice: Can't create device object for %s\n", deviceName));
1104
1105 return status;
1106 }
1107
1108 //
1109 // Set up device extension fields.
1110 //
1111
1112 pdoExtension = pdo->DeviceExtension;
1113
1114 //
1115 // Set up device object fields.
1116 //
1117
1118 SET_FLAG(pdo->Flags, DO_DIRECT_IO);
1119
1120 pdo->StackSize = (CCHAR)
1121 pdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1;
1122
1123 //
1124 // Get pointer to new disk data.
1125 //
1126
1127 diskData = (PDISK_DATA) pdoExtension->CommonExtension.DriverData;
1128
1129 //
1130 // Set the alignment requirements for the device based on the
1131 // host adapter requirements
1132 //
1133
1134 if (Fdo->AlignmentRequirement > pdo->AlignmentRequirement) {
1135 pdo->AlignmentRequirement = Fdo->AlignmentRequirement;
1136 }
1137
1138 if (fdoExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
1139 numberListElements = 30;
1140 } else {
1141 numberListElements = 8;
1142 }
1143
1144 //
1145 // Build the lookaside list for srb's for this partition based on
1146 // whether the adapter and disk can do tagged queueing. Don't bother to
1147 // check the status - this can't fail when called for a PDO.
1148 //
1149
1150 ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION) pdoExtension,
1151 numberListElements);
1152
1153 //
1154 // Set the sense-data pointer in the device extension.
1155 //
1156
1157 diskData->PartitionOrdinal = PartitionOrdinal;
1158 pdoExtension->CommonExtension.PartitionNumber = PartitionEntry->PartitionNumber;
1159
1160 //
1161 // Initialize relevant data.
1162 //
1163
1164 if (PartitionStyle == PARTITION_STYLE_MBR) {
1165
1166 diskData->Mbr.PartitionType = PartitionEntry->Mbr.PartitionType;
1167 diskData->Mbr.BootIndicator = PartitionEntry->Mbr.BootIndicator;
1168 diskData->Mbr.HiddenSectors = PartitionEntry->Mbr.HiddenSectors;
1169
1170 } else {
1171
1172 diskData->Efi.PartitionType = PartitionEntry->Gpt.PartitionType;
1173 diskData->Efi.PartitionId = PartitionEntry->Gpt.PartitionType;
1174 diskData->Efi.Attributes = PartitionEntry->Gpt.Attributes;
1175 RtlCopyMemory (diskData->Efi.PartitionName,
1176 PartitionEntry->Gpt.Name,
1177 sizeof (diskData->Efi.PartitionName)
1178 );
1179 }
1180
1181 DebugPrint((2, "DiskEnumerateDevice: Partition type is %x\n",
1182 diskData->Mbr.PartitionType));
1183
1184 pdoExtension->CommonExtension.StartingOffset =
1185 PartitionEntry->StartingOffset;
1186
1187 pdoExtension->CommonExtension.PartitionLength =
1188 PartitionEntry->PartitionLength;
1189
1190
1191 DebugPrint((1, "DiskCreatePdo: hidden sectors value for pdo %#p set to %#x\n",
1192 pdo,
1193 diskData->Mbr.HiddenSectors));
1194
1195 //
1196 // Check for removable media support.
1197 //
1198
1199 if (fdoExtension->DeviceDescriptor->RemovableMedia) {
1200 SET_FLAG(pdo->Characteristics, FILE_REMOVABLE_MEDIA);
1201 }
1202
1203 pdoExtension->CommonExtension.DeviceObject = pdo;
1204
1205 CLEAR_FLAG(pdo->Flags, DO_DEVICE_INITIALIZING);
1206
1207 *Pdo = pdo;
1208
1209 return status;
1210 }
1211
1212
1213
1214
1215 \f
1216 VOID
1217 DiskAcquirePartitioningLock(
1218 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
1219 )
1220 {
1221 PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
1222
1223 PAGED_CODE();
1224
1225 ASSERT_FDO(FdoExtension->DeviceObject);
1226
1227 KeWaitForSingleObject(&(diskData->PartitioningEvent),
1228 UserRequest,
1229 UserMode,
1230 FALSE,
1231 NULL);
1232 return;
1233 }
1234
1235 \f
1236 VOID
1237 DiskReleasePartitioningLock(
1238 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
1239 )
1240 {
1241 PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
1242
1243 PAGED_CODE();
1244
1245 ASSERT_FDO(FdoExtension->DeviceObject);
1246
1247 KeSetEvent(&(diskData->PartitioningEvent), IO_NO_INCREMENT, FALSE);
1248 return;
1249 }
1250