update for HEAD-2003091401
[reactos.git] / drivers / storage / atapi / atapi.c
index e540426..c42d750 100644 (file)
 typedef struct _ATAPI_MINIPORT_EXTENSION
 {
   IDE_DRIVE_IDENTIFY DeviceParams[2];
-  BOOLEAN DevicePresent[2];
-  BOOLEAN DeviceAtapi[2];
-  ULONG TransferSize[2]; 
-  BOOLEAN MultiSectorCommand[2];
-  BOOLEAN DWordIo[2];
-
+  ULONG DeviceFlags[2];
+  ULONG TransferSize[2];
 
   ULONG CommandPortBase;
   ULONG ControlPortBase;
@@ -93,6 +89,14 @@ typedef struct _ATAPI_MINIPORT_EXTENSION
   ULONG DataTransferLength;
 } ATAPI_MINIPORT_EXTENSION, *PATAPI_MINIPORT_EXTENSION;
 
+/* DeviceFlags */
+#define DEVICE_PRESENT           0x00000001
+#define DEVICE_ATAPI             0x00000002
+#define DEVICE_MULTI_SECTOR_CMD  0x00000004
+#define DEVICE_DWORD_IO          0x00000008
+#define DEVICE_48BIT_ADDRESS     0x00000010
+#define DEVICE_MEDIA_STATUS      0x00000020
+
 
 typedef struct _UNIT_EXTENSION
 {
@@ -237,10 +241,17 @@ static ULONG
 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
                PSCSI_REQUEST_BLOCK Srb);
 
+static ULONG
+AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+                  PSCSI_REQUEST_BLOCK Srb);
+
 static UCHAR
 AtapiErrorToScsi(PVOID DeviceExtension,
                 PSCSI_REQUEST_BLOCK Srb);
 
+static VOID
+AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb);
+
 //  ----------------------------------------------------------------  Inlines
 
 void
