update for HEAD-2003021201
[reactos.git] / drivers / storage / disk / disk.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2001, 2002 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   ULONG HiddenSectors;
44   ULONG PartitionNumber;
45   ULONG PartitionOrdinal;
46   UCHAR PartitionType;
47   BOOLEAN BootIndicator;
48   BOOLEAN DriveNotReady;
49 } DISK_DATA, *PDISK_DATA;
50
51
52 BOOLEAN STDCALL
53 DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
54                      PUNICODE_STRING RegistryPath,
55                      PCLASS_INIT_DATA InitializationData,
56                      PDEVICE_OBJECT PortDeviceObject,
57                      ULONG PortNumber);
58
59 BOOLEAN STDCALL
60 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData);
61
62 NTSTATUS STDCALL
63 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
64                         IN PIRP Irp);
65
66
67 static NTSTATUS
68 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
69                             IN PUNICODE_STRING RegistryPath, /* what's this used for? */
70                             IN PDEVICE_OBJECT PortDeviceObject,
71                             IN ULONG PortNumber,
72                             IN ULONG DiskNumber,
73                             IN PIO_SCSI_CAPABILITIES Capabilities,
74                             IN PSCSI_INQUIRY_DATA InquiryData,
75                             IN PCLASS_INIT_DATA InitializationData);
76
77 NTSTATUS STDCALL
78 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
79                        IN PIRP Irp);
80
81 NTSTATUS STDCALL
82 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
83                        IN PIRP Irp);
84
85
86
87 /* FUNCTIONS ****************************************************************/
88
89 //    DriverEntry
90 //
91 //  DESCRIPTION:
92 //    This function initializes the driver, locates and claims 
93 //    hardware resources, and creates various NT objects needed
94 //    to process I/O requests.
95 //
96 //  RUN LEVEL:
97 //    PASSIVE_LEVEL
98 //
99 //  ARGUMENTS:
100 //    IN  PDRIVER_OBJECT   DriverObject  System allocated Driver Object
101 //                                       for this driver
102 //    IN  PUNICODE_STRING  RegistryPath  Name of registry driver service 
103 //                                       key
104 //
105 //  RETURNS:
106 //    NTSTATUS
107
108 NTSTATUS STDCALL
109 DriverEntry(IN PDRIVER_OBJECT DriverObject,
110             IN PUNICODE_STRING RegistryPath)
111 {
112   CLASS_INIT_DATA InitData;
113
114   DPRINT("Disk Class Driver %s\n",
115          VERSION);
116   DPRINT("RegistryPath '%wZ'\n",
117          RegistryPath);
118
119   RtlZeroMemory(&InitData,
120                 sizeof(CLASS_INIT_DATA));
121
122   InitData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
123   InitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA);
124   InitData.DeviceType = FILE_DEVICE_DISK;
125   InitData.DeviceCharacteristics = 0;
126
127   InitData.ClassError = NULL;   // DiskClassProcessError;
128   InitData.ClassReadWriteVerification = DiskClassCheckReadWrite;
129   InitData.ClassFindDeviceCallBack = DiskClassCheckDevice;
130   InitData.ClassFindDevices = DiskClassFindDevices;
131   InitData.ClassDeviceControl = DiskClassDeviceControl;
132   InitData.ClassShutdownFlush = DiskClassShutdownFlush;
133   InitData.ClassCreateClose = NULL;
134   InitData.ClassStartIo = NULL;
135
136   return(ScsiClassInitialize(DriverObject,
137                              RegistryPath,
138                              &InitData));
139 }
140
141
142 /**********************************************************************
143  * NAME                                                 EXPORTED
144  *      DiskClassFindDevices
145  *
146  * DESCRIPTION
147  *      This function searches for device that are attached to the
148  *      given scsi port.
149  *
150  * RUN LEVEL
151  *      PASSIVE_LEVEL
152  *
153  * ARGUMENTS
154  *      DriverObject
155  *              System allocated Driver Object for this driver
156  *
157  *      RegistryPath
158  *              Name of registry driver service key
159  *
160  *      InitializationData
161  *              Pointer to the main initialization data
162  *
163  *      PortDeviceObject
164  *              Pointer to the port Device Object
165  *
166  *      PortNumber
167  *              Port number
168  *
169  * RETURN VALUE
170  *      TRUE: At least one disk drive was found
171  *      FALSE: No disk drive found
172  */
173
174 BOOLEAN STDCALL
175 DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
176                      PUNICODE_STRING RegistryPath,
177                      PCLASS_INIT_DATA InitializationData,
178                      PDEVICE_OBJECT PortDeviceObject,
179                      ULONG PortNumber)
180 {
181   PCONFIGURATION_INFORMATION ConfigInfo;
182   PIO_SCSI_CAPABILITIES PortCapabilities;
183   PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
184   PSCSI_INQUIRY_DATA UnitInfo;
185   PINQUIRYDATA InquiryData;
186   PCHAR Buffer;
187   ULONG Bus;
188   ULONG DeviceCount;
189   BOOLEAN FoundDevice;
190   NTSTATUS Status;
191
192   DPRINT("DiskClassFindDevices() called.\n");
193
194   /* Get port capabilities */
195   Status = ScsiClassGetCapabilities(PortDeviceObject,
196                                     &PortCapabilities);
197   if (!NT_SUCCESS(Status))
198     {
199       DPRINT("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status);
200       return(FALSE);
201     }
202
203   DPRINT("PortCapabilities: %p\n", PortCapabilities);
204   DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
205   DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities->MaximumPhysicalPages);
206
207   /* Get inquiry data */
208   Status = ScsiClassGetInquiryData(PortDeviceObject,
209                                    (PSCSI_ADAPTER_BUS_INFO *)&Buffer);
210   if (!NT_SUCCESS(Status))
211     {
212       DPRINT("ScsiClassGetInquiryData() failed! (Status %x)\n", Status);
213       return(FALSE);
214     }
215
216   /* Check whether there are unclaimed devices */
217   AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
218   DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
219                                               AdapterBusInfo);
220   if (DeviceCount == 0)
221     {
222       DPRINT("No unclaimed devices!\n");
223       return(FALSE);
224     }
225
226   DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
227
228   ConfigInfo = IoGetConfigurationInformation();
229
230   /* Search each bus of this adapter */
231   for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
232     {
233       DPRINT("Searching bus %lu\n", Bus);
234
235       UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
236
237       while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
238         {
239           InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
240
241           if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
242                (InquiryData->DeviceType == OPTICAL_DEVICE)) &&
243               (InquiryData->DeviceTypeQualifier == 0) &&
244               (UnitInfo->DeviceClaimed == FALSE))
245             {
246               DPRINT("Vendor: '%.24s'\n",
247                      InquiryData->VendorId);
248
249               /* Create device objects for disk */
250               Status = DiskClassCreateDeviceObject(DriverObject,
251                                                    RegistryPath,
252                                                    PortDeviceObject,
253                                                    PortNumber,
254                                                    ConfigInfo->DiskCount,
255                                                    PortCapabilities,
256                                                    UnitInfo,
257                                                    InitializationData);
258               if (NT_SUCCESS(Status))
259                 {
260                   ConfigInfo->DiskCount++;
261                   FoundDevice = TRUE;
262                 }
263             }
264
265           if (UnitInfo->NextInquiryDataOffset == 0)
266             break;
267
268           UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
269         }
270     }
271
272   ExFreePool(Buffer);
273
274   DPRINT("DiskClassFindDevices() done\n");
275
276   return(FoundDevice);
277 }
278
279
280 /**********************************************************************
281  * NAME                                                 EXPORTED
282  *      DiskClassCheckDevice
283  *
284  * DESCRIPTION
285  *      This function checks the InquiryData for the correct device
286  *      type and qualifier.
287  *
288  * RUN LEVEL
289  *      PASSIVE_LEVEL
290  *
291  * ARGUMENTS
292  *      InquiryData
293  *              Pointer to the inquiry data for the device in question.
294  *
295  * RETURN VALUE
296  *      TRUE: A disk device was found.
297  *      FALSE: Otherwise.
298  */
299
300 BOOLEAN STDCALL
301 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData)
302 {
303   return((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE ||
304           InquiryData->DeviceType == OPTICAL_DEVICE) &&
305          InquiryData->DeviceTypeQualifier == 0);
306 }
307
308
309 /**********************************************************************
310  * NAME                                                 EXPORTED
311  *      DiskClassCheckReadWrite
312  *
313  * DESCRIPTION
314  *      This function checks the given IRP for correct data.
315  *
316  * RUN LEVEL
317  *      PASSIVE_LEVEL
318  *
319  * ARGUMENTS
320  *      DeviceObject
321  *              Pointer to the device.
322  *
323  *      Irp
324  *              Irp to check.
325  *
326  * RETURN VALUE
327  *      STATUS_SUCCESS: The IRP matches the requirements of the given device.
328  *      Others: Failure.
329  */
330
331 NTSTATUS STDCALL
332 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
333                         IN PIRP Irp)
334 {
335   PDEVICE_EXTENSION DeviceExtension;
336   PDISK_DATA DiskData;
337
338   DPRINT("DiskClassCheckReadWrite() called\n");
339
340   DeviceExtension = DeviceObject->DeviceExtension;
341   DiskData = (PDISK_DATA)(DeviceExtension + 1);
342
343   if (DiskData->DriveNotReady == TRUE)
344     {
345       Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
346       IoSetHardErrorOrVerifyDevice(Irp,
347                                    DeviceObject);
348       return(STATUS_INVALID_PARAMETER);
349     }
350
351   return(STATUS_SUCCESS);
352 }
353
354
355 /**********************************************************************
356  * NAME                                                 EXPORTED
357  *      DiskClassCreateDeviceObject
358  *
359  * DESCRIPTION
360  *      Create the raw device and any partition devices on this drive
361  *
362  * RUN LEVEL
363  *      PASSIVE_LEVEL
364  *
365  * ARGUMENTS
366  *      DriverObject
367  *              The system created driver object
368  *      RegistryPath
369  *      PortDeviceObject
370  *      PortNumber
371  *      DiskNumber
372  *      Capabilities
373  *      InquiryData
374  *      InitialzationData
375  *
376  * RETURN VALUE
377  *      STATUS_SUCCESS: Device objects for disk and partitions were created.
378  *      Others: Failure.
379  */
380
381 static NTSTATUS
382 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
383                             IN PUNICODE_STRING RegistryPath, /* what's this used for? */
384                             IN PDEVICE_OBJECT PortDeviceObject,
385                             IN ULONG PortNumber,
386                             IN ULONG DiskNumber,
387                             IN PIO_SCSI_CAPABILITIES Capabilities,
388                             IN PSCSI_INQUIRY_DATA InquiryData,
389                             IN PCLASS_INIT_DATA InitializationData)
390 {
391   OBJECT_ATTRIBUTES ObjectAttributes;
392   UNICODE_STRING UnicodeDeviceDirName;
393   WCHAR NameBuffer[80];
394   CHAR NameBuffer2[80];
395   PDEVICE_OBJECT DiskDeviceObject;
396   PDEVICE_OBJECT PartitionDeviceObject;
397   PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
398   PDEVICE_EXTENSION PartitionDeviceExtension; /* defined in class2.h */
399   PDRIVE_LAYOUT_INFORMATION PartitionList = NULL;
400   HANDLE Handle;
401   PPARTITION_INFORMATION PartitionEntry;
402   PDISK_DATA DiskData;
403   ULONG PartitionNumber;
404   NTSTATUS Status;
405
406   DPRINT("DiskClassCreateDeviceObject() called\n");
407
408   /* Create the harddisk device directory */
409   swprintf(NameBuffer,
410            L"\\Device\\Harddisk%lu",
411            DiskNumber);
412   RtlInitUnicodeString(&UnicodeDeviceDirName,
413                        NameBuffer);
414   InitializeObjectAttributes(&ObjectAttributes,
415                              &UnicodeDeviceDirName,
416                              0,
417                              NULL,
418                              NULL);
419   Status = ZwCreateDirectoryObject(&Handle,
420                                    0,
421                                    &ObjectAttributes);
422   if (!NT_SUCCESS(Status))
423     {
424       DbgPrint("Could not create device dir object\n");
425       return(Status);
426     }
427
428   /* Claim the disk device */
429   Status = ScsiClassClaimDevice(PortDeviceObject,
430                                 InquiryData,
431                                 FALSE,
432                                 &PortDeviceObject);
433   if (!NT_SUCCESS(Status))
434     {
435       DbgPrint("Could not claim disk device\n");
436
437       ZwMakeTemporaryObject(Handle);
438       ZwClose(Handle);
439
440       return(Status);
441     }
442
443   /* Create disk device (Partition 0) */
444   sprintf(NameBuffer2,
445           "\\Device\\Harddisk%lu\\Partition0",
446           DiskNumber);
447
448   Status = ScsiClassCreateDeviceObject(DriverObject,
449                                        NameBuffer2,
450                                        NULL,
451                                        &DiskDeviceObject,
452                                        InitializationData);
453   if (!NT_SUCCESS(Status))
454     {
455       DPRINT("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
456
457       /* Release (unclaim) the disk */
458       ScsiClassClaimDevice(PortDeviceObject,
459                            InquiryData,
460                            TRUE,
461                            NULL);
462
463       /* Delete the harddisk device directory */
464       ZwMakeTemporaryObject(Handle);
465       ZwClose(Handle);
466
467       return(Status);
468     }
469
470   DiskDeviceObject->Flags |= DO_DIRECT_IO;
471   if (((PINQUIRYDATA)InquiryData->InquiryData)->RemovableMedia)
472     {
473       DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
474     }
475   DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
476
477   if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
478     {
479       DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
480     }
481
482   DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
483   DiskDeviceExtension->LockCount = 0;
484   DiskDeviceExtension->DeviceNumber = DiskNumber;
485   DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
486   DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
487   DiskDeviceExtension->PortCapabilities = Capabilities;
488   DiskDeviceExtension->StartingOffset.QuadPart = 0;
489   DiskDeviceExtension->PortNumber = (UCHAR)PortNumber;
490   DiskDeviceExtension->PathId = InquiryData->PathId;
491   DiskDeviceExtension->TargetId = InquiryData->TargetId;
492   DiskDeviceExtension->Lun = InquiryData->Lun;
493
494   /* Initialize the lookaside list for SRBs */
495   ScsiClassInitializeSrbLookasideList(DiskDeviceExtension,
496                                       4);
497
498   /* zero-out disk data */
499   DiskData = (PDISK_DATA)(DiskDeviceExtension + 1);
500   RtlZeroMemory(DiskData,
501                 sizeof(DISK_DATA));
502
503   /* Get disk geometry */
504   DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
505                                                      sizeof(DISK_GEOMETRY));
506   if (DiskDeviceExtension->DiskGeometry == NULL)
507     {
508       DPRINT("Failed to allocate geometry buffer!\n");
509
510       ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
511
512       IoDeleteDevice(DiskDeviceObject);
513
514       /* Release (unclaim) the disk */
515       ScsiClassClaimDevice(PortDeviceObject,
516                            InquiryData,
517                            TRUE,
518                            NULL);
519
520       /* Delete the harddisk device directory */
521       ZwMakeTemporaryObject(Handle);
522       ZwClose(Handle);
523
524       return(STATUS_INSUFFICIENT_RESOURCES);
525     }
526
527   /* Read the drive's capacity */
528   Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
529   if (!NT_SUCCESS(Status) &&
530       (DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0)
531     {
532       DPRINT1("Failed to retrieve drive capacity!\n");
533       return(STATUS_SUCCESS);
534     }
535   else
536     {
537       /* Clear the verify flag for removable media drives. */
538       DiskDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
539     }
540
541   DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
542
543   if ((DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
544       (DiskDeviceExtension->DiskGeometry->MediaType == RemovableMedia))
545     {
546       /* Allocate a partition list for a single entry. */
547       PartitionList = ExAllocatePool(NonPagedPool,
548                                      sizeof(DRIVE_LAYOUT_INFORMATION));
549       if (PartitionList != NULL)
550         {
551           RtlZeroMemory(PartitionList,
552                         sizeof(DRIVE_LAYOUT_INFORMATION));
553           PartitionList->PartitionCount = 1;
554
555           DiskData->DriveNotReady = TRUE;
556           Status = STATUS_SUCCESS;
557         }
558     }
559   else
560     {
561       /* Read partition table */
562       Status = IoReadPartitionTable(DiskDeviceObject,
563                                     DiskDeviceExtension->DiskGeometry->BytesPerSector,
564                                     TRUE,
565                                     &PartitionList);
566
567       DPRINT("IoReadPartitionTable(): Status: %lx\n", Status);
568
569       if ((!NT_SUCCESS(Status) || PartitionList->PartitionCount == 0) &&
570           DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
571         {
572           if (!NT_SUCCESS(Status))
573             {
574               /* Drive is not ready. */
575               DPRINT("Drive not ready\n");
576               DiskData->DriveNotReady = TRUE;
577             }
578           else
579             {
580               ExFreePool(PartitionList);
581             }
582
583           /* Allocate a partition list for a single entry. */
584           PartitionList = ExAllocatePool(NonPagedPool,
585                                          sizeof(DRIVE_LAYOUT_INFORMATION));
586           if (PartitionList != NULL)
587             {
588               RtlZeroMemory(PartitionList,
589                             sizeof(DRIVE_LAYOUT_INFORMATION));
590               PartitionList->PartitionCount = 1;
591
592               Status = STATUS_SUCCESS;
593             }
594         }
595     }
596
597   if (NT_SUCCESS(Status))
598     {
599       DPRINT("Read partition table!\n");
600
601       DPRINT("  Number of partitions: %u\n", PartitionList->PartitionCount);
602
603       for (PartitionNumber = 0; PartitionNumber < PartitionList->PartitionCount; PartitionNumber++)
604         {
605           PartitionEntry = &PartitionList->PartitionEntry[PartitionNumber];
606
607           DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
608                  PartitionNumber,
609                  PartitionEntry->PartitionNumber,
610                  PartitionEntry->BootIndicator,
611                  PartitionEntry->PartitionType,
612                  PartitionEntry->StartingOffset.QuadPart / 512 /*DrvParms.BytesPerSector*/,
613                  PartitionEntry->PartitionLength.QuadPart / 512 /* DrvParms.BytesPerSector*/);
614
615           /* Create partition device object */
616           sprintf(NameBuffer2,
617                   "\\Device\\Harddisk%lu\\Partition%lu",
618                   DiskNumber,
619                   PartitionNumber + 1);
620
621           Status = ScsiClassCreateDeviceObject(DriverObject,
622                                                NameBuffer2,
623                                                DiskDeviceObject,
624                                                &PartitionDeviceObject,
625                                                InitializationData);
626           DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status);
627           if (NT_SUCCESS(Status))
628             {
629               PartitionDeviceObject->Flags = DiskDeviceObject->Flags;
630               PartitionDeviceObject->Characteristics = DiskDeviceObject->Characteristics;
631               PartitionDeviceObject->StackSize = DiskDeviceObject->StackSize;
632               PartitionDeviceObject->AlignmentRequirement = DiskDeviceObject->AlignmentRequirement;
633
634               PartitionDeviceExtension = PartitionDeviceObject->DeviceExtension;
635               PartitionDeviceExtension->LockCount = 0;
636               PartitionDeviceExtension->DeviceNumber = DiskNumber;
637               PartitionDeviceExtension->PortDeviceObject = PortDeviceObject;
638               PartitionDeviceExtension->DiskGeometry = DiskDeviceExtension->DiskGeometry;
639               PartitionDeviceExtension->PhysicalDevice = DiskDeviceExtension->PhysicalDevice;
640               PartitionDeviceExtension->PortCapabilities = Capabilities;
641               PartitionDeviceExtension->StartingOffset.QuadPart =
642                 PartitionEntry->StartingOffset.QuadPart;
643               PartitionDeviceExtension->PartitionLength.QuadPart =
644                 PartitionEntry->PartitionLength.QuadPart;
645               PartitionDeviceExtension->PortNumber = (UCHAR)PortNumber;
646               PartitionDeviceExtension->PathId = InquiryData->PathId;
647               PartitionDeviceExtension->TargetId = InquiryData->TargetId;
648               PartitionDeviceExtension->Lun = InquiryData->Lun;
649               PartitionDeviceExtension->SectorShift = DiskDeviceExtension->SectorShift;
650
651               /* Initialize lookaside list for SRBs */
652               ScsiClassInitializeSrbLookasideList(PartitionDeviceExtension,
653                                                   8);
654
655               DiskData = (PDISK_DATA)(PartitionDeviceExtension + 1);
656               DiskData->PartitionType = PartitionEntry->PartitionType;
657               DiskData->PartitionNumber = PartitionNumber + 1;
658               DiskData->PartitionOrdinal = PartitionNumber + 1;
659               DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
660               DiskData->BootIndicator = PartitionEntry->BootIndicator;
661               DiskData->DriveNotReady = FALSE;
662             }
663           else
664             {
665               DPRINT1("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status);
666
667               break;
668             }
669         }
670     }
671
672   if (PartitionList != NULL)
673     ExFreePool(PartitionList);
674
675   DPRINT("DiskClassCreateDeviceObjects() done\n");
676
677   return(STATUS_SUCCESS);
678 }
679
680
681 /**********************************************************************
682  * NAME                                                 EXPORTED
683  *      DiskClassDeviceControl
684  *
685  * DESCRIPTION
686  *      Answer requests for device control calls
687  *
688  * RUN LEVEL
689  *      PASSIVE_LEVEL
690  *
691  * ARGUMENTS
692  *      Standard dispatch arguments
693  *
694  * RETURNS
695  *      Status
696  */
697
698 NTSTATUS STDCALL
699 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
700                        IN PIRP Irp)
701 {
702   PDEVICE_EXTENSION DeviceExtension;
703   PIO_STACK_LOCATION IrpStack;
704   ULONG ControlCode, InputLength, OutputLength;
705   PDISK_DATA DiskData;
706   ULONG Information;
707   NTSTATUS Status;
708
709   DPRINT("DiskClassDeviceControl() called!\n");
710
711   Status = STATUS_INVALID_DEVICE_REQUEST;
712   Information = 0;
713   IrpStack = IoGetCurrentIrpStackLocation(Irp);
714   ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
715   InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
716   OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
717   DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
718   DiskData = (PDISK_DATA)(DeviceExtension + 1);
719
720   switch (ControlCode)
721     {
722       case IOCTL_DISK_GET_DRIVE_GEOMETRY:
723         DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
724         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
725           {
726             Status = STATUS_INVALID_PARAMETER;
727           }
728         else
729           {
730             PDISK_GEOMETRY Geometry;
731
732             if (DeviceExtension->DiskGeometry == NULL)
733               {
734                 DPRINT("No disk geometry available!\n");
735                 DeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
736                                                                sizeof(DISK_GEOMETRY));
737               }
738             Status = ScsiClassReadDriveCapacity(DeviceObject);
739             DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status);
740             if (NT_SUCCESS(Status))
741               {
742                 Geometry = (PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer;
743                 RtlMoveMemory(Geometry,
744                               DeviceExtension->DiskGeometry,
745                               sizeof(DISK_GEOMETRY));
746
747                 Status = STATUS_SUCCESS;
748                 Information = sizeof(DISK_GEOMETRY);
749               }
750           }
751         break;
752
753       case IOCTL_DISK_GET_PARTITION_INFO:
754         DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
755         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
756             sizeof(PARTITION_INFORMATION))
757           {
758             Status = STATUS_INFO_LENGTH_MISMATCH;
759           }
760         else if (DiskData->PartitionNumber == 0)
761           {
762             Status = STATUS_INVALID_DEVICE_REQUEST;
763           }
764         else
765           {
766             PPARTITION_INFORMATION PartitionInfo;
767
768             PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
769
770             PartitionInfo->PartitionType = DiskData->PartitionType;
771             PartitionInfo->StartingOffset = DeviceExtension->StartingOffset;
772             PartitionInfo->PartitionLength = DeviceExtension->PartitionLength;
773             PartitionInfo->HiddenSectors = DiskData->HiddenSectors;
774             PartitionInfo->PartitionNumber = DiskData->PartitionNumber;
775             PartitionInfo->BootIndicator = DiskData->BootIndicator;
776             PartitionInfo->RewritePartition = FALSE;
777             PartitionInfo->RecognizedPartition =
778               IsRecognizedPartition(DiskData->PartitionType);
779
780             Status = STATUS_SUCCESS;
781             Information = sizeof(PARTITION_INFORMATION);
782           }
783         break;
784
785       case IOCTL_DISK_SET_PARTITION_INFO:
786         if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
787             sizeof(SET_PARTITION_INFORMATION))
788           {
789             Status = STATUS_INFO_LENGTH_MISMATCH;
790           }
791         else if (DiskData->PartitionNumber == 0)
792           {
793             Status = STATUS_INVALID_DEVICE_REQUEST;
794           }
795         else
796           {
797             PSET_PARTITION_INFORMATION PartitionInfo;
798
799             PartitionInfo = (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
800
801             Status = IoSetPartitionInformation(DeviceExtension->PhysicalDevice,
802                                                DeviceExtension->DiskGeometry->BytesPerSector,
803                                                DiskData->PartitionOrdinal,
804                                                PartitionInfo->PartitionType);
805             if (NT_SUCCESS(Status))
806               {
807                 DiskData->PartitionType = PartitionInfo->PartitionType;
808               }
809           }
810         break;
811
812       case IOCTL_DISK_GET_DRIVE_LAYOUT:
813         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
814             sizeof(DRIVE_LAYOUT_INFORMATION))
815           {
816             Status = STATUS_BUFFER_TOO_SMALL;
817           }
818         else
819           {
820             PDRIVE_LAYOUT_INFORMATION PartitionList;
821
822             Status = IoReadPartitionTable(DeviceExtension->PhysicalDevice,
823                                           DeviceExtension->DiskGeometry->BytesPerSector,
824                                           FALSE,
825                                           &PartitionList);
826             if (NT_SUCCESS(Status))
827               {
828                 ULONG BufferSize;
829
830                 BufferSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
831                                           PartitionEntry[0]);
832                 BufferSize += PartitionList->PartitionCount * sizeof(PARTITION_INFORMATION);
833
834                 if (BufferSize > IrpStack->Parameters.DeviceIoControl.OutputBufferLength)
835                   {
836                     Status = STATUS_BUFFER_TOO_SMALL;
837                   }
838                 else
839                   {
840                     RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
841                                   PartitionList,
842                                   BufferSize);
843                     Status = STATUS_SUCCESS;
844                     Information = BufferSize;
845                   }
846                 ExFreePool(PartitionList);
847               }
848           }
849         break;
850
851       case IOCTL_DISK_SET_DRIVE_LAYOUT:
852         if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
853             sizeof(DRIVE_LAYOUT_INFORMATION))
854           {
855             Status = STATUS_INFO_LENGTH_MISMATCH;
856           }
857         else if (DeviceExtension->PhysicalDevice->DeviceExtension != DeviceExtension)
858           {
859             Status = STATUS_INVALID_PARAMETER;
860           }
861         else
862           {
863             PDRIVE_LAYOUT_INFORMATION PartitionList;
864             ULONG TableSize;
865
866             PartitionList = Irp->AssociatedIrp.SystemBuffer;
867             TableSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
868                         ((PartitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
869
870             if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < TableSize)
871               {
872                 Status = STATUS_BUFFER_TOO_SMALL;
873               }
874             else
875               {
876                 Status = IoWritePartitionTable(DeviceExtension->DeviceObject,
877                                                DeviceExtension->DiskGeometry->BytesPerSector,
878                                                DeviceExtension->DiskGeometry->SectorsPerTrack,
879                                                DeviceExtension->DiskGeometry->TracksPerCylinder,
880                                                PartitionList);
881                 if (NT_SUCCESS(Status))
882                   {
883                     /* FIXME: Update partition device objects */
884
885                     Information = TableSize;
886                   }
887               }
888           }
889         break;
890
891       case IOCTL_DISK_VERIFY:
892       case IOCTL_DISK_FORMAT_TRACKS:
893       case IOCTL_DISK_PERFORMANCE:
894       case IOCTL_DISK_IS_WRITABLE:
895       case IOCTL_DISK_LOGGING:
896       case IOCTL_DISK_FORMAT_TRACKS_EX:
897       case IOCTL_DISK_HISTOGRAM_STRUCTURE:
898       case IOCTL_DISK_HISTOGRAM_DATA:
899       case IOCTL_DISK_HISTOGRAM_RESET:
900       case IOCTL_DISK_REQUEST_STRUCTURE:
901       case IOCTL_DISK_REQUEST_DATA:
902         /* If we get here, something went wrong. Inform the requestor */
903         DPRINT1("Unhandled control code: %lx\n", ControlCode);
904         Status = STATUS_INVALID_DEVICE_REQUEST;
905         Information = 0;
906         break;
907
908       default:
909         /* Call the common device control function */
910         return(ScsiClassDeviceControl(DeviceObject, Irp));
911     }
912
913   /* Verify the device if the user caused the error */
914   if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
915     {
916       IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
917     }
918
919   Irp->IoStatus.Status = Status;
920   Irp->IoStatus.Information = Information;
921   IoCompleteRequest(Irp,
922                     IO_NO_INCREMENT);
923
924   return(Status);
925 }
926
927
928 /**********************************************************************
929  * NAME                                                 EXPORTED
930  *      DiskClassShutdownFlush
931  *
932  * DESCRIPTION
933  *      Answer requests for shutdown and flush calls.
934  *
935  * RUN LEVEL
936  *      PASSIVE_LEVEL
937  *
938  * ARGUMENTS
939  *      DeviceObject
940  *              Pointer to the device.
941  *
942  *      Irp
943  *              Pointer to the IRP
944  *
945  * RETURN VALUE
946  *      Status
947  */
948
949 NTSTATUS STDCALL
950 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
951                        IN PIRP Irp)
952 {
953   PDEVICE_EXTENSION DeviceExtension;
954   PIO_STACK_LOCATION IrpStack;
955   PSCSI_REQUEST_BLOCK Srb;
956
957   DPRINT("DiskClassShutdownFlush() called!\n");
958
959   DeviceExtension = DeviceObject->DeviceExtension;
960
961   /* Allocate SRB */
962   Srb = ExAllocatePool(NonPagedPool,
963                        sizeof(SCSI_REQUEST_BLOCK));
964   if (Srb == NULL)
965     {
966       Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
967       Irp->IoStatus.Information = 0;
968       IoCompleteRequest(Irp, IO_NO_INCREMENT);
969
970       return(STATUS_INSUFFICIENT_RESOURCES);
971     }
972
973   /* Initialize SRB */
974   RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
975   Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
976
977   /* Set device IDs */
978   Srb->PathId = DeviceExtension->PathId;
979   Srb->TargetId = DeviceExtension->TargetId;
980   Srb->Lun = DeviceExtension->Lun;
981
982   /* Flush write cache */
983   Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
984   Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
985   Srb->CdbLength = 10;
986   Srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
987   ScsiClassSendSrbSynchronous(DeviceObject,
988                               Srb,
989                               NULL,
990                               0,
991                               TRUE);
992
993   /* Get current stack location */
994   IrpStack = IoGetCurrentIrpStackLocation(Irp);
995
996   /* FIXME: Unlock removable media upon shutdown */
997
998
999   /* No retry */
1000   IrpStack->Parameters.Others.Argument4 = (PVOID)0;
1001
1002   /* Send shutdown or flush request to the port driver */
1003   Srb->CdbLength = 0;
1004   if (IrpStack->MajorFunction == IRP_MJ_SHUTDOWN)
1005     Srb->Function = SRB_FUNCTION_SHUTDOWN;
1006   else
1007     Srb->Function = SRB_FUNCTION_FLUSH;
1008
1009   /* Init completion routine */
1010   IoSetCompletionRoutine(Irp,
1011                          ScsiClassIoComplete,
1012                          Srb,
1013                          TRUE,
1014                          TRUE,
1015                          TRUE);
1016
1017   /* Prepare next stack location for a call to the port driver */
1018   IrpStack = IoGetNextIrpStackLocation(Irp);
1019   IrpStack->MajorFunction = IRP_MJ_SCSI;
1020   IrpStack->Parameters.Scsi.Srb = Srb;
1021   Srb->OriginalRequest = Irp;
1022
1023   /* Call port driver */
1024   return(IoCallDriver(DeviceExtension->PortDeviceObject, Irp));
1025 }
1026
1027 /* EOF */