Started support for removable disk drives.
[reactos.git] / reactos / drivers / storage / disk / disk.c
index a2b6bbf..7ad5a19 100644 (file)
@@ -1,88 +1,90 @@
-/* $Id: disk.c,v 1.1 2001/07/24 10:21:15 ekohl Exp $
+/*
+ *  ReactOS kernel
+ *  Copyright (C) 2001, 2002 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* $Id: disk.c,v 1.11 2002/03/22 20:35:09 ekohl Exp $
  *
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            services/storage/disk/disk.c
+ * PURPOSE:         disk class driver
+ * PROGRAMMER:      Eric Kohl (ekohl@rz-online.de)
  */
 
-//  -------------------------------------------------------------------------
+/* INCLUDES *****************************************************************/
 
 #include <ddk/ntddk.h>
 
-//#define NDEBUG
-#include <debug.h>
-
-//#include "ide.h"
-//#include "partitio.h"
-
-#define VERSION "V0.0.1"
+#include "../include/scsi.h"
+#include "../include/class2.h"
+#include "../include/ntddscsi.h"
 
+#define NDEBUG
+#include <debug.h>
 
-static NTSTATUS DiskCreateDevices(VOID);
-static BOOLEAN DiskFindDiskDrives(PDEVICE_OBJECT PortDeviceObject, ULONG PortNumber);
+#define VERSION  "0.0.1"
 
 
-/*
- *  DiskOpenClose
- *
- *  DESCRIPTION:
- *    Answer requests for Open/Close calls: a null operation
- *
- *  RUN LEVEL:
- *    PASSIVE_LEVEL
- *
- *  ARGUMENTS:
- *    Standard dispatch arguments
- *
- *  RETURNS:
- *    NTSTATUS
-*/
-#if 0
-static NTSTATUS STDCALL
-DiskOpenClose(IN PDEVICE_OBJECT pDO,
-             IN PIRP Irp)
+typedef struct _DISK_DATA
 {
-   Irp->IoStatus.Status = STATUS_SUCCESS;
-   Irp->IoStatus.Information = FILE_OPENED;
-   IoCompleteRequest(Irp, IO_NO_INCREMENT);
+  ULONG HiddenSectors;
+  ULONG PartitionNumber;
+  UCHAR PartitionType;
+  BOOLEAN BootIndicator;
+  BOOLEAN DriveNotReady;
+} DISK_DATA, *PDISK_DATA;
 
-   return STATUS_SUCCESS;
-}
-#endif
 
+BOOLEAN STDCALL
+DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
+                    PUNICODE_STRING RegistryPath,
+                    PCLASS_INIT_DATA InitializationData,
+                    PDEVICE_OBJECT PortDeviceObject,
+                    ULONG PortNumber);
 
-static NTSTATUS STDCALL
-DiskClassReadWrite(IN PDEVICE_OBJECT pDO,
-                  IN PIRP Irp)
-{
-   Irp->IoStatus.Status = STATUS_SUCCESS;
-   Irp->IoStatus.Information = 0;
-   IoCompleteRequest(Irp, IO_NO_INCREMENT);
+BOOLEAN STDCALL
+DiskClassCheckDevice(IN PINQUIRYDATA InquiryData);
 
-   return STATUS_SUCCESS;
-}
+NTSTATUS STDCALL
+DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
+                       IN PIRP Irp);
 
 
-static NTSTATUS STDCALL
-DiskClassDeviceControl(IN PDEVICE_OBJECT pDO,
-                      IN PIRP Irp)
-{
-   Irp->IoStatus.Status = STATUS_SUCCESS;
-   Irp->IoStatus.Information = 0;
-   IoCompleteRequest(Irp, IO_NO_INCREMENT);
+static NTSTATUS
+DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
+                           IN PUNICODE_STRING RegistryPath, /* what's this used for? */
+                           IN PDEVICE_OBJECT PortDeviceObject,
+                           IN ULONG PortNumber,
+                           IN ULONG DiskNumber,
+                           IN PIO_SCSI_CAPABILITIES Capabilities,
+                           IN PSCSI_INQUIRY_DATA InquiryData,
+                           IN PCLASS_INIT_DATA InitializationData);
 
-   return STATUS_SUCCESS;
-}
+NTSTATUS STDCALL
+DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
+                      IN PIRP Irp);
 
+NTSTATUS STDCALL
+DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
+                      IN PIRP Irp);
 
-static NTSTATUS STDCALL
-DiskClassShutdownFlush(IN PDEVICE_OBJECT pDO,
-                      IN PIRP Irp)
-{
-   Irp->IoStatus.Status = STATUS_SUCCESS;
-   Irp->IoStatus.Information = 0;
-   IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
-   return STATUS_SUCCESS;
-}
 
+/* FUNCTIONS ****************************************************************/
 
 //    DriverEntry
 //