@@ -830,7 +841,7 @@ AtapiStartIo(IN PVOID DeviceExtension,
     {
       case SRB_FUNCTION_EXECUTE_SCSI:
        DevExt->CurrentSrb = Srb;
-       if (DevExt->DeviceAtapi[Srb->TargetId] == TRUE)
+       if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
          {
            Result = AtapiSendAtapiCommand(DevExt,
                                           Srb);
@@ -842,6 +853,20 @@ AtapiStartIo(IN PVOID DeviceExtension,
          }
        break;
 
+      case SRB_FUNCTION_ABORT_COMMAND:
+       if (DevExt->CurrentSrb != NULL)
+         {
+           Result = SRB_STATUS_ABORT_FAILED;
+         }
+       else
+         {
+           Result = SRB_STATUS_SUCCESS;
+         }
+       break;
+
+      default:
+       Result = SRB_STATUS_INVALID_REQUEST;
+       break;
     }
 
   Srb->SrbStatus = Result;
@@ -877,13 +902,14 @@ AtapiInterrupt(IN PVOID DeviceExtension)
   PSCSI_REQUEST_BLOCK Srb;
   ULONG CommandPortBase;
   ULONG ControlPortBase;
-
   UCHAR DeviceStatus;
   BOOLEAN IsLastBlock;
   BOOLEAN IsAtapi;
   ULONG Retries;
   PUCHAR TargetAddress;
   ULONG TransferSize;
+  ULONG JunkSize;
+  USHORT Junk;
 
   DPRINT("AtapiInterrupt() called!\n");
 
@@ -915,7 +941,7 @@ AtapiInterrupt(IN PVOID DeviceExtension)
 
   DPRINT("CommandPortBase: %lx  ControlPortBase: %lx\n", CommandPortBase, ControlPortBase);
 
-  IsAtapi = DevExt->DeviceAtapi[Srb->TargetId];
+  IsAtapi = (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI);
   DPRINT("IsAtapi == %s\n", (IsAtapi) ? "TRUE" : "FALSE");
 
   IsLastBlock = FALSE;
@@ -954,10 +980,16 @@ AtapiInterrupt(IN PVOID DeviceExtension)
 
          if (DevExt->DataTransferLength <= TransferSize)
            {
-             if (!IsAtapi)
-             {
-                TransferSize = DevExt->DataTransferLength;
-             }
+             JunkSize = TransferSize - DevExt->DataTransferLength;
+             TransferSize = DevExt->DataTransferLength;
+
+#ifndef NDEBUG
+             if (JunkSize > 0)
+               {
+                 DPRINT1("Junk data: %lu bytes\n", JunkSize);
+               }
+#endif
+
              DevExt->DataTransferLength = 0;
              IsLastBlock = TRUE;
            }
@@ -974,25 +1006,35 @@ AtapiInterrupt(IN PVOID DeviceExtension)
               !(IDEReadStatus(CommandPortBase) & IDE_SR_DRQ);
               Retries++)
            {
-               KeStallExecutionProcessor(10);
+             KeStallExecutionProcessor(10);
            }
 
          /* Copy the block of data */
-         if (DevExt->DWordIo[Srb->TargetId])
-         {
-            IDEReadBlock32(CommandPortBase,
-                           TargetAddress,
-                           TransferSize);
-         }
+         if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
+           {
+             IDEReadBlock32(CommandPortBase,
+                            TargetAddress,
+                            TransferSize);
+           }
          else
-         {
-            IDEReadBlock(CommandPortBase,
-                         TargetAddress,
-                         TransferSize);
-         }
+           {
+             IDEReadBlock(CommandPortBase,
+                          TargetAddress,
+                          TransferSize);
+           }
+
          /* check DRQ */
          if (IsLastBlock)
            {
+             /* Read remaining junk from device */
+             while (JunkSize > 0)
+               {
+                 IDEReadBlock(CommandPortBase,
+                              &Junk,
+                              2);
+                 JunkSize -= 2;
+               }
+
              for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
                   (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
                   Retries++)
@@ -1034,35 +1076,35 @@ AtapiInterrupt(IN PVOID DeviceExtension)
              /* Update DevExt data */
              TransferSize = DevExt->TransferSize[Srb->TargetId];
              if (DevExt->DataTransferLength < TransferSize)
-             {
-                TransferSize = DevExt->DataTransferLength;
-             }
-                
+               {
+                 TransferSize = DevExt->DataTransferLength;
+               }
+
              TargetAddress = DevExt->DataBuffer;
              DevExt->DataBuffer += TransferSize;
              DevExt->DataTransferLength -= TransferSize;
 
              /* Write the sector */
-              if (DevExt->DWordIo[Srb->TargetId])
-             {
-                IDEWriteBlock32(CommandPortBase,
-                                TargetAddress,
-                                TransferSize);
-             }
+             if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
+               {
+                 IDEWriteBlock32(CommandPortBase,
+                                 TargetAddress,
+                                 TransferSize);
+               }
              else
-             {
-                IDEWriteBlock(CommandPortBase,
-                              TargetAddress,
-                              TransferSize);
-             }
+               {
+                 IDEWriteBlock(CommandPortBase,
+                               TargetAddress,
+                               TransferSize);
+               }
            }
 
          Srb->SrbStatus = SRB_STATUS_SUCCESS;
        }
       else
        {
-         DPRINT1("Unspecified transfer direction!\n");
-         Srb->SrbStatus = SRB_STATUS_SUCCESS; // SRB_STATUS_ERROR;
+         DPRINT("Unspecified transfer direction!\n");
+         Srb->SrbStatus = SRB_STATUS_SUCCESS;
          IsLastBlock = TRUE;
        }
     }
@@ -1179,7 +1221,7 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
       if (Retries >= 20000)
        {
          DPRINT("Timeout on drive %lu\n", UnitNumber);
-         DeviceExtension->DevicePresent[UnitNumber] = FALSE;
+         DeviceExtension->DeviceFlags[UnitNumber] &= ~DEVICE_PRESENT;
          continue;
        }
 
