update for HEAD-2003091401
[reactos.git] / drivers / storage / disk / disk.c
index 354be2b..db2bc4b 100644 (file)
@@ -37,6 +37,9 @@
 
 #define VERSION  "0.0.1"
 
+#define SCSI_DISK_TIMEOUT      10      /* Default timeout: 10 seconds */
+#define MODE_DATA_SIZE         192
+
 
 typedef struct _DISK_DATA
 {
@@ -260,6 +263,8 @@ DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
        {
          InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
 
+         DPRINT("Device type %u\n", InquiryData->DeviceType);
+
          if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
               (InquiryData->DeviceType == OPTICAL_DEVICE)) &&
              (InquiryData->DeviceTypeQualifier == 0) &&
@@ -402,7 +407,7 @@ DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
 
 static NTSTATUS
 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
-                           IN PUNICODE_STRING RegistryPath, /* what's this used for? */
+                           IN PUNICODE_STRING RegistryPath,
                            IN PDEVICE_OBJECT PortDeviceObject,
                            IN ULONG PortNumber,
                            IN ULONG DiskNumber,
@@ -515,6 +520,12 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
   DiskDeviceExtension->TargetId = InquiryData->TargetId;
   DiskDeviceExtension->Lun = InquiryData->Lun;
 
+  /* Get timeout value */
+  DiskDeviceExtension->TimeOutValue =
+    ScsiClassQueryTimeOutRegistryValue(RegistryPath);
+  if (DiskDeviceExtension->TimeOutValue == 0)
+    DiskDeviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
+
   /* Initialize the lookaside list for SRBs */
   ScsiClassInitializeSrbLookasideList(DiskDeviceExtension,
                                      4);
@@ -548,6 +559,32 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
       return(STATUS_INSUFFICIENT_RESOURCES);
     }
 
+  /* Allocate sense data buffer */
+  DiskDeviceExtension->SenseData = ExAllocatePool(NonPagedPool,
+                                                 sizeof(SENSE_BUFFER_SIZE));
+  if (DiskDeviceExtension->SenseData == NULL)
+    {
+      DPRINT("Failed to allocate sense data buffer!\n");
+
+      ExFreePool (DiskDeviceExtension->DiskGeometry);
+
+      ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
+
+      IoDeleteDevice(DiskDeviceObject);
+
+      /* Release (unclaim) the disk */
+      ScsiClassClaimDevice(PortDeviceObject,
+                          InquiryData,
+                          TRUE,
+                          NULL);
+
+      /* Delete the harddisk device directory */
+      ZwMakeTemporaryObject(Handle);
+      ZwClose(Handle);
+
+      return(STATUS_INSUFFICIENT_RESOURCES);
+    }
+
   /* Read the drive's capacity */
   Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
   if (!NT_SUCCESS(Status) &&
@@ -703,6 +740,7 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
              PartitionDeviceObject->AlignmentRequirement = DiskDeviceObject->AlignmentRequirement;
 
              PartitionDeviceExtension = PartitionDeviceObject->DeviceExtension;
+             PartitionDeviceExtension->SenseData = DiskDeviceExtension->SenseData;
              PartitionDeviceExtension->LockCount = 0;
              PartitionDeviceExtension->DeviceNumber = DiskNumber;
              PartitionDeviceExtension->DeviceObject = PartitionDeviceObject;
@@ -722,6 +760,7 @@ DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
              PartitionDeviceExtension->TargetId = InquiryData->TargetId;
              PartitionDeviceExtension->Lun = InquiryData->Lun;
              PartitionDeviceExtension->SectorShift = DiskDeviceExtension->SectorShift;
+             PartitionDeviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
 
              /* Initialize lookaside list for SRBs */
              ScsiClassInitializeSrbLookasideList(PartitionDeviceExtension,
@@ -804,30 +843,37 @@ DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
        if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
          {
            Status = STATUS_INVALID_PARAMETER;
+           break;
          }
-       else
+
+       if (DeviceExtension->DiskGeometry == NULL)
          {
-           PDISK_GEOMETRY Geometry;
+           DPRINT("No disk geometry available!\n");
+           DeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
+                                                          sizeof(DISK_GEOMETRY));
+         }
 
-           if (DeviceExtension->DiskGeometry == NULL)
-             {
-               DPRINT("No disk geometry available!\n");
-               DeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
-                                                              sizeof(DISK_GEOMETRY));
-             }
+       if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
+         {
            Status = ScsiClassReadDriveCapacity(DeviceObject);
            DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status);
-           if (NT_SUCCESS(Status))
+           if (!NT_SUCCESS(Status))
              {
-               Geometry = (PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer;
-               RtlMoveMemory(Geometry,
-                             DeviceExtension->DiskGeometry,
-                             sizeof(DISK_GEOMETRY));
-
-               Status = STATUS_SUCCESS;
-               Information = sizeof(DISK_GEOMETRY);
+               /* Drive is not ready */
+               DiskData->DriveNotReady = FALSE;
+               break;
              }
+
+           /* Drive is ready */
+           DiskData->DriveNotReady = FALSE;
          }
+
+       RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
+                     DeviceExtension->DiskGeometry,
+                     sizeof(DISK_GEOMETRY));
+
+       Status = STATUS_SUCCESS;
+       Information = sizeof(DISK_GEOMETRY);
        break;
 
       case IOCTL_DISK_GET_PARTITION_INFO:
@@ -971,10 +1017,48 @@ DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
          }
        break;
 
+      case IOCTL_DISK_IS_WRITABLE:
+       {
+         PMODE_PARAMETER_HEADER ModeData;
+         ULONG Length;
+
+         ModeData = ExAllocatePool (NonPagedPool,
+                                    MODE_DATA_SIZE);
+         if (ModeData == NULL)
+           {
+             Status = STATUS_INSUFFICIENT_RESOURCES;
+             break;
+           }
+         RtlZeroMemory (ModeData,
+                        MODE_DATA_SIZE);
+
+         Length = ScsiClassModeSense (DeviceObject,
+                                      (PVOID)ModeData,
+                                      MODE_DATA_SIZE,
+                                      MODE_SENSE_RETURN_ALL);
+         if (Length < sizeof(MODE_PARAMETER_HEADER))
+           {
+             /* FIXME: Retry */
+             Status = STATUS_IO_DEVICE_ERROR;
+             ExFreePool (ModeData);
+             break;
+           }
+
+         if (ModeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT)
+           {
+             Status = STATUS_MEDIA_WRITE_PROTECTED;
+           }
+         else
+           {
+             Status = STATUS_SUCCESS;
+           }
+         ExFreePool (ModeData);
+       }
+       break;
+
       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:
@@ -1062,6 +1146,9 @@ DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
   Srb->TargetId = DeviceExtension->TargetId;
   Srb->Lun = DeviceExtension->Lun;
 
+  /* Set timeout */
+  Srb->TimeOutValue = DeviceExtension->TimeOutValue * 4;
+
   /* Flush write cache */
   Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
   Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;