@@ -107,206 +109,554 @@ NTSTATUS STDCALL
 DriverEntry(IN PDRIVER_OBJECT DriverObject,
            IN PUNICODE_STRING RegistryPath)
 {
-   NTSTATUS Status;
+  CLASS_INIT_DATA InitData;
+
+  DbgPrint("Disk Class Driver %s\n",
+          VERSION);
+  DPRINT("RegistryPath '%wZ'\n",
+        RegistryPath);
+
+  RtlZeroMemory(&InitData,
+               sizeof(CLASS_INIT_DATA));
+
+  InitData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
+  InitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA);
+  InitData.DeviceType = FILE_DEVICE_DISK;
+  InitData.DeviceCharacteristics = 0;
+
+  InitData.ClassError = NULL;  // DiskClassProcessError;
+  InitData.ClassReadWriteVerification = DiskClassCheckReadWrite;
+  InitData.ClassFindDeviceCallBack = DiskClassCheckDevice;
+  InitData.ClassFindDevices = DiskClassFindDevices;
+  InitData.ClassDeviceControl = DiskClassDeviceControl;
+  InitData.ClassShutdownFlush = DiskClassShutdownFlush;
+  InitData.ClassCreateClose = NULL;
+  InitData.ClassStartIo = NULL;
+
+  return(ScsiClassInitialize(DriverObject,
+                            RegistryPath,
+                            &InitData));
+}
 
-   DbgPrint("Disk Class Driver %s\n", VERSION);
 
-   /* Export other driver entry points... */
-//   DriverObject->DriverStartIo = IDEStartIo;
-//   DriverObject->MajorFunction[IRP_MJ_CREATE] = DiskClassOpenClose;
-//   DriverObject->MajorFunction[IRP_MJ_CLOSE] = DiskClassOpenClose;
-   DriverObject->MajorFunction[IRP_MJ_READ] = DiskClassReadWrite;
-   DriverObject->MajorFunction[IRP_MJ_WRITE] = DiskClassReadWrite;
-   DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DiskClassDeviceControl;
-   DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = DiskClassShutdownFlush;
-   DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = DiskClassShutdownFlush;
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     DiskClassFindDevices
+ *
+ * DESCRIPTION
+ *     This function searches for device that are attached to the
+ *     given scsi port.
+ *
+ * RUN LEVEL
+ *     PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ *     DriverObject
+ *             System allocated Driver Object for this driver
+ *
+ *     RegistryPath
+ *             Name of registry driver service key
+ *
+ *     InitializationData
+ *             Pointer to the main initialization data
+ *
+ *     PortDeviceObject
+ *             Pointer to the port Device Object
+ *
+ *     PortNumber
+ *             Port number
+ *
+ * RETURN VALUE
+ *     TRUE: At least one disk drive was found
+ *     FALSE: No disk drive found
+ */
 
-   Status = DiskCreateDevices();
-   DPRINT("Status 0x%08X\n", Status);
+BOOLEAN STDCALL
+DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
+                    PUNICODE_STRING RegistryPath,
+                    PCLASS_INIT_DATA InitializationData,
+                    PDEVICE_OBJECT PortDeviceObject,
+                    ULONG PortNumber)
+{
+  PCONFIGURATION_INFORMATION ConfigInfo;
+  PIO_SCSI_CAPABILITIES PortCapabilities;
+  PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
+  PSCSI_INQUIRY_DATA UnitInfo;
+  PINQUIRYDATA InquiryData;
+  PCHAR Buffer;
+  ULONG Bus;
+  ULONG DeviceCount;
+  BOOLEAN FoundDevice;
+  NTSTATUS Status;
+
+  DPRINT("DiskClassFindDevices() called.\n");
+
+  /* Get port capabilities */
+  Status = ScsiClassGetCapabilities(PortDeviceObject,
+                                   &PortCapabilities);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status);
+      return(FALSE);
+    }
 
-   DPRINT("Returning from DriverEntry\n");
-   return STATUS_SUCCESS;
-}
+  DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
 
+  /* Get inquiry data */
+  Status = ScsiClassGetInquiryData(PortDeviceObject,
+                                  (PSCSI_ADAPTER_BUS_INFO *)&Buffer);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("ScsiClassGetInquiryData() failed! (Status %x)\n", Status);
+      return(FALSE);
+    }
 
+  /* Check whether there are unclaimed devices */
+  AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
+  DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
+                                             AdapterBusInfo);
+  if (DeviceCount == 0)
+    {
+      DPRINT1("No unclaimed devices!\n");
+      return(FALSE);
+    }
 