@@ -1200,11 +1242,10 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
                                  &DeviceExtension->DeviceParams[UnitNumber]))
            {
              DPRINT("  ATAPI drive found!\n");
-             DeviceExtension->DevicePresent[UnitNumber] = TRUE;
-             DeviceExtension->DeviceAtapi[UnitNumber] = TRUE;
-             DeviceExtension->TransferSize[UnitNumber] = DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
-              DeviceExtension->MultiSectorCommand[UnitNumber] = FALSE;
-              DeviceExtension->DWordIo[UnitNumber] = FALSE;
+             DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
+             DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_ATAPI;
+             DeviceExtension->TransferSize[UnitNumber] =
+               DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
              DeviceFound = TRUE;
            }
          else
@@ -1221,22 +1262,22 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
                                  &DeviceExtension->DeviceParams[UnitNumber]))
            {
              DPRINT("  IDE drive found!\n");
-             DeviceExtension->DevicePresent[UnitNumber] = TRUE;
-             DeviceExtension->DeviceAtapi[UnitNumber] = FALSE;
+             DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
              DeviceExtension->TransferSize[UnitNumber] = DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
              if ((DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0x8000) && 
                  (DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0xff) &&
                  (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0x100) &&
                  (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff))
-             {
-                DeviceExtension->TransferSize[UnitNumber] *= (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff);
-                DeviceExtension->MultiSectorCommand[UnitNumber] = TRUE;
-             }
-             else
-             {
-                 DeviceExtension->MultiSectorCommand[UnitNumber] = FALSE;
-             }
-              DeviceExtension->DWordIo[UnitNumber] = DeviceExtension->DeviceParams[UnitNumber].DWordIo ? TRUE : FALSE;
+               {
+                 DeviceExtension->TransferSize[UnitNumber] *= (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff);
+                 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_MULTI_SECTOR_CMD;
+               }
+
+             if (DeviceExtension->DeviceParams[UnitNumber].DWordIo)
+               {
+                 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DWORD_IO;
+               }
+
              DeviceFound = TRUE;
            }
          else
@@ -1677,7 +1718,7 @@ AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
       return(SRB_STATUS_INVALID_LUN);
     }
 
-  if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
+  if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
     {
       Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
       return(SRB_STATUS_NO_DEVICE);
@@ -1771,6 +1812,16 @@ AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
       ScsiPortStallExecution(10);
     }
 
+  /* Convert special SCSI SRBs to ATAPI format */
+  switch (Srb->Cdb[0])
+    {
+      case SCSIOP_FORMAT_UNIT:
+      case SCSIOP_MODE_SELECT:
+      case SCSIOP_MODE_SENSE:
+       AtapiScsiSrbToAtapi (Srb);
+       break;
+    }
+
   CdbSize = (DeviceExtension->DeviceParams[Srb->TargetId].ConfigBits & 0x3 == 1) ? 16 : 12;
   DPRINT("CdbSize: %lu\n", CdbSize);
 
@@ -1800,6 +1851,30 @@ AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
         Srb->TargetId,
         Srb->Lun);
 
+  if (Srb->PathId != 0)
+    {
+      Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
+      return(SRB_STATUS_INVALID_PATH_ID);
+    }
+
+  if (Srb->TargetId > 1)
+    {
+      Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
+      return(SRB_STATUS_INVALID_TARGET_ID);
+    }
+
+  if (Srb->Lun != 0)
+    {
+      Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+      return(SRB_STATUS_INVALID_LUN);
+    }
+
+  if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
+    {
+      Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+      return(SRB_STATUS_NO_DEVICE);
+    }
+
   switch (Srb->Cdb[0])
     {
       case SCSIOP_INQUIRY:
@@ -1823,8 +1898,13 @@ AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
                                    Srb);
        break;
 
-      case SCSIOP_MODE_SENSE:
       case SCSIOP_TEST_UNIT_READY:
+       SrbStatus = AtapiTestUnitReady(DeviceExtension,
+                                      Srb);
+       break;
+
+      case SCSIOP_MODE_SENSE:
+
       case SCSIOP_VERIFY:
       case SCSIOP_START_STOP_UNIT:
       case SCSIOP_REQUEST_SENSE:
