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