-static NTSTATUS
-DiskCreateDevices(VOID)
-{
-   WCHAR NameBuffer[80];
-   UNICODE_STRING PortName;
-   ULONG PortNumber = 0;
-   PDEVICE_OBJECT PortDeviceObject;
-   PFILE_OBJECT FileObject;
-   BOOLEAN DiskFound = FALSE;
-   NTSTATUS Status;
-   
-   DPRINT1("DiskCreateDevices() called.\n");
-   
-   /* look for ScsiPortX scsi port devices */
-   do
-     {
-       swprintf(NameBuffer,
-                L"\\Device\\ScsiPort%ld",
-                PortNumber);
-       RtlInitUnicodeString(&PortName,
-                            NameBuffer);
-       DPRINT1("Checking scsi port %ld\n", PortNumber);
-       Status = IoGetDeviceObjectPointer(&PortName,
-                                         FILE_READ_ATTRIBUTES,
-                                         &FileObject,
-                                         &PortDeviceObject);
-       DPRINT1("Status 0x%08lX\n", Status);
-       if (NT_SUCCESS(Status))
-         {
-            DPRINT1("ScsiPort%ld found.\n", PortNumber);
+  DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
 
-            /* Check scsi port for attached disk drives */
-            DiskFound = DiskFindDiskDrives(PortDeviceObject, PortNumber);
-         }
-       PortNumber++;
-     }
-   while (NT_SUCCESS(Status));
+  ConfigInfo = IoGetConfigurationInformation();
+
+  /* Search each bus of this adapter */
+  for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
+    {
+      DPRINT("Searching bus %lu\n", Bus);
+
+      UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
+
+      while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
+       {
+         InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
+
+         if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
+              (InquiryData->DeviceType == OPTICAL_DEVICE)) &&
+             (InquiryData->DeviceTypeQualifier == 0) &&
+             (UnitInfo->DeviceClaimed == FALSE))
+           {
+             DPRINT("Vendor: '%.24s'\n",
+                    InquiryData->VendorId);
+
+             /* Create device objects for disk */
+             Status = DiskClassCreateDeviceObject(DriverObject,
+                                                  RegistryPath,
+                                                  PortDeviceObject,
+                                                  PortNumber,
+                                                  ConfigInfo->DiskCount,
+                                                  PortCapabilities,
+                                                  UnitInfo,
+                                                  InitializationData);
+             if (NT_SUCCESS(Status))
+               {
+                 ConfigInfo->DiskCount++;
+                 FoundDevice = TRUE;
+               }
+           }
+
+         if (UnitInfo->NextInquiryDataOffset == 0)
+           break;
+
+         UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
+       }
+    }
+
+  ExFreePool(Buffer);
+  ExFreePool(PortCapabilities);
+
+  DPRINT("DiskClassFindDevices() done\n");
+
+  return(FoundDevice);
+}
+
+
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     DiskClassCheckDevice
+ *
+ * DESCRIPTION
+ *     This function checks the InquiryData for the correct device
+ *     type and qualifier.
+ *
+ * RUN LEVEL
+ *     PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ *     InquiryData
+ *             Pointer to the inquiry data for the device in question.
+ *
+ * RETURN VALUE
+ *     TRUE: A disk device was found.
+ *     FALSE: Otherwise.
+ */
 
-   return(STATUS_SUCCESS);
+BOOLEAN STDCALL
+DiskClassCheckDevice(IN PINQUIRYDATA InquiryData)
+{
+  return((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE ||
+         InquiryData->DeviceType == OPTICAL_DEVICE) &&
+        InquiryData->DeviceTypeQualifier == 0);
 }
 
 
-static BOOLEAN
-DiskFindDiskDrives(PDEVICE_OBJECT PortDeviceObject,
-                  ULONG PortNumber)
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     DiskClassCheckReadWrite
+ *
+ * DESCRIPTION
+ *     This function checks the given IRP for correct data.
+ *
+ * RUN LEVEL
+ *     PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ *     DeviceObject
+ *             Pointer to the device.
+ *
+ *     Irp
+ *             Irp to check.
+ *
+ * RETURN VALUE
+ *     STATUS_SUCCESS: The IRP matches the requirements of the given device.
+ *     Others: Failure.
+ */
+
+NTSTATUS STDCALL
+DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
+                       IN PIRP Irp)
 {
-   DPRINT1("DiskFindDiskDevices() called.\n");
+  PDEVICE_EXTENSION DeviceExtension;
+  PDISK_DATA DiskData;
+
+  DPRINT1("DiskClassCheckReadWrite() called\n");
+
+  DeviceExtension = DeviceObject->DeviceExtension;
+  DiskData = (PDISK_DATA)(DeviceExtension + 1);
+
+  if (DiskData->DriveNotReady == TRUE)
+    {
+      Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
+      IoSetHardErrorOrVerifyDevice(Irp,
+                                  DeviceObject);
+      return(STATUS_INVALID_PARAMETER);
+    }
 
-   return TRUE;
+  return(STATUS_SUCCESS);
 }
 
-//    IDECreateDevice
+
+//    DiskClassCreateDeviceObject
 //
 //  DESCRIPTION:
-//    Creates a device by calling IoCreateDevice and a sylbolic link for Win32
+//    Create the raw device and any partition devices on this drive
 //
 //  RUN LEVEL:
 //    PASSIVE_LEVEL
 //
 //  ARGUMENTS:
-//    IN   PDRIVER_OBJECT      DriverObject      The system supplied driver object
-//    OUT  PDEVICE_OBJECT     *DeviceObject      The created device object
-//    IN   PCONTROLLER_OBJECT  ControllerObject  The Controller for the device
-//    IN   BOOLEAN             LBASupported      Does the drive support LBA addressing?
-//    IN   BOOLEAN             DMASupported      Does the drive support DMA?
-//    IN   int                 SectorsPerLogCyl  Sectors per cylinder
-//    IN   int                 SectorsPerLogTrk  Sectors per track
-//    IN   DWORD               Offset            First valid sector for this device
-//    IN   DWORD               Size              Count of valid sectors for this device
+//    IN  PDRIVER_OBJECT  DriverObject  The system created driver object
+//    IN  PCONTROLLER_OBJECT         ControllerObject
+//    IN  PIDE_CONTROLLER_EXTENSION  ControllerExtension
+//                                      The IDE controller extension for
+//                                      this device
+//    IN  int             DriveIdx      The index of the drive on this
+//                                      controller
+//    IN  int             HarddiskIdx   The NT device number for this
+//                                      drive
 //
 //  RETURNS:
-//    NTSTATUS
+//    TRUE   Drive exists and devices were created
+//    FALSE  no devices were created for this device
 //
-#if 0
-NTSTATUS
-IDECreateDevice(IN PDRIVER_OBJECT DriverObject,
-                OUT PDEVICE_OBJECT *DeviceObject,
-                IN PCONTROLLER_OBJECT ControllerObject,
-                IN int UnitNumber,
-                IN ULONG DiskNumber,
-                IN ULONG PartitionNumber,
-                IN PIDE_DRIVE_IDENTIFY DrvParms,
-                IN DWORD Offset,
-                IN DWORD Size)
+
+static NTSTATUS
+DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
+                           IN PUNICODE_STRING RegistryPath, /* what's this used for? */
+                           IN PDEVICE_OBJECT PortDeviceObject,
+                           IN ULONG PortNumber,
+                           IN ULONG DiskNumber,
+                           IN PIO_SCSI_CAPABILITIES Capabilities,
+                           IN PSCSI_INQUIRY_DATA InquiryData,
+                           IN PCLASS_INIT_DATA InitializationData)
 {
-  WCHAR                  NameBuffer[IDE_MAX_NAME_LENGTH];
-  WCHAR                  ArcNameBuffer[IDE_MAX_NAME_LENGTH + 15];
-  UNICODE_STRING         DeviceName;
-  UNICODE_STRING         ArcName;
-  NTSTATUS               RC;
-  PIDE_DEVICE_EXTENSION  DeviceExtension;
-
-    // Create a unicode device name
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  UNICODE_STRING UnicodeDeviceDirName;
+  WCHAR NameBuffer[80];
+  CHAR NameBuffer2[80];
+  PDEVICE_OBJECT DiskDeviceObject;
+  PDEVICE_OBJECT PartitionDeviceObject;
+  PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
+  PDEVICE_EXTENSION PartitionDeviceExtension; /* defined in class2.h */
+  PDRIVE_LAYOUT_INFORMATION PartitionList = NULL;
+  HANDLE Handle;
+  PPARTITION_INFORMATION PartitionEntry;
+  PDISK_DATA DiskData;
+  ULONG PartitionNumber;
+  NTSTATUS Status;
+
+  DPRINT("DiskClassCreateDeviceObject() called\n");
+
+  /* Create the harddisk device directory */
   swprintf(NameBuffer,
-           L"\\Device\\Harddisk%d\\Partition%d",
-           DiskNumber,
-           PartitionNumber);
-  RtlInitUnicodeString(&DeviceName,
-                       NameBuffer);
-
-    // Create the device
-  RC = IoCreateDevice(DriverObject, sizeof(IDE_DEVICE_EXTENSION),
-      &DeviceName, FILE_DEVICE_DISK, 0, TRUE, DeviceObject);
-  if (!NT_SUCCESS(RC))
+          L"\\Device\\Harddisk%lu",
+          DiskNumber);
+  RtlInitUnicodeString(&UnicodeDeviceDirName,
+                      NameBuffer);
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &UnicodeDeviceDirName,
+                            0,
+                            NULL,
+                            NULL);
+  Status = ZwCreateDirectoryObject(&Handle,
+                                  0,
+                                  &ObjectAttributes);
+  if (!NT_SUCCESS(Status))
+    {
+      DbgPrint("Could not create device dir object\n");
+      return(Status);
+    }
+
+  /* Claim the disk device */
+  Status = ScsiClassClaimDevice(PortDeviceObject,
+                               InquiryData,
+                               FALSE,
+                               &PortDeviceObject);
+  if (!NT_SUCCESS(Status))
+    {
+      DbgPrint("Could not claim disk device\n");
+
+      ZwMakeTemporaryObject(Handle);
+      ZwClose(Handle);
+
+      return(Status);
+    }
+
+  /* Create disk device (Partition 0) */
+  sprintf(NameBuffer2,
+         "\\Device\\Harddisk%lu\\Partition0",
+         DiskNumber);
+
+  Status = ScsiClassCreateDeviceObject(DriverObject,
+                                      NameBuffer2,
+                                      NULL,
+                                      &DiskDeviceObject,
+                                      InitializationData);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
+
+      /* Release (unclaim) the disk */
+      ScsiClassClaimDevice(PortDeviceObject,
+                          InquiryData,
+                          TRUE,
+                          NULL);
+
+      /* Delete the harddisk device directory */
+      ZwMakeTemporaryObject(Handle);
+      ZwClose(Handle);
+
+      return(Status);
+    }
+
+  DiskDeviceObject->Flags |= DO_DIRECT_IO;
+  if (((PINQUIRYDATA)InquiryData->InquiryData)->RemovableMedia)
+    {
+      DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
+    }
+  DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
+
+  if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
     {
-      DPRINT("IoCreateDevice call failed\n",0);
-      return RC;
+      DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
     }
 