@@ -1854,30 +1934,6 @@ AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
   DPRINT("SCSIOP_INQUIRY: DeviceExtension %p  TargetId: %lu\n",
         DeviceExtension, Srb->TargetId);
 
-  if (Srb->PathId != 0)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
-      return(SRB_STATUS_INVALID_PATH_ID);
-    }
-
-  if (Srb->TargetId > 1)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
-      return(SRB_STATUS_INVALID_TARGET_ID);
-    }
-
-  if (Srb->Lun != 0)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
-      return(SRB_STATUS_INVALID_LUN);
-    }
-
-  if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
-    {
-      Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
-      return(SRB_STATUS_NO_DEVICE);
-    }
-
   InquiryData = Srb->DataBuffer;
   DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
 
@@ -1888,17 +1944,17 @@ AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
     }
 
   /* set device class */
-  if (DeviceExtension->DeviceAtapi[Srb->TargetId] == FALSE)
-    {
-      /* hard-disk */
-      InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
-    }
-  else
+  if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
     {
       /* get it from the ATAPI configuration word */
       InquiryData->DeviceType = (DeviceParams->ConfigBits >> 8) & 0x1F;
       DPRINT("Device class: %u\n", InquiryData->DeviceType);
     }
+  else
+    {
+      /* hard-disk */
+      InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
+    }
 
   DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
   if (DeviceParams->ConfigBits & 0x80)
@@ -1944,31 +2000,6 @@ AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
   ULONG LastSector;
 
   DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
-
-  if (Srb->PathId != 0)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
-      return(SRB_STATUS_INVALID_PATH_ID);
-    }
-
-  if (Srb->TargetId > 1)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
-      return(SRB_STATUS_INVALID_TARGET_ID);
-    }
-
-  if (Srb->Lun != 0)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
-      return(SRB_STATUS_INVALID_LUN);
-    }
-
-  if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
-    {
-      Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
-      return(SRB_STATUS_NO_DEVICE);
-    }
-
   CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
   DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
 
@@ -2019,31 +2050,6 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
   UCHAR Status;
 
   DPRINT("AtapiReadWrite() called!\n");
-
-  if (Srb->PathId != 0)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
-      return(SRB_STATUS_INVALID_PATH_ID);
-    }
-
-  if (Srb->TargetId > 1)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
-      return(SRB_STATUS_INVALID_TARGET_ID);
-    }
-
-  if (Srb->Lun != 0)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
-      return(SRB_STATUS_INVALID_LUN);
-    }
-
-  if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
-    {
-      Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
-      return(SRB_STATUS_NO_DEVICE);
-    }
-
   DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
         Srb->TargetId);
 
@@ -2086,11 +2092,11 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
 
   if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
     {
-      Command = DeviceExtension->MultiSectorCommand[Srb->TargetId] ? IDE_CMD_READ_MULTIPLE : IDE_CMD_READ;
+      Command = (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MULTI_SECTOR_CMD) ? IDE_CMD_READ_MULTIPLE : IDE_CMD_READ;
     }
   else
     {
-      Command = DeviceExtension->MultiSectorCommand[Srb->TargetId] ? IDE_CMD_WRITE_MULTIPLE : IDE_CMD_WRITE;
+      Command = (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MULTI_SECTOR_CMD) ? IDE_CMD_WRITE_MULTIPLE : IDE_CMD_WRITE;
     }
 
   if (DrvHead & IDE_DH_LBA)
@@ -2205,27 +2211,27 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
       /* Update DeviceExtension data */
       TransferSize = DeviceExtension->TransferSize[Srb->TargetId];
       if (DeviceExtension->DataTransferLength < TransferSize)
-      {
-        TransferSize = DeviceExtension->DataTransferLength;
-      }
+       {
+         TransferSize = DeviceExtension->DataTransferLength;
+       }
 
       TargetAddress = DeviceExtension->DataBuffer;
       DeviceExtension->DataBuffer += TransferSize;
       DeviceExtension->DataTransferLength -= TransferSize;
 
       /* Write data block */
