Started support for removable disk drives.
[reactos.git] / reactos / drivers / storage / disk / disk.c
index ecc724a..7ad5a19 100644 (file)
@@ -1,5 +1,28 @@
-/* $Id: disk.c,v 1.6 2002/03/01 23:18:35 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 *****************************************************************/
@@ -13,7 +36,7 @@
 #define NDEBUG
 #include <debug.h>
 
-#define VERSION "V0.0.1"
+#define VERSION  "0.0.1"
 
 
 typedef struct _DISK_DATA
@@ -198,7 +221,7 @@ DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
       return(FALSE);
     }
 
-  DPRINT1("Found %lu unclaimed devices!\n", DeviceCount);
+  DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
 
   ConfigInfo = IoGetConfigurationInformation();
 
@@ -218,7 +241,7 @@ DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
              (InquiryData->DeviceTypeQualifier == 0) &&
              (UnitInfo->DeviceClaimed == FALSE))
            {
-             DPRINT1("Vendor: '%.24s'\n",
+             DPRINT("Vendor: '%.24s'\n",
                     InquiryData->VendorId);
 
              /* Create device objects for disk */
@@ -282,11 +305,47 @@ DiskClassCheckDevice(IN PINQUIRYDATA InquiryData)
 }
 
 
+/**********************************************************************
+ * 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)
 {
-  DPRINT("DiskClassCheckReadWrite() 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(STATUS_SUCCESS);
 }
@@ -341,12 +400,7 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
   ULONG PartitionNumber;
   NTSTATUS Status;
 
-  WCHAR ArcNameBuffer[120];
-  UNICODE_STRING ArcName;
-  ANSI_STRING DeviceNameA;
-  UNICODE_STRING DeviceName;
-
-  DPRINT1("DiskClassCreateDeviceObject() called\n");
+  DPRINT("DiskClassCreateDeviceObject() called\n");
 
   /* Create the harddisk device directory */
   swprintf(NameBuffer,
@@ -423,11 +477,10 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
     }
 
   DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
-//  DiskData = (PDISK_DEVICE_EXTENSION)((PUCHAR)DiskDeviceExtension + sizeof(DEVICE_EXTENSION));
-
   DiskDeviceExtension->LockCount = 0;
   DiskDeviceExtension->DeviceNumber = DiskNumber;
   DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
+  DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
 
   /* FIXME: Not yet! Will cause pointer corruption! */
 //  DiskDeviceExtension->PortCapabilities = PortCapabilities;
@@ -475,35 +528,11 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
     }
   else
     {
-      /* Clear the verify flag for non-removable media drives. */
+      /* Clear the verify flag for removable media drives. */
       DiskDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
     }
 
-  DPRINT1("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
-
-  /* assign arc name */
-  RtlInitAnsiString(&DeviceNameA,
-                   NameBuffer2);
-  RtlAnsiStringToUnicodeString(&DeviceName,
-                              &DeviceNameA,
-                              TRUE);
-  swprintf(ArcNameBuffer,
-          L"\\ArcName\\multi(0)disk(0)rdisk(%lu)",
-          DiskNumber);
-  RtlInitUnicodeString(&ArcName,
-                      ArcNameBuffer);
-  DPRINT1("ArcNameBuffer '%S'\n", ArcNameBuffer);
-  DPRINT1("%wZ ==> %wZ\n", &ArcName, &DeviceName);
-  Status = IoAssignArcName(&ArcName,
-                          &DeviceName);
-  RtlFreeUnicodeString(&DeviceName);
-
-  if (!NT_SUCCESS(Status))
-    {
-      DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName, Status);
-      KeBugCheck(0);
-    }
-
+  DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
 
   /* Read partition table */
   Status = IoReadPartitionTable(DiskDeviceObject,
@@ -511,7 +540,7 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
                                TRUE,
                                &PartitionList);
 
