update for HEAD-2003091401
[reactos.git] / drivers / storage / disk / disk.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2001, 2002, 2003 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * COPYRIGHT:       See COPYING in the top level directory
22  * PROJECT:         ReactOS kernel
23  * FILE:            services/storage/disk/disk.c
24  * PURPOSE:         disk class driver
25  * PROGRAMMER:      Eric Kohl (ekohl@rz-online.de)
26  */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <ddk/scsi.h>
32 #include <ddk/class2.h>
33 #include <ddk/ntddscsi.h>
34
35 #define NDEBUG
36 #include <debug.h>
37
38 #define VERSION  "0.0.1"
39
40 #define SCSI_DISK_TIMEOUT       10      /* Default timeout: 10 seconds */
41 #define MODE_DATA_SIZE          192
42
43
44 typedef struct _DISK_DATA
45 {
46   PDEVICE_EXTENSION NextPartition;
47   ULONG Signature;
48   ULONG MbrCheckSum;
49   ULONG HiddenSectors;
50   ULONG PartitionNumber;
51   ULONG PartitionOrdinal;
52   UCHAR PartitionType;
53   BOOLEAN BootIndicator;
54   BOOLEAN DriveNotReady;
55 } DISK_DATA, *PDISK_DATA;
56
57
58 BOOLEAN STDCALL
59 DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
60                      PUNICODE_STRING RegistryPath,
61                      PCLASS_INIT_DATA InitializationData,
62                      PDEVICE_OBJECT PortDeviceObject,
63                      ULONG PortNumber);
64
65 BOOLEAN STDCALL
66 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData);
67
68 NTSTATUS STDCALL
69 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
70                         IN PIRP Irp);
71
72
73 static NTSTATUS
74 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
75                             IN PUNICODE_STRING RegistryPath, /* what's this used for? */
76                             IN PDEVICE_OBJECT PortDeviceObject,
77                             IN ULONG PortNumber,
78                             IN ULONG DiskNumber,
79                             IN PIO_SCSI_CAPABILITIES Capabilities,
80                             IN PSCSI_INQUIRY_DATA InquiryData,
81                             IN PCLASS_INIT_DATA InitializationData);
82
83 NTSTATUS STDCALL
84 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
85                        IN PIRP Irp);
86
87 NTSTATUS STDCALL
88 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
89                        IN PIRP Irp);
90
91 static BOOLEAN
92 ScsiDiskSearchForDisk(IN PDEVICE_EXTENSION DeviceExtension,
93                       IN HANDLE BusKey,
94                       OUT PULONG DetectedDiskNumber);
95
96 static VOID
97 DiskClassUpdatePartitionDeviceObjects (IN PDEVICE_OBJECT DeviceObject,
98                                        IN PIRP Irp);
99
100 static VOID
101 ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension);
102
103 static BOOLEAN
104 ScsiDiskCalcMbrCheckSum(IN PDEVICE_EXTENSION DeviceExtension,
105                         OUT PULONG Checksum);
106
107
108 /* FUNCTIONS ****************************************************************/
109
110 /**********************************************************************
111  * NAME                                                 EXPORTED
112  *      DriverEntry
113  *
114  * DESCRIPTION
115  *      This function initializes the driver, locates and claims 
116  *      hardware resources, and creates various NT objects needed
117  *      to process I/O requests.
118  *
119  * RUN LEVEL
120  *      PASSIVE_LEVEL
121  *
122  * ARGUMENTS
123  *      DriverObject
124  *              System allocated Driver Object for this driver
125  *
126  *      RegistryPath
127  *              Name of registry driver service key
128  *
129  * RETURN VALUE
130  *      Status
131  */
132
133 NTSTATUS STDCALL
134 DriverEntry(IN PDRIVER_OBJECT DriverObject,
135             IN PUNICODE_STRING RegistryPath)
136 {
137   CLASS_INIT_DATA InitData;
138
139   DPRINT("Disk Class Driver %s\n",
140          VERSION);
141   DPRINT("RegistryPath '%wZ'\n",
142          RegistryPath);
143
144   RtlZeroMemory(&InitData,
145                 sizeof(CLASS_INIT_DATA));
146
147   InitData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
148   InitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA);
149   InitData.DeviceType = FILE_DEVICE_DISK;
150   InitData.DeviceCharacteristics = 0;
151
152   InitData.ClassError = NULL;   // DiskClassProcessError;
153   InitData.ClassReadWriteVerification = DiskClassCheckReadWrite;
154   InitData.ClassFindDeviceCallBack = DiskClassCheckDevice;
155   InitData.ClassFindDevices = DiskClassFindDevices;
156   InitData.ClassDeviceControl = DiskClassDeviceControl;
157   InitData.ClassShutdownFlush = DiskClassShutdownFlush;
158   InitData.ClassCreateClose = NULL;
159   InitData.ClassStartIo = NULL;
160
161   return(ScsiClassInitialize(DriverObject,
162                              RegistryPath,
163                              &InitData));
164 }
165
166
167 /**********************************************************************
168  * NAME                                                 EXPORTED
169  *      DiskClassFindDevices
170  *
171  * DESCRIPTION
172  *      This function searches for device that are attached to the
173  *      given scsi port.
174  *
175  * RUN LEVEL
176  *      PASSIVE_LEVEL
177  *
178  * ARGUMENTS
179  *      DriverObject
180  *              System allocated Driver Object for this driver
181  *
182  *      RegistryPath
183  *              Name of registry driver service key
184  *
185  *      InitializationData
186  *              Pointer to the main initialization data
187  *
188  *      PortDeviceObject
189  *              Pointer to the port Device Object
190  *
191  *      PortNumber
192  *              Port number
193  *
194  * RETURN VALUE
195  *      TRUE: At least one disk drive was found
196  *      FALSE: No disk drive found
197  */
198
199 BOOLEAN STDCALL
200 DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
201                      PUNICODE_STRING RegistryPath,
202                      PCLASS_INIT_DATA InitializationData,
203                      PDEVICE_OBJECT PortDeviceObject,
204                      ULONG PortNumber)
205 {
206   PCONFIGURATION_INFORMATION ConfigInfo;
207   PIO_SCSI_CAPABILITIES PortCapabilities;
208   PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
209   PSCSI_INQUIRY_DATA UnitInfo;
210   PINQUIRYDATA InquiryData;
211   PCHAR Buffer;
212   ULONG Bus;
213   ULONG DeviceCount;
214   BOOLEAN FoundDevice;
215   NTSTATUS Status;
216
217   DPRINT("DiskClassFindDevices() called.\n");
218
219   /* Get port capabilities */
220   Status = ScsiClassGetCapabilities(PortDeviceObject,
221                                     &PortCapabilities);
222   if (!NT_SUCCESS(Status))
223     {
224       DPRINT("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status);
225       return(FALSE);
226     }
227
228   DPRINT("PortCapabilities: %p\n", PortCapabilities);
229   DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
230   DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities->MaximumPhysicalPages);
231
232   /* Get inquiry data */
233   Status = ScsiClassGetInquiryData(PortDeviceObject,
234                                    (PSCSI_ADAPTER_BUS_INFO *)&Buffer);
235   if (!NT_SUCCESS(Status))
236     {
237       DPRINT("ScsiClassGetInquiryData() failed! (Status %x)\n", Status);
238       return(FALSE);
239     }
240
241   /* Check whether there are unclaimed devices */
242   AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
243   DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
244                                               AdapterBusInfo);
245   if (DeviceCount == 0)
246     {
247       DPRINT("No unclaimed devices!\n");
248       return(FALSE);
249     }
250
251   DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
252
253   ConfigInfo = IoGetConfigurationInformation();
254
255   /* Search each bus of this adapter */
256   for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
257     {
258       DPRINT("Searching bus %lu\n", Bus);
259
260       UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
261
262       while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
263         {
264           InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
265
266           DPRINT("Device type %u\n", InquiryData->DeviceType);
267
268           if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
269                (InquiryData->DeviceType == OPTICAL_DEVICE)) &&
270               (InquiryData->DeviceTypeQualifier == 0) &&
271               (UnitInfo->DeviceClaimed == FALSE))
272             {
273               DPRINT("Vendor: '%.24s'\n",
274                      InquiryData->VendorId);
275
276               /* Create device objects for disk */
277               Status = DiskClassCreateDeviceObject(DriverObject,
278                                                    RegistryPath,
279                                                    PortDeviceObject,
280                                                    PortNumber,
281                                                    ConfigInfo->DiskCount,
282                                                    PortCapabilities,
283                                                    UnitInfo,
284                                                    InitializationData);
285               if (NT_SUCCESS(Status))
286                 {
287                   ConfigInfo->DiskCount++;
288                   FoundDevice = TRUE;
289                 }
290             }
291
292           if (UnitInfo->NextInquiryDataOffset == 0)
293             break;
294
295           UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
296         }
297     }
298
299   ExFreePool(Buffer);
300
301   DPRINT("DiskClassFindDevices() done\n");
302
303   return(FoundDevice);
304 }
305
306
307 /**********************************************************************
308  * NAME                                                 EXPORTED
309  *      DiskClassCheckDevice
310  *
311  * DESCRIPTION
312  *      This function checks the InquiryData for the correct device
313  *      type and qualifier.
314  *
315  * RUN LEVEL
316  *      PASSIVE_LEVEL
317  *
318  * ARGUMENTS
319  *      InquiryData
320  *              Pointer to the inquiry data for the device in question.
321  *
322  * RETURN VALUE
323  *      TRUE: A disk device was found.
324  *      FALSE: Otherwise.
325  */
326
327 BOOLEAN STDCALL
328 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData)
329 {
330   return((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE ||
331           InquiryData->DeviceType == OPTICAL_DEVICE) &&
332          InquiryData->DeviceTypeQualifier == 0);
333 }
334
335
336 /**********************************************************************
337  * NAME                                                 EXPORTED
338  *      DiskClassCheckReadWrite
339  *
340  * DESCRIPTION
341  *      This function checks the given IRP for correct data.
342  *
343  * RUN LEVEL
344  *      PASSIVE_LEVEL
345  *
346  * ARGUMENTS
347  *      DeviceObject
348  *              Pointer to the device.
349  *
350  *      Irp
351  *              Irp to check.
352  *
353  * RETURN VALUE
354  *      STATUS_SUCCESS: The IRP matches the requirements of the given device.
355  *      Others: Failure.
356  */
357
358 NTSTATUS STDCALL
359 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
360                         IN PIRP Irp)
361 {
362   PDEVICE_EXTENSION DeviceExtension;
363   PDISK_DATA DiskData;
364
365   DPRINT("DiskClassCheckReadWrite() called\n");
366
367   DeviceExtension = DeviceObject->DeviceExtension;
368   DiskData = (PDISK_DATA)(DeviceExtension + 1);
369
370   if (DiskData->DriveNotReady == TRUE)
371     {
372       Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
373       IoSetHardErrorOrVerifyDevice(Irp,
374                                    DeviceObject);
375       return(STATUS_INVALID_PARAMETER);
376     }
377
378   return(STATUS_SUCCESS);
379 }
380
381
382 /**********************************************************************
383  * NAME                                                 INTERNAL
384  *      DiskClassCreateDeviceObject
385  *
386  * DESCRIPTION
387  *      Create the raw device and any partition devices on this drive
388  *
389  * RUN LEVEL
390  *      PASSIVE_LEVEL
391  *
392  * ARGUMENTS
393  *      DriverObject
394  *              The system created driver object
395  *      RegistryPath
396  *      PortDeviceObject
397  *      PortNumber
398  *      DiskNumber
399  *      Capabilities
400  *      InquiryData
401  *      InitialzationData
402  *
403  * RETURN VALUE
404  *      STATUS_SUCCESS: Device objects for disk and partitions were created.
405  *      Others: Failure.
406  */
407
408 static NTSTATUS
409 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
410                             IN PUNICODE_STRING RegistryPath,
411                             IN PDEVICE_OBJECT PortDeviceObject,
412                             IN ULONG PortNumber,
413                             IN ULONG DiskNumber,
414                             IN PIO_SCSI_CAPABILITIES Capabilities,
415                             IN PSCSI_INQUIRY_DATA InquiryData,
416                             IN PCLASS_INIT_DATA InitializationData)
417 {
418   OBJECT_ATTRIBUTES ObjectAttributes;
419   UNICODE_STRING UnicodeDeviceDirName;
420   WCHAR NameBuffer[80];
421   CHAR NameBuffer2[80];
422   PDEVICE_OBJECT DiskDeviceObject;
423   PDEVICE_OBJECT PartitionDeviceObject;
424   PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
425   PDEVICE_EXTENSION PartitionDeviceExtension; /* defined in class2.h */
426   PDRIVE_LAYOUT_INFORMATION PartitionList = NULL;
427   HANDLE Handle;
428   PPARTITION_INFORMATION PartitionEntry;
429   PDISK_DATA DiskData;
430   ULONG PartitionNumber;
431   PVOID MbrBuffer;
432   NTSTATUS Status;
433
434   DPRINT("DiskClassCreateDeviceObject() called\n");
435
436   /* Create the harddisk device directory */
437   swprintf(NameBuffer,
438            L"\\Device\\Harddisk%lu",
439            DiskNumber);
440   RtlInitUnicodeString(&UnicodeDeviceDirName,
441                        NameBuffer);
442   InitializeObjectAttributes(&ObjectAttributes,
443                              &UnicodeDeviceDirName,
444                              0,
445                              NULL,
446                              NULL);
447   Status = ZwCreateDirectoryObject(&Handle,
448                                    0,
449                                    &ObjectAttributes);
450   if (!NT_SUCCESS(Status))
451     {
452       DbgPrint("Could not create device dir object\n");
453       return(Status);
454     }
455
456   /* Claim the disk device */
457   Status = ScsiClassClaimDevice(PortDeviceObject,
458                                 InquiryData,
459                                 FALSE,
460                                 &PortDeviceObject);
461   if (!NT_SUCCESS(Status))
462     {
463       DbgPrint("Could not claim disk device\n");
464
465       ZwMakeTemporaryObject(Handle);
466       ZwClose(Handle);
467
468       return(Status);
469     }
470
471   /* Create disk device (Partition 0) */
472   sprintf(NameBuffer2,
473           "\\Device\\Harddisk%lu\\Partition0",
474           DiskNumber);
475
476   Status = ScsiClassCreateDeviceObject(DriverObject,
477                                        NameBuffer2,
478                                        NULL,
479                                        &DiskDeviceObject,
480                                        InitializationData);
481   if (!NT_SUCCESS(Status))
482     {
483       DPRINT("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
484
485       /* Release (unclaim) the disk */
486       ScsiClassClaimDevice(PortDeviceObject,
487                            InquiryData,
488                            TRUE,
489                            NULL);
490
491       /* Delete the harddisk device directory */
492       ZwMakeTemporaryObject(Handle);
493       ZwClose(Handle);
494
495       return(Status);
496     }
497
498   DiskDeviceObject->Flags |= DO_DIRECT_IO;
499   if (((PINQUIRYDATA)InquiryData->InquiryData)->RemovableMedia)
500     {
501       DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
502     }
503   DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
504
505   if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
506     {
507       DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
508     }
509
510   DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
511   DiskDeviceExtension->LockCount = 0;
512   DiskDeviceExtension->DeviceNumber = DiskNumber;
513   DiskDeviceExtension->DeviceObject = DiskDeviceObject;
514   DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
515   DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
516   DiskDeviceExtension->PortCapabilities = Capabilities;
517   DiskDeviceExtension->StartingOffset.QuadPart = 0;
518   DiskDeviceExtension->PortNumber = (UCHAR)PortNumber;
519   DiskDeviceExtension->PathId = InquiryData->PathId;
520   DiskDeviceExtension->TargetId = InquiryData->TargetId;
521   DiskDeviceExtension->Lun = InquiryData->Lun;
522
523   /* Get timeout value */
524   DiskDeviceExtension->TimeOutValue =
525     ScsiClassQueryTimeOutRegistryValue(RegistryPath);
526   if (DiskDeviceExtension->TimeOutValue == 0)
527     DiskDeviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
528
529   /* Initialize the lookaside list for SRBs */
530   ScsiClassInitializeSrbLookasideList(DiskDeviceExtension,
531                                       4);
532
533   /* zero-out disk data */
534   DiskData = (PDISK_DATA)(DiskDeviceExtension + 1);
535   RtlZeroMemory(DiskData,
536                 sizeof(DISK_DATA));
537
538   /* Get disk geometry */
539   DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
540                                                      sizeof(DISK_GEOMETRY));
541   if (DiskDeviceExtension->DiskGeometry == NULL)
542     {
543       DPRINT("Failed to allocate geometry buffer!\n");
544
545       ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
546
547       IoDeleteDevice(DiskDeviceObject);
548
549       /* Release (unclaim) the disk */
550       ScsiClassClaimDevice(PortDeviceObject,
551                            InquiryData,
552                            TRUE,
553                            NULL);
554
555       /* Delete the harddisk device directory */
556       ZwMakeTemporaryObject(Handle);
557       ZwClose(Handle);
558
559       return(STATUS_INSUFFICIENT_RESOURCES);
560     }
561
562   /* Allocate sense data buffer */
563   DiskDeviceExtension->SenseData = ExAllocatePool(NonPagedPool,
564                                                   sizeof(SENSE_BUFFER_SIZE));
565   if (DiskDeviceExtension->SenseData == NULL)
566     {
567       DPRINT("Failed to allocate sense data buffer!\n");
568
569       ExFreePool (DiskDeviceExtension->DiskGeometry);
570
571       ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
572
573       IoDeleteDevice(DiskDeviceObject);
574
575       /* Release (unclaim) the disk */
576       ScsiClassClaimDevice(PortDeviceObject,
577                            InquiryData,
578                            TRUE,
579                            NULL);
580
581       /* Delete the harddisk device directory */
582       ZwMakeTemporaryObject(Handle);
583       ZwClose(Handle);
584
585       return(STATUS_INSUFFICIENT_RESOURCES);
586     }
587
588   /* Read the drive's capacity */
589   Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
590   if (!NT_SUCCESS(Status) &&
591       (DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0)
592     {
593       DPRINT1("Failed to retrieve drive capacity!\n");
594       return(STATUS_SUCCESS);
595     }
596   else
597     {
598       /* Clear the verify flag for removable media drives. */
599       DiskDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
600     }
601
602   DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
603
604   /* Check disk for presence of a disk manager */
605   HalExamineMBR(DiskDeviceObject,
606                 DiskDeviceExtension->DiskGeometry->BytesPerSector,
607                 0x54,
608                 &MbrBuffer);
609   if (MbrBuffer != NULL)
610     {
611       /* Start disk at sector 63 if the Ontrack Disk Manager was found */
612       DPRINT("Found 'Ontrack Disk Manager'!\n");
613
614       DiskDeviceExtension->DMSkew = 63;
615       DiskDeviceExtension->DMByteSkew =
616         63 * DiskDeviceExtension->DiskGeometry->BytesPerSector;
617       DiskDeviceExtension->DMActive = TRUE;
618
619       ExFreePool(MbrBuffer);
620       MbrBuffer = NULL;
621     }
622
623   if ((DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
624       (DiskDeviceExtension->DiskGeometry->MediaType == RemovableMedia))
625     {
626       /* Allocate a partition list for a single entry. */
627       PartitionList = ExAllocatePool(NonPagedPool,
628                                      sizeof(DRIVE_LAYOUT_INFORMATION));
629       if (PartitionList != NULL)
630         {
631           RtlZeroMemory(PartitionList,
632                         sizeof(DRIVE_LAYOUT_INFORMATION));
633           PartitionList->PartitionCount = 1;
634
635           DiskData->DriveNotReady = TRUE;
636           Status = STATUS_SUCCESS;
637         }
638     }
639   else
640     {
641       /* Read partition table */
642       Status = IoReadPartitionTable(DiskDeviceObject,
643                                     DiskDeviceExtension->DiskGeometry->BytesPerSector,
644                                     TRUE,
645                                     &PartitionList);
646
647       DPRINT("IoReadPartitionTable(): Status: %lx\n", Status);
648
649       if ((!NT_SUCCESS(Status) || PartitionList->PartitionCount == 0) &&
650           DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
651         {
652           if (!NT_SUCCESS(Status))
653             {
654               /* Drive is not ready. */
655               DPRINT("Drive not ready\n");
656               DiskData->DriveNotReady = TRUE;
657             }
658           else
659             {
660               ExFreePool(PartitionList);
661             }
662
663           /* Allocate a partition list for a single entry. */
664           PartitionList = ExAllocatePool(NonPagedPool,
665                                          sizeof(DRIVE_LAYOUT_INFORMATION));
666           if (PartitionList != NULL)
667             {
668               RtlZeroMemory(PartitionList,
669                             sizeof(DRIVE_LAYOUT_INFORMATION));
670               PartitionList->PartitionCount = 1;
671
672               Status = STATUS_SUCCESS;
673             }
674         }
675     }
676
677   if (NT_SUCCESS(Status))
678     {
679       DPRINT("Read partition table!\n");
680       DPRINT("  Number of partitions: %u\n", PartitionList->PartitionCount);
681
682       /* Set disk signature */
683       DiskData->Signature = PartitionList->Signature;
684
685       /* Calculate MBR checksum if disk got no signature */
686       if (DiskData->Signature == 0)
687         {
688           if (!ScsiDiskCalcMbrCheckSum(DiskDeviceExtension,
689                                        &DiskData->MbrCheckSum))
690             {
691               DPRINT("MBR checksum calculation failed for disk %lu\n",
692                      DiskDeviceExtension->DeviceNumber);
693             }
694           else
695             {
696               DPRINT("MBR checksum for disk %lu is %lx\n",
697                      DiskDeviceExtension->DeviceNumber,
698                      DiskData->MbrCheckSum);
699             }
700         }
701       else
702         {
703           DPRINT("Signature on disk %lu is %lx\n",
704                  DiskDeviceExtension->DeviceNumber,
705                  DiskData->Signature);
706         }
707
708       /* Update disk geometry if disk is visible to the BIOS */
709       ScsiDiskUpdateFixedDiskGeometry(DiskDeviceExtension);
710
711       for (PartitionNumber = 0; PartitionNumber < PartitionList->PartitionCount; PartitionNumber++)
712         {
713           PartitionEntry = &PartitionList->PartitionEntry[PartitionNumber];
714
715           DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
716                  PartitionNumber,
717                  PartitionEntry->PartitionNumber,
718                  PartitionEntry->BootIndicator,
719                  PartitionEntry->PartitionType,
720                  PartitionEntry->StartingOffset.QuadPart / 512 /*DrvParms.BytesPerSector*/,
721                  PartitionEntry->PartitionLength.QuadPart / 512 /* DrvParms.BytesPerSector*/);
722
723           /* Create partition device object */
724           sprintf(NameBuffer2,
725                   "\\Device\\Harddisk%lu\\Partition%lu",
726                   DiskNumber,
727                   PartitionNumber + 1);
728
729           Status = ScsiClassCreateDeviceObject(DriverObject,
730                                                NameBuffer2,
731                                                DiskDeviceObject,
732                                                &PartitionDeviceObject,
733                                                InitializationData);
734           DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status);
735           if (NT_SUCCESS(Status))
736             {
737               PartitionDeviceObject->Flags = DiskDeviceObject->Flags;
738               PartitionDeviceObject->Characteristics = DiskDeviceObject->Characteristics;
739               PartitionDeviceObject->StackSize = DiskDeviceObject->StackSize;
740               PartitionDeviceObject->AlignmentRequirement = DiskDeviceObject->AlignmentRequirement;
741
742               PartitionDeviceExtension = PartitionDeviceObject->DeviceExtension;
743               PartitionDeviceExtension->SenseData = DiskDeviceExtension->SenseData;
744               PartitionDeviceExtension->LockCount = 0;
745               PartitionDeviceExtension->DeviceNumber = DiskNumber;
746               PartitionDeviceExtension->DeviceObject = PartitionDeviceObject;
747               PartitionDeviceExtension->PortDeviceObject = PortDeviceObject;
748               PartitionDeviceExtension->DiskGeometry = DiskDeviceExtension->DiskGeometry;
749               PartitionDeviceExtension->PhysicalDevice = DiskDeviceExtension->PhysicalDevice;
750               PartitionDeviceExtension->PortCapabilities = Capabilities;
751               PartitionDeviceExtension->StartingOffset.QuadPart =
752                 PartitionEntry->StartingOffset.QuadPart;
753               PartitionDeviceExtension->PartitionLength.QuadPart =
754                 PartitionEntry->PartitionLength.QuadPart;
755               PartitionDeviceExtension->DMSkew = DiskDeviceExtension->DMSkew;
756               PartitionDeviceExtension->DMByteSkew = DiskDeviceExtension->DMByteSkew;
757               PartitionDeviceExtension->DMActive = DiskDeviceExtension->DMActive;
758               PartitionDeviceExtension->PortNumber = (UCHAR)PortNumber;
759               PartitionDeviceExtension->PathId = InquiryData->PathId;
760               PartitionDeviceExtension->TargetId = InquiryData->TargetId;
761               PartitionDeviceExtension->Lun = InquiryData->Lun;
762               PartitionDeviceExtension->SectorShift = DiskDeviceExtension->SectorShift;
763               PartitionDeviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
764
765               /* Initialize lookaside list for SRBs */
766               ScsiClassInitializeSrbLookasideList(PartitionDeviceExtension,
767                                                   8);
768
769               /* Link current partition device extension to previous disk data */
770               DiskData->NextPartition = PartitionDeviceExtension;
771
772               /* Initialize current disk data */
773               DiskData = (PDISK_DATA)(PartitionDeviceExtension + 1);
774               DiskData->NextPartition = NULL;
775               DiskData->PartitionType = PartitionEntry->PartitionType;
776               DiskData->PartitionNumber = PartitionNumber + 1;
777               DiskData->PartitionOrdinal = PartitionNumber + 1;
778               DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
779               DiskData->BootIndicator = PartitionEntry->BootIndicator;
780               DiskData->DriveNotReady = FALSE;
781             }
782           else
783             {
784               DPRINT1("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status);
785
786               break;
787             }
788         }
789     }
790
791   if (PartitionList != NULL)
792     ExFreePool(PartitionList);
793
794   DPRINT("DiskClassCreateDeviceObjects() done\n");
795
796   return(STATUS_SUCCESS);
797 }
798
799
800 /**********************************************************************
801  * NAME                                                 EXPORTED
802  *      DiskClassDeviceControl
803  *
804  * DESCRIPTION
805  *      Answer requests for device control calls
806  *
807  * RUN LEVEL
808  *      PASSIVE_LEVEL
809  *
810  * ARGUMENTS
811  *      Standard dispatch arguments
812  *
813  * RETURNS
814  *      Status
815  */
816
817 NTSTATUS STDCALL
818 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
819                        IN PIRP Irp)
820 {
821   PDEVICE_EXTENSION DeviceExtension;
822   PIO_STACK_LOCATION IrpStack;
823   ULONG ControlCode, InputLength, OutputLength;
824   PDISK_DATA DiskData;
825   ULONG Information;
826   NTSTATUS Status;
827
828   DPRINT("DiskClassDeviceControl() called!\n");
829
830   Status = STATUS_INVALID_DEVICE_REQUEST;
831   Information = 0;
832   IrpStack = IoGetCurrentIrpStackLocation(Irp);
833   ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
834   InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
835   OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
836   DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
837   DiskData = (PDISK_DATA)(DeviceExtension + 1);
838
839   switch (ControlCode)
840     {
841       case IOCTL_DISK_GET_DRIVE_GEOMETRY:
842         DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
843         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
844           {
845             Status = STATUS_INVALID_PARAMETER;
846             break;
847           }
848
849         if (DeviceExtension->DiskGeometry == NULL)
850           {
851             DPRINT("No disk geometry available!\n");
852             DeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
853                                                            sizeof(DISK_GEOMETRY));
854           }
855
856         if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
857           {
858             Status = ScsiClassReadDriveCapacity(DeviceObject);
859             DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status);
860             if (!NT_SUCCESS(Status))
861               {
862                 /* Drive is not ready */
863                 DiskData->DriveNotReady = FALSE;
864                 break;
865               }
866
867             /* Drive is ready */
868             DiskData->DriveNotReady = FALSE;
869           }
870
871         RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
872                       DeviceExtension->DiskGeometry,
873                       sizeof(DISK_GEOMETRY));
874
875         Status = STATUS_SUCCESS;
876         Information = sizeof(DISK_GEOMETRY);
877         break;
878
879       case IOCTL_DISK_GET_PARTITION_INFO:
880         DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
881         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
882             sizeof(PARTITION_INFORMATION))
883           {
884             Status = STATUS_INFO_LENGTH_MISMATCH;
885           }
886         else if (DiskData->PartitionNumber == 0)
887           {
888             Status = STATUS_INVALID_DEVICE_REQUEST;
889           }
890         else
891           {
892             PPARTITION_INFORMATION PartitionInfo;
893
894             PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
895
896             PartitionInfo->PartitionType = DiskData->PartitionType;
897             PartitionInfo->StartingOffset = DeviceExtension->StartingOffset;
898             PartitionInfo->PartitionLength = DeviceExtension->PartitionLength;
899             PartitionInfo->HiddenSectors = DiskData->HiddenSectors;
900             PartitionInfo->PartitionNumber = DiskData->PartitionNumber;
901             PartitionInfo->BootIndicator = DiskData->BootIndicator;
902             PartitionInfo->RewritePartition = FALSE;
903             PartitionInfo->RecognizedPartition =
904               IsRecognizedPartition(DiskData->PartitionType);
905
906             Status = STATUS_SUCCESS;
907             Information = sizeof(PARTITION_INFORMATION);
908           }
909         break;
910
911       case IOCTL_DISK_SET_PARTITION_INFO:
912         if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
913             sizeof(SET_PARTITION_INFORMATION))
914           {
915             Status = STATUS_INFO_LENGTH_MISMATCH;
916           }
917         else if (DiskData->PartitionNumber == 0)
918           {
919             Status = STATUS_INVALID_DEVICE_REQUEST;
920           }
921         else
922           {
923             PSET_PARTITION_INFORMATION PartitionInfo;
924
925             PartitionInfo = (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
926
927             Status = IoSetPartitionInformation(DeviceExtension->PhysicalDevice,
928                                                DeviceExtension->DiskGeometry->BytesPerSector,
929                                                DiskData->PartitionOrdinal,
930                                                PartitionInfo->PartitionType);
931             if (NT_SUCCESS(Status))
932               {
933                 DiskData->PartitionType = PartitionInfo->PartitionType;
934               }
935           }
936         break;
937
938       case IOCTL_DISK_GET_DRIVE_LAYOUT:
939         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
940             sizeof(DRIVE_LAYOUT_INFORMATION))
941           {
942             Status = STATUS_BUFFER_TOO_SMALL;
943           }
944         else
945           {
946             PDRIVE_LAYOUT_INFORMATION PartitionList;
947
948             Status = IoReadPartitionTable(DeviceExtension->PhysicalDevice,
949                                           DeviceExtension->DiskGeometry->BytesPerSector,
950                                           FALSE,
951                                           &PartitionList);
952             if (NT_SUCCESS(Status))
953               {
954                 ULONG BufferSize;
955
956                 BufferSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
957                                           PartitionEntry[0]);
958                 BufferSize += PartitionList->PartitionCount * sizeof(PARTITION_INFORMATION);
959
960                 if (BufferSize > IrpStack->Parameters.DeviceIoControl.OutputBufferLength)
961                   {
962                     Status = STATUS_BUFFER_TOO_SMALL;
963                   }
964                 else
965                   {
966                     RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
967                                   PartitionList,
968                                   BufferSize);
969                     Status = STATUS_SUCCESS;
970                     Information = BufferSize;
971                   }
972                 ExFreePool(PartitionList);
973               }
974           }
975         break;
976
977       case IOCTL_DISK_SET_DRIVE_LAYOUT:
978         if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
979             sizeof(DRIVE_LAYOUT_INFORMATION))
980           {
981             Status = STATUS_INFO_LENGTH_MISMATCH;
982           }
983         else if (DeviceExtension->PhysicalDevice->DeviceExtension != DeviceExtension)
984           {
985             Status = STATUS_INVALID_PARAMETER;
986           }
987         else
988           {
989             PDRIVE_LAYOUT_INFORMATION PartitionList;
990             ULONG TableSize;
991
992             PartitionList = Irp->AssociatedIrp.SystemBuffer;
993             TableSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
994                         ((PartitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
995
996             if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < TableSize)
997               {
998                 Status = STATUS_BUFFER_TOO_SMALL;
999               }
1000             else
1001               {
1002                 /* Update partition device objects */
1003                 DiskClassUpdatePartitionDeviceObjects (DeviceObject,
1004                                                        Irp);
1005
1006                 /* Write partition table */
1007                 Status = IoWritePartitionTable(DeviceExtension->PhysicalDevice,
1008                                                DeviceExtension->DiskGeometry->BytesPerSector,
1009                                                DeviceExtension->DiskGeometry->SectorsPerTrack,
1010                                                DeviceExtension->DiskGeometry->TracksPerCylinder,
1011                                                PartitionList);
1012                 if (NT_SUCCESS(Status))
1013                   {
1014                     Information = TableSize;
1015                   }
1016               }
1017           }
1018         break;
1019
1020       case IOCTL_DISK_IS_WRITABLE:
1021         {
1022           PMODE_PARAMETER_HEADER ModeData;
1023           ULONG Length;
1024
1025           ModeData = ExAllocatePool (NonPagedPool,
1026                                      MODE_DATA_SIZE);
1027           if (ModeData == NULL)
1028             {
1029               Status = STATUS_INSUFFICIENT_RESOURCES;
1030               break;
1031             }
1032           RtlZeroMemory (ModeData,
1033                          MODE_DATA_SIZE);
1034
1035           Length = ScsiClassModeSense (DeviceObject,
1036                                        (PVOID)ModeData,
1037                                        MODE_DATA_SIZE,
1038                                        MODE_SENSE_RETURN_ALL);
1039           if (Length < sizeof(MODE_PARAMETER_HEADER))
1040             {
1041               /* FIXME: Retry */
1042               Status = STATUS_IO_DEVICE_ERROR;
1043               ExFreePool (ModeData);
1044               break;
1045             }
1046
1047           if (ModeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT)
1048             {
1049               Status = STATUS_MEDIA_WRITE_PROTECTED;
1050             }
1051           else
1052             {
1053               Status = STATUS_SUCCESS;
1054             }
1055           ExFreePool (ModeData);
1056         }
1057         break;
1058
1059       case IOCTL_DISK_VERIFY:
1060       case IOCTL_DISK_FORMAT_TRACKS:
1061       case IOCTL_DISK_PERFORMANCE:
1062       case IOCTL_DISK_LOGGING:
1063       case IOCTL_DISK_FORMAT_TRACKS_EX:
1064       case IOCTL_DISK_HISTOGRAM_STRUCTURE:
1065       case IOCTL_DISK_HISTOGRAM_DATA:
1066       case IOCTL_DISK_HISTOGRAM_RESET:
1067       case IOCTL_DISK_REQUEST_STRUCTURE:
1068       case IOCTL_DISK_REQUEST_DATA:
1069         /* If we get here, something went wrong. Inform the requestor */
1070         DPRINT1("Unhandled control code: %lx\n", ControlCode);
1071         Status = STATUS_INVALID_DEVICE_REQUEST;
1072         Information = 0;
1073         break;
1074
1075       default:
1076         /* Call the common device control function */
1077         return(ScsiClassDeviceControl(DeviceObject, Irp));
1078     }
1079
1080   /* Verify the device if the user caused the error */
1081   if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
1082     {
1083       IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1084     }
1085
1086   Irp->IoStatus.Status = Status;
1087   Irp->IoStatus.Information = Information;
1088   IoCompleteRequest(Irp,
1089                     IO_NO_INCREMENT);
1090
1091   return(Status);
1092 }
1093
1094
1095 /**********************************************************************
1096  * NAME                                                 EXPORTED
1097  *      DiskClassShutdownFlush
1098  *
1099  * DESCRIPTION
1100  *      Answer requests for shutdown and flush calls.
1101  *
1102  * RUN LEVEL
1103  *      PASSIVE_LEVEL
1104  *
1105  * ARGUMENTS
1106  *      DeviceObject
1107  *              Pointer to the device.
1108  *
1109  *      Irp
1110  *              Pointer to the IRP
1111  *
1112  * RETURN VALUE
1113  *      Status
1114  */
1115
1116 NTSTATUS STDCALL
1117 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
1118                        IN PIRP Irp)
1119 {
1120   PDEVICE_EXTENSION DeviceExtension;
1121   PIO_STACK_LOCATION IrpStack;
1122   PSCSI_REQUEST_BLOCK Srb;
1123
1124   DPRINT("DiskClassShutdownFlush() called!\n");
1125
1126   DeviceExtension = DeviceObject->DeviceExtension;
1127
1128   /* Allocate SRB */
1129   Srb = ExAllocatePool(NonPagedPool,
1130                        sizeof(SCSI_REQUEST_BLOCK));
1131   if (Srb == NULL)
1132     {
1133       Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1134       Irp->IoStatus.Information = 0;
1135       IoCompleteRequest(Irp, IO_NO_INCREMENT);
1136
1137       return(STATUS_INSUFFICIENT_RESOURCES);
1138     }
1139
1140   /* Initialize SRB */
1141   RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
1142   Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1143
1144   /* Set device IDs */
1145   Srb->PathId = DeviceExtension->PathId;
1146   Srb->TargetId = DeviceExtension->TargetId;
1147   Srb->Lun = DeviceExtension->Lun;
1148
1149   /* Set timeout */
1150   Srb->TimeOutValue = DeviceExtension->TimeOutValue * 4;
1151
1152   /* Flush write cache */
1153   Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1154   Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1155   Srb->CdbLength = 10;
1156   Srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
1157   ScsiClassSendSrbSynchronous(DeviceObject,
1158                               Srb,
1159                               NULL,
1160                               0,
1161                               TRUE);
1162
1163   /* Get current stack location */
1164   IrpStack = IoGetCurrentIrpStackLocation(Irp);
1165
1166   /* FIXME: Unlock removable media upon shutdown */
1167
1168
1169   /* No retry */
1170   IrpStack->Parameters.Others.Argument4 = (PVOID)0;
1171
1172   /* Send shutdown or flush request to the port driver */
1173   Srb->CdbLength = 0;
1174   if (IrpStack->MajorFunction == IRP_MJ_SHUTDOWN)
1175     Srb->Function = SRB_FUNCTION_SHUTDOWN;
1176   else
1177     Srb->Function = SRB_FUNCTION_FLUSH;
1178
1179   /* Init completion routine */
1180   IoSetCompletionRoutine(Irp,
1181                          ScsiClassIoComplete,
1182                          Srb,
1183                          TRUE,
1184                          TRUE,
1185                          TRUE);
1186
1187   /* Prepare next stack location for a call to the port driver */
1188   IrpStack = IoGetNextIrpStackLocation(Irp);
1189   IrpStack->MajorFunction = IRP_MJ_SCSI;
1190   IrpStack->Parameters.Scsi.Srb = Srb;
1191   Srb->OriginalRequest = Irp;
1192
1193   /* Call port driver */
1194   return(IoCallDriver(DeviceExtension->PortDeviceObject, Irp));
1195 }
1196
1197
1198 /**********************************************************************
1199  * NAME                                                 INTERNAL
1200  *      DiskClassUpdatePartitionDeviceObjects
1201  *
1202  * DESCRIPTION
1203  *      Deletes, modifies or creates partition device objects.
1204  *
1205  * RUN LEVEL
1206  *      PASSIVE_LEVEL
1207  *
1208  * ARGUMENTS
1209  *      DeviceObject
1210  *              Pointer to the device.
1211  *
1212  *      Irp
1213  *              Pointer to the IRP
1214  *
1215  * RETURN VALUE
1216  *      None
1217  */
1218
1219 static VOID
1220 DiskClassUpdatePartitionDeviceObjects(IN PDEVICE_OBJECT DiskDeviceObject,
1221                                       IN PIRP Irp)
1222 {
1223   PDRIVE_LAYOUT_INFORMATION PartitionList;
1224   PPARTITION_INFORMATION PartitionEntry;
1225   PDEVICE_EXTENSION DeviceExtension;
1226   PDEVICE_EXTENSION DiskDeviceExtension;
1227   PDISK_DATA DiskData;
1228   ULONG PartitionCount;
1229   ULONG PartitionOrdinal;
1230   ULONG PartitionNumber;
1231   ULONG LastPartitionNumber;
1232   ULONG i;
1233   BOOLEAN Found;
1234   WCHAR NameBuffer[MAX_PATH];
1235   UNICODE_STRING DeviceName;
1236   PDEVICE_OBJECT DeviceObject;
1237   NTSTATUS Status;
1238
1239   DPRINT("ScsiDiskUpdatePartitionDeviceObjects() called\n");
1240
1241   /* Get partition list */
1242   PartitionList = Irp->AssociatedIrp.SystemBuffer;
1243
1244   /* Round partition count up by 4 */
1245   PartitionCount = ((PartitionList->PartitionCount + 3) / 4) * 4;
1246
1247   /* Remove the partition numbers from the partition list */
1248   for (i = 0; i < PartitionCount; i++)
1249     {
1250       PartitionList->PartitionEntry[i].PartitionNumber = 0;
1251     }
1252
1253   DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
1254
1255   /* Traverse on-disk partition list */
1256   LastPartitionNumber = 0;
1257   DeviceExtension = DiskDeviceExtension;
1258   DiskData = (PDISK_DATA)(DeviceExtension + 1);
1259   while (TRUE)
1260     {
1261       DeviceExtension = DiskData->NextPartition;
1262       if (DeviceExtension == NULL)
1263         break;
1264
1265       /* Get disk data */
1266       DiskData = (PDISK_DATA)(DeviceExtension + 1);
1267
1268       /* Update last partition number */
1269       if (DiskData->PartitionNumber > LastPartitionNumber)
1270         LastPartitionNumber = DiskData->PartitionNumber;
1271
1272       /* Ignore unused on-disk partitions */
1273       if (DeviceExtension->PartitionLength.QuadPart == 0ULL)
1274         continue;
1275
1276       Found = FALSE;
1277       PartitionOrdinal = 0;
1278       for (i = 0; i < PartitionCount; i++)
1279         {
1280           /* Get current partition entry */
1281           PartitionEntry = &PartitionList->PartitionEntry[i];
1282
1283           /* Ignore empty (aka unused) or extended partitions */
1284           if (PartitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
1285               IsContainerPartition (PartitionEntry->PartitionType))
1286             continue;
1287
1288           PartitionOrdinal++;
1289
1290           /* Check for matching partition start offset and length */
1291           if ((PartitionEntry->StartingOffset.QuadPart !=
1292                DeviceExtension->StartingOffset.QuadPart) ||
1293               (PartitionEntry->PartitionLength.QuadPart !=
1294                DeviceExtension->PartitionLength.QuadPart))
1295             continue;
1296
1297           DPRINT1("Found matching partition entry for partition %lu\n",
1298                   DiskData->PartitionNumber);
1299
1300           /* Found matching partition */
1301           Found = TRUE;
1302
1303           /* Update partition number in partition list */
1304           PartitionEntry->PartitionNumber = DiskData->PartitionNumber;
1305           break;
1306         }
1307
1308       if (Found == TRUE)
1309         {
1310           /* Get disk data for current partition */
1311           DiskData = (PDISK_DATA)(DeviceExtension + 1);
1312
1313           /* Update partition type if partiton will be rewritten */
1314           if (PartitionEntry->RewritePartition == TRUE)
1315             DiskData->PartitionType = PartitionEntry->PartitionType;
1316
1317           /* Assign new partiton ordinal */
1318           DiskData->PartitionOrdinal = PartitionOrdinal;
1319
1320           DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1321                  DiskData->PartitionOrdinal,
1322                  DiskData->PartitionNumber);
1323         }
1324       else
1325         {
1326           /* Delete this partition */
1327           DeviceExtension->PartitionLength.QuadPart = 0ULL;
1328
1329           DPRINT("Deleting partition %lu\n",
1330                  DiskData->PartitionNumber);
1331         }
1332     }
1333
1334   /* Traverse partiton list and create new partiton devices */
1335   PartitionOrdinal = 0;
1336   for (i = 0; i < PartitionCount; i++)
1337     {
1338       /* Get current partition entry */
1339       PartitionEntry = &PartitionList->PartitionEntry[i];
1340
1341       /* Ignore empty (aka unused) or extended partitions */
1342       if (PartitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
1343           IsContainerPartition (PartitionEntry->PartitionType))
1344         continue;
1345
1346       PartitionOrdinal++;
1347
1348       /* Ignore unchanged partition entries */
1349       if (PartitionEntry->RewritePartition == FALSE)
1350         continue;
1351
1352       /* Check for an unused device object */
1353       PartitionNumber = 0;
1354       DeviceExtension = DiskDeviceExtension;
1355       DiskData = (PDISK_DATA)(DeviceExtension + 1);
1356       while (TRUE)
1357         {
1358           DeviceExtension = DiskData->NextPartition;
1359           if (DeviceExtension == NULL)
1360             break;
1361
1362           /* Get partition disk data */
1363           DiskData = (PDISK_DATA)(DeviceExtension + 1);
1364
1365           /* Found a free (unused) partition (device object) */
1366           if (DeviceExtension->PartitionLength.QuadPart == 0ULL)
1367             {
1368               PartitionNumber = DiskData->PartitionNumber;
1369               break;
1370             }
1371         }
1372
1373       if (PartitionNumber == 0)
1374         {
1375           /* Create a new partition device object */
1376           DPRINT("Create new partition device object\n");
1377
1378           /* Get new partiton number */
1379           LastPartitionNumber++;
1380           PartitionNumber = LastPartitionNumber;
1381
1382           /* Create partition device object */
1383           swprintf(NameBuffer,
1384                    L"\\Device\\Harddisk%lu\\Partition%lu",
1385                    DiskDeviceExtension->DeviceNumber,
1386                    PartitionNumber);
1387           RtlInitUnicodeString(&DeviceName,
1388                                NameBuffer);
1389
1390           Status = IoCreateDevice(DiskDeviceObject->DriverObject,
1391                                   sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA),
1392                                   &DeviceName,
1393                                   FILE_DEVICE_DISK,
1394                                   0,
1395                                   FALSE,
1396                                   &DeviceObject);
1397           if (!NT_SUCCESS(Status))
1398             {
1399               DPRINT1("IoCreateDevice() failed (Status %lx)\n", Status);
1400               continue;
1401             }
1402
1403           DeviceObject->Flags |= DO_DIRECT_IO;
1404           DeviceObject->StackSize = DiskDeviceObject->StackSize;
1405           DeviceObject->Characteristics = DiskDeviceObject->Characteristics;
1406           DeviceObject->AlignmentRequirement = DiskDeviceObject->AlignmentRequirement;
1407
1408           /* Initialize device extension */
1409           DeviceExtension = DeviceObject->DeviceExtension;
1410           RtlCopyMemory(DeviceExtension,
1411                         DiskDeviceObject->DeviceExtension,
1412                         sizeof(DEVICE_EXTENSION));
1413           DeviceExtension->DeviceObject = DeviceObject;
1414
1415           /* Initialize lookaside list for SRBs */
1416           ScsiClassInitializeSrbLookasideList(DeviceExtension,
1417                                               8);
1418
1419           /* Link current partition device extension to previous disk data */
1420           DiskData->NextPartition = DeviceExtension;
1421           DiskData = (PDISK_DATA)(DeviceExtension + 1);
1422           DiskData->NextPartition = NULL;
1423         }
1424       else
1425         {
1426           /* Reuse an existing partition device object */
1427           DPRINT("Reuse an exisiting partition device object\n");
1428           DiskData = (PDISK_DATA)(DeviceExtension + 1);
1429         }
1430
1431       /* Update partition data and device extension */
1432       DiskData->PartitionNumber = PartitionNumber;
1433       DiskData->PartitionOrdinal = PartitionOrdinal;
1434       DiskData->PartitionType = PartitionEntry->PartitionType;
1435       DiskData->BootIndicator = PartitionEntry->BootIndicator;
1436       DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
1437       DeviceExtension->StartingOffset = PartitionEntry->StartingOffset;
1438       DeviceExtension->PartitionLength = PartitionEntry->PartitionLength;
1439
1440       /* Update partition number in the partition list */
1441       PartitionEntry->PartitionNumber = PartitionNumber;
1442
1443       DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1444              DiskData->PartitionOrdinal,
1445              DiskData->PartitionNumber);
1446     }
1447
1448   DPRINT("ScsiDiskUpdatePartitionDeviceObjects() done\n");
1449 }
1450
1451
1452 /**********************************************************************
1453  * NAME                                                 INTERNAL
1454  *      ScsiDiskSearchForDisk
1455  *
1456  * DESCRIPTION
1457  *      Searches the hardware tree for the given disk.
1458  *
1459  * RUN LEVEL
1460  *      PASSIVE_LEVEL
1461  *
1462  * ARGUMENTS
1463  *      DeviceExtension
1464  *              Disk device extension.
1465  *
1466  *      BusKey
1467  *              Handle to the hardware bus key.
1468  *
1469  *      DetectedDiskNumber
1470  *              Returned disk number.
1471  *
1472  * RETURN VALUE
1473  *      TRUE: Disk was found.
1474  *      FALSE: Search failed.
1475  */
1476
1477 static BOOLEAN
1478 ScsiDiskSearchForDisk(IN PDEVICE_EXTENSION DeviceExtension,
1479                       IN HANDLE BusKey,
1480                       OUT PULONG DetectedDiskNumber)
1481 {
1482   PKEY_VALUE_FULL_INFORMATION ValueData;
1483   OBJECT_ATTRIBUTES ObjectAttributes;
1484   PDISK_DATA DiskData;
1485   UNICODE_STRING IdentifierString;
1486   UNICODE_STRING NameString;
1487   HANDLE BusInstanceKey;
1488   HANDLE ControllerKey;
1489   HANDLE DiskKey;
1490   HANDLE DiskInstanceKey;
1491   ULONG BusNumber;
1492   ULONG ControllerNumber;
1493   ULONG DiskNumber;
1494   ULONG Length;
1495   WCHAR Buffer[32];
1496   BOOLEAN DiskFound;
1497   NTSTATUS Status;
1498
1499   DPRINT("ScsiDiskSearchForDiskData() called\n");
1500
1501   DiskFound = FALSE;
1502
1503   /* Enumerate buses */
1504   for (BusNumber = 0; ; BusNumber++)
1505     {
1506       /* Open bus instance subkey */
1507       swprintf(Buffer,
1508                L"%lu",
1509                BusNumber);
1510
1511       RtlInitUnicodeString(&NameString,
1512                            Buffer);
1513
1514       InitializeObjectAttributes(&ObjectAttributes,
1515                                  &NameString,
1516                                  OBJ_CASE_INSENSITIVE,
1517                                  BusKey,
1518                                  NULL);
1519
1520       Status = ZwOpenKey(&BusInstanceKey,
1521                          KEY_READ,
1522                          &ObjectAttributes);
1523       if (!NT_SUCCESS(Status))
1524         {
1525           break;
1526         }
1527
1528       /* Open 'DiskController' subkey */
1529       RtlInitUnicodeString(&NameString,
1530                            L"DiskController");
1531
1532       InitializeObjectAttributes(&ObjectAttributes,
1533                                  &NameString,
1534                                  OBJ_CASE_INSENSITIVE,
1535                                  BusInstanceKey,
1536                                  NULL);
1537
1538       Status = ZwOpenKey(&ControllerKey,
1539                          KEY_READ,
1540                          &ObjectAttributes);
1541       if (!NT_SUCCESS(Status))
1542         {
1543           ZwClose(BusInstanceKey);
1544           continue;
1545         }
1546
1547       /* Enumerate controllers */
1548       for (ControllerNumber = 0; ; ControllerNumber++)
1549         {
1550           /* Open 'DiskPeripheral' subkey */
1551           swprintf(Buffer,
1552                    L"%lu\\DiskPeripheral",
1553                    ControllerNumber);
1554
1555           RtlInitUnicodeString(&NameString,
1556                                Buffer);
1557
1558           InitializeObjectAttributes(&ObjectAttributes,
1559                                      &NameString,
1560                                      OBJ_CASE_INSENSITIVE,
1561                                      ControllerKey,
1562                                      NULL);
1563
1564           Status = ZwOpenKey(&DiskKey,
1565                              KEY_READ,
1566                              &ObjectAttributes);
1567           if (!NT_SUCCESS(Status))
1568             {
1569               break;
1570             }
1571
1572           /* Enumerate disks */
1573           for (DiskNumber = 0; ; DiskNumber++)
1574             {
1575               /* Open disk instance subkey */
1576               swprintf(Buffer,
1577                        L"%lu",
1578                        DiskNumber);
1579
1580               RtlInitUnicodeString(&NameString,
1581                                    Buffer);
1582
1583               InitializeObjectAttributes(&ObjectAttributes,
1584                                          &NameString,
1585                                          OBJ_CASE_INSENSITIVE,
1586                                          DiskKey,
1587                                          NULL);
1588
1589               Status = ZwOpenKey(&DiskInstanceKey,
1590                                  KEY_READ,
1591                                  &ObjectAttributes);
1592               if (!NT_SUCCESS(Status))
1593                 {
1594                   break;
1595                 }
1596
1597               DPRINT("Found disk key: bus %lu  controller %lu  disk %lu\n",
1598                      BusNumber,
1599                      ControllerNumber,
1600                      DiskNumber);
1601
1602               /* Allocate data buffer */
1603               ValueData = ExAllocatePool(PagedPool,
1604                                          2048);
1605               if (ValueData == NULL)
1606                 {
1607                   ZwClose(DiskInstanceKey);
1608                   continue;
1609                 }
1610
1611               /* Get the 'Identifier' value */
1612               RtlInitUnicodeString(&NameString,
1613                                    L"Identifier");
1614               Status = ZwQueryValueKey(DiskInstanceKey,
1615                                        &NameString,
1616                                        KeyValueFullInformation,
1617                                        ValueData,
1618                                        2048,
1619                                        &Length);
1620
1621               ZwClose(DiskInstanceKey);
1622               if (!NT_SUCCESS(Status))
1623                 {
1624                   ExFreePool(ValueData);
1625                   continue;
1626                 }
1627
1628               IdentifierString.Buffer =
1629                 (PWSTR)((PUCHAR)ValueData + ValueData->DataOffset);
1630               IdentifierString.Length = (USHORT)ValueData->DataLength - 2;
1631               IdentifierString.MaximumLength = (USHORT)ValueData->DataLength;
1632
1633               DPRINT("DiskIdentifier: %wZ\n",
1634                      &IdentifierString);
1635
1636               DiskData = (PDISK_DATA)(DeviceExtension + 1);
1637               if (DiskData->Signature != 0)
1638                 {
1639                   /* Comapre disk signature */
1640                   swprintf(Buffer,
1641                            L"%08lx",
1642                            DiskData->Signature);
1643                   if (!_wcsnicmp(Buffer, &IdentifierString.Buffer[9], 8))
1644                     {
1645                       DPRINT("Found disk %lu\n", DiskNumber);
1646                       DiskFound = TRUE;
1647                       *DetectedDiskNumber = DiskNumber;
1648                     }
1649                 }
1650               else
1651                 {
1652                   /* Comapre mbr checksum */
1653                   swprintf(Buffer,
1654                            L"%08lx",
1655                            DiskData->MbrCheckSum);
1656                   if (!_wcsnicmp(Buffer, &IdentifierString.Buffer[0], 8))
1657                     {
1658                       DPRINT("Found disk %lu\n", DiskNumber);
1659                       DiskFound = TRUE;
1660                       *DetectedDiskNumber = DiskNumber;
1661                     }
1662                 }
1663
1664               ExFreePool(ValueData);
1665
1666               ZwClose(DiskInstanceKey);
1667
1668               if (DiskFound == TRUE)
1669                 break;
1670             }
1671
1672           ZwClose(DiskKey);
1673         }
1674
1675       ZwClose(ControllerKey);
1676       ZwClose(BusInstanceKey);
1677     }
1678
1679   DPRINT("ScsiDiskSearchForDisk() done\n");
1680
1681   return DiskFound;
1682 }
1683
1684
1685 /**********************************************************************
1686  * NAME                                                 INTERNAL
1687  *      DiskClassUpdateFixedDiskGeometry
1688  *
1689  * DESCRIPTION
1690  *      Updated the geometry of a disk if the disk can be accessed
1691  *      by the BIOS.
1692  *
1693  * RUN LEVEL
1694  *      PASSIVE_LEVEL
1695  *
1696  * ARGUMENTS
1697  *      DeviceExtension
1698  *              Disk device extension.
1699  *
1700  * RETURN VALUE
1701  *      None
1702  */
1703
1704 static VOID
1705 ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension)
1706 {
1707   PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor;
1708   PCM_INT13_DRIVE_PARAMETER DriveParameters;
1709   PKEY_VALUE_FULL_INFORMATION ValueBuffer;
1710   OBJECT_ATTRIBUTES ObjectAttributes;
1711   UNICODE_STRING KeyName;
1712   UNICODE_STRING ValueName;
1713   HANDLE SystemKey;
1714   HANDLE BusKey;
1715   ULONG DiskNumber;
1716   ULONG Length;
1717   ULONG i;
1718   ULONG Cylinders;
1719   ULONG Sectors;
1720   ULONG SectorsPerTrack;
1721   ULONG TracksPerCylinder;
1722   NTSTATUS Status;
1723
1724   DPRINT("ScsiDiskUpdateFixedDiskGeometry() called\n");
1725
1726   RtlInitUnicodeString(&KeyName,
1727                        L"\\Registry\\Machine\\Hardware\\Description\\System");
1728
1729   InitializeObjectAttributes(&ObjectAttributes,
1730                              &KeyName,
1731                              OBJ_CASE_INSENSITIVE,
1732                              NULL,
1733                              NULL);
1734
1735   /* Open the adapter key */
1736   Status = ZwOpenKey(&SystemKey,
1737                      KEY_READ,
1738                      &ObjectAttributes);
1739   if (!NT_SUCCESS(Status))
1740     {
1741       DPRINT("ZwOpenKey() failed (Status %lx)\n", Status);
1742       return;
1743     }
1744
1745   /* Allocate value buffer */
1746   ValueBuffer = ExAllocatePool(PagedPool,
1747                                1024);
1748   if (ValueBuffer == NULL)
1749     {
1750       DPRINT1("Failed to allocate value buffer\n");
1751       ZwClose(SystemKey);
1752       return;
1753     }
1754
1755   RtlInitUnicodeString(&ValueName,
1756                        L"Configuration Data");
1757
1758   /* Query 'Configuration Data' value */
1759   Status = ZwQueryValueKey(SystemKey,
1760                            &ValueName,
1761                            KeyValueFullInformation,
1762                            ValueBuffer,
1763                            1024,
1764                            &Length);
1765   if (!NT_SUCCESS(Status))
1766     {
1767       DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status);
1768       ExFreePool(ValueBuffer);
1769       ZwClose(SystemKey);
1770       return;
1771     }
1772
1773   /* Open the 'MultifunctionAdapter' subkey */
1774   RtlInitUnicodeString(&KeyName,
1775                        L"MultifunctionAdapter");
1776
1777   InitializeObjectAttributes(&ObjectAttributes,
1778                              &KeyName,
1779                              OBJ_CASE_INSENSITIVE,
1780                              SystemKey,
1781                              NULL);
1782
1783   Status = ZwOpenKey(&BusKey,
1784                      KEY_READ,
1785                      &ObjectAttributes);
1786   ZwClose(SystemKey);
1787   if (!NT_SUCCESS(Status))
1788     {
1789       DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status);
1790       ExFreePool(ValueBuffer);
1791       return;
1792     }
1793
1794   if (!ScsiDiskSearchForDisk(DeviceExtension, BusKey, &DiskNumber))
1795     {
1796       DPRINT("ScsiDiskSearchForDisk() failed\n");
1797       ZwClose(BusKey);
1798       ExFreePool(ValueBuffer);
1799       return;
1800     }
1801
1802   ZwClose(BusKey);
1803
1804   ResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
1805     ((PUCHAR)ValueBuffer + ValueBuffer->DataOffset);
1806
1807   DriveParameters = (PCM_INT13_DRIVE_PARAMETER)
1808     ((PUCHAR)ResourceDescriptor + sizeof(CM_FULL_RESOURCE_DESCRIPTOR));
1809
1810 #if 0
1811   for (i = 0; i< DriveParameters[0].NumberDrives; i++)
1812     {
1813       DPRINT1("Drive %lu: %lu Cylinders  %hu Heads  %hu Sectors\n",
1814               i,
1815               DriveParameters[i].MaxCylinders,
1816               DriveParameters[i].MaxHeads,
1817               DriveParameters[i].SectorsPerTrack);
1818     }
1819 #endif
1820
1821   Cylinders = DriveParameters[DiskNumber].MaxCylinders + 1;
1822   TracksPerCylinder = DriveParameters[DiskNumber].MaxHeads +1;
1823   SectorsPerTrack = DriveParameters[DiskNumber].SectorsPerTrack;
1824
1825   DPRINT("BIOS geometry: %lu Cylinders  %hu Heads  %hu Sectors\n",
1826          Cylinders,
1827          TracksPerCylinder,
1828          SectorsPerTrack);
1829
1830   Sectors = (ULONG)
1831     (DeviceExtension->PartitionLength.QuadPart >> DeviceExtension->SectorShift);
1832
1833   DPRINT("Physical sectors: %lu\n",
1834          Sectors);
1835
1836   Length = TracksPerCylinder * SectorsPerTrack;
1837   if (Length == 0)
1838     {
1839       DPRINT1("Invalid track length 0\n");
1840       ExFreePool(ValueBuffer);
1841       return;
1842     }
1843
1844   Cylinders = Sectors / Length;
1845
1846   DPRINT("Logical geometry: %lu Cylinders  %hu Heads  %hu Sectors\n",
1847          Cylinders,
1848          TracksPerCylinder,
1849          SectorsPerTrack);
1850
1851   /* Update the disk geometry */
1852   DeviceExtension->DiskGeometry->SectorsPerTrack = SectorsPerTrack;
1853   DeviceExtension->DiskGeometry->TracksPerCylinder = TracksPerCylinder;
1854   DeviceExtension->DiskGeometry->Cylinders.QuadPart = (ULONGLONG)Cylinders;
1855
1856   if (DeviceExtension->DMActive)
1857     {
1858       DPRINT1("FIXME: Update geometry with respect to the installed disk manager!\n");
1859
1860       /* FIXME: Update geometry for disk managers */
1861
1862     }
1863
1864   ExFreePool(ValueBuffer);
1865
1866   DPRINT("ScsiDiskUpdateFixedDiskGeometry() done\n");
1867 }
1868
1869
1870 /**********************************************************************
1871  * NAME                                                 INTERNAL
1872  *      ScsiDiskCalcMbrCheckSum
1873  *
1874  * DESCRIPTION
1875  *      Calculates the Checksum from drives MBR.
1876  *
1877  * RUN LEVEL
1878  *      PASSIVE_LEVEL
1879  *
1880  * ARGUMENTS
1881  *      DeviceExtension
1882  *              Disk device extension.
1883  *
1884  *      Checksum
1885  *              Pointer to the caller supplied cecksum variable.
1886  *
1887  * RETURN VALUE
1888  *      TRUE: Checksum was calculated.
1889  *      FALSE: Calculation failed.
1890  */
1891
1892 static BOOLEAN
1893 ScsiDiskCalcMbrCheckSum(IN PDEVICE_EXTENSION DeviceExtension,
1894                         OUT PULONG Checksum)
1895 {
1896   IO_STATUS_BLOCK IoStatusBlock;
1897   LARGE_INTEGER SectorOffset;
1898   ULONG SectorSize;
1899   PULONG MbrBuffer;
1900   KEVENT Event;
1901   PIRP Irp;
1902   ULONG i;
1903   ULONG Sum;
1904   NTSTATUS Status;
1905
1906   KeInitializeEvent(&Event,
1907                     NotificationEvent,
1908                     FALSE);
1909
1910   /* Get the disk sector size */
1911   SectorSize = DeviceExtension->DiskGeometry->BytesPerSector;
1912   if (SectorSize < 512)
1913     {
1914       SectorSize = 512;
1915     }
1916
1917   /* Allocate MBR buffer */
1918   MbrBuffer = ExAllocatePool(NonPagedPool,
1919                              SectorSize);
1920   if (MbrBuffer == NULL)
1921     {
1922       return FALSE;
1923     }
1924
1925   /* Allocate an IRP */
1926   SectorOffset.QuadPart = 0ULL;
1927   Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
1928                                      DeviceExtension->DeviceObject,
1929                                      MbrBuffer,
1930                                      SectorSize,
1931                                      &SectorOffset,
1932                                      &Event,
1933                                      &IoStatusBlock);
1934   if (Irp == NULL)
1935     {
1936       ExFreePool(MbrBuffer);
1937       return FALSE;
1938     }
1939
1940   /* Call the miniport driver */
1941   Status = IoCallDriver(DeviceExtension->DeviceObject,
1942                         Irp);
1943   if (Status == STATUS_PENDING)
1944     {
1945       KeWaitForSingleObject(&Event,
1946                             Suspended,
1947                             KernelMode,
1948                             FALSE,
1949                             NULL);
1950       Status = IoStatusBlock.Status;
1951     }
1952
1953   if (!NT_SUCCESS(Status))
1954     {
1955       ExFreePool(MbrBuffer);
1956       return FALSE;
1957     }
1958
1959   /* Calculate MBR checksum */
1960   Sum = 0;
1961   for (i = 0; i < 128; i++)
1962     {
1963       Sum += MbrBuffer[i];
1964     }
1965   *Checksum = ~Sum + 1;
1966
1967   ExFreePool(MbrBuffer);
1968
1969   return TRUE;
1970 }
1971
1972 /* EOF */