-      if (DeviceExtension->DWordIo[Srb->TargetId])
-      {
-         IDEWriteBlock32(DeviceExtension->CommandPortBase,
-                        TargetAddress,
-                        TransferSize);
-      }
+      if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
+       {
+         IDEWriteBlock32(DeviceExtension->CommandPortBase,
+                         TargetAddress,
+                         TransferSize);
+       }
       else
-      {
-         IDEWriteBlock(DeviceExtension->CommandPortBase,
-                      TargetAddress,
-                      TransferSize);
-      }
+       {
+         IDEWriteBlock(DeviceExtension->CommandPortBase,
+                       TargetAddress,
+                       TransferSize);
+       }
     }
 
   DPRINT("AtapiReadWrite() done!\n");
@@ -2242,35 +2248,82 @@ AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
   ULONG Retries;
   UCHAR Status;
 
-  DPRINT1("AtapiFlushCache() called!\n");
+  DPRINT("AtapiFlushCache() called!\n");
+  DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
+        Srb->TargetId);
 
-  if (Srb->PathId != 0)
+  /* Wait for BUSY to clear */
+  for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
     {
-      Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
-      return(SRB_STATUS_INVALID_PATH_ID);
+      Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+      if (!(Status & IDE_SR_BUSY))
+        {
+          break;
+        }
+      ScsiPortStallExecution(10);
     }
-
-  if (Srb->TargetId > 1)
+  DPRINT("Status=%02x\n", Status);
+  DPRINT("Waited %ld usecs for busy to clear\n", Retries * 10);
+  if (Retries >= IDE_MAX_BUSY_RETRIES)
     {
-      Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
-      return(SRB_STATUS_INVALID_TARGET_ID);
+      DPRINT1("Drive is BUSY for too long\n");
+      return(SRB_STATUS_BUSY);
     }
 
-  if (Srb->Lun != 0)
+  /* Select the desired drive */
+  IDEWriteDriveHead(DeviceExtension->CommandPortBase,
+                   IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
+  ScsiPortStallExecution(10);
+
+  /* Issue command to drive */
+  IDEWriteCommand(DeviceExtension->CommandPortBase, IDE_CMD_FLUSH_CACHE);
+
+  /* Wait for controller ready */
+  for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
     {
-      Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
-      return(SRB_STATUS_INVALID_LUN);
+      BYTE  Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+      if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
+       {
+         break;
+       }
+      KeStallExecutionProcessor(10);
     }
-
-  if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
+  if (Retries >= IDE_MAX_WRITE_RETRIES)
     {
-      Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
-      return(SRB_STATUS_NO_DEVICE);
+      DPRINT1("Drive is BUSY for too long after sending write command\n");
+      return(SRB_STATUS_BUSY);
     }
 
-  DPRINT1("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
+  /* Indicate expecting an interrupt. */
+  DeviceExtension->ExpectingInterrupt = TRUE;
+
+  DPRINT("AtapiFlushCache() done!\n");
+
+  /* Wait for interrupt. */
+  return(SRB_STATUS_PENDING);
+}
+
+
+static ULONG
+AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+                  PSCSI_REQUEST_BLOCK Srb)
+{
+  ULONG Retries;
+  UCHAR Status;
+  UCHAR Error;
+
+  DPRINT1("AtapiTestUnitReady() called!\n");
+
+  DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
         Srb->TargetId);
 
