:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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   /* zero-out disk data */
495   DiskData = (PDISK_DATA)(DiskDeviceExtension + 1);
496   RtlZeroMemory(DiskData,
497                 sizeof(DISK_DATA));
498
499   /* Get disk geometry */
500   DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
501                                                      sizeof(DISK_GEOMETRY));
502   if (DiskDeviceExtension->DiskGeometry == NULL)
503     {
504       DPRINT("Failed to allocate geometry buffer!\n");
505
506       IoDeleteDevice(DiskDeviceObject);
507
508       /* Release (unclaim) the disk */
509       ScsiClassClaimDevice(PortDeviceObject,
510                            InquiryData,
511                            TRUE,
512                            NULL);
513
514       /* Delete the harddisk device directory */
515       ZwMakeTemporaryObject(Handle);
516       ZwClose(Handle);
517
518       return(STATUS_INSUFFICIENT_RESOURCES);
519     }
520
521   /* Read the drive's capacity */
522   Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
523   if (!NT_SUCCESS(Status) &&
524       (DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0)
525     {
526       DPRINT1("Failed to retrieve drive capacity!\n");
527       return(STATUS_SUCCESS);
528     }
529   else
530     {
531       /* Clear the verify flag for removable media drives. */
532       DiskDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
533     }
534
535   DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
536
537   if ((DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
538       (DiskDeviceExtension->DiskGeometry->MediaType == RemovableMedia))
539     {
540       /* Allocate a partition list for a single entry. */
541       PartitionList = ExAllocatePool(NonPagedPool,
542                                      sizeof(DRIVE_LAYOUT_INFORMATION));
543       if (PartitionList != NULL)
544         {
545           RtlZeroMemory(PartitionList,
546                         sizeof(DRIVE_LAYOUT_INFORMATION));
547           PartitionList->PartitionCount = 1;
548
549           DiskData->DriveNotReady = TRUE;
550           Status = STATUS_SUCCESS;
551         }
552     }
553   else
554     {
555   /* Read partition table */
556   Status = IoReadPartitionTable(DiskDeviceObject,
557                                 DiskDeviceExtension->DiskGeometry->BytesPerSector,
558                                 TRUE,
559                                 &PartitionList);
560
561   DPRINT("IoReadPartitionTable(): Status: %lx\n", Status);
562
563   if ((!NT_SUCCESS(Status) || PartitionList->PartitionCount == 0) &&
564       DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
565     {
566       if (!NT_SUCCESS(Status))
567         {
568           /* Drive is not ready. */
569           DPRINT("Drive not ready\n");
570           DiskData->DriveNotReady = TRUE;
571         }
572       else
573         {
574           ExFreePool(PartitionList);
575         }
576
577       /* Allocate a partition list for a single entry. */
578       PartitionList = ExAllocatePool(NonPagedPool,
579                                      sizeof(DRIVE_LAYOUT_INFORMATION));
580       if (PartitionList != NULL)
581         {
582           RtlZeroMemory(PartitionList,
583                         sizeof(DRIVE_LAYOUT_INFORMATION));
584           PartitionList->PartitionCount = 1;
585
586           Status = STATUS_SUCCESS;
587         }
588     }
589   }
590
591   if (NT_SUCCESS(Status))
592     {
593       DPRINT("Read partition table!\n");
594
595       DPRINT("  Number of partitions: %u\n", PartitionList->PartitionCount);
596
597       for (PartitionNumber = 0; PartitionNumber < PartitionList->PartitionCount; PartitionNumber++)
598         {
599           PartitionEntry = &PartitionList->PartitionEntry[PartitionNumber];
600
601           DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
602                  PartitionNumber,
603                  PartitionEntry->PartitionNumber,
604                  PartitionEntry->BootIndicator,
605                  PartitionEntry->PartitionType,
606                  PartitionEntry->StartingOffset.QuadPart / 512 /*DrvParms.BytesPerSector*/,
607                  PartitionEntry->PartitionLength.QuadPart / 512 /* DrvParms.BytesPerSector*/);
608
609           /* Create partition device object */
610           sprintf(NameBuffer2,
611                   "\\Device\\Harddisk%lu\\Partition%lu",
612                   DiskNumber,
613                   PartitionNumber + 1);
614
615           Status = ScsiClassCreateDeviceObject(DriverObject,
616                                                NameBuffer2,
617                                                DiskDeviceObject,
618                                                &PartitionDeviceObject,
619                                                InitializationData);
620           DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status);
621           if (NT_SUCCESS(Status))
622             {
623               PartitionDeviceObject->Flags = DiskDeviceObject->Flags;
624               PartitionDeviceObject->Characteristics = DiskDeviceObject->Characteristics;
625               PartitionDeviceObject->StackSize = DiskDeviceObject->StackSize;
626               PartitionDeviceObject->AlignmentRequirement = DiskDeviceObject->AlignmentRequirement;
627
628               PartitionDeviceExtension = PartitionDeviceObject->DeviceExtension;
629               PartitionDeviceExtension->LockCount = 0;
630               PartitionDeviceExtension->DeviceNumber = DiskNumber;
631               PartitionDeviceExtension->PortDeviceObject = PortDeviceObject;
632               PartitionDeviceExtension->DiskGeometry = DiskDeviceExtension->DiskGeometry;
633               PartitionDeviceExtension->PhysicalDevice = DiskDeviceExtension->PhysicalDevice;
634               PartitionDeviceExtension->PortCapabilities = Capabilities;
635               PartitionDeviceExtension->StartingOffset.QuadPart =
636                 PartitionEntry->StartingOffset.QuadPart;
637               PartitionDeviceExtension->PartitionLength.QuadPart =
638                 PartitionEntry->PartitionLength.QuadPart;
639               PartitionDeviceExtension->PortNumber = (UCHAR)PortNumber;
640               PartitionDeviceExtension->PathId = InquiryData->PathId;
641               PartitionDeviceExtension->TargetId = InquiryData->TargetId;
642               PartitionDeviceExtension->Lun = InquiryData->Lun;
643               PartitionDeviceExtension->SectorShift = DiskDeviceExtension->SectorShift;
644
645               DiskData = (PDISK_DATA)(PartitionDeviceExtension + 1);
646               DiskData->PartitionType = PartitionEntry->PartitionType;
647               DiskData->PartitionNumber = PartitionNumber + 1;
648               DiskData->PartitionOrdinal = PartitionNumber + 1;
649               DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
650               DiskData->BootIndicator = PartitionEntry->BootIndicator;
651               DiskData->DriveNotReady = FALSE;
652             }
653           else
654             {
655               DPRINT1("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status);
656
657               break;
658             }
659         }
660     }
661
662   if (PartitionList != NULL)
663     ExFreePool(PartitionList);
664
665   DPRINT("DiskClassCreateDeviceObjects() done\n");
666
667   return(STATUS_SUCCESS);
668 }
669
670
671 /**********************************************************************
672  * NAME                                                 EXPORTED
673  *      DiskClassDeviceControl
674  *
675  * DESCRIPTION
676  *      Answer requests for device control calls
677  *
678  * RUN LEVEL
679  *      PASSIVE_LEVEL
680  *
681  * ARGUMENTS
682  *      Standard dispatch arguments
683  *
684  * RETURNS
685  *      Status
686  */
687
688 NTSTATUS STDCALL
689 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
690                        IN PIRP Irp)
691 {
692   PDEVICE_EXTENSION DeviceExtension;
693   PIO_STACK_LOCATION IrpStack;
694   ULONG ControlCode, InputLength, OutputLength;
695   PDISK_DATA DiskData;
696   ULONG Information;
697   NTSTATUS Status;
698
699   DPRINT("DiskClassDeviceControl() called!\n");
700
701   Status = STATUS_INVALID_DEVICE_REQUEST;
702   Information = 0;
703   IrpStack = IoGetCurrentIrpStackLocation(Irp);
704   ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
705   InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
706   OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
707   DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
708   DiskData = (PDISK_DATA)(DeviceExtension + 1);
709
710   switch (ControlCode)
711     {
712       case IOCTL_DISK_GET_DRIVE_GEOMETRY:
713         DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
714         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
715           {
716             Status = STATUS_INVALID_PARAMETER;
717           }
718         else
719           {
720             PDISK_GEOMETRY Geometry;
721
722             if (DeviceExtension->DiskGeometry == NULL)
723               {
724                 DPRINT("No disk geometry available!\n");
725                 DeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
726                                                                sizeof(DISK_GEOMETRY));
727               }
728             Status = ScsiClassReadDriveCapacity(DeviceObject);
729             DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status);
730             if (NT_SUCCESS(Status))
731               {
732                 Geometry = (PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer;
733                 RtlMoveMemory(Geometry,
734                               DeviceExtension->DiskGeometry,
735                               sizeof(DISK_GEOMETRY));
736
737                 Status = STATUS_SUCCESS;
738                 Information = sizeof(DISK_GEOMETRY);
739               }
740           }
741         break;
742
743       case IOCTL_DISK_GET_PARTITION_INFO:
744         DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
745         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
746             sizeof(PARTITION_INFORMATION))
747           {
748             Status = STATUS_INFO_LENGTH_MISMATCH;
749           }
750         else if (DiskData->PartitionNumber == 0)
751           {
752             Status = STATUS_INVALID_DEVICE_REQUEST;
753           }
754         else
755           {
756             PPARTITION_INFORMATION PartitionInfo;
757
758             PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
759
760             PartitionInfo->PartitionType = DiskData->PartitionType;
761             PartitionInfo->StartingOffset = DeviceExtension->StartingOffset;
762             PartitionInfo->PartitionLength = DeviceExtension->PartitionLength;
763             PartitionInfo->HiddenSectors = DiskData->HiddenSectors;
764             PartitionInfo->PartitionNumber = DiskData->PartitionNumber;
765             PartitionInfo->BootIndicator = DiskData->BootIndicator;
766             PartitionInfo->RewritePartition = FALSE;
767             PartitionInfo->RecognizedPartition =
768               IsRecognizedPartition(DiskData->PartitionType);
769
770             Status = STATUS_SUCCESS;
771             Information = sizeof(PARTITION_INFORMATION);
772           }
773         break;
774
775       case IOCTL_DISK_SET_PARTITION_INFO:
776         if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
777             sizeof(SET_PARTITION_INFORMATION))
778           {
779             Status = STATUS_INFO_LENGTH_MISMATCH;
780           }
781         else if (DiskData->PartitionNumber == 0)
782           {
783             Status = STATUS_INVALID_DEVICE_REQUEST;
784           }
785         else
786           {
787             PSET_PARTITION_INFORMATION PartitionInfo;
788
789             PartitionInfo = (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
790
791             Status = IoSetPartitionInformation(DeviceExtension->PhysicalDevice,
792                                                DeviceExtension->DiskGeometry->BytesPerSector,
793                                                DiskData->PartitionOrdinal,
794                                                PartitionInfo->PartitionType);
795             if (NT_SUCCESS(Status))
796               {
797                 DiskData->PartitionType = PartitionInfo->PartitionType;
798               }
799           }
800         break;
801
802       case IOCTL_DISK_GET_DRIVE_LAYOUT:
803         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
804             sizeof(DRIVE_LAYOUT_INFORMATION))
805           {
806             Status = STATUS_BUFFER_TOO_SMALL;
807           }
808         else
809           {
810             PDRIVE_LAYOUT_INFORMATION PartitionList;
811
812             Status = IoReadPartitionTable(DeviceExtension->PhysicalDevice,
813                                           DeviceExtension->DiskGeometry->BytesPerSector,
814                                           FALSE,
815                                           &PartitionList);
816             if (NT_SUCCESS(Status))
817               {
818                 ULONG BufferSize;
819
820                 BufferSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
821                                           PartitionEntry[0]);
822                 BufferSize += PartitionList->PartitionCount * sizeof(PARTITION_INFORMATION);
823
824                 if (BufferSize > IrpStack->Parameters.DeviceIoControl.OutputBufferLength)
825                   {
826                     Status = STATUS_BUFFER_TOO_SMALL;
827                   }
828                 else
829                   {
830                     RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
831                                   PartitionList,
832                                   BufferSize);
833                     Status = STATUS_SUCCESS;
834                     Information = BufferSize;
835                   }
836                 ExFreePool(PartitionList);
837               }
838           }
839         break;
840
841       case IOCTL_DISK_SET_DRIVE_LAYOUT:
842         if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
843             sizeof(DRIVE_LAYOUT_INFORMATION))
844           {
845             Status = STATUS_INFO_LENGTH_MISMATCH;
846           }
847         else if (DeviceExtension->PhysicalDevice->DeviceExtension != DeviceExtension)
848           {
849             Status = STATUS_INVALID_PARAMETER;
850           }
851         else
852           {
853             PDRIVE_LAYOUT_INFORMATION PartitionList;
854             ULONG TableSize;
855
856             PartitionList = Irp->AssociatedIrp.SystemBuffer;
857             TableSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
858                         ((PartitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
859
860             if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < TableSize)
861               {
862                 Status = STATUS_BUFFER_TOO_SMALL;
863               }
864             else
865               {
866                 Status = IoWritePartitionTable(DeviceExtension->DeviceObject,
867                                                DeviceExtension->DiskGeometry->BytesPerSector,
868                                                DeviceExtension->DiskGeometry->SectorsPerTrack,
869                                                DeviceExtension->DiskGeometry->TracksPerCylinder,
870                                                PartitionList);
871                 if (NT_SUCCESS(Status))
872                   {
873                     /* FIXME: Update partition device objects */
874
875                     Information = TableSize;
876                   }
877               }
878           }
879         break;
880
881       case IOCTL_DISK_VERIFY:
882       case IOCTL_DISK_FORMAT_TRACKS:
883       case IOCTL_DISK_PERFORMANCE:
884       case IOCTL_DISK_IS_WRITABLE:
885       case IOCTL_DISK_LOGGING:
886       case IOCTL_DISK_FORMAT_TRACKS_EX:
887       case IOCTL_DISK_HISTOGRAM_STRUCTURE:
888       case IOCTL_DISK_HISTOGRAM_DATA:
889       case IOCTL_DISK_HISTOGRAM_RESET:
890       case IOCTL_DISK_REQUEST_STRUCTURE:
891       case IOCTL_DISK_REQUEST_DATA:
892         /* If we get here, something went wrong. Inform the requestor */
893         DPRINT1("Unhandled control code: %lx\n", ControlCode);
894         Status = STATUS_INVALID_DEVICE_REQUEST;
895         Information = 0;
896         break;
897
898       default:
899         /* Call the common device control function */
900         return(ScsiClassDeviceControl(DeviceObject, Irp));
901     }
902
903   /* Verify the device if the user caused the error */
904   if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
905     {
906       IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
907     }
908
909   Irp->IoStatus.Status = Status;
910   Irp->IoStatus.Information = Information;
911   IoCompleteRequest(Irp,
912                     IO_NO_INCREMENT);
913
914   return(Status);
915 }
916
917
918 /**********************************************************************
919  * NAME                                                 EXPORTED
920  *      DiskClassShutdownFlush
921  *
922  * DESCRIPTION
923  *      Answer requests for shutdown and flush calls.
924  *
925  * RUN LEVEL
926  *      PASSIVE_LEVEL
927  *
928  * ARGUMENTS
929  *      DeviceObject
930  *              Pointer to the device.
931  *
932  *      Irp
933  *              Pointer to the IRP
934  *
935  * RETURN VALUE
936  *      Status
937  */
938
939 NTSTATUS STDCALL
940 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
941                        IN PIRP Irp)
942 {
943   PDEVICE_EXTENSION DeviceExtension;
944   PIO_STACK_LOCATION IrpStack;
945   PSCSI_REQUEST_BLOCK Srb;
946
947   DPRINT("DiskClassShutdownFlush() called!\n");
948
949   DeviceExtension = DeviceObject->DeviceExtension;
950
951   /* Allocate SRB */
952   Srb = ExAllocatePool(NonPagedPool,
953                        sizeof(SCSI_REQUEST_BLOCK));
954   if (Srb == NULL)
955     {
956       Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
957       Irp->IoStatus.Information = 0;
958       IoCompleteRequest(Irp, IO_NO_INCREMENT);
959
960       return(STATUS_INSUFFICIENT_RESOURCES);
961     }
962
963   /* Initialize SRB */
964   RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
965   Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
966
967   /* Set device IDs */
968   Srb->PathId = DeviceExtension->PathId;
969   Srb->TargetId = DeviceExtension->TargetId;
970   Srb->Lun = DeviceExtension->Lun;
971
972
973   /* FIXME: Flush write cache */
974
975
976   /* Get current stack location */
977   IrpStack = IoGetCurrentIrpStackLocation(Irp);
978
979
980   /* FIXME: Unlock removable media upon shutdown */
981
982
983   /* No retry */
984   IrpStack->Parameters.Others.Argument4 = (PVOID)0;
985
986   /* Send shutdown or flush request to the port driver */
987   Srb->CdbLength = 0;
988   if (IrpStack->MajorFunction == IRP_MJ_SHUTDOWN)
989     Srb->Function = SRB_FUNCTION_SHUTDOWN;
990   else
991     Srb->Function = SRB_FUNCTION_FLUSH;
992
993   /* Init completion routine */
994   IoSetCompletionRoutine(Irp,
995                          ScsiClassIoComplete,
996                          Srb,
997                          TRUE,
998                          TRUE,
999                          TRUE);
1000
1001   /* Prepare next stack location for a call to the port driver */
1002   IrpStack = IoGetNextIrpStackLocation(Irp);
1003   IrpStack->MajorFunction = IRP_MJ_SCSI;
1004   IrpStack->Parameters.Scsi.Srb = Srb;
1005   Srb->OriginalRequest = Irp;
1006
1007   /* Call port driver */
1008   return(IoCallDriver(DeviceExtension->PortDeviceObject, Irp));
1009 }
1010
1011 /* EOF */