-  DPRINT1("IoReadPartitionTable(): Status: %lx\n", Status);
+  DPRINT("IoReadPartitionTable(): Status: %lx\n", Status);
 
   if ((!NT_SUCCESS(Status) || PartitionList->PartitionCount == 0) &&
       DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
@@ -519,7 +548,8 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
       if (!NT_SUCCESS(Status))
        {
          /* Drive is not ready. */
-//       diskData->DriveNotReady = TRUE;
+         DPRINT1("Drive not ready\n");
+         DiskData->DriveNotReady = TRUE;
        }
       else
        {
@@ -541,7 +571,7 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
 
   if (NT_SUCCESS(Status))
     {
-      DPRINT1("Read partition table!\n");
+      DPRINT("Read partition table!\n");
 
       DPRINT("  Number of partitions: %u\n", PartitionList->PartitionCount);
 
@@ -549,15 +579,15 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
        {
          PartitionEntry = &PartitionList->PartitionEntry[PartitionNumber];
 
-         DPRINT1("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*/);
+         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 (Partition 0) */
+         /* Create partition device object */
          sprintf(NameBuffer2,
                  "\\Device\\Harddisk%lu\\Partition%lu",
                  DiskNumber,
@@ -568,7 +598,7 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
                                               DiskDeviceObject,
                                               &PartitionDeviceObject,
                                               InitializationData);
-         DPRINT1("ScsiClassCreateDeviceObject(): Status %x\n", Status);
+         DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status);
          if (NT_SUCCESS(Status))
            {
              PartitionDeviceObject->Flags = DiskDeviceObject->Flags;
@@ -581,6 +611,7 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
              PartitionDeviceExtension->DeviceNumber = DiskNumber;
              PartitionDeviceExtension->PortDeviceObject = PortDeviceObject;
              PartitionDeviceExtension->DiskGeometry = DiskDeviceExtension->DiskGeometry;
+             PartitionDeviceExtension->PhysicalDevice = DiskDeviceExtension->PhysicalDevice;
 
          /* FIXME: Not yet! Will cause pointer corruption! */
 //       PartitionDeviceExtension->PortCapabilities = PortCapabilities;
@@ -593,6 +624,7 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
              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;
@@ -600,32 +632,6 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
              DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
              DiskData->BootIndicator = PartitionEntry->BootIndicator;
              DiskData->DriveNotReady = FALSE;
-
-
-             /* assign arc name */
-             RtlInitAnsiString(&DeviceNameA,
-                               NameBuffer2);
-             RtlAnsiStringToUnicodeString(&DeviceName,
-                                          &DeviceNameA,
-                                          TRUE);
-             swprintf(ArcNameBuffer,
-                      L"\\ArcName\\multi(0)disk(0)rdisk(%lu)partition(%lu)",
-                      DiskNumber,
-                      PartitionNumber + 1);
-             RtlInitUnicodeString(&ArcName,
-                                  ArcNameBuffer);
-             DPRINT1("ArcNameBuffer '%S'\n", ArcNameBuffer);
-             DPRINT1("%wZ ==> %wZ\n", &ArcName, &DeviceName);
-             Status = IoAssignArcName(&ArcName,
-                                      &DeviceName);
-             RtlFreeUnicodeString(&DeviceName);
-
-             if (!NT_SUCCESS(Status))
-               {
-                 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName, Status);
-                 KeBugCheck(0);
-               }
-
            }
          else
            {
@@ -641,7 +647,7 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
   if (PartitionList != NULL)
     ExFreePool(PartitionList);
 
-  DPRINT1("DiskClassCreateDeviceObjects() done\n");
+  DPRINT("DiskClassCreateDeviceObjects() done\n");
 
   return(STATUS_SUCCESS);
 }
@@ -673,27 +679,33 @@ DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
   PIO_STACK_LOCATION IrpStack;
   ULONG ControlCode, InputLength, OutputLength;
   PDISK_DATA DiskData;
+  ULONG Information;
   NTSTATUS Status;
 
-  DPRINT1("DiskClassDeviceControl() called!\n");
+  DPRINT("DiskClassDeviceControl() called!\n");
 
-  Status = 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 = (PDEVICE_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)
     {
       case IOCTL_DISK_GET_DRIVE_GEOMETRY:
-       DPRINT1("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
+       DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
        if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
          {
-           Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-           Irp->IoStatus.Information = 0;
+           Status = STATUS_INVALID_PARAMETER;
+         }
+       else if (DeviceExtension->DiskGeometry == NULL)
+         {
+           DPRINT1("No disk geometry available!\n");
+           Status = STATUS_NO_SUCH_DEVICE;
          }
        else
          {
@@ -704,37 +716,21 @@ DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
                          DeviceExtension->DiskGeometry,
                          sizeof(DISK_GEOMETRY));
 
-#if 0
-
-  RtlCopyMemory(DiskData->Geometry,
-               DiskDeviceExtension->DiskGeometry,
-               sizeof(DISK_GEOMETRY));
-          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;
-#endif
-           Irp->IoStatus.Status = STATUS_SUCCESS;
-           Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
+           Status = STATUS_SUCCESS;
+           Information = sizeof(DISK_GEOMETRY);
          }
        break;
 
       case IOCTL_DISK_GET_PARTITION_INFO:
-       DPRINT1("IOCTL_DISK_GET_PARTITION_INFO\n");
+       DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
        if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
            sizeof(PARTITION_INFORMATION))
          {
-           Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
-           Irp->IoStatus.Information = 0;
+           Status = STATUS_INFO_LENGTH_MISMATCH;
          }
        else if (DiskData->PartitionNumber == 0)
          {
-           Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
-           Irp->IoStatus.Information = 0;
+           Status = STATUS_INVALID_DEVICE_REQUEST;
          }
        else
          {
@@ -752,13 +748,56 @@ DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
            PartitionInfo->RecognizedPartition =
              IsRecognizedPartition(DiskData->PartitionType);
 
-           Irp->IoStatus.Status = STATUS_SUCCESS;
-           Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
+           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:
@@ -776,11 +815,12 @@ DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
       default:
        DPRINT1("Unhandled control code: %lx\n", ControlCode);
        Status = STATUS_INVALID_DEVICE_REQUEST;
-       Irp->IoStatus.Status = Status;
-       Irp->IoStatus.Information = 0;
+       Information = 0;
        break;
     }
 
+  Irp->IoStatus.Status = Status;
+  Irp->IoStatus.Information = Information;
   IoCompleteRequest(Irp,
                    IO_NO_INCREMENT);
 
@@ -788,20 +828,26 @@ DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
 }
 
 
-//    DiskClassShutdownFlush
-//
-//  DESCRIPTION:
-//    Answer requests for shutdown and flush calls
-//
-//  RUN LEVEL:
-//    PASSIVE_LEVEL
-//
-//  ARGUMENTS:
-//    Standard dispatch arguments
-//
-//  RETURNS:
-//    NTSTATUS
-//
+/**********************************************************************
+ * 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,