+  /* Return success if media status is not supported */
+  if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MEDIA_STATUS))
+    {
+      Srb->SrbStatus = SRB_STATUS_SUCCESS;
+      return(SRB_STATUS_SUCCESS);
+    }
+
   /* Wait for BUSY to clear */
   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
     {
@@ -2295,12 +2348,12 @@ AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
   ScsiPortStallExecution(10);
 
   /* Issue command to drive */
-  IDEWriteCommand(DeviceExtension->CommandPortBase, IDE_CMD_FLUSH_CACHE);
+  IDEWriteCommand(DeviceExtension->CommandPortBase, IDE_CMD_GET_MEDIA_STATUS);
 
   /* Wait for controller ready */
   for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
     {
-      BYTE  Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+      Status = IDEReadStatus(DeviceExtension->CommandPortBase);
       if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
        {
          break;
@@ -2313,13 +2366,29 @@ AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
       return(SRB_STATUS_BUSY);
     }
 
-  /* Indicate expecting an interrupt. */
-  DeviceExtension->ExpectingInterrupt = TRUE;
+  if (Status & IDE_SR_ERR)
+    {
+      Error = IDEReadError(DeviceExtension->CommandPortBase);
+      if (Error == IDE_ER_UNC)
+       {
+CHECKPOINT1;
+         /* Handle write protection 'error' */
+         Srb->SrbStatus = SRB_STATUS_SUCCESS;
+         return(SRB_STATUS_SUCCESS);
+       }
+      else
+       {
+CHECKPOINT1;
+         /* Indicate expecting an interrupt. */
+         DeviceExtension->ExpectingInterrupt = TRUE;
+         return(SRB_STATUS_PENDING);
+       }
+    }
 
-  DPRINT1("AtapiFlushCache() done!\n");
+  DPRINT1("AtapiTestUnitReady() done!\n");
 
-  /* Wait for interrupt. */
-  return(SRB_STATUS_PENDING);
+  Srb->SrbStatus = SRB_STATUS_SUCCESS;
+  return(SRB_STATUS_SUCCESS);
 }
 
 
@@ -2343,7 +2412,7 @@ AtapiErrorToScsi(PVOID DeviceExtension,
 
   ErrorReg = IDEReadError(CommandPortBase);
 
-  if (DevExt->DeviceAtapi[Srb->TargetId])
+  if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
     {
       switch (ErrorReg >> 4)
        {
@@ -2449,4 +2518,56 @@ AtapiErrorToScsi(PVOID DeviceExtension,
   return(SrbStatus);
 }
 
+
+static VOID
+AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb)
+{
+  DPRINT("AtapiConvertScsiToAtapi() called\n");
+
+  Srb->CdbLength = 12;
+
+  switch (Srb->Cdb[0])
+    {
+      case SCSIOP_FORMAT_UNIT:
+       Srb->Cdb[0] = ATAPI_FORMAT_UNIT;
+       break;
+
+      case SCSIOP_MODE_SELECT:
+         {
+           PATAPI_MODE_SELECT12 AtapiModeSelect;
+           UCHAR Length;
+
+           AtapiModeSelect = (PATAPI_MODE_SELECT12)Srb->Cdb;
+           Length = ((PCDB)Srb->Cdb)->MODE_SELECT.ParameterListLength;
+
+           RtlZeroMemory (Srb->Cdb,
+                          MAXIMUM_CDB_SIZE);
+           AtapiModeSelect->OperationCode = ATAPI_MODE_SELECT;
+           AtapiModeSelect->PFBit = 1;
+           AtapiModeSelect->ParameterListLengthMsb = 0;
+           AtapiModeSelect->ParameterListLengthLsb = Length;
+         }
+       break;
+
+      case SCSIOP_MODE_SENSE:
+         {
+           PATAPI_MODE_SENSE12 AtapiModeSense;
+           UCHAR PageCode;
+           UCHAR Length;
+
+           AtapiModeSense = (PATAPI_MODE_SENSE12)Srb->Cdb;
+           PageCode = ((PCDB)Srb->Cdb)->MODE_SENSE.PageCode;
+           Length = ((PCDB)Srb->Cdb)->MODE_SENSE.AllocationLength;
+
+           RtlZeroMemory (Srb->Cdb,
+                          MAXIMUM_CDB_SIZE);
+           AtapiModeSense->OperationCode = ATAPI_MODE_SENSE;
+           AtapiModeSense->PageCode = PageCode;
+           AtapiModeSense->ParameterListLengthMsb = 0;
+           AtapiModeSense->ParameterListLengthLsb = Length;
+         }
+       break;
+    }
+}
+
 /* EOF */