[CRT] Remove useless #undef abort from process.h
[reactos.git] / drivers / storage / class / disk / geometry.c
1 /*++
2
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4
5 Module Name:
6
7 geometry.c
8
9 Abstract:
10
11 SCSI disk class driver - this module contains all the code for generating
12 disk geometries.
13
14 Environment:
15
16 kernel mode only
17
18 Notes:
19
20 Revision History:
21
22 --*/
23
24
25 #include "disk.h"
26 #include "ntddstor.h"
27
28 #ifdef DEBUG_USE_WPP
29 #include "geometry.tmh"
30 #endif
31
32 #if defined(_X86_) || defined(_AMD64_)
33
34 DISK_GEOMETRY_SOURCE
35 DiskUpdateGeometry(
36 IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension
37 );
38
39 NTSTATUS
40 DiskUpdateRemovableGeometry (
41 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
42 );
43
44 VOID
45 DiskScanBusDetectInfo(
46 IN PDRIVER_OBJECT DriverObject,
47 IN HANDLE BusKey
48 );
49
50 NTSTATUS
51 DiskSaveBusDetectInfo(
52 IN PDRIVER_OBJECT DriverObject,
53 IN HANDLE TargetKey,
54 IN ULONG DiskNumber
55 );
56
57 NTSTATUS
58 DiskSaveGeometryDetectInfo(
59 IN PDRIVER_OBJECT DriverObject,
60 IN HANDLE HardwareKey
61 );
62
63 NTSTATUS
64 DiskGetPortGeometry(
65 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
66 OUT PDISK_GEOMETRY Geometry
67 );
68
69 typedef struct _DISK_DETECT_INFO {
70 BOOLEAN Initialized;
71 ULONG Style;
72 ULONG Signature;
73 ULONG MbrCheckSum;
74 PDEVICE_OBJECT Device;
75 CM_INT13_DRIVE_PARAMETER DriveParameters;
76 } DISK_DETECT_INFO, *PDISK_DETECT_INFO;
77
78 //
79 // Information about the disk geometries collected and saved into the registry
80 // by NTDETECT.COM or the system firmware.
81 //
82
83 PDISK_DETECT_INFO DetectInfoList = NULL;
84 ULONG DetectInfoCount = 0;
85 LONG DetectInfoUsedCount = 0;
86
87 #define GET_STARTING_SECTOR(p) ( \
88 (ULONG) (p->StartingSectorLsb0) + \
89 (ULONG) (p->StartingSectorLsb1 << 8 ) + \
90 (ULONG) (p->StartingSectorMsb0 << 16) + \
91 (ULONG) (p->StartingSectorMsb1 << 24) )
92
93 #define GET_ENDING_S_OF_CHS(p) ( \
94 (UCHAR) (p->EndingCylinderLsb & 0x3F) )
95
96 //
97 // Definitions from hal.h
98 //
99
100 //
101 // Boot record disk partition table entry structure format
102 //
103
104 typedef struct _PARTITION_DESCRIPTOR
105 {
106 UCHAR ActiveFlag;
107 UCHAR StartingTrack;
108 UCHAR StartingCylinderLsb;
109 UCHAR StartingCylinderMsb;
110 UCHAR PartitionType;
111 UCHAR EndingTrack;
112 UCHAR EndingCylinderLsb;
113 UCHAR EndingCylinderMsb;
114 UCHAR StartingSectorLsb0;
115 UCHAR StartingSectorLsb1;
116 UCHAR StartingSectorMsb0;
117 UCHAR StartingSectorMsb1;
118 UCHAR PartitionLengthLsb0;
119 UCHAR PartitionLengthLsb1;
120 UCHAR PartitionLengthMsb0;
121 UCHAR PartitionLengthMsb1;
122
123 } PARTITION_DESCRIPTOR, *PPARTITION_DESCRIPTOR;
124
125 //
126 // Number of partition table entries
127 //
128
129 #define NUM_PARTITION_TABLE_ENTRIES 4
130
131 //
132 // Partition table record and boot signature offsets in 16-bit words
133 //
134
135 #define PARTITION_TABLE_OFFSET ( 0x1be / 2)
136 #define BOOT_SIGNATURE_OFFSET ((0x200 / 2) - 1)
137
138 //
139 // Boot record signature value
140 //
141
142 #define BOOT_RECORD_SIGNATURE (0xaa55)
143
144
145 #ifdef ALLOC_PRAGMA
146 #pragma alloc_text(INIT, DiskSaveDetectInfo)
147 #pragma alloc_text(INIT, DiskScanBusDetectInfo)
148 #pragma alloc_text(INIT, DiskSaveBusDetectInfo)
149 #pragma alloc_text(INIT, DiskSaveGeometryDetectInfo)
150
151 #pragma alloc_text(PAGE, DiskUpdateGeometry)
152 #pragma alloc_text(PAGE, DiskUpdateRemovableGeometry)
153 #pragma alloc_text(PAGE, DiskGetPortGeometry)
154 #pragma alloc_text(PAGE, DiskIsNT4Geometry)
155 #pragma alloc_text(PAGE, DiskGetDetectInfo)
156 #pragma alloc_text(PAGE, DiskReadSignature)
157 #endif
158
159
160 NTSTATUS
161 DiskSaveDetectInfo(
162 PDRIVER_OBJECT DriverObject
163 )
164
165 /*++
166
167 Routine Description:
168
169 This routine saves away the firmware information about the disks which has
170 been saved in the registry. It generates a list (DetectInfoList) which
171 contains the disk geometries, signatures & checksums of all drives which
172 were examined by NtDetect. This list is later used to assign geometries
173 to disks as they are initialized.
174
175 Arguments:
176
177 DriverObject - the driver being initialized. This is used to get to the
178 hardware database.
179
180 Return Value:
181
182 status.
183
184 --*/
185
186 {
187 OBJECT_ATTRIBUTES objectAttributes = {0};
188 HANDLE hardwareKey;
189
190 UNICODE_STRING unicodeString;
191 HANDLE busKey;
192
193 NTSTATUS status;
194
195 PAGED_CODE();
196
197 InitializeObjectAttributes(
198 &objectAttributes,
199 DriverObject->HardwareDatabase,
200 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
201 NULL,
202 NULL);
203
204 //
205 // Create the hardware base key.
206 //
207
208 status = ZwOpenKey(&hardwareKey, KEY_READ, &objectAttributes);
209
210 if(!NT_SUCCESS(status)) {
211 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Cannot open hardware data. "
212 "Name: %wZ\n",
213 DriverObject->HardwareDatabase));
214 return status;
215 }
216
217 status = DiskSaveGeometryDetectInfo(DriverObject, hardwareKey);
218
219 if(!NT_SUCCESS(status)) {
220 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Can't query configuration data "
221 "(%#08lx)\n",
222 status));
223 ZwClose(hardwareKey);
224 return status;
225 }
226
227 //
228 // Open EISA bus key.
229 //
230
231 RtlInitUnicodeString(&unicodeString, L"EisaAdapter");
232 InitializeObjectAttributes(&objectAttributes,
233 &unicodeString,
234 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
235 hardwareKey,
236 NULL);
237
238 status = ZwOpenKey(&busKey,
239 KEY_READ,
240 &objectAttributes);
241
242 if(NT_SUCCESS(status)) {
243 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Opened EisaAdapter key\n"));
244 DiskScanBusDetectInfo(DriverObject, busKey);
245 ZwClose(busKey);
246 }
247
248 //
249 // Open MultiFunction bus key.
250 //
251
252 RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter");
253 InitializeObjectAttributes(&objectAttributes,
254 &unicodeString,
255 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
256 hardwareKey,
257 NULL);
258
259 status = ZwOpenKey(&busKey,
260 KEY_READ,
261 &objectAttributes);
262
263 if(NT_SUCCESS(status)) {
264 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Opened MultifunctionAdapter key\n"));
265 DiskScanBusDetectInfo(DriverObject, busKey);
266 ZwClose(busKey);
267 }
268
269 ZwClose(hardwareKey);
270
271 return STATUS_SUCCESS;
272 }
273
274
275 VOID
276 DiskCleanupDetectInfo(
277 IN PDRIVER_OBJECT DriverObject
278 )
279 /*++
280
281 Routine Description:
282
283 This routine will cleanup the data structure built by DiskSaveDetectInfo.
284
285 Arguments:
286
287 DriverObject - a pointer to the kernel object for this driver.
288
289 Return Value:
290
291 none
292
293 --*/
294
295 {
296 UNREFERENCED_PARAMETER(DriverObject);
297 FREE_POOL(DetectInfoList);
298 return;
299 }
300
301
302 NTSTATUS
303 DiskSaveGeometryDetectInfo(
304 IN PDRIVER_OBJECT DriverObject,
305 IN HANDLE HardwareKey
306 )
307 {
308 UNICODE_STRING unicodeString;
309 PKEY_VALUE_FULL_INFORMATION keyData;
310 ULONG length;
311
312 PCM_FULL_RESOURCE_DESCRIPTOR fullDescriptor;
313 PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
314
315 PCM_INT13_DRIVE_PARAMETER driveParameters;
316 ULONG numberOfDrives;
317
318 ULONG i;
319
320 NTSTATUS status;
321
322 PAGED_CODE();
323 UNREFERENCED_PARAMETER(DriverObject);
324
325 //
326 // Get disk BIOS geometry information.
327 //
328
329 RtlInitUnicodeString(&unicodeString, L"Configuration Data");
330
331 keyData = ExAllocatePoolWithTag(PagedPool,
332 VALUE_BUFFER_SIZE,
333 DISK_TAG_UPDATE_GEOM);
334
335 if(keyData == NULL) {
336 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: Can't allocate config "
337 "data buffer\n"));
338 return STATUS_INSUFFICIENT_RESOURCES;
339 }
340
341 status = ZwQueryValueKey(HardwareKey,
342 &unicodeString,
343 KeyValueFullInformation,
344 keyData,
345 VALUE_BUFFER_SIZE,
346 &length);
347
348 if(!NT_SUCCESS(status)) {
349 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: Can't query configuration "
350 "data (%#08lx)\n",
351 status));
352 FREE_POOL(keyData);
353 return status;
354 }
355
356 //
357 // Extract the resource list out of the key data.
358 //
359
360 fullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
361 (((PUCHAR) keyData) + keyData->DataOffset);
362 partialDescriptor =
363 fullDescriptor->PartialResourceList.PartialDescriptors;
364 length = partialDescriptor->u.DeviceSpecificData.DataSize;
365
366 if((keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) ||
367 (fullDescriptor->PartialResourceList.Count == 0) ||
368 (partialDescriptor->Type != CmResourceTypeDeviceSpecific) ||
369 (length < sizeof(ULONG))) {
370
371 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: BIOS header data too small "
372 "or invalid\n"));
373 FREE_POOL(keyData);
374 return STATUS_INVALID_PARAMETER;
375 }
376
377 //
378 // Point to the BIOS data. THe BIOS data is located after the first
379 // partial Resource list which should be device specific data.
380 //
381
382 {
383 PUCHAR buffer = (PUCHAR) keyData;
384 buffer += keyData->DataOffset;
385 buffer += sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
386 driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer;
387 }
388
389 numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER);
390
391 //
392 // Allocate our detect info list now that we know how many entries there
393 // are going to be. No other routine allocates detect info and this is
394 // done out of DriverEntry so we don't need to synchronize it's creation.
395 //
396
397 length = sizeof(DISK_DETECT_INFO) * numberOfDrives;
398 DetectInfoList = ExAllocatePoolWithTag(PagedPool,
399 length,
400 DISK_TAG_UPDATE_GEOM);
401
402 if(DetectInfoList == NULL) {
403 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: Couldn't allocate %x bytes "
404 "for DetectInfoList\n",
405 length));
406
407 FREE_POOL(keyData);
408 return STATUS_INSUFFICIENT_RESOURCES;
409 }
410
411 DetectInfoCount = numberOfDrives;
412
413 RtlZeroMemory(DetectInfoList, length);
414
415 //
416 // Copy the information out of the key data and into the list we've
417 // allocated.
418 //
419
420 for(i = 0; i < numberOfDrives; i++) {
421 #ifdef _MSC_VER
422 #pragma warning(suppress: 6386) // PREFast bug means it doesn't correctly remember the size of DetectInfoList
423 #endif
424 DetectInfoList[i].DriveParameters = driveParameters[i];
425 }
426
427 FREE_POOL(keyData);
428 return STATUS_SUCCESS;
429 }
430
431
432 VOID
433 DiskScanBusDetectInfo(
434 IN PDRIVER_OBJECT DriverObject,
435 IN HANDLE BusKey
436 )
437 /*++
438
439 Routine Description:
440
441 The routine queries the registry to determine which disks are visible to
442 the BIOS. If a disk is visable to the BIOS then the geometry information
443 is updated with the disk's signature and MBR checksum.
444
445 Arguments:
446
447 DriverObject - the object for this driver.
448 BusKey - handle to the bus key to be enumerated.
449
450 Return Value:
451
452 status
453
454 --*/
455 {
456 ULONG busNumber;
457
458 NTSTATUS status;
459
460 for(busNumber = 0; ; busNumber++) {
461
462 WCHAR buffer[32] = { 0 };
463 UNICODE_STRING unicodeString;
464
465 OBJECT_ATTRIBUTES objectAttributes = {0};
466
467 HANDLE spareKey;
468 HANDLE adapterKey;
469
470 ULONG adapterNumber;
471
472 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Scanning bus %d\n", busNumber));
473
474 //
475 // Open controller name key.
476 //
477
478 status = RtlStringCchPrintfW(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d", busNumber);
479 if (!NT_SUCCESS(status)) {
480 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Format symbolic link failed with error: 0x%X\n", status));
481 break;
482 }
483
484 RtlInitUnicodeString(&unicodeString, buffer);
485
486 InitializeObjectAttributes(&objectAttributes,
487 &unicodeString,
488 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
489 BusKey,
490 NULL);
491
492 status = ZwOpenKey(&spareKey, KEY_READ, &objectAttributes);
493
494 if(!NT_SUCCESS(status)) {
495 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx opening bus "
496 "key %#x\n",
497 status, busNumber));
498 break;
499 }
500
501 //
502 // Open up a controller ordinal key.
503 //
504
505 RtlInitUnicodeString(&unicodeString, L"DiskController");
506 InitializeObjectAttributes(&objectAttributes,
507 &unicodeString,
508 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
509 spareKey,
510 NULL);
511
512 status = ZwOpenKey(&adapterKey, KEY_READ, &objectAttributes);
513 ZwClose(spareKey);
514
515 if(!NT_SUCCESS(status)) {
516 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx opening "
517 "DiskController key\n",
518 status));
519 continue;
520 }
521
522 for(adapterNumber = 0; ; adapterNumber++) {
523
524 HANDLE diskKey;
525 ULONG diskNumber;
526
527 //
528 // Open disk key.
529 //
530
531 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Scanning disk key "
532 "%d\\DiskController\\%d\\DiskPeripheral\n",
533 busNumber, adapterNumber));
534
535 status = RtlStringCchPrintfW(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d\\DiskPeripheral", adapterNumber);
536 if (!NT_SUCCESS(status)) {
537 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Format symbolic link failed with error: 0x%X\n", status));
538 break;
539 }
540
541 RtlInitUnicodeString(&unicodeString, buffer);
542
543 InitializeObjectAttributes(&objectAttributes,
544 &unicodeString,
545 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
546 adapterKey,
547 NULL);
548
549 status = ZwOpenKey(&diskKey, KEY_READ, &objectAttributes);
550
551 if(!NT_SUCCESS(status)) {
552 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx opening "
553 "disk key\n",
554 status));
555 break;
556 }
557
558 for(diskNumber = 0; ; diskNumber++) {
559
560 HANDLE targetKey;
561
562 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Scanning target key "
563 "%d\\DiskController\\%d\\DiskPeripheral\\%d\n",
564 busNumber, adapterNumber, diskNumber));
565
566 status = RtlStringCchPrintfW(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d", diskNumber);
567 if (!NT_SUCCESS(status)) {
568 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Format symbolic link failed with error: 0x%X\n", status));
569 break;
570 }
571
572 RtlInitUnicodeString(&unicodeString, buffer);
573
574 InitializeObjectAttributes(&objectAttributes,
575 &unicodeString,
576 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
577 diskKey,
578 NULL);
579
580 status = ZwOpenKey(&targetKey, KEY_READ, &objectAttributes);
581
582 if(!NT_SUCCESS(status)) {
583 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx "
584 "opening target key\n",
585 status));
586 break;
587 }
588
589 DiskSaveBusDetectInfo(DriverObject, targetKey, diskNumber);
590
591 ZwClose(targetKey);
592 }
593
594 ZwClose(diskKey);
595 }
596
597 ZwClose(adapterKey);
598 }
599
600 return;
601 }
602
603
604 NTSTATUS
605 DiskSaveBusDetectInfo(
606 IN PDRIVER_OBJECT DriverObject,
607 IN HANDLE TargetKey,
608 IN ULONG DiskNumber
609 )
610 /*++
611
612 Routine Description:
613
614 This routine will transfer the firmware/ntdetect reported information
615 in the specified target key into the appropriate entry in the
616 DetectInfoList.
617
618 Arguments:
619
620 DriverObject - the object for this driver.
621
622 TargetKey - the key for the disk being saved.
623
624 DiskNumber - the ordinal of the entry in the DiskPeripheral tree for this
625 entry
626
627 Return Value:
628
629 status
630
631 --*/
632 {
633 PDISK_DETECT_INFO diskInfo;
634
635 UNICODE_STRING unicodeString;
636
637 PKEY_VALUE_FULL_INFORMATION keyData;
638 ULONG length;
639
640 NTSTATUS status;
641
642 PAGED_CODE();
643 UNREFERENCED_PARAMETER(DriverObject);
644
645 if (DiskNumber >= DetectInfoCount)
646 {
647 return STATUS_UNSUCCESSFUL;
648 }
649
650 diskInfo = &(DetectInfoList[DiskNumber]);
651
652 if(diskInfo->Initialized) {
653
654 NT_ASSERT(FALSE);
655 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: disk entry %#x already has a "
656 "signature of %#08lx and mbr checksum of %#08lx\n",
657 DiskNumber,
658 diskInfo->Signature,
659 diskInfo->MbrCheckSum));
660 return STATUS_UNSUCCESSFUL;
661 }
662
663 RtlInitUnicodeString(&unicodeString, L"Identifier");
664
665 keyData = ExAllocatePoolWithTag(PagedPool,
666 VALUE_BUFFER_SIZE,
667 DISK_TAG_UPDATE_GEOM);
668
669 if(keyData == NULL) {
670 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Couldn't allocate space for "
671 "registry data\n"));
672 return STATUS_INSUFFICIENT_RESOURCES;
673 }
674
675 //
676 // Get disk peripheral identifier.
677 //
678
679 status = ZwQueryValueKey(TargetKey,
680 &unicodeString,
681 KeyValueFullInformation,
682 keyData,
683 VALUE_BUFFER_SIZE,
684 &length);
685
686 if(!NT_SUCCESS(status)) {
687 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Error %#08lx getting "
688 "Identifier\n",
689 status));
690 FREE_POOL(keyData);
691 return status;
692
693 } else if (keyData->DataLength < 9*sizeof(WCHAR)) {
694
695 //
696 // the data is too short to use (we subtract 9 chars in normal path)
697 //
698 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Saved data was invalid, "
699 "not enough data in registry!\n"));
700 FREE_POOL(keyData);
701 return STATUS_UNSUCCESSFUL;
702
703 } else {
704
705 UNICODE_STRING identifier;
706 ULONG value;
707
708 //
709 // Complete unicode string.
710 //
711
712 identifier.Buffer = (PWSTR) ((PUCHAR)keyData + keyData->DataOffset);
713 identifier.Length = (USHORT) keyData->DataLength;
714 identifier.MaximumLength = (USHORT) keyData->DataLength;
715
716 //
717 // Get the first value out of the identifier - this will be the MBR
718 // checksum.
719 //
720
721 status = RtlUnicodeStringToInteger(&identifier, 16, &value);
722
723 if(!NT_SUCCESS(status)) {
724 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Error %#08lx converting "
725 "identifier %wZ into MBR xsum\n",
726 status,
727 &identifier));
728 FREE_POOL(keyData);
729 return status;
730 }
731
732 diskInfo->MbrCheckSum = value;
733
734 //
735 // Shift the string over to get the disk signature
736 //
737
738 identifier.Buffer += 9;
739 identifier.Length -= 9 * sizeof(WCHAR);
740 identifier.MaximumLength -= 9 * sizeof(WCHAR);
741
742 status = RtlUnicodeStringToInteger(&identifier, 16, &value);
743
744 if(!NT_SUCCESS(status)) {
745 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Error %#08lx converting "
746 "identifier %wZ into disk signature\n",
747 status,
748 &identifier));
749 value = 0;
750 }
751
752 diskInfo->Signature = value;
753 }
754
755 //
756 // Here is where we would save away the extended int13 data.
757 //
758
759 //
760 // Mark this entry as initialized so we can make sure not to do it again.
761 //
762
763 diskInfo->Initialized = TRUE;
764
765 FREE_POOL(keyData);
766
767 return STATUS_SUCCESS;
768 }
769
770
771 DISK_GEOMETRY_SOURCE
772 DiskUpdateGeometry(
773 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
774 )
775 /*++
776
777 Routine Description:
778
779 This routine checks the DetectInfoList saved away during disk driver init
780 to see if any geometry information was reported for this drive. If the
781 geometry data exists (determined by matching non-zero signatures or
782 non-zero MBR checksums) then it will be saved in the RealGeometry member
783 of the disk data block.
784
785 ClassReadDriveCapacity MUST be called after calling this routine to update
786 the cylinder count based on the size of the disk and the presence of any
787 disk management software.
788
789 Arguments:
790
791 DeviceExtension - Supplies a pointer to the device information for disk.
792
793 Return Value:
794
795 Inidicates whether the "RealGeometry" in the data block is now valid.
796
797 --*/
798
799 {
800 PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
801
802 ULONG i;
803 PDISK_DETECT_INFO diskInfo = NULL;
804
805 BOOLEAN found = FALSE;
806
807 NTSTATUS status;
808
809 PAGED_CODE();
810
811
812 NT_ASSERT((FdoExtension->DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0);
813
814 //
815 // If we've already set a non-default geometry for this drive then there's
816 // no need to try and update again.
817 //
818
819 if(diskData->GeometrySource != DiskGeometryUnknown) {
820 return diskData->GeometrySource;
821 }
822
823 //
824 // Scan through the saved detect info to see if we can find a match
825 // for this device.
826 //
827
828 for(i = 0; i < DetectInfoCount; i++) {
829
830 NT_ASSERT(DetectInfoList != NULL);
831
832 diskInfo = &(DetectInfoList[i]);
833
834 if((diskData->Mbr.Signature != 0) &&
835 (diskData->Mbr.Signature == diskInfo->Signature)) {
836 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: found match for signature "
837 "%#08lx\n",
838 diskData->Mbr.Signature));
839 found = TRUE;
840 break;
841 } else if((diskData->Mbr.Signature == 0) &&
842 (diskData->Mbr.MbrCheckSum != 0) &&
843 (diskData->Mbr.MbrCheckSum == diskInfo->MbrCheckSum)) {
844 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: found match for xsum %#08lx\n",
845 diskData->Mbr.MbrCheckSum));
846 found = TRUE;
847 break;
848 }
849 }
850
851 if(found) {
852
853 ULONG cylinders;
854 ULONG sectorsPerTrack;
855 ULONG tracksPerCylinder;
856
857 ULONG length;
858
859 //
860 // Point to the array of drive parameters.
861 //
862
863 cylinders = diskInfo->DriveParameters.MaxCylinders + 1;
864 sectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack;
865 tracksPerCylinder = diskInfo->DriveParameters.MaxHeads + 1;
866
867 //
868 // Since the BIOS may not report the full drive, recalculate the drive
869 // size based on the volume size and the BIOS values for tracks per
870 // cylinder and sectors per track..
871 //
872
873 length = tracksPerCylinder * sectorsPerTrack;
874
875 if (length == 0) {
876
877 //
878 // The BIOS information is bogus.
879 //
880
881 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: H (%d) or S(%d) is zero\n",
882 tracksPerCylinder, sectorsPerTrack));
883 return DiskGeometryUnknown;
884 }
885
886 //
887 // since we are copying the structure RealGeometry here, we should
888 // really initialize all the fields, especially since a zero'd
889 // BytesPerSector field would cause a trap in xHalReadPartitionTable()
890 //
891
892 diskData->RealGeometry = FdoExtension->DiskGeometry;
893
894 //
895 // Save the geometry information away in the disk data block and
896 // set the bit indicating that we found a valid one.
897 //
898
899 diskData->RealGeometry.SectorsPerTrack = sectorsPerTrack;
900 diskData->RealGeometry.TracksPerCylinder = tracksPerCylinder;
901 diskData->RealGeometry.Cylinders.QuadPart = (LONGLONG)cylinders;
902
903 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: BIOS spt %#x, #heads %#x, "
904 "#cylinders %#x\n",
905 sectorsPerTrack, tracksPerCylinder, cylinders));
906
907 diskData->GeometrySource = DiskGeometryFromBios;
908 diskInfo->Device = FdoExtension->DeviceObject;
909
910 //
911 // Increment the count of used geometry entries.
912 //
913
914 InterlockedIncrement(&DetectInfoUsedCount);
915
916 } else {
917
918 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: no match found for signature %#08lx\n", diskData->Mbr.Signature));
919 }
920
921 if(diskData->GeometrySource == DiskGeometryUnknown) {
922
923 //
924 // We couldn't find a geometry from the BIOS. Check with the port
925 // driver and see if it can provide one.
926 //
927
928 status = DiskGetPortGeometry(FdoExtension, &(diskData->RealGeometry));
929
930 if(NT_SUCCESS(status)) {
931
932 //
933 // Check the geometry to make sure it's valid.
934 //
935
936 if((diskData->RealGeometry.TracksPerCylinder *
937 diskData->RealGeometry.SectorsPerTrack) != 0) {
938
939 diskData->GeometrySource = DiskGeometryFromPort;
940 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: using Port geometry for disk %#p\n", FdoExtension));
941
942 if (diskData->RealGeometry.BytesPerSector == 0) {
943
944 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskDriverReinit: Port driver failed to "
945 "set BytesPerSector in the RealGeometry\n"));
946 diskData->RealGeometry.BytesPerSector =
947 FdoExtension->DiskGeometry.BytesPerSector;
948 if (diskData->RealGeometry.BytesPerSector == 0) {
949 NT_ASSERT(!"BytesPerSector is still zero!");
950 }
951
952 }
953 }
954 }
955 }
956
957 //
958 // If we came up with a "real" geometry for this drive then set it in the
959 // device extension.
960 //
961
962 if (diskData->GeometrySource != DiskGeometryUnknown) {
963
964 FdoExtension->DiskGeometry = diskData->RealGeometry;
965 }
966
967 return diskData->GeometrySource;
968 }
969
970
971 NTSTATUS
972 DiskUpdateRemovableGeometry (
973 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
974 )
975
976 /*++
977
978 Routine Description:
979
980 This routine updates the geometry of the disk. It will query the port
981 driver to see if it can provide any geometry info. If not it will use
982 the current head & sector count.
983
984 Based on these values & the capacity of the drive as reported by
985 ClassReadDriveCapacity it will determine a new cylinder count for the
986 device.
987
988 Arguments:
989
990 Fdo - Supplies the functional device object whos size needs to be updated.
991
992 Return Value:
993
994 Returns the status of the opertion.
995
996 --*/
997 {
998 PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension);
999 PDISK_DATA diskData = commonExtension->DriverData;
1000 PDISK_GEOMETRY geometry = &(diskData->RealGeometry);
1001
1002 NTSTATUS status;
1003
1004 PAGED_CODE();
1005
1006 if (FdoExtension->DeviceDescriptor) {
1007 NT_ASSERT(FdoExtension->DeviceDescriptor->RemovableMedia);
1008 }
1009 NT_ASSERT(TEST_FLAG(FdoExtension->DeviceObject->Characteristics,
1010 FILE_REMOVABLE_MEDIA));
1011
1012 //
1013 // Attempt to determine the disk geometry. First we'll check with the
1014 // port driver to see what it suggests for a value.
1015 //
1016
1017 status = DiskGetPortGeometry(FdoExtension, geometry);
1018
1019 if(NT_SUCCESS(status) &&
1020 ((geometry->TracksPerCylinder * geometry->SectorsPerTrack) != 0)) {
1021
1022 FdoExtension->DiskGeometry = (*geometry);
1023 }
1024
1025 return status;
1026 }
1027
1028
1029 NTSTATUS
1030 DiskGetPortGeometry(
1031 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
1032 OUT PDISK_GEOMETRY Geometry
1033 )
1034 /*++
1035
1036 Routine Description:
1037
1038 This routine will query the port driver for disk geometry. Some port
1039 drivers (in particular IDEPORT) may be able to provide geometry for the
1040 device.
1041
1042 Arguments:
1043
1044 FdoExtension - the device object for the disk.
1045
1046 Geometry - a structure to save the geometry information into (if any is
1047 available)
1048
1049 Return Value:
1050
1051 STATUS_SUCCESS if geometry information can be provided or
1052 error status indicating why it can't.
1053
1054 --*/
1055 {
1056 PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension);
1057 PIRP irp;
1058 PIO_STACK_LOCATION irpStack;
1059 KEVENT event;
1060
1061 NTSTATUS status;
1062
1063 PAGED_CODE();
1064
1065 //
1066 // Build an irp to send IOCTL_DISK_GET_DRIVE_GEOMETRY to the lower driver.
1067 //
1068
1069 irp = IoAllocateIrp(commonExtension->LowerDeviceObject->StackSize, FALSE);
1070
1071 if(irp == NULL) {
1072 return STATUS_INSUFFICIENT_RESOURCES;
1073 }
1074
1075 irpStack = IoGetNextIrpStackLocation(irp);
1076
1077 irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
1078
1079 irpStack->Parameters.DeviceIoControl.IoControlCode =
1080 IOCTL_DISK_GET_DRIVE_GEOMETRY;
1081 irpStack->Parameters.DeviceIoControl.OutputBufferLength =
1082 sizeof(DISK_GEOMETRY);
1083
1084 irp->AssociatedIrp.SystemBuffer = Geometry;
1085
1086 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
1087
1088 IoSetCompletionRoutine(irp,
1089 ClassSignalCompletion,
1090 &event,
1091 TRUE,
1092 TRUE,
1093 TRUE);
1094
1095 status = IoCallDriver(commonExtension->LowerDeviceObject, irp);
1096 if (status == STATUS_PENDING) {
1097 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
1098 status = irp->IoStatus.Status;
1099 }
1100
1101 IoFreeIrp(irp);
1102
1103 return status;
1104 }
1105
1106
1107 BOOLEAN
1108 DiskIsNT4Geometry(
1109 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
1110 )
1111
1112 /*++
1113
1114 Routine Description:
1115
1116 The default geometry that was used in partitioning disks under Windows NT 4.0 was
1117
1118 Sectors per Track = 0x20 = 32
1119 Tracks per Cylinder = 0x40 = 64
1120
1121 This was changed in Windows 2000 to
1122
1123 Sectors per Track = 0x3F = 63
1124 Tracks per Cylinder = 0xFF = 255
1125
1126 If neither the BIOS nor the port driver can report the correct geometry, we will
1127 default to the new numbers on such disks. Now LVM uses the geometry when creating
1128 logical volumes and dynamic disks. So reporting an incorrect geometry will cause
1129 the entire extended partition / dynamic disk to be destroyed
1130
1131 In this routine, we will look at the Master Boot Record. In 90% of the cases, the
1132 first entry corresponds to a partition that starts on the first track. If this is
1133 so, we shall retrieve the logical block address associated with it and calculate
1134 the correct geometry. Now, all partitions start on a cylinder boundary. So, for
1135 the remaining 10% we will look at the ending CHS number to determine the geometry
1136
1137 --*/
1138
1139 {
1140 PUSHORT readBuffer = NULL;
1141 BOOLEAN bFoundNT4 = FALSE;
1142
1143 PAGED_CODE();
1144
1145 readBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, FdoExtension->DiskGeometry.BytesPerSector, DISK_TAG_UPDATE_GEOM);
1146
1147 if (readBuffer)
1148 {
1149 KEVENT event;
1150 LARGE_INTEGER diskOffset;
1151 IO_STATUS_BLOCK ioStatus = { 0 };
1152 PIRP irp;
1153
1154 KeInitializeEvent(&event, NotificationEvent, FALSE);
1155
1156 //
1157 // Read the Master Boot Record at disk offset 0
1158 //
1159
1160 diskOffset.QuadPart = 0;
1161
1162 irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, FdoExtension->DeviceObject, readBuffer, FdoExtension->DiskGeometry.BytesPerSector, &diskOffset, &event, &ioStatus);
1163
1164 if (irp)
1165 {
1166 PIO_STACK_LOCATION irpSp = IoGetNextIrpStackLocation(irp);
1167 NTSTATUS status;
1168
1169 irpSp->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1170
1171 status = IoCallDriver(FdoExtension->DeviceObject, irp);
1172
1173 if (status == STATUS_PENDING)
1174 {
1175 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
1176 status = ioStatus.Status;
1177 }
1178
1179 if (NT_SUCCESS(status))
1180 {
1181 //
1182 // Match the boot record signature
1183 //
1184
1185 if (readBuffer[BOOT_SIGNATURE_OFFSET] == BOOT_RECORD_SIGNATURE)
1186 {
1187 PPARTITION_DESCRIPTOR partitionTableEntry = (PPARTITION_DESCRIPTOR)&readBuffer[PARTITION_TABLE_OFFSET];
1188 ULONG uCount = 0;
1189
1190 //
1191 // Walk the entries looking for a clue as to what the geometry might be
1192 //
1193
1194 for (uCount = 0; uCount < NUM_PARTITION_TABLE_ENTRIES; uCount++)
1195 {
1196 //
1197 // We are only concerned if there might be a logical volume or if this disk is part of a dynamic set
1198 //
1199
1200 if (IsContainerPartition(partitionTableEntry->PartitionType) || partitionTableEntry->PartitionType == PARTITION_LDM)
1201 {
1202 //
1203 // In 90% of the cases, the first entry corresponds to a partition that starts on the first track
1204 //
1205
1206 if (partitionTableEntry->StartingTrack == 1 && GET_STARTING_SECTOR(partitionTableEntry) == 0x20)
1207 {
1208 bFoundNT4 = TRUE;
1209 break;
1210 }
1211
1212 //
1213 // In almost every case, the ending CHS number is on a cylinder boundary
1214 //
1215
1216 if (partitionTableEntry->EndingTrack == 0x3F && GET_ENDING_S_OF_CHS(partitionTableEntry) == 0x20)
1217 {
1218 bFoundNT4 = TRUE;
1219 break;
1220 }
1221 }
1222
1223 partitionTableEntry++;
1224 }
1225 }
1226 else
1227 {
1228 //
1229 // The Master Boot Record is invalid
1230 //
1231 }
1232 }
1233 }
1234
1235 FREE_POOL(readBuffer);
1236 }
1237
1238 return bFoundNT4;
1239 }
1240
1241
1242 NTSTATUS
1243 DiskReadDriveCapacity(
1244 IN PDEVICE_OBJECT Fdo
1245 )
1246 /*++
1247
1248 Routine Description:
1249
1250 This routine is used by disk.sys as a wrapper for the classpnp API
1251 ClassReadDriveCapacity. It will perform some additional operations to
1252 attempt to determine drive geometry before it calls the classpnp version
1253 of the routine.
1254
1255 For fixed disks this involves calling DiskUpdateGeometry which will check
1256 various sources (the BIOS, the port driver) for geometry information.
1257
1258 Arguments:
1259
1260 Fdo - a pointer to the device object to be checked.
1261
1262 Return Value:
1263
1264 status of ClassReadDriveCapacity.
1265
1266 --*/
1267
1268 {
1269 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
1270 NTSTATUS status;
1271
1272 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
1273 DiskUpdateRemovableGeometry(fdoExtension);
1274 } else {
1275 DiskUpdateGeometry(fdoExtension);
1276 }
1277
1278 status = ClassReadDriveCapacity(Fdo);
1279
1280 return status;
1281 }
1282
1283
1284 VOID
1285 DiskDriverReinitialization(
1286 IN PDRIVER_OBJECT DriverObject,
1287 IN PVOID Nothing,
1288 IN ULONG Count
1289 )
1290 /*++
1291
1292 Routine Description:
1293
1294 This routine will scan through the current list of disks and attempt to
1295 match them to any remaining geometry information. This will only be done
1296 on the first call to the routine.
1297
1298 Note: This routine assumes that the system will not be adding or removing
1299 devices during this phase of the init process. This is very likely
1300 a bad assumption but it greatly simplifies the code.
1301
1302 Arguments:
1303
1304 DriverObject - a pointer to the object for the disk driver.
1305
1306 Nothing - unused
1307
1308 Count - an indication of how many times this routine has been called.
1309
1310 Return Value:
1311
1312 none
1313
1314 --*/
1315
1316 {
1317 PDEVICE_OBJECT deviceObject;
1318 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
1319 PDISK_DATA diskData;
1320
1321 ULONG unmatchedDiskCount;
1322 PDEVICE_OBJECT unmatchedDisk = NULL;
1323
1324 ULONG i;
1325 PDISK_DETECT_INFO diskInfo = NULL;
1326
1327 UNREFERENCED_PARAMETER(Nothing);
1328
1329 if(Count != 1) {
1330 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinitialization: ignoring call %d\n",
1331 Count));
1332 return;
1333 }
1334
1335 //
1336 // Check to see how many entries in the detect info list have been matched.
1337 // If there's only one remaining we'll see if we can find a disk to go with
1338 // it.
1339 //
1340
1341 if(DetectInfoCount == 0) {
1342 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinitialization: no detect info saved\n"));
1343 return;
1344 }
1345
1346 if((DetectInfoCount - DetectInfoUsedCount) != 1) {
1347 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinitialization: %d of %d geometry entries "
1348 "used - will not attempt match\n", DetectInfoUsedCount, DetectInfoCount));
1349 return;
1350 }
1351
1352 //
1353 // Scan through the list of disks and see if any of them are missing
1354 // geometry information. If there is only one such disk we'll try to
1355 // match it to the unmatched geometry.
1356 //
1357
1358
1359 //
1360 // ISSUE-2000/5/24-henrygab - figure out if there's a way to keep
1361 // removals from happening while doing this.
1362 //
1363 unmatchedDiskCount = 0;
1364 for(deviceObject = DriverObject->DeviceObject;
1365 deviceObject != NULL;
1366 #ifdef _MSC_VER
1367 #pragma prefast(suppress:28175, "Need to access the opaque field to scan through the list of disks")
1368 #endif
1369 deviceObject = deviceObject->NextDevice) {
1370
1371 fdoExtension = deviceObject->DeviceExtension;
1372
1373 if (!fdoExtension->CommonExtension.IsFdo) {
1374 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: %#p is not an FDO\n",
1375 deviceObject));
1376 continue;
1377 }
1378
1379 //
1380 // If the geometry for this one is already known then skip it.
1381 //
1382
1383 diskData = fdoExtension->CommonExtension.DriverData;
1384 if(diskData->GeometrySource != DiskGeometryUnknown) {
1385 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: FDO %#p has a geometry\n",
1386 deviceObject));
1387 continue;
1388 }
1389
1390 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinit: FDO %#p has no geometry\n",
1391 deviceObject));
1392
1393 //
1394 // Mark this one as using the default. It's past the time when disk
1395 // might blunder across the geometry info. If we set the geometry
1396 // from the bios we'll reset this field down below.
1397 //
1398
1399 diskData->GeometrySource = DiskGeometryFromDefault;
1400
1401 //
1402 // As long as we've only got one unmatched disk we're fine.
1403 //
1404
1405 unmatchedDiskCount++;
1406 if(unmatchedDiskCount > 1) {
1407 NT_ASSERT(unmatchedDisk != NULL);
1408 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinit: FDO %#p also has no geometry\n",
1409 unmatchedDisk));
1410 unmatchedDisk = NULL;
1411 break;
1412 }
1413
1414 unmatchedDisk = deviceObject;
1415 }
1416
1417 //
1418 // If there's more or less than one ungeometried disk then we can't do
1419 // anything about the geometry.
1420 //
1421
1422 if(unmatchedDiskCount != 1) {
1423 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskDriverReinit: Unable to match geometry\n"));
1424 return;
1425
1426 }
1427
1428 fdoExtension = unmatchedDisk->DeviceExtension;
1429 diskData = fdoExtension->CommonExtension.DriverData;
1430
1431 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: Found possible match\n"));
1432
1433 //
1434 // Find the geometry which wasn't assigned.
1435 //
1436
1437 for(i = 0; i < DetectInfoCount; i++) {
1438 if(DetectInfoList[i].Device == NULL) {
1439 diskInfo = &(DetectInfoList[i]);
1440 break;
1441 }
1442 }
1443
1444 if (diskInfo != NULL)
1445 {
1446 //
1447 // Save the geometry information away in the disk data block and
1448 // set the bit indicating that we found a valid one.
1449 //
1450
1451 ULONG cylinders;
1452 ULONG sectorsPerTrack;
1453 ULONG tracksPerCylinder;
1454
1455 ULONG length;
1456
1457 //
1458 // Point to the array of drive parameters.
1459 //
1460
1461 cylinders = diskInfo->DriveParameters.MaxCylinders + 1;
1462 sectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack;
1463 tracksPerCylinder = diskInfo->DriveParameters.MaxHeads + 1;
1464
1465 //
1466 // Since the BIOS may not report the full drive, recalculate the drive
1467 // size based on the volume size and the BIOS values for tracks per
1468 // cylinder and sectors per track..
1469 //
1470
1471 length = tracksPerCylinder * sectorsPerTrack;
1472
1473 if (length == 0) {
1474
1475 //
1476 // The BIOS information is bogus.
1477 //
1478
1479 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: H (%d) or S(%d) is zero\n",
1480 tracksPerCylinder, sectorsPerTrack));
1481 return;
1482 }
1483
1484 //
1485 // since we are copying the structure RealGeometry here, we should
1486 // really initialize all the fields, especially since a zero'd
1487 // BytesPerSector field would cause a trap in xHalReadPartitionTable()
1488 //
1489
1490 diskData->RealGeometry = fdoExtension->DiskGeometry;
1491
1492 //
1493 // Save the geometry information away in the disk data block and
1494 // set the bit indicating that we found a valid one.
1495 //
1496
1497 diskData->RealGeometry.SectorsPerTrack = sectorsPerTrack;
1498 diskData->RealGeometry.TracksPerCylinder = tracksPerCylinder;
1499 diskData->RealGeometry.Cylinders.QuadPart = (LONGLONG)cylinders;
1500
1501 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: BIOS spt %#x, #heads %#x, "
1502 "#cylinders %#x\n",
1503 sectorsPerTrack, tracksPerCylinder, cylinders));
1504
1505 diskData->GeometrySource = DiskGeometryGuessedFromBios;
1506 diskInfo->Device = unmatchedDisk;
1507
1508 //
1509 // Now copy the geometry over to the fdo extension and call
1510 // classpnp to redetermine the disk size and cylinder count.
1511 //
1512
1513 fdoExtension->DiskGeometry = diskData->RealGeometry;
1514
1515 (VOID)ClassReadDriveCapacity(unmatchedDisk);
1516
1517 if (diskData->RealGeometry.BytesPerSector == 0) {
1518
1519 //
1520 // if the BytesPerSector field is set to zero for a disk
1521 // listed in the bios, then the system will bugcheck in
1522 // xHalReadPartitionTable(). assert here since it is
1523 // easier to determine what is happening this way.
1524 //
1525
1526 NT_ASSERT(!"RealGeometry not set to non-zero bps\n");
1527 }
1528 }
1529
1530 return;
1531 }
1532
1533
1534 NTSTATUS
1535 DiskGetDetectInfo(
1536 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
1537 OUT PDISK_DETECTION_INFO DetectInfo
1538 )
1539 /*++
1540
1541 Routine Description:
1542
1543 Get the Int13 information from the BIOS DetectInfoList.
1544
1545 Arguments:
1546
1547 FdoExtension - Supplies a pointer to the FDO extension that we want to
1548 obtain the detect information for.
1549
1550 DetectInfo - A buffer where the detect information will be copied to.
1551
1552 Return Value:
1553
1554 NTSTATUS code.
1555
1556 --*/
1557 {
1558 ULONG i;
1559 BOOLEAN found = FALSE;
1560 PDISK_DETECT_INFO diskInfo = NULL;
1561 PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
1562
1563 PAGED_CODE ();
1564
1565 //
1566 // Fail for non-fixed drives.
1567 //
1568
1569 if (TEST_FLAG (FdoExtension->DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
1570 return STATUS_NOT_SUPPORTED;
1571 }
1572
1573 //
1574 // There is no GPT detection info, so fail this.
1575 //
1576
1577 if (diskData->PartitionStyle == PARTITION_STYLE_GPT) {
1578 return STATUS_NOT_SUPPORTED;
1579 }
1580
1581 for(i = 0; i < DetectInfoCount; i++) {
1582
1583
1584 NT_ASSERT(DetectInfoList != NULL);
1585
1586 diskInfo = &(DetectInfoList[i]);
1587
1588 if((diskData->Mbr.Signature != 0) &&
1589 (diskData->Mbr.Signature == diskInfo->Signature)) {
1590 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskGetDetectInfo: found match for signature "
1591 "%#08lx\n",
1592 diskData->Mbr.Signature));
1593 found = TRUE;
1594 break;
1595 } else if((diskData->Mbr.Signature == 0) &&
1596 (diskData->Mbr.MbrCheckSum != 0) &&
1597 (diskData->Mbr.MbrCheckSum == diskInfo->MbrCheckSum)) {
1598 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskGetDetectInfo: found match for xsum %#08lx\n",
1599 diskData->Mbr.MbrCheckSum));
1600 found = TRUE;
1601 break;
1602 }
1603 }
1604
1605 if ( found ) {
1606 DetectInfo->DetectionType = DetectInt13;
1607 DetectInfo->Int13.DriveSelect = diskInfo->DriveParameters.DriveSelect;
1608 DetectInfo->Int13.MaxCylinders = diskInfo->DriveParameters.MaxCylinders;
1609 DetectInfo->Int13.SectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack;
1610 DetectInfo->Int13.MaxHeads = diskInfo->DriveParameters.MaxHeads;
1611 DetectInfo->Int13.NumberDrives = diskInfo->DriveParameters.NumberDrives;
1612 RtlZeroMemory (&DetectInfo->ExInt13, sizeof (DetectInfo->ExInt13));
1613 }
1614
1615 return (found ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
1616 }
1617
1618
1619 NTSTATUS
1620 DiskReadSignature(
1621 IN PDEVICE_OBJECT Fdo
1622 )
1623
1624 /*++
1625
1626 Routine Description:
1627
1628 Read the disks signature from the drive. The signature can be either
1629 a MBR signature or a GPT/EFI signature.
1630
1631 The low-level signature reading is done by IoReadDiskSignature().
1632
1633 Arguments:
1634
1635 Fdo - Pointer to the FDO of a disk to read the signature for.
1636
1637 Return Value:
1638
1639 NTSTATUS code.
1640
1641 --*/
1642
1643
1644 {
1645 NTSTATUS Status;
1646 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
1647 PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData;
1648 DISK_SIGNATURE Signature = { 0 };
1649
1650 PAGED_CODE();
1651
1652 Status = IoReadDiskSignature (Fdo,
1653 fdoExtension->DiskGeometry.BytesPerSector,
1654 &Signature);
1655
1656 if (!NT_SUCCESS (Status)) {
1657 return Status;
1658 }
1659
1660 if (Signature.PartitionStyle == PARTITION_STYLE_GPT) {
1661 diskData->PartitionStyle = PARTITION_STYLE_GPT;
1662 diskData->Efi.DiskId = Signature.Gpt.DiskId;
1663 } else if (Signature.PartitionStyle == PARTITION_STYLE_MBR) {
1664 diskData->PartitionStyle = PARTITION_STYLE_MBR;
1665 diskData->Mbr.Signature = Signature.Mbr.Signature;
1666 diskData->Mbr.MbrCheckSum = Signature.Mbr.CheckSum;
1667 } else {
1668 NT_ASSERT (FALSE);
1669 Status = STATUS_UNSUCCESSFUL;
1670 }
1671
1672 return Status;
1673 }
1674
1675 #endif // defined(_X86_) || defined(_AMD64_)
1676