-    //  Set the buffering strategy here...
-  (*DeviceObject)->Flags |= DO_DIRECT_IO;
-  (*DeviceObject)->AlignmentRequirement = FILE_WORD_ALIGNMENT;
-
-    //  Fill out Device extension data
-  DeviceExtension = (PIDE_DEVICE_EXTENSION) (*DeviceObject)->DeviceExtension;
-  DeviceExtension->DeviceObject = (*DeviceObject);
-  DeviceExtension->ControllerObject = ControllerObject;
-  DeviceExtension->UnitNumber = UnitNumber;
-  DeviceExtension->LBASupported = 
-    (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0;
-  DeviceExtension->DMASupported = 
-    (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0;
-    // FIXME: deal with bizarre sector sizes
-  DeviceExtension->BytesPerSector = 512 /* DrvParms->BytesPerSector */;
-  DeviceExtension->SectorsPerLogCyl = DrvParms->LogicalHeads *
-      DrvParms->SectorsPerTrack;
-  DeviceExtension->SectorsPerLogTrk = DrvParms->SectorsPerTrack;
-  DeviceExtension->LogicalHeads = DrvParms->LogicalHeads;
-  DeviceExtension->Offset = Offset;
-  DeviceExtension->Size = Size;
-  DPRINT("%wZ: offset %d size %d \n",
-         &DeviceName,
-         DeviceExtension->Offset,
-         DeviceExtension->Size);
-
-    //  Initialize the DPC object here
-  IoInitializeDpcRequest(*DeviceObject, IDEDpcForIsr);
-
-  if (PartitionNumber != 0)
+  DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
+  DiskDeviceExtension->LockCount = 0;
+  DiskDeviceExtension->DeviceNumber = DiskNumber;
+  DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
+  DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
+
+  /* FIXME: Not yet! Will cause pointer corruption! */
+//  DiskDeviceExtension->PortCapabilities = PortCapabilities;
+
+  DiskDeviceExtension->StartingOffset.QuadPart = 0;
+  DiskDeviceExtension->PortNumber = (UCHAR)PortNumber;
+  DiskDeviceExtension->PathId = InquiryData->PathId;
+  DiskDeviceExtension->TargetId = InquiryData->TargetId;
+  DiskDeviceExtension->Lun = InquiryData->Lun;
+
+  /* zero-out disk data */
+  DiskData = (PDISK_DATA)(DiskDeviceExtension + 1);
+  RtlZeroMemory(DiskData,
+               sizeof(DISK_DATA));
+
+  /* Get disk geometry */
+  DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
+                                                    sizeof(DISK_GEOMETRY));
+  if (DiskDeviceExtension->DiskGeometry == NULL)
     {
-      DbgPrint("%wZ %dMB\n", &DeviceName, Size / 2048);
+      DPRINT1("Failed to allocate geometry buffer!\n");
+
+      IoDeleteDevice(DiskDeviceObject);
+
+      /* Release (unclaim) the disk */
+      ScsiClassClaimDevice(PortDeviceObject,
+                          InquiryData,
+                          TRUE,
+                          NULL);
+
+      /* Delete the harddisk device directory */
+      ZwMakeTemporaryObject(Handle);
+      ZwClose(Handle);
+
+      return(STATUS_INSUFFICIENT_RESOURCES);
     }
 
-  /* assign arc name */
-  if (PartitionNumber == 0)
+  /* Read the drive's capacity */
+  Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
+  if (!NT_SUCCESS(Status) &&
+      (DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0)
     {
-      swprintf(ArcNameBuffer,
-               L"\\ArcName\\multi(0)disk(0)rdisk(%d)",
-               DiskNumber);
+      DPRINT1("Failed to retrieve drive capacity!\n");
+      return(STATUS_SUCCESS);
     }
   else
     {
-      swprintf(ArcNameBuffer,
-               L"\\ArcName\\multi(0)disk(0)rdisk(%d)partition(%d)",
-               DiskNumber,
-               PartitionNumber);
+      /* Clear the verify flag for removable media drives. */
+      DiskDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
     }
-  RtlInitUnicodeString (&ArcName,
-                        ArcNameBuffer);
-  DPRINT("%wZ ==> %wZ\n", &ArcName, &DeviceName);
-  RC = IoAssignArcName (&ArcName,
-                        &DeviceName);
-  if (!NT_SUCCESS(RC))
+
+  DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
+
+  /* Read partition table */
+  Status = IoReadPartitionTable(DiskDeviceObject,
+                               DiskDeviceExtension->DiskGeometry->BytesPerSector,
+                               TRUE,
+                               &PartitionList);
+
+  DPRINT("IoReadPartitionTable(): Status: %lx\n", Status);
+
+  if ((!NT_SUCCESS(Status) || PartitionList->PartitionCount == 0) &&
+      DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
     {
-      DPRINT("IoAssignArcName (%wZ) failed (Status %x)\n",
-             &ArcName, RC);
+      if (!NT_SUCCESS(Status))
+       {
+         /* Drive is not ready. */
+         DPRINT1("Drive not ready\n");
+         DiskData->DriveNotReady = TRUE;
+       }
+      else
+       {
+         ExFreePool(PartitionList);
+       }
+
+      /* Allocate a partition list for a single entry. */
+      PartitionList = ExAllocatePool(NonPagedPool,
+                                    sizeof(DRIVE_LAYOUT_INFORMATION));
+      if (PartitionList != NULL)
+       {
+         RtlZeroMemory(PartitionList,
+                       sizeof(DRIVE_LAYOUT_INFORMATION));
+         PartitionList->PartitionCount = 1;
+
+         Status = STATUS_SUCCESS;
+       }
     }
 
+  if (NT_SUCCESS(Status))
+    {
+      DPRINT("Read partition table!\n");
+
+      DPRINT("  Number of partitions: %u\n", PartitionList->PartitionCount);
+
+      for (PartitionNumber = 0; PartitionNumber < PartitionList->PartitionCount; PartitionNumber++)
+       {
+         PartitionEntry = &PartitionList->PartitionEntry[PartitionNumber];
+
+         DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
+                PartitionNumber,
+                PartitionEntry->PartitionNumber,
+                PartitionEntry->BootIndicator,
+                PartitionEntry->PartitionType,
+                PartitionEntry->StartingOffset.QuadPart / 512 /*DrvParms.BytesPerSector*/,
+                PartitionEntry->PartitionLength.QuadPart / 512 /* DrvParms.BytesPerSector*/);
+
+         /* Create partition device object */
+         sprintf(NameBuffer2,
+                 "\\Device\\Harddisk%lu\\Partition%lu",
+                 DiskNumber,
+                 PartitionNumber + 1);
+
+         Status = ScsiClassCreateDeviceObject(DriverObject,
+                                              NameBuffer2,
+                                              DiskDeviceObject,
+                                              &PartitionDeviceObject,
+                                              InitializationData);
+         DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status);
+         if (NT_SUCCESS(Status))
+           {
+             PartitionDeviceObject->Flags = DiskDeviceObject->Flags;
+             PartitionDeviceObject->Characteristics = DiskDeviceObject->Characteristics;
+             PartitionDeviceObject->StackSize = DiskDeviceObject->StackSize;
+             PartitionDeviceObject->AlignmentRequirement = DiskDeviceObject->AlignmentRequirement;
+
+             PartitionDeviceExtension = PartitionDeviceObject->DeviceExtension;
+             PartitionDeviceExtension->LockCount = 0;
+             PartitionDeviceExtension->DeviceNumber = DiskNumber;
+             PartitionDeviceExtension->PortDeviceObject = PortDeviceObject;
+             PartitionDeviceExtension->DiskGeometry = DiskDeviceExtension->DiskGeometry;
+             PartitionDeviceExtension->PhysicalDevice = DiskDeviceExtension->PhysicalDevice;
+
+         /* FIXME: Not yet! Will cause pointer corruption! */
+//       PartitionDeviceExtension->PortCapabilities = PortCapabilities;
+
+             PartitionDeviceExtension->StartingOffset.QuadPart =
+               PartitionEntry->StartingOffset.QuadPart;
+             PartitionDeviceExtension->PartitionLength.QuadPart =
+               PartitionEntry->PartitionLength.QuadPart;
+             PartitionDeviceExtension->PortNumber = (UCHAR)PortNumber;
+             PartitionDeviceExtension->PathId = InquiryData->PathId;
+             PartitionDeviceExtension->TargetId = InquiryData->TargetId;
+             PartitionDeviceExtension->Lun = InquiryData->Lun;
+             PartitionDeviceExtension->SectorShift = DiskDeviceExtension->SectorShift;
+
+             DiskData = (PDISK_DATA)(PartitionDeviceExtension + 1);
+             DiskData->PartitionType = PartitionEntry->PartitionType;
+             DiskData->PartitionNumber = PartitionNumber + 1;
+             DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
+             DiskData->BootIndicator = PartitionEntry->BootIndicator;
+             DiskData->DriveNotReady = FALSE;
+           }
+         else
+           {
+             DPRINT1("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status);
+
+             break;
+           }
+       }
+
+
+    }
+
+  if (PartitionList != NULL)
+    ExFreePool(PartitionList);
 
-  return  RC;
+  DPRINT("DiskClassCreateDeviceObjects() done\n");
+
+  return(STATUS_SUCCESS);
 }
-#endif
 
 
 
 
-//    IDEDispatchDeviceControl
+
+//    DiskClassDeviceControl
 //
 //  DESCRIPTION:
 //    Answer requests for device control calls
@@ -320,79 +670,197 @@ IDECreateDevice(IN PDRIVER_OBJECT DriverObject,
 //  RETURNS:
 //    NTSTATUS
 //
-#if 0
-static  NTSTATUS  STDCALL
-IDEDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject,
-                         IN PIRP Irp) 
+
+NTSTATUS STDCALL
+DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
+                      IN PIRP Irp)
 {
-  NTSTATUS  RC;
-  ULONG     ControlCode, InputLength, OutputLength;
-  PIO_STACK_LOCATION     IrpStack;
-  PIDE_DEVICE_EXTENSION  DeviceExtension;
+  PDEVICE_EXTENSION DeviceExtension;
+  PIO_STACK_LOCATION IrpStack;
+  ULONG ControlCode, InputLength, OutputLength;
+  PDISK_DATA DiskData;
+  ULONG Information;
+  NTSTATUS Status;
+
+  DPRINT("DiskClassDeviceControl() called!\n");
 
-  RC = STATUS_SUCCESS;
+  Status = STATUS_INVALID_DEVICE_REQUEST;
+  Information = 0;
   IrpStack = IoGetCurrentIrpStackLocation(Irp);
   ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
   InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
   OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
-  DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
+  DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+  DiskData = (PDISK_DATA)(DeviceExtension + 1);
 
-    //  A huge switch statement in a Windows program?! who would have thought?
-  switch (ControlCode) 
+  /* A huge switch statement in a Windows program?! who would have thought? */
+  switch (ControlCode)
     {
-    case IOCTL_DISK_GET_DRIVE_GEOMETRY:
-      if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) 
-        {
-          Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-        } 
-      else 
-        {
-          PDISK_GEOMETRY Geometry;
-
-          Geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
-          Geometry->MediaType = FixedMedia;
-              // FIXME: should report for RawDevice even on partition
-          Geometry->Cylinders.QuadPart = DeviceExtension->Size / 
-              DeviceExtension->SectorsPerLogCyl;
-          Geometry->TracksPerCylinder = DeviceExtension->SectorsPerLogTrk /
-              DeviceExtension->SectorsPerLogCyl;
-          Geometry->SectorsPerTrack = DeviceExtension->SectorsPerLogTrk;
-          Geometry->BytesPerSector = DeviceExtension->BytesPerSector;
-
-          Irp->IoStatus.Status = STATUS_SUCCESS;
-          Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
-        }
-      break;
-
-    case IOCTL_DISK_GET_PARTITION_INFO:
-    case IOCTL_DISK_SET_PARTITION_INFO:
-    case IOCTL_DISK_GET_DRIVE_LAYOUT:
-    case IOCTL_DISK_SET_DRIVE_LAYOUT:
-    case IOCTL_DISK_VERIFY:
-    case IOCTL_DISK_FORMAT_TRACKS:
-    case IOCTL_DISK_PERFORMANCE:
-    case IOCTL_DISK_IS_WRITABLE:
-    case IOCTL_DISK_LOGGING:
-    case IOCTL_DISK_FORMAT_TRACKS_EX:
-    case IOCTL_DISK_HISTOGRAM_STRUCTURE:
-    case IOCTL_DISK_HISTOGRAM_DATA:
-    case IOCTL_DISK_HISTOGRAM_RESET:
-    case IOCTL_DISK_REQUEST_STRUCTURE:
-    case IOCTL_DISK_REQUEST_DATA:
-
-      //  If we get here, something went wrong.  inform the requestor
-    default:
-      RC = STATUS_INVALID_DEVICE_REQUEST;
-      Irp->IoStatus.Status = RC;
-      Irp->IoStatus.Information = 0;
-      break;
+      case IOCTL_DISK_GET_DRIVE_GEOMETRY:
+       DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
+       if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
+         {
+           Status = STATUS_INVALID_PARAMETER;
+         }
+       else if (DeviceExtension->DiskGeometry == NULL)
+         {
+           DPRINT1("No disk geometry available!\n");
+           Status = STATUS_NO_SUCH_DEVICE;
+         }
+       else
+         {
+           PDISK_GEOMETRY Geometry;
+
+           Geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
+           RtlMoveMemory(Geometry,
+                         DeviceExtension->DiskGeometry,
+                         sizeof(DISK_GEOMETRY));
+
+           Status = STATUS_SUCCESS;
+           Information = sizeof(DISK_GEOMETRY);
+         }
+       break;
+
+      case IOCTL_DISK_GET_PARTITION_INFO:
+       DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
+       if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
+           sizeof(PARTITION_INFORMATION))
+         {
+           Status = STATUS_INFO_LENGTH_MISMATCH;
+         }
+       else if (DiskData->PartitionNumber == 0)
+         {
+           Status = STATUS_INVALID_DEVICE_REQUEST;
+         }
+       else
+         {
+           PPARTITION_INFORMATION PartitionInfo;
+
+           PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+           PartitionInfo->PartitionType = DiskData->PartitionType;
+           PartitionInfo->StartingOffset = DeviceExtension->StartingOffset;
+           PartitionInfo->PartitionLength = DeviceExtension->PartitionLength;
+           PartitionInfo->HiddenSectors = DiskData->HiddenSectors;
+           PartitionInfo->PartitionNumber = DiskData->PartitionNumber;
+           PartitionInfo->BootIndicator = DiskData->BootIndicator;
+           PartitionInfo->RewritePartition = FALSE;
+           PartitionInfo->RecognizedPartition =
+             IsRecognizedPartition(DiskData->PartitionType);
+
+           Status = STATUS_SUCCESS;
+           Information = sizeof(PARTITION_INFORMATION);
+         }
+       break;
+
+      case IOCTL_DISK_SET_PARTITION_INFO:
+       DPRINT1("Unhandled IOCTL_DISK_SET_PARTITION_INFO\n");
+       Status = STATUS_INVALID_DEVICE_REQUEST;
+       Information = 0;
+       break;
+
+      case IOCTL_DISK_GET_DRIVE_LAYOUT:
+       if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
+           sizeof(DRIVE_LAYOUT_INFORMATION))
+         {
+           Status = STATUS_BUFFER_TOO_SMALL;
+         }
+       else
+         {
+           PDRIVE_LAYOUT_INFORMATION PartitionList;
+
+           Status = IoReadPartitionTable(DeviceExtension->PhysicalDevice,
+                                         DeviceExtension->DiskGeometry->BytesPerSector,
+                                         FALSE,
+                                         &PartitionList);
+           if (NT_SUCCESS(Status))
+             {
+               ULONG BufferSize;
+
+               BufferSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
+                                         PartitionEntry[0]);
+               BufferSize += PartitionList->PartitionCount * sizeof(PARTITION_INFORMATION);
+
+               if (BufferSize > IrpStack->Parameters.DeviceIoControl.OutputBufferLength)
+                 {
+                   Status = STATUS_BUFFER_TOO_SMALL;
+                 }
+               else
+                 {
+                   RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
+                                 PartitionList,
+                                 BufferSize);
+                   Status = STATUS_SUCCESS;
+                   Information = BufferSize;
+                 }
+               ExFreePool(PartitionList);
+             }
+         }
+       break;
+
+      case IOCTL_DISK_SET_DRIVE_LAYOUT:
+      case IOCTL_DISK_VERIFY:
+      case IOCTL_DISK_FORMAT_TRACKS:
+      case IOCTL_DISK_PERFORMANCE:
+      case IOCTL_DISK_IS_WRITABLE:
+      case IOCTL_DISK_LOGGING:
+      case IOCTL_DISK_FORMAT_TRACKS_EX:
+      case IOCTL_DISK_HISTOGRAM_STRUCTURE:
+      case IOCTL_DISK_HISTOGRAM_DATA:
+      case IOCTL_DISK_HISTOGRAM_RESET:
+      case IOCTL_DISK_REQUEST_STRUCTURE:
+      case IOCTL_DISK_REQUEST_DATA:
+
+      /* If we get here, something went wrong.  inform the requestor */
+      default:
+       DPRINT1("Unhandled control code: %lx\n", ControlCode);
+       Status = STATUS_INVALID_DEVICE_REQUEST;
+       Information = 0;
+       break;
     }
 
+  Irp->IoStatus.Status = Status;
+  Irp->IoStatus.Information = Information;
+  IoCompleteRequest(Irp,
+                   IO_NO_INCREMENT);
+
+  return(Status);
+}
+
+
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     DiskClassShutdownFlush
+ *
+ * DESCRIPTION
+ *     Answer requests for shutdown and flush calls.
+ *
+ * RUN LEVEL
+ *     PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ *     DeviceObject
+ *             Pointer to the device.
+ *
+ *     Irp
+ *             Pointer to the IRP
+ *
+ * RETURN VALUE
+ *     Status
+ */
+
+NTSTATUS STDCALL
+DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
+                      IN PIRP Irp)
+{
+  DPRINT("DiskClassShutdownFlush() called!\n");
+
+  Irp->IoStatus.Status = STATUS_SUCCESS;
+  Irp->IoStatus.Information = 0;
   IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
-  return  RC;
+  return(STATUS_SUCCESS);
 }
-#endif
 
 
 /* EOF */