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