Check for removable media and Partition length is 0, for DiskClassCheckReadWrite.
[reactos.git] / reactos / drivers / storage / disk / disk.c
index d97a0ad..b0e8904 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ReactOS kernel
- *  Copyright (C) 2001, 2002, 2003 ReactOS Team
+ *  Copyright (C) 2001, 2002, 2003, 2004 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
  *  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.34 2004/01/09 20:21:31 gvg Exp $
+/* $Id$
  *
  * 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)
+ * PROGRAMMER:      Eric Kohl
  */
 
 /* INCLUDES *****************************************************************/
@@ -54,7 +54,6 @@ typedef struct _DISK_DATA
   BOOLEAN DriveNotReady;
 } DISK_DATA, *PDISK_DATA;
 
-
 BOOLEAN STDCALL
 DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
                     PUNICODE_STRING RegistryPath,
@@ -69,6 +68,9 @@ NTSTATUS STDCALL
 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
                        IN PIRP Irp);
 
+static VOID
+DiskClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
+                                IN ULONG DeviceNumber); 
 
 static NTSTATUS
 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
@@ -105,6 +107,11 @@ ScsiDiskCalcMbrCheckSum(IN PDEVICE_EXTENSION DeviceExtension,
                        OUT PULONG Checksum);
 
 
+static NTSTATUS
+DiskBuildPartitionTable(IN PDEVICE_OBJECT DiskDeviceObject,
+                     IN PIRP Irp);
+
+
 /* FUNCTIONS ****************************************************************/
 
 /**********************************************************************
@@ -211,7 +218,7 @@ DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
   PCHAR Buffer;
   ULONG Bus;
   ULONG DeviceCount;
-  BOOLEAN FoundDevice;
+  BOOLEAN FoundDevice = FALSE;
   NTSTATUS Status;
 
   DPRINT("DiskClassFindDevices() called.\n");
@@ -304,6 +311,28 @@ DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
 }
 
 
+static VOID
+DiskClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
+                                IN ULONG DeviceNumber)
+{
+  WCHAR NameBuffer[MAX_PATH];
+  UNICODE_STRING Name;
+
+  swprintf (NameBuffer,
+           L"\\Device\\MediaChangeEvent%lu",
+           DeviceNumber);
+  RtlInitUnicodeString (&Name,
+                       NameBuffer);
+
+  DeviceExtension->MediaChangeEvent =
+    IoCreateSynchronizationEvent (&Name,
+                                 &DeviceExtension->MediaChangeEventHandle);
+
+  KeClearEvent (DeviceExtension->MediaChangeEvent);
+}
+
+
+
 /**********************************************************************
  * NAME                                                        EXPORTED
  *     DiskClassCheckDevice
@@ -361,6 +390,8 @@ DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
 {
   PDEVICE_EXTENSION DeviceExtension;
   PDISK_DATA DiskData;
+  PIO_STACK_LOCATION IrpStack;
+  ULARGE_INTEGER EndingOffset;
 
   DPRINT("DiskClassCheckReadWrite() called\n");
 
@@ -375,6 +406,32 @@ DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
       return(STATUS_INVALID_PARAMETER);
     }
 
+
+
+  IrpStack = IoGetCurrentIrpStackLocation(Irp);  
+  EndingOffset.QuadPart = IrpStack->Parameters.Read.ByteOffset.QuadPart +
+                          IrpStack->Parameters.Read.Length;
+
+
+  DPRINT("Ending %I64d, and RealEnding %I64d! PartSize %I64d\n",EndingOffset.QuadPart,
+          DeviceExtension->PartitionLength.QuadPart,
+         DeviceExtension->PartitionLength.QuadPart /
+          DeviceExtension->DiskGeometry->BytesPerSector);
+
+  if ((DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
+      (DeviceExtension->DiskGeometry->MediaType == RemovableMedia))
+    {
+/* Assume if removable media and if Partition length is 0, Partition not built yet! */
+       if (DeviceExtension->PartitionLength.QuadPart == 0)
+            return(STATUS_SUCCESS);
+    }
+
+  if (EndingOffset.QuadPart > DeviceExtension->PartitionLength.QuadPart)
+    {
+      Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+      return(STATUS_INVALID_PARAMETER);
+    }
+
   return(STATUS_SUCCESS);
 }
 
@@ -519,6 +576,14 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
   DiskDeviceExtension->PathId = InquiryData->PathId;
   DiskDeviceExtension->TargetId = InquiryData->TargetId;
   DiskDeviceExtension->Lun = InquiryData->Lun;
+  DiskDeviceExtension->SrbFlags = 0;
+
+  /* Enable the command queueing, if it possible */
+  if (Capabilities->TaggedQueuing &&
+      ((PINQUIRYDATA)InquiryData->InquiryData)->CommandQueue)
+    {
+      DiskDeviceExtension->SrbFlags |= SRB_FLAGS_QUEUE_ACTION_ENABLE;
+    }
 
   /* Get timeout value */
   DiskDeviceExtension->TimeOutValue =
@@ -560,8 +625,8 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
     }
 
   /* Allocate sense data buffer */
-  DiskDeviceExtension->SenseData = ExAllocatePool(NonPagedPool,
-                                                 sizeof(SENSE_BUFFER_SIZE));
+  DiskDeviceExtension->SenseData = ExAllocatePool(NonPagedPoolCacheAligned,
+                                                 SENSE_BUFFER_SIZE);
   if (DiskDeviceExtension->SenseData == NULL)
     {
       DPRINT("Failed to allocate sense data buffer!\n");
@@ -590,7 +655,7 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
   if (!NT_SUCCESS(Status) &&
       (DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0)
     {
-      DPRINT1("Failed to retrieve drive capacity!\n");
+      DPRINT("Failed to retrieve drive capacity!\n");
       return(STATUS_SUCCESS);
     }
   else
@@ -601,6 +666,16 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
 
   DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
 
+  if ((DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
+      (DiskDeviceExtension->DiskGeometry->MediaType == RemovableMedia))
+    {
+      DiskClassCreateMediaChangeEvent(DiskDeviceExtension,DiskNumber); 
+      if (DiskDeviceExtension->MediaChangeEvent != NULL)
+       {
+         DPRINT("Allocated media change event!\n");
+       }
+    }
+
   /* Check disk for presence of a disk manager */
   HalExamineMBR(DiskDeviceObject,
                DiskDeviceExtension->DiskGeometry->BytesPerSector,
@@ -717,8 +792,10 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
                 PartitionEntry->PartitionNumber,
                 PartitionEntry->BootIndicator,
                 PartitionEntry->PartitionType,
-                PartitionEntry->StartingOffset.QuadPart / 512 /*DrvParms.BytesPerSector*/,
-                PartitionEntry->PartitionLength.QuadPart / 512 /* DrvParms.BytesPerSector*/);
+                PartitionEntry->StartingOffset.QuadPart /
+                  DiskDeviceExtension->DiskGeometry->BytesPerSector,
+                PartitionEntry->PartitionLength.QuadPart /
+                  DiskDeviceExtension->DiskGeometry->BytesPerSector);
 
          /* Create partition device object */
          sprintf(NameBuffer2,
@@ -729,7 +806,7 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
          Status = ScsiClassCreateDeviceObject(DriverObject,
                                               NameBuffer2,
                                               DiskDeviceObject,
-                                              &PartitionDeviceObject,
+                                              &PartitionDeviceObject ,
                                               InitializationData);
          DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status);
          if (NT_SUCCESS(Status))
@@ -781,7 +858,7 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
            }
          else
            {
-             DPRINT1("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status);
+             DPRINT("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status);
 
              break;
            }
@@ -797,6 +874,111 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
 }
 
 
+static NTSTATUS
+DiskBuildPartitionTable(IN PDEVICE_OBJECT DiskDeviceObject,
+                        IN PIRP Irp)
+{
+  PDRIVE_LAYOUT_INFORMATION PartitionList = NULL;
+  PDEVICE_EXTENSION DiskDeviceExtension, DDE;
+  PDISK_DATA DiskData, DD;
+  PPARTITION_INFORMATION PartitionEntry;
+  ULONG PartitionNumber;
+  NTSTATUS Status;
+
+  DPRINT("DiskBuildPartitionTable() start\n");
+
+  DiskDeviceExtension = (PDEVICE_EXTENSION)DiskDeviceObject->DeviceExtension;
+  DiskData = (PDISK_DATA)(DiskDeviceExtension + 1);
+
+  DDE = (PDEVICE_EXTENSION) DiskDeviceExtension->PhysicalDevice->DeviceExtension;
+  DD = (PDISK_DATA)(DDE +1);
+
+  /* Clear flag for Partition0, just incase it was set. */
+  DD->DriveNotReady = FALSE;
+
+  Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
+  if (!NT_SUCCESS(Status))
+    {
+      /* Drive is not ready. */
+      DPRINT("Drive not ready\n");
+      DiskData->DriveNotReady = TRUE;
+      return Status;
+    }
+
+  /* Read partition table */
+  Status = IoReadPartitionTable(DiskDeviceExtension->PhysicalDevice,
+                               DiskDeviceExtension->DiskGeometry->BytesPerSector,
+                               TRUE,
+                               &PartitionList);
+
+  DPRINT("IoReadPartitionTable(): Status: %lx\n", Status);
+
+  if (!NT_SUCCESS(Status))
+    {
+      /* Drive is not ready. */
+      DPRINT("Drive not ready\n");
+      DiskData->DriveNotReady = TRUE;
+      if (PartitionList != NULL)
+       ExFreePool(PartitionList);
+      return Status;
+    }
+
+  if (NT_SUCCESS(Status))
+    {
+      DPRINT("Read partition table!\n");
+      DPRINT("  Number of partitions: %u\n", PartitionList->PartitionCount);
+
+      /* Set disk signature */
+      DiskData->Signature = PartitionList->Signature;
+
+      DiskData->NextPartition = NULL;
+
+      if (PartitionList->PartitionCount)
+        {
+         for (PartitionNumber = 0; PartitionNumber < PartitionList->PartitionCount; PartitionNumber++)
+           {
+             PartitionEntry = &PartitionList->PartitionEntry[PartitionNumber];
+
+             DiskData->PartitionType = PartitionEntry->PartitionType;
+             DiskData->PartitionNumber = PartitionNumber + 1;
+             DiskData->PartitionOrdinal = PartitionNumber + 1;
+             DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
+             DiskData->BootIndicator = PartitionEntry->BootIndicator;
+             DiskData->DriveNotReady = FALSE;
+             DiskDeviceExtension->StartingOffset = PartitionEntry->StartingOffset;
+             DiskDeviceExtension->PartitionLength = PartitionEntry->PartitionLength;
+
+             DPRINT1("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
+                     PartitionNumber,
+                     DiskData->PartitionNumber,
+                     DiskData->BootIndicator,
+                     DiskData->PartitionType,
+                     DiskDeviceExtension->StartingOffset.QuadPart /
+                       DiskDeviceExtension->DiskGeometry->BytesPerSector,
+                     DiskDeviceExtension->PartitionLength.QuadPart /
+                       DiskDeviceExtension->DiskGeometry->BytesPerSector);
+           }
+       }
+      else
+       {
+         DiskData->PartitionType = 0;
+         DiskData->PartitionNumber = 1;
+         DiskData->PartitionOrdinal = 0;
+         DiskData->HiddenSectors = 0;
+         DiskData->BootIndicator = 0;
+         DiskData->DriveNotReady = FALSE;
+         DiskDeviceExtension->StartingOffset.QuadPart = 0;
+         DiskDeviceExtension->PartitionLength.QuadPart += DiskDeviceExtension->StartingOffset.QuadPart;
+       }
+    }
+
+  DPRINT("DiskBuildPartitionTable() done\n");
+  if (PartitionList != NULL)
+       ExFreePool(PartitionList);
+  return(STATUS_SUCCESS);
+}
+
+
 /**********************************************************************
  * NAME                                                        EXPORTED
  *     DiskClassDeviceControl
@@ -817,7 +999,7 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
 NTSTATUS STDCALL
 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
                       IN PIRP Irp)
-{
+{ 
   PDEVICE_EXTENSION DeviceExtension;
   PIO_STACK_LOCATION IrpStack;
   ULONG ControlCode, InputLength, OutputLength;
@@ -860,7 +1042,7 @@ DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
            if (!NT_SUCCESS(Status))
              {
                /* Drive is not ready */
-               DiskData->DriveNotReady = FALSE;
+               DiskData->DriveNotReady = TRUE;
                break;
              }
 
@@ -878,6 +1060,14 @@ DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
 
       case IOCTL_DISK_GET_PARTITION_INFO:
        DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
+
+       if ((DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
+       (DeviceExtension->DiskGeometry->MediaType == RemovableMedia))
+       {
+               /* Update a partition list for a single entry. */
+               Status = DiskBuildPartitionTable(DeviceObject,Irp);
+       }
+       
        if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
            sizeof(PARTITION_INFORMATION))
          {
@@ -888,7 +1078,7 @@ DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
            Status = STATUS_INVALID_DEVICE_REQUEST;
          }
        else
-         {
+       {
            PPARTITION_INFORMATION PartitionInfo;
 
            PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
@@ -1063,7 +1253,7 @@ DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
       case IOCTL_DISK_REQUEST_STRUCTURE:
       case IOCTL_DISK_REQUEST_DATA:
        /* If we get here, something went wrong. Inform the requestor */
-       DPRINT1("Unhandled control code: %lx\n", ControlCode);
+       DPRINT("Unhandled control code: %lx\n", ControlCode);
        Status = STATUS_INVALID_DEVICE_REQUEST;
        Information = 0;
        break;
@@ -1290,7 +1480,7 @@ DiskClassUpdatePartitionDeviceObjects(IN PDEVICE_OBJECT DiskDeviceObject,
               DeviceExtension->PartitionLength.QuadPart))
            continue;
 
-         DPRINT1("Found matching partition entry for partition %lu\n",
+         DPRINT("Found matching partition entry for partition %lu\n",
                  DiskData->PartitionNumber);
 
          /* Found matching partition */
@@ -1392,7 +1582,7 @@ DiskClassUpdatePartitionDeviceObjects(IN PDEVICE_OBJECT DiskDeviceObject,
                                  &DeviceObject);
          if (!NT_SUCCESS(Status))
            {
-             DPRINT1("IoCreateDevice() failed (Status %lx)\n", Status);
+             DPRINT("IoCreateDevice() failed (Status %lx)\n", Status);
              continue;
            }
 
@@ -1745,7 +1935,7 @@ ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension)
                               1024);
   if (ValueBuffer == NULL)
     {
-      DPRINT1("Failed to allocate value buffer\n");
+      DPRINT("Failed to allocate value buffer\n");
       ZwClose(SystemKey);
       return;
     }
@@ -1808,7 +1998,7 @@ ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension)
 #if 0
   for (i = 0; i< DriveParameters[0].NumberDrives; i++)
     {
-      DPRINT1("Drive %lu: %lu Cylinders  %hu Heads  %hu Sectors\n",
+      DPRINT("Drive %lu: %lu Cylinders  %hu Heads  %hu Sectors\n",
              i,
              DriveParameters[i].MaxCylinders,
              DriveParameters[i].MaxHeads,
@@ -1834,7 +2024,7 @@ ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension)
   Length = TracksPerCylinder * SectorsPerTrack;
   if (Length == 0)
     {
-      DPRINT1("Invalid track length 0\n");
+      DPRINT("Invalid track length 0\n");
       ExFreePool(ValueBuffer);
       return;
     }
@@ -1853,7 +2043,7 @@ ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension)
 
   if (DeviceExtension->DMActive)
     {
-      DPRINT1("FIXME: Update geometry with respect to the installed disk manager!\n");
+      DPRINT("FIXME: Update geometry with respect to the installed disk manager!\n");
 
       /* FIXME: Update geometry